[Pkg-samba-maint] [samba] 01/11: Imported Upstream version 4.4.0

Andrew Bartlett abartlet-guest at moszumanska.debian.org
Tue Apr 12 22:37:45 UTC 2016


This is an automated email from the git hooks/post-receive script.

abartlet-guest pushed a commit to branch master
in repository samba.

commit 05ed29815370fb04c3a8a47d8ba77cf3648a65ab
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Apr 1 15:12:47 2016 +1300

    Imported Upstream version 4.4.0
---
 .travis.yml                                        |   31 +
 Makefile                                           |    3 +
 README                                             |   20 +-
 README.Coding                                      |   59 +-
 VERSION                                            |    4 +-
 WHATSNEW.txt                                       | 1125 ++----
 auth/credentials/pycredentials.c                   |  164 +-
 auth/credentials/pycredentials.h                   |    5 -
 auth/credentials/wscript_build                     |    2 +-
 auth/gensec/gensec.pc.in                           |   11 -
 auth/gensec/gensec_util.c                          |    2 +-
 auth/gensec/spnego.c                               |   19 +-
 auth/gensec/wscript_build                          |    7 +-
 auth/kerberos/gssapi_pac.c                         |   12 +-
 auth/ntlmssp/gensec_ntlmssp_server.c               |    1 +
 auth/ntlmssp/ntlmssp_client.c                      |   21 +-
 buildtools/wafsamba/configure_file.py              |   13 +-
 buildtools/wafsamba/gccdeps.py                     |  127 -
 buildtools/wafsamba/nothreads.py                   |    7 +-
 buildtools/wafsamba/pkgconfig.py                   |   15 +-
 buildtools/wafsamba/samba_abi.py                   |    9 +-
 buildtools/wafsamba/samba_autoconf.py              |   36 +-
 buildtools/wafsamba/samba_autoproto.py             |    3 +-
 buildtools/wafsamba/samba_bundled.py               |   58 +-
 buildtools/wafsamba/samba_conftests.py             |   93 +-
 buildtools/wafsamba/samba_cross.py                 |    4 +-
 buildtools/wafsamba/samba_deps.py                  |  101 +-
 buildtools/wafsamba/samba_dist.py                  |    6 +-
 buildtools/wafsamba/samba_headers.py               |    5 +-
 buildtools/wafsamba/samba_install.py               |   11 +-
 buildtools/wafsamba/samba_optimisation.py          |   30 +-
 buildtools/wafsamba/samba_patterns.py              |   12 +-
 buildtools/wafsamba/samba_perl.py                  |    9 +-
 buildtools/wafsamba/samba_pidl.py                  |   11 +-
 buildtools/wafsamba/samba_python.py                |   26 +-
 buildtools/wafsamba/samba_third_party.py           |    4 +-
 buildtools/wafsamba/samba_utils.py                 |   85 +-
 buildtools/wafsamba/samba_version.py               |    5 +-
 buildtools/wafsamba/samba_wildcard.py              |    9 +-
 buildtools/wafsamba/symbols.py                     |   21 +-
 buildtools/wafsamba/wafsamba.py                    |   42 +-
 buildtools/wafsamba/wscript                        |   59 +-
 ctdb/client/client.h                               |  842 +++++
 ctdb/client/client_call.c                          |  177 +
 ctdb/client/client_connect.c                       |  338 ++
 ctdb/client/client_control.c                       |  429 +++
 ctdb/client/client_control_sync.c                  | 3119 ++++++++++++++++
 ctdb/client/client_db.c                            | 2133 +++++++++++
 ctdb/client/client_message.c                       |  227 ++
 ctdb/client/client_message_sync.c                  |  196 +
 ctdb/client/client_private.h                       |   82 +
 ctdb/client/client_util.c                          |  155 +
 ctdb/client/ctdb_client.c                          |  482 +--
 ctdb/common/cmdline.c                              |   40 +-
 ctdb/common/cmdline.h                              |   13 +
 ctdb/common/comm.c                                 |  404 +++
 ctdb/common/comm.h                                 |  101 +
 ctdb/common/common.h                               |  146 +
 ctdb/common/ctdb_fork.c                            |  163 -
 ctdb/common/ctdb_io.c                              |   46 +-
 ctdb/common/ctdb_logging.c                         |   85 -
 ctdb/common/ctdb_ltdb.c                            |   13 +-
 ctdb/common/ctdb_message.c                         |  286 --
 ctdb/common/ctdb_util.c                            |  117 +-
 ctdb/common/db_hash.c                              |  268 ++
 ctdb/common/db_hash.h                              |  159 +
 ctdb/common/logging.c                              |  103 +
 ctdb/common/logging.h                              |   41 +
 ctdb/common/pkt_read.c                             |  190 +
 ctdb/common/pkt_read.h                             |   98 +
 ctdb/common/pkt_write.c                            |  101 +
 ctdb/common/pkt_write.h                            |   79 +
 ctdb/common/rb_tree.c                              |   16 +-
 ctdb/common/reqid.c                                |   89 +
 ctdb/common/reqid.h                                |   89 +
 ctdb/common/srvid.c                                |  269 ++
 ctdb/common/srvid.h                                |  115 +
 ctdb/common/system.h                               |   65 +
 ctdb/common/system_aix.c                           |   36 +-
 ctdb/common/system_common.c                        |    9 +-
 ctdb/common/system_freebsd.c                       |   52 +-
 ctdb/common/system_gnu.c                           |   38 +-
 ctdb/common/system_kfreebsd.c                      |   51 +-
 ctdb/common/system_linux.c                         |  218 +-
 ctdb/common/system_util.c                          |   10 +-
 ctdb/config/ctdb.sudoers                           |    4 +-
 ctdb/config/ctdbd_wrapper                          |   74 +-
 ctdb/config/debug-hung-script.sh                   |    2 +-
 ctdb/config/debug_locks.sh                         |   24 +-
 ctdb/config/events.d/00.ctdb                       |   60 +-
 ctdb/config/events.d/05.system                     |  176 +
 ctdb/config/events.d/10.interface                  |  161 +-
 ctdb/config/events.d/11.natgw                      |   55 +-
 ctdb/config/events.d/13.per_ip_routing             |   44 +-
 ctdb/config/events.d/40.fs_use                     |   55 -
 ctdb/config/events.d/50.samba                      |   45 +-
 ctdb/config/events.d/60.nfs                        |    3 +
 ctdb/config/events.d/62.cnfs                       |   78 -
 ctdb/config/events.d/README                        |  271 +-
 ctdb/config/functions                              |  256 +-
 ctdb/config/nfs-linux-kernel-callout               |   32 +-
 ctdb/config/statd-callout                          |   15 +-
 ctdb/ctdb.pc.in                                    |   19 -
 ctdb/doc/ctdb-statistics.7                         |    4 +-
 ctdb/doc/ctdb-statistics.7.html                    |  134 +-
 ctdb/doc/ctdb-tunables.7                           |   19 +-
 ctdb/doc/ctdb-tunables.7.html                      |  124 +-
 ctdb/doc/ctdb-tunables.7.xml                       |   28 +-
 ctdb/doc/ctdb.1                                    |  231 +-
 ctdb/doc/ctdb.1.html                               |  351 +-
 ctdb/doc/ctdb.1.xml                                |  189 +-
 ctdb/doc/ctdb.7                                    |   50 +-
 ctdb/doc/ctdb.7.html                               |   97 +-
 ctdb/doc/ctdb.7.xml                                |   71 +-
 ctdb/doc/ctdbd.1                                   |   39 +-
 ctdb/doc/ctdbd.1.html                              |   45 +-
 ctdb/doc/ctdbd.1.xml                               |   44 +-
 ctdb/doc/ctdbd.conf.5                              |  161 +-
 ctdb/doc/ctdbd.conf.5.html                         |  240 +-
 ctdb/doc/ctdbd.conf.5.xml                          |  228 +-
 ctdb/doc/ctdbd_wrapper.1                           |    4 +-
 ctdb/doc/ctdbd_wrapper.1.html                      |    4 +-
 ctdb/doc/ltdbtool.1                                |    4 +-
 ctdb/doc/ltdbtool.1.html                           |   10 +-
 ctdb/doc/onnode.1                                  |   39 +-
 ctdb/doc/onnode.1.html                             |   43 +-
 ctdb/doc/onnode.1.xml                              |   37 +-
 ctdb/doc/ping_pong.1                               |    4 +-
 ctdb/doc/ping_pong.1.html                          |    8 +-
 ctdb/ib/ibw_ctdb.c                                 |   41 +-
 ctdb/ib/ibw_ctdb.h                                 |    5 +-
 ctdb/ib/ibw_ctdb_init.c                            |   26 +-
 ctdb/ib/ibwrapper.c                                |   46 +-
 ctdb/ib/ibwrapper.h                                |    2 +-
 ctdb/ib/ibwrapper_internal.h                       |    6 +-
 ctdb/ib/ibwrapper_test.c                           |   68 +-
 ctdb/include/common/srvid.h                        |    1 +
 ctdb/include/ctdb.h                                | 1236 -------
 ctdb/include/ctdb_client.h                         |  839 +++--
 ctdb/include/ctdb_logging.h                        |   54 -
 ctdb/include/ctdb_private.h                        | 1375 +++-----
 ctdb/include/ctdb_protocol.h                       |  700 +---
 ctdb/include/ctdb_typesafe_cb.h                    |  177 -
 ctdb/include/internal/cmdline.h                    |   10 -
 ctdb/include/internal/includes.h                   |   24 -
 ctdb/include/public/util/README.txt                |    6 +
 ctdb/packaging/RPM/ctdb.spec.in                    |   47 +-
 ctdb/packaging/mkversion.sh                        |   13 +-
 ctdb/protocol/protocol.h                           | 1022 ++++++
 ctdb/protocol/protocol_api.h                       |  669 ++++
 ctdb/protocol/protocol_call.c                      |  446 +++
 ctdb/protocol/protocol_client.c                    | 2470 +++++++++++++
 ctdb/protocol/protocol_control.c                   | 2087 +++++++++++
 ctdb/protocol/protocol_header.c                    |   73 +
 ctdb/protocol/protocol_message.c                   |  395 +++
 ctdb/protocol/protocol_packet.c                    |   44 +
 ctdb/protocol/protocol_private.h                   |  279 ++
 ctdb/protocol/protocol_types.c                     | 2575 ++++++++++++++
 ctdb/protocol/protocol_util.c                      |  142 +
 ctdb/server/ctdb_banning.c                         |   93 +-
 ctdb/server/ctdb_call.c                            |  217 +-
 ctdb/server/ctdb_control.c                         |  160 +-
 ctdb/server/ctdb_daemon.c                          |  232 +-
 ctdb/server/ctdb_event_helper.c                    |    9 +-
 ctdb/server/ctdb_fork.c                            |  174 +
 ctdb/server/ctdb_freeze.c                          |  852 ++++-
 ctdb/server/ctdb_keepalive.c                       |   35 +-
 ctdb/server/ctdb_lock.c                            |  139 +-
 ctdb/server/ctdb_lock_helper.c                     |    9 +-
 ctdb/server/ctdb_logging.c                         |   36 +-
 ctdb/server/ctdb_logging_file.c                    |   14 +-
 ctdb/server/ctdb_logging_syslog.c                  |    6 +-
 ctdb/server/ctdb_ltdb_server.c                     |   94 +-
 ctdb/server/ctdb_monitor.c                         |  154 +-
 ctdb/server/ctdb_persistent.c                      |   43 +-
 ctdb/server/ctdb_recover.c                         |  182 +-
 ctdb/server/ctdb_recoverd.c                        | 1403 ++++----
 ctdb/server/ctdb_recovery_helper.c                 | 1888 ++++++++++
 ctdb/server/ctdb_server.c                          |   29 +-
 ctdb/server/ctdb_serverids.c                       |   45 +-
 ctdb/server/ctdb_statistics.c                      |   35 +-
 ctdb/server/ctdb_takeover.c                        | 1754 +++------
 ctdb/server/ctdb_traverse.c                        |   69 +-
 ctdb/server/ctdb_tunables.c                        |  136 +-
 ctdb/server/ctdb_update_record.c                   |   49 +-
 ctdb/server/ctdb_uptime.c                          |   14 +-
 ctdb/server/ctdb_vacuum.c                          |  118 +-
 ctdb/server/ctdbd.c                                |   45 +-
 ctdb/server/eventscript.c                          |  104 +-
 ctdb/server/ipalloc.c                              |   53 +
 ctdb/server/ipalloc.h                              |   63 +
 ctdb/server/ipalloc_common.c                       |  206 ++
 ctdb/server/ipalloc_deterministic.c                |   62 +
 ctdb/server/ipalloc_lcp2.c                         |  515 +++
 ctdb/server/ipalloc_nondeterministic.c             |  147 +
 ctdb/server/ipalloc_private.h                      |   43 +
 ctdb/tcp/ctdb_tcp.h                                |    6 +-
 ctdb/tcp/tcp_connect.c                             |   60 +-
 ctdb/tcp/tcp_init.c                                |   28 +-
 ctdb/tcp/tcp_io.c                                  |   14 +-
 ctdb/tests/complex/18_ctdb_reloadips.sh            |    6 +-
 ctdb/tests/cunit/comm_test_001.sh                  |    7 +
 ctdb/tests/cunit/comm_test_002.sh                  |   24 +
 ctdb/tests/cunit/db_hash_test_001.sh               |    7 +
 ctdb/tests/cunit/pkt_read_001.sh                   |    7 +
 ctdb/tests/cunit/pkt_write_001.sh                  |    7 +
 ctdb/tests/cunit/protocol_test_001.sh              |    9 +
 ctdb/tests/cunit/protocol_test_002.sh              |   36 +
 ctdb/tests/cunit/reqid_test_001.sh                 |   13 +
 ctdb/tests/cunit/srvid_test_001.sh                 |    7 +
 ctdb/tests/eventscripts/00.ctdb.monitor.001.sh     |   15 -
 ctdb/tests/eventscripts/00.ctdb.monitor.002.sh     |   15 -
 ctdb/tests/eventscripts/00.ctdb.monitor.003.sh     |   19 -
 ctdb/tests/eventscripts/00.ctdb.monitor.004.sh     |   17 -
 ctdb/tests/eventscripts/00.ctdb.monitor.005.sh     |   21 -
 ctdb/tests/eventscripts/05.system.monitor.001.sh   |   14 +
 ctdb/tests/eventscripts/05.system.monitor.002.sh   |   12 +
 ctdb/tests/eventscripts/05.system.monitor.003.sh   |   14 +
 ctdb/tests/eventscripts/05.system.monitor.004.sh   |   12 +
 ctdb/tests/eventscripts/05.system.monitor.005.sh   |   14 +
 ctdb/tests/eventscripts/05.system.monitor.006.sh   |   14 +
 ctdb/tests/eventscripts/05.system.monitor.007.sh   |   12 +
 ctdb/tests/eventscripts/05.system.monitor.011.sh   |   16 +
 ctdb/tests/eventscripts/05.system.monitor.012.sh   |   14 +
 ctdb/tests/eventscripts/05.system.monitor.013.sh   |   19 +
 ctdb/tests/eventscripts/05.system.monitor.014.sh   |   16 +
 ctdb/tests/eventscripts/05.system.monitor.015.sh   |   18 +
 ctdb/tests/eventscripts/05.system.monitor.016.sh   |   16 +
 ctdb/tests/eventscripts/05.system.monitor.017.sh   |   40 +
 ctdb/tests/eventscripts/05.system.monitor.018.sh   |  123 +
 .../tests/eventscripts/10.interface.monitor.015.sh |    2 +-
 .../tests/eventscripts/10.interface.monitor.016.sh |    2 +-
 ctdb/tests/eventscripts/11.natgw.005.sh            |   24 -
 ctdb/tests/eventscripts/11.natgw.041.sh            |    5 +-
 ctdb/tests/eventscripts/11.natgw.042.sh            |    5 +-
 ctdb/tests/eventscripts/11.natgw.051.sh            |   16 +
 ctdb/tests/eventscripts/11.natgw.052.sh            |   20 +
 ctdb/tests/eventscripts/11.natgw.053.sh            |   16 +
 ctdb/tests/eventscripts/11.natgw.054.sh            |   20 +
 ctdb/tests/eventscripts/13.per_ip_routing.023.sh   |   26 +
 ctdb/tests/eventscripts/50.samba.monitor.110.sh    |   20 +
 ctdb/tests/eventscripts/50.samba.monitor.111.sh    |   25 +
 ctdb/tests/eventscripts/50.samba.monitor.112.sh    |   13 +
 ctdb/tests/eventscripts/50.samba.monitor.113.sh    |   16 +
 ctdb/tests/eventscripts/scripts/local.sh           |  150 +-
 ctdb/tests/eventscripts/stubs/ctdb                 |   77 +-
 ctdb/tests/eventscripts/stubs/ctdb_natgw           |   34 +
 ctdb/tests/eventscripts/stubs/df                   |   38 +
 ctdb/tests/eventscripts/stubs/free                 |    9 -
 ctdb/tests/eventscripts/stubs/ip                   |   10 +
 ctdb/tests/eventscripts/stubs/ps                   |    2 +-
 ctdb/tests/eventscripts/stubs/testparm             |   38 +-
 ctdb/tests/eventscripts/stubs/timeout              |    8 +
 ctdb/tests/onnode/functions                        |    1 +
 ctdb/tests/run_tests.sh                            |    2 +-
 ctdb/tests/scripts/integration.bash                |   30 +-
 ctdb/tests/simple/06_ctdb_getpid.sh                |   10 +-
 ctdb/tests/simple/11_ctdb_ip.sh                    |    4 +-
 ctdb/tests/simple/12_ctdb_getdebug.sh              |   10 +-
 ctdb/tests/simple/13_ctdb_setdebug.sh              |   16 +-
 ctdb/tests/simple/14_ctdb_statistics.sh            |    7 +-
 ctdb/tests/simple/16_ctdb_config_add_ip.sh         |    2 +-
 ctdb/tests/simple/20_delip_iface_gc.sh             |    2 +-
 ctdb/tests/simple/23_ctdb_moveip.sh                |    4 +-
 ctdb/tests/simple/25_dumpmemory.sh                 |   17 -
 ctdb/tests/simple/35_set_reclock.sh                |  124 +
 ctdb/tests/simple/35_set_recmaster.sh              |  117 -
 ctdb/tests/simple/60_recoverd_missing_ip.sh        |    2 +-
 ctdb/tests/simple/functions                        |    1 +
 ctdb/tests/simple/scripts/local.bash               |    5 +
 ctdb/tests/simple/scripts/local_daemons.bash       |    3 +-
 ctdb/tests/src/comm_client_test.c                  |  216 ++
 ctdb/tests/src/comm_server_test.c                  |  367 ++
 ctdb/tests/src/comm_test.c                         |  260 ++
 ctdb/tests/src/ctdb_bench.c                        |  120 +-
 ctdb/tests/src/ctdb_fetch.c                        |   96 +-
 ctdb/tests/src/ctdb_fetch_one.c                    |   28 +-
 ctdb/tests/src/ctdb_fetch_readonly_loop.c          |   26 +-
 ctdb/tests/src/ctdb_fetch_readonly_once.c          |   24 +-
 ctdb/tests/src/ctdb_lock_tdb.c                     |    6 +-
 ctdb/tests/src/ctdb_persistent.c                   |   39 +-
 ctdb/tests/src/ctdb_porting_tests.c                |   40 +-
 ctdb/tests/src/ctdb_randrec.c                      |   26 +-
 ctdb/tests/src/ctdb_store.c                        |   29 +-
 ctdb/tests/src/ctdb_takeover_tests.c               |  198 +-
 ctdb/tests/src/ctdb_test.c                         |   20 +-
 ctdb/tests/src/ctdb_test_stubs.c                   |   47 +-
 ctdb/tests/src/ctdb_trackingdb_test.c              |   21 +-
 ctdb/tests/src/ctdb_transaction.c                  |   38 +-
 ctdb/tests/src/ctdb_traverse.c                     |   33 +-
 ctdb/tests/src/ctdb_update_record.c                |   25 +-
 ctdb/tests/src/ctdb_update_record_persistent.c     |   28 +-
 ctdb/tests/src/ctdbd_test.c                        |   25 +-
 ctdb/tests/src/db_hash_test.c                      |  101 +
 ctdb/tests/src/pkt_read_test.c                     |  242 ++
 ctdb/tests/src/pkt_write_test.c                    |  370 ++
 ctdb/tests/src/protocol_client_test.c              | 2353 ++++++++++++
 ctdb/tests/src/protocol_types_test.c               | 1287 +++++++
 ctdb/tests/src/rb_test.c                           |   19 +-
 ctdb/tests/src/reqid_test.c                        |   72 +
 ctdb/tests/src/srvid_test.c                        |   78 +
 ctdb/tests/takeover/scripts/local.sh               |    2 +-
 ctdb/tests/takeover/simulation/ctdb_takeover.py    |    4 +-
 ctdb/tests/test_check_tcp_ports.sh                 |    3 +-
 ctdb/tests/tool/scripts/local.sh                   |   38 +-
 ctdb/tests/tool/stubby.getcapabilities.001.sh      |    1 -
 ctdb/tests/tool/stubby.getcapabilities.002.sh      |    1 -
 ctdb/tests/tool/stubby.getcapabilities.004.sh      |    5 +-
 ctdb/tests/tool/stubby.natgwlist.006.sh            |    6 +-
 ctdb/tests/tool/stubby.natgwlist.007.sh            |   14 +-
 ctdb/tests/tool/stubby.natgwlist.009.sh            |   36 -
 ctdb/tests/tool/stubby.natgwlist.010.sh            |   37 -
 ctdb/tests/tool/stubby.nodestatus.002.sh           |    8 +-
 ctdb/tests/tool/stubby.nodestatus.003.sh           |   30 -
 ctdb/tests/tool/stubby.nodestatus.004.sh           |   31 -
 ctdb/tests/tool/stubby.nodestatus.005.sh           |   34 -
 ctdb/tests/tool/stubs/ctdb                         |   27 +
 ctdb/tools/ctdb.c                                  |  568 ++-
 ctdb/tools/ctdb_diagnostics                        |   18 +-
 ctdb/tools/ctdb_natgw                              |  199 ++
 ctdb/tools/ctdb_vacuum.c                           |  193 -
 ctdb/tools/ltdbtool.c                              |   21 +-
 ctdb/tools/onnode                                  |   17 +-
 ctdb/utils/ping_pong/ping_pong.c                   |   65 +-
 ctdb/utils/pmda/pmda_ctdb.c                        |   22 +-
 ctdb/utils/smnotify/smnotify.c                     |    2 +-
 ctdb/web/iscsi.html                                |    2 +-
 ctdb/web/testing.html                              |    4 +-
 ctdb/wscript                                       |  328 +-
 dfs_server/dfs_server_ad.c                         |    1 +
 docs-xml/Samba3-HOWTO/TOSHARG-Passdb.xml           |    2 +-
 docs-xml/archives/THANKS                           |    2 +-
 docs-xml/build/DTD/samba-doc                       |    4 +
 docs-xml/manpages/cifsdd.8.xml                     |  101 +
 docs-xml/manpages/dbwrap_tool.1.xml                |    2 +-
 docs-xml/manpages/eventlogadm.8.xml                |    2 +-
 docs-xml/manpages/findsmb.1.xml                    |    2 +-
 docs-xml/manpages/idmap_ad.8.xml                   |    2 +-
 docs-xml/manpages/idmap_autorid.8.xml              |   17 +-
 docs-xml/manpages/idmap_hash.8.xml                 |    2 +-
 docs-xml/manpages/idmap_ldap.8.xml                 |    2 +-
 docs-xml/manpages/idmap_nss.8.xml                  |    2 +-
 docs-xml/manpages/idmap_rfc2307.8.xml              |   17 +-
 docs-xml/manpages/idmap_rid.8.xml                  |    2 +-
 docs-xml/manpages/idmap_script.8.xml               |    2 +-
 docs-xml/manpages/idmap_tdb.8.xml                  |    2 +-
 docs-xml/manpages/idmap_tdb2.8.xml                 |    2 +-
 docs-xml/manpages/libsmbclient.7.xml               |    2 +-
 docs-xml/manpages/lmhosts.5.xml                    |    2 +-
 docs-xml/manpages/log2pcap.1.xml                   |    2 +-
 docs-xml/manpages/net.8.xml                        |   24 +-
 docs-xml/manpages/nmbd.8.xml                       |    2 +-
 docs-xml/manpages/nmblookup.1.xml                  |    2 +-
 docs-xml/manpages/ntlm_auth.1.xml                  |    8 +-
 docs-xml/manpages/pam_winbind.8.xml                |    4 +-
 docs-xml/manpages/pam_winbind.conf.5.xml           |    4 +-
 docs-xml/manpages/pdbedit.8.xml                    |   24 +-
 docs-xml/manpages/profiles.1.xml                   |    2 +-
 docs-xml/manpages/rpcclient.1.xml                  |    2 +-
 docs-xml/manpages/samba-regedit.8.xml              |    2 +-
 docs-xml/manpages/samba-tool.8.xml                 |    2 +-
 docs-xml/manpages/samba.7.xml                      |    2 +-
 docs-xml/manpages/samba.8.xml                      |    2 +-
 docs-xml/manpages/sharesec.1.xml                   |    2 +-
 docs-xml/manpages/smb.conf.5.xml                   |    2 +-
 docs-xml/manpages/smbcacls.1.xml                   |    2 +-
 docs-xml/manpages/smbclient.1.xml                  |    2 +-
 docs-xml/manpages/smbcontrol.1.xml                 |    2 +-
 docs-xml/manpages/smbcquotas.1.xml                 |    2 +-
 docs-xml/manpages/smbd.8.xml                       |   10 +-
 docs-xml/manpages/smbget.1.xml                     |   24 +-
 docs-xml/manpages/smbgetrc.5.xml                   |   10 +-
 docs-xml/manpages/smbpasswd.5.xml                  |    2 +-
 docs-xml/manpages/smbpasswd.8.xml                  |    2 +-
 docs-xml/manpages/smbspool.8.xml                   |    7 +-
 docs-xml/manpages/smbstatus.1.xml                  |    2 +-
 docs-xml/manpages/smbta-util.8.xml                 |  115 -
 docs-xml/manpages/smbtar.1.xml                     |    2 +-
 docs-xml/manpages/smbtree.1.xml                    |    2 +-
 docs-xml/manpages/testparm.1.xml                   |    2 +-
 docs-xml/manpages/vfs_acl_tdb.8.xml                |    2 +-
 docs-xml/manpages/vfs_acl_xattr.8.xml              |    2 +-
 docs-xml/manpages/vfs_aio_fork.8.xml               |    2 +-
 docs-xml/manpages/vfs_aio_linux.8.xml              |    2 +-
 docs-xml/manpages/vfs_aio_pthread.8.xml            |    2 +-
 docs-xml/manpages/vfs_audit.8.xml                  |    2 +-
 docs-xml/manpages/vfs_btrfs.8.xml                  |    2 +-
 docs-xml/manpages/vfs_cacheprime.8.xml             |    2 +-
 docs-xml/manpages/vfs_cap.8.xml                    |    2 +-
 docs-xml/manpages/vfs_catia.8.xml                  |    2 +-
 docs-xml/manpages/vfs_ceph.8.xml                   |    4 +-
 docs-xml/manpages/vfs_commit.8.xml                 |    2 +-
 docs-xml/manpages/vfs_crossrename.8.xml            |    2 +-
 docs-xml/manpages/vfs_default_quota.8.xml          |    2 +-
 docs-xml/manpages/vfs_dirsort.8.xml                |    2 +-
 docs-xml/manpages/vfs_extd_audit.8.xml             |    2 +-
 docs-xml/manpages/vfs_fake_perms.8.xml             |    2 +-
 docs-xml/manpages/vfs_fileid.8.xml                 |    2 +-
 docs-xml/manpages/vfs_fruit.8.xml                  |    2 +-
 docs-xml/manpages/vfs_full_audit.8.xml             |    2 +-
 docs-xml/manpages/vfs_glusterfs.8.xml              |    2 +-
 docs-xml/manpages/vfs_gpfs.8.xml                   |    2 +-
 docs-xml/manpages/vfs_linux_xfs_sgid.8.xml         |    2 +-
 docs-xml/manpages/vfs_media_harmony.8.xml          |    2 +-
 docs-xml/manpages/vfs_netatalk.8.xml               |    2 +-
 docs-xml/manpages/vfs_offline.8.xml                |   72 +
 docs-xml/manpages/vfs_prealloc.8.xml               |    2 +-
 docs-xml/manpages/vfs_preopen.8.xml                |    2 +-
 docs-xml/manpages/vfs_readahead.8.xml              |    2 +-
 docs-xml/manpages/vfs_readonly.8.xml               |    2 +-
 docs-xml/manpages/vfs_recycle.8.xml                |    2 +-
 docs-xml/manpages/vfs_scannedonly.8.xml            |  243 --
 docs-xml/manpages/vfs_shadow_copy.8.xml            |    2 +-
 docs-xml/manpages/vfs_shadow_copy2.8.xml           |   50 +-
 docs-xml/manpages/vfs_shell_snap.8.xml             |    2 +-
 docs-xml/manpages/vfs_smb_traffic_analyzer.8.xml   |  299 --
 docs-xml/manpages/vfs_snapper.8.xml                |    2 +-
 docs-xml/manpages/vfs_streams_depot.8.xml          |    2 +-
 docs-xml/manpages/vfs_streams_xattr.8.xml          |    2 +-
 docs-xml/manpages/vfs_syncops.8.xml                |    2 +-
 docs-xml/manpages/vfs_time_audit.8.xml             |    2 +-
 docs-xml/manpages/vfs_tsmsm.8.xml                  |    2 +-
 docs-xml/manpages/vfs_unityed_media.8.xml          |    2 +-
 docs-xml/manpages/vfs_worm.8.xml                   |    2 +-
 docs-xml/manpages/vfs_xattr_tdb.8.xml              |    2 +-
 docs-xml/manpages/vfs_zfsacl.8.xml                 |    2 +-
 docs-xml/manpages/vfstest.1.xml                    |    2 +-
 docs-xml/manpages/wbinfo.1.xml                     |    4 +-
 docs-xml/manpages/winbind_krb5_locator.7.xml       |    2 +-
 docs-xml/manpages/winbindd.8.xml                   |    2 +-
 docs-xml/smbdotconf/base/bindinterfacesonly.xml    |    2 +-
 docs-xml/smbdotconf/base/comment.xml               |    2 +-
 docs-xml/smbdotconf/base/configbackend.xml         |    3 +-
 docs-xml/smbdotconf/base/doscharset.xml            |    5 +-
 docs-xml/smbdotconf/base/interfaces.xml            |   25 +-
 docs-xml/smbdotconf/base/multicastdnsregister.xml  |    2 +-
 docs-xml/smbdotconf/base/netbiosaliases.xml        |    3 +-
 docs-xml/smbdotconf/base/netbiosname.xml           |    2 +-
 docs-xml/smbdotconf/base/netbiosscope.xml          |    2 +-
 docs-xml/smbdotconf/base/realm.xml                 |    3 +-
 docs-xml/smbdotconf/base/sharebackend.xml          |    2 +-
 docs-xml/smbdotconf/base/unixcharset.xml           |    5 +-
 docs-xml/smbdotconf/base/workgroup.xml             |    2 +-
 docs-xml/smbdotconf/browse/browseable.xml          |    4 +-
 docs-xml/smbdotconf/browse/browselist.xml          |    2 +-
 docs-xml/smbdotconf/browse/domainmaster.xml        |    3 +-
 docs-xml/smbdotconf/browse/enhancedbrowsing.xml    |    2 +-
 docs-xml/smbdotconf/browse/lmannounce.xml          |    3 +-
 docs-xml/smbdotconf/browse/lminterval.xml          |    2 +-
 docs-xml/smbdotconf/browse/oslevel.xml             |    2 +-
 docs-xml/smbdotconf/browse/preferredmaster.xml     |    5 +-
 docs-xml/smbdotconf/domain/allowdnsupdates.xml     |    1 +
 docs-xml/smbdotconf/domain/dnsupdatecommand.xml    |    2 +-
 .../smbdotconf/domain/machinepasswordtimeout.xml   |   13 +-
 docs-xml/smbdotconf/domain/nsupdatecommand.xml     |    2 +-
 docs-xml/smbdotconf/domain/rndccommand.xml         |    2 +-
 docs-xml/smbdotconf/domain/spnupdatecommand.xml    |    2 +-
 docs-xml/smbdotconf/filename/casesensitive.xml     |    3 +-
 docs-xml/smbdotconf/filename/defaultcase.xml       |    6 +-
 docs-xml/smbdotconf/filename/deletevetofiles.xml   |    2 +-
 docs-xml/smbdotconf/filename/hidedotfiles.xml      |    2 +-
 docs-xml/smbdotconf/filename/hidespecialfiles.xml  |    2 +-
 docs-xml/smbdotconf/filename/hideunreadable.xml    |    2 +-
 .../smbdotconf/filename/hideunwriteablefiles.xml   |    2 +-
 docs-xml/smbdotconf/filename/manglednames.xml      |    2 +-
 docs-xml/smbdotconf/filename/mangleprefix.xml      |    2 +-
 docs-xml/smbdotconf/filename/manglingchar.xml      |    2 +-
 docs-xml/smbdotconf/filename/manglingmethod.xml    |    4 +-
 docs-xml/smbdotconf/filename/maparchive.xml        |    4 +-
 docs-xml/smbdotconf/filename/maphidden.xml         |    2 +-
 docs-xml/smbdotconf/filename/mapreadonly.xml       |    3 +-
 docs-xml/smbdotconf/filename/mapsystem.xml         |    2 +-
 docs-xml/smbdotconf/filename/maxstatcachesize.xml  |    2 +-
 docs-xml/smbdotconf/filename/preservecase.xml      |    2 +-
 docs-xml/smbdotconf/filename/shortpreservecase.xml |    2 +-
 docs-xml/smbdotconf/filename/statcache.xml         |    2 +-
 .../smbdotconf/filename/storedosattributes.xml     |    2 +-
 docs-xml/smbdotconf/filename/vetofiles.xml         |    2 +-
 docs-xml/smbdotconf/filename/vetooplockfiles.xml   |    2 +-
 .../smbdotconf/ldap/clientldapsaslwrapping.xml     |    3 +-
 docs-xml/smbdotconf/ldap/ldapadmindn.xml           |    4 +-
 docs-xml/smbdotconf/ldap/ldapconnectiontimeout.xml |    6 +-
 docs-xml/smbdotconf/ldap/ldapdeletedn.xml          |    2 +-
 docs-xml/smbdotconf/ldap/ldapderef.xml             |    7 +-
 docs-xml/smbdotconf/ldap/ldapfollowreferral.xml    |    7 +-
 docs-xml/smbdotconf/ldap/ldapgroupsuffix.xml       |    4 +-
 docs-xml/smbdotconf/ldap/ldapidmapsuffix.xml       |    4 +-
 docs-xml/smbdotconf/ldap/ldapmachinesuffix.xml     |    8 +-
 docs-xml/smbdotconf/ldap/ldappagesize.xml          |    8 +-
 docs-xml/smbdotconf/ldap/ldappasswdsync.xml        |    7 +-
 docs-xml/smbdotconf/ldap/ldapreplicationsleep.xml  |    2 +-
 docs-xml/smbdotconf/ldap/ldapsameditposix.xml      |    4 +-
 docs-xml/smbdotconf/ldap/ldapsamtrusted.xml        |    4 +-
 docs-xml/smbdotconf/ldap/ldapssl.xml               |    3 +-
 docs-xml/smbdotconf/ldap/ldapsslads.xml            |    6 +-
 docs-xml/smbdotconf/ldap/ldapsuffix.xml            |    2 +-
 docs-xml/smbdotconf/ldap/ldaptimeout.xml           |    2 +-
 docs-xml/smbdotconf/ldap/ldapusersuffix.xml        |    8 +-
 docs-xml/smbdotconf/locking/blockinglocks.xml      |    2 +-
 docs-xml/smbdotconf/locking/cscpolicy.xml          |    3 +-
 docs-xml/smbdotconf/locking/fakeoplocks.xml        |    2 +-
 docs-xml/smbdotconf/locking/kerneloplocks.xml      |    4 +-
 docs-xml/smbdotconf/locking/kernelsharemodes.xml   |    4 +-
 docs-xml/smbdotconf/locking/level2oplocks.xml      |    2 +-
 docs-xml/smbdotconf/locking/locking.xml            |    2 +-
 docs-xml/smbdotconf/locking/lockspintime.xml       |    2 +-
 .../smbdotconf/locking/oplockbreakwaittime.xml     |    2 +-
 .../smbdotconf/locking/oplockcontentionlimit.xml   |    2 +-
 docs-xml/smbdotconf/locking/oplocks.xml            |    2 +-
 docs-xml/smbdotconf/locking/posixlocking.xml       |    2 +-
 docs-xml/smbdotconf/locking/smb2leases.xml         |    2 +-
 docs-xml/smbdotconf/locking/strictlocking.xml      |    3 +-
 docs-xml/smbdotconf/logging/debugclass.xml         |    2 +-
 .../smbdotconf/logging/debughirestimestamp.xml     |    2 +-
 docs-xml/smbdotconf/logging/debugpid.xml           |    2 +-
 .../smbdotconf/logging/debugprefixtimestamp.xml    |    2 +-
 docs-xml/smbdotconf/logging/debugtimestamp.xml     |   15 -
 docs-xml/smbdotconf/logging/debuguid.xml           |    2 +-
 docs-xml/smbdotconf/logging/ldapdebuglevel.xml     |    7 +-
 docs-xml/smbdotconf/logging/ldapdebugthreshold.xml |    6 +-
 docs-xml/smbdotconf/logging/logfile.xml            |    3 +-
 docs-xml/smbdotconf/logging/logging.xml            |    6 +-
 docs-xml/smbdotconf/logging/loglevel.xml           |    5 +-
 docs-xml/smbdotconf/logging/maxlogsize.xml         |    2 +-
 docs-xml/smbdotconf/logging/syslog.xml             |    3 +-
 docs-xml/smbdotconf/logging/syslogonly.xml         |    3 +-
 docs-xml/smbdotconf/logging/timestamplogs.xml      |   14 +
 docs-xml/smbdotconf/logon/domainlogons.xml         |    2 +-
 docs-xml/smbdotconf/logon/enableprivileges.xml     |    3 +-
 .../smbdotconf/logon/initlogondelayedhosts.xml     |    2 +-
 docs-xml/smbdotconf/logon/logondrive.xml           |    2 +-
 docs-xml/smbdotconf/logon/logonhome.xml            |    2 +-
 docs-xml/smbdotconf/logon/logonpath.xml            |    2 +-
 docs-xml/smbdotconf/logon/logonscript.xml          |    2 +-
 docs-xml/smbdotconf/misc/addsharecommand.xml       |    2 +-
 docs-xml/smbdotconf/misc/afsshare.xml              |    6 +-
 docs-xml/smbdotconf/misc/afsusernamemap.xml        |    2 +-
 .../smbdotconf/misc/allowinsecurewidelinks.xml     |    6 +-
 docs-xml/smbdotconf/misc/asyncsmbechohandler.xml   |    2 +-
 docs-xml/smbdotconf/misc/auto_services.xml         |   21 +
 docs-xml/smbdotconf/misc/available.xml             |    6 +-
 docs-xml/smbdotconf/misc/cachedirectory.xml        |    4 +-
 docs-xml/smbdotconf/misc/changenotify.xml          |    2 +-
 docs-xml/smbdotconf/misc/changesharecommand.xml    |    2 +-
 docs-xml/smbdotconf/misc/clusteraddresses.xml      |    6 +-
 docs-xml/smbdotconf/misc/clustering.xml            |    2 +-
 docs-xml/smbdotconf/misc/configfile.xml            |    2 +-
 docs-xml/smbdotconf/misc/copy.xml                  |    1 +
 .../smbdotconf/misc/ctdblocktimewarnthreshold.xml  |    2 +-
 docs-xml/smbdotconf/misc/ctdbtimeout.xml           |    2 +-
 docs-xml/smbdotconf/misc/defaultservice.xml        |    2 +-
 docs-xml/smbdotconf/misc/deletereadonly.xml        |    6 +-
 docs-xml/smbdotconf/misc/deletesharecommand.xml    |    2 +-
 docs-xml/smbdotconf/misc/dfreecachetime.xml        |    6 +-
 .../smbdotconf/misc/directorynamecachesize.xml     |    6 +-
 docs-xml/smbdotconf/misc/dmapisupport.xml          |    2 +-
 docs-xml/smbdotconf/misc/dontdescend.xml           |    6 +-
 docs-xml/smbdotconf/misc/dosfilemode.xml           |    6 +-
 docs-xml/smbdotconf/misc/dosfiletimeresolution.xml |    6 +-
 docs-xml/smbdotconf/misc/dosfiletimes.xml          |    8 +-
 .../smbdotconf/misc/fakedirectorycreatetimes.xml   |    6 +-
 docs-xml/smbdotconf/misc/followsymlinks.xml        |    6 +-
 docs-xml/smbdotconf/misc/fssprunestale.xml         |    2 +-
 docs-xml/smbdotconf/misc/fsssequencetimeout.xml    |    2 +-
 docs-xml/smbdotconf/misc/fstype.xml                |    6 +-
 docs-xml/smbdotconf/misc/homedirmap.xml            |    6 +-
 docs-xml/smbdotconf/misc/include.xml               |    7 +-
 docs-xml/smbdotconf/misc/kernelchangenotify.xml    |    2 +-
 docs-xml/smbdotconf/misc/lockdirectory.xml         |    2 +-
 .../smbdotconf/misc/logwriteablefilesonexit.xml    |    6 +-
 docs-xml/smbdotconf/misc/magicoutput.xml           |    6 +-
 docs-xml/smbdotconf/misc/magicscript.xml           |    6 +-
 docs-xml/smbdotconf/misc/messagecommand.xml        |    6 +-
 .../smbdotconf/misc/nbtclientsocketaddress.xml     |    7 +-
 docs-xml/smbdotconf/misc/ncalrpcdir.xml            |    6 +-
 docs-xml/smbdotconf/misc/nishomedir.xml            |    6 +-
 .../smbdotconf/misc/nmbdbindexplicitbroadcast.xml  |    6 +-
 docs-xml/smbdotconf/misc/panicaction.xml           |    6 +-
 docs-xml/smbdotconf/misc/perfcountmodule.xml       |    6 +-
 docs-xml/smbdotconf/misc/piddirectory.xml          |    2 +-
 docs-xml/smbdotconf/misc/postexec.xml              |    6 +-
 docs-xml/smbdotconf/misc/preexec.xml               |    8 +-
 docs-xml/smbdotconf/misc/preload.xml               |   22 -
 docs-xml/smbdotconf/misc/registryshares.xml        |    2 +-
 docs-xml/smbdotconf/misc/remoteannounce.xml        |    6 +-
 docs-xml/smbdotconf/misc/remotebrowsesync.xml      |    6 +-
 docs-xml/smbdotconf/misc/resetonzerovc.xml         |    6 +-
 docs-xml/smbdotconf/misc/rootpostexec.xml          |    6 +-
 docs-xml/smbdotconf/misc/rootpreexec.xml           |    6 +-
 docs-xml/smbdotconf/misc/rootpreexecclose.xml      |    6 +-
 docs-xml/smbdotconf/misc/rpcdaemon.xml             |    4 +-
 docs-xml/smbdotconf/misc/rpcserver.xml             |    4 +-
 docs-xml/smbdotconf/misc/smbdprofilinglevel.xml    |    7 +-
 docs-xml/smbdotconf/misc/statedirectory.xml        |    4 +-
 docs-xml/smbdotconf/misc/usershareallowguests.xml  |    6 +-
 docs-xml/smbdotconf/misc/usersharemaxshares.xml    |    6 +-
 docs-xml/smbdotconf/misc/usershareowneronly.xml    |    6 +-
 docs-xml/smbdotconf/misc/usersharepath.xml         |    6 +-
 .../smbdotconf/misc/usershareprefixallowlist.xml   |    6 +-
 .../smbdotconf/misc/usershareprefixdenylist.xml    |    6 +-
 .../smbdotconf/misc/usersharetemplateshare.xml     |    6 +-
 docs-xml/smbdotconf/misc/utmpdirectory.xml         |    2 +-
 docs-xml/smbdotconf/misc/valid.xml                 |    7 +-
 docs-xml/smbdotconf/misc/volume.xml                |    6 +-
 docs-xml/smbdotconf/misc/widelinks.xml             |    7 +-
 docs-xml/smbdotconf/misc/wtmpdirectory.xml         |    2 +-
 docs-xml/smbdotconf/printing/addportcommand.xml    |    2 +-
 docs-xml/smbdotconf/printing/addprintercommand.xml |    2 +-
 docs-xml/smbdotconf/printing/cupsencrypt.xml       |    8 +-
 docs-xml/smbdotconf/printing/cupsoptions.xml       |    2 +-
 docs-xml/smbdotconf/printing/cupsserver.xml        |    2 +-
 docs-xml/smbdotconf/printing/defaultdevmode.xml    |    2 +-
 .../smbdotconf/printing/deleteprintercommand.xml   |    2 +-
 docs-xml/smbdotconf/printing/disablespoolss.xml    |    2 +-
 docs-xml/smbdotconf/printing/enablespoolss.xml     |    3 +-
 docs-xml/smbdotconf/printing/enumportscommand.xml  |    2 +-
 docs-xml/smbdotconf/printing/forceprintername.xml  |    2 +-
 docs-xml/smbdotconf/printing/iprintserver.xml      |    2 +-
 docs-xml/smbdotconf/printing/loadprinters.xml      |    2 +-
 docs-xml/smbdotconf/printing/lppausecommand.xml    |    2 +-
 docs-xml/smbdotconf/printing/lpqcachetime.xml      |    6 +-
 docs-xml/smbdotconf/printing/lpqcommand.xml        |    2 +-
 docs-xml/smbdotconf/printing/lpresumecommand.xml   |    2 +-
 docs-xml/smbdotconf/printing/lprmcommand.xml       |    2 +-
 docs-xml/smbdotconf/printing/maxprintjobs.xml      |    3 +-
 .../smbdotconf/printing/maxreportedprintjobs.xml   |    2 +-
 docs-xml/smbdotconf/printing/os2drivermap.xml      |    2 +-
 docs-xml/smbdotconf/printing/printable.xml         |    2 +-
 docs-xml/smbdotconf/printing/printcapcachetime.xml |    4 +-
 docs-xml/smbdotconf/printing/printcapname.xml      |    6 +-
 docs-xml/smbdotconf/printing/printcommand.xml      |    2 +-
 docs-xml/smbdotconf/printing/printername.xml       |    2 +-
 docs-xml/smbdotconf/printing/printing.xml          |    4 +-
 docs-xml/smbdotconf/printing/printjobusername.xml  |    2 +-
 .../smbdotconf/printing/printnotifybackchannel.xml |    6 +-
 docs-xml/smbdotconf/printing/queuepausecommand.xml |    2 +-
 .../smbdotconf/printing/queueresumecommand.xml     |    2 +-
 .../smbdotconf/printing/showaddprinterwizard.xml   |    2 +-
 .../smbdotconf/printing/spoolssarchitecture.xml    |    6 +-
 docs-xml/smbdotconf/printing/spoolssosversion.xml  |    6 +-
 docs-xml/smbdotconf/printing/useclientdriver.xml   |    2 +-
 .../smbdotconf/protocol/aclcheckpermissions.xml    |    3 +-
 docs-xml/smbdotconf/protocol/aclmapfullcontrol.xml |    6 +-
 docs-xml/smbdotconf/protocol/cldapport.xml         |    2 +-
 docs-xml/smbdotconf/protocol/clientmaxprotocol.xml |    9 +-
 docs-xml/smbdotconf/protocol/clientminprotocol.xml |    7 +-
 docs-xml/smbdotconf/protocol/clientusespnego.xml   |    2 +-
 .../smbdotconf/protocol/dcerpcendpointservers.xml  |    2 +-
 .../smbdotconf/protocol/defersharingviolations.xml |    2 +-
 docs-xml/smbdotconf/protocol/dgramport.xml         |    2 +-
 docs-xml/smbdotconf/protocol/disablenetbios.xml    |    2 +-
 docs-xml/smbdotconf/protocol/easupport.xml         |    2 +-
 docs-xml/smbdotconf/protocol/enableasusupport.xml  |    6 +-
 docs-xml/smbdotconf/protocol/eventloglist.xml      |    2 +-
 docs-xml/smbdotconf/protocol/largereadwrite.xml    |    2 +-
 docs-xml/smbdotconf/protocol/mapaclinherit.xml     |    2 +-
 docs-xml/smbdotconf/protocol/maxmux.xml            |    2 +-
 docs-xml/smbdotconf/protocol/maxttl.xml            |    2 +-
 docs-xml/smbdotconf/protocol/maxwinsttl.xml        |    2 +-
 docs-xml/smbdotconf/protocol/maxxmit.xml           |    2 +-
 .../smbdotconf/protocol/minreceivefilesize.xml     |    7 +-
 docs-xml/smbdotconf/protocol/minwinsttl.xml        |    2 +-
 docs-xml/smbdotconf/protocol/nameresolveorder.xml  |    2 +-
 docs-xml/smbdotconf/protocol/nbtport.xml           |    2 +-
 docs-xml/smbdotconf/protocol/ntaclsupport.xml      |    2 +-
 docs-xml/smbdotconf/protocol/ntpipesupport.xml     |    2 +-
 docs-xml/smbdotconf/protocol/ntstatussupport.xml   |    2 +-
 docs-xml/smbdotconf/protocol/profileacls.xml       |    2 +-
 docs-xml/smbdotconf/protocol/readraw.xml           |    6 +-
 docs-xml/smbdotconf/protocol/rpcbigendian.xml      |    2 +-
 docs-xml/smbdotconf/protocol/servermaxprotocol.xml |    7 +-
 docs-xml/smbdotconf/protocol/serverminprotocol.xml |    7 +-
 .../protocol/servermultichannelsupport.xml         |   21 +
 docs-xml/smbdotconf/protocol/sharefakefscaps.xml   |    4 +-
 docs-xml/smbdotconf/protocol/smb2maxcredits.xml    |    8 +-
 docs-xml/smbdotconf/protocol/smb2maxread.xml       |    6 +-
 docs-xml/smbdotconf/protocol/smb2maxtrans.xml      |    6 +-
 docs-xml/smbdotconf/protocol/smb2maxwrite.xml      |    6 +-
 docs-xml/smbdotconf/protocol/smbports.xml          |    3 +-
 docs-xml/smbdotconf/protocol/svcctllist.xml        |    2 +-
 docs-xml/smbdotconf/protocol/timeserver.xml        |    2 +-
 docs-xml/smbdotconf/protocol/unicode.xml           |    2 +-
 docs-xml/smbdotconf/protocol/unixextensions.xml    |    2 +-
 docs-xml/smbdotconf/protocol/usespnego.xml         |    3 +-
 docs-xml/smbdotconf/protocol/webport.xml           |    2 +-
 docs-xml/smbdotconf/protocol/writeraw.xml          |    6 +-
 .../smbdotconf/security/accessbasedshareenum.xml   |    4 +-
 docs-xml/smbdotconf/security/aclgroupcontrol.xml   |    2 +-
 docs-xml/smbdotconf/security/adminusers.xml        |    2 +-
 .../smbdotconf/security/algorithmicridbase.xml     |    4 +-
 .../smbdotconf/security/allowtrusteddomains.xml    |    4 +-
 docs-xml/smbdotconf/security/authmethods.xml       |    4 +-
 .../smbdotconf/security/checkpasswordscript.xml    |    2 +-
 docs-xml/smbdotconf/security/clientlanmanauth.xml  |    2 +-
 docs-xml/smbdotconf/security/clientntlmv2auth.xml  |    2 +-
 .../smbdotconf/security/clientplaintextauth.xml    |    4 +-
 docs-xml/smbdotconf/security/clientschannel.xml    |    5 +-
 docs-xml/smbdotconf/security/clientsigning.xml     |    5 +-
 .../security/clientusepsnegoprincipal.xml          |    3 +-
 docs-xml/smbdotconf/security/createmask.xml        |    2 +-
 .../smbdotconf/security/dedicatedkeytabfile.xml    |    4 +-
 docs-xml/smbdotconf/security/directorymask.xml     |    4 +-
 .../smbdotconf/security/directorysecuritymask.xml  |    8 +-
 docs-xml/smbdotconf/security/encryptpasswords.xml  |    4 +-
 docs-xml/smbdotconf/security/forcecreatemode.xml   |    2 +-
 .../smbdotconf/security/forcedirectorymode.xml     |    2 +-
 .../security/forcedirectorysecuritymode.xml        |    8 +-
 docs-xml/smbdotconf/security/forcegroup.xml        |    2 +-
 .../smbdotconf/security/forceunknownacluser.xml    |    2 +-
 docs-xml/smbdotconf/security/forceuser.xml         |    2 +-
 docs-xml/smbdotconf/security/guestaccount.xml      |    4 +-
 docs-xml/smbdotconf/security/guestok.xml           |    4 +-
 docs-xml/smbdotconf/security/guestonly.xml         |    2 +-
 docs-xml/smbdotconf/security/hostsallow.xml        |    2 +-
 docs-xml/smbdotconf/security/hostsdeny.xml         |    2 +-
 docs-xml/smbdotconf/security/inheritacls.xml       |    2 +-
 docs-xml/smbdotconf/security/inheritowner.xml      |    2 +-
 .../smbdotconf/security/inheritpermissions.xml     |    2 +-
 docs-xml/smbdotconf/security/invalidusers.xml      |    2 +-
 docs-xml/smbdotconf/security/kerberosmethod.xml    |    5 +-
 docs-xml/smbdotconf/security/kpasswdport.xml       |    2 +-
 docs-xml/smbdotconf/security/krb5port.xml          |    2 +-
 docs-xml/smbdotconf/security/lanmanauth.xml        |    4 +-
 docs-xml/smbdotconf/security/maptoguest.xml        |    5 +-
 .../smbdotconf/security/mapuntrustedtodomain.xml   |    4 +-
 docs-xml/smbdotconf/security/ntlmauth.xml          |    2 +-
 docs-xml/smbdotconf/security/nullpasswords.xml     |    5 +-
 .../smbdotconf/security/obeypamrestrictions.xml    |    4 +-
 .../security/oldpasswordallowedperiod.xml          |    4 +-
 docs-xml/smbdotconf/security/onlyuser.xml          |    3 +-
 docs-xml/smbdotconf/security/pampasswordchange.xml |    4 +-
 docs-xml/smbdotconf/security/passdbbackend.xml     |    4 +-
 .../smbdotconf/security/passdbexpandexplicit.xml   |    4 +-
 docs-xml/smbdotconf/security/passwdchatdebug.xml   |    2 +-
 docs-xml/smbdotconf/security/passwdchattimeout.xml |    2 +-
 docs-xml/smbdotconf/security/passwdprogram.xml     |    4 +-
 docs-xml/smbdotconf/security/passwordserver.xml    |    4 +-
 docs-xml/smbdotconf/security/preloadmodules.xml    |    6 +-
 docs-xml/smbdotconf/security/privatedir.xml        |    4 +-
 docs-xml/smbdotconf/security/readlist.xml          |    2 +-
 docs-xml/smbdotconf/security/readonly.xml          |    3 +-
 docs-xml/smbdotconf/security/renameuserscript.xml  |    4 +-
 docs-xml/smbdotconf/security/restrictanonymous.xml |    2 +-
 docs-xml/smbdotconf/security/rootdirectory.xml     |    6 +-
 docs-xml/smbdotconf/security/sambakcccommand.xml   |    2 +-
 docs-xml/smbdotconf/security/security.xml          |   11 +-
 docs-xml/smbdotconf/security/serverrole.xml        |   11 +-
 docs-xml/smbdotconf/security/serverschannel.xml    |    5 +-
 docs-xml/smbdotconf/security/serversigning.xml     |    5 +-
 docs-xml/smbdotconf/security/smbencrypt.xml        |    5 +-
 docs-xml/smbdotconf/security/smbpasswdfile.xml     |    4 +-
 docs-xml/smbdotconf/security/tlsdhparamsfile.xml   |    2 +-
 docs-xml/smbdotconf/security/unixpasswordsync.xml  |    2 +-
 docs-xml/smbdotconf/security/username.xml          |    5 +-
 docs-xml/smbdotconf/security/usernamelevel.xml     |    2 +-
 docs-xml/smbdotconf/security/usernamemap.xml       |    2 +-
 .../smbdotconf/security/usernamemapcachetime.xml   |    2 +-
 docs-xml/smbdotconf/security/usernamemapscript.xml |    2 +-
 docs-xml/smbdotconf/security/validusers.xml        |    2 +-
 docs-xml/smbdotconf/security/writeable.xml         |    4 +-
 docs-xml/smbdotconf/security/writelist.xml         |    2 +-
 docs-xml/smbdotconf/tuning/aiomaxthreads.xml       |   19 +
 docs-xml/smbdotconf/tuning/aioreadsize.xml         |    2 +-
 docs-xml/smbdotconf/tuning/aiowritesize.xml        |    2 +-
 .../smbdotconf/tuning/allocationroundupsize.xml    |    2 +-
 docs-xml/smbdotconf/tuning/blocksize.xml           |    2 +-
 docs-xml/smbdotconf/tuning/maxdisksize.xml         |    2 +-
 docs-xml/smbdotconf/tuning/strictrename.xml        |   15 +-
 docs-xml/smbdotconf/tuning/strictsync.xml          |    6 +-
 docs-xml/smbdotconf/tuning/writecachesize.xml      |    2 +-
 docs-xml/smbdotconf/vfs/vfsobjects.xml             |    2 +-
 docs-xml/smbdotconf/winbind/createkrb5conf.xml     |    4 +-
 docs-xml/smbdotconf/winbind/idmapbackend.xml       |    4 +-
 docs-xml/smbdotconf/winbind/idmapcachetime.xml     |    2 +-
 docs-xml/smbdotconf/winbind/idmapconfig.xml        |    2 +-
 docs-xml/smbdotconf/winbind/idmapgid.xml           |    6 +-
 .../smbdotconf/winbind/idmapnegativecachetime.xml  |    2 +-
 docs-xml/smbdotconf/winbind/idmapuid.xml           |    4 +-
 docs-xml/smbdotconf/winbind/templatehomedir.xml    |    2 +-
 docs-xml/smbdotconf/winbind/templateshell.xml      |    2 +-
 docs-xml/smbdotconf/winbind/winbindcachetime.xml   |    2 +-
 docs-xml/smbdotconf/winbind/winbindenumgroups.xml  |    2 +-
 .../smbdotconf/winbind/winbindexpandgroups.xml     |    2 +-
 docs-xml/smbdotconf/winbind/winbindmaxclients.xml  |    2 +-
 .../winbind/winbindmaxdomainconnections.xml        |    8 +-
 .../smbdotconf/winbind/winbindnestedgroups.xml     |    2 +-
 .../smbdotconf/winbind/winbindnormalizenames.xml   |    2 +-
 docs-xml/smbdotconf/winbind/winbindnssinfo.xml     |    2 +-
 .../smbdotconf/winbind/winbindofflinelogon.xml     |    4 +-
 .../smbdotconf/winbind/winbindreconnectdelay.xml   |    2 +-
 .../smbdotconf/winbind/winbindrefreshtickets.xml   |    2 +-
 .../smbdotconf/winbind/winbindrequesttimeout.xml   |    2 +-
 docs-xml/smbdotconf/winbind/winbindrpconly.xml     |    4 +-
 docs-xml/smbdotconf/winbind/winbindseparator.xml   |    2 +-
 .../winbind/winbindtrusteddomainsonly.xml          |    2 +-
 .../smbdotconf/winbind/winbindusedefaultdomain.xml |    2 +-
 docs-xml/smbdotconf/wins/dnsproxy.xml              |    2 +-
 docs-xml/smbdotconf/wins/winsserver.xml            |    2 +-
 docs-xml/using_samba/ch02.xml                      |    2 +-
 docs-xml/using_samba/ch05.xml                      |    2 +-
 docs-xml/wscript_build                             |   11 +-
 docs/manpages/cifsdd.8                             |  104 +
 docs/manpages/dbwrap_tool.1                        |    6 +-
 docs/manpages/eventlogadm.8                        |    6 +-
 docs/manpages/findsmb.1                            |    6 +-
 docs/manpages/idmap_ad.8                           |    6 +-
 docs/manpages/idmap_autorid.8                      |   11 +-
 docs/manpages/idmap_hash.8                         |    6 +-
 docs/manpages/idmap_ldap.8                         |    6 +-
 docs/manpages/idmap_nss.8                          |    6 +-
 docs/manpages/idmap_rfc2307.8                      |   17 +-
 docs/manpages/idmap_rid.8                          |    6 +-
 docs/manpages/idmap_script.8                       |    6 +-
 docs/manpages/idmap_tdb.8                          |    6 +-
 docs/manpages/idmap_tdb2.8                         |    6 +-
 docs/manpages/libsmbclient.7                       |    6 +-
 docs/manpages/lmhosts.5                            |    6 +-
 docs/manpages/log2pcap.1                           |    6 +-
 docs/manpages/net.8                                |   23 +-
 docs/manpages/nmbd.8                               |    6 +-
 docs/manpages/nmblookup.1                          |    6 +-
 docs/manpages/ntlm_auth.1                          |   11 +-
 docs/manpages/pam_winbind.8                        |    8 +-
 docs/manpages/pam_winbind.conf.5                   |    8 +-
 docs/manpages/pdbedit.8                            |   22 +-
 docs/manpages/profiles.1                           |    6 +-
 docs/manpages/rpcclient.1                          |    6 +-
 docs/manpages/samba-regedit.8                      |    6 +-
 docs/manpages/samba-tool.8                         |    6 +-
 docs/manpages/samba.7                              |    6 +-
 docs/manpages/samba.8                              |    6 +-
 docs/manpages/sharesec.1                           |    6 +-
 docs/manpages/smb.conf.5                           |  206 +-
 docs/manpages/smbcacls.1                           |    6 +-
 docs/manpages/smbclient.1                          |    6 +-
 docs/manpages/smbcontrol.1                         |    6 +-
 docs/manpages/smbcquotas.1                         |    6 +-
 docs/manpages/smbd.8                               |    8 +-
 docs/manpages/smbget.1                             |   24 +-
 docs/manpages/smbgetrc.5                           |   15 +-
 docs/manpages/smbpasswd.5                          |    6 +-
 docs/manpages/smbpasswd.8                          |    6 +-
 docs/manpages/smbspool.8                           |   19 +-
 docs/manpages/smbspool_krb5_wrapper.8              |    4 +-
 docs/manpages/smbstatus.1                          |    6 +-
 docs/manpages/smbta-util.8                         |   83 -
 docs/manpages/smbtar.1                             |    6 +-
 docs/manpages/smbtree.1                            |    6 +-
 docs/manpages/testparm.1                           |    6 +-
 docs/manpages/vfs_acl_tdb.8                        |    6 +-
 docs/manpages/vfs_acl_xattr.8                      |    6 +-
 docs/manpages/vfs_aio_fork.8                       |    6 +-
 docs/manpages/vfs_aio_linux.8                      |    6 +-
 docs/manpages/vfs_aio_pthread.8                    |    6 +-
 docs/manpages/vfs_audit.8                          |    6 +-
 docs/manpages/vfs_btrfs.8                          |    6 +-
 docs/manpages/vfs_cacheprime.8                     |    6 +-
 docs/manpages/vfs_cap.8                            |    6 +-
 docs/manpages/vfs_catia.8                          |    6 +-
 docs/manpages/vfs_ceph.8                           |    8 +-
 docs/manpages/vfs_commit.8                         |    6 +-
 docs/manpages/vfs_crossrename.8                    |    6 +-
 docs/manpages/vfs_default_quota.8                  |    6 +-
 docs/manpages/vfs_dirsort.8                        |    6 +-
 docs/manpages/vfs_extd_audit.8                     |    6 +-
 docs/manpages/vfs_fake_perms.8                     |    6 +-
 docs/manpages/vfs_fileid.8                         |    6 +-
 docs/manpages/vfs_fruit.8                          |    6 +-
 docs/manpages/vfs_full_audit.8                     |    6 +-
 docs/manpages/vfs_glusterfs.8                      |    6 +-
 docs/manpages/vfs_gpfs.8                           |    6 +-
 docs/manpages/vfs_linux_xfs_sgid.8                 |    6 +-
 docs/manpages/vfs_media_harmony.8                  |    6 +-
 docs/manpages/vfs_netatalk.8                       |    6 +-
 docs/manpages/vfs_offline.8                        |   65 +
 docs/manpages/vfs_prealloc.8                       |    6 +-
 docs/manpages/vfs_preopen.8                        |    6 +-
 docs/manpages/vfs_readahead.8                      |    6 +-
 docs/manpages/vfs_readonly.8                       |    6 +-
 docs/manpages/vfs_recycle.8                        |    6 +-
 docs/manpages/vfs_scannedonly.8                    |  164 -
 docs/manpages/vfs_shadow_copy.8                    |    6 +-
 docs/manpages/vfs_shadow_copy2.8                   |   77 +-
 docs/manpages/vfs_shell_snap.8                     |    6 +-
 docs/manpages/vfs_smb_traffic_analyzer.8           |  385 --
 docs/manpages/vfs_snapper.8                        |    6 +-
 docs/manpages/vfs_streams_depot.8                  |    6 +-
 docs/manpages/vfs_streams_xattr.8                  |    6 +-
 docs/manpages/vfs_syncops.8                        |    6 +-
 docs/manpages/vfs_time_audit.8                     |    6 +-
 docs/manpages/vfs_tsmsm.8                          |    6 +-
 docs/manpages/vfs_unityed_media.8                  |    6 +-
 docs/manpages/vfs_worm.8                           |    6 +-
 docs/manpages/vfs_xattr_tdb.8                      |    6 +-
 docs/manpages/vfs_zfsacl.8                         |    6 +-
 docs/manpages/vfstest.1                            |    6 +-
 docs/manpages/wbinfo.1                             |    8 +-
 docs/manpages/winbind_krb5_locator.7               |    6 +-
 docs/manpages/winbindd.8                           |    6 +-
 dynconfig/dynconfig.c                              |    7 +-
 dynconfig/wscript                                  |    8 +-
 examples/VFS/shadow_copy_test.c                    |    1 +
 examples/VFS/skel_opaque.c                         |    6 +-
 examples/VFS/skel_transparent.c                    |    8 +-
 examples/libsmbclient/get_auth_data_fn.h           |   16 +-
 examples/libsmbclient/teststat.c                   |   16 +-
 examples/libsmbclient/teststat2.c                  |   16 +-
 examples/libsmbclient/testutime.c                  |   16 +-
 examples/pdb/test.c                                |    4 +-
 install_with_python.sh                             |   41 +-
 lib/crypto/REQUIREMENTS                            |    3 -
 lib/dbwrap/dbwrap.c                                |    9 +-
 lib/dbwrap/dbwrap.h                                |    6 +-
 lib/dbwrap/dbwrap_cache.c                          |    8 +-
 lib/dbwrap/dbwrap_local_open.c                     |    9 +-
 lib/dbwrap/dbwrap_private.h                        |    4 +-
 lib/dbwrap/dbwrap_rbt.c                            |    8 +-
 lib/dbwrap/dbwrap_tdb.c                            |   23 +-
 lib/dbwrap/dbwrap_tdb.h                            |    1 -
 lib/dbwrap/dbwrap_util.c                           |   20 +-
 lib/dbwrap/wscript_build                           |    2 +-
 lib/krb5_wrap/krb5_samba.c                         |   17 +-
 lib/ldb-samba/ldb_ildap.c                          |   12 +-
 lib/ldb-samba/ldb_matching_rules.c                 |  342 ++
 lib/ldb-samba/ldb_matching_rules.h                 |   28 +
 lib/ldb-samba/ldb_wrap.c                           |    8 +-
 lib/ldb-samba/ldif_handlers.c                      |    6 +
 lib/ldb-samba/tests/match_rules.py                 | 1427 +++++++-
 lib/ldb-samba/wscript_build                        |    4 +-
 lib/ldb/ABI/ldb-1.1.22.sigs                        |  264 ++
 lib/ldb/ABI/ldb-1.1.23.sigs                        |  264 ++
 lib/ldb/ABI/ldb-1.1.24.sigs                        |  264 ++
 lib/ldb/ABI/ldb-1.1.25.sigs                        |  265 ++
 lib/ldb/ABI/ldb-1.1.26.sigs                        |  265 ++
 lib/ldb/ABI/pyldb-util-1.1.22.sigs                 |    2 +
 lib/ldb/ABI/pyldb-util-1.1.23.sigs                 |    2 +
 lib/ldb/ABI/pyldb-util-1.1.24.sigs                 |    2 +
 lib/ldb/ABI/pyldb-util-1.1.25.sigs                 |    2 +
 lib/ldb/ABI/pyldb-util-1.1.26.sigs                 |    2 +
 lib/ldb/ABI/pyldb-util.py3-1.1.23.sigs             |    2 +
 lib/ldb/ABI/pyldb-util.py3-1.1.24.sigs             |    2 +
 lib/ldb/ABI/pyldb-util.py3-1.1.25.sigs             |    2 +
 lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs             |    2 +
 lib/ldb/_ldb_text.py                               |  148 +
 lib/ldb/common/ldb_controls.c                      |   73 +-
 lib/ldb/common/ldb_dn.c                            |   38 +-
 lib/ldb/common/ldb_ldif.c                          |   77 +-
 lib/ldb/common/ldb_match.c                         |    5 +-
 lib/ldb/common/ldb_modules.c                       |    6 +-
 lib/ldb/common/ldb_pack.c                          |  274 +-
 lib/ldb/include/dlinklist.h                        |   15 +-
 lib/ldb/include/ldb.h                              |    7 +
 lib/ldb/include/ldb_module.h                       |   18 +
 lib/ldb/include/ldb_private.h                      |   13 +-
 lib/ldb/ldb_ldap/ldb_ldap.c                        |   18 +-
 lib/ldb/ldb_sqlite3/ldb_sqlite3.c                  |   11 +-
 lib/ldb/ldb_tdb/ldb_search.c                       |   19 +-
 lib/ldb/ldb_tdb/ldb_tdb.c                          |   14 +-
 lib/ldb/ldb_tdb/ldb_tdb.h                          |    3 +
 lib/ldb/pyldb.c                                    | 1043 ++++--
 lib/ldb/pyldb.h                                    |    7 +
 lib/ldb/pyldb_util.c                               |   21 +-
 lib/ldb/tests/python/api.py                        |  845 ++++-
 lib/ldb/tests/test-tdb.sh                          |    7 -
 lib/ldb/tools/cmdline.c                            |   33 +
 lib/ldb/wscript                                    |   73 +-
 lib/nss_wrapper/nss_wrapper.c                      | 2015 +++++++++--
 lib/nss_wrapper/wscript                            |    3 +-
 lib/param/README                                   |   20 +-
 lib/param/loadparm.c                               |  155 +-
 lib/param/loadparm.h                               |   35 +-
 lib/param/param.h                                  |   10 +-
 lib/param/param_table.c                            | 3728 +-------------------
 lib/param/util.c                                   |    1 +
 lib/param/wscript_build                            |    6 +
 lib/replace/replace.c                              |   17 +-
 lib/replace/wscript                                |   37 +-
 lib/resolv_wrapper/resolv_wrapper.c                |  227 +-
 lib/resolv_wrapper/wscript                         |    3 +-
 lib/socket/interfaces.c                            |   66 +
 lib/socket/interfaces.h                            |    3 +
 lib/socket/wscript                                 |    7 +
 lib/socket_wrapper/socket_wrapper.c                |  121 +-
 lib/socket_wrapper/wscript                         |    3 +-
 lib/talloc/ABI/pytalloc-util-2.1.4.sigs            |    6 +
 lib/talloc/ABI/pytalloc-util-2.1.5.sigs            |    6 +
 lib/talloc/ABI/pytalloc-util-2.1.6.sigs            |   13 +
 lib/talloc/ABI/pytalloc-util.py3-2.1.5.sigs        |    5 +
 lib/talloc/ABI/pytalloc-util.py3-2.1.6.sigs        |   12 +
 lib/talloc/ABI/talloc-2.1.4.sigs                   |   65 +
 lib/talloc/ABI/talloc-2.1.5.sigs                   |   65 +
 lib/talloc/ABI/talloc-2.1.6.sigs                   |   65 +
 lib/talloc/pytalloc.c                              |   86 +
 lib/talloc/pytalloc.h                              |   23 +-
 lib/talloc/pytalloc_guide.txt                      |   40 +-
 lib/talloc/pytalloc_private.h                      |   26 +
 lib/talloc/pytalloc_util.c                         |  199 +-
 lib/talloc/talloc.c                                |   89 +-
 lib/talloc/talloc.h                                |    4 +-
 lib/talloc/test_magic_differs.sh                   |   16 +
 lib/talloc/test_magic_differs_helper.c             |   12 +
 lib/talloc/test_pytalloc.c                         |   83 +-
 lib/talloc/test_pytalloc.py                        |   73 +-
 lib/talloc/testsuite.c                             |   71 +
 lib/talloc/wscript                                 |   23 +-
 lib/tdb/ABI/tdb-1.3.8.sigs                         |   69 +
 lib/tdb/common/open.c                              |    7 +
 lib/tdb/docs/mutex.txt                             |    4 +-
 lib/tdb/wscript                                    |    4 +-
 lib/tdb_wrap/tdb_wrap.c                            |   12 +-
 lib/tevent/ABI/tevent-0.9.26.sigs                  |   90 +
 lib/tevent/ABI/tevent-0.9.27.sigs                  |   90 +
 lib/tevent/ABI/tevent-0.9.28.sigs                  |   90 +
 lib/tevent/doc/tevent_thread.dox                   |  322 ++
 lib/tevent/doc/tevent_tutorial.dox                 |    2 +
 lib/tevent/testsuite.c                             |  330 ++
 lib/tevent/tevent.h                                |   52 +
 lib/tevent/tevent_epoll.c                          |    6 +-
 lib/tevent/tevent_immediate.c                      |    2 +-
 lib/tevent/tevent_poll.c                           |    7 +-
 lib/tevent/tevent_port.c                           |   22 +-
 lib/tevent/tevent_queue.c                          |    2 +-
 lib/tevent/tevent_select.c                         |    2 +-
 lib/tevent/tevent_signal.c                         |    4 +
 lib/tevent/tevent_threads.c                        |  370 ++
 lib/tevent/tevent_util.h                           |   15 +-
 lib/tevent/wscript                                 |    9 +-
 lib/torture/torture.c                              |   14 +-
 lib/torture/torture.h                              |   11 +
 lib/torture/torture.pc.in                          |   12 -
 lib/torture/wscript_build                          |   11 +-
 lib/tsocket/tsocket_bsd.c                          |   13 +-
 lib/uid_wrapper/uid_wrapper.c                      |  646 +++-
 lib/uid_wrapper/wscript                            |   75 +-
 lib/util/asn1.c                                    |  121 +-
 lib/util/asn1.h                                    |   27 +-
 lib/util/charset/util_str.c                        |    4 +-
 lib/util/debug.c                                   |    2 +-
 lib/util/debug.h                                   |   20 +-
 lib/util/dlinklist.h                               |   15 +-
 lib/util/genrand.c                                 |  259 +-
 lib/util/genrand.h                                 |   11 -
 lib/util/idtree.c                                  |    7 +-
 lib/util/parmlist.c                                |  111 -
 lib/util/parmlist.h                                |   57 -
 lib/util/samba_util.h                              |   32 +-
 lib/util/server_id.c                               |  110 +-
 lib/util/server_id_db.c                            |   23 +-
 lib/util/sys_rw.c                                  |  101 +
 {source3/lib => lib/util}/sys_rw.h                 |    0
 lib/util/sys_rw_data.c                             |  117 +
 {source3/lib => lib/util}/sys_rw_data.h            |    0
 lib/util/talloc_report.c                           |    4 +-
 lib/util/tests/asn1_tests.c                        |    6 +-
 lib/util/tests/dlinklist.c                         |    8 +-
 lib/util/tests/genrand.c                           |   12 -
 lib/util/tests/genrandperf.c                       |   39 +
 lib/util/tests/parmlist.c                          |  107 -
 lib/util/time_basic.c                              |    3 +-
 lib/util/time_basic.h                              |    3 +-
 lib/util/util.c                                    |    2 +-
 lib/util/util.h                                    |   53 +
 lib/util/util_process.c                            |    1 +
 lib/util/wscript_build                             |   54 +-
 lib/util/wscript_configure                         |    6 +-
 libcli/auth/netlogon_creds_cli.c                   |   15 +-
 libcli/auth/spnego_parse.c                         |   50 +-
 libcli/auth/wscript_build                          |    2 +-
 libcli/cldap/cldap.c                               |   14 +-
 libcli/dns/dns.c                                   |   34 +-
 libcli/dns/libdns.h                                |   10 +-
 libcli/drsuapi/drsuapi.h                           |    1 +
 libcli/drsuapi/repl_decrypt.c                      |    6 +
 libcli/drsuapi/wscript_build                       |    2 +-
 libcli/ldap/ldap_message.c                         |   34 +-
 libcli/ldap/wscript_build                          |    7 +-
 libcli/nbt/libnbt.h                                |    2 +
 libcli/nbt/nbtsocket.c                             |    7 +-
 libcli/security/dom_sid.h                          |    6 +-
 libcli/security/secace.c                           |   19 -
 libcli/security/secace.h                           |    1 -
 libcli/security/secdesc.c                          |   21 +-
 libcli/security/secdesc.h                          |    5 -
 libcli/security/util_sid.c                         |   31 +-
 libcli/smb/smb1cli_read.c                          |   53 +-
 libcli/smb/smb2_signing.c                          |   17 +-
 libcli/smb/smb2cli_ioctl.c                         |   84 +-
 libcli/smb/smb2cli_query_info.c                    |   24 +-
 libcli/smb/smb2cli_read.c                          |   26 +-
 libcli/smb/smbXcli_base.c                          |   43 +-
 libcli/smb/smb_constants.h                         |    1 -
 libcli/smb/smb_unix_ext.h                          |    2 +-
 libcli/smb/tstream_smbXcli_np.c                    |   13 +-
 libcli/smb/wscript                                 |    6 +-
 libcli/smbreadline/smbreadline.c                   |    6 +
 libcli/util/wscript_build                          |    6 +-
 libds/common/flags.h                               |    4 +-
 libds/common/wscript_build                         |    6 +-
 libgpo/gpo_ldap.c                                  |    2 +-
 librpc/idl/clusapi.idl                             |  154 +-
 librpc/idl/dcom.idl                                |  131 +-
 librpc/idl/ioctl.idl                               |    1 +
 librpc/idl/messaging.idl                           |    1 +
 librpc/idl/negoex.idl                              |  156 +
 librpc/idl/orpc.idl                                |   36 +-
 librpc/idl/oxidresolver.idl                        |   52 +-
 librpc/idl/remact.idl                              |   44 +-
 librpc/idl/rot.idl                                 |   58 +-
 librpc/idl/security.idl                            |    3 +
 librpc/idl/witness.idl                             |    6 +-
 librpc/idl/wmi.idl                                 |    8 +-
 librpc/idl/wscript_build                           |    2 +-
 librpc/idl/xattr.idl                               |    1 +
 librpc/ndr/libndr.h                                |    6 +-
 librpc/ndr/ndr_basic.c                             |    4 +-
 librpc/ndr/ndr_dns.c                               |    2 +-
 librpc/ndr/ndr_nbt.c                               |    2 +-
 librpc/ndr/ndr_negoex.c                            |  520 +++
 librpc/ndr/ndr_negoex.h                            |   37 +
 librpc/rpc/binding.c                               |    2 +-
 librpc/rpc/rpc_common.h                            |    1 +
 librpc/tools/wscript_build                         |    2 +-
 librpc/wscript_build                               |   11 +-
 nsswitch/libwbclient/tests/wbclient.c              |   20 +-
 nsswitch/pam_winbind.c                             |   28 +-
 nsswitch/wb_common.c                               |    4 +-
 nsswitch/wbinfo.c                                  |   10 +
 nsswitch/wins.c                                    |  242 +-
 nsswitch/wins_freebsd.c                            |   81 +
 nsswitch/wscript_build                             |    9 +-
 packaging/RHEL-CTDB/configure.rpm                  |    2 -
 packaging/RHEL-CTDB/samba.spec.tmpl                |   10 +-
 packaging/RHEL/samba.spec.tmpl                     |    6 +-
 pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm            |   11 +-
 pidl/lib/Parse/Pidl/Samba3/Template.pm             |   11 +-
 pidl/lib/Parse/Pidl/Samba4/NDR/Client.pm           |   11 +-
 pidl/lib/Parse/Pidl/Samba4/Python.pm               |   43 +-
 pidl/lib/Parse/Pidl/Samba4/Template.pm             |   11 +-
 pidl/lib/Parse/Pidl/Util.pm                        |   16 +-
 pidl/wscript                                       |    5 +-
 python/pyglue.c                                    |   11 +
 python/samba/__init__.py                           |    1 +
 python/samba/dbchecker.py                          |  162 +-
 python/samba/join.py                               |  144 +-
 python/samba/kcc/__init__.py                       |  372 +-
 python/samba/kcc/kcc_utils.py                      |  105 +-
 python/samba/kcc/ldif_import_export.py             |   10 +-
 python/samba/netcmd/dns.py                         |    6 +-
 python/samba/netcmd/domain.py                      |  267 +-
 python/samba/netcmd/drs.py                         |   46 +
 python/samba/netcmd/main.py                        |    2 -
 python/samba/netcmd/ntacl.py                       |   24 +-
 python/samba/netcmd/sites.py                       |  163 +-
 python/samba/netcmd/user.py                        |   10 +-
 python/samba/netcmd/vampire.py                     |   55 -
 python/samba/ntacls.py                             |    8 +
 python/samba/provision/__init__.py                 |   11 +-
 python/samba/provision/sambadns.py                 |   15 +-
 python/samba/remove_dc.py                          |  435 +++
 python/samba/samdb.py                              |   25 +-
 python/samba/sites.py                              |   52 +-
 python/samba/subnets.py                            |  186 +
 python/samba/tests/__init__.py                     |    2 +-
 python/samba/tests/blackbox/samba_tool_drs.py      |  169 +-
 python/samba/tests/dcerpc/array.py                 |  171 +
 python/samba/tests/dcerpc/rpc_talloc.py            |   14 +-
 python/samba/tests/dns.py                          |   34 +-
 python/samba/tests/docs.py                         |  142 +-
 python/samba/tests/kcc/ldif_import_export.py       |   37 +-
 python/samba/tests/provision.py                    |    3 -
 python/samba/tests/samba_tool/sites.py             |  136 +
 python/samba/upgradehelpers.py                     |    2 +-
 python/uuidmodule.c                                |   58 -
 python/wscript_build                               |    8 -
 script/autobuild.py                                |   89 +-
 script/generate_param.py                           |  159 +-
 script/release.sh                                  |   44 +-
 selftest/flapping                                  |    2 +
 selftest/knownfail                                 |   16 -
 selftest/selftest.pl                               |   10 +-
 selftest/selftesthelpers.py                        |    2 +
 selftest/target/Samba.pm                           |    6 +-
 selftest/target/Samba3.pm                          |  153 +-
 selftest/target/Samba4.pm                          |  110 +-
 selftest/tests.py                                  |    4 +
 source3/auth/auth.c                                |    2 +-
 source3/auth/auth_samba4.c                         |    9 +-
 source3/auth/pampass.c                             |    2 +-
 source3/client/clitar.c                            |   12 +-
 source3/client/dnsbrowse.c                         |    2 +-
 source3/client/smbspool.c                          |    4 +-
 source3/include/MacExtensions.h                    |   10 +-
 source3/include/ads.h                              |    2 -
 source3/include/ctdbd_conn.h                       |  102 +-
 source3/include/messages.h                         |   18 +-
 source3/include/ntquotas.h                         |    2 +-
 source3/include/passdb.h                           |    2 +-
 source3/include/proto.h                            |   67 +-
 source3/include/samba_linux_quota.h                |    2 +-
 source3/include/secrets.h                          |    1 +
 source3/include/serverid.h                         |   13 +-
 source3/include/session.h                          |    5 +-
 source3/include/smb.h                              |   10 +-
 source3/include/smb_ldap.h                         |    2 +-
 source3/include/smbprofile.h                       |    4 +-
 source3/include/tldap.h                            |    1 +
 source3/include/vfs.h                              |   20 +-
 source3/include/vfs_macros.h                       |    8 +-
 source3/lib/background.c                           |    2 +-
 source3/lib/cluster_support.c                      |   16 +
 source3/lib/cluster_support.h                      |    1 +
 source3/lib/conn_tdb.c                             |   10 +
 source3/lib/conn_tdb.h                             |    4 +
 source3/lib/ctdb_dummy.c                           |   68 +-
 source3/lib/ctdbd_conn.c                           |  783 ++--
 source3/lib/dbwrap/dbwrap_ctdb.c                   |  148 +-
 source3/lib/dbwrap/dbwrap_open.c                   |    1 +
 source3/lib/dbwrap/dbwrap_watch.c                  |  188 +-
 source3/lib/dummyparam.c                           |   30 -
 source3/lib/events.c                               |    2 +-
 source3/lib/gencache.c                             |   42 +-
 source3/lib/gencache.h                             |   52 +
 source3/lib/interface.c                            |  113 +-
 source3/lib/messages.c                             |   69 +-
 source3/lib/messages_ctdbd.c                       |   62 +-
 source3/lib/messages_dgm.c                         |  113 +-
 source3/lib/messages_dgm.h                         |    3 +-
 source3/lib/messages_dgm_ref.c                     |   17 +-
 source3/lib/messages_dgm_ref.h                     |    2 +-
 .../examples/netdomjoin-gui/netdomjoin-gui.c       |    2 +-
 source3/lib/poll_funcs/poll_funcs_tevent.c         |    2 +-
 source3/lib/popt_common.c                          |    2 +-
 source3/lib/privileges.c                           |    2 +-
 source3/lib/pthreadpool/pthreadpool.c              |   11 +-
 source3/lib/recvfile.c                             |    2 +-
 source3/lib/server_id_db_util.c                    |   10 +-
 source3/lib/serverid.c                             |  243 +-
 source3/lib/sessionid_tdb.c                        |   33 +-
 source3/lib/smbldap.c                              |    6 +-
 source3/lib/substitute.c                           |    4 +-
 source3/lib/sys_rw.c                               |  101 -
 source3/lib/sys_rw_data.c                          |  117 -
 source3/lib/sysquotas_nfs.c                        |    7 -
 source3/lib/talloc_dict.c                          |    7 +-
 source3/lib/tldap.c                                |   29 +-
 source3/lib/tldap_util.c                           |    2 +-
 source3/lib/unix_msg/unix_msg.c                    |    4 +-
 source3/lib/util.c                                 |  184 +-
 source3/lib/util_cluster.c                         |    9 +-
 source3/lib/util_ea.c                              |    2 +-
 source3/lib/util_file.c                            |    2 +-
 source3/lib/util_names.c                           |   14 +
 source3/lib/util_path.c                            |   95 +
 source3/lib/util_path.h                            |   31 +
 source3/lib/util_procid.c                          |   69 +
 source3/lib/util_procid.h                          |   37 +
 source3/lib/util_sec.c                             |   14 +
 source3/lib/util_sid.c                             |   11 +-
 source3/lib/util_sock.c                            |    6 +-
 source3/lib/util_specialsids.c                     |   40 +
 source3/lib/util_transfer_file.c                   |    2 +-
 source3/lib/util_tsock.c                           |    5 +-
 source3/lib/util_tsock.h                           |   38 +
 source3/libads/ads_proto.h                         |    6 +-
 source3/libads/ads_struct.c                        |   12 +-
 source3/libads/krb5_setpw.c                        |   13 +-
 source3/libads/ldap.c                              |   62 +-
 source3/libads/ldap_utils.c                        |    4 +-
 source3/libads/ndr.c                               |    2 +-
 source3/libnet/libnet_dssync.c                     |    1 +
 source3/libnet/libnet_join.c                       |  239 +-
 source3/librpc/crypto/gse.c                        |   13 +-
 source3/librpc/idl/libnet_join.idl                 |    4 +-
 source3/librpc/idl/smbXsrv.idl                     |  117 +-
 source3/libsmb/clidfs.c                            |    2 +-
 source3/libsmb/clifsinfo.c                         |    2 -
 source3/libsmb/cliquota.c                          |    6 +-
 source3/libsmb/clireadwrite.c                      |    8 +-
 source3/libsmb/clispnego.c                         |   59 +-
 source3/libsmb/dsgetdcname.c                       |   40 +-
 source3/libsmb/libsmb_printjob.c                   |    4 +-
 source3/libsmb/namequery.c                         |   80 +-
 source3/libsmb/pylibsmb.c                          |    2 +-
 source3/libsmb/unexpected.c                        |    3 +-
 source3/locale/net/de.po                           |    8 +-
 source3/modules/nfs4_acls.c                        |  248 +-
 source3/modules/nfs4_acls.h                        |   32 +-
 source3/modules/perfcount_test.c                   |    1 +
 source3/modules/vfs_acl_tdb.c                      |    3 +-
 source3/modules/vfs_acl_xattr.c                    |    3 +-
 source3/modules/vfs_aio_fork.c                     |   15 +-
 source3/modules/vfs_aio_linux.c                    |   25 +-
 source3/modules/vfs_aio_posix.c                    |  301 --
 source3/modules/vfs_aio_pthread.c                  |    6 +-
 source3/modules/vfs_aixacl2.c                      |   16 +-
 source3/modules/vfs_audit.c                        |    1 +
 source3/modules/vfs_cacheprime.c                   |    2 +-
 source3/modules/vfs_cap.c                          |   21 +-
 source3/modules/vfs_catia.c                        |    1 +
 source3/modules/vfs_ceph.c                         |    5 +-
 source3/modules/vfs_default.c                      |   48 +-
 source3/modules/vfs_default_quota.c                |   13 +-
 source3/modules/vfs_dirsort.c                      |    1 +
 source3/modules/vfs_extd_audit.c                   |    1 +
 source3/modules/vfs_fake_dfq.c                     |  174 +
 source3/modules/vfs_fruit.c                        |    6 +-
 source3/modules/vfs_full_audit.c                   |    9 +-
 source3/modules/vfs_glusterfs.c                    |  170 +-
 source3/modules/vfs_gpfs.c                         |  134 +-
 source3/modules/vfs_nfs4acl_xattr.c                |   36 +-
 source3/modules/vfs_offline.c                      |   47 +
 source3/modules/vfs_posix_eadb.c                   |    2 +-
 source3/modules/vfs_preopen.c                      |    2 +-
 source3/modules/vfs_scannedonly.c                  | 1043 ------
 source3/modules/vfs_shadow_copy2.c                 |  116 +-
 source3/modules/vfs_smb_traffic_analyzer.c         |  946 -----
 source3/modules/vfs_smb_traffic_analyzer.h         |  157 -
 source3/modules/vfs_snapper.c                      |   36 +-
 source3/modules/vfs_syncops.c                      |    1 +
 source3/modules/vfs_time_audit.c                   |    6 +-
 source3/modules/vfs_zfsacl.c                       |   13 +-
 source3/modules/wscript_build                      |   42 +-
 source3/nmbd/asyncdns.c                            |    4 +-
 source3/nmbd/nmbd.c                                |    3 +-
 source3/nmbd/nmbd_browserdb.c                      |    2 +-
 source3/nmbd/nmbd_packets.c                        |    2 +-
 source3/nmbd/nmbd_responserecordsdb.c              |    2 +-
 source3/nmbd/nmbd_serverlistdb.c                   |    2 +-
 source3/pam_smbpass/CHANGELOG                      |   31 -
 source3/pam_smbpass/INSTALL                        |   64 -
 source3/pam_smbpass/README                         |   68 -
 source3/pam_smbpass/TODO                           |    7 -
 source3/pam_smbpass/general.h                      |  134 -
 source3/pam_smbpass/pam_smb_acct.c                 |  150 -
 source3/pam_smbpass/pam_smb_auth.c                 |  264 --
 source3/pam_smbpass/pam_smb_passwd.c               |  365 --
 source3/pam_smbpass/samples/README                 |    3 -
 source3/pam_smbpass/samples/kdc-pdc                |   15 -
 source3/pam_smbpass/samples/password-mature        |   14 -
 source3/pam_smbpass/samples/password-migration     |   18 -
 source3/pam_smbpass/samples/password-sync          |   15 -
 source3/pam_smbpass/support.c                      |  698 ----
 source3/pam_smbpass/support.h                      |   57 -
 source3/pam_smbpass/wscript_build                  |   16 -
 source3/param/loadparm.c                           |  197 +-
 source3/passdb/ABI/samba-passdb-0.24.2.sigs        |  313 ++
 source3/passdb/ABI/samba-passdb-0.25.0.sigs        |  312 ++
 source3/passdb/machine_account_secrets.c           |   32 +-
 source3/passdb/passdb.c                            |   21 +-
 source3/passdb/pdb_get_set.c                       |   24 +-
 source3/passdb/pdb_ipa.c                           |    2 +-
 source3/passdb/py_passdb.c                         |  285 +-
 source3/passdb/secrets.c                           |   29 -
 source3/passdb/wscript_build                       |    2 +-
 source3/printing/notify.c                          |    2 +-
 source3/printing/print_cups.c                      |    4 +-
 source3/printing/printing.c                        |    2 +-
 source3/printing/queue_process.c                   |    4 +-
 source3/printing/spoolssd.c                        |   12 +-
 source3/profile/profile.c                          |    4 +-
 source3/registry/reg_backend_db.c                  |    7 +-
 source3/registry/reg_objects.c                     |    4 +-
 source3/registry/regfio.c                          |    2 +-
 source3/rpc_client/rpc_transport_np.c              |    3 +-
 source3/rpc_server/epmd.c                          |    6 +-
 source3/rpc_server/fss/srv_fss_agent.c             |    9 +-
 source3/rpc_server/fss/srv_fss_state.c             |   12 +-
 source3/rpc_server/fssd.c                          |    4 +-
 source3/rpc_server/lsa/srv_lsa_nt.c                |    2 +-
 source3/rpc_server/lsasd.c                         |   10 +-
 source3/rpc_server/mdssd.c                         |   11 +-
 source3/rpc_server/samr/srv_samr_chgpasswd.c       |    2 +-
 source3/rpc_server/spoolss/srv_spoolss_nt.c        |   83 +
 source3/rpc_server/srvsvc/srv_srvsvc_nt.c          |   23 +-
 source3/rpcclient/cmd_clusapi.c                    |   58 +
 source3/rpcclient/cmd_witness.c                    |    5 +
 source3/script/tests/test_dfree_quota.sh           |  174 +
 source3/script/tests/test_forceuser_validusers.sh  |   59 +
 source3/script/tests/test_ntlm_auth_s3.sh          |  196 +-
 source3/script/tests/test_offline.sh               |   33 +
 source3/script/tests/test_shadow_copy.sh           |    1 +
 source3/script/tests/test_smbclient_s3.sh          |   60 +
 source3/script/tests/test_smbclient_tarmode.pl     |    6 +-
 source3/script/tests/test_smbget.sh                |  236 ++
 source3/script/tests/test_valid_users.sh           |   70 +
 source3/selftest/tests.py                          |    5 +
 source3/smbd/aio.c                                 |   64 +-
 source3/smbd/blocking.c                            |    2 +-
 source3/smbd/dfree.c                               |   15 +-
 source3/smbd/dir.c                                 |   13 +-
 source3/smbd/dosmode.c                             |   65 +-
 source3/smbd/filename.c                            |   55 +-
 source3/smbd/globals.c                             |    3 -
 source3/smbd/globals.h                             |   56 +-
 source3/smbd/negprot.c                             |  153 +-
 source3/smbd/notify.c                              |    3 +-
 source3/smbd/notify_inotify.c                      |    2 +-
 source3/smbd/notifyd/notifyd.c                     |   63 +-
 source3/smbd/ntquotas.c                            |    2 +-
 source3/smbd/nttrans.c                             |   95 +-
 source3/smbd/open.c                                |   34 +-
 source3/smbd/posix_acls.c                          |   30 +-
 source3/smbd/process.c                             |  112 +-
 source3/smbd/proto.h                               |   28 +-
 source3/smbd/quotas.c                              |   42 +-
 source3/smbd/reply.c                               |  218 +-
 source3/smbd/scavenger.c                           |   57 +-
 source3/smbd/seal.c                                |    2 -
 source3/smbd/server.c                              |  208 +-
 source3/smbd/server_exit.c                         |   10 +-
 source3/smbd/sesssetup.c                           |   40 +-
 source3/smbd/smb2_break.c                          |    8 +-
 source3/smbd/smb2_close.c                          |    1 -
 source3/smbd/smb2_create.c                         |  130 +-
 source3/smbd/smb2_flush.c                          |   60 +-
 source3/smbd/smb2_ioctl_filesys.c                  |    7 +-
 source3/smbd/smb2_ioctl_network_fs.c               |  136 +
 source3/smbd/smb2_negprot.c                        |   77 +-
 source3/smbd/smb2_query_directory.c                |   12 +-
 source3/smbd/smb2_read.c                           |    2 +-
 source3/smbd/smb2_server.c                         |  201 +-
 source3/smbd/smb2_sesssetup.c                      |  327 +-
 source3/smbd/smb2_tcon.c                           |   12 +-
 source3/smbd/smbXsrv_client.c                      |  781 ++++
 source3/smbd/smbXsrv_open.c                        |  288 +-
 source3/smbd/smbXsrv_session.c                     |  345 +-
 source3/smbd/smbXsrv_tcon.c                        |  119 +-
 source3/smbd/smbd_cleanupd.c                       |  156 +
 source3/smbd/smbd_cleanupd.h                       |   33 +
 source3/smbd/trans2.c                              |  276 +-
 source3/smbd/vfs.c                                 |    4 +-
 source3/torture/torture.c                          |   11 +-
 source3/utils/net.c                                |    8 +-
 source3/utils/net.h                                |    1 +
 source3/utils/net_ads.c                            |   64 +-
 source3/utils/net_serverid.c                       |   62 +-
 source3/utils/ntlm_auth.c                          |   93 +-
 source3/utils/pdbedit.c                            |   43 +-
 source3/utils/smbcontrol.c                         |    2 +-
 source3/utils/smbfilter.c                          |    2 +-
 source3/utils/smbget.c                             |  759 ++--
 source3/utils/smbta-util.c                         |  211 --
 source3/utils/status.c                             |  207 +-
 source3/winbindd/idmap_ad.c                        |    1 +
 source3/winbindd/idmap_autorid.c                   |    1 +
 source3/winbindd/idmap_hash/idmap_hash.c           |    1 +
 source3/winbindd/idmap_nss.c                       |    8 +-
 source3/winbindd/idmap_rfc2307.c                   |   40 +-
 source3/winbindd/idmap_rid.c                       |    7 +-
 source3/winbindd/idmap_script.c                    |    1 +
 source3/winbindd/idmap_tdb2.c                      |    1 +
 source3/winbindd/idmap_util.c                      |    4 +-
 source3/winbindd/wb_sids2xids.c                    |   14 +-
 source3/winbindd/winbindd.c                        |   13 +-
 source3/winbindd/winbindd_ads.c                    |    2 +-
 source3/winbindd/winbindd_cache.c                  |    2 +-
 source3/winbindd/winbindd_cm.c                     |    4 +-
 source3/winbindd/winbindd_cred_cache.c             |   24 -
 source3/winbindd/winbindd_dual.c                   |    6 +-
 source3/winbindd/winbindd_misc.c                   |   13 +-
 source3/winbindd/winbindd_msrpc.c                  |    2 +-
 source3/winbindd/winbindd_pam.c                    |   13 +-
 source3/winbindd/winbindd_util.c                   |  155 +-
 source3/winbindd/wscript_build                     |   16 +-
 source3/wscript                                    |  245 +-
 source3/wscript_build                              |   62 +-
 source4/auth/gensec/gensec_gssapi.c                |    5 +-
 source4/auth/gensec/gensec_krb5.c                  |   24 +-
 source4/auth/gensec/pygensec.c                     |   79 +-
 source4/auth/kerberos/kerberos-notes.txt           |    2 +-
 source4/auth/kerberos/kerberos_util.c              |   13 +-
 source4/auth/kerberos/wscript_build                |    2 +-
 source4/auth/ntlm/auth.c                           |    3 +-
 source4/auth/ntlm/auth_sam.c                       |    1 +
 source4/auth/ntlm/auth_unix.c                      |    6 +-
 source4/auth/ntlm/auth_winbind.c                   |   15 +-
 source4/auth/pyauth.c                              |   14 +-
 source4/cldap_server/cldap_server.c                |    1 +
 source4/client/cifsdd.c                            |    2 +-
 source4/dns_server/dlz_bind9.c                     |   16 +-
 source4/dns_server/dns_query.c                     |  569 ++-
 source4/dns_server/dns_server.c                    |   73 +-
 source4/dns_server/dns_server.h                    |   11 +-
 source4/dns_server/dns_utils.c                     |   92 +-
 source4/dns_server/dnsserver_common.c              |  192 +-
 source4/dns_server/dnsserver_common.h              |   18 +-
 source4/dns_server/pydns.c                         |  319 ++
 source4/dns_server/wscript_build                   |    8 +-
 source4/dsdb/common/util.c                         |    2 +-
 source4/dsdb/common/util_trusts.c                  |    2 +-
 source4/dsdb/dns/dns_update.c                      |    1 +
 source4/dsdb/kcc/kcc_drs_replica_info.c            |    2 +-
 source4/dsdb/kcc/kcc_service.c                     |    1 +
 source4/dsdb/pydsdb.c                              |  171 +-
 source4/dsdb/repl/drepl_notify.c                   |    2 +-
 source4/dsdb/repl/drepl_out_helpers.c              |    3 +
 source4/dsdb/repl/drepl_out_pull.c                 |    2 +-
 source4/dsdb/repl/drepl_partitions.c               |    4 +-
 source4/dsdb/repl/drepl_service.c                  |    1 +
 source4/dsdb/repl/replicated_objects.c             |   92 +-
 source4/dsdb/samdb/ldb_modules/acl.c               |    2 +-
 source4/dsdb/samdb/ldb_modules/descriptor.c        |    4 +-
 source4/dsdb/samdb/ldb_modules/dns_notify.c        |    2 +-
 source4/dsdb/samdb/ldb_modules/extended_dn_in.c    |    4 +-
 source4/dsdb/samdb/ldb_modules/linked_attributes.c |    2 +-
 source4/dsdb/samdb/ldb_modules/operational.c       |    2 +-
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c    |  121 +-
 source4/dsdb/samdb/ldb_modules/rootdse.c           |    2 +-
 source4/dsdb/samdb/ldb_modules/samldb.c            |  289 +-
 source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c  |    2 +-
 source4/dsdb/samdb/ldb_modules/update_keytab.c     |    2 +-
 .../dsdb/samdb/ldb_modules/wscript_build_server    |    2 +-
 source4/dsdb/samdb/samdb.h                         |    1 +
 source4/dsdb/schema/schema_query.c                 |    8 +-
 source4/dsdb/schema/schema_syntax.c                |   12 +-
 source4/dsdb/tests/python/acl.py                   |    2 +-
 source4/dsdb/tests/python/ldap_schema.py           |   31 +-
 source4/dsdb/tests/python/sites.py                 |  447 ++-
 source4/dsdb/wscript_build                         |    4 +-
 source4/echo_server/echo_server.c                  |    3 +-
 .../heimdal/lib/gssapi/krb5/accept_sec_context.c   |   71 +-
 source4/heimdal/lib/roken/resolve.c                |    1 +
 source4/heimdal_build/wscript_build                |   10 +-
 source4/heimdal_build/wscript_configure            |   10 +-
 source4/kdc/db-glue.c                              |  206 +-
 source4/kdc/db-glue.h                              |    8 +-
 source4/kdc/hdb-samba4.c                           |  138 +-
 source4/kdc/kdc.c                                  |    1 +
 source4/kdc/pac-glue.c                             |    1 -
 source4/kdc/sdb.c                                  |  131 +
 source4/kdc/sdb.h                                  |  126 +
 source4/kdc/sdb_to_hdb.c                           |  347 ++
 source4/kdc/wscript_build                          |   19 +-
 source4/ldap_server/ldap_backend.c                 |    2 +-
 source4/ldap_server/ldap_server.c                  |    1 +
 source4/lib/com/dcom/dcom.h                        |    2 +-
 source4/lib/com/dcom/main.c                        |    8 +-
 source4/lib/http/http.c                            |    2 +-
 source4/lib/messaging/messaging.c                  |   10 +-
 source4/lib/messaging/pymessaging.c                |    2 +-
 source4/lib/messaging/wscript_build                |    2 +-
 source4/lib/registry/pyregistry.c                  |   19 +-
 source4/lib/registry/registry.pc.in                |   12 -
 source4/lib/registry/wscript_build                 |    5 +-
 source4/lib/socket/interface.c                     |   11 +-
 source4/lib/socket/wscript_build                   |    2 +-
 source4/lib/stream/packet.c                        |    2 +-
 source4/lib/tls/tls.c                              |   90 +-
 source4/lib/tls/tls.h                              |    7 -
 source4/lib/tls/tls_tstream.c                      |    2 +-
 source4/lib/tls/wscript                            |   26 +-
 source4/lib/wmi/tools/wmis.c                       |    3 +-
 source4/lib/wmi/wmi_wrap.c                         |    2 +-
 source4/lib/wmi/wmicore.c                          |    3 +-
 source4/libcli/dgram/dgramsocket.c                 |    2 +-
 source4/libcli/ldap/ldap_client.c                  |   52 +-
 source4/libcli/ldap/ldap_controls.c                |   49 +-
 source4/libcli/ldap/wscript_build                  |    4 +-
 source4/libcli/pysmb.c                             |  116 +-
 source4/libcli/raw/smbclient-raw.pc.in             |   10 -
 source4/libcli/resolve/resolve.c                   |    2 +-
 source4/libcli/smb2/wscript_build                  |    2 +-
 source4/libcli/wbclient/wscript_build              |    2 +-
 source4/libcli/wscript_build                       |   16 +-
 source4/libnet/libnet_vampire.c                    |  293 +-
 source4/libnet/py_net.c                            |   59 -
 source4/libnet/wscript_build                       |    2 +-
 source4/librpc/dcerpc_atsvc.pc.in                  |   11 -
 source4/librpc/rpc/dcerpc.c                        |    6 +-
 source4/librpc/rpc/pyrpc.c                         |    8 +-
 source4/librpc/rpc/pyrpc_util.c                    |    3 +
 source4/librpc/wscript_build                       |   18 +-
 source4/nbt_server/dgram/netlogon.c                |    1 +
 source4/nbt_server/register.c                      |    3 +-
 source4/nbt_server/wins/winsserver.c               |    2 +-
 source4/ntvfs/ntvfs_base.c                         |    2 +-
 source4/ntvfs/posix/posix_eadb.h                   |    2 +-
 source4/ntvfs/posix/pvfs_notify.c                  |    2 +-
 source4/ntvfs/posix/python/pyposix_eadb.c          |    4 +-
 source4/ntvfs/posix/python/pyxattr_native.c        |    4 +-
 source4/ntvfs/posix/python/pyxattr_tdb.c           |   19 +-
 source4/ntvfs/unixuid/vfs_unixuid.c                |    3 +
 source4/param/pyparam.c                            |   87 +-
 source4/param/secrets.c                            |   53 -
 source4/param/secrets.h                            |    8 -
 source4/param/share_ldb.c                          |    2 +-
 source4/param/tests/loadparm.c                     |    1 +
 source4/param/wscript_build                        |    2 +-
 source4/rpc_server/backupkey/dcesrv_backupkey.c    | 1042 +++---
 .../backupkey/dcesrv_backupkey_heimdal.c           | 1852 ++++++++++
 source4/rpc_server/common/reply.c                  |   10 +-
 source4/rpc_server/common/server_info.c            |    1 +
 source4/rpc_server/dcerpc_server.c                 |   22 +-
 source4/rpc_server/dnsserver/dcerpc_dnsserver.c    |    7 +-
 source4/rpc_server/dnsserver/dnsdb.c               |    6 +-
 source4/rpc_server/drsuapi/getncchanges.c          |   10 +
 source4/rpc_server/lsa/dcesrv_lsa.c                |    1 +
 source4/rpc_server/samr/dcesrv_samr.h              |    1 +
 source4/rpc_server/spoolss/dcesrv_spoolss.c        |    2 +-
 source4/rpc_server/wscript_build                   |   24 +-
 source4/scripting/bin/gen_hresult.py               |    2 +-
 source4/scripting/bin/gen_ntstatus.py              |   30 +-
 source4/scripting/bin/samba_dnsupdate              |   34 +-
 source4/scripting/bin/samba_kcc                    |   74 +-
 source4/scripting/bin/samba_upgradedns             |   28 +-
 source4/scripting/bin/samba_upgradeprovision       |    2 +-
 source4/selftest/tests.py                          |   47 +-
 source4/setup/wscript_build                        |    2 +-
 source4/smb_server/smb/wscript_build               |    2 +-
 source4/smb_server/smb2/receive.c                  |    2 +-
 source4/smb_server/smb2/wscript_build              |    2 +-
 source4/smb_server/smb_server.h                    |    2 +-
 source4/smb_server/wscript_build                   |    4 +-
 source4/smbd/process_standard.c                    |    6 -
 source4/smbd/server.c                              |    9 +-
 source4/smbd/service.c                             |    2 +-
 source4/torture/basic/aliases.c                    |    4 +-
 source4/torture/basic/base.c                       |    1 -
 source4/torture/basic/misc.c                       |    4 +-
 source4/torture/drs/wscript_build                  |    2 +-
 source4/torture/gentest.c                          |    7 +-
 source4/torture/ldap/cldap.c                       |   13 +-
 source4/torture/ldap/netlogon.c                    |   13 +-
 source4/torture/ldb/ldb.c                          |  463 ++-
 source4/torture/local/fsrvp_state.c                |   20 +-
 source4/torture/local/local.c                      |    1 -
 source4/torture/local/wscript_build                |    2 +-
 source4/torture/nbench/nbio.c                      |    4 +-
 source4/torture/nbt/wins.c                         |    3 +-
 source4/torture/ndr/backupkey.c                    |    6 +-
 source4/torture/ndr/clusapi.c                      |  383 ++
 source4/torture/ndr/ndr.c                          |    6 +-
 source4/torture/ndr/negoex.c                       |  100 +
 source4/torture/ndr/witness.c                      |   44 +
 source4/torture/raw/pingpong.c                     |    2 +-
 source4/torture/raw/session.c                      |    2 +-
 source4/torture/rpc/backupkey.c                    |  801 +++--
 source4/torture/rpc/backupkey_heimdal.c            | 2134 +++++++++++
 source4/torture/rpc/clusapi.c                      |  459 ++-
 source4/torture/rpc/fsrvp.c                        |    2 +-
 source4/torture/rpc/lsa.c                          |   20 +-
 source4/torture/rpc/oxidresolve.c                  |  100 +-
 source4/torture/rpc/remact.c                       |   47 +-
 source4/torture/rpc/rpc.c                          |    4 +-
 source4/torture/rpc/spoolss.c                      |    2 +-
 source4/torture/rpc/spoolss_notify.c               |    2 +-
 source4/torture/smb2/connect.c                     |   89 +-
 source4/torture/smb2/dir.c                         |   28 +
 source4/torture/smb2/durable_open.c                |    2 +-
 source4/torture/smb2/rename.c                      |    2 +-
 source4/torture/smb2/replay.c                      | 1381 +++++++-
 source4/torture/smb2/session.c                     |  340 +-
 source4/torture/smb2/smb2.c                        |    4 +-
 source4/torture/smb2/streams.c                     |   74 +
 source4/torture/unix/whoami.c                      |   16 +-
 source4/torture/util_smb.c                         |    6 +-
 source4/torture/vfs/fruit.c                        |    2 +-
 source4/torture/vfs/vfs.c                          |    2 +-
 source4/torture/winbind/struct_based.c             |   15 +-
 source4/torture/wscript_build                      |   47 +-
 source4/utils/man/ntlm_auth4.1.xml                 |    2 +-
 source4/web_server/web_server.c                    |   15 +-
 source4/web_server/wsgi.c                          |    7 -
 source4/wrepl_server/wrepl_server.c                |    4 +-
 testprogs/blackbox/dbcheck-oldrelease.sh           |   82 +-
 testprogs/blackbox/demote-saveddb.sh               |   67 +
 testprogs/blackbox/test_kinit.sh                   |  273 --
 testprogs/blackbox/test_kinit_heimdal.sh           |  273 ++
 ...init_trusts.sh => test_kinit_trusts_heimdal.sh} |    0
 testprogs/blackbox/test_net_ads.sh                 |   35 +
 testprogs/blackbox/test_pdbtest.sh                 |    7 +
 .../{test_pkinit.sh => test_pkinit_heimdal.sh}     |    0
 testprogs/win32/spoolss/README.win32               |    2 +-
 testprogs/win32/spoolss/testspoolss.c              |    4 +-
 tests/oldquotas.c                                  |  174 +
 testsuite/headers/wscript_build                    |   13 +-
 third_party/waf/wafadmin/3rdparty/gccdeps.py       |    2 +-
 .../waf/wafadmin/3rdparty/print_commands.py        |   25 +
 third_party/waf/wafadmin/Build.py                  |    4 +
 third_party/waf/wafadmin/Node.py                   |    7 +
 third_party/waf/wafadmin/TaskGen.py                |    3 +
 third_party/waf/wafadmin/Tools/cc.py               |    6 +-
 third_party/waf/wafadmin/Tools/ccroot.py           |   10 +-
 third_party/waf/wafadmin/Tools/config_c.py         |    4 +
 third_party/waf/wafadmin/Tools/msvc.py             |    2 +-
 third_party/waf/wafadmin/Tools/osx.py              |    6 +-
 third_party/waf/wafadmin/Utils.py                  |   44 +-
 wscript                                            |   25 +-
 1688 files changed, 78307 insertions(+), 34359 deletions(-)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..9d12665
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,31 @@
+language: c
+dist: trusty
+
+sudo: true
+
+cache: ccache
+
+# Everything except samba and ctdb (long tests)
+env:
+  - TASK=samba-xc
+  - TASK=samba-ctdb
+  - TASK=samba-libs
+  - TASK=samba-static
+  - TASK=ldb
+  - TASK=tdb
+  - TASK=talloc
+  - TASK=replace
+  - TASK=tevent
+  - TASK=pidl
+
+# Fail everything after the first job fails
+matrix:
+  fast_finish: true
+
+before_install:
+ - sudo apt-get update -qq
+ - sudo apt-get install --assume-yes screen git build-essential libacl1-dev libattr1-dev libblkid-dev libgnutls-dev libreadline-dev python-dev libpam0g-dev python-dnspython gdb pkg-config libpopt-dev libldap2-dev dnsutils libbsd-dev attr krb5-user docbook-xsl libcups2-dev acl bison debhelper docbook-xml docbook-xsl flex libaio-dev libbsd-dev libcap-dev libcups2-dev libncurses5-dev libpam0g-dev libpopt-dev libreadline-dev perl perl-modules libparse-yapp-perl pkg-config python-all-dev pyth [...]
+
+script:
+ - git fetch --unshallow
+ - ./script/autobuild.py --tail --testbase=/tmp $TASK
diff --git a/Makefile b/Makefile
index aa532b6..95681ae 100644
--- a/Makefile
+++ b/Makefile
@@ -35,6 +35,9 @@ quicktest:
 randomized-test:
 	$(WAF) test --random-order $(TEST_OPTIONS)
 
+testlist:
+	$(WAF) test --list $(TEST_OPTIONS)
+
 dist:
 	touch .tmplock
 	WAFLOCK=.tmplock $(WAF) dist
diff --git a/README b/README
index 6fc98e6..bdc1cb2 100644
--- a/README
+++ b/README
@@ -100,7 +100,23 @@ Related packages include:
 CONTRIBUTIONS
 =============
 
-If you want to contribute to the development of the software then
+1. To contribute via GitHub
+  - fork the official Samba team repository on GitHub
+      * see https://github.com/samba-team/samba
+  - become familiar with the coding standards as described in README.Coding
+  - make sure you read the Samba copyright policy
+      * see https://www.samba.org/samba/devel/copyright-policy.html
+  - create a feature branch
+  - make changes
+  - when committing, be sure to add signed-off-by tags
+      * see https://wiki.samba.org/index.php/CodeReview#commit_message_tags
+  - send a pull request for your branch through GitHub
+  - this will trigger an email to the samba-technical mailing list
+  - discussion happens on the samba-technical mailing list as described below
+  - more info on using Git for Samba development can be found on the Samba Wiki
+      * see https://wiki.samba.org/index.php/Using_Git_for_Samba_Development
+
+2. If you want to contribute to the development of the software then
 please join the mailing list. The Samba team accepts patches
 (preferably in "diff -u" format, see http://samba.org/samba/devel/ 
 for more details) and are always glad to receive feedback or 
@@ -132,7 +148,7 @@ collection of information under docs/.
 A list of Samba documentation in languages other than English is
 available on the web page.
 
-If you would like to help with the documentation, please coodinate 
+If you would like to help with the documentation, please coordinate
 on the samba at samba.org mailing list.  See the next section for details 
 on subscribing to samba mailing lists.
 
diff --git a/README.Coding b/README.Coding
index 52dca49..29bad1b 100644
--- a/README.Coding
+++ b/README.Coding
@@ -320,6 +320,39 @@ Samba tries to avoid "typedef struct { .. } x_t;" so we do always try to use
 "struct x { .. };". We know there are still such typedefs in the code,
 but for new code, please don't do that anymore.
 
+Initialize pointers
+-------------------
+
+All pointer variables MUST be initialized to NULL. History has
+demonstrated that uninitialized pointer variables have lead to various
+bugs and security issues.
+
+Pointers MUST be initialized even if the assignment directly follows
+the declaration, like pointer2 in the example below, because the
+instructions sequence may change over time.
+
+Good Example:
+
+	char *pointer1 = NULL;
+	char *pointer2 = NULL;
+
+	pointer2 = some_func2();
+
+	...
+
+	pointer1 = some_func1();
+
+Bad Example:
+
+	char *pointer1;
+	char *pointer2;
+
+	pointer2 = some_func2();
+
+	...
+
+	pointer1 = some_func1();
+
 Make use of helper variables
 ----------------------------
 
@@ -329,7 +362,7 @@ it's also easier to use the "step" command within gdb.
 
 Good Example:
 
-	char *name;
+	char *name = NULL;
 
 	name = get_some_name();
 	if (name == NULL) {
@@ -384,15 +417,21 @@ The only exception is the test code that depends repeated use of calls
 like CHECK_STATUS, CHECK_VAL and others.
 
 
-Function names in DEBUG statements
-----------------------------------
+DEBUG statements
+----------------
 
-Many DEBUG statements contain the name of the function they appear in. This is
-not a good idea, as this is prone to bitrot. Function names change, code
-moves, but the DEBUG statements are not adapted. Use %s and __func__ for this:
+Use these following macros instead of DEBUG:
 
-Bad Example:
-	DEBUG(0, ("strstr_m: src malloc fail\n"));
+DBG_ERR	log level 0		error conditions
+DBG_WARNING	log level 1		warning conditions
+DBG_NOTICE	log level 3		normal, but significant, condition
+DBG_INFO	log level 5		informational message
+DBG_DEBUG	log level 10		debug-level message
 
-Good Example:
-	DEBUG(0, ("%s: src malloc fail\n", __func__));
+Example usage:
+
+DBG_ERR("Memory allocation failed\n");
+DBG_DEBUG("Received %d bytes\n", count);
+
+The messages from these macros are automatically prefixed with the
+function name.
diff --git a/VERSION b/VERSION
index 2dec4b2..437e544 100644
--- a/VERSION
+++ b/VERSION
@@ -24,8 +24,8 @@
 #  ->  "3.0.0"                                         #
 ########################################################
 SAMBA_VERSION_MAJOR=4
-SAMBA_VERSION_MINOR=3
-SAMBA_VERSION_RELEASE=6
+SAMBA_VERSION_MINOR=4
+SAMBA_VERSION_RELEASE=0
 
 ########################################################
 # If a official release has a serious bug              #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index a47ede4..396ce6e 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,952 +1,439 @@
-                   =============================
-                   Release Notes for Samba 4.3.6
-                           March 8, 2016
-                   =============================
+Release Announcements
+=====================
 
+This is the first stable release of the Samba 4.4 release series.
 
-This is a security release in order to address the following CVEs:
 
-o  CVE-2015-7560 (Incorrect ACL get/set allowed on symlink path)
-o  CVE-2016-0771 (Out-of-bounds read in internal DNS server)
-
-=======
-Details
-=======
-
-o  CVE-2015-7560:
-   All versions of Samba from 3.2.0 to 4.4.0rc3 inclusive are vulnerable to
-   a malicious client overwriting the ownership of ACLs using symlinks.
-
-   An authenticated malicious client can use SMB1 UNIX extensions to
-   create a symlink to a file or directory, and then use non-UNIX SMB1
-   calls to overwrite the contents of the ACL on the file or directory
-   linked to.
-
-o  CVE-2016-0771:
-   All versions of Samba from 4.0.0 to 4.4.0rc3 inclusive, when deployed as
-   an AD DC and choose to run the internal DNS server, are vulnerable to an
-   out-of-bounds read issue during DNS TXT record handling caused by users
-   with permission to modify DNS records.
-
-   A malicious client can upload a specially constructed DNS TXT record,
-   resulting in a remote denial-of-service attack. As long as the affected
-   TXT record remains undisturbed in the Samba database, a targeted DNS
-   query may continue to trigger this exploit.
-
-   While unlikely, the out-of-bounds read may bypass safety checks and
-   allow leakage of memory from the server in the form of a DNS TXT reply.
-
-   By default only authenticated accounts can upload DNS records,
-   as "allow dns updates = secure only" is the default.
-   Any other value would allow anonymous clients to trigger this
-   bug, which is a much higher risk.
-
-
-Changes since 4.3.5:
---------------------
-
-o  Jeremy Allison <jra at samba.org>
-   * BUG 11648: CVE-2015-7560: Getting and setting Windows ACLs on symlinks can
-     change permissions on link target.
-
-o  Garming Sam <garming at catalyst.net.nz>
-   * BUGs 11128, 11686: CVE-2016-0771: Read of uninitialized memory DNS TXT
-     handling.
-
-o  Stefan Metzmacher <metze at samba.org>
-   * BUGs 11128, 11686: CVE-2016-0771: Read of uninitialized memory DNS TXT
-     handling.
-
-
-#######################################
-Reporting bugs & Development Discussion
-#######################################
-
-Please discuss this release on the samba-technical mailing list or by
-joining the #samba-technical IRC channel on irc.freenode.net.
-
-If you do report problems then please try to send high quality
-feedback. If you don't provide vital information to help us track down
-the problem then you will probably be ignored.  All bug reports should
-be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
-database (https://bugzilla.samba.org/).
-
-
-======================================================================
-== Our Code, Our Bugs, Our Responsibility.
-== The Samba Team
-======================================================================
-
-
-Older release notes to follow:
-------------------------------
-
-                   =============================
-                   Release Notes for Samba 4.3.5
-                         February 23, 2016
-                   =============================
-
-
-This is the latest stable release of Samba 4.3.
-
-
-Changes since 4.3.4:
---------------------
-
-o  Jeremy Allison <jra at samba.org>
-   * BUG 10489: s3: smbd: posix_acls: Fix check for setting u:g:o entry on a
-     filesystem with no ACL support.
-   * BUG 11703: s3: smbd: Fix timestamp rounding inside SMB2 create.
-
-o  Christian Ambach <ambi at samba.org>
-   * BUG 6482: s3:utils/smbget: Fix recursive download.
-   * BUG 11400: s3:smbd/oplock: Obey kernel oplock setting when releasing
-     oplocks.
-
-o  Alexander Bokovoy <ab at samba.org>
-   * BUG 11693: s3-parm: Clean up defaults when removing global parameters.
-
-o  Ralph Boehme <slow at samba.org>
-   * BUG 11684: s3:smbd: Ignore initial allocation size for directory creation.
-   * BUG 11714: lib/tsocket: Work around sockets not supporting FIONREAD.
-
-o  Amitay Isaacs <amitay at gmail.com>
-   * BUG 11705: ctdb: Remove error messages after kernel security update
-     (CVE-2015-8543).
-
-o  Volker Lendecke <vl at samba.org>
-   * BUG 11732: param: Fix str_list_v3 to accept ";" again.
-
-o  Stefan Metzmacher <metze at samba.org>
-   * BUG 11699: Use M2Crypto.RC4.RC4 on platforms without Crypto.Cipher.ARC4.
-
-o  Jose A. Rivera <jarrpa at samba.org>
-   * BUG 11727: s3:smbd:open: Skip redundant call to file_set_dosmode when
-     creating a new file.
-
-o  Christof Schmitt <cs at samba.org>
-   * BUG 11670: winbindd: Handle expired sessions correctly.
-
-o  Andreas Schneider <asn at samba.org>
-   * BUG 11690: s3-client: Add a KRB5 wrapper for smbspool.
-
-o  Uri Simchoni <uri at samba.org>
-   * BUG 11580: vfs_shadow_copy2: Fix case where snapshots are outside the
-     share.
-   * BUG 11662: smbclient: Query disk usage relative to current directory.
-   * BUG 11681: smbd: Show correct disk size for different quota and dfree block
-     sizes.
-   * BUG 11682: smbcacls: Fix uninitialized variable.
-
-o  Martin Schwenke <martin at meltin.net>
-   * BUG 11719: ctdb-scripts: Drop use of "smbcontrol winbindd ip-dropped ...".
-
-o  Hemanth Thummala <hemanth.thummala at nutanix.com>
-   * BUG 11708: loadparm: Fix memory leak issue.
-
-
-#######################################
-Reporting bugs & Development Discussion
-#######################################
-
-Please discuss this release on the samba-technical mailing list or by
-joining the #samba-technical IRC channel on irc.freenode.net.
-
-If you do report problems then please try to send high quality
-feedback. If you don't provide vital information to help us track down
-the problem then you will probably be ignored.  All bug reports should
-be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
-database (https://bugzilla.samba.org/).
-
-
-======================================================================
-== Our Code, Our Bugs, Our Responsibility.
-== The Samba Team
-======================================================================
-
-
-----------------------------------------------------------------------
-
-
-                   =============================
-                   Release Notes for Samba 4.3.4
-                         January 12, 2016
-                   =============================
-
-
-This is the latest stable release of Samba 4.3.
-
-
-Changes since 4.3.3:
---------------------
-
-o  Michael Adam <obnox at samba.org>
-   * BUG 11619: doc: Fix a typo in the smb.conf manpage, explanation of idmap
-     config.
-   * BUG 11647: s3:smbd: Fix a corner case of the symlink verification.
-
-o  Jeremy Allison <jra at samba.org>
-   * BUG 11624: s3: libsmb: Correctly initialize the list head when keeping a
-     list of primary followed by DFS connections.
-   * BUG 11625: Reduce the memory footprint of empty string options.
-
-o  Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
-   * BUG 11659: Update lastLogon and lastLogonTimestamp.
-
-o  Ralph Boehme <slow at samba.org>
-   * BUG 11065: vfs_fruit: Enable POSIX directory rename semantics.
-   * BUG 11466: Copying files with vfs_fruit fails when using vfs_streams_xattr
-     without stream prefix and type suffix.
-   * BUG 11645: smbd: Make "hide dot files" option work with "store dos
-     attributes = yes".
-
-o  Günther Deschner <gd at samba.org>
-   * BUG 11639: lib/async_req: Do not install async_connect_send_test.
-
-o  Stefan Metzmacher <metze at samba.org>
-   * BUG 11394: Crash: Bad talloc magic value - access after free.
+UPGRADING
+=========
 
-o  Rowland Penny <repenny241155 at gmail.com>
-   * BUG 11613: samba-tool: Fix uncaught exception if no fSMORoleOwner
-     attribute is given.
+Nothing special.
 
-o  Karolin Seeger <kseeger at samba.org>
-   * BUG 11619: docs: Fix some typos in the idmap backend section.
-   * BUG 11641: docs: Fix typos in man vfs_gpfs.
 
-o  Uri Simchoni <uri at samba.org>
-   * BUG 11649: smbd: Do not disable "store dos attributes" on-the-fly.
+NEW FEATURES/CHANGES
+====================
 
+Asynchronous flush requests
+---------------------------
 
-#######################################
-Reporting bugs & Development Discussion
-#######################################
+Flush requests from SMB2/3 clients are handled asynchronously and do
+not block the processing of other requests. Note that 'strict sync'
+has to be set to 'yes' for Samba to honor flush requests from SMB
+clients.
 
-Please discuss this release on the samba-technical mailing list or by
-joining the #samba-technical IRC channel on irc.freenode.net.
+s3: smbd
+--------
 
-If you do report problems then please try to send high quality
-feedback. If you don't provide vital information to help us track down
-the problem then you will probably be ignored.  All bug reports should
-be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
-database (https://bugzilla.samba.org/).
+Remove '--with-aio-support' configure option. We no longer would ever prefer
+POSIX-RT aio, use pthread_aio instead.
 
+samba-tool sites
+----------------
 
-======================================================================
-== Our Code, Our Bugs, Our Responsibility.
-== The Samba Team
-======================================================================
+The 'samba-tool sites' subcommand can now be run against another server by
+specifying an LDB URL using the '-H' option and not against the local database
+only (which is still the default when no URL is given).
 
+samba-tool domain demote
+------------------------
 
-----------------------------------------------------------------------
-
-
-                   =============================
-                   Release Notes for Samba 4.3.3
-                         December 16, 2015
-                   =============================
+Add '--remove-other-dead-server' option to 'samba-tool domain demote'
+subcommand. The new version of this tool now can remove another DC that is
+itself offline.  The '--remove-other-dead-server' removes as many references
+to the DC as possible.
 
+samba-tool drs clone-dc-database
+--------------------------------
 
-This is a security release in order to address the following CVEs:
+Replicate an initial clone of domain, but do not join it.
+This is developed for debugging purposes, but not for setting up another DC.
 
-o  CVE-2015-3223 (Denial of service in Samba Active Directory
-		  server)
-o  CVE-2015-5252 (Insufficient symlink verification in smbd)
-o  CVE-2015-5299 (Missing access control check in shadow copy
-		  code)
-o  CVE-2015-5296 (Samba client requesting encryption vulnerable
-		  to downgrade attack)
-o  CVE-2015-8467 (Denial of service attack against Windows
-		  Active Directory server)
-o  CVE-2015-5330 (Remote memory read in Samba LDAP server)
+pdbedit
+-------
 
-Please note that if building against a system libldb, the required
-version has been bumped to ldb-1.1.24.  This is needed to ensure
-we build against a system ldb library that contains the fixes
-for CVE-2015-5330 and CVE-2015-3223.
+Add '--set-nt-hash' option to pdbedit to update user password from nt-hash
+hexstring. 'pdbedit -vw' shows also password hashes.
 
-=======
-Details
-=======
+smbstatus
+---------
 
-o  CVE-2015-3223:
-   All versions of Samba from 4.0.0 to 4.3.2 inclusive (resp. all
-   ldb versions up to 1.1.23 inclusive) are vulnerable to
-   a denial of service attack in the samba daemon LDAP server.
+'smbstatus' was enhanced to show the state of signing and encryption for
+sessions and shares.
 
-   A malicious client can send packets that cause the LDAP server in the
-   samba daemon process to become unresponsive, preventing the server
-   from servicing any other requests.
+smbget
+------
+The -u and -p options for user and password were replaced by the -U option that
+accepts username[%password] as in many other tools of the Samba suite.
+Similary, smbgetrc files do not accept username and password options any more,
+only a single "user" option which also accepts user%password combinations.
+The -P option was removed.
 
-   This flaw is not exploitable beyond causing the code to loop expending
-   CPU resources.
+s4-rpc_server
+-------------
 
-o  CVE-2015-5252:
-   All versions of Samba from 3.0.0 to 4.3.2 inclusive are vulnerable to
-   a bug in symlink verification, which under certain circumstances could
-   allow client access to files outside the exported share path.
+Add a GnuTLS based backupkey implementation.
 
-   If a Samba share is configured with a path that shares a common path
-   prefix with another directory on the file system, the smbd daemon may
-   allow the client to follow a symlink pointing to a file or directory
-   in that other directory, even if the share parameter "wide links" is
-   set to "no" (the default).
+ntlm_auth
+---------
 
-o  CVE-2015-5299:
-   All versions of Samba from 3.2.0 to 4.3.2 inclusive are vulnerable to
-   a missing access control check in the vfs_shadow_copy2 module. When
-   looking for the shadow copy directory under the share path the current
-   accessing user should have DIRECTORY_LIST access rights in order to
-   view the current snapshots.
+Using the '--offline-logon' enables ntlm_auth to use cached passwords when the
+DC is offline.
 
-   This was not being checked in the affected versions of Samba.
+Allow '--password' force a local password check for ntlm-server-1 mode.
 
-o  CVE-2015-5296:
-   Versions of Samba from 3.2.0 to 4.3.2 inclusive do not ensure that
-   signing is negotiated when creating an encrypted client connection to
-   a server.
+vfs_offline
+-----------
 
-   Without this a man-in-the-middle attack could downgrade the connection
-   and connect using the supplied credentials as an unsigned, unencrypted
-   connection.
+A new VFS module called vfs_offline has been added to mark all files in the
+share as offline. It can be useful for shares mounted on top of a remote file
+system (either through a samba VFS module or via FUSE).
 
-o  CVE-2015-8467:
-   Samba, operating as an AD DC, is sometimes operated in a domain with a
-   mix of Samba and Windows Active Directory Domain Controllers.
+KCC
+---
 
-   All versions of Samba from 4.0.0 to 4.3.2 inclusive, when deployed as
-   an AD DC in the same domain with Windows DCs, could be used to
-   override the protection against the MS15-096 / CVE-2015-2535 security
-   issue in Windows.
+The Samba KCC has been improved, but is still disabled by default.
 
-   Prior to MS16-096 it was possible to bypass the quota of machine
-   accounts a non-administrative user could create.  Pure Samba domains
-   are not impacted, as Samba does not implement the
-   SeMachineAccountPrivilege functionality to allow non-administrator
-   users to create new computer objects.
+DNS
+---
 
-o  CVE-2015-5330:
-   All versions of Samba from 4.0.0 to 4.3.2 inclusive (resp. all
-   ldb versions up to 1.1.23 inclusive) are vulnerable to
-   a remote memory read attack in the samba daemon LDAP server.
+There were several improvements concerning the Samba DNS server.
 
-   A malicious client can send packets that cause the LDAP server in the
-   samba daemon process to return heap memory beyond the length of the
-   requested value.
+Active Directory
+----------------
 
-   This memory may contain data that the client should not be allowed to
-   see, allowing compromise of the server.
+There were some improvements in the Active Directory area.
 
-   The memory may either be returned to the client in an error string, or
-   stored in the database by a suitabily privileged user.  If untrusted
-   users can create objects in your database, please confirm that all DN
-   and name attributes are reasonable.
-
-
-Changes since 4.3.2:
+WINS nsswitch module
 --------------------
 
-o  Andrew Bartlett <abartlet at samba.org>
-   * BUG 11552: CVE-2015-8467: samdb: Match MS15-096 behaviour for
-     userAccountControl.
-
-o  Jeremy Allison <jra at samba.org>
-   * BUG 11325: CVE-2015-3223: Fix LDAP \00 search expression attack DoS.
-   * BUG 11395: CVE-2015-5252: Fix insufficient symlink verification (file
-     access outside the share).
-   * BUG 11529: CVE-2015-5299: s3-shadow-copy2: Fix missing access check on
-     snapdir.
-
-o  Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
-   * BUG 11599: CVE-2015-5330: Fix remote read memory exploit in LDB.
-
-o  Stefan Metzmacher <metze at samba.org>
-   * BUG 11536: CVE-2015-5296: Add man in the middle protection when forcing
-     smb encryption on the client side.
-
-
-#######################################
-Reporting bugs & Development Discussion
-#######################################
-
-Please discuss this release on the samba-technical mailing list or by
-joining the #samba-technical IRC channel on irc.freenode.net.
-
-If you do report problems then please try to send high quality
-feedback. If you don't provide vital information to help us track down
-the problem then you will probably be ignored.  All bug reports should
-be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
-database (https://bugzilla.samba.org/).
-
-
-======================================================================
-== Our Code, Our Bugs, Our Responsibility.
-== The Samba Team
-======================================================================
+The WINS nsswitch module has been rewritten to address memory issues and to
+simplify the code. The module now uses libwbclient to do WINS queries. This
+means that winbind needs to be running in order to resolve WINS names using
+the nss_wins module. This does not affect smbd.
 
+CTDB changes
+------------
 
-----------------------------------------------------------------------
+* CTDB now uses a newly implemented parallel database recovery scheme
+  that avoids deadlocks with smbd.
 
+  In certain circumstances CTDB and smbd could deadlock.  The new
+  recovery implementation avoid this.  It also provides improved
+  recovery performance.
 
-                   =============================
-                   Release Notes for Samba 4.3.2
-                         December 01, 2015
-                   =============================
+* All files are now installed into and referred to by the paths
+  configured at build time.  Therefore, CTDB will now work properly
+  when installed into the default location at /usr/local.
 
+* Public CTDB header files are no longer installed, since Samba and
+  CTDB are built from within the same source tree.
 
-This is the latest stable release of Samba 4.3.
+* CTDB_DBDIR can now be set to tmpfs[:<tmpfs-options>]
 
+  This will cause volatile TDBs to be located in a tmpfs.  This can
+  help to avoid performance problems associated with contention on the
+  disk where volatile TDBs are usually stored.  See ctdbd.conf(5) for
+  more details.
 
-Changes since 4.3.1:
---------------------
-
-o   Michael Adam <obnox at samba.org>
-    * BUG 11577: ctdb: Open the RO tracking db with perms 0600 instead of 0000.
-
-o   Jeremy Allison <jra at samba.org>
-    * BUG 11452: s3-smbd: Fix old DOS client doing wildcard delete - gives an
-      attribute type of zero.
-    * BUG 11565: auth: gensec: Fix a memory leak.
-    * BUG 11566: lib: util: Make non-critical message a warning.
-    * BUG 11589: s3: smbd: If EAs are turned off on a share don't allow an SMB2
-      create containing them.
-    * BUG 11615: s3: smbd: have_file_open_below() fails to enumerate open files
-      below an open directory handle.
-
-o   Ralph Boehme <slow at samba.org>
-    * BUG 11562: s4:lib/messaging: Use correct path for names.tdb.
-    * BUG 11564: async_req: Fix non-blocking connect().
-
-o   Volker Lendecke <vl at samba.org>
-    * BUG 11243: vfs_gpfs: Re-enable share modes.
-    * BUG 11570: smbd: Send SMB2 oplock breaks unencrypted.
-    * BUG 11612: winbind: Fix crash on invalid idmap configs.
+* Configuration variable CTDB_NATGW_SLAVE_ONLY is no longer used.
+  Instead, nodes should be annotated with the "slave-only" option in
+  the CTDB NAT gateway nodes file.  This file must be consistent
+  across nodes in a NAT gateway group.  See ctdbd.conf(5) for more
+  details.
 
-o   YvanM <yvan.masson at openmailbox.org>
-    * BUG 11584: manpage: Correct small typo error.
+* New event script 05.system allows various system resources to be
+  monitored
 
-o   Stefan Metzmacher <metze at samba.org>
-    * BUG 11327: dcerpc.idl: Accept invalid dcerpc_bind_nak pdus.
-    * BUG 11581: s3:smb2_server: Make the logic of SMB2_CANCEL DLIST_REMOVE()
-      clearer.
+  This can be helpful for explaining poor performance or unexpected
+  behaviour.  New configuration variables are
+  CTDB_MONITOR_FILESYSTEM_USAGE, CTDB_MONITOR_MEMORY_USAGE and
+  CTDB_MONITOR_SWAP_USAGE.  Default values cause warnings to be
+  logged.  See the SYSTEM RESOURCE MONITORING CONFIGURATION in
+  ctdbd.conf(5) for more information.
 
-o   Marc Muehlfeld <mmuehlfeld at samba.org>
-    * BUG 9912: Changing log level of two entries to DBG_NOTICE.
-    * BUG 11581: s3-smbd: Fix use after issue in smbd_smb2_request_dispatch().
+  The memory, swap and filesystem usage monitoring previously found in
+  00.ctdb and 40.fs_use is no longer available.  Therefore,
+  configuration variables CTDB_CHECK_FS_USE, CTDB_MONITOR_FREE_MEMORY,
+  CTDB_MONITOR_FREE_MEMORY_WARN and CTDB_CHECK_SWAP_IS_NOT_USED are
+  now ignored.
 
-o   Noel Power <noel.power at suse.com>
-    * BUG 11569: Fix winbindd crashes with samlogon for trusted domain user.
-    * BUG 11597: Backport some valgrind fixes from upstream master.
+* The 62.cnfs eventscript has been removed.  To get a similar effect
+  just do something like this:
 
-o   Andreas Schneider <asn at samba.org
-    * BUG 11563: Fix segfault of 'net ads (join|leave) -S INVALID' with
-      nss_wins.
+      mmaddcallback ctdb-disable-on-quorumLoss \
+        --command /usr/bin/ctdb \
+        --event quorumLoss --parms "disable"
 
-o   Tom Schulz <schulz at adi.com>
-    * BUG 11511: Add libreplace dependency to texpect, fixes a linking error on
-      Solaris.
-    * BUG 11512: s4: Fix linking of 'smbtorture' on Solaris.
+      mmaddcallback ctdb-enable-on-quorumReached \
+        --command /usr/bin/ctdb \
+        --event quorumReached --parms "enable"
 
-o   Uri Simchoni <uri at samba.org>
-    * BUG 11608: auth: Consistent handling of well-known alias as primary gid.
+* The CTDB tunable parameter EventScriptTimeoutCount has been renamed
+  to MonitorTimeoutCount
 
-#######################################
-Reporting bugs & Development Discussion
-#######################################
-
-Please discuss this release on the samba-technical mailing list or by
-joining the #samba-technical IRC channel on irc.freenode.net.
+  It has only ever been used to limit timed-out monitor events.
 
-If you do report problems then please try to send high quality
-feedback. If you don't provide vital information to help us track down
-the problem then you will probably be ignored.  All bug reports should
-be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
-database (https://bugzilla.samba.org/).
+  Configurations containing CTDB_SET_EventScriptTimeoutCount=<n> will
+  cause CTDB to fail at startup.  Useful messages will be logged.
 
+* The commandline option "-n all" to CTDB tool has been removed.
 
-======================================================================
-== Our Code, Our Bugs, Our Responsibility.
-== The Samba Team
-======================================================================
+  The option was not uniformly implemented for all the commands.
+  Instead of command "ctdb ip -n all", use "ctdb ip all".
 
+* All CTDB current manual pages are now correctly installed
 
-----------------------------------------------------------------------
 
+EXPERIMENTAL FEATURES
+=====================
 
-                   =============================
-                   Release Notes for Samba 4.3.1
-                         October 20, 2015
-                   =============================
+SMB3 Multi-Channel
+------------------
 
+Samba 4.4.0 adds *experimental* support for SMB3 Multi-Channel.
+Multi-Channel is an SMB3 protocol feature that allows the client
+to bind multiple transport connections into one authenticated
+SMB session. This allows for increased fault tolerance and
+throughput. The client chooses transport connections as reported
+by the server and also chooses over which of the bound transport
+connections to send traffic. I/O operations for a given file
+handle can span multiple network connections this way.
+An SMB multi-channel session will be valid as long as at least
+one of its channels are up.
 
-This is the latest stable release of Samba 4.3.
+In Samba, multi-channel can be enabled by setting the new
+smb.conf option "server multi channel support" to "yes".
+It is disabled by default.
 
+Samba has to report interface speeds and some capabilities to
+the client. On Linux, Samba can auto-detect the speed of an
+interface. But to support other platforms, and in order to be
+able to manually override the detected values, the "interfaces"
+smb.conf option has been given an extended syntax, by which an
+interface specification can additionally carry speed and
+capability information. The extended syntax looks like this
+for setting the speed to 1 gigabit per second:
 
-Changes since 4.3.0:
---------------------
+    interfaces = 192.168.1.42;speed=1000000000
 
-o   Jeremy Allison <jra at samba.org>
-    * BUG 10252: s3: smbd: Fix our access-based enumeration on "hide unreadable"
-      to match Windows.
-    * BUG 10634: smbd: Fix file name buflen and padding in notify repsonse.
-    * BUG 11486: s3: smbd: Fix mkdir race condition.
-    * BUG 11522: s3: smbd: Fix opening/creating :stream files on the root share
-      directory.
-    * BUG 11535: s3: smbd: Fix NULL pointer bug introduced by previous 'raw'
-    * stream fix (bug #11522).
-    * BUG 11555: s3: lsa: lookup_name() logic for unqualified (no DOMAIN\
-      component) names is incorrect.
-
-o   Ralph Boehme <slow at samba.org>
-    * BUG 11535: s3: smbd: Fix a crash in unix_convert().
-    * BUG 11543: vfs_fruit: Return value of ad_pack in vfs_fruit.c.
-    * BUG 11549: s3:locking: Initialize lease pointer in
-      share_mode_traverse_fn().
-    * BUG 11550: s3:smbstatus: Add stream name to share_entry_forall().
-    * BUG 11555: s3:lib: Validate domain name in lookup_wellknown_name().
-
-o   Günther Deschner <gd at samba.org>
-    * BUG 11038: kerberos: Make sure we only use prompter type when available.
-
-o   Volker Lendecke <vl at samba.org>
-    * BUG 11038: winbind: Fix 100% loop.
-    * BUG 11053: source3/lib/msghdr.c: Fix compiling error on Solaris.
-
-o   Stefan Metzmacher <metze at samba.org>
-    * BUG 11316: s3:ctdbd_conn: make sure we destroy tevent_fd before closing
-      the socket.
-    * BUG 11515: s4:lib/messaging: Use 'msg.lock' and 'msg.sock' for messaging
-      related subdirs.
-    * BUG 11526: lib/param: Fix hiding of FLAG_SYNONYM values.
-
-o   Björn Jacke <bj at sernet.de>
-    * BUG 10365: nss_winbind: Fix hang on Solaris on big groups.
-    * BUG 11355: build: Use as-needed linker flag also on OpenBSD.
-
-o   Har Gagan Sahai <SHarGagan at novell.com>
-    * BUG 11509: s3: dfs: Fix a crash when the dfs targets are disabled.
-
-o   Andreas Schneider <asn at samba.org>
-    * BUG 11502: pam_winbind: Fix a segfault if initialization fails.
-
-o   Uri Simchoni <uri at samba.org>
-    * BUG 11528: net: Fix a crash with 'net ads keytab create'.
-    * BUG 11547: vfs_commit: set the fd on open before calling SMB_VFS_FSTAT.
+This extension should be used with care and are mainly intended
+for testing. See the smb.conf manual page for details.
 
-#######################################
-Reporting bugs & Development Discussion
-#######################################
+CAVEAT: While this should be working without problems mostly,
+there are still corner cases in the treatment of channel failures
+that may result in DATA CORRUPTION when these race conditions hit.
+It is hence
 
-Please discuss this release on the samba-technical mailing list or by
-joining the #samba-technical IRC channel on irc.freenode.net.
+    NOT RECOMMENDED TO USE MULTI-CHANNEL IN PRODUCTION
 
-If you do report problems then please try to send high quality
-feedback. If you don't provide vital information to help us track down
-the problem then you will probably be ignored.  All bug reports should
-be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
-database (https://bugzilla.samba.org/).
+at this stage. This situation can be expected to improve during
+the life-time of the 4.4 release. Feed-back from test-setups is
+highly welcome.
 
 
-======================================================================
-== Our Code, Our Bugs, Our Responsibility.
-== The Samba Team
-======================================================================
+REMOVED FEATURES
+================
 
+Public headers
+--------------
 
-----------------------------------------------------------------------
+Several public headers are not installed any longer. They are made for internal
+use only. More public headers will very likely be removed in future releases.
 
+The following headers are not installed any longer:
+dlinklist.h, gen_ndr/epmapper.h, gen_ndr/mgmt.h, gen_ndr/ndr_atsvc_c.h,
+gen_ndr/ndr_epmapper_c.h, gen_ndr/ndr_epmapper.h, gen_ndr/ndr_mgmt_c.h,
+gen_ndr/ndr_mgmt.h,gensec.h, ldap_errors.h, ldap_message.h, ldap_ndr.h,
+ldap-util.h, pytalloc.h, read_smb.h, registry.h, roles.h, samba_util.h,
+smb2_constants.h, smb2_create_blob.h, smb2.h, smb2_lease.h, smb2_signing.h,
+smb_cli.h, smb_cliraw.h, smb_common.h, smb_composite.h, smb_constants.h,
+smb_raw.h, smb_raw_interfaces.h, smb_raw_signing.h, smb_raw_trans2.h,
+smb_request.h, smb_seal.h, smb_signing.h, smb_unix_ext.h, smb_util.h,
+torture.h, tstream_smbXcli_np.h.
 
-                   =============================
-                   Release Notes for Samba 4.3.0
-                           September 8, 2015
-                   =============================
+vfs_smb_traffic_analyzer
+------------------------
 
+The SMB traffic analyzer VFS module has been removed, because it is not
+maintained any longer and not widely used.
 
-This is the first stable release of Samba 4.3.
+vfs_scannedonly
+---------------
 
+The scannedonly VFS module has been removed, because it is not maintained
+any longer.
 
-UPGRADING
-=========
+smb.conf changes
+----------------
 
-Read the "New FileChangeNotify subsystem" and "smb.conf changes" sections
-(below).
+  Parameter Name		Description		Default
+  --------------		-----------		-------
+  aio max threads               New                     100
+  ldap page size		Changed default		1000
+  server multi channel support	New			No
+  interfaces			Extended syntax
 
 
-NEW FEATURES
+KNOWN ISSUES
 ============
 
-Logging
--------
-
-The logging code now supports logging to multiple backends.  In
-addition to the previously available syslog and file backends, the
-backends for logging to the systemd-journal, lttng and gpfs have been
-added. Please consult the section for the 'logging' parameter in the
-smb.conf manpage for details.
-
-Spotlight
----------
-
-Support for Apple's Spotlight has been added by integrating with Gnome
-Tracker.
-
-For detailed instructions how to build and setup Samba for Spotlight,
-please see the Samba wiki: <https://wiki.samba.org/index.php/Spotlight>
-
-New FileChangeNotify subsystem
-------------------------------
-
-Samba now contains a new subsystem to do FileChangeNotify. The
-previous system used a central database, notify_index.tdb, to store
-all notification requests. In particular in a cluster this turned out
-to be a major bottleneck, because some hot records need to be bounced
-back and forth between nodes on every change event like a new created
-file.
-
-The new FileChangeNotify subsystem works with a central daemon per
-node. Every FileChangeNotify request and every event are handled by an
-asynchronous message from smbd to the notify daemon. The notify daemon
-maintains a database of all FileChangeNotify requests in memory and
-will distribute the notify events accordingly. This database is
-asynchronously distributed in the cluster by the notify daemons.
-
-The notify daemon is supposed to scale a lot better than the previous
-implementation. The functional advantage is cross-node kernel change
-notify: Files created via NFS will be seen by SMB clients on other
-nodes per FileChangeNotify, despite the fact that popular cluster file
-systems do not offer cross-node inotify.
-
-Two changes to the configuration were required for this new subsystem:
-The parameters "change notify" and "kernel change notify" are not
-per-share anymore but must be set globally. So it is no longer
-possible to enable or disable notify per share, the notify daemon has
-no notion of a share, it only works on absolute paths.
-
-New SMB profiling code
-----------------------
-
-The code for SMB (SMB1, SMB2 and SMB3) profiling uses a tdb instead
-of sysv IPC shared memory. This avoids performance problems and NUMA
-effects. The profile stats are a bit more detailed than before.
-
-Improved DCERPC man in the middle detection for kerberos
---------------------------------------------------------
-
-The gssapi based kerberos backends for gensec have support for
-DCERPC header signing when using DCERPC_AUTH_LEVEL_PRIVACY.
-
-SMB signing required in winbindd by default
--------------------------------------------
-
-The effective value for "client signing" is required
-by default for winbindd, if the primary domain uses active directory.
-
-Experimental NTDB was removed
------------------------------
-
-The experimental NTDB library introduced in Samba 4.0 has been
-removed again.
-
-Improved support for trusted domains (as AD DC)
------------------------------------------------
-
-The support for trusted domains/forests has improved a lot.
-
-samba-tool got "domain trust" subcommands to manage trusts:
-
-  create      - Create a domain or forest trust.
-  delete      - Delete a domain trust.
-  list        - List domain trusts.
-  namespaces  - Manage forest trust namespaces.
-  show        - Show trusted domain details.
-  validate    - Validate a domain trust.
-
-External trusts between individual domains work in both ways
-(inbound and outbound). The same applies to root domains of
-a forest trust. The transitive routing into the other forest
-is fully functional for kerberos, but not yet supported for NTLMSSP.
-
-While a lot of things are working fine, there are currently a few limitations:
-
-  - Both sides of the trust need to fully trust each other!
-  - No SID filtering rules are applied at all!
-  - This means DCs of domain A can grant domain admin rights
-    in domain B.
-  - It's not possible to add users/groups of a trusted domain
-    into domain groups.
-
-SMB 3.1.1 supported
--------------------
-
-Both client and server have support for SMB 3.1.1 now.
-
-This is the dialect introduced with Windows 10, it improves the secure
-negotiation of SMB dialects and features.
-
-There's also a new optinal encryption algorithm aes-gcm-128,
-but for now this is only selected as fallback and aes-ccm-128
-is preferred because of the better performance. This might change
-in future versions when hardware encryption will be supported.
-See https://bugzilla.samba.org/show_bug.cgi?id=11451.
-
-New smbclient subcommands
--------------------------
-
-  - Query a directory for change notifications: notify <dir name>
-  - Server side copy: scopy <source filename> <destination filename>
-
-New rpcclient subcommands
--------------------------
-
-  netshareenumall 	- Enumerate all shares
-  netsharegetinfo 	- Get Share Info
-  netsharesetinfo 	- Set Share Info
-  netsharesetdfsflags	- Set DFS flags
-  netfileenum		- Enumerate open files
-  netnamevalidate	- Validate sharename
-  netfilegetsec		- Get File security
-  netsessdel		- Delete Session
-  netsessenum		- Enumerate Sessions
-  netdiskenum		- Enumerate Disks
-  netconnenum		- Enumerate Connections
-  netshareadd		- Add share
-  netsharedel		- Delete share
-
-New modules
------------
-
-  idmap_script 		- see 'man 8 idmap_script'
-  vfs_unityed_media	- see 'man 8 vfs_unityed_media'
-  vfs_shell_snap	- see 'man 8 vfs_shell_snap'
-
-New sparsely connected replia graph (Improved KCC)
---------------------------------------------------
-
-The Knowledge Consistency Checker (KCC) maintains a replication graph
-for DCs across an AD network. The existing Samba KCC uses a fully
-connected graph, so that each DC replicates from all the others, which
-does not scale well with large networks. In 4.3 there is an
-experimental new KCC that creates a sparsely connected replication
-graph and closely follows Microsoft's specification. It is turned off
-by default. To use the new KCC, set "kccsrv:samba_kcc=true" in
-smb.conf and let us know how it goes. You should consider doing this
-if you are making a large new network. For small networks there is
-little benefit and you can always switch over at a later date.
-
-Configurable TLS protocol support, with better defaults
--------------------------------------------------------
-
-The "tls priority" option can be used to change the supported TLS
-protocols. The default is to disable SSLv3, which is no longer
-considered secure.
-
-Samba-tool now supports all 7 FSMO roles
--------------------------------------------------------
-
-Previously "samba-tool fsmo" could only show, transfer or seize the
-five well-known FSMO roles:
-
-	Schema Master
-	Domain Naming Master
-	RID Master
-	PDC Emulator
-	Infrastructure Master
-
-It can now also show, transfer or seize the DNS infrastructure roles:
-
-	DomainDnsZones Infrastructure Master
-	ForestDnsZones Infrastructure Master
+Currently none.
 
-CTDB logging changes
---------------------
 
-The destination for CTDB logging is now set via a single new
-configuration variable CTDB_LOGGING.  This replaces CTDB_LOGFILE and
-CTDB_SYSLOG, which have both been removed.  See ctdbd.conf(5) for
-details of CTDB_LOGGING.
+CHANGES SINCE 4.4.0rc5
+======================
 
-CTDB no longer runs a separate logging daemon.
+o  Michael Adam <obnox at samba.org>
+   * BUG 11796: smbd: Enable multi-channel if 'server multi channel support =
+     yes' in the config.
 
-CTDB NFS support changes
-------------------------
+o  Günther Deschner <gd at samba.org>
+   * BUG 11802: lib/socket/interfaces: Fix some uninitialied bytes.
 
-CTDB's NFS service management has been combined into a single 60.nfs
-event script.  This updated 60.nfs script now uses a call-out to
-interact with different NFS implementations.  See the CTDB_NFS_CALLOUT
-option in the ctdbd.conf(5) manual page for details.  A default
-call-out is provided to interact with the Linux kernel NFS
-implementation.  The 60.ganesha event script has been removed - a
-sample call-out is provided for NFS Ganesha, based on this script.
+o  Uri Simchoni <uri at samba.org>
+   * BUG 11798: build: Fix build when '--without-quota' specified.
 
-The method of configuring NFS RPC checks has been improved.  See
-ctdb/config/nfs-checks.d/README for details.
 
-Improved Cross-Compiling Support
---------------------------------
+CHANGES SINCE 4.4.0rc4
+======================
 
-A new "hybrid" build configuration mode is added to improve
-cross-compilation support.
+o  Andrew Bartlett <abartlet at samba.org>
+   * BUG 11780: mkdir can return ACCESS_DENIED incorrectly on create race.
+   * BUG 11783: Mismatch between local and remote attribute ids lets
+     replication fail with custom schema.
+   * BUG 11789: Talloc: Version 2.1.6.
 
-A common challenge in cross-compilation is that of obtaining the results
-of tests that have to run on the target, during the configuration
-phase of the build. The Samba build system already supports the following
-means to do so:
+o  Ira Cooper <ira at samba.org>
+   * BUG 11774: vfs_glusterfs: Fix use after free in AIO callback.
 
-  - Executing configure tests using the --cross-execute parameter
-  - Obtaining the results from an answers file using the --cross-answers
-    parameter
+o  Günther Deschner <gd at samba.org>
+   * BUG 11755: Fix net join.
 
-The first method has the drawback of inaccurate results if the tests are
-run using an emulator, or a need to be connected to a running target
-while building, if the tests are to be run on an actual target. The
-second method presents a challenge of figuring out the test results.
+o  Amitay Isaacs <amitay at gmail.com>
+   * BUG 11770: Reset TCP Connections during IP failover.
 
-The new hybrid mode runs the tests and records the result in an answer file.
-To activate this mode, use both --cross-execute and --cross-answers in the
-same configure invocation. This mode can be activated once against a
-running target, and then the generated answers file can be used in
-subsequent builds.
+o  Justin Maggard <jmaggard10 at gmail.com>
+   * BUG 11773: s3:smbd: Add negprot remote arch detection for OSX.
 
-Also supplied is an example script that can be used as the
-cross-execute program. This script copies the test to a running target
-and runs the test on the target, obtaining the result. The obtained
-results are more accurate than running the test with an emulator, because
-they reflect the exact kernel and system libraries that exist on the
-target.
+o  Stefan Metzmacher <metze at samba.org>
+   * BUG 11772: ldb: Version 1.1.26.
+   * BUG 11782: "trustdom_list_done: Got invalid trustdom response" message
+     should be avoided.
 
-Improved Sparse File Support
-----------------------------
-Support for the FSCTL_SET_ZERO_DATA and FSCTL_QUERY_ALLOCATED_RANGES
-SMB2 requests has been added to the smbd file server.
-This allows for clients to deallocate (hole punch) regions within a
-sparse file, and check which portions of a file are allocated.
+o  Uri Simchoni <uri at samba.org>
+   * BUG 11769: libnet: Make Kerberos domain join site-aware.
+   * BUG 11788: Quota is not supported on Solaris 10.
 
 
-######################################################################
-Changes
-#######
+CHANGES SINCE 4.4.0rc3
+======================
 
-smb.conf changes
-----------------
+o  Jeremy Allison <jra at samba.org>
+   * BUG 11648: CVE-2015-7560: Getting and setting Windows ACLs on symlinks can
+     change permissions on link target.
 
-  Parameter Name		Description		Default
-  --------------		-----------		-------
-  logging			New			(empty)
-  msdfs shuffle referrals	New			no
-  smbd profiling level		New			off
-  spotlight			New			no
-  tls priority			New 			NORMAL:-VERS-SSL3.0
-  use ntdb			Removed
-  change notify			Changed to [global]
-  kernel change notify		Changed to [global]
-  client max protocol		Changed	default		SMB3_11
-  server max protocol		Changed default		SMB3_11
-
-Removed modules
----------------
+o  Christian Ambach <ambi at samba.org>
+   * BUG 11767: s3:utils/smbget: Fix option parsing.
 
-vfs_notify_fam - see section 'New FileChangeNotify subsystem'.
+o  Alberto Maria Fiaschi <alberto.fiaschi at estar.toscana.it>
+   * BUG 8093: Access based share enum: handle permission set in configuration
+     files.
 
+o  Stefan Metzmacher <metze at samba.org>
+   * BUG 11702: s3:clispnego: Fix confusing warning in spnego_gen_krb5_wrap().
+   * BUG 11742: tevent: version 0.9.28: Fix memory leak when old signal action
+     restored.
+   * BUG 11755: s3:libads: setup the msDS-SupportedEncryptionTypes attribute on
+     ldap_add.
+   * BUGs 11128, 11686: CVE-2016-0771: Read of uninitialized memory DNS TXT
+     handling.
 
-KNOWN ISSUES
-============
+o  Garming Sam <garming at catalyst.net.nz>
+   * BUGs 11128, 11686: CVE-2016-0771: Read of uninitialized memory DNS TXT
+     handling.
 
-Currently none.
+o  Uri Simchoni <uri at samba.org>
+   * BUG 11691: winbindd: Return trust parameters when listing trusts.
+   * BUG 11753: smbd: Ignore SVHDX create context.
+   * BUG 11763: passdb: Add linefeed to debug message.
 
 
-CHANGES SINCE 4.2.0rc4
+CHANGES SINCE 4.4.0rc2
 ======================
 
-o   Andrew Bartlett <abartlet at samba.org>
-    * Bug 10973: No objectClass found in replPropertyMetaData on ordinary
-      objects (non-deleted)
-    * Bug 11429: Python bindings don't check integer types
-    * Bug 11430: Python bindings don't check array sizes
-
-o   Ralph Boehme <slow at samba.org>
-    * Bug 11467: Handling of 0 byte resource fork stream
+o  Michael Adam <obnox at samba.org>
+   * BUG 11723: lib:socket: Fix CID 1350010: Integer OVERFLOW_BEFORE_WIDEN.
+   * BUG 11735: lib:socket: Fix CID 1350009: Fix illegal memory accesses
+     (BUFFER_SIZE_WARNING).
 
-o   Volker Lendecke <vl at samba.org>
-    * Bug 11488: AD samr GetGroupsForUser fails for users with "()" in
-      their name
+o  Jeremy Allison <jra at samba.org>
+   * BUG 10489: s3: smbd: posix_acls: Fix check for setting u:g:o entry on a
+     filesystem with no ACL support.
 
-o   Stefan Metzmacher <metze at samba.org>
-    * Bug 11429: Python bindings don't check integer types
+o  Christian Ambach <ambi at samba.org>
+   * BUG 11700: s3:utils/smbget: Set default blocksize.
 
-o   Matthieu Patou <mat at matws.net>
-    * Bug 10973: No objectClass found in replPropertyMetaData on ordinary
-      objects (non-deleted)
+o  Anoop C S <anoopcs at redhat.com>
+   * BUG 11734: lib/socket: Fix improper use of default interface speed.
 
+o  Ralph Boehme <slow at samba.org>
+   * BUG 11714: lib/tsocket: Work around sockets not supporting FIONREAD.
 
-CHANGES SINCE 4.2.0rc3
-======================
+o  Volker Lendecke <vl at samba.org>
+   * BUG 11724: smbd: Fix CID 1351215 Improper use of negative value.
+   * BUG 11725: smbd: Fix CID 1351216 Dereference null return value.
+   * BUG 11732: param: Fix str_list_v3 to accept ; again.
 
-o   Ralph Boehme <slow at samba.org>
-    * Bug 11444: Crash in notify_remove caused by change notify = no
+o  Noel Power <noel.power at suse.com>
+   * BUG 11738: libcli: Fix debug message, print sid string for new_ace trustee.
 
-o   Günther Deschner <gd at samba.org>
-    * Bug 11411: smbtorture does not build when configured --with-system-mitkrb5
+o  Jose A. Rivera <jarrpa at samba.org>
+   * BUG 11727: s3:smbd:open: Skip redundant call to file_set_dosmode when
+     creating a new file.
 
-o   Volker Lendecke <vl at samba.org>
-    * Bug 11455: fix recursion problem in rep_strtoll in lib/replace/replace.c
-    * Bug 11464: xid2sid gives inconsistent results
-    * Bug 11465: ctdb: Fix the build on FreeBSD 10.1
+o  Andreas Schneider <asn at samba.org>
+   * BUG 11730: docs: Add manpage for cifsdd.
+   * BUG 11739: Fix installation path of Samba helper binaries.
 
-o   Roel van Meer <roel at 1afa.com>
-    * Bug 11427: nmbd incorrectly matches netbios names as own name
+o  Berend De Schouwer <berend.de.schouwer at gmail.com>
+   * BUG 11643: docs: Add example for domain logins to smbspool man page.
 
-o   Stefan Metzmacher <metze at samba.org>
-    * Bug 11451: Poor SMB3 encryption performance with AES-GCM
-    * Bug 11458: --bundled-libraries=!ldb,!pyldb,!pyldb-util doesn't
-      disable ldb build and install
+o  Martin Schwenke <martin at meltin.net>
+   * BUG 11719: ctdb-scripts: Drop use of "smbcontrol winbindd ip-dropped ..."
 
-o   Andreas Schneider <asn at samba.org>
-    * Bug 9862: Samba "map to guest = Bad uid" doesn't work
+o  Hemanth Thummala <hemanth.thummala at nutanix.com>
+   * BUG 11708: loadparm: Fix memory leak issue.
+   * BUG 11740: Fix memory leak in loadparm.
 
 
-CHANGES SINCE 4.3.0rc2
+CHANGES SINCE 4.4.0rc1
 ======================
 
-o   Andrew Bartlett <abartlet at samba.org>
-    * Bug 11436: samba-tool uncaught exception error
-    * Bug 10493: revert LDAP extended rule 1.2.840.113556.1.4.1941
-                 LDAP_MATCHING_RULE_IN_CHAIN changes
-
-o   Ralph Boehme <slow at samba.org>
-    * Bug 11278: Stream names with colon don't work with
-                 fruit:encoding = native
-    * Bug 11426: net share allowedusers crashes
-
-o   Amitay Isaacs <amitay at gmail.com>
-    * Bug 11432: Fix crash in nested ctdb banning
-    * Bug 11434: Cannot build ctdbpmda
-    * Bug 11431: CTDB's eventscript error handling is broken
-
-o   Stefan Metzmacher <metze at samba.org>
-    * Bug 11451: Poor SMB3 encryption performance with AES-GCM (part1)
-    * Bug 11316: tevent_fd needs to be destroyed before closing the fd
-
-o   Arvid Requate <requate at univention.de>
-    * Bug 11291: NetApp joined to a Samba/ADDC cannot resolve SIDs
+o  Michael Adam <obnox at samba.org>
+   * BUG 11715: s3:vfs:glusterfs: Fix build after quota changes.
 
-o   Martin Schwenke <martin at meltin.net>
-    * Bug 11432: Fix crash in nested ctdb banning
+o  Jeremy Allison <jra at samba.org>
+   * BUG 11703: s3: smbd: Fix timestamp rounding inside SMB2 create.
 
+o  Christian Ambach <ambi at samba.org>
+   * BUG 11700: Streamline 'smbget' options with the rest of the Samba utils.
 
-CHANGES SINCE 4.3.0rc1
-======================
+o  Günther Deschner <gd at samba.org>
+   * BUG 11696: ctdb: Do not provide a useless pkgconfig file for ctdb.
 
-o   Jeremy Allison <jra at samba.org>
-    * BUG 11359: strsep is not available on Solaris
+o  Stefan Metzmacher <metze at samba.org>
+   * BUG 11699: Crypto.Cipher.ARC4 is not available on some platforms, fallback
+     to M2Crypto.RC4.RC4 then.
 
-o   Björn Baumbach <bb at sernet.de>
-    * BUG 11421: Build with GPFS support is broken
+o  Amitay Isaacs <amitay at gmail.com>
+   * BUG 11705: Sockets with htons(IPPROTO_RAW) and CVE-2015-8543.
 
-o   Justin Maggard <jmaggard at netgear.com>
-    * BUG 11320: "force group" with local group not working
+o  Andreas Schneider <asn at samba.org>
+   * BUG 11690: docs: Add smbspool_krb5_wrapper manpage.
 
-o   Martin Schwenke <martin at meltin.net>
-    * BUG 11424: Build broken with --disable-python
+o  Uri Simchoni <uri at samba.org>
+   * BUG 11681: smbd: Show correct disk size for different quota and dfree block
+     sizes.
 
 
 #######################################
@@ -959,7 +446,7 @@ joining the #samba-technical IRC channel on irc.freenode.net.
 If you do report problems then please try to send high quality
 feedback. If you don't provide vital information to help us track down
 the problem then you will probably be ignored.  All bug reports should
-be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
+be filed under the Samba 4.1 and newer product in the project's Bugzilla
 database (https://bugzilla.samba.org/).
 
 
diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c
index 5fc2a70..1344391 100644
--- a/auth/credentials/pycredentials.c
+++ b/auth/credentials/pycredentials.c
@@ -37,26 +37,15 @@ static PyObject *PyString_FromStringOrNULL(const char *str)
 
 static PyObject *py_creds_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
-	pytalloc_Object *ret = (pytalloc_Object *)type->tp_alloc(type, 0);
-	if (ret == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-	ret->talloc_ctx = talloc_new(NULL);
-	if (ret->talloc_ctx == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-	ret->ptr = cli_credentials_init(ret->talloc_ctx);
-	return (PyObject *)ret;
+	return pytalloc_steal(type, cli_credentials_init(NULL));
 }
 
-static PyObject *py_creds_get_username(pytalloc_Object *self)
+static PyObject *py_creds_get_username(PyObject *self, PyObject *unused)
 {
 	return PyString_FromStringOrNULL(cli_credentials_get_username(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_set_username(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_username(PyObject *self, PyObject *args)
 {
 	char *newval;
 	enum credentials_obtained obt = CRED_SPECIFIED;
@@ -70,13 +59,13 @@ static PyObject *py_creds_set_username(pytalloc_Object *self, PyObject *args)
 	return PyBool_FromLong(cli_credentials_set_username(PyCredentials_AsCliCredentials(self), newval, obt));
 }
 
-static PyObject *py_creds_get_password(pytalloc_Object *self)
+static PyObject *py_creds_get_password(PyObject *self, PyObject *unused)
 {
 	return PyString_FromStringOrNULL(cli_credentials_get_password(PyCredentials_AsCliCredentials(self)));
 }
 
 
-static PyObject *py_creds_set_password(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_password(PyObject *self, PyObject *args)
 {
 	char *newval;
 	enum credentials_obtained obt = CRED_SPECIFIED;
@@ -90,12 +79,12 @@ static PyObject *py_creds_set_password(pytalloc_Object *self, PyObject *args)
 	return PyBool_FromLong(cli_credentials_set_password(PyCredentials_AsCliCredentials(self), newval, obt));
 }
 
-static PyObject *py_creds_get_domain(pytalloc_Object *self)
+static PyObject *py_creds_get_domain(PyObject *self, PyObject *unused)
 {
 	return PyString_FromStringOrNULL(cli_credentials_get_domain(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_set_domain(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_domain(PyObject *self, PyObject *args)
 {
 	char *newval;
 	enum credentials_obtained obt = CRED_SPECIFIED;
@@ -109,12 +98,12 @@ static PyObject *py_creds_set_domain(pytalloc_Object *self, PyObject *args)
 	return PyBool_FromLong(cli_credentials_set_domain(PyCredentials_AsCliCredentials(self), newval, obt));
 }
 
-static PyObject *py_creds_get_realm(pytalloc_Object *self)
+static PyObject *py_creds_get_realm(PyObject *self, PyObject *unused)
 {
 	return PyString_FromStringOrNULL(cli_credentials_get_realm(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_set_realm(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_realm(PyObject *self, PyObject *args)
 {
 	char *newval;
 	enum credentials_obtained obt = CRED_SPECIFIED;
@@ -128,12 +117,12 @@ static PyObject *py_creds_set_realm(pytalloc_Object *self, PyObject *args)
 	return PyBool_FromLong(cli_credentials_set_realm(PyCredentials_AsCliCredentials(self), newval, obt));
 }
 
-static PyObject *py_creds_get_bind_dn(pytalloc_Object *self)
+static PyObject *py_creds_get_bind_dn(PyObject *self, PyObject *unused)
 {
 	return PyString_FromStringOrNULL(cli_credentials_get_bind_dn(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_set_bind_dn(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_bind_dn(PyObject *self, PyObject *args)
 {
 	char *newval;
 	if (!PyArg_ParseTuple(args, "s", &newval))
@@ -142,12 +131,12 @@ static PyObject *py_creds_set_bind_dn(pytalloc_Object *self, PyObject *args)
 	return PyBool_FromLong(cli_credentials_set_bind_dn(PyCredentials_AsCliCredentials(self), newval));
 }
 
-static PyObject *py_creds_get_workstation(pytalloc_Object *self)
+static PyObject *py_creds_get_workstation(PyObject *self, PyObject *unused)
 {
 	return PyString_FromStringOrNULL(cli_credentials_get_workstation(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_set_workstation(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_workstation(PyObject *self, PyObject *args)
 {
 	char *newval;
 	enum credentials_obtained obt = CRED_SPECIFIED;
@@ -161,33 +150,33 @@ static PyObject *py_creds_set_workstation(pytalloc_Object *self, PyObject *args)
 	return PyBool_FromLong(cli_credentials_set_workstation(PyCredentials_AsCliCredentials(self), newval, obt));
 }
 
-static PyObject *py_creds_is_anonymous(pytalloc_Object *self)
+static PyObject *py_creds_is_anonymous(PyObject *self, PyObject *unused)
 {
 	return PyBool_FromLong(cli_credentials_is_anonymous(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_set_anonymous(pytalloc_Object *self)
+static PyObject *py_creds_set_anonymous(PyObject *self, PyObject *unused)
 {
 	cli_credentials_set_anonymous(PyCredentials_AsCliCredentials(self));
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_creds_authentication_requested(pytalloc_Object *self)
+static PyObject *py_creds_authentication_requested(PyObject *self, PyObject *unused)
 {
         return PyBool_FromLong(cli_credentials_authentication_requested(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_wrong_password(pytalloc_Object *self)
+static PyObject *py_creds_wrong_password(PyObject *self, PyObject *unused)
 {
         return PyBool_FromLong(cli_credentials_wrong_password(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_set_cmdline_callbacks(pytalloc_Object *self)
+static PyObject *py_creds_set_cmdline_callbacks(PyObject *self, PyObject *unused)
 {
         return PyBool_FromLong(cli_credentials_set_cmdline_callbacks(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_parse_string(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_parse_string(PyObject *self, PyObject *args)
 {
 	char *newval;
 	enum credentials_obtained obt = CRED_SPECIFIED;
@@ -202,20 +191,24 @@ static PyObject *py_creds_parse_string(pytalloc_Object *self, PyObject *args)
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_creds_get_nt_hash(pytalloc_Object *self)
+static PyObject *py_creds_get_nt_hash(PyObject *self, PyObject *unused)
 {
-	const struct samr_Password *ntpw = cli_credentials_get_nt_hash(PyCredentials_AsCliCredentials(self), self->ptr);
+	PyObject *ret;
+	struct cli_credentials *creds = PyCredentials_AsCliCredentials(self);
+	struct samr_Password *ntpw = cli_credentials_get_nt_hash(creds, creds);
 
-	return PyString_FromStringAndSize(discard_const_p(char, ntpw->hash), 16);
+	ret = PyString_FromStringAndSize(discard_const_p(char, ntpw->hash), 16);
+	TALLOC_FREE(ntpw);
+	return ret;
 }
 
-static PyObject *py_creds_get_kerberos_state(pytalloc_Object *self)
+static PyObject *py_creds_get_kerberos_state(PyObject *self, PyObject *unused)
 {
 	int state = cli_credentials_get_kerberos_state(PyCredentials_AsCliCredentials(self));
 	return PyInt_FromLong(state);
 }
 
-static PyObject *py_creds_set_kerberos_state(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_kerberos_state(PyObject *self, PyObject *args)
 {
 	int state;
 	if (!PyArg_ParseTuple(args, "i", &state))
@@ -225,7 +218,7 @@ static PyObject *py_creds_set_kerberos_state(pytalloc_Object *self, PyObject *ar
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_creds_set_krb_forwardable(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_krb_forwardable(PyObject *self, PyObject *args)
 {
 	int state;
 	if (!PyArg_ParseTuple(args, "i", &state))
@@ -236,12 +229,12 @@ static PyObject *py_creds_set_krb_forwardable(pytalloc_Object *self, PyObject *a
 }
 
 
-static PyObject *py_creds_get_forced_sasl_mech(pytalloc_Object *self)
+static PyObject *py_creds_get_forced_sasl_mech(PyObject *self, PyObject *unused)
 {
 	return PyString_FromStringOrNULL(cli_credentials_get_forced_sasl_mech(PyCredentials_AsCliCredentials(self)));
 }
 
-static PyObject *py_creds_set_forced_sasl_mech(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_forced_sasl_mech(PyObject *self, PyObject *args)
 {
 	char *newval;
 	enum credentials_obtained obt = CRED_SPECIFIED;
@@ -256,7 +249,7 @@ static PyObject *py_creds_set_forced_sasl_mech(pytalloc_Object *self, PyObject *
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_creds_guess(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_guess(PyObject *self, PyObject *args)
 {
 	PyObject *py_lp_ctx = Py_None;
 	struct loadparm_context *lp_ctx;
@@ -287,7 +280,7 @@ static PyObject *py_creds_guess(pytalloc_Object *self, PyObject *args)
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_creds_set_machine_account(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_machine_account(PyObject *self, PyObject *args)
 {
 	PyObject *py_lp_ctx = Py_None;
 	struct loadparm_context *lp_ctx;
@@ -322,24 +315,11 @@ static PyObject *py_creds_set_machine_account(pytalloc_Object *self, PyObject *a
 
 static PyObject *PyCredentialCacheContainer_from_ccache_container(struct ccache_container *ccc)
 {
-	PyCredentialCacheContainerObject *py_ret;
-
-	if (ccc == NULL) {
-		Py_RETURN_NONE;
-	}
-
-	py_ret = (PyCredentialCacheContainerObject *)PyCredentialCacheContainer.tp_alloc(&PyCredentialCacheContainer, 0);
-	if (py_ret == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-	py_ret->mem_ctx = talloc_new(NULL);
-	py_ret->ccc = talloc_reference(py_ret->mem_ctx, ccc);
-	return (PyObject *)py_ret;
+	return pytalloc_reference(&PyCredentialCacheContainer, ccc);
 }
 
 
-static PyObject *py_creds_get_named_ccache(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_get_named_ccache(PyObject *self, PyObject *args)
 {
 	PyObject *py_lp_ctx = Py_None;
 	char *ccache_name;
@@ -385,7 +365,7 @@ static PyObject *py_creds_get_named_ccache(pytalloc_Object *self, PyObject *args
 	return NULL;
 }
 
-static PyObject *py_creds_set_gensec_features(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_set_gensec_features(PyObject *self, PyObject *args)
 {
 	unsigned int gensec_features;
 
@@ -397,7 +377,7 @@ static PyObject *py_creds_set_gensec_features(pytalloc_Object *self, PyObject *a
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_creds_get_gensec_features(pytalloc_Object *self, PyObject *args)
+static PyObject *py_creds_get_gensec_features(PyObject *self, PyObject *args)
 {
 	unsigned int gensec_features;
 
@@ -407,71 +387,71 @@ static PyObject *py_creds_get_gensec_features(pytalloc_Object *self, PyObject *a
 
 
 static PyMethodDef py_creds_methods[] = {
-	{ "get_username", (PyCFunction)py_creds_get_username, METH_NOARGS,
+	{ "get_username", py_creds_get_username, METH_NOARGS,
 		"S.get_username() -> username\nObtain username." },
-	{ "set_username", (PyCFunction)py_creds_set_username, METH_VARARGS,
+	{ "set_username", py_creds_set_username, METH_VARARGS,
 		"S.set_username(name, obtained=CRED_SPECIFIED) -> None\n"
 		"Change username." },
-	{ "get_password", (PyCFunction)py_creds_get_password, METH_NOARGS,
+	{ "get_password", py_creds_get_password, METH_NOARGS,
 		"S.get_password() -> password\n"
 		"Obtain password." },
-	{ "set_password", (PyCFunction)py_creds_set_password, METH_VARARGS,
+	{ "set_password", py_creds_set_password, METH_VARARGS,
 		"S.set_password(password, obtained=CRED_SPECIFIED) -> None\n"
 		"Change password." },
-	{ "get_domain", (PyCFunction)py_creds_get_domain, METH_NOARGS,
+	{ "get_domain", py_creds_get_domain, METH_NOARGS,
 		"S.get_domain() -> domain\n"
 		"Obtain domain name." },
-	{ "set_domain", (PyCFunction)py_creds_set_domain, METH_VARARGS,
+	{ "set_domain", py_creds_set_domain, METH_VARARGS,
 		"S.set_domain(domain, obtained=CRED_SPECIFIED) -> None\n"
 		"Change domain name." },
-	{ "get_realm", (PyCFunction)py_creds_get_realm, METH_NOARGS,
+	{ "get_realm", py_creds_get_realm, METH_NOARGS,
 		"S.get_realm() -> realm\n"
 		"Obtain realm name." },
-	{ "set_realm", (PyCFunction)py_creds_set_realm, METH_VARARGS,
+	{ "set_realm", py_creds_set_realm, METH_VARARGS,
 		"S.set_realm(realm, obtained=CRED_SPECIFIED) -> None\n"
 		"Change realm name." },
-	{ "get_bind_dn", (PyCFunction)py_creds_get_bind_dn, METH_NOARGS,
+	{ "get_bind_dn", py_creds_get_bind_dn, METH_NOARGS,
 		"S.get_bind_dn() -> bind dn\n"
 		"Obtain bind DN." },
-	{ "set_bind_dn", (PyCFunction)py_creds_set_bind_dn, METH_VARARGS,
+	{ "set_bind_dn", py_creds_set_bind_dn, METH_VARARGS,
 		"S.set_bind_dn(bind_dn) -> None\n"
 		"Change bind DN." },
-	{ "is_anonymous", (PyCFunction)py_creds_is_anonymous, METH_NOARGS,
+	{ "is_anonymous", py_creds_is_anonymous, METH_NOARGS,
 		NULL },
-	{ "set_anonymous", (PyCFunction)py_creds_set_anonymous, METH_NOARGS,
+	{ "set_anonymous", py_creds_set_anonymous, METH_NOARGS,
         	"S.set_anonymous() -> None\n"
 		"Use anonymous credentials." },
-	{ "get_workstation", (PyCFunction)py_creds_get_workstation, METH_NOARGS,
+	{ "get_workstation", py_creds_get_workstation, METH_NOARGS,
 		NULL },
-	{ "set_workstation", (PyCFunction)py_creds_set_workstation, METH_VARARGS,
+	{ "set_workstation", py_creds_set_workstation, METH_VARARGS,
 		NULL },
-	{ "authentication_requested", (PyCFunction)py_creds_authentication_requested, METH_NOARGS,
+	{ "authentication_requested", py_creds_authentication_requested, METH_NOARGS,
 		NULL },
-	{ "wrong_password", (PyCFunction)py_creds_wrong_password, METH_NOARGS,
+	{ "wrong_password", py_creds_wrong_password, METH_NOARGS,
 		"S.wrong_password() -> bool\n"
 		"Indicate the returned password was incorrect." },
-	{ "set_cmdline_callbacks", (PyCFunction)py_creds_set_cmdline_callbacks, METH_NOARGS,
+	{ "set_cmdline_callbacks", py_creds_set_cmdline_callbacks, METH_NOARGS,
 		"S.set_cmdline_callbacks() -> bool\n"
 		"Use command-line to obtain credentials not explicitly set." },
-	{ "parse_string", (PyCFunction)py_creds_parse_string, METH_VARARGS,
+	{ "parse_string", py_creds_parse_string, METH_VARARGS,
 		"S.parse_string(text, obtained=CRED_SPECIFIED) -> None\n"
 		"Parse credentials string." },
-	{ "get_nt_hash", (PyCFunction)py_creds_get_nt_hash, METH_NOARGS,
+	{ "get_nt_hash", py_creds_get_nt_hash, METH_NOARGS,
 		NULL },
-	{ "get_kerberos_state", (PyCFunction)py_creds_get_kerberos_state, METH_NOARGS,
+	{ "get_kerberos_state", py_creds_get_kerberos_state, METH_NOARGS,
 		NULL },
-	{ "set_kerberos_state", (PyCFunction)py_creds_set_kerberos_state, METH_VARARGS,
+	{ "set_kerberos_state", py_creds_set_kerberos_state, METH_VARARGS,
 		NULL },
-	{ "set_krb_forwardable", (PyCFunction)py_creds_set_krb_forwardable, METH_VARARGS,
+	{ "set_krb_forwardable", py_creds_set_krb_forwardable, METH_VARARGS,
 		NULL },
-	{ "guess", (PyCFunction)py_creds_guess, METH_VARARGS, NULL },
-	{ "set_machine_account", (PyCFunction)py_creds_set_machine_account, METH_VARARGS, NULL },
-	{ "get_named_ccache", (PyCFunction)py_creds_get_named_ccache, METH_VARARGS, NULL },
-	{ "set_gensec_features", (PyCFunction)py_creds_set_gensec_features, METH_VARARGS, NULL },
-	{ "get_gensec_features", (PyCFunction)py_creds_get_gensec_features, METH_NOARGS, NULL },
-	{ "get_forced_sasl_mech", (PyCFunction)py_creds_get_forced_sasl_mech, METH_NOARGS,
+	{ "guess", py_creds_guess, METH_VARARGS, NULL },
+	{ "set_machine_account", py_creds_set_machine_account, METH_VARARGS, NULL },
+	{ "get_named_ccache", py_creds_get_named_ccache, METH_VARARGS, NULL },
+	{ "set_gensec_features", py_creds_set_gensec_features, METH_VARARGS, NULL },
+	{ "get_gensec_features", py_creds_get_gensec_features, METH_NOARGS, NULL },
+	{ "get_forced_sasl_mech", py_creds_get_forced_sasl_mech, METH_NOARGS,
 		"S.get_forced_sasl_mech() -> SASL mechanism\nObtain forced SASL mechanism." },
-	{ "set_forced_sasl_mech", (PyCFunction)py_creds_set_forced_sasl_mech, METH_VARARGS,
+	{ "set_forced_sasl_mech", py_creds_set_forced_sasl_mech, METH_VARARGS,
 		"S.set_forced_sasl_mech(name) -> None\n"
 		"Set forced SASL mechanism." },
 	{ NULL }
@@ -479,7 +459,6 @@ static PyMethodDef py_creds_methods[] = {
 
 PyTypeObject PyCredentials = {
 	.tp_name = "credentials.Credentials",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_new = py_creds_new,
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 	.tp_methods = py_creds_methods,
@@ -488,23 +467,16 @@ PyTypeObject PyCredentials = {
 
 PyTypeObject PyCredentialCacheContainer = {
 	.tp_name = "credentials.CredentialCacheContainer",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 };
 
 void initcredentials(void)
 {
 	PyObject *m;
-	PyTypeObject *talloc_type = pytalloc_GetObjectType();
-	if (talloc_type == NULL)
-		return;
-
-	PyCredentials.tp_base = PyCredentialCacheContainer.tp_base = talloc_type;
-
-	if (PyType_Ready(&PyCredentials) < 0)
+	if (pytalloc_BaseObject_PyType_Ready(&PyCredentials) < 0)
 		return;
 
-	if (PyType_Ready(&PyCredentialCacheContainer) < 0)
+	if (pytalloc_BaseObject_PyType_Ready(&PyCredentialCacheContainer) < 0)
 		return;
 
 	m = Py_InitModule3("credentials", NULL, "Credentials management.");
diff --git a/auth/credentials/pycredentials.h b/auth/credentials/pycredentials.h
index 3a110fb..a136a21 100644
--- a/auth/credentials/pycredentials.h
+++ b/auth/credentials/pycredentials.h
@@ -24,11 +24,6 @@
 
 extern PyTypeObject PyCredentials;
 extern PyTypeObject PyCredentialCacheContainer;
-typedef struct {
-	PyObject_HEAD
-	TALLOC_CTX *mem_ctx;
-	struct ccache_container *ccc;
-} PyCredentialCacheContainerObject;
 #define PyCredentials_Check(py_obj) PyObject_TypeCheck(py_obj, &PyCredentials)
 #define PyCredentials_AsCliCredentials(py_obj) pytalloc_get_type(py_obj, struct cli_credentials)
 #define cli_credentials_from_py_object(py_obj) (py_obj == Py_None)?cli_credentials_init_anon(NULL):PyCredentials_AsCliCredentials(py_obj)
diff --git a/auth/credentials/wscript_build b/auth/credentials/wscript_build
index 06d58a7..009f5ec 100755
--- a/auth/credentials/wscript_build
+++ b/auth/credentials/wscript_build
@@ -5,7 +5,7 @@ bld.SAMBA_LIBRARY('samba-credentials',
 	autoproto='credentials_proto.h',
 	public_headers='credentials.h',
 	pc_files='samba-credentials.pc',
-	deps='LIBCRYPTO errors events LIBCLI_AUTH samba-security CREDENTIALS_SECRETS CREDENTIALS_KRB5',
+	deps='LIBCRYPTO samba-errors events LIBCLI_AUTH samba-security CREDENTIALS_SECRETS CREDENTIALS_KRB5',
 	vnum='0.0.1'
 	)
 
diff --git a/auth/gensec/gensec.pc.in b/auth/gensec/gensec.pc.in
deleted file mode 100644
index f32226d..0000000
--- a/auth/gensec/gensec.pc.in
+++ /dev/null
@@ -1,11 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-modulesdir=${prefix}/modules/gensec
-
-Name: gensec
-Description: Generic Security Library
-Version: @PACKAGE_VERSION@
-Libs: @LIB_RPATH@ -L${libdir} -lgensec
-Cflags: -I${includedir}  -DHAVE_IMMEDIATE_STRUCTURES=1
diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c
index 8ef4b25..64fffb1 100644
--- a/auth/gensec/gensec_util.c
+++ b/auth/gensec/gensec_util.c
@@ -81,7 +81,7 @@ static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid)
 	if (!asn1_start_tag(data, ASN1_APPLICATION(0))) goto err;
 	if (!asn1_check_OID(data, oid)) goto err;
 
-	ret = !data->has_error;
+	ret = !asn1_has_error(data);
 
   err:
 
diff --git a/auth/gensec/spnego.c b/auth/gensec/spnego.c
index fe2ec43..079a2bc 100644
--- a/auth/gensec/spnego.c
+++ b/auth/gensec/spnego.c
@@ -1095,26 +1095,24 @@ static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
 {
 	struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
 	size_t expected;
-	NTSTATUS status;
 	bool ok;
 
 	*full_in = data_blob_null;
 
 	if (spnego_state->in_needed == 0) {
 		size_t size = 0;
+		int ret;
 
 		/*
 		 * try to work out the size of the full
 		 * input token, it might be fragmented
 		 */
-		status = asn1_peek_full_tag(in,  ASN1_APPLICATION(0), &size);
-		if (!NT_STATUS_IS_OK(status) &&
-		    !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
-			status = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size);
+		ret = asn1_peek_full_tag(in,  ASN1_APPLICATION(0), &size);
+		if ((ret != 0) && (ret != EAGAIN)) {
+			ret = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size);
 		}
 
-		if (NT_STATUS_IS_OK(status) ||
-		    NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+		if ((ret == 0) || (ret == EAGAIN)) {
 			spnego_state->in_needed = size;
 		} else {
 			/*
@@ -1184,6 +1182,7 @@ static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security
 {
 	struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
 	DATA_BLOB out = data_blob_null;
+	bool ok;
 
 	*_out = data_blob_null;
 
@@ -1222,7 +1221,11 @@ static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security
 	/*
 	 * truncate the buffer
 	 */
-	data_blob_realloc(spnego_state, &out, spnego_state->out_max_length);
+	ok = data_blob_realloc(spnego_state, &out,
+			       spnego_state->out_max_length);
+	if (!ok) {
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	talloc_steal(out_mem_ctx, out.data);
 	*_out = out;
diff --git a/auth/gensec/wscript_build b/auth/gensec/wscript_build
index e4c4a08..d8299be 100755
--- a/auth/gensec/wscript_build
+++ b/auth/gensec/wscript_build
@@ -1,12 +1,11 @@
 #!/usr/bin/env python
 bld.SAMBA_LIBRARY('gensec',
 	source='gensec.c gensec_start.c gensec_util.c',
-	pc_files='gensec.pc',
 	autoproto='gensec_toplevel_proto.h',
-	public_deps='tevent-util samba-util errors auth_system_session samba-modules gensec_util asn1util',
-	public_headers='gensec.h',
+	public_deps='tevent-util samba-util samba-errors auth_system_session samba-modules gensec_util asn1util',
+	private_headers='gensec.h',
 	deps='com_err',
-	vnum='0.0.1'
+	private_library=True,
 	)
 
 bld.SAMBA_MODULE('gensec_spnego',
diff --git a/auth/kerberos/gssapi_pac.c b/auth/kerberos/gssapi_pac.c
index c6fa909..685d0ec 100644
--- a/auth/kerberos/gssapi_pac.c
+++ b/auth/kerberos/gssapi_pac.c
@@ -113,7 +113,11 @@ NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx,
 
 	if (gss_maj != 0) {
 		DEBUG(0, ("obtaining PAC via GSSAPI gss_get_name_attribute failed: %s\n",
-			  gssapi_error_string(mem_ctx, gss_maj, gss_min, gss_mech_krb5)));
+			  gssapi_error_string(mem_ctx,
+					      gss_maj,
+					      gss_min,
+					      discard_const_p(struct gss_OID_desc_struct,
+							      gss_mech_krb5))));
 		return NT_STATUS_ACCESS_DENIED;
 	} else if (authenticated && complete) {
 		/* The PAC blob is returned directly */
@@ -199,7 +203,11 @@ NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx,
 				&gse_sesskey_inq_oid, &set);
 	if (gss_maj) {
 		DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
-			  gssapi_error_string(mem_ctx, gss_maj, gss_min, gss_mech_krb5)));
+			  gssapi_error_string(mem_ctx,
+					      gss_maj,
+					      gss_min,
+					      discard_const_p(struct gss_OID_desc_struct,
+							      gss_mech_krb5))));
 		return NT_STATUS_NO_USER_SESSION_KEY;
 	}
 
diff --git a/auth/ntlmssp/gensec_ntlmssp_server.c b/auth/ntlmssp/gensec_ntlmssp_server.c
index 69c56fb..03d539b 100644
--- a/auth/ntlmssp/gensec_ntlmssp_server.c
+++ b/auth/ntlmssp/gensec_ntlmssp_server.c
@@ -34,6 +34,7 @@
 #include "auth/gensec/gensec_internal.h"
 #include "auth/common_auth.h"
 #include "param/param.h"
+#include "libds/common/roles.h"
 
 
 /**
diff --git a/auth/ntlmssp/ntlmssp_client.c b/auth/ntlmssp/ntlmssp_client.c
index d8531e4c..b22619b 100644
--- a/auth/ntlmssp/ntlmssp_client.c
+++ b/auth/ntlmssp/ntlmssp_client.c
@@ -147,7 +147,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
 	DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
 	NTSTATUS nt_status;
 	int flags = 0;
-	const char *user, *domain;
+	const char *user = NULL, *domain = NULL, *workstation = NULL;
 
 	TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
 	if (!mem_ctx) {
@@ -256,6 +256,23 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
 	cli_credentials_get_ntlm_username_domain(gensec_security->credentials, mem_ctx,
 						 &user, &domain);
 
+	workstation = cli_credentials_get_workstation(gensec_security->credentials);
+
+	if (user == NULL) {
+		DEBUG(10, ("User is NULL, returning INVALID_PARAMETER\n"));
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	if (domain == NULL) {
+		DEBUG(10, ("Domain is NULL, returning INVALID_PARAMETER\n"));
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	if (workstation == NULL) {
+		DEBUG(10, ("Workstation is NULL, returning INVALID_PARAMETER\n"));
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
 	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
 		flags |= CLI_CRED_NTLM2;
 	}
@@ -337,7 +354,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
 		       nt_response.data, nt_response.length,
 		       domain,
 		       user,
-		       cli_credentials_get_workstation(gensec_security->credentials),
+		       workstation,
 		       encrypted_session_key.data, encrypted_session_key.length,
 		       ntlmssp_state->neg_flags);
 	if (!NT_STATUS_IS_OK(nt_status)) {
diff --git a/buildtools/wafsamba/configure_file.py b/buildtools/wafsamba/configure_file.py
index 8e2ba3b..e28282b 100644
--- a/buildtools/wafsamba/configure_file.py
+++ b/buildtools/wafsamba/configure_file.py
@@ -1,18 +1,15 @@
 # handle substitution of variables in .in files
 
+import re, os
 import Build, sys, Logs
-from samba_utils import *
+from samba_utils import SUBST_VARS_RECURSIVE
 
 def subst_at_vars(task):
     '''substiture @VAR@ style variables in a file'''
 
     env = task.env
-    src = task.inputs[0].srcpath(env)
-    tgt = task.outputs[0].bldpath(env)
+    s = task.inputs[0].read()
 
-    f = open(src, 'r')
-    s = f.read()
-    f.close()
     # split on the vars
     a = re.split('(@\w+@)', s)
     out = []
@@ -27,9 +24,7 @@ def subst_at_vars(task):
             v = SUBST_VARS_RECURSIVE(task.env[vname], task.env)
         out.append(v)
     contents = ''.join(out)
-    f = open(tgt, 'w')
-    s = f.write(contents)
-    f.close()
+    task.outputs[0].write(contents)
     return 0
 
 def CONFIGURE_FILE(bld, in_file, **kwargs):
diff --git a/buildtools/wafsamba/gccdeps.py b/buildtools/wafsamba/gccdeps.py
deleted file mode 100644
index 2da42e6..0000000
--- a/buildtools/wafsamba/gccdeps.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# encoding: utf-8
-# Thomas Nagy, 2008-2010 (ita)
-
-"""
-Execute the tasks with gcc -MD, read the dependencies from the .d file
-and prepare the dependency calculation for the next run
-"""
-
-import os, re, threading
-import Task, Logs, Utils, preproc
-from TaskGen import before, after, feature
-
-lock = threading.Lock()
-
-preprocessor_flag = '-MD'
-
- at feature('cc')
- at before('apply_core')
-def add_mmd_cc(self):
-    if self.env.get_flat('CCFLAGS').find(preprocessor_flag) < 0:
-        self.env.append_value('CCFLAGS', preprocessor_flag)
-
- at feature('cxx')
- at before('apply_core')
-def add_mmd_cxx(self):
-    if self.env.get_flat('CXXFLAGS').find(preprocessor_flag) < 0:
-        self.env.append_value('CXXFLAGS', preprocessor_flag)
-
-def scan(self):
-    "the scanner does not do anything initially"
-    nodes = self.generator.bld.node_deps.get(self.unique_id(), [])
-    names = []
-    return (nodes, names)
-
-re_o = re.compile("\.o$")
-re_src = re.compile("^(\.\.)[\\/](.*)$")
-
-def post_run(self):
-    # The following code is executed by threads, it is not safe, so a lock is needed...
-
-    if getattr(self, 'cached', None):
-        return Task.Task.post_run(self)
-
-    name = self.outputs[0].abspath(self.env)
-    name = re_o.sub('.d', name)
-    txt = Utils.readf(name)
-    #os.unlink(name)
-
-    txt = txt.replace('\\\n', '')
-
-    lst = txt.strip().split(':')
-    val = ":".join(lst[1:])
-    val = val.split()
-
-    nodes = []
-    bld = self.generator.bld
-
-    f = re.compile("^("+self.env.variant()+"|\.\.)[\\/](.*)$")
-    for x in val:
-        if os.path.isabs(x):
-
-            if not preproc.go_absolute:
-                continue
-
-            lock.acquire()
-            try:
-                node = bld.root.find_resource(x)
-            finally:
-                lock.release()
-        else:
-            g = re.search(re_src, x)
-            if g:
-                x = g.group(2)
-                lock.acquire()
-                try:
-                    node = bld.bldnode.parent.find_resource(x)
-                finally:
-                    lock.release()
-            else:
-                g = re.search(f, x)
-                if g:
-                    x = g.group(2)
-                    lock.acquire()
-                    try:
-                        node = bld.srcnode.find_resource(x)
-                    finally:
-                        lock.release()
-
-        if id(node) == id(self.inputs[0]):
-            # ignore the source file, it is already in the dependencies
-            # this way, successful config tests may be retrieved from the cache
-            continue
-
-        if not node:
-            raise ValueError('could not find %r for %r' % (x, self))
-        else:
-            nodes.append(node)
-
-    Logs.debug('deps: real scanner for %s returned %s' % (str(self), str(nodes)))
-
-    bld.node_deps[self.unique_id()] = nodes
-    bld.raw_deps[self.unique_id()] = []
-
-    try:
-        del self.cache_sig
-    except:
-        pass
-
-    Task.Task.post_run(self)
-
-import Constants, Utils
-def sig_implicit_deps(self):
-    try:
-        return Task.Task.sig_implicit_deps(self)
-    except Utils.WafError:
-        return Constants.SIG_NIL
-
-for name in 'cc cxx'.split():
-    try:
-        cls = Task.TaskBase.classes[name]
-    except KeyError:
-        pass
-    else:
-        cls.post_run = post_run
-        cls.scan = scan
-        cls.sig_implicit_deps = sig_implicit_deps
-
diff --git a/buildtools/wafsamba/nothreads.py b/buildtools/wafsamba/nothreads.py
index 075dcd3..d194eb8 100644
--- a/buildtools/wafsamba/nothreads.py
+++ b/buildtools/wafsamba/nothreads.py
@@ -10,12 +10,11 @@
 
 "Execute the tasks"
 
-import sys, random, time, threading, traceback, os
+import sys, random, threading
 try: from Queue import Queue
 except ImportError: from queue import Queue
-import Build, Utils, Logs, Options
-from Logs import debug, error
-from Constants import *
+import Utils, Options
+from Constants import EXCEPTION, CRASHED, MAXJOBS, ASK_LATER, SKIPPED, SKIP_ME, SUCCESS
 
 GAP = 15
 
diff --git a/buildtools/wafsamba/pkgconfig.py b/buildtools/wafsamba/pkgconfig.py
index 8a3f807..25cec78 100644
--- a/buildtools/wafsamba/pkgconfig.py
+++ b/buildtools/wafsamba/pkgconfig.py
@@ -1,16 +1,13 @@
 # handle substitution of variables in pc files
 
-import Build, sys, Logs
-from samba_utils import *
+import os, re, sys
+import Build, Logs
+from samba_utils import SUBST_VARS_RECURSIVE, TO_LIST
 
 def subst_at_vars(task):
     '''substiture @VAR@ style variables in a file'''
-    src = task.inputs[0].srcpath(task.env)
-    tgt = task.outputs[0].bldpath(task.env)
 
-    f = open(src, 'r')
-    s = f.read()
-    f.close()
+    s = task.inputs[0].read()
     # split on the vars
     a = re.split('(@\w+@)', s)
     out = []
@@ -37,9 +34,7 @@ def subst_at_vars(task):
                     break
         out.append(v)
     contents = ''.join(out)
-    f = open(tgt, 'w')
-    s = f.write(contents)
-    f.close()
+    task.outputs[0].write(contents)
     return 0
 
 
diff --git a/buildtools/wafsamba/samba_abi.py b/buildtools/wafsamba/samba_abi.py
index 76acd00..196b468 100644
--- a/buildtools/wafsamba/samba_abi.py
+++ b/buildtools/wafsamba/samba_abi.py
@@ -137,7 +137,8 @@ def abi_check(self):
     topsrc = self.bld.srcnode.abspath()
     abi_gen = os.path.join(topsrc, 'buildtools/scripts/abi_gen.sh')
 
-    abi_file = "%s/%s-%s.sigs" % (self.abi_directory, self.name, self.vnum)
+    abi_file = "%s/%s-%s.sigs" % (self.abi_directory, self.version_libname,
+                                  self.vnum)
 
     tsk = self.create_task('abi_check', self.link_task.outputs[0])
     tsk.ABI_FILE = abi_file
@@ -147,12 +148,10 @@ def abi_check(self):
 
 def abi_process_file(fname, version, symmap):
     '''process one ABI file, adding new symbols to the symmap'''
-    f = open(fname, mode='r')
-    for line in f:
+    for line in Utils.readf(fname).splitlines():
         symname = line.split(":")[0]
         if not symname in symmap:
             symmap[symname] = version
-    f.close()
 
 
 def abi_write_vscript(f, libname, current_version, versions, symmap, abi_match):
@@ -226,7 +225,7 @@ def abi_build_vscript(task):
 def ABI_VSCRIPT(bld, libname, abi_directory, version, vscript, abi_match=None):
     '''generate a vscript file for our public libraries'''
     if abi_directory:
-        source = bld.path.ant_glob('%s/%s-[0-9]*.sigs' % (abi_directory, libname))
+        source = bld.path.ant_glob('%s/%s-[0-9]*.sigs' % (abi_directory, libname), flat=True)
         def abi_file_key(path):
             return version_key(path[:-len(".sigs")].rsplit("-")[-1])
         source = sorted(source.split(), key=abi_file_key)
diff --git a/buildtools/wafsamba/samba_autoconf.py b/buildtools/wafsamba/samba_autoconf.py
index c5f132c..09ce218 100644
--- a/buildtools/wafsamba/samba_autoconf.py
+++ b/buildtools/wafsamba/samba_autoconf.py
@@ -1,10 +1,10 @@
 # a waf tool to add autoconf-like macros to the configure section
 
-import Build, os, sys, Options, preproc, Logs
-import string
+import os, sys
+import Build, Options, preproc, Logs
 from Configure import conf
-from samba_utils import *
-import samba_cross
+from TaskGen import feature
+from samba_utils import TO_LIST, GET_TARGET_TYPE, SET_TARGET_TYPE, unique_list, mkdir_p
 
 missing_headers = set()
 
@@ -13,7 +13,6 @@ missing_headers = set()
 # to waf a bit easier for those used to autoconf
 # m4 files
 
- at runonce
 @conf
 def DEFINE(conf, d, v, add_to_cflags=False, quote=False):
     '''define a config option'''
@@ -101,6 +100,7 @@ def CHECK_HEADER(conf, h, add_headers=False, lib=None):
                      type='nolink',
                      execute=0,
                      ccflags=ccflags,
+                     mandatory=False,
                      includes=cpppath,
                      uselib=lib.upper(),
                      msg="Checking for header %s" % h)
@@ -486,6 +486,7 @@ def CHECK_LDFLAGS(conf, ldflags):
     return conf.check(fragment='int main(void) { return 0; }\n',
                       execute=0,
                       ldflags=ldflags,
+                      mandatory=False,
                       msg="Checking linker accepts %s" % ldflags)
 
 
@@ -569,9 +570,9 @@ int foo()
 
         (ccflags, ldflags, cpppath) = library_flags(conf, lib)
         if shlib:
-            res = conf.check(features='cc cshlib', fragment=fragment, lib=lib, uselib_store=lib, ccflags=ccflags, ldflags=ldflags, uselib=lib.upper())
+            res = conf.check(features='c cshlib', fragment=fragment, lib=lib, uselib_store=lib, ccflags=ccflags, ldflags=ldflags, uselib=lib.upper(), mandatory=False)
         else:
-            res = conf.check(lib=lib, uselib_store=lib, ccflags=ccflags, ldflags=ldflags, uselib=lib.upper())
+            res = conf.check(lib=lib, uselib_store=lib, ccflags=ccflags, ldflags=ldflags, uselib=lib.upper(), mandatory=False)
 
         if not res:
             if mandatory:
@@ -657,9 +658,24 @@ def SAMBA_CONFIG_H(conf, path=None):
     if not IN_LAUNCH_DIR(conf):
         return
 
-    if conf.CHECK_CFLAGS(['-fstack-protector']) and conf.CHECK_LDFLAGS(['-fstack-protector']):
-        conf.ADD_CFLAGS('-fstack-protector')
-        conf.ADD_LDFLAGS('-fstack-protector')
+    # we need to build real code that can't be optimized away to test
+    if conf.check(fragment='''
+        #include <stdio.h>
+
+        int main(void)
+        {
+            char t[100000];
+            while (fgets(t, sizeof(t), stdin));
+            return 0;
+        }
+        ''',
+        execute=0,
+        ccflags='-fstack-protector',
+        ldflags='-fstack-protector',
+        mandatory=False,
+        msg='Checking if toolchain accepts -fstack-protector'):
+            conf.ADD_CFLAGS('-fstack-protector')
+            conf.ADD_LDFLAGS('-fstack-protector')
 
     if Options.options.debug:
         conf.ADD_CFLAGS('-g', testflags=True)
diff --git a/buildtools/wafsamba/samba_autoproto.py b/buildtools/wafsamba/samba_autoproto.py
index bad627a..b2b5233 100644
--- a/buildtools/wafsamba/samba_autoproto.py
+++ b/buildtools/wafsamba/samba_autoproto.py
@@ -1,7 +1,8 @@
 # waf build tool for building automatic prototypes from C source
 
+import os
 import Build
-from samba_utils import *
+from samba_utils import SET_TARGET_TYPE, os_path_relpath
 
 def SAMBA_AUTOPROTO(bld, header, source):
     '''rule for samba prototype generation'''
diff --git a/buildtools/wafsamba/samba_bundled.py b/buildtools/wafsamba/samba_bundled.py
index c8bfcd2..ea88807 100644
--- a/buildtools/wafsamba/samba_bundled.py
+++ b/buildtools/wafsamba/samba_bundled.py
@@ -1,8 +1,9 @@
 # functions to support bundled libraries
 
+import sys
+import Build, Options, Logs
 from Configure import conf
-import sys, Logs
-from samba_utils import *
+from samba_utils import TO_LIST
 
 def PRIVATE_NAME(bld, name, private_extension, private_library):
     '''possibly rename a library to include a bundled extension'''
@@ -108,17 +109,6 @@ def LIB_MUST_BE_PRIVATE(conf, libname):
             libname in conf.env.PRIVATE_LIBS)
 
 @conf
-def CHECK_PREREQUISITES(conf, prereqs):
-    missing = []
-    for syslib in TO_LIST(prereqs):
-        f = 'FOUND_SYSTEMLIB_%s' % syslib
-        if not f in conf.env:
-            missing.append(syslib)
-    return missing
-
-
- at runonce
- at conf
 def CHECK_BUNDLED_SYSTEM_PKG(conf, libname, minversion='0.0.0',
         onlyif=None, implied_deps=None, pkg=None):
     '''check if a library is available as a system library.
@@ -131,7 +121,6 @@ def CHECK_BUNDLED_SYSTEM_PKG(conf, libname, minversion='0.0.0',
                                      implied_deps=implied_deps,
                                      pkg=pkg)
 
- at runonce
 @conf
 def CHECK_BUNDLED_SYSTEM(conf, libname, minversion='0.0.0',
                          checkfunctions=None, headers=None, checkcode=None,
@@ -141,11 +130,34 @@ def CHECK_BUNDLED_SYSTEM(conf, libname, minversion='0.0.0',
     this first tries via pkg-config, then if that fails
     tries by testing for a specified function in the specified lib
     '''
-    if conf.LIB_MUST_BE_BUNDLED(libname):
-        return False
+    # We always do a logic validation of 'onlyif' first
+    missing = []
+    if onlyif:
+        for l in TO_LIST(onlyif):
+            f = 'FOUND_SYSTEMLIB_%s' % l
+            if not f in conf.env:
+                Logs.error('ERROR: CHECK_BUNDLED_SYSTEM(%s) - ' % (libname) +
+                           'missing prerequisite check for ' +
+                           'system library %s, onlyif=%r' % (l, onlyif))
+                sys.exit(1)
+            if not conf.env[f]:
+                missing.append(l)
     found = 'FOUND_SYSTEMLIB_%s' % libname
     if found in conf.env:
         return conf.env[found]
+    if conf.LIB_MUST_BE_BUNDLED(libname):
+        conf.env[found] = False
+        return False
+
+    # see if the library should only use a system version if another dependent
+    # system version is found. That prevents possible use of mixed library
+    # versions
+    if missing:
+        if not conf.LIB_MAY_BE_BUNDLED(libname):
+            Logs.error('ERROR: Use of system library %s depends on missing system library/libraries %r' % (libname, missing))
+            sys.exit(1)
+        conf.env[found] = False
+        return False
 
     def check_functions_headers_code():
         '''helper function for CHECK_BUNDLED_SYSTEM'''
@@ -166,19 +178,6 @@ def CHECK_BUNDLED_SYSTEM(conf, libname, minversion='0.0.0',
                 return False
         return True
 
-
-    # see if the library should only use a system version if another dependent
-    # system version is found. That prevents possible use of mixed library
-    # versions
-    if onlyif:
-        missing = conf.CHECK_PREREQUISITES(onlyif)
-        if missing:
-            if not conf.LIB_MAY_BE_BUNDLED(libname):
-                Logs.error('ERROR: Use of system library %s depends on missing system library/libraries %r' % (libname, missing))
-                sys.exit(1)
-            conf.env[found] = False
-            return False
-
     minversion = minimum_library_version(conf, libname, minversion)
 
     msg = 'Checking for system %s' % libname
@@ -218,7 +217,6 @@ def CHECK_BUNDLED_SYSTEM(conf, libname, minversion='0.0.0',
 def tuplize_version(version):
     return tuple([int(x) for x in version.split(".")])
 
- at runonce
 @conf
 def CHECK_BUNDLED_SYSTEM_PYTHON(conf, libname, modulename, minversion='0.0.0'):
     '''check if a python module is available on the system and
diff --git a/buildtools/wafsamba/samba_conftests.py b/buildtools/wafsamba/samba_conftests.py
index 96fead5..045f858 100644
--- a/buildtools/wafsamba/samba_conftests.py
+++ b/buildtools/wafsamba/samba_conftests.py
@@ -2,10 +2,9 @@
 # to test for commonly needed configuration options
 
 import os, shutil, re
-import Build, Configure, Utils
+import Build, Configure, Utils, Options, Logs
 from Configure import conf
-import config_c
-from samba_utils import *
+from samba_utils import TO_LIST, ADD_LD_LIBRARY_PATH
 
 
 def add_option(self, *k, **kw):
@@ -197,7 +196,7 @@ int foo(int v) {
     return v * 2;
 }
 '''
-    return conf.check(features='cc cshlib',vnum="1",fragment=snip,msg=msg)
+    return conf.check(features='c cshlib',vnum="1",fragment=snip,msg=msg, mandatory=False)
 
 @conf
 def CHECK_NEED_LC(conf, msg):
@@ -216,9 +215,7 @@ def CHECK_NEED_LC(conf, msg):
 
     os.makedirs(subdir)
 
-    dest = open(os.path.join(subdir, 'liblc1.c'), 'w')
-    dest.write('#include <stdio.h>\nint lib_func(void) { FILE *f = fopen("foo", "r");}\n')
-    dest.close()
+    Utils.writef(os.path.join(subdir, 'liblc1.c'), '#include <stdio.h>\nint lib_func(void) { FILE *f = fopen("foo", "r");}\n')
 
     bld = Build.BuildContext()
     bld.log = conf.log
@@ -229,7 +226,7 @@ def CHECK_NEED_LC(conf, msg):
 
     bld.rescan(bld.srcnode)
 
-    bld(features='cc cshlib',
+    bld(features='c cshlib',
         source='liblctest/liblc1.c',
         ldflags=conf.env['EXTRA_LDFLAGS'],
         target='liblc',
@@ -249,9 +246,6 @@ def CHECK_SHLIB_W_PYTHON(conf, msg):
     '''check if we need -undefined dynamic_lookup'''
 
     dir = find_config_dir(conf)
-
-    env = conf.env
-
     snip = '''
 #include <Python.h>
 #include <crt_externs.h>
@@ -264,7 +258,7 @@ int foo(int v) {
     ldb_module = PyImport_ImportModule("ldb");
     return v * 2;
 }'''
-    return conf.check(features='cc cshlib',uselib='PYEMBED',fragment=snip,msg=msg)
+    return conf.check(features='c cshlib',uselib='PYEMBED',fragment=snip,msg=msg, mandatory=False)
 
 # this one is quite complex, and should probably be broken up
 # into several parts. I'd quite like to create a set of CHECK_COMPOUND()
@@ -291,13 +285,8 @@ def CHECK_LIBRARY_SUPPORT(conf, rpath=False, version_script=False, msg=None):
 
     os.makedirs(subdir)
 
-    dest = open(os.path.join(subdir, 'lib1.c'), 'w')
-    dest.write('int lib_func(void) { return 42; }\n')
-    dest.close()
-
-    dest = open(os.path.join(dir, 'main.c'), 'w')
-    dest.write('int main(void) {return !(lib_func() == 42);}\n')
-    dest.close()
+    Utils.writef(os.path.join(subdir, 'lib1.c'), 'int lib_func(void) { return 42; }\n')
+    Utils.writef(os.path.join(dir, 'main.c'), 'int main(void) {return !(lib_func() == 42);}\n')
 
     bld = Build.BuildContext()
     bld.log = conf.log
@@ -311,17 +300,15 @@ def CHECK_LIBRARY_SUPPORT(conf, rpath=False, version_script=False, msg=None):
     ldflags = []
     if version_script:
         ldflags.append("-Wl,--version-script=%s/vscript" % bld.path.abspath())
-        dest = open(os.path.join(dir,'vscript'), 'w')
-        dest.write('TEST_1.0A2 { global: *; };\n')
-        dest.close()
+        Utils.writef(os.path.join(dir,'vscript'), 'TEST_1.0A2 { global: *; };\n')
 
-    bld(features='cc cshlib',
+    bld(features='c cshlib',
         source='libdir/lib1.c',
         target='libdir/lib1',
         ldflags=ldflags,
         name='lib1')
 
-    o = bld(features='cc cprogram',
+    o = bld(features='c cprogram',
             source='main.c',
             target='prog1',
             uselib_local='lib1')
@@ -383,15 +370,13 @@ def CHECK_PERL_MANPAGE(conf, msg=None, section=None):
     if not os.path.exists(bdir):
         os.makedirs(bdir)
 
-    dest = open(os.path.join(bdir, 'Makefile.PL'), 'w')
-    dest.write("""
+    Utils.writef(os.path.join(bdir, 'Makefile.PL'), """
 use ExtUtils::MakeMaker;
 WriteMakefile(
     'NAME'    => 'WafTest',
     'EXE_FILES' => [ 'WafTest' ]
 );
 """)
-    dest.close()
     back = os.path.abspath('.')
     os.chdir(bdir)
     proc = Utils.pproc.Popen(['perl', 'Makefile.PL'],
@@ -406,9 +391,7 @@ WriteMakefile(
         return
 
     if section:
-        f = open(os.path.join(bdir,'Makefile'), 'r')
-        man = f.read()
-        f.close()
+        man = Utils.readf(os.path.join(bdir,'Makefile'))
         m = re.search('MAN%sEXT\s+=\s+(\w+)' % section, man)
         if not m:
             conf.check_message_2('not found', color='YELLOW')
@@ -537,53 +520,3 @@ def CHECK_STANDARD_LIBPATH(conf):
 
     conf.env.STANDARD_LIBPATH = dirlist
 
-
-waf_config_c_parse_flags = config_c.parse_flags;
-def samba_config_c_parse_flags(line1, uselib, env):
-    #
-    # We do a special treatment of the rpath components
-    # in the linkflags line, because currently the upstream
-    # parse_flags function is incomplete with respect to
-    # treatment of the rpath. The remainder of the linkflags
-    # line is later passed to the original funcion.
-    #
-    lst1 = shlex.split(line1)
-    lst2 = []
-    while lst1:
-        x = lst1.pop(0)
-
-        #
-        # NOTE on special treatment of -Wl,-R and -Wl,-rpath:
-        #
-        # It is important to not put a library provided RPATH
-        # into the LINKFLAGS but in the RPATH instead, since
-        # the provided LINKFLAGS get prepended to our own internal
-        # RPATH later, and hence can potentially lead to linking
-        # in too old versions of our internal libs.
-        #
-        # We do this filtering here on our own because of some
-        # bugs in the real parse_flags() function.
-        #
-        if x == '-Wl,-rpath' or x == '-Wl,-R':
-            x = lst1.pop(0)
-            if x.startswith('-Wl,'):
-                rpath = x[4:]
-            else:
-                rpath = x
-        elif x.startswith('-Wl,-R,'):
-            rpath = x[7:]
-        elif x.startswith('-Wl,-R'):
-            rpath = x[6:]
-        elif x.startswith('-Wl,-rpath,'):
-            rpath = x[11:]
-        else:
-            lst2.append(x)
-            continue
-
-        env.append_value('RPATH_' + uselib, rpath)
-
-    line2 = ' '.join(lst2)
-    waf_config_c_parse_flags(line2, uselib, env)
-
-    return
-config_c.parse_flags = samba_config_c_parse_flags
diff --git a/buildtools/wafsamba/samba_cross.py b/buildtools/wafsamba/samba_cross.py
index ed3af1e..b8f2000 100644
--- a/buildtools/wafsamba/samba_cross.py
+++ b/buildtools/wafsamba/samba_cross.py
@@ -1,8 +1,8 @@
 # functions for handling cross-compilation
 
-import Utils, Logs, sys, os, Options, re
+import os, sys, re, shlex
+import Utils, Logs, Options
 from Configure import conf
-import shlex
 
 real_Popen = None
 
diff --git a/buildtools/wafsamba/samba_deps.py b/buildtools/wafsamba/samba_deps.py
index d252dc4..2ffe745 100644
--- a/buildtools/wafsamba/samba_deps.py
+++ b/buildtools/wafsamba/samba_deps.py
@@ -1,9 +1,14 @@
 # Samba automatic dependency handling and project rules
 
-import Build, os, sys, re, Environment, Logs, time
-from samba_utils import *
-from samba_autoconf import *
+import os, sys, re, time
+
+import Build, Environment, Options, Logs, Utils
+from Logs import debug
+from Configure import conf
+
 from samba_bundled import BUILTIN_LIBRARY
+from samba_utils import LOCAL_CACHE, TO_LIST, get_tgt_list, unique_list, os_path_relpath
+from samba_autoconf import library_flags
 
 @conf
 def ADD_GLOBAL_DEPENDENCY(ctx, dep):
@@ -47,7 +52,7 @@ def expand_subsystem_deps(bld):
         #    module_name    = rpc_epmapper (a module within the dcerpc_server subsystem)
         #    module         = rpc_epmapper (a module object within the dcerpc_server subsystem)
 
-        subsystem = bld.name_to_obj(subsystem_name, bld.env)
+        subsystem = bld.get_tgen_by_name(subsystem_name)
         bld.ASSERT(subsystem is not None, "Unable to find subsystem %s" % subsystem_name)
         for d in subsystem_list[subsystem_name]:
             module_name = d['TARGET']
@@ -101,7 +106,7 @@ def build_dependencies(self):
         self.uselib = list(self.final_syslibs)
         self.uselib.extend(list(self.direct_syslibs))
         for lib in self.final_libs:
-            t = self.bld.name_to_obj(lib, self.bld.env)
+            t = self.bld.get_tgen_by_name(lib)
             self.uselib.extend(list(t.final_syslibs))
         self.uselib = unique_list(self.uselib)
 
@@ -150,7 +155,7 @@ def build_includes(self):
     inc_abs = []
 
     for d in inc_deps:
-        t = bld.name_to_obj(d, bld.env)
+        t = bld.get_tgen_by_name(d)
         bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
         inclist = getattr(t, 'samba_includes_extended', [])[:]
         if getattr(t, 'local_include', True):
@@ -214,6 +219,9 @@ def add_init_functions(self):
     if m is not None:
         modules.append(m)
 
+    if 'pyembed' in self.features:
+        return
+
     sentinel = getattr(self, 'init_function_sentinel', 'NULL')
 
     targets    = LOCAL_CACHE(bld, 'TARGET_TYPE')
@@ -252,15 +260,10 @@ def add_init_functions(self):
 
 
 def check_duplicate_sources(bld, tgt_list):
-    '''see if we are compiling the same source file more than once
-       without an allow_duplicates attribute'''
+    '''see if we are compiling the same source file more than once'''
 
     debug('deps: checking for duplicate sources')
-
     targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
-    ret = True
-
-    global tstart
 
     for t in tgt_list:
         source_list = TO_LIST(getattr(t, 'source', ''))
@@ -278,11 +281,10 @@ def check_duplicate_sources(bld, tgt_list):
 
     # build a list of targets that each source file is part of
     for t in tgt_list:
-        sources = []
         if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
             continue
         for obj in t.add_objects:
-            t2 = t.bld.name_to_obj(obj, bld.env)
+            t2 = t.bld.get_tgen_by_name(obj)
             source_set = getattr(t2, 'samba_source_set', set())
             for s in source_set:
                 if not s in subsystems:
@@ -298,24 +300,7 @@ def check_duplicate_sources(bld, tgt_list):
             if len(subsystems[s][tname]) > 1:
                 raise Utils.WafError("ERROR: source %s is in more than one subsystem of target '%s': %s" % (s, tname, subsystems[s][tname]))
 
-    return ret
-
-
-def check_orphaned_targets(bld, tgt_list):
-    '''check if any build targets are orphaned'''
-
-    target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
-
-    debug('deps: checking for orphaned targets')
-
-    for t in tgt_list:
-        if getattr(t, 'samba_used', False):
-            continue
-        type = target_dict[t.sname]
-        if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
-            if re.search('^PIDL_', t.sname) is None:
-                Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
-
+    return True
 
 def check_group_ordering(bld, tgt_list):
     '''see if we have any dependencies that violate the group ordering
@@ -346,7 +331,7 @@ def check_group_ordering(bld, tgt_list):
     for t in tgt_list:
         tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
         for d in tdeps:
-            t2 = bld.name_to_obj(d, bld.env)
+            t2 = bld.get_tgen_by_name(d)
             if t2 is None:
                 continue
             map1 = grp_map[t.samba_group]
@@ -358,7 +343,7 @@ def check_group_ordering(bld, tgt_list):
                 ret = False
 
     return ret
-
+Build.BuildContext.check_group_ordering = check_group_ordering
 
 def show_final_deps(bld, tgt_list):
     '''show the final dependencies for all targets'''
@@ -429,7 +414,7 @@ def build_direct_deps(bld, tgt_list):
     global_deps = bld.env.GLOBAL_DEPENDENCIES
     global_deps_exclude = set()
     for dep in global_deps:
-        t = bld.name_to_obj(dep, bld.env)
+        t = bld.get_tgen_by_name(dep)
         for d in t.samba_deps:
             # prevent loops from the global dependencies list
             global_deps_exclude.add(d)
@@ -469,7 +454,7 @@ def build_direct_deps(bld, tgt_list):
                                 implied, t.sname, targets[implied]))
                             sys.exit(1)
                 continue
-            t2 = bld.name_to_obj(d, bld.env)
+            t2 = bld.get_tgen_by_name(d)
             if t2 is None:
                 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
                 sys.exit(1)
@@ -507,7 +492,7 @@ def indirect_libs(bld, t, chain, loops):
             dependency_loop(loops, t, obj)
             continue
         chain.add(obj)
-        t2 = bld.name_to_obj(obj, bld.env)
+        t2 = bld.get_tgen_by_name(obj)
         r2 = indirect_libs(bld, t2, chain, loops)
         chain.remove(obj)
         ret = ret.union(t2.direct_libs)
@@ -518,7 +503,7 @@ def indirect_libs(bld, t, chain, loops):
             dependency_loop(loops, t, obj)
             continue
         chain.add(obj)
-        t2 = bld.name_to_obj(obj, bld.env)
+        t2 = bld.get_tgen_by_name(obj)
         r2 = indirect_libs(bld, t2, chain, loops)
         chain.remove(obj)
         ret = ret.union(t2.direct_libs)
@@ -545,7 +530,7 @@ def indirect_objects(bld, t, chain, loops):
             dependency_loop(loops, t, lib)
             continue
         chain.add(lib)
-        t2 = bld.name_to_obj(lib, bld.env)
+        t2 = bld.get_tgen_by_name(lib)
         r2 = indirect_objects(bld, t2, chain, loops)
         chain.remove(lib)
         ret = ret.union(t2.direct_objects)
@@ -573,7 +558,7 @@ def extended_objects(bld, t, chain):
     for lib in t.final_libs:
         if lib in chain:
             continue
-        t2 = bld.name_to_obj(lib, bld.env)
+        t2 = bld.get_tgen_by_name(lib)
         chain.add(lib)
         r2 = extended_objects(bld, t2, chain)
         chain.remove(lib)
@@ -601,7 +586,7 @@ def includes_objects(bld, t, chain, inc_loops):
             dependency_loop(inc_loops, t, obj)
             continue
         chain.add(obj)
-        t2 = bld.name_to_obj(obj, bld.env)
+        t2 = bld.get_tgen_by_name(obj)
         r2 = includes_objects(bld, t2, chain, inc_loops)
         chain.remove(obj)
         ret = ret.union(t2.direct_objects)
@@ -612,7 +597,7 @@ def includes_objects(bld, t, chain, inc_loops):
             dependency_loop(inc_loops, t, lib)
             continue
         chain.add(lib)
-        t2 = bld.name_to_obj(lib, bld.env)
+        t2 = bld.get_tgen_by_name(lib)
         if t2 is None:
             targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
             Logs.error('Target %s of type %s not found in direct_libs for %s' % (
@@ -665,7 +650,7 @@ def break_dependency_loops(bld, tgt_list):
 
     # expand indirect subsystem and library loops
     for loop in loops.copy():
-        t = bld.name_to_obj(loop, bld.env)
+        t = bld.get_tgen_by_name(loop)
         if t.samba_type in ['SUBSYSTEM']:
             loops[loop] = loops[loop].union(t.indirect_objects)
             loops[loop] = loops[loop].union(t.direct_objects)
@@ -677,7 +662,7 @@ def break_dependency_loops(bld, tgt_list):
 
     # expand indirect includes loops
     for loop in inc_loops.copy():
-        t = bld.name_to_obj(loop, bld.env)
+        t = bld.get_tgen_by_name(loop)
         inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
         if loop in inc_loops[loop]:
             inc_loops[loop].remove(loop)
@@ -723,7 +708,7 @@ def reduce_objects(bld, tgt_list):
             # if we will indirectly link to a target then we don't need it
             new = t.final_objects.copy()
             for l in t.final_libs:
-                t2 = bld.name_to_obj(l, bld.env)
+                t2 = bld.get_tgen_by_name(l)
                 t2_obj = extended_objects(bld, t2, set())
                 dup = new.intersection(t2_obj)
                 if t.sname in rely_on:
@@ -743,7 +728,7 @@ def reduce_objects(bld, tgt_list):
 
     # add back in any objects that were relied upon by the reduction rules
     for r in rely_on:
-        t = bld.name_to_obj(r, bld.env)
+        t = bld.get_tgen_by_name(r)
         t.final_objects = t.final_objects.union(rely_on[r])
 
     return True
@@ -752,7 +737,7 @@ def reduce_objects(bld, tgt_list):
 def show_library_loop(bld, lib1, lib2, path, seen):
     '''show the detailed path of a library loop between lib1 and lib2'''
 
-    t = bld.name_to_obj(lib1, bld.env)
+    t = bld.get_tgen_by_name(lib1)
     if not lib2 in getattr(t, 'final_libs', set()):
         return
 
@@ -791,7 +776,7 @@ def calculate_final_deps(bld, tgt_list, loops):
             # replace lib deps with objlist deps
             for l in t.final_libs:
                 objname = l + '.objlist'
-                t2 = bld.name_to_obj(objname, bld.env)
+                t2 = bld.get_tgen_by_name(objname)
                 if t2 is None:
                     Logs.error('ERROR: subsystem %s not found' % objname)
                     sys.exit(1)
@@ -807,7 +792,7 @@ def calculate_final_deps(bld, tgt_list, loops):
                             objname = module_name
                         else:
                             continue
-                        t2 = bld.name_to_obj(objname, bld.env)
+                        t2 = bld.get_tgen_by_name(objname)
                         if t2 is None:
                             Logs.error('ERROR: subsystem %s not found' % objname)
                             sys.exit(1)
@@ -819,7 +804,7 @@ def calculate_final_deps(bld, tgt_list, loops):
     for t in tgt_list:
         if t.samba_type in ['LIBRARY', 'PYTHON']:
             for l in t.final_libs.copy():
-                t2 = bld.name_to_obj(l, bld.env)
+                t2 = bld.get_tgen_by_name(l)
                 if t.sname in t2.final_libs:
                     if getattr(bld.env, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
                         # we could break this in either direction. If one of the libraries
@@ -853,7 +838,7 @@ def calculate_final_deps(bld, tgt_list, loops):
                         diff.remove(t.sname)
                     # make sure we don't recreate the loop again!
                     for d in diff.copy():
-                        t2 = bld.name_to_obj(d, bld.env)
+                        t2 = bld.get_tgen_by_name(d)
                         if t2.samba_type == 'LIBRARY':
                             if t.sname in t2.final_libs:
                                 debug('deps: removing expansion %s from %s', d, t.sname)
@@ -878,12 +863,12 @@ def calculate_final_deps(bld, tgt_list, loops):
             continue
         syslibs = set()
         for d in t.final_objects:
-            t2 = bld.name_to_obj(d, bld.env)
+            t2 = bld.get_tgen_by_name(d)
             syslibs = syslibs.union(t2.direct_syslibs)
         # this adds the indirect syslibs as well, which may not be needed
         # depending on the linker flags
         for d in t.final_libs:
-            t2 = bld.name_to_obj(d, bld.env)
+            t2 = bld.get_tgen_by_name(d)
             syslibs = syslibs.union(t2.direct_syslibs)
         t.final_syslibs = syslibs
 
@@ -893,7 +878,7 @@ def calculate_final_deps(bld, tgt_list, loops):
     for t in tgt_list:
         if t.samba_type in ['LIBRARY', 'PYTHON']:
             for l in t.final_libs.copy():
-                t2 = bld.name_to_obj(l, bld.env)
+                t2 = bld.get_tgen_by_name(l)
                 if t.sname in t2.final_libs:
                     Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
                     lib_loop_error = True
@@ -909,7 +894,7 @@ def show_dependencies(bld, target, seen):
     if target in seen:
         return
 
-    t = bld.name_to_obj(target, bld.env)
+    t = bld.get_tgen_by_name(target)
     if t is None:
         Logs.error("ERROR: Unable to find target '%s'" % target)
         sys.exit(1)
@@ -938,7 +923,7 @@ def show_object_duplicates(bld, tgt_list):
         if not targets[t.sname] in [ 'LIBRARY', 'PYTHON' ]:
             continue
         for n in getattr(t, 'final_objects', set()):
-            t2 = bld.name_to_obj(n, bld.env)
+            t2 = bld.get_tgen_by_name(n)
             if not n in used_by:
                 used_by[n] = set()
             used_by[n].add(t.sname)
@@ -1149,15 +1134,13 @@ def check_project_rules(bld):
 
     debug('deps: project rules stage1 completed')
 
-    #check_orphaned_targets(bld, tgt_list)
-
     if not check_duplicate_sources(bld, tgt_list):
         Logs.error("Duplicate sources present - aborting")
         sys.exit(1)
 
     debug("deps: check_duplicate_sources: %f" % (time.clock() - tstart))
 
-    if not check_group_ordering(bld, tgt_list):
+    if not bld.check_group_ordering(tgt_list):
         Logs.error("Bad group ordering - aborting")
         sys.exit(1)
 
diff --git a/buildtools/wafsamba/samba_dist.py b/buildtools/wafsamba/samba_dist.py
index 654a168..dbcb02a 100644
--- a/buildtools/wafsamba/samba_dist.py
+++ b/buildtools/wafsamba/samba_dist.py
@@ -1,8 +1,10 @@
 # customised version of 'waf dist' for Samba tools
 # uses git ls-files to get file lists
 
-import Utils, os, sys, tarfile, stat, Scripting, Logs, Options
-from samba_utils import *
+import os, sys, tarfile
+import Utils, Scripting, Logs, Options
+from Configure import conf
+from samba_utils import os_path_relpath
 
 dist_dirs = None
 dist_files = None
diff --git a/buildtools/wafsamba/samba_headers.py b/buildtools/wafsamba/samba_headers.py
index 50ccad7..0a80082 100644
--- a/buildtools/wafsamba/samba_headers.py
+++ b/buildtools/wafsamba/samba_headers.py
@@ -1,7 +1,8 @@
 # specialist handling of header files for Samba
 
-import Build, re, Task, TaskGen, shutil, sys, Logs
-from samba_utils import *
+import os, re, sys, fnmatch
+import Build, Logs, Utils
+from samba_utils import TO_LIST, os_path_relpath
 
 
 def header_install_path(header, header_path):
diff --git a/buildtools/wafsamba/samba_install.py b/buildtools/wafsamba/samba_install.py
index 3d0c23a..21035bf 100644
--- a/buildtools/wafsamba/samba_install.py
+++ b/buildtools/wafsamba/samba_install.py
@@ -3,9 +3,10 @@
 # with all the configure options that affect rpath and shared
 # library use
 
-import Options
+import os
+import Utils
 from TaskGen import feature, before, after
-from samba_utils import *
+from samba_utils import LIB_PATH, MODE_755, install_rpath, build_rpath
 
 @feature('install_bin')
 @after('apply_core')
@@ -18,7 +19,7 @@ def install_binary(self):
     install_ldflags = install_rpath(self)
     build_ldflags   = build_rpath(bld)
 
-    if not Options.is_install:
+    if not self.bld.is_install:
         # just need to set rpath if we are not installing
         self.env.RPATH = build_ldflags
         return
@@ -67,7 +68,7 @@ def install_library(self):
         install_ldflags = install_rpath(self)
         build_ldflags   = build_rpath(bld)
 
-        if not Options.is_install or not getattr(self, 'samba_install', True):
+        if not self.bld.is_install or not getattr(self, 'samba_install', True):
             # just need to set the build rpath if we are not installing
             self.env.RPATH = build_ldflags
             return
@@ -91,6 +92,7 @@ def install_library(self):
             t = self.clone(self.env)
             t.posted = False
             t.target += '.inst'
+            t.name = self.name + '.inst'
             self.env.RPATH = build_ldflags
         else:
             t = self
@@ -224,7 +226,6 @@ def symlink_bin(self):
     if self.target.endswith('.inst'):
         return
 
-    blddir = os.path.dirname(self.bld.srcnode.abspath(self.bld.env))
     if not self.link_task.outputs or not self.link_task.outputs[0]:
         raise Utils.WafError('no outputs found for %s in symlink_bin' % self.name)
     binpath = self.link_task.outputs[0].abspath(self.env)
diff --git a/buildtools/wafsamba/samba_optimisation.py b/buildtools/wafsamba/samba_optimisation.py
index 51d514e..5008f83 100644
--- a/buildtools/wafsamba/samba_optimisation.py
+++ b/buildtools/wafsamba/samba_optimisation.py
@@ -11,7 +11,7 @@ import Build, Utils, Node
 from TaskGen import feature, after, before
 import preproc
 
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 @after('apply_type_vars', 'apply_lib_vars', 'apply_core')
 def apply_incpaths(self):
     lst = []
@@ -59,7 +59,7 @@ def apply_incpaths(self):
         if node:
             self.env.append_value('INC_PATHS', node)
 
- at feature('cc')
+ at feature('c', 'cc')
 @after('apply_incpaths')
 def apply_obj_vars_cc(self):
     """after apply_incpaths for INC_PATHS"""
@@ -165,7 +165,7 @@ def is_this_a_static_lib(self, name):
     try:
         return cache[name]
     except KeyError:
-        ret = cache[name] = 'cstaticlib' in self.bld.name_to_obj(name, self.env).features
+        ret = cache[name] = 'cstaticlib' in self.bld.get_tgen_by_name(name).features
         return ret
 TaskGen.task_gen.is_this_a_static_lib = is_this_a_static_lib
 
@@ -187,7 +187,7 @@ def shared_ancestors(self):
         return ret
 TaskGen.task_gen.shared_ancestors = shared_ancestors
 
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 @after('apply_link', 'init_cc', 'init_cxx', 'apply_core')
 def apply_lib_vars(self):
     """after apply_link because of 'link_task'
@@ -215,7 +215,7 @@ def apply_lib_vars(self):
         if lib_name in seen:
             continue
 
-        y = self.name_to_obj(lib_name)
+        y = self.get_tgen_by_name(lib_name)
         if not y:
             raise Utils.WafError('object %r was not found in uselib_local (required by %r)' % (lib_name, self.name))
         y.post()
@@ -266,24 +266,4 @@ def apply_lib_vars(self):
             if val:
                 self.env.append_value(v, val)
 
- at feature('cprogram', 'cshlib', 'cstaticlib')
- at after('apply_lib_vars')
- at before('apply_obj_vars')
-def samba_before_apply_obj_vars(self):
-    """before apply_obj_vars for uselib, this removes the standard pathes"""
 
-    def is_standard_libpath(env, path):
-        for _path in env.STANDARD_LIBPATH:
-            if _path == os.path.normpath(path):
-                return True
-        return False
-
-    v = self.env
-
-    for i in v['RPATH']:
-        if is_standard_libpath(v, i):
-            v['RPATH'].remove(i)
-
-    for i in v['LIBPATH']:
-        if is_standard_libpath(v, i):
-            v['LIBPATH'].remove(i)
diff --git a/buildtools/wafsamba/samba_patterns.py b/buildtools/wafsamba/samba_patterns.py
index 0469992..ceca2cc 100644
--- a/buildtools/wafsamba/samba_patterns.py
+++ b/buildtools/wafsamba/samba_patterns.py
@@ -1,21 +1,16 @@
 # a waf tool to add extension based build patterns for Samba
 
-import Task
-from TaskGen import extension
-from samba_utils import *
+import Build
 from wafsamba import samba_version_file
 
 def write_version_header(task):
     '''print version.h contents'''
     src = task.inputs[0].srcpath(task.env)
-    tgt = task.outputs[0].bldpath(task.env)
 
-    version = samba_version_file(src, task.env.srcdir, env=task.env, is_install=task.env.is_install)
+    version = samba_version_file(src, task.env.srcdir, env=task.env, is_install=task.generator.bld.is_install)
     string = str(version)
 
-    f = open(tgt, 'w')
-    s = f.write(string)
-    f.close()
+    task.outputs[0].write(string)
     return 0
 
 
@@ -30,7 +25,6 @@ def SAMBA_MKVERSION(bld, target):
                             source= 'VERSION',
                             target=target,
                             always=bld.is_install)
-    t.env.is_install = bld.is_install
 Build.BuildContext.SAMBA_MKVERSION = SAMBA_MKVERSION
 
 
diff --git a/buildtools/wafsamba/samba_perl.py b/buildtools/wafsamba/samba_perl.py
index 3909aba..f2f176d 100644
--- a/buildtools/wafsamba/samba_perl.py
+++ b/buildtools/wafsamba/samba_perl.py
@@ -1,17 +1,10 @@
-import Build
-from samba_utils import *
+import Utils
 from Configure import conf
 
 done = {}
 
 @conf
 def SAMBA_CHECK_PERL(conf, mandatory=True, version=(5,0,0)):
-    #
-    # TODO: use the @runonce mechanism for this.
-    # The problem is that @runonce currently does
-    # not seem to work together with @conf...
-    # So @runonce (and/or) @conf needs fixing.
-    #
     if "done" in done:
         return
     done["done"] = True
diff --git a/buildtools/wafsamba/samba_pidl.py b/buildtools/wafsamba/samba_pidl.py
index 110b15e..9651e4d 100644
--- a/buildtools/wafsamba/samba_pidl.py
+++ b/buildtools/wafsamba/samba_pidl.py
@@ -1,8 +1,9 @@
 # waf build tool for building IDL files with pidl
 
-from TaskGen import before
-import Build, os, sys, Logs
-from samba_utils import *
+import os
+import Build
+from TaskGen import feature, before
+from samba_utils import SET_TARGET_TYPE, TO_LIST, LOCAL_CACHE
 
 def SAMBA_PIDL(bld, pname, source,
                options='',
@@ -112,13 +113,12 @@ Build.BuildContext.SAMBA_PIDL_LIST = SAMBA_PIDL_LIST
 
 #################################################################
 # the rule for generating the NDR tables
-from TaskGen import feature, before
 @feature('collect')
 @before('exec_rule')
 def collect(self):
     pidl_headers = LOCAL_CACHE(self.bld, 'PIDL_HEADERS')
     for (name, hd) in pidl_headers.items():
-        y = self.bld.name_to_obj(name, self.env)
+        y = self.bld.get_tgen_by_name(name)
         self.bld.ASSERT(y is not None, 'Failed to find PIDL header %s' % name)
         y.post()
         for node in hd:
@@ -128,7 +128,6 @@ def collect(self):
 
 def SAMBA_PIDL_TABLES(bld, name, target):
     '''generate the pidl NDR tables file'''
-    headers = bld.env.PIDL_HEADERS
     bld.SET_BUILD_GROUP('main')
     t = bld(
             features = 'collect',
diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index a8f780f..057a017 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -1,9 +1,7 @@
 # waf build tool for building IDL files with pidl
 
-import Build
-from samba_utils import *
-from samba_autoconf import *
-
+import os
+import Build, Logs, Utils, Configure
 from Configure import conf
 
 @conf
@@ -65,7 +63,12 @@ def SAMBA_CHECK_PYTHON_HEADERS(conf, mandatory=True):
     del(conf.env.defines['PYTHONARCHDIR'])
 
 def _check_python_headers(conf, mandatory):
-    conf.check_python_headers(mandatory=mandatory)
+    try:
+        Configure.ConfigurationError
+        conf.check_python_headers(mandatory=mandatory)
+    except Configure.ConfigurationError:
+        if mandatory:
+             raise
 
     if conf.env['PYTHON_VERSION'] > '3':
         abi_pattern = os.path.splitext(conf.env['pyext_PATTERN'])[0]
@@ -94,7 +97,18 @@ def SAMBA_PYTHON(bld, name,
     # when we support static python modules we'll need to gather
     # the list from all the SAMBA_PYTHON() targets
     if init_function_sentinel is not None:
-        cflags += '-DSTATIC_LIBPYTHON_MODULES=%s' % init_function_sentinel
+        cflags += ' -DSTATIC_LIBPYTHON_MODULES=%s' % init_function_sentinel
+
+    # From https://docs.python.org/2/c-api/arg.html:
+    # Starting with Python 2.5 the type of the length argument to
+    # PyArg_ParseTuple(), PyArg_ParseTupleAndKeywords() and PyArg_Parse()
+    # can be controlled by defining the macro PY_SSIZE_T_CLEAN before
+    # including Python.h. If the macro is defined, length is a Py_ssize_t
+    # rather than an int.
+
+    # Because <Python.h> if often included before includes.h/config.h
+    # This must be in the -D compiler options
+    cflags += ' -DPY_SSIZE_T_CLEAN=1'
 
     source = bld.EXPAND_VARIABLES(source, vars=vars)
 
diff --git a/buildtools/wafsamba/samba_third_party.py b/buildtools/wafsamba/samba_third_party.py
index 46a1b94..8cfa4df 100644
--- a/buildtools/wafsamba/samba_third_party.py
+++ b/buildtools/wafsamba/samba_third_party.py
@@ -1,8 +1,8 @@
 # functions to support third party libraries
 
+import os
+import Utils, Build
 from Configure import conf
-import sys, Logs, os
-from samba_bundled import *
 
 @conf
 def CHECK_FOR_THIRD_PARTY(conf):
diff --git a/buildtools/wafsamba/samba_utils.py b/buildtools/wafsamba/samba_utils.py
index 540fe44..49a8759 100644
--- a/buildtools/wafsamba/samba_utils.py
+++ b/buildtools/wafsamba/samba_utils.py
@@ -1,11 +1,11 @@
 # a waf tool to add autoconf-like macros to the configure section
 # and for SAMBA_ macros for building libraries, binaries etc
 
-import Build, os, sys, Options, Utils, Task, re, fnmatch, Logs
-from TaskGen import feature, before
+import os, sys, re, fnmatch, shlex
+import Build, Options, Utils, Task, Logs, Configure
+from TaskGen import feature, before, after
 from Configure import conf, ConfigurationContext
 from Logs import debug
-import shlex
 
 # TODO: make this a --option
 LIB_PATH="shared"
@@ -35,22 +35,6 @@ def GET_TARGET_TYPE(ctx, target):
     return cache[target]
 
 
-######################################################
-# this is used as a decorator to make functions only
-# run once. Based on the idea from
-# http://stackoverflow.com/questions/815110/is-there-a-decorator-to-simply-cache-function-return-values
-def runonce(function):
-    runonce_ret = {}
-    def runonce_wrapper(*args):
-        if args in runonce_ret:
-            return runonce_ret[args]
-        else:
-            ret = function(*args)
-            runonce_ret[args] = ret
-            return ret
-    return runonce_wrapper
-
-
 def ADD_LD_LIBRARY_PATH(path):
     '''add something to LD_LIBRARY_PATH'''
     if 'LD_LIBRARY_PATH' in os.environ:
@@ -66,7 +50,7 @@ def ADD_LD_LIBRARY_PATH(path):
 def needs_private_lib(bld, target):
     '''return True if a target links to a private library'''
     for lib in getattr(target, "final_libs", []):
-        t = bld.name_to_obj(lib, bld.env)
+        t = bld.get_tgen_by_name(lib)
         if t and getattr(t, 'private_library', False):
             return True
     return False
@@ -135,28 +119,6 @@ def dict_concat(d1, d2):
         if t not in d1:
             d1[t] = d2[t]
 
-
-def exec_command(self, cmd, **kw):
-    '''this overrides the 'waf -v' debug output to be in a nice
-    unix like format instead of a python list.
-    Thanks to ita on #waf for this'''
-    import Utils, Logs
-    _cmd = cmd
-    if isinstance(cmd, list):
-        _cmd = ' '.join(cmd)
-    debug('runner: %s' % _cmd)
-    if self.log:
-        self.log.write('%s\n' % cmd)
-        kw['log'] = self.log
-    try:
-        if not kw.get('cwd', None):
-            kw['cwd'] = self.cwd
-    except AttributeError:
-        self.cwd = kw['cwd'] = self.bldnode.abspath()
-    return Utils.exec_command(cmd, **kw)
-Build.BuildContext.exec_command = exec_command
-
-
 def ADD_COMMAND(opt, name, function):
     '''add a new top level command to waf'''
     Utils.g_module.__dict__[name] = function
@@ -164,7 +126,7 @@ def ADD_COMMAND(opt, name, function):
 Options.Handler.ADD_COMMAND = ADD_COMMAND
 
 
- at feature('cc', 'cshlib', 'cprogram')
+ at feature('c', 'cc', 'cshlib', 'cprogram')
 @before('apply_core','exec_rule')
 def process_depends_on(self):
     '''The new depends_on attribute for build rules
@@ -173,7 +135,7 @@ def process_depends_on(self):
     if getattr(self , 'depends_on', None):
         lst = self.to_list(self.depends_on)
         for x in lst:
-            y = self.bld.name_to_obj(x, self.env)
+            y = self.bld.get_tgen_by_name(x)
             self.bld.ASSERT(y is not None, "Failed to find dependency %s of %s" % (x, self.name))
             y.post()
             if getattr(y, 'more_includes', None):
@@ -386,7 +348,7 @@ def RUN_COMMAND(cmd,
     return -1
 
 
-def RUN_PYTHON_TESTS(testfiles, pythonpath=None):
+def RUN_PYTHON_TESTS(testfiles, pythonpath=None, extra_env=None):
     env = LOAD_ENVIRONMENT()
     if pythonpath is None:
         pythonpath = os.path.join(Utils.g_module.blddir, 'python')
@@ -394,6 +356,9 @@ def RUN_PYTHON_TESTS(testfiles, pythonpath=None):
     for interp in env.python_interpreters:
         for testfile in testfiles:
             cmd = "PYTHONPATH=%s %s %s" % (pythonpath, interp, testfile)
+            if extra_env:
+                for key, value in extra_env.items():
+                    cmd = "%s=%s %s" % (key, value, cmd)
             print('Running Python test with %s: %s' % (interp, testfile))
             ret = RUN_COMMAND(cmd)
             if ret:
@@ -644,7 +609,7 @@ def get_tgt_list(bld):
         type = targets[tgt]
         if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
             continue
-        t = bld.name_to_obj(tgt, bld.env)
+        t = bld.get_tgen_by_name(tgt)
         if t is None:
             Logs.error("Target %s of type %s has no task generator" % (tgt, type))
             sys.exit(1)
@@ -657,11 +622,10 @@ def PROCESS_SEPARATE_RULE(self, rule):
         You should have file named wscript_<stage>_rule in the current directory
         where stage is either 'configure' or 'build'
     '''
-    ctxclass = self.__class__.__name__
     stage = ''
-    if ctxclass == 'ConfigurationContext':
+    if isinstance(self, Configure.ConfigurationContext):
         stage = 'configure'
-    elif ctxclass == 'BuildContext':
+    elif isinstance(self, Build.BuildContext):
         stage = 'build'
     file_path = os.path.join(self.curdir, WSCRIPT_FILE+'_'+stage+'_'+rule)
     txt = load_file(file_path)
@@ -682,3 +646,26 @@ def AD_DC_BUILD_IS_ENABLED(self):
     return False
 
 Build.BuildContext.AD_DC_BUILD_IS_ENABLED = AD_DC_BUILD_IS_ENABLED
+
+ at feature('cprogram', 'cshlib', 'cstaticlib')
+ at after('apply_lib_vars')
+ at before('apply_obj_vars')
+def samba_before_apply_obj_vars(self):
+    """before apply_obj_vars for uselib, this removes the standard paths"""
+
+    def is_standard_libpath(env, path):
+        for _path in env.STANDARD_LIBPATH:
+            if _path == os.path.normpath(path):
+                return True
+        return False
+
+    v = self.env
+
+    for i in v['RPATH']:
+        if is_standard_libpath(v, i):
+            v['RPATH'].remove(i)
+
+    for i in v['LIBPATH']:
+        if is_standard_libpath(v, i):
+            v['LIBPATH'].remove(i)
+
diff --git a/buildtools/wafsamba/samba_version.py b/buildtools/wafsamba/samba_version.py
index bb0be96..950a855 100644
--- a/buildtools/wafsamba/samba_version.py
+++ b/buildtools/wafsamba/samba_version.py
@@ -42,12 +42,10 @@ def git_version_summary(path, env=None):
 
 def distversion_version_summary(path):
     #get version from .distversion file
-    f = open(path + '/.distversion', 'r')
     suffix = None
     fields = {}
 
-    for line in f:
-        line = line.strip()
+    for line in Utils.readf(path + '/.distversion').splitlines():
         if line == '':
             continue
         if line.startswith("#"):
@@ -64,7 +62,6 @@ def distversion_version_summary(path):
         except:
             print("Failed to parse line %s from .distversion file." % (line))
             raise
-    f.close()
 
     if "COMMIT_TIME" in fields:
         fields["COMMIT_TIME"] = int(fields["COMMIT_TIME"])
diff --git a/buildtools/wafsamba/samba_wildcard.py b/buildtools/wafsamba/samba_wildcard.py
index 84503b8..ed3e0c2 100644
--- a/buildtools/wafsamba/samba_wildcard.py
+++ b/buildtools/wafsamba/samba_wildcard.py
@@ -1,9 +1,9 @@
 # based on playground/evil in the waf svn tree
 
-import os, datetime
-import Scripting, Utils, Options, Logs, Environment, fnmatch
-from Constants import *
-from samba_utils import *
+import os, datetime, fnmatch
+import Scripting, Utils, Options, Logs, Environment
+from Constants import SRCDIR, BLDDIR
+from samba_utils import LOCAL_CACHE, os_path_relpath
 
 def run_task(t, k):
     '''run a single build task'''
@@ -130,7 +130,6 @@ def fake_build_environment(info=True, flush=False):
 
     Options.commands['install'] = False
     Options.commands['uninstall'] = False
-    Options.is_install = False
 
     bld.is_install = 0 # False
 
diff --git a/buildtools/wafsamba/symbols.py b/buildtools/wafsamba/symbols.py
index daa18b9..7ff4bac 100644
--- a/buildtools/wafsamba/symbols.py
+++ b/buildtools/wafsamba/symbols.py
@@ -1,9 +1,10 @@
 # a waf tool to extract symbols from object files or libraries
 # using nm, producing a set of exposed defined/undefined symbols
 
-import Utils, Build, subprocess, Logs, re
-from samba_wildcard import fake_build_environment
-from samba_utils import *
+import os, re, subprocess
+import Utils, Build, Options, Logs
+from Logs import debug
+from samba_utils import TO_LIST, LOCAL_CACHE, get_tgt_list, os_path_relpath
 
 # these are the data structures used in symbols.py:
 #
@@ -251,7 +252,7 @@ def build_symbol_sets(bld, tgt_list):
             bld.env.public_symbols[name] = t.public_symbols
         if t.samba_type == 'LIBRARY':
             for dep in t.add_objects:
-                t2 = bld.name_to_obj(dep, bld.env)
+                t2 = bld.get_tgen_by_name(dep)
                 bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep))
                 bld.env.public_symbols[name] = bld.env.public_symbols[name].union(t2.public_symbols)
 
@@ -264,7 +265,7 @@ def build_symbol_sets(bld, tgt_list):
             bld.env.used_symbols[name] = t.used_symbols
         if t.samba_type == 'LIBRARY':
             for dep in t.add_objects:
-                t2 = bld.name_to_obj(dep, bld.env)
+                t2 = bld.get_tgen_by_name(dep)
                 bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep))
                 bld.env.used_symbols[name] = bld.env.used_symbols[name].union(t2.used_symbols)
 
@@ -362,7 +363,7 @@ def build_autodeps(bld, t):
             if targets[depname[0]] in [ 'SYSLIB' ]:
                 deps.add(depname[0])
                 continue
-            t2 = bld.name_to_obj(depname[0], bld.env)
+            t2 = bld.get_tgen_by_name(depname[0])
             if len(t2.in_library) != 1:
                 deps.add(depname[0])
                 continue
@@ -385,7 +386,7 @@ def build_library_names(bld, tgt_list):
     for t in tgt_list:
         if t.samba_type in [ 'LIBRARY' ]:
             for obj in t.samba_deps_extended:
-                t2 = bld.name_to_obj(obj, bld.env)
+                t2 = bld.get_tgen_by_name(obj)
                 if t2 and t2.samba_type in [ 'SUBSYSTEM', 'ASN1' ]:
                     if not t.sname in t2.in_library:
                         t2.in_library.append(t.sname)
@@ -402,7 +403,7 @@ def check_library_deps(bld, t):
         Logs.warn("WARNING: Target '%s' in multiple libraries: %s" % (t.sname, t.in_library))
 
     for dep in t.autodeps:
-        t2 = bld.name_to_obj(dep, bld.env)
+        t2 = bld.get_tgen_by_name(dep)
         if t2 is None:
             continue
         for dep2 in t2.autodeps:
@@ -435,7 +436,7 @@ def check_syslib_collisions(bld, tgt_list):
 def check_dependencies(bld, t):
     '''check for depenencies that should be changed'''
 
-    if bld.name_to_obj(t.sname + ".objlist", bld.env):
+    if bld.get_tgen_by_name(t.sname + ".objlist"):
         return
 
     targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
@@ -475,7 +476,7 @@ def check_dependencies(bld, t):
 def check_syslib_dependencies(bld, t):
     '''check for syslib depenencies'''
 
-    if bld.name_to_obj(t.sname + ".objlist", bld.env):
+    if bld.get_tgen_by_name(t.sname + ".objlist"):
         return
 
     sname = real_name(t.sname)
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index c27241e..4a47dbf 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -20,6 +20,7 @@ from samba_perl import *
 from samba_deps import *
 from samba_bundled import *
 from samba_third_party import *
+import samba_cross
 import samba_install
 import samba_conftests
 import samba_abi
@@ -95,9 +96,7 @@ Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
 
 
 def generate_empty_file(task):
-    target_fname = installed_location=task.outputs[0].bldpath(task.env)
-    target_file = open(installed_location, 'w')
-    target_file.close()
+    task.outputs[0].write('')
     return 0
 
 #################################################################
@@ -107,6 +106,7 @@ def SAMBA_LIBRARY(bld, libname, source,
                   includes='',
                   public_headers=None,
                   public_headers_install=True,
+                  private_headers=None,
                   header_path=None,
                   pc_files=None,
                   vnum=None,
@@ -146,8 +146,12 @@ def SAMBA_LIBRARY(bld, libname, source,
     if pyembed and bld.env['IS_EXTRA_PYTHON']:
         public_headers = pc_files = None
 
+    if private_library and public_headers:
+        raise Utils.WafError("private library '%s' must not have public header files" %
+                             libname)
+
     if LIB_MUST_BE_PRIVATE(bld, libname):
-        private_library=True
+        private_library = True
 
     if not enabled:
         SET_TARGET_TYPE(bld, libname, 'DISABLED')
@@ -188,6 +192,7 @@ def SAMBA_LIBRARY(bld, libname, source,
                         includes       = includes,
                         public_headers = public_headers,
                         public_headers_install = public_headers_install,
+                        private_headers= private_headers,
                         header_path    = header_path,
                         cflags         = cflags,
                         group          = subsystem_group,
@@ -245,7 +250,7 @@ def SAMBA_LIBRARY(bld, libname, source,
     if bld.env['ENABLE_RELRO'] is True:
         ldflags.extend(TO_LIST('-Wl,-z,relro,-z,now'))
 
-    features = 'cc cshlib symlink_lib install_lib'
+    features = 'c cshlib symlink_lib install_lib'
     if pyext:
         features += ' pyext'
     if pyembed:
@@ -254,6 +259,15 @@ def SAMBA_LIBRARY(bld, libname, source,
     if abi_directory:
         features += ' abi_check'
 
+    if pyembed and bld.env['PYTHON_SO_ABI_FLAG']:
+        # For ABI checking, we don't care about the exact Python version.
+        # Replace the Python ABI tag (e.g. ".cpython-35m") by a generic ".py3"
+        abi_flag = bld.env['PYTHON_SO_ABI_FLAG']
+        replacement = '.py%s' % bld.env['PYTHON_VERSION'].split('.')[0]
+        version_libname = libname.replace(abi_flag, replacement)
+    else:
+        version_libname = libname
+
     vscript = None
     if bld.env.HAVE_LD_VERSION_SCRIPT:
         if private_library:
@@ -264,7 +278,7 @@ def SAMBA_LIBRARY(bld, libname, source,
             version = None
         if version:
             vscript = "%s.vscript" % libname
-            bld.ABI_VSCRIPT(libname, abi_directory, version, vscript,
+            bld.ABI_VSCRIPT(version_libname, abi_directory, version, vscript,
                             abi_match)
             fullname = apply_pattern(bundled_name, bld.env.shlib_PATTERN)
             fullpath = bld.path.find_or_declare(fullname)
@@ -274,7 +288,7 @@ def SAMBA_LIBRARY(bld, libname, source,
             if not vscriptpath:
                 raise Utils.WafError("unable to find vscript path for %s" % vscript)
             bld.add_manual_dependency(fullpath, vscriptpath)
-            if Options.is_install:
+            if bld.is_install:
                 # also make the .inst file depend on the vscript
                 instname = apply_pattern(bundled_name + '.inst', bld.env.shlib_PATTERN)
                 bld.add_manual_dependency(bld.path.find_or_declare(instname), bld.path.find_or_declare(vscript))
@@ -290,6 +304,7 @@ def SAMBA_LIBRARY(bld, libname, source,
         samba_deps      = deps,
         samba_includes  = includes,
         version_script  = vscript,
+        version_libname = version_libname,
         local_include   = local_include,
         global_include  = global_include,
         vnum            = vnum,
@@ -328,6 +343,7 @@ def SAMBA_BINARY(bld, binname, source,
                  deps='',
                  includes='',
                  public_headers=None,
+                 private_headers=None,
                  header_path=None,
                  modules=None,
                  ldflags=None,
@@ -356,7 +372,7 @@ def SAMBA_BINARY(bld, binname, source,
     if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
         return
 
-    features = 'cc cprogram symlink_bin install_bin'
+    features = 'c cprogram symlink_bin install_bin'
     if pyembed:
         features += ' pyembed'
 
@@ -530,6 +546,7 @@ def SAMBA_SUBSYSTEM(bld, modname, source,
                     includes='',
                     public_headers=None,
                     public_headers_install=True,
+                    private_headers=None,
                     header_path=None,
                     cflags='',
                     cflags_end=None,
@@ -580,7 +597,7 @@ def SAMBA_SUBSYSTEM(bld, modname, source,
 
     bld.SET_BUILD_GROUP(group)
 
-    features = 'cc'
+    features = 'c'
     if pyext:
         features += ' pyext'
     if pyembed:
@@ -622,6 +639,7 @@ def SAMBA_GENERATOR(bld, name, rule, source='', target='',
                     group='generators', enabled=True,
                     public_headers=None,
                     public_headers_install=True,
+                    private_headers=None,
                     header_path=None,
                     vars=None,
                     dep_vars=[],
@@ -665,7 +683,7 @@ Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
 
 
 
- at runonce
+ at Utils.run_once
 def SETUP_BUILD_GROUPS(bld):
     '''setup build groups used to ensure that the different build
     phases happen consecutively'''
@@ -718,7 +736,7 @@ def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
     '''used to copy scripts from the source tree into the build directory
        for use by selftest'''
 
-    source = bld.path.ant_glob(pattern)
+    source = bld.path.ant_glob(pattern, flat=True)
 
     bld.SET_BUILD_GROUP('build_source')
     for s in TO_LIST(source):
@@ -847,7 +865,7 @@ Build.BuildContext.INSTALL_FILES = INSTALL_FILES
 def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
                      python_fixup=False, exclude=None, trim_path=None):
     '''install a set of files matching a wildcard pattern'''
-    files=TO_LIST(bld.path.ant_glob(pattern))
+    files=TO_LIST(bld.path.ant_glob(pattern, flat=True))
     if trim_path:
         files2 = []
         for f in files:
diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript
index d6bb688..586cc4b 100755
--- a/buildtools/wafsamba/wscript
+++ b/buildtools/wafsamba/wscript
@@ -2,9 +2,9 @@
 
 # this is a base set of waf rules that everything else pulls in first
 
-import sys, wafsamba, Configure, Logs
-import Options, os, preproc
-from samba_utils import *
+import os, sys
+import wafsamba, Configure, Logs, Options, Utils
+from samba_utils import os_path_relpath
 from optparse import SUPPRESS_HELP
 
 # this forces configure to be re-run if any of the configure
@@ -78,9 +78,6 @@ def set_options(opt):
                    help='additional directory to search for libiconv',
                    action='store', dest='iconv_open', default='/usr/local',
                    match = ['Checking for library iconv', 'Checking for iconv_open', 'Checking for header iconv.h'])
-    opt.add_option('--with-gettext',
-                   help='additional directory to search for gettext',
-                   action='store', dest='gettext_location', default='None')
     opt.add_option('--without-gettext',
                    help=("Disable use of gettext"),
                    action="store_true", dest='disable_gettext', default=False)
@@ -99,9 +96,13 @@ def set_options(opt):
     gr.add_option('--enable-developer',
                    help=("Turn on developer warnings and debugging"),
                    action="store_true", dest='developer', default=False)
+    def picky_developer_callback(option, opt_str, value, parser):
+        parser.values.developer = True
+        parser.values.picky_developer = True
     gr.add_option('--picky-developer',
                    help=("Treat all warnings as errors (enable -Werror)"),
-                   action="store_true", dest='picky_developer', default=False)
+                   action="callback", callback=picky_developer_callback,
+                   dest='picky_developer', default=False)
     gr.add_option('--fatal-errors',
                    help=("Stop compilation on first error (enable -Wfatal-errors)"),
                    action="store_true", dest='fatal_errors', default=False)
@@ -202,7 +203,7 @@ def set_options(opt):
                     metavar="PYTHON", dest='EXTRA_PYTHON', default=None)
 
 
- at wafsamba.runonce
+ at Utils.run_once
 def configure(conf):
     conf.env.hlist = []
     conf.env.srcdir = conf.srcdir
@@ -215,6 +216,7 @@ def configure(conf):
     # load our local waf extensions
     conf.check_tool('gnu_dirs')
     conf.check_tool('wafsamba')
+    conf.check_tool('print_commands')
 
     conf.CHECK_CC_ENV()
 
@@ -227,6 +229,11 @@ def configure(conf):
 
     # older gcc versions (< 4.4) does not work with gccdeps, so we have to see if the .d file is generated
     if Options.options.enable_gccdeps:
+        # stale file removal - the configuration may pick up the old .pyc file
+        p = os.path.join(conf.srcdir, 'buildtools/wafsamba/gccdeps.pyc')
+        if os.path.exists(p):
+            os.remove(p)
+
         from TaskGen import feature, after
         @feature('testd')
         @after('apply_core')
@@ -241,7 +248,7 @@ def configure(conf):
         cc.run = Task.compile_fun_noshell('cc', '${CC} ${CCFLAGS} ${CPPFLAGS} ${_CCINCFLAGS} ${_CCDEFFLAGS} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT[0].abspath(env)}')[0]
         try:
             try:
-                conf.check(features='cc testd', fragment='int main() {return 0;}\n', ccflags=['-MD'], mandatory=True, msg='Check for -MD')
+                conf.check(features='c testd', fragment='int main() {return 0;}\n', ccflags=['-MD'], mandatory=True, msg='Check for -MD')
             except:
                 pass
             else:
@@ -361,6 +368,40 @@ def configure(conf):
                         cflags=conf.env.VISIBILITY_CFLAGS,
                         define='HAVE_VISIBILITY_ATTR', addmain=False)
 
+    # check HAVE_CONSTRUCTOR_ATTRIBUTE
+    conf.CHECK_CODE('''
+            void test_constructor_attribute(void) __attribute__ ((constructor));
+
+            void test_constructor_attribute(void)
+            {
+                return;
+            }
+
+            int main(void) {
+                return 0;
+            }
+            ''',
+            'HAVE_CONSTRUCTOR_ATTRIBUTE',
+            addmain=False,
+            msg='Checking for library constructor support')
+
+        # check HAVE_DESTRUCTOR_ATTRIBUTE
+    conf.CHECK_CODE('''
+            void test_destructor_attribute(void) __attribute__ ((destructor));
+
+            void test_destructor_attribute(void)
+            {
+                return;
+            }
+
+            int main(void) {
+                return 0;
+            }
+            ''',
+            'HAVE_DESTRUCTOR_ATTRIBUTE',
+            addmain=False,
+            msg='Checking for library destructor support')
+
     if sys.platform.startswith('aix'):
         conf.DEFINE('_ALL_SOURCE', 1, add_to_cflags=True)
         # Might not be needed if ALL_SOURCE is defined
diff --git a/ctdb/client/client.h b/ctdb/client/client.h
new file mode 100644
index 0000000..bce0c6b
--- /dev/null
+++ b/ctdb/client/client.h
@@ -0,0 +1,842 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_CLIENT_H__
+#define __CTDB_CLIENT_H__
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "protocol/protocol.h"
+#include "common/srvid.h"
+
+struct ctdb_client_context;
+struct ctdb_db_context;
+struct ctdb_record_handle;
+
+typedef void (*ctdb_client_callback_func_t)(void *private_data);
+
+/* from client/client_connect.c */
+
+int ctdb_client_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		     const char *sockpath, struct ctdb_client_context **ret);
+
+void ctdb_client_set_disconnect_callback(struct ctdb_client_context *client,
+					 ctdb_client_callback_func_t func,
+					 void *private_data);
+
+uint32_t ctdb_client_pnn(struct ctdb_client_context *client);
+
+void ctdb_client_wait(struct tevent_context *ev, bool *done);
+
+struct tevent_req *ctdb_recovery_wait_send(TALLOC_CTX *mem_ctx,
+					   struct tevent_context *ev,
+					   struct ctdb_client_context *client);
+
+bool ctdb_recovery_wait_recv(struct tevent_req *req, int *perr);
+
+/* from client/client_call.c */
+
+struct tevent_req *ctdb_client_call_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct ctdb_client_context *client,
+					 struct ctdb_req_call *request);
+
+bool ctdb_client_call_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+			   struct ctdb_reply_call **reply, int *perr);
+
+
+/* from client/client_message.c */
+
+struct tevent_req *ctdb_client_message_send(TALLOC_CTX *mem_ctx,
+					    struct tevent_context *ev,
+					    struct ctdb_client_context *client,
+					    uint32_t destnode,
+					    struct ctdb_req_message *message);
+
+bool ctdb_client_message_recv(struct tevent_req *req, int *perr);
+
+int ctdb_client_message(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			uint32_t destnode, struct ctdb_req_message *message);
+
+int ctdb_client_set_message_handler(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    uint64_t srvid, srvid_handler_fn handler,
+				    void *private_data);
+
+int ctdb_client_remove_message_handler(TALLOC_CTX *mem_ctx,
+				       struct tevent_context *ev,
+				       struct ctdb_client_context *client,
+				       uint64_t srvid, void *private_data);
+
+/* from client/client_message_sync.c */
+
+int ctdb_message_recd_update_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct ctdb_public_ip *pubip);
+
+int ctdb_message_mem_dump(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct ctdb_srvid_message *msg);
+
+int ctdb_message_reload_nodes(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode);
+
+int ctdb_message_takeover_run(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct ctdb_srvid_message *msg);
+
+int ctdb_message_rebalance_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, uint32_t pnn);
+
+int ctdb_message_disable_takeover_runs(TALLOC_CTX *mem_ctx,
+				       struct tevent_context *ev,
+				       struct ctdb_client_context *client,
+				       int destnode,
+				       struct ctdb_disable_message *disable);
+
+int ctdb_message_disable_recoveries(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    int destnode,
+				    struct ctdb_disable_message *disable);
+
+int ctdb_message_disable_ip_check(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  struct ctdb_client_context *client,
+				  int destnode, uint32_t timeout);
+
+/* from client/client_control.c */
+
+struct tevent_req *ctdb_client_control_send(TALLOC_CTX *mem_ctx,
+					    struct tevent_context *ev,
+					    struct ctdb_client_context *client,
+					    uint32_t destnode,
+					    struct timeval timeout,
+					    struct ctdb_req_control *request);
+
+bool ctdb_client_control_recv(struct tevent_req *req, int *perr,
+			      TALLOC_CTX *mem_ctx,
+			      struct ctdb_reply_control **preply);
+
+struct tevent_req *ctdb_client_control_multi_send(
+				TALLOC_CTX *mem_ctx,
+				struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				uint32_t *pnn_list, int count,
+				struct timeval timeout,
+				struct ctdb_req_control *request);
+
+bool ctdb_client_control_multi_recv(struct tevent_req *req, int *perr,
+				    TALLOC_CTX *mem_ctx, int **perr_list,
+				    struct ctdb_reply_control ***preply);
+
+int ctdb_client_control_multi_error(uint32_t *pnn_list, int count,
+				    int *err_list, uint32_t *pnn);
+
+int ctdb_client_control(TALLOC_CTX *mem_ctx,
+			struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			uint32_t destnode,
+			struct timeval timeout,
+			struct ctdb_req_control *c,
+			struct ctdb_reply_control **preply);
+
+int ctdb_client_control_multi(TALLOC_CTX *mem_ctx,
+			      struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      uint32_t *pnn_list, int count,
+			      struct timeval timeout,
+			      struct ctdb_req_control *request,
+			      int **perr,
+			      struct ctdb_reply_control ***preply);
+
+/* from client/client_control_sync.c */
+
+int ctdb_ctrl_process_exists(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     pid_t pid, int *status);
+
+int ctdb_ctrl_statistics(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 struct ctdb_statistics **stats);
+
+int ctdb_ctrl_ping(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		   struct ctdb_client_context *client,
+		   int destnode, struct timeval timeout,
+		   int *num_clients);
+
+int ctdb_ctrl_getdbpath(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			uint32_t db_id, const char **db_path);
+
+int ctdb_ctrl_getvnnmap(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			struct ctdb_vnn_map **vnnmap);
+
+int ctdb_ctrl_getdebug(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       int destnode, struct timeval timeout,
+		       uint32_t *loglevel);
+
+int ctdb_ctrl_setdebug(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       int destnode, struct timeval timeout,
+		       uint32_t loglevel);
+
+int ctdb_ctrl_get_dbmap(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			struct ctdb_dbid_map **dbmap);
+
+int ctdb_ctrl_pull_db(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client, int destnode,
+		      struct timeval timeout, struct ctdb_pulldb *pulldb,
+		      struct ctdb_rec_buffer **recbuf);
+
+int ctdb_ctrl_push_db(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client, int destnode,
+		      struct timeval timeout, struct ctdb_rec_buffer *recbuf);
+
+int ctdb_ctrl_get_recmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  int *recmode);
+
+int ctdb_ctrl_set_recmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  int recmode);
+
+int ctdb_ctrl_statistics_reset(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout);
+
+int ctdb_ctrl_db_attach(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			const char *db_name, uint32_t tdb_flags,
+			uint32_t *db_id);
+
+int ctdb_ctrl_traverse_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     struct ctdb_traverse_start *traverse);
+
+int ctdb_ctrl_register_srvid(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     uint64_t srvid);
+
+int ctdb_ctrl_deregister_srvid(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       uint64_t srvid);
+
+int ctdb_ctrl_get_dbname(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 uint32_t db_id, const char **db_name);
+
+int ctdb_ctrl_enable_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id);
+
+int ctdb_ctrl_update_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id);
+
+int ctdb_ctrl_dump_memory(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  const char **mem_str);
+
+int ctdb_ctrl_get_pid(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client,
+		      int destnode, struct timeval timeout,
+		      pid_t *pid);
+
+int ctdb_ctrl_get_recmaster(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t *recmaster);
+
+int ctdb_ctrl_set_recmaster(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t recmaster);
+
+int ctdb_ctrl_freeze(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		     struct ctdb_client_context *client,
+		     int destnode, struct timeval timeout,
+		     int priority);
+
+int ctdb_ctrl_thaw(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		   struct ctdb_client_context *client,
+		   int destnode, struct timeval timeout,
+		   int priority);
+
+int ctdb_ctrl_get_pnn(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client,
+		      int destnode, struct timeval timeout,
+		      uint32_t *pnn);
+
+int ctdb_ctrl_shutdown(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       int destnode, struct timeval timeout);
+
+int ctdb_ctrl_get_monmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  int *mon_mode);
+
+int ctdb_ctrl_tcp_add(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client,
+		      int destnode, struct timeval timeout,
+		      struct ctdb_connection *conn);
+
+int ctdb_ctrl_tcp_remove(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 struct ctdb_connection *conn);
+
+int ctdb_ctrl_set_tunable(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  struct ctdb_tunable *tunable);
+
+int ctdb_ctrl_get_tunable(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  const char *var, uint32_t *value);
+
+int ctdb_ctrl_list_tunables(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_var_list **var_list);
+
+int ctdb_ctrl_modify_flags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   int destnode, struct timeval timeout,
+			   uint32_t pnn, uint32_t old_flags,
+			   uint32_t new_flags);
+
+int ctdb_ctrl_get_all_tunables(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       struct ctdb_tunable_list **tun_list);
+
+int ctdb_ctrl_kill_tcp(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       int destnode, struct timeval timeout,
+		       struct ctdb_connection *conn);
+
+int ctdb_ctrl_get_tcp_tickle_list(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  struct ctdb_client_context *client,
+				  int destnode, struct timeval timeout,
+				  ctdb_sock_addr *addr,
+				  struct ctdb_tickle_list **tickles);
+
+int ctdb_ctrl_set_tcp_tickle_list(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  struct ctdb_client_context *client,
+				  int destnode, struct timeval timeout,
+				  struct ctdb_tickle_list *tickles);
+
+int ctdb_ctrl_register_server_id(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 struct ctdb_client_id *cid);
+
+int ctdb_ctrl_unregister_server_id(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct ctdb_client_context *client,
+				   int destnode, struct timeval timeout,
+				   struct ctdb_client_id *cid);
+
+int ctdb_ctrl_check_server_id(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      struct ctdb_client_id *cid);
+
+int ctdb_ctrl_get_server_id_list(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 struct ctdb_client_id_map **cid_map);
+
+int ctdb_ctrl_db_attach_persistent(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct ctdb_client_context *client,
+				   int destnode, struct timeval timeout,
+				   const char *db_name, int tdb_flags,
+				   uint32_t *db_id);
+
+int ctdb_ctrl_send_gratuitous_arp(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  struct ctdb_client_context *client,
+				  int destnode, struct timeval timeout,
+				  struct ctdb_addr_info *addr_info);
+
+int ctdb_ctrl_transaction_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout,
+				uint32_t tid);
+
+int ctdb_ctrl_transaction_commit(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 uint32_t tid);
+
+int ctdb_ctrl_wipe_database(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id, uint32_t tid);
+
+int ctdb_ctrl_uptime(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		     struct ctdb_client_context *client,
+		     int destnode, struct timeval timeout,
+		     struct ctdb_uptime **uptime);
+
+int ctdb_ctrl_start_recovery(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout);
+
+int ctdb_ctrl_end_recovery(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   int destnode, struct timeval timeout);
+
+int ctdb_ctrl_reload_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout);
+
+int ctdb_ctrl_enable_monitor(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout);
+
+int ctdb_ctrl_disable_monitor(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout);
+
+int ctdb_ctrl_add_public_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_addr_info *addr_info);
+
+int ctdb_ctrl_del_public_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_addr_info *addr_info);
+
+int ctdb_ctrl_run_eventscripts(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       const char *event);
+
+int ctdb_ctrl_get_capabilities(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       uint32_t *caps);
+
+int ctdb_ctrl_release_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 struct ctdb_public_ip *pubip);
+
+int ctdb_ctrl_takeover_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  struct ctdb_public_ip *pubip);
+
+int ctdb_ctrl_get_public_ips(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     struct ctdb_public_ip_list **pubip_list);
+
+int ctdb_ctrl_get_nodemap(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  struct ctdb_node_map **nodemap);
+
+int ctdb_ctrl_get_event_script_status(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      struct ctdb_client_context *client,
+				      int destnode, struct timeval timeout,
+				      enum ctdb_event event,
+				      struct ctdb_script_list **slist);
+
+int ctdb_ctrl_traverse_kill(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_traverse_start *traverse);
+
+int ctdb_ctrl_get_reclock_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       const char **reclock_file);
+
+int ctdb_ctrl_set_reclock_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       const char *reclock_file);
+
+int ctdb_ctrl_stop_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout);
+
+int ctdb_ctrl_continue_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout);
+
+int ctdb_ctrl_set_natgwstate(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     uint32_t natgw_role);
+
+int ctdb_ctrl_set_lmasterrole(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      uint32_t lmaster_role);
+
+int ctdb_ctrl_set_recmasterrole(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout,
+				uint32_t recmaster_role);
+
+int ctdb_ctrl_enable_script(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    const char *script);
+
+int ctdb_ctrl_disable_script(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     const char *script);
+
+int ctdb_ctrl_set_ban_state(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_ban_state *ban_state);
+
+int ctdb_ctrl_get_ban_state(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_ban_state **ban_state);
+
+int ctdb_ctrl_set_db_priority(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      uint32_t db_id, int priority);
+
+int ctdb_ctrl_get_db_priority(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      uint32_t db_id, uint32_t *priority);
+
+int ctdb_ctrl_transaction_cancel(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 uint32_t tid);
+
+int ctdb_ctrl_register_notify(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      struct ctdb_notify_data *notify);
+
+int ctdb_ctrl_deregister_notify(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout,
+				uint64_t srvid);
+
+int ctdb_ctrl_trans3_commit(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_rec_buffer *recbuf);
+
+int ctdb_ctrl_get_db_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id, uint64_t *seqnum);
+
+int ctdb_ctrl_db_set_healthy(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     uint32_t db_id);
+
+int ctdb_ctrl_db_get_health(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id, const char **reason);
+
+int ctdb_ctrl_get_public_ip_info(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 ctdb_sock_addr *addr,
+				 struct ctdb_public_ip_info **ipinfo);
+
+int ctdb_ctrl_get_ifaces(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 struct ctdb_iface_list **iface_list);
+
+int ctdb_ctrl_set_iface_link_state(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct ctdb_client_context *client,
+				   int destnode, struct timeval timeout,
+				   struct ctdb_iface *iface);
+
+int ctdb_ctrl_tcp_add_delayed_update(TALLOC_CTX *mem_ctx,
+				     struct tevent_context *ev,
+				     struct ctdb_client_context *client,
+				     int destnode, struct timeval timeout,
+				     struct ctdb_connection *conn);
+
+int ctdb_ctrl_get_stat_history(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       struct ctdb_statistics_list **stats_list);
+
+int ctdb_ctrl_schedule_for_deletion(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    int destnode, struct timeval timeout,
+				    struct ctdb_key_data *key);
+
+int ctdb_ctrl_set_db_readonly(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      uint32_t db_id);
+
+int ctdb_ctrl_check_srvids(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   int destnode, struct timeval timeout,
+			   uint64_t *srvid, int count, uint8_t **result);
+
+int ctdb_ctrl_traverse_start_ext(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 struct ctdb_traverse_start_ext *traverse);
+
+int ctdb_ctrl_get_db_statistics(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout,
+				uint32_t db_id,
+				struct ctdb_db_statistics **dbstats);
+
+int ctdb_ctrl_set_db_sticky(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id);
+
+int ctdb_ctrl_reload_public_ips(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout);
+
+int ctdb_ctrl_ipreallocated(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout);
+
+int ctdb_ctrl_get_runstate(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   int destnode, struct timeval timeout,
+			   enum ctdb_runstate *runstate);
+
+int ctdb_ctrl_db_detach(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			uint32_t db_id);
+
+int ctdb_ctrl_get_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     struct ctdb_node_map **nodemap);
+
+int ctdb_ctrl_db_freeze(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout, uint32_t db_id);
+
+int ctdb_ctrl_db_thaw(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client,
+		      int destnode, struct timeval timeout, uint32_t db_id);
+
+int ctdb_ctrl_db_transaction_start(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct ctdb_client_context *client,
+				   int destnode, struct timeval timeout,
+				   struct ctdb_transdb *transdb);
+
+int ctdb_ctrl_db_transaction_commit(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    int destnode, struct timeval timeout,
+				    struct ctdb_transdb *transdb);
+
+int ctdb_ctrl_db_transaction_cancel(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    int destnode, struct timeval timeout,
+				    uint32_t db_id);
+
+/* from client/client_db.c */
+
+struct tevent_req *ctdb_attach_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    struct timeval timeout,
+				    const char *db_name, uint8_t db_flags);
+
+bool ctdb_attach_recv(struct tevent_req *req, int *perr,
+		      struct ctdb_db_context **out);
+
+int ctdb_attach(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		struct ctdb_client_context *client,
+		struct timeval timeout,
+		const char *db_name, uint8_t db_flags,
+		struct ctdb_db_context **out);
+
+int ctdb_detach(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		struct ctdb_client_context *client,
+		struct timeval timeout, uint32_t db_id);
+
+uint32_t ctdb_db_id(struct ctdb_db_context *db);
+
+int ctdb_db_traverse(struct ctdb_db_context *db, bool readonly,
+		     bool extract_header,
+		     ctdb_rec_parser_func_t parser, void *private_data);
+
+struct tevent_req *ctdb_fetch_lock_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct ctdb_client_context *client,
+					struct ctdb_db_context *db,
+					TDB_DATA key, bool readonly);
+
+struct ctdb_record_handle *ctdb_fetch_lock_recv(struct tevent_req *req,
+						struct ctdb_ltdb_header *header,
+						TALLOC_CTX *mem_ctx,
+						TDB_DATA *data, int *perr);
+
+int ctdb_fetch_lock(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		    struct ctdb_client_context *client,
+		    struct ctdb_db_context *db, TDB_DATA key, bool readonly,
+		    struct ctdb_record_handle **out,
+		    struct ctdb_ltdb_header *header, TDB_DATA *data);
+
+int ctdb_store_record(struct ctdb_record_handle *h, TDB_DATA data);
+
+int ctdb_delete_record(struct ctdb_record_handle *h);
+
+struct tevent_req *ctdb_g_lock_lock_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct ctdb_client_context *client,
+					 struct ctdb_db_context *db,
+					 const char *keyname,
+					 struct ctdb_server_id *sid,
+					 bool readonly);
+
+bool ctdb_g_lock_lock_recv(struct tevent_req *req, int *perr);
+
+struct tevent_req *ctdb_g_lock_unlock_send(TALLOC_CTX *mem_ctx,
+					   struct tevent_context *ev,
+					   struct ctdb_client_context *client,
+					   struct ctdb_db_context *db,
+					   const char *keyname,
+					   struct ctdb_server_id sid);
+
+bool ctdb_g_lock_unlock_recv(struct tevent_req *req, int *perr);
+
+struct tevent_req *ctdb_transaction_start_send(TALLOC_CTX *mem_ctx,
+					       struct tevent_context *ev,
+					       struct ctdb_client_context *client,
+					       struct timeval timeout,
+					       struct ctdb_db_context *db,
+					       bool readonly);
+
+struct ctdb_transaction_handle *ctdb_transaction_start_recv(
+					struct tevent_req *req,
+					int *perr);
+
+int ctdb_transaction_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   struct timeval timeout,
+			   struct ctdb_db_context *db, bool readonly,
+			   struct ctdb_transaction_handle **out);
+
+int ctdb_transaction_fetch_record(struct ctdb_transaction_handle *h,
+				  TDB_DATA key,
+				  TALLOC_CTX *mem_ctx, TDB_DATA *data);
+
+int ctdb_transaction_store_record(struct ctdb_transaction_handle *h,
+				  TDB_DATA key, TDB_DATA data);
+
+int ctdb_transaction_delete_record(struct ctdb_transaction_handle *h,
+				   TDB_DATA key);
+
+struct tevent_req *ctdb_transaction_commit_send(
+					TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct ctdb_transaction_handle *h);
+
+bool ctdb_transaction_commit_recv(struct tevent_req *req, int *perr);
+
+int ctdb_transaction_commit(struct ctdb_transaction_handle *h);
+
+int ctdb_transaction_cancel(struct ctdb_transaction_handle *h);
+
+/* from client/client_util.c */
+
+int list_of_nodes(struct ctdb_node_map *nodemap,
+		  uint32_t flags_mask, uint32_t exclude_pnn,
+		  TALLOC_CTX *mem_ctx, uint32_t **pnn_list);
+
+int list_of_active_nodes(struct ctdb_node_map *nodemap, uint32_t exclude_pnn,
+			 TALLOC_CTX *mem_ctx, uint32_t **pnn_list);
+
+int list_of_connected_nodes(struct ctdb_node_map *nodemap,
+			    uint32_t exclude_pnn,
+			    TALLOC_CTX *mem_ctx, uint32_t **pnn_list);
+
+int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       uint32_t destnode, struct timeval timeout,
+		       uint32_t set, uint32_t clear);
+
+bool ctdb_server_id_equal(struct ctdb_server_id *sid1,
+			  struct ctdb_server_id *sid2);
+
+int ctdb_server_id_exists(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  struct ctdb_server_id *sid, bool *exists);
+
+#endif /* __CTDB_CLIENT_H__ */
diff --git a/ctdb/client/client_call.c b/ctdb/client/client_call.c
new file mode 100644
index 0000000..aa8a05b
--- /dev/null
+++ b/ctdb/client/client_call.c
@@ -0,0 +1,177 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/tevent_unix.h"
+
+#include "common/reqid.h"
+#include "common/srvid.h"
+#include "common/comm.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+
+#include "client/client_private.h"
+#include "client/client.h"
+
+
+/*
+ * Handle REQ_CALL and REPLY_CALL
+ */
+
+struct ctdb_client_call_state {
+	struct ctdb_client_context *client;
+	uint32_t reqid;
+	struct ctdb_reply_call *reply;
+	struct tevent_req *req;
+};
+
+static int ctdb_client_call_state_destructor(
+	struct ctdb_client_call_state *state);
+static void ctdb_client_call_done(struct tevent_req *subreq);
+
+struct tevent_req *ctdb_client_call_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct ctdb_client_context *client,
+					 struct ctdb_req_call *request)
+{
+	struct ctdb_req_header h;
+	struct tevent_req *req, *subreq;
+	struct ctdb_client_call_state *state;
+	uint32_t reqid;
+	uint8_t *buf;
+	size_t buflen;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_client_call_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	reqid = reqid_new(client->idr, state);
+	if (reqid == REQID_INVALID) {
+		talloc_free(req);
+		return NULL;
+	}
+
+	state->client = client;
+	state->reqid = reqid;
+	state->req = req;
+	state->reply = talloc_zero(state, struct ctdb_reply_call);
+	if (tevent_req_nomem(state->reply, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	talloc_set_destructor(state, ctdb_client_call_state_destructor);
+
+	ctdb_req_header_fill(&h, 0, CTDB_REQ_CALL, CTDB_CURRENT_NODE,
+			     client->pnn, reqid);
+
+	ret = ctdb_req_call_push(&h, request, state, &buf, &buflen);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return tevent_req_post(req, ev);
+	}
+
+	subreq = comm_write_send(state, ev, client->comm, buf, buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_client_call_done, req);
+
+	return req;
+}
+
+static int ctdb_client_call_state_destructor(
+	struct ctdb_client_call_state *state)
+{
+	reqid_remove(state->client->idr, state->reqid);
+	return 0;
+}
+
+static void ctdb_client_call_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	bool status;
+	int ret;
+
+	status = comm_write_recv(subreq, &ret);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	/* wait for the reply */
+}
+
+void ctdb_client_reply_call(struct ctdb_client_context *client,
+			    uint8_t *buf, size_t buflen, uint32_t reqid)
+{
+	struct ctdb_req_header h;
+	struct ctdb_client_call_state *state;
+	int ret;
+
+	state = reqid_find(client->idr, reqid, struct ctdb_client_call_state);
+	if (state == NULL) {
+		return;
+	}
+
+	if (reqid != state->reqid) {
+		return;
+	}
+
+	ret = ctdb_reply_call_pull(buf, buflen, &h, state, state->reply);
+	if (ret != 0) {
+		tevent_req_error(state->req, ret);
+		return;
+	}
+
+	tevent_req_done(state->req);
+}
+
+bool ctdb_client_call_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+			   struct ctdb_reply_call **reply, int *perr)
+{
+	struct ctdb_client_call_state *state = tevent_req_data(
+		req, struct ctdb_client_call_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	if (reply != NULL) {
+		*reply = talloc_steal(mem_ctx, state->reply);
+	}
+
+	return true;
+}
diff --git a/ctdb/client/client_connect.c b/ctdb/client/client_connect.c
new file mode 100644
index 0000000..d433f7d
--- /dev/null
+++ b/ctdb/client/client_connect.c
@@ -0,0 +1,338 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "common/reqid.h"
+#include "common/srvid.h"
+#include "common/comm.h"
+#include "common/logging.h"
+
+#include "lib/util/tevent_unix.h"
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+
+#include "client/client_private.h"
+#include "client/client.h"
+
+static int ctdb_client_connect(struct ctdb_client_context *client,
+			       struct tevent_context *ev,
+			       const char *sockpath);
+
+static int ctdb_client_context_destructor(struct ctdb_client_context *client);
+
+int ctdb_client_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		     const char *sockpath, struct ctdb_client_context **out)
+{
+	struct ctdb_client_context *client;
+	int ret;
+
+	client = talloc_zero(mem_ctx, struct ctdb_client_context);
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " memory allocation error\n"));
+		return ENOMEM;
+	}
+
+	ret = reqid_init(client, INT_MAX-200, &client->idr);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("reqid_init() failed, ret=%d\n", ret));
+		talloc_free(client);
+		return ret;
+	}
+
+	ret = srvid_init(client, &client->srv);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("srvid_init() failed, ret=%d\n", ret));
+		talloc_free(client);
+		return ret;
+	}
+
+	client->fd = -1;
+	client->pnn = CTDB_UNKNOWN_PNN;
+
+	ret = ctdb_client_connect(client, ev, sockpath);
+	if (ret != 0) {
+		talloc_free(client);
+		return ret;
+	}
+
+	talloc_set_destructor(client, ctdb_client_context_destructor);
+
+	*out = client;
+	return 0;
+}
+
+static int ctdb_client_context_destructor(struct ctdb_client_context *client)
+{
+	if (client->fd != -1) {
+		close(client->fd);
+		client->fd = -1;
+	}
+	return 0;
+}
+
+static void client_read_handler(uint8_t *buf, size_t buflen,
+				void *private_data);
+static void client_dead_handler(void *private_data);
+
+static int ctdb_client_connect(struct ctdb_client_context *client,
+			       struct tevent_context *ev, const char *sockpath)
+{
+	struct sockaddr_un addr;
+	size_t len;
+	int fd, ret;
+
+	if (sockpath == NULL) {
+		DEBUG(DEBUG_ERR, ("socket path cannot be NULL\n"));
+		return EINVAL;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
+	if (len != strlen(sockpath)) {
+		DEBUG(DEBUG_ERR, ("socket path too long, len=%zu\n",
+				  strlen(sockpath)));
+		return ENAMETOOLONG;
+	}
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd == -1) {
+		ret = errno;
+		DEBUG(DEBUG_ERR, ("socket() failed, errno=%d\n", ret));
+		return ret;
+	}
+
+	ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret == -1) {
+		ret = errno;
+		DEBUG(DEBUG_ERR, ("connect() failed, errno=%d\n", ret));
+		close(fd);
+		return ret;
+	}
+	client->fd = fd;
+
+	ret = comm_setup(client, ev, fd, client_read_handler, client,
+			 client_dead_handler, client, &client->comm);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("comm_setup() failed, ret=%d\n", ret));
+		close(fd);
+		client->fd = -1;
+		return ret;
+	}
+
+	ret = ctdb_ctrl_get_pnn(client, ev, client, CTDB_CURRENT_NODE,
+				tevent_timeval_zero(), &client->pnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("failed to get current node pnn\n"));
+		close(fd);
+		client->fd = -1;
+		TALLOC_FREE(client->comm);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void client_read_handler(uint8_t *buf, size_t buflen,
+				void *private_data)
+{
+	struct ctdb_client_context *client = talloc_get_type_abort(
+		private_data, struct ctdb_client_context);
+	struct ctdb_req_header hdr;
+	int ret;
+
+	ret = ctdb_req_header_pull(discard_const(buf), buflen, &hdr);
+	if (ret != 0) {
+		DEBUG(DEBUG_WARNING, ("invalid header, ret=%d\n", ret));
+		return;
+	}
+
+	if (buflen != hdr.length) {
+		DEBUG(DEBUG_WARNING, ("packet size mismatch %zu != %d\n",
+				      buflen, hdr.length));
+		return;
+	}
+
+	ret = ctdb_req_header_verify(&hdr, 0);
+	if (ret != 0) {
+		DEBUG(DEBUG_WARNING, ("invalid header, ret=%d\n", ret));
+		return;
+	}
+
+	switch (hdr.operation) {
+	case CTDB_REPLY_CALL:
+		ctdb_client_reply_call(client, buf, buflen, hdr.reqid);
+		break;
+
+	case CTDB_REQ_MESSAGE:
+		ctdb_client_req_message(client, buf, buflen, hdr.reqid);
+		break;
+
+	case CTDB_REPLY_CONTROL:
+		ctdb_client_reply_control(client, buf, buflen, hdr.reqid);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void client_dead_handler(void *private_data)
+{
+	struct ctdb_client_context *client = talloc_get_type_abort(
+		private_data, struct ctdb_client_context);
+	ctdb_client_callback_func_t callback = client->callback;
+	void *callback_data = client->private_data;
+
+	talloc_free(client);
+	if (callback != NULL) {
+		callback(callback_data);
+		return;
+	}
+
+	DEBUG(DEBUG_NOTICE, ("connection to daemon closed, exiting\n"));
+	exit(1);
+}
+
+void ctdb_client_set_disconnect_callback(struct ctdb_client_context *client,
+					 ctdb_client_callback_func_t callback,
+					 void *private_data)
+{
+	client->callback = callback;
+	client->private_data = private_data;
+}
+
+uint32_t ctdb_client_pnn(struct ctdb_client_context *client)
+{
+	return client->pnn;
+}
+
+void ctdb_client_wait(struct tevent_context *ev, bool *done)
+{
+	while (! (*done)) {
+		tevent_loop_once(ev);
+	}
+}
+
+struct ctdb_recovery_wait_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+};
+
+static void ctdb_recovery_wait_retry(struct tevent_req *subreq);
+
+struct tevent_req *ctdb_recovery_wait_send(TALLOC_CTX *mem_ctx,
+					   struct tevent_context *ev,
+					   struct ctdb_client_context *client)
+{
+	struct tevent_req *req, *subreq;
+	struct ctdb_recovery_wait_state *state;
+	int recmode;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_recovery_wait_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->client = client;
+
+	ret = ctdb_ctrl_get_recmode(client, ev, client, client->pnn,
+				    tevent_timeval_zero(), &recmode);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return tevent_req_post(req, ev);
+	}
+
+	if (recmode == CTDB_RECOVERY_NORMAL) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	subreq = tevent_wakeup_send(state, ev,
+				    tevent_timeval_current_ofs(1, 0));
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_recovery_wait_retry, req);
+
+	return req;
+}
+
+static void ctdb_recovery_wait_retry(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_recovery_wait_state *state = tevent_req_data(
+		req, struct ctdb_recovery_wait_state);
+	int ret, recmode;
+	bool status;
+
+	status = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ENOMEM);
+		return;
+	}
+
+	ret = ctdb_ctrl_get_recmode(state, state->ev, state->client,
+				    ctdb_client_pnn(state->client),
+				    tevent_timeval_zero(), &recmode);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	if (recmode == CTDB_RECOVERY_NORMAL) {
+		tevent_req_done(req);
+		return;
+	}
+
+	subreq = tevent_wakeup_send(state, state->ev,
+				    tevent_timeval_current_ofs(1, 0));
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, ctdb_recovery_wait_retry, req);
+}
+
+bool ctdb_recovery_wait_recv(struct tevent_req *req, int *perr)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	return true;
+}
diff --git a/ctdb/client/client_control.c b/ctdb/client/client_control.c
new file mode 100644
index 0000000..b25ff40
--- /dev/null
+++ b/ctdb/client/client_control.c
@@ -0,0 +1,429 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/tevent_unix.h"
+
+#include "common/reqid.h"
+#include "common/srvid.h"
+#include "common/comm.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+
+#include "client/client_private.h"
+#include "client/client.h"
+
+
+/*
+ * Handle REQ_CONTROL and REPLY_CONTROL
+ */
+
+struct ctdb_client_control_state {
+	struct ctdb_client_context *client;
+	uint32_t opcode;
+	uint32_t flags;
+	uint32_t reqid;
+	struct ctdb_reply_control *reply;
+	struct tevent_req *req;
+};
+
+static int ctdb_client_control_state_destructor(
+	struct ctdb_client_control_state *state);
+static void ctdb_client_control_done(struct tevent_req *subreq);
+
+struct tevent_req *ctdb_client_control_send(TALLOC_CTX *mem_ctx,
+					    struct tevent_context *ev,
+					    struct ctdb_client_context *client,
+					    uint32_t destnode,
+					    struct timeval timeout,
+					    struct ctdb_req_control *request)
+{
+	struct ctdb_req_header h;
+	struct tevent_req *req, *subreq;
+	struct ctdb_client_control_state *state;
+	uint32_t reqid;
+	uint8_t *buf;
+	size_t buflen;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_client_control_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	reqid = reqid_new(client->idr, state);
+	if (reqid == REQID_INVALID) {
+		talloc_free(req);
+		return NULL;
+	}
+
+	state->client = client;
+	state->flags = request->flags;
+	state->opcode = request->opcode;
+	state->reqid = reqid;
+	state->req = req;
+	state->reply = talloc_zero(state, struct ctdb_reply_control);
+	if (tevent_req_nomem(state->reply, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	talloc_set_destructor(state, ctdb_client_control_state_destructor);
+
+	ctdb_req_header_fill(&h, 0, CTDB_REQ_CONTROL, destnode,
+			     client->pnn, reqid);
+
+	ret = ctdb_req_control_push(&h, request, state, &buf, &buflen);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return tevent_req_post(req, ev);
+	}
+
+	if (!tevent_timeval_is_zero(&timeout)) {
+		tevent_req_set_endtime(req, ev, timeout);
+	}
+
+	subreq = comm_write_send(state, ev, client->comm, buf, buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_client_control_done, req);
+
+	return req;
+}
+
+static int ctdb_client_control_state_destructor(
+	struct ctdb_client_control_state *state)
+{
+	reqid_remove(state->client->idr, state->reqid);
+	return 0;
+}
+
+static void ctdb_client_control_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_client_control_state *state = tevent_req_data(
+		req, struct ctdb_client_control_state);
+	bool status;
+	int ret;
+
+	status = comm_write_recv(subreq, &ret);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	/* Daemon will not reply, so we set status to 0 */
+	if (state->flags & CTDB_CTRL_FLAG_NOREPLY) {
+		state->reply->status = 0;
+		tevent_req_done(req);
+	}
+
+	/* wait for the reply or timeout */
+}
+
+void ctdb_client_reply_control(struct ctdb_client_context *client,
+			       uint8_t *buf, size_t buflen, uint32_t reqid)
+{
+	struct ctdb_req_header h;
+	struct ctdb_client_control_state *state;
+	int ret;
+
+	state = reqid_find(client->idr, reqid,
+			   struct ctdb_client_control_state);
+	if (state == NULL) {
+		return;
+	}
+
+	if (reqid != state->reqid) {
+		return;
+	}
+
+	ret = ctdb_reply_control_pull(buf, buflen, state->opcode, &h,
+				      state->reply, state->reply);
+	if (ret != 0) {
+		tevent_req_error(state->req, ret);
+		return;
+	}
+
+	tevent_req_done(state->req);
+}
+
+bool ctdb_client_control_recv(struct tevent_req *req, int *perr,
+			      TALLOC_CTX *mem_ctx,
+			      struct ctdb_reply_control **reply)
+{
+	struct ctdb_client_control_state *state = tevent_req_data(
+		req, struct ctdb_client_control_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	if (reply != NULL) {
+		*reply = talloc_steal(mem_ctx, state->reply);
+	}
+
+	return true;
+}
+
+/*
+ * Handle multiple nodes - there cannot be any return data
+ */
+
+struct ctdb_client_control_multi_state {
+	uint32_t *pnn_list;
+	int count;
+	int done;
+	int err;
+	int *err_list;
+	struct ctdb_reply_control **reply;
+};
+
+struct control_index_state {
+	struct tevent_req *req;
+	int index;
+};
+
+static void ctdb_client_control_multi_done(struct tevent_req *subreq);
+
+struct tevent_req *ctdb_client_control_multi_send(
+				TALLOC_CTX *mem_ctx,
+				struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				uint32_t *pnn_list, int count,
+				struct timeval timeout,
+				struct ctdb_req_control *request)
+{
+	struct tevent_req *req, *subreq;
+	struct ctdb_client_control_multi_state *state;
+	int i;
+
+	if (pnn_list == NULL || count == 0) {
+		return NULL;
+	}
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_client_control_multi_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->pnn_list = pnn_list;
+	state->count = count;
+	state->done = 0;
+	state->err = 0;
+	state->err_list = talloc_zero_array(state, int, count);
+	if (tevent_req_nomem(state->err_list, req)) {
+		return tevent_req_post(req, ev);
+	}
+	state->reply = talloc_zero_array(state, struct ctdb_reply_control *,
+					 count);
+	if (tevent_req_nomem(state->reply, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	for (i=0; i<count; i++) {
+		struct control_index_state *substate;
+
+		subreq = ctdb_client_control_send(state, ev, client,
+						  pnn_list[i], timeout,
+						  request);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+
+		substate = talloc(subreq, struct control_index_state);
+		if (tevent_req_nomem(substate, req)) {
+			return tevent_req_post(req, ev);
+		}
+
+		substate->req = req;
+		substate->index = i;
+
+		tevent_req_set_callback(subreq, ctdb_client_control_multi_done,
+					substate);
+	}
+
+	return req;
+}
+
+static void ctdb_client_control_multi_done(struct tevent_req *subreq)
+{
+	struct control_index_state *substate = tevent_req_callback_data(
+		subreq, struct control_index_state);
+	struct tevent_req *req = substate->req;
+	int idx = substate->index;
+	struct ctdb_client_control_multi_state *state = tevent_req_data(
+		req, struct ctdb_client_control_multi_state);
+	bool status;
+	int ret;
+
+	status = ctdb_client_control_recv(subreq, &ret, state->reply,
+					  &state->reply[idx]);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		if (state->err == 0) {
+			state->err = ret;
+			state->err_list[idx] = state->err;
+		}
+	} else {
+		if (state->reply[idx]->status != 0) {
+			if (state->err == 0) {
+				state->err = state->reply[idx]->status;
+				state->err_list[idx] = state->err;
+			}
+		}
+	}
+
+	state->done += 1;
+
+	if (state->done == state->count) {
+		tevent_req_done(req);
+	}
+}
+
+bool ctdb_client_control_multi_recv(struct tevent_req *req, int *perr,
+				    TALLOC_CTX *mem_ctx, int **perr_list,
+				    struct ctdb_reply_control ***preply)
+{
+	struct ctdb_client_control_multi_state *state = tevent_req_data(
+		req, struct ctdb_client_control_multi_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		if (perr_list != NULL) {
+			*perr_list = talloc_steal(mem_ctx, state->err_list);
+		}
+		return false;
+	}
+
+	if (perr != NULL) {
+		*perr = state->err;
+	}
+
+	if (perr_list != NULL) {
+		*perr_list = talloc_steal(mem_ctx, state->err_list);
+	}
+
+	if (preply != NULL) {
+		*preply = talloc_steal(mem_ctx, state->reply);
+	}
+
+	if (state->err != 0) {
+		return false;
+	}
+
+	return true;
+}
+
+int ctdb_client_control_multi_error(uint32_t *pnn_list, int count,
+				    int *err_list, uint32_t *pnn)
+{
+	int ret = 0, i;
+
+	for (i=0; i<count; i++) {
+		if (err_list[i] != 0) {
+			ret = err_list[i];
+			*pnn = pnn_list[i];
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Sync version of control send/recv
+ */
+
+int ctdb_client_control(TALLOC_CTX *mem_ctx,
+			struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			uint32_t destnode,
+			struct timeval timeout,
+			struct ctdb_req_control *request,
+			struct ctdb_reply_control **reply)
+{
+	struct tevent_req *req;
+	int ret;
+	bool status;
+
+	req = ctdb_client_control_send(mem_ctx, ev, client, destnode, timeout,
+				       request);
+	if (req == NULL) {
+		return ENOMEM;
+	}
+
+	tevent_req_poll(req, ev);
+
+	status = ctdb_client_control_recv(req, &ret, mem_ctx, reply);
+	if (! status) {
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_client_control_multi(TALLOC_CTX *mem_ctx,
+			      struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      uint32_t *pnn_list, int count,
+			      struct timeval timeout,
+			      struct ctdb_req_control *request,
+			      int **perr_list,
+			      struct ctdb_reply_control ***preply)
+{
+	struct tevent_req *req;
+	bool status;
+	int ret;
+
+	req = ctdb_client_control_multi_send(mem_ctx, ev, client,
+					     pnn_list, count,
+					     timeout, request);
+	if (req == NULL) {
+		return ENOMEM;
+	}
+
+	tevent_req_poll(req, ev);
+
+	status = ctdb_client_control_multi_recv(req, &ret, mem_ctx, perr_list,
+						preply);
+	if (! status) {
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/ctdb/client/client_control_sync.c b/ctdb/client/client_control_sync.c
new file mode 100644
index 0000000..de52b47
--- /dev/null
+++ b/ctdb/client/client_control_sync.c
@@ -0,0 +1,3119 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "common/logging.h"
+
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+#include "client/client_private.h"
+#include "client/client.h"
+
+int ctdb_ctrl_process_exists(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     pid_t pid, int *status)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_process_exists(&request, pid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control PROCESS_EXISTS failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_process_exists(reply, status);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control PROCESS_EXISTS failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_statistics(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 struct ctdb_statistics **stats)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_statistics(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control STATISTICS failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_statistics(reply, mem_ctx, stats);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control STATISTICS failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_ping(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		   struct ctdb_client_context *client,
+		   int destnode, struct timeval timeout,
+		   int *num_clients)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_ping(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control PING failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_ping(reply, num_clients);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control PING failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_getdbpath(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			uint32_t db_id,
+			const char **db_path)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_getdbpath(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GETDBPATH failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_getdbpath(reply, mem_ctx, db_path);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GETDBPATH failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_getvnnmap(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			struct ctdb_vnn_map **vnnmap)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_getvnnmap(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GETVNNMAP failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_getvnnmap(reply, mem_ctx, vnnmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GETVNNMAP failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_getdebug(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       int destnode, struct timeval timeout,
+		       uint32_t *loglevel)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_debug(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DEBUG failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_debug(reply, loglevel);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DEBUG failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_setdebug(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       int destnode, struct timeval timeout,
+		       uint32_t loglevel)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_debug(&request, loglevel);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_DEBUG failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_debug(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_DEBUG failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_dbmap(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			struct ctdb_dbid_map **dbmap)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_dbmap(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DBMAP failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_dbmap(reply, mem_ctx, dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DBMAP failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_pull_db(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client, int destnode,
+		      struct timeval timeout, struct ctdb_pulldb *pulldb,
+		      struct ctdb_rec_buffer **recbuf)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_pull_db(&request, pulldb);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control PULL_DB failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_pull_db(reply, mem_ctx, recbuf);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control PULL_DB failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_push_db(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client, int destnode,
+		      struct timeval timeout, struct ctdb_rec_buffer *recbuf)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_push_db(&request, recbuf);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control PUSH_DB failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_push_db(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control PUSH_DB failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+
+int ctdb_ctrl_get_recmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  int *recmode)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_recmode(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_RECMODE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_recmode(reply, recmode);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_RECMODE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_recmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  int recmode)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_recmode(&request, recmode);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_RECMODE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_recmode(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_RECMODE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_statistics_reset(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_statistics_reset(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control STATISTICS_RESET failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_statistics_reset(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control STATISTICS_RESET failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_attach(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			const char *db_name, uint32_t tdb_flags,
+			uint32_t *db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_attach(&request, db_name, tdb_flags);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_ATTACH failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_attach(reply, db_id);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_ATTACH failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_traverse_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     struct ctdb_traverse_start *traverse)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_traverse_start(&request, traverse);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRAVERSE_START failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_traverse_start(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRAVERSE_START failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_register_srvid(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     uint64_t srvid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_register_srvid(&request, srvid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control REGISTER_SRVID failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_register_srvid(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control REGISTER_SRVID failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_deregister_srvid(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       uint64_t srvid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_deregister_srvid(&request, srvid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DEREGISTER_SRVID failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_deregister_srvid(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DEREGISTER_SRVID failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_dbname(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 uint32_t db_id, const char **db_name)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_dbname(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DBNAME failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_dbname(reply, mem_ctx, db_name);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DBNAME failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_enable_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_enable_seqnum(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control ENABLE_SEQNUM failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_enable_seqnum(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control ENABLE_SEQNUM failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_update_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_update_seqnum(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control UPDATE_SEQNUM failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_update_seqnum(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control UPDATE_SEQNUM failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_dump_memory(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  const char **mem_str)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_dump_memory(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DUMP_MEMORY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_dump_memory(reply, mem_ctx, mem_str);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DUMP_MEMORY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_pid(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client,
+		      int destnode, struct timeval timeout,
+		      pid_t *pid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_pid(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_PID failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_pid(reply, pid);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_PID failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_recmaster(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t *recmaster)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_recmaster(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_RECMASTER failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_recmaster(reply, recmaster);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_RECMASTER failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_recmaster(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t recmaster)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_recmaster(&request, recmaster);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_RECMASTER failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_recmaster(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_RECMASTER failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_freeze(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		     struct ctdb_client_context *client,
+		     int destnode, struct timeval timeout,
+		     int priority)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_freeze(&request, priority);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control FREEZE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_freeze(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control FREEZE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_thaw(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		   struct ctdb_client_context *client,
+		   int destnode, struct timeval timeout,
+		   int priority)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_thaw(&request, priority);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control THAW failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_thaw(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control THAW failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_pnn(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client,
+		      int destnode, struct timeval timeout,
+		      uint32_t *pnn)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_pnn(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_PNN failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_pnn(reply, pnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_PNN failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_shutdown(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_shutdown(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SHUTDOWN failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_shutdown(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SHUTDOWN failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_monmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  int *mon_mode)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_monmode(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_MONMODE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_monmode(reply, mon_mode);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_MONMODE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_tcp_add(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client,
+		      int destnode, struct timeval timeout,
+		      struct ctdb_connection *conn)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_tcp_add(&request, conn);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TCP_ADD failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_tcp_add(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TCP_ADD failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_tcp_remove(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 struct ctdb_connection *conn)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_tcp_remove(&request, conn);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TCP_REMOVE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_tcp_remove(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TCP_REMOVE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_tunable(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  struct ctdb_tunable *tunable)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_tunable(&request, tunable);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_TUNABLE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_tunable(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_TUNABLE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_tunable(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  const char *var, uint32_t *value)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_tunable(&request, var);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_TUNABLE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_tunable(reply, value);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_TUNABLE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_list_tunables(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_var_list **var_list)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_list_tunables(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control LIST_TUNABLES failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_list_tunables(reply, mem_ctx, var_list);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control LIST_TUNABLES failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_modify_flags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   int destnode, struct timeval timeout,
+			   uint32_t pnn, uint32_t old_flags,
+			   uint32_t new_flags)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	struct ctdb_node_flag_change flag_change;
+	int ret;
+
+	flag_change.pnn = pnn;
+	flag_change.old_flags = old_flags;
+	flag_change.new_flags = new_flags;
+
+	ctdb_req_control_modify_flags(&request, &flag_change);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control MODIFY_FLAGS failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_modify_flags(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control MODIFY_FLAGS failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_all_tunables(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       struct ctdb_tunable_list **tun_list)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_all_tunables(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_ALL_TUNABLES failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_all_tunables(reply, mem_ctx, tun_list);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_ALL_TUNABLES failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_kill_tcp(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       int destnode, struct timeval timeout,
+		       struct ctdb_connection *conn)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_kill_tcp(&request, conn);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control KILL_TCP failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_kill_tcp(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control KILL_TCP failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_tcp_tickle_list(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  struct ctdb_client_context *client,
+				  int destnode, struct timeval timeout,
+				  ctdb_sock_addr *addr,
+				  struct ctdb_tickle_list **tickles)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_tcp_tickle_list(&request, addr);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_TCP_TICKLE_LIST failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_tcp_tickle_list(reply, mem_ctx, tickles);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_TCP_TICKLE_LIST failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_tcp_tickle_list(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  struct ctdb_client_context *client,
+				  int destnode, struct timeval timeout,
+				  struct ctdb_tickle_list *tickles)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_tcp_tickle_list(&request, tickles);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_TCP_TICKLE_LIST failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_tcp_tickle_list(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_TCP_TICKLE_LIST failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_register_server_id(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 struct ctdb_client_id *cid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_register_server_id(&request, cid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control REGISTER_SERVER_ID failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_register_server_id(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control REGISTER_SERVER_ID failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_unregister_server_id(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct ctdb_client_context *client,
+				   int destnode, struct timeval timeout,
+				   struct ctdb_client_id *cid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_unregister_server_id(&request, cid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control UNREGISTER_SERVER_ID failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_unregister_server_id(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control UNREGISTER_SERVER_ID failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_check_server_id(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      struct ctdb_client_id *cid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_check_server_id(&request, cid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control CHECK_SERVER_ID failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_check_server_id(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control CHECK_SERVER_ID failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_server_id_list(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 struct ctdb_client_id_map **cid_map)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_server_id_list(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_SERVER_ID_LIST failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_server_id_list(reply, mem_ctx, cid_map);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_SERVER_ID_LIST failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_attach_persistent(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct ctdb_client_context *client,
+				   int destnode, struct timeval timeout,
+				   const char *db_name, int tdb_flags,
+				   uint32_t *db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_attach_persistent(&request, db_name, tdb_flags);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_ATTACH_PERSISTENT failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_attach_persistent(reply, db_id);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_ATTACH_PERSISTENT failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_send_gratuitous_arp(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  struct ctdb_client_context *client,
+				  int destnode, struct timeval timeout,
+				  struct ctdb_addr_info *addr_info)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_send_gratuitous_arp(&request, addr_info);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SEND_GRATUITOUS_ARP failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_send_gratuitous_arp(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SEND_GRATUITOUS_ARP failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_transaction_start(TALLOC_CTX *mem_ctx,
+				struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout,
+				uint32_t tid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_transaction_start(&request, tid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRANSACTION_START failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_transaction_start(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRANSACTION_START failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_transaction_commit(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 uint32_t tid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_transaction_commit(&request, tid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRANSACTION_COMMIT failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_transaction_commit(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRANSACTION_COMMIT failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_wipe_database(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id, uint32_t tid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	struct ctdb_transdb transdb;
+	int ret;
+
+	transdb.db_id = db_id;
+	transdb.tid = tid;
+
+	ctdb_req_control_wipe_database(&request, &transdb);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control WIPE_DATABASE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_wipe_database(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control WIPE_DATABASE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_uptime(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		     struct ctdb_client_context *client,
+		     int destnode, struct timeval timeout,
+		     struct ctdb_uptime **uptime)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_uptime(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control UPTIME failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_uptime(reply, mem_ctx, uptime);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control UPTIME failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_start_recovery(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_start_recovery(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control START_RECOVERY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_start_recovery(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control START_RECOVERY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_end_recovery(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_end_recovery(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control END_RECOVERY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_end_recovery(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control END_RECOVERY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_reload_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_reload_nodes_file(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control RELOAD_NODES_FILE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_reload_nodes_file(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control RELOAD_NODES_FILE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_enable_monitor(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_enable_monitor(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control ENABLE_MONITOR failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_enable_monitor(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control ENABLE_MONITOR failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_disable_monitor(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_disable_monitor(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DISABLE_MONITOR failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_disable_monitor(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DISABLE_MONITOR failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_add_public_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_addr_info *addr_info)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_add_public_ip(&request, addr_info);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control ADD_PUBLIC_IP failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_add_public_ip(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control ADD_PUBLIC_IP failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_del_public_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_addr_info *addr_info)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_del_public_ip(&request, addr_info);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DEL_PUBLIC_IP failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_del_public_ip(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DEL_PUBLIC_IP failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_run_eventscripts(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       const char *event)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_run_eventscripts(&request, event);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control RUN_EVENTSCRIPTS failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_run_eventscripts(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control RUN_EVENTSCRIPTS failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_capabilities(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       uint32_t *caps)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_capabilities(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_CAPABILITIES failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_capabilities(reply, caps);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_CAPABILITIES failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_release_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 struct ctdb_public_ip *pubip)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_release_ip(&request, pubip);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control RELEASE_IP failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_release_ip(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control RELEASE_IP failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_takeover_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  struct ctdb_public_ip *pubip)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_takeover_ip(&request, pubip);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TAKEOVER_IP failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_takeover_ip(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TAKEOVER_IP failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_public_ips(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     struct ctdb_public_ip_list **pubip_list)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_public_ips(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_PUBLIC_IPS failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_public_ips(reply, mem_ctx, pubip_list);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_PUBLIC_IPS failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_nodemap(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct timeval timeout,
+			  struct ctdb_node_map **nodemap)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_nodemap(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_NODEMAP failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_nodemap(reply, mem_ctx, nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_NODEMAP failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_event_script_status(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      struct ctdb_client_context *client,
+				      int destnode, struct timeval timeout,
+				      enum ctdb_event event,
+				      struct ctdb_script_list **slist)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_event_script_status(&request, event);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_EVENT_SCRIPT_STATUS failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_event_script_status(reply, mem_ctx, slist);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_EVENT_SCRIPT_STATUS failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_traverse_kill(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_traverse_start *traverse)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_traverse_kill(&request, traverse);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRAVERSE_KILL failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_traverse_kill(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRAVERSE_KILL failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_reclock_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       const char **reclock_file)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_reclock_file(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_RECLOCK_FILE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_reclock_file(reply, mem_ctx, reclock_file);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_RECLOCK_FILE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_reclock_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       const char *reclock_file)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_reclock_file(&request, reclock_file);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_RECLOCK_FILE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_reclock_file(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_RECLOCK_FILE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_stop_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_stop_node(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control STOP_NODE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_stop_node(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control STOP_NODE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_continue_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_continue_node(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control CONTINUE_NODE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_continue_node(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control CONTINUE_NODE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_natgwstate(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     uint32_t natgw_role)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_natgwstate(&request, natgw_role);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_NATGWSTATE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_natgwstate(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_NATGWSTATE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_lmasterrole(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      uint32_t lmaster_role)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_lmasterrole(&request, lmaster_role);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_LMASTERROLE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_lmasterrole(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_LMASTERROLE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_recmasterrole(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout,
+				uint32_t recmaster_role)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_recmasterrole(&request, recmaster_role);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_RECMASTERROLE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_recmasterrole(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_RECMASTERROLE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_enable_script(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    const char *script)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_enable_script(&request, script);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control ENABLE_SCRIPT failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_enable_script(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control ENABLE_SCRIPT failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_disable_script(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     const char *script)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_disable_script(&request, script);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DISABLE_SCRIPT failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_disable_script(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DISABLE_SCRIPT failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_ban_state(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_ban_state *ban_state)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_ban_state(&request, ban_state);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_BAN_STATE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_ban_state(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_BAN_STATE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_ban_state(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_ban_state **ban_state)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_ban_state(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_BAN_STATE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_ban_state(reply, mem_ctx, ban_state);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_BAN_STATE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_db_priority(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      uint32_t db_id, int priority)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	struct ctdb_db_priority db_prio;
+	int ret;
+
+	db_prio.db_id = db_id;
+	db_prio.priority = priority;
+
+	ctdb_req_control_set_db_priority(&request, &db_prio);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_DB_PRIORITY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_db_priority(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_DB_PRIORITY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_db_priority(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      uint32_t db_id, uint32_t *priority)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_db_priority(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DB_PRIORITY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_db_priority(reply, priority);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DB_PRIORITY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_transaction_cancel(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 uint32_t tid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_transaction_cancel(&request, tid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRANSACTION_CANCEL failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_transaction_cancel(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRANSACTION_CANCEL failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_register_notify(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      struct ctdb_notify_data *notify)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_register_notify(&request, notify);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control REGISTER_NOTIFY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_register_notify(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control REGISTER_NOTIFY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_deregister_notify(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout,
+				uint64_t srvid)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_deregister_notify(&request, srvid);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DEREGISTER_NOTIFY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_deregister_notify(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DEREGISTER_NOTIFY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_trans3_commit(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    struct ctdb_rec_buffer *recbuf)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_trans3_commit(&request, recbuf);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRANS3_COMMIT failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_trans3_commit(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRANS3_COMMIT failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_db_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id, uint64_t *seqnum)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_db_seqnum(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DB_SEQNUM failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_db_seqnum(reply, seqnum);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DB_SEQNUM failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_set_healthy(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     uint32_t db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_set_healthy(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_SET_HEALTHY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_set_healthy(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_SET_HEALTHY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_get_health(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id, const char **reason)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_get_health(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_GET_HEALTH failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_get_health(reply, mem_ctx, reason);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_GET_HEALTH failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_public_ip_info(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 ctdb_sock_addr *addr,
+				 struct ctdb_public_ip_info **ipinfo)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_public_ip_info(&request, addr);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_PUBLIC_IP_INFO failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_public_ip_info(reply, mem_ctx, ipinfo);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_PUBLIC_IP_INFO failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_ifaces(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 struct ctdb_client_context *client,
+			 int destnode, struct timeval timeout,
+			 struct ctdb_iface_list **iface_list)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_ifaces(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_IFACES failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_ifaces(reply, mem_ctx, iface_list);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_IFACES failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_iface_link_state(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct ctdb_client_context *client,
+				   int destnode, struct timeval timeout,
+				   struct ctdb_iface *iface)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_iface_link_state(&request, iface);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_IFACE_LINK_STATE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_iface_link_state(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_IFACE_LINK_STATE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_tcp_add_delayed_update(TALLOC_CTX *mem_ctx,
+				     struct tevent_context *ev,
+				     struct ctdb_client_context *client,
+				     int destnode, struct timeval timeout,
+				     struct ctdb_connection *conn)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_tcp_add_delayed_update(&request, conn);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TCP_ADD_DELAYED_UPDATE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_tcp_add_delayed_update(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TCP_ADD_DELAYED_UDATE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_stat_history(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct ctdb_client_context *client,
+			       int destnode, struct timeval timeout,
+			       struct ctdb_statistics_list **stats_list)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_stat_history(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_STAT_HISTORY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_stat_history(reply, mem_ctx, stats_list);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_STAT_HISTORY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_schedule_for_deletion(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    int destnode, struct timeval timeout,
+				    struct ctdb_key_data *key)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_schedule_for_deletion(&request, key);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SCHEDULE_FOR_DELETION failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_schedule_for_deletion(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SCHEDULE_FOR_DELETION failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_db_readonly(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct timeval timeout,
+			      uint32_t db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_db_readonly(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_DB_READONY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_db_readonly(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_DB_READONY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_check_srvids(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   int destnode, struct timeval timeout,
+			   uint64_t *srvid, int count, uint8_t **result)
+{
+	struct ctdb_uint64_array srvid_list;
+	struct ctdb_uint8_array *u8_array;
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	srvid_list.num = count;
+	srvid_list.val = srvid;
+
+	ctdb_req_control_check_srvids(&request, &srvid_list);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control CHECK_SRVIDS failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_check_srvids(reply, &request, &u8_array);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control CHECK_SRVIDS failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	if (u8_array->num != count) {
+		DEBUG(DEBUG_ERR,
+		      ("Control CHECK_SRVIDS returned invalid data %d != %d\n",
+		       u8_array->num, count));
+		return ret;
+	}
+
+	*result = talloc_steal(mem_ctx, u8_array->val);
+	return 0;
+}
+
+int ctdb_ctrl_traverse_start_ext(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct ctdb_client_context *client,
+				 int destnode, struct timeval timeout,
+				 struct ctdb_traverse_start_ext *traverse)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_traverse_start_ext(&request, traverse);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRAVERSE_START_EXT failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_traverse_start_ext(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control TRAVERSE_START_EXT failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_db_statistics(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout,
+				uint32_t db_id,
+				struct ctdb_db_statistics **dbstats)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_db_statistics(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DB_STATISTICS failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_db_statistics(reply, mem_ctx, dbstats);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_DB_STATISTICS failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_db_sticky(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout,
+			    uint32_t db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_set_db_sticky(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_DB_STICKY failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_set_db_sticky(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control SET_DB_STICKY failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_reload_public_ips(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_reload_public_ips(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control RELOAD_PUBLIC_IPS failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_reload_public_ips(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control RELOAD_PUBLIC_IPS failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_ipreallocated(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			    struct ctdb_client_context *client,
+			    int destnode, struct timeval timeout)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_ipreallocated(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control IPREALLOCATED failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_ipreallocated(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control IPREALLOCATED failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_runstate(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   int destnode, struct timeval timeout,
+			   enum ctdb_runstate *runstate)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_runstate(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_RUNSTATE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_runstate(reply, runstate);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_RUNSTATE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_detach(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout,
+			uint32_t db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_detach(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_DETACH failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_detach(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_DETACH failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			     struct ctdb_client_context *client,
+			     int destnode, struct timeval timeout,
+			     struct ctdb_node_map **nodemap)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_get_nodes_file(&request);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_NODES_FILE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_get_nodes_file(reply, mem_ctx, nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control GET_NODES_FILE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_freeze(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			int destnode, struct timeval timeout, uint32_t db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_freeze(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_FREEZE failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_freeze(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_FREEZE failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_thaw(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		      struct ctdb_client_context *client,
+		      int destnode, struct timeval timeout, uint32_t db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_thaw(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_THAW failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_thaw(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_THAW failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_transaction_start(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct ctdb_client_context *client,
+				   int destnode, struct timeval timeout,
+				   struct ctdb_transdb *transdb)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_transaction_start(&request, transdb);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_TRANSACTION_START failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_transaction_start(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_TRANSACTION_START failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_transaction_commit(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    int destnode, struct timeval timeout,
+				    struct ctdb_transdb *transdb)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_transaction_commit(&request, transdb);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_TRANSACTION_COMMIT failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_transaction_commit(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_TRANSACTION_COMMIT failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_db_transaction_cancel(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    int destnode, struct timeval timeout,
+				    uint32_t db_id)
+{
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	int ret;
+
+	ctdb_req_control_db_transaction_cancel(&request, db_id);
+	ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout,
+				  &request, &reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_TRANSACTION_CANCEL failed to node %u, ret=%d\n",
+		       destnode, ret));
+		return ret;
+	}
+
+	ret = ctdb_reply_control_db_transaction_cancel(reply);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Control DB_TRANSACTION_CANCEL failed, ret=%d\n", ret));
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/ctdb/client/client_db.c b/ctdb/client/client_db.c
new file mode 100644
index 0000000..287efd6
--- /dev/null
+++ b/ctdb/client/client_db.c
@@ -0,0 +1,2133 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "common/logging.h"
+
+#include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+#include "client/client_private.h"
+#include "client/client.h"
+
+static struct ctdb_db_context *client_db_handle(
+					struct ctdb_client_context *client,
+					const char *db_name)
+{
+	struct ctdb_db_context *db;
+
+	for (db = client->db; db != NULL; db = db->next) {
+		if (strcmp(db_name, db->db_name) == 0) {
+			return db;
+		}
+	}
+
+	return NULL;
+}
+
+struct ctdb_set_db_flags_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	struct timeval timeout;
+	uint32_t db_id;
+	uint8_t db_flags;
+	bool readonly_done, sticky_done;
+	uint32_t *pnn_list;
+	int count;
+};
+
+static void ctdb_set_db_flags_nodemap_done(struct tevent_req *subreq);
+static void ctdb_set_db_flags_readonly_done(struct tevent_req *subreq);
+static void ctdb_set_db_flags_sticky_done(struct tevent_req *subreq);
+
+static struct tevent_req *ctdb_set_db_flags_send(
+				TALLOC_CTX *mem_ctx,
+				struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				uint32_t destnode, struct timeval timeout,
+				uint32_t db_id, uint8_t db_flags)
+{
+	struct tevent_req *req, *subreq;
+	struct ctdb_set_db_flags_state *state;
+	struct ctdb_req_control request;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_set_db_flags_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	if (! (db_flags & (CTDB_DB_FLAGS_READONLY | CTDB_DB_FLAGS_STICKY))) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	state->ev = ev;
+	state->client = client;
+	state->timeout = timeout;
+	state->db_id = db_id;
+	state->db_flags = db_flags;
+
+	ctdb_req_control_get_nodemap(&request);
+	subreq = ctdb_client_control_send(state, ev, client, destnode, timeout,
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_set_db_flags_nodemap_done, req);
+
+	return req;
+}
+
+static void ctdb_set_db_flags_nodemap_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_set_db_flags_state *state = tevent_req_data(
+		req, struct ctdb_set_db_flags_state);
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	struct ctdb_node_map *nodemap;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_get_nodemap(reply, state, &nodemap);
+	talloc_free(reply);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	state->count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
+					       state, &state->pnn_list);
+	talloc_free(nodemap);
+	if (state->count <= 0) {
+		tevent_req_error(req, ENOMEM);
+		return;
+	}
+
+	if (state->db_flags & CTDB_DB_FLAGS_READONLY) {
+		ctdb_req_control_set_db_readonly(&request, state->db_id);
+		subreq = ctdb_client_control_multi_send(
+					state, state->ev, state->client,
+					state->pnn_list, state->count,
+					state->timeout, &request);
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		tevent_req_set_callback(subreq,
+					ctdb_set_db_flags_readonly_done, req);
+	} else {
+		state->readonly_done = true;
+	}
+
+	if (state->db_flags & CTDB_DB_FLAGS_STICKY) {
+		ctdb_req_control_set_db_sticky(&request, state->db_id);
+		subreq = ctdb_client_control_multi_send(
+					state, state->ev, state->client,
+					state->pnn_list, state->count,
+					state->timeout, &request);
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		tevent_req_set_callback(subreq, ctdb_set_db_flags_sticky_done,
+					req);
+	} else {
+		state->sticky_done = true;
+	}
+}
+
+static void ctdb_set_db_flags_readonly_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_set_db_flags_state *state = tevent_req_data(
+		req, struct ctdb_set_db_flags_state);
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, NULL,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	state->readonly_done = true;
+
+	if (state->readonly_done && state->sticky_done) {
+		tevent_req_done(req);
+	}
+}
+
+static void ctdb_set_db_flags_sticky_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_set_db_flags_state *state = tevent_req_data(
+		req, struct ctdb_set_db_flags_state);
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, NULL,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	state->sticky_done = true;
+
+	if (state->readonly_done && state->sticky_done) {
+		tevent_req_done(req);
+	}
+}
+
+static bool ctdb_set_db_flags_recv(struct tevent_req *req, int *perr)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+	return true;
+}
+
+struct ctdb_attach_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	struct timeval timeout;
+	uint32_t destnode;
+	uint8_t db_flags;
+	uint32_t tdb_flags;
+	struct ctdb_db_context *db;
+};
+
+static void ctdb_attach_mutex_done(struct tevent_req *subreq);
+static void ctdb_attach_dbid_done(struct tevent_req *subreq);
+static void ctdb_attach_dbpath_done(struct tevent_req *subreq);
+static void ctdb_attach_health_done(struct tevent_req *subreq);
+static void ctdb_attach_flags_done(struct tevent_req *subreq);
+
+struct tevent_req *ctdb_attach_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    struct timeval timeout,
+				    const char *db_name, uint8_t db_flags)
+{
+	struct tevent_req *req, *subreq;
+	struct ctdb_attach_state *state;
+	struct ctdb_req_control request;
+
+	req = tevent_req_create(mem_ctx, &state, struct ctdb_attach_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->db = client_db_handle(client, db_name);
+	if (state->db != NULL) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	state->ev = ev;
+	state->client = client;
+	state->timeout = timeout;
+	state->destnode = ctdb_client_pnn(client);
+	state->db_flags = db_flags;
+
+	state->db = talloc_zero(client, struct ctdb_db_context);
+	if (tevent_req_nomem(state->db, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	state->db->db_name = talloc_strdup(state->db, db_name);
+	if (tevent_req_nomem(state->db, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
+		state->db->persistent = true;
+	}
+
+	ctdb_req_control_get_tunable(&request, "TDBMutexEnabled");
+	subreq = ctdb_client_control_send(state, ev, client,
+					  ctdb_client_pnn(client), timeout,
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_attach_mutex_done, req);
+
+	return req;
+}
+
+static void ctdb_attach_mutex_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_attach_state *state = tevent_req_data(
+		req, struct ctdb_attach_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_req_control request;
+	uint32_t mutex_enabled;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_get_tunable(reply, &mutex_enabled);
+	if (ret != 0) {
+		/* Treat error as mutex support not available */
+		mutex_enabled = 0;
+	}
+
+	state->tdb_flags = TDB_DEFAULT;
+	if (! state->db->persistent) {
+		state->tdb_flags |= (TDB_INCOMPATIBLE_HASH |
+				     TDB_CLEAR_IF_FIRST);
+	}
+	if (mutex_enabled == 1) {
+		state->tdb_flags |= TDB_MUTEX_LOCKING;
+	}
+
+	if (state->db->persistent) {
+		ctdb_req_control_db_attach_persistent(&request,
+						      state->db->db_name,
+						      state->tdb_flags);
+	} else {
+		ctdb_req_control_db_attach(&request, state->db->db_name,
+					   state->tdb_flags);
+	}
+
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->destnode, state->timeout,
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, ctdb_attach_dbid_done, req);
+}
+
+static void ctdb_attach_dbid_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_attach_state *state = tevent_req_data(
+		req, struct ctdb_attach_state);
+	struct ctdb_req_control request;
+	struct ctdb_reply_control *reply;
+	bool status;
+	int ret;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	if (state->db->persistent) {
+		ret = ctdb_reply_control_db_attach_persistent(
+				reply, &state->db->db_id);
+	} else {
+		ret = ctdb_reply_control_db_attach(reply, &state->db->db_id);
+	}
+	talloc_free(reply);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_req_control_getdbpath(&request, state->db->db_id);
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->destnode, state->timeout,
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, ctdb_attach_dbpath_done, req);
+}
+
+static void ctdb_attach_dbpath_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_attach_state *state = tevent_req_data(
+		req, struct ctdb_attach_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_req_control request;
+	bool status;
+	int ret;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_getdbpath(reply, state->db,
+					   &state->db->db_path);
+	talloc_free(reply);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_req_control_db_get_health(&request, state->db->db_id);
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->destnode, state->timeout,
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, ctdb_attach_health_done, req);
+}
+
+static void ctdb_attach_health_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_attach_state *state = tevent_req_data(
+		req, struct ctdb_attach_state);
+	struct ctdb_reply_control *reply;
+	const char *reason;
+	bool status;
+	int ret;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_db_get_health(reply, state, &reason);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	if (reason != NULL) {
+		/* Database unhealthy, avoid attach */
+		/* FIXME: Log here */
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	subreq = ctdb_set_db_flags_send(state, state->ev, state->client,
+					state->destnode, state->timeout,
+					state->db->db_id, state->db_flags);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, ctdb_attach_flags_done, req);
+}
+
+static void ctdb_attach_flags_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_attach_state *state = tevent_req_data(
+		req, struct ctdb_attach_state);
+	bool status;
+	int ret;
+
+	status = ctdb_set_db_flags_recv(subreq, &ret);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	state->db->ltdb = tdb_wrap_open(state->db, state->db->db_path, 0,
+					state->tdb_flags, O_RDWR, 0);
+	if (tevent_req_nomem(state->db->ltdb, req)) {
+		return;
+	}
+	DLIST_ADD(state->client->db, state->db);
+
+	tevent_req_done(req);
+}
+
+bool ctdb_attach_recv(struct tevent_req *req, int *perr,
+		      struct ctdb_db_context **out)
+{
+	struct ctdb_attach_state *state = tevent_req_data(
+		req, struct ctdb_attach_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	if (out != NULL) {
+		*out = state->db;
+	}
+	return true;
+}
+
+int ctdb_attach(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		struct ctdb_client_context *client,
+		struct timeval timeout,
+		const char *db_name, uint8_t db_flags,
+		struct ctdb_db_context **out)
+{
+	struct tevent_req *req;
+	bool status;
+	int ret;
+
+	req = ctdb_attach_send(mem_ctx, ev, client, timeout,
+			       db_name, db_flags);
+	if (req == NULL) {
+		return ENOMEM;
+	}
+
+	tevent_req_poll(req, ev);
+
+	status = ctdb_attach_recv(req, &ret, out);
+	if (! status) {
+		return ret;
+	}
+
+	/*
+	ctdb_set_call(db, CTDB_NULL_FUNC, ctdb_null_func);
+	ctdb_set_call(db, CTDB_FETCH_FUNC, ctdb_fetch_func);
+	ctdb_set_call(db, CTDB_FETCH_WITH_HEADER_FUNC, ctdb_fetch_with_header_func);
+	*/
+
+	return 0;
+}
+
+int ctdb_detach(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		struct ctdb_client_context *client,
+		struct timeval timeout, uint32_t db_id)
+{
+	struct ctdb_db_context *db;
+	int ret;
+
+	ret = ctdb_ctrl_db_detach(mem_ctx, ev, client, client->pnn, timeout,
+				  db_id);
+	if (ret != 0) {
+		return ret;
+	}
+
+	for (db = client->db; db != NULL; db = db->next) {
+		if (db->db_id == db_id) {
+			DLIST_REMOVE(client->db, db);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+uint32_t ctdb_db_id(struct ctdb_db_context *db)
+{
+	return db->db_id;
+}
+
+struct ctdb_db_traverse_state {
+	ctdb_rec_parser_func_t parser;
+	void *private_data;
+	bool extract_header;
+	int error;
+};
+
+static int ctdb_db_traverse_handler(struct tdb_context *tdb, TDB_DATA key,
+				    TDB_DATA data, void *private_data)
+{
+	struct ctdb_db_traverse_state *state =
+		(struct ctdb_db_traverse_state *)private_data;
+	int ret;
+
+	if (state->extract_header) {
+		struct ctdb_ltdb_header header;
+
+		ret = ctdb_ltdb_header_extract(&data, &header);
+		if (ret != 0) {
+			state->error = ret;
+			return 1;
+		}
+
+		ret = state->parser(0, &header, key, data, state->private_data);
+	} else {
+		ret = state->parser(0, NULL, key, data, state->private_data);
+	}
+
+	if (ret != 0) {
+		state->error = ret;
+		return 1;
+	}
+
+	return 0;
+}
+
+int ctdb_db_traverse(struct ctdb_db_context *db, bool readonly,
+		     bool extract_header,
+		     ctdb_rec_parser_func_t parser, void *private_data)
+{
+	struct ctdb_db_traverse_state state;
+	int ret;
+
+	state.parser = parser;
+	state.private_data = private_data;
+	state.extract_header = extract_header;
+	state.error = 0;
+
+	if (readonly) {
+		ret = tdb_traverse_read(db->ltdb->tdb,
+					ctdb_db_traverse_handler, &state);
+	} else {
+		ret = tdb_traverse(db->ltdb->tdb,
+				   ctdb_db_traverse_handler, &state);
+	}
+
+	if (ret == -1) {
+		return EIO;
+	}
+
+	return state.error;
+}
+
+static int ctdb_ltdb_fetch(struct ctdb_db_context *db, TDB_DATA key,
+			   struct ctdb_ltdb_header *header,
+			   TALLOC_CTX *mem_ctx, TDB_DATA *data)
+{
+	TDB_DATA rec;
+	int ret;
+
+	rec = tdb_fetch(db->ltdb->tdb, key);
+	if (rec.dsize < sizeof(struct ctdb_ltdb_header)) {
+		/* No record present */
+		if (rec.dptr != NULL) {
+			free(rec.dptr);
+		}
+
+		if (tdb_error(db->ltdb->tdb) != TDB_ERR_NOEXIST) {
+			return EIO;
+		}
+
+		header->rsn = 0;
+		header->dmaster = CTDB_UNKNOWN_PNN;
+		header->flags = 0;
+
+		if (data != NULL) {
+			*data = tdb_null;
+		}
+		return 0;
+	}
+
+	ret = ctdb_ltdb_header_pull(rec.dptr, rec.dsize, header);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = 0;
+	if (data != NULL) {
+		size_t offset = ctdb_ltdb_header_len(header);
+
+		data->dsize = rec.dsize - offset;
+		data->dptr = talloc_memdup(mem_ctx, rec.dptr + offset,
+					   data->dsize);
+		if (data->dptr == NULL) {
+			ret = ENOMEM;
+		}
+	}
+
+	free(rec.dptr);
+	return ret;
+}
+
+/*
+ * Fetch a record from volatile database
+ *
+ * Steps:
+ *  1. Get a lock on the hash chain
+ *  2. If the record does not exist, migrate the record
+ *  3. If readonly=true and delegations do not exist, migrate the record.
+ *  4. If readonly=false and delegations exist, migrate the record.
+ *  5. If the local node is not dmaster, migrate the record.
+ *  6. Return record
+ */
+
+struct ctdb_fetch_lock_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	struct ctdb_record_handle *h;
+	bool readonly;
+	uint32_t pnn;
+};
+
+static int ctdb_fetch_lock_check(struct tevent_req *req);
+static void ctdb_fetch_lock_migrate(struct tevent_req *req);
+static void ctdb_fetch_lock_migrate_done(struct tevent_req *subreq);
+
+struct tevent_req *ctdb_fetch_lock_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct ctdb_client_context *client,
+					struct ctdb_db_context *db,
+					TDB_DATA key, bool readonly)
+{
+	struct ctdb_fetch_lock_state *state;
+	struct tevent_req *req;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state, struct ctdb_fetch_lock_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->client = client;
+
+	state->h = talloc_zero(db, struct ctdb_record_handle);
+	if (tevent_req_nomem(state->h, req)) {
+		return tevent_req_post(req, ev);
+	}
+	state->h->client = client;
+	state->h->db = db;
+	state->h->key.dptr = talloc_memdup(state->h, key.dptr, key.dsize);
+	if (tevent_req_nomem(state->h->key.dptr, req)) {
+		return tevent_req_post(req, ev);
+	}
+	state->h->key.dsize = key.dsize;
+	state->h->readonly = false;
+
+	state->readonly = readonly;
+	state->pnn = ctdb_client_pnn(client);
+
+	/* Check that database is not persistent */
+	if (db->persistent) {
+		tevent_req_error(req, EINVAL);
+		return tevent_req_post(req, ev);
+	}
+
+	ret = ctdb_fetch_lock_check(req);
+	if (ret == 0) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+	if (ret != EAGAIN) {
+		tevent_req_error(req, ret);
+		return tevent_req_post(req, ev);
+	}
+	return req;
+}
+
+static int ctdb_fetch_lock_check(struct tevent_req *req)
+{
+	struct ctdb_fetch_lock_state *state = tevent_req_data(
+		req, struct ctdb_fetch_lock_state);
+	struct ctdb_record_handle *h = state->h;
+	struct ctdb_ltdb_header header;
+	TDB_DATA data = tdb_null;
+	int ret, err = 0;
+	bool do_migrate = false;
+
+	ret = tdb_chainlock(state->h->db->ltdb->tdb, state->h->key);
+	if (ret != 0) {
+		err = EIO;
+		goto failed;
+	}
+
+	data = tdb_fetch(h->db->ltdb->tdb, h->key);
+	if (data.dptr == NULL) {
+		if (tdb_error(h->db->ltdb->tdb) == TDB_ERR_NOEXIST) {
+			goto migrate;
+		} else {
+			err = EIO;
+			goto failed;
+		}
+	}
+
+	/* Got the record */
+	ret = ctdb_ltdb_header_pull(data.dptr, data.dsize, &header);
+	if (ret != 0) {
+		err = ret;
+		goto failed;
+	}
+
+	if (! state->readonly) {
+		/* Read/write access */
+		if (header.dmaster == state->pnn &&
+		    header.flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
+			goto migrate;
+		}
+
+		if (header.dmaster != state->pnn) {
+			goto migrate;
+		}
+	} else {
+		/* Readonly access */
+		if (header.dmaster != state->pnn &&
+		    ! (header.flags & (CTDB_REC_RO_HAVE_READONLY |
+				       CTDB_REC_RO_HAVE_DELEGATIONS))) {
+			goto migrate;
+		}
+	}
+
+	/* We are the dmaster or readonly delegation */
+	h->header = header;
+	h->data = data;
+	if (header.flags & (CTDB_REC_RO_HAVE_READONLY |
+			    CTDB_REC_RO_HAVE_DELEGATIONS)) {
+		h->readonly = true;
+	}
+	return 0;
+
+migrate:
+	do_migrate = true;
+	err = EAGAIN;
+
+failed:
+	if (data.dptr != NULL) {
+		free(data.dptr);
+	}
+	ret = tdb_chainunlock(h->db->ltdb->tdb, h->key);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("tdb_chainunlock failed on %s\n",
+				  h->db->db_name));
+		return EIO;
+	}
+
+	if (do_migrate) {
+		ctdb_fetch_lock_migrate(req);
+	}
+	return err;
+}
+
+static void ctdb_fetch_lock_migrate(struct tevent_req *req)
+{
+	struct ctdb_fetch_lock_state *state = tevent_req_data(
+		req, struct ctdb_fetch_lock_state);
+	struct ctdb_req_call request;
+	struct tevent_req *subreq;
+
+	ZERO_STRUCT(request);
+	request.flags = CTDB_IMMEDIATE_MIGRATION;
+	if (state->readonly) {
+		request.flags |= CTDB_WANT_READONLY;
+	}
+	request.db_id = state->h->db->db_id;
+	request.callid = CTDB_NULL_FUNC;
+	request.key = state->h->key;
+
+	subreq = ctdb_client_call_send(state, state->ev, state->client,
+				       &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+
+	tevent_req_set_callback(subreq, ctdb_fetch_lock_migrate_done, req);
+}
+
+static void ctdb_fetch_lock_migrate_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_fetch_lock_state *state = tevent_req_data(
+		req, struct ctdb_fetch_lock_state);
+	struct ctdb_reply_call *reply;
+	int ret;
+	bool status;
+
+	status = ctdb_client_call_recv(subreq, state, &reply, &ret);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	if (reply->status != 0) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+	talloc_free(reply);
+
+	ret = ctdb_fetch_lock_check(req);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+static int ctdb_record_handle_destructor(struct ctdb_record_handle *h)
+{
+	tdb_chainunlock(h->db->ltdb->tdb, h->key);
+	free(h->data.dptr);
+	return 0;
+}
+
+struct ctdb_record_handle *ctdb_fetch_lock_recv(struct tevent_req *req,
+						struct ctdb_ltdb_header *header,
+						TALLOC_CTX *mem_ctx,
+						TDB_DATA *data, int *perr)
+{
+	struct ctdb_fetch_lock_state *state = tevent_req_data(
+		req, struct ctdb_fetch_lock_state);
+	struct ctdb_record_handle *h = state->h;
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return NULL;
+	}
+
+	if (header != NULL) {
+		*header = h->header;
+	}
+	if (data != NULL) {
+		size_t offset;
+
+		offset = ctdb_ltdb_header_len(&h->header);
+
+		data->dsize = h->data.dsize - offset;
+		data->dptr = talloc_memdup(mem_ctx, h->data.dptr + offset,
+					   data->dsize);
+		if (data->dptr == NULL) {
+			TALLOC_FREE(state->h);
+			if (perr != NULL) {
+				*perr = ENOMEM;
+			}
+			return NULL;
+		}
+	}
+
+	talloc_set_destructor(h, ctdb_record_handle_destructor);
+	return h;
+}
+
+int ctdb_fetch_lock(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		    struct ctdb_client_context *client,
+		    struct ctdb_db_context *db, TDB_DATA key, bool readonly,
+		    struct ctdb_record_handle **out,
+		    struct ctdb_ltdb_header *header, TDB_DATA *data)
+{
+	struct tevent_req *req;
+	struct ctdb_record_handle *h;
+	int ret;
+
+	req = ctdb_fetch_lock_send(mem_ctx, ev, client, db, key, readonly);
+	if (req == NULL) {
+		return ENOMEM;
+	}
+
+	tevent_req_poll(req, ev);
+
+	h = ctdb_fetch_lock_recv(req, header, mem_ctx, data, &ret);
+	if (h == NULL) {
+		return ret;
+	}
+
+	*out = h;
+	return 0;
+}
+
+int ctdb_store_record(struct ctdb_record_handle *h, TDB_DATA data)
+{
+	TDB_DATA rec;
+	size_t offset;
+	int ret;
+
+	/* Cannot modify the record if it was obtained as a readonly copy */
+	if (h->readonly) {
+		return EINVAL;
+	}
+
+	/* Check if the new data is same */
+	if (h->data.dsize == data.dsize &&
+	    memcmp(h->data.dptr, data.dptr, data.dsize) == 0) {
+		/* No need to do anything */
+		return 0;
+	}
+
+	offset = ctdb_ltdb_header_len(&h->header);
+	rec.dsize = offset + data.dsize;
+	rec.dptr = talloc_size(h, rec.dsize);
+	if (rec.dptr == NULL) {
+		return ENOMEM;
+	}
+
+	ctdb_ltdb_header_push(&h->header, rec.dptr);
+	memcpy(rec.dptr + offset, data.dptr, data.dsize);
+
+	ret = tdb_store(h->db->ltdb->tdb, h->key, rec, TDB_REPLACE);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Failed to store record in DB %s\n",
+				  h->db->db_name));
+		return EIO;
+	}
+
+	talloc_free(rec.dptr);
+	return 0;
+}
+
+int ctdb_delete_record(struct ctdb_record_handle *h)
+{
+	TDB_DATA rec;
+	struct ctdb_key_data key;
+	int ret;
+
+	/* Cannot delete the record if it was obtained as a readonly copy */
+	if (h->readonly) {
+		return EINVAL;
+	}
+
+	rec.dsize = ctdb_ltdb_header_len(&h->header);
+	rec.dptr = talloc_size(h, rec.dsize);
+	if (rec.dptr == NULL) {
+		return ENOMEM;
+	}
+
+	ctdb_ltdb_header_push(&h->header, rec.dptr);
+
+	ret = tdb_store(h->db->ltdb->tdb, h->key, rec, TDB_REPLACE);
+	talloc_free(rec.dptr);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Failed to delete record in DB %s\n",
+				  h->db->db_name));
+		return EIO;
+	}
+
+	key.db_id = h->db->db_id;
+	key.header = h->header;
+	key.key = h->key;
+
+	ret = ctdb_ctrl_schedule_for_deletion(h, h->ev, h->client,
+					      h->client->pnn,
+					      tevent_timeval_zero(), &key);
+	if (ret != 0) {
+		DEBUG(DEBUG_WARNING,
+		      ("Failed to mark record to be deleted in DB %s\n",
+		       h->db->db_name));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Global lock functions
+ */
+
+struct ctdb_g_lock_lock_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	struct ctdb_db_context *db;
+	TDB_DATA key;
+	struct ctdb_server_id my_sid;
+	enum ctdb_g_lock_type lock_type;
+	struct ctdb_record_handle *h;
+	/* state for verification of active locks */
+	struct ctdb_g_lock_list *lock_list;
+	unsigned int current;
+};
+
+static void ctdb_g_lock_lock_fetched(struct tevent_req *subreq);
+static void ctdb_g_lock_lock_process_locks(struct tevent_req *req);
+static void ctdb_g_lock_lock_checked(struct tevent_req *subreq);
+static int ctdb_g_lock_lock_update(struct tevent_req *req);
+static void ctdb_g_lock_lock_retry(struct tevent_req *subreq);
+
+static bool ctdb_g_lock_conflicts(enum ctdb_g_lock_type l1,
+				  enum ctdb_g_lock_type l2)
+{
+	if ((l1 == CTDB_G_LOCK_READ) && (l2 == CTDB_G_LOCK_READ)) {
+		return false;
+	}
+	return true;
+}
+
+struct tevent_req *ctdb_g_lock_lock_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct ctdb_client_context *client,
+					 struct ctdb_db_context *db,
+					 const char *keyname,
+					 struct ctdb_server_id *sid,
+					 bool readonly)
+{
+	struct tevent_req *req, *subreq;
+	struct ctdb_g_lock_lock_state *state;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_g_lock_lock_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->client = client;
+	state->db = db;
+	state->key.dptr = discard_const(keyname);
+	state->key.dsize = strlen(keyname) + 1;
+	state->my_sid = *sid;
+	state->lock_type = (readonly ? CTDB_G_LOCK_READ : CTDB_G_LOCK_WRITE);
+
+	subreq = ctdb_fetch_lock_send(state, ev, client, db, state->key,
+				      false);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_g_lock_lock_fetched, req);
+
+	return req;
+}
+
+static void ctdb_g_lock_lock_fetched(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_g_lock_lock_state *state = tevent_req_data(
+		req, struct ctdb_g_lock_lock_state);
+	TDB_DATA data;
+	int ret = 0;
+
+	state->h = ctdb_fetch_lock_recv(subreq, NULL, state, &data, &ret);
+	TALLOC_FREE(subreq);
+	if (state->h == NULL) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	if (state->lock_list != NULL) {
+		TALLOC_FREE(state->lock_list);
+		state->current = 0;
+	}
+
+	ret = ctdb_g_lock_list_pull(data.dptr, data.dsize, state,
+				    &state->lock_list);
+	talloc_free(data.dptr);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_g_lock_lock_process_locks(req);
+}
+
+static void ctdb_g_lock_lock_process_locks(struct tevent_req *req)
+{
+	struct ctdb_g_lock_lock_state *state = tevent_req_data(
+		req, struct ctdb_g_lock_lock_state);
+	struct tevent_req *subreq;
+	struct ctdb_g_lock *lock;
+	bool check_server = false;
+	int ret;
+
+	while (state->current < state->lock_list->num) {
+		lock = &state->lock_list->lock[state->current];
+
+		/* We should not ask for the same lock more than once */
+		if (ctdb_server_id_equal(&lock->sid, &state->my_sid)) {
+			tevent_req_error(req, EDEADLK);
+			return;
+		}
+
+		if (ctdb_g_lock_conflicts(lock->type, state->lock_type)) {
+			check_server = true;
+			break;
+		}
+
+		state->current += 1;
+	}
+
+	if (check_server) {
+		struct ctdb_req_control request;
+		struct ctdb_uint64_array u64_array;
+
+		u64_array.num = 1;
+		u64_array.val = &lock->sid.unique_id;
+
+		ctdb_req_control_check_srvids(&request, &u64_array);
+		subreq = ctdb_client_control_send(state, state->ev,
+						  state->client,
+						  state->client->pnn,
+						  tevent_timeval_zero(),
+						  &request);
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		tevent_req_set_callback(subreq, ctdb_g_lock_lock_checked, req);
+		return;
+	}
+
+	/* There is no conflict, add ourself to the lock_list */
+	state->lock_list->lock = talloc_realloc(state->lock_list,
+						state->lock_list->lock,
+						struct ctdb_g_lock,
+						state->lock_list->num + 1);
+	if (state->lock_list->lock == NULL) {
+		tevent_req_error(req, ENOMEM);
+		return;
+	}
+
+	lock = &state->lock_list->lock[state->lock_list->num];
+	lock->type = state->lock_type;
+	lock->sid = state->my_sid;
+	state->lock_list->num += 1;
+
+	ret = ctdb_g_lock_lock_update(req);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+static void ctdb_g_lock_lock_checked(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_g_lock_lock_state *state = tevent_req_data(
+		req, struct ctdb_g_lock_lock_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_uint8_array *u8_array;
+	int ret;
+	bool status;
+	int8_t val;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_check_srvids(reply, state, &u8_array);
+	if (ret != 0) {
+		tevent_req_error(req, ENOMEM);
+		return;
+	}
+
+	if (u8_array->num != 1) {
+		talloc_free(u8_array);
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	val = u8_array->val[0];
+	talloc_free(u8_array);
+
+	if (val == 1) {
+		/* server process exists, need to retry */
+		subreq = tevent_wakeup_send(state, state->ev,
+					    tevent_timeval_current_ofs(1,0));
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		tevent_req_set_callback(subreq, ctdb_g_lock_lock_retry, req);
+		return;
+	}
+
+	/* server process does not exist, remove conflicting entry */
+	state->lock_list->lock[state->current] =
+		state->lock_list->lock[state->lock_list->num-1];
+	state->lock_list->num -= 1;
+
+	ret = ctdb_g_lock_lock_update(req);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_g_lock_lock_process_locks(req);
+}
+
+static int ctdb_g_lock_lock_update(struct tevent_req *req)
+{
+	struct ctdb_g_lock_lock_state *state = tevent_req_data(
+		req, struct ctdb_g_lock_lock_state);
+	TDB_DATA data;
+	int ret;
+
+	data.dsize = ctdb_g_lock_list_len(state->lock_list);
+	data.dptr = talloc_size(state, data.dsize);
+	if (data.dptr == NULL) {
+		return ENOMEM;
+	}
+
+	ctdb_g_lock_list_push(state->lock_list, data.dptr);
+	ret = ctdb_store_record(state->h, data);
+	talloc_free(data.dptr);
+	return ret;
+}
+
+#if 0
+static int ctdb_g_lock_lock_update(struct ctdb_g_lock_lock_state *state,
+				   struct ctdb_g_lock_list *lock_list,
+				   struct ctdb_record_handle *h)
+{
+	struct ctdb_g_lock *lock;
+	bool conflict = false;
+	bool modified = false;
+	int ret, i;
+
+	for (i=0; i<lock_list->num; i++) {
+		lock = &lock_list->lock[i];
+
+		/* We should not ask for lock more than once */
+		if (ctdb_server_id_equal(&lock->sid, &state->my_sid)) {
+			return EDEADLK;
+		}
+
+		if (ctdb_g_lock_conflicts(lock->type, state->lock_type)) {
+			bool exists;
+
+			conflict = true;
+			ret = ctdb_server_id_exists(state->client, &lock->sid,
+						    &exists);
+			if (ret != 0) {
+				return ret;
+			}
+
+			if (exists) {
+				break;
+			}
+
+			/* Server does not exist, delete conflicting entry */
+			lock_list->lock[i] = lock_list->lock[lock_list->num-1];
+			lock_list->num -= 1;
+			modified = true;
+		}
+	}
+
+	if (! conflict) {
+		lock = talloc_realloc(lock_list, lock_list->lock,
+				      struct ctdb_g_lock, lock_list->num+1);
+		if (lock == NULL) {
+			return ENOMEM;
+		}
+
+		lock[lock_list->num].type = state->lock_type;
+		lock[lock_list->num].sid = state->my_sid;
+		lock_list->lock = lock;
+		lock_list->num += 1;
+		modified = true;
+	}
+
+	if (modified) {
+		TDB_DATA data;
+
+		data.dsize = ctdb_g_lock_list_len(lock_list);
+		data.dptr = talloc_size(state, data.dsize);
+		if (data.dptr == NULL) {
+			return ENOMEM;
+		}
+
+		ctdb_g_lock_list_push(lock_list, data.dptr);
+		ret = ctdb_store_record(h, data);
+		talloc_free(data.dptr);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	if (conflict) {
+		return EAGAIN;
+	}
+	return 0;
+}
+#endif
+
+static void ctdb_g_lock_lock_retry(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_g_lock_lock_state *state = tevent_req_data(
+		req, struct ctdb_g_lock_lock_state);
+	bool success;
+
+	success = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (! success) {
+		tevent_req_error(req, ENOMEM);
+		return;
+	}
+
+	subreq = ctdb_fetch_lock_send(state, state->ev, state->client,
+				      state->db, state->key, false);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, ctdb_g_lock_lock_fetched, req);
+}
+
+bool ctdb_g_lock_lock_recv(struct tevent_req *req, int *perr)
+{
+	struct ctdb_g_lock_lock_state *state = tevent_req_data(
+		req, struct ctdb_g_lock_lock_state);
+	int err;
+
+	TALLOC_FREE(state->h);
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+struct ctdb_g_lock_unlock_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	struct ctdb_db_context *db;
+	TDB_DATA key;
+	struct ctdb_server_id my_sid;
+	struct ctdb_record_handle *h;
+	struct ctdb_g_lock_list *lock_list;
+};
+
+static void ctdb_g_lock_unlock_fetched(struct tevent_req *subreq);
+static int ctdb_g_lock_unlock_update(struct tevent_req *req);
+
+struct tevent_req *ctdb_g_lock_unlock_send(TALLOC_CTX *mem_ctx,
+					   struct tevent_context *ev,
+					   struct ctdb_client_context *client,
+					   struct ctdb_db_context *db,
+					   const char *keyname,
+					   struct ctdb_server_id sid)
+{
+	struct tevent_req *req, *subreq;
+	struct ctdb_g_lock_unlock_state *state;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_g_lock_unlock_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->client = client;
+	state->db = db;
+	state->key.dptr = discard_const(keyname);
+	state->key.dsize = strlen(keyname) + 1;
+	state->my_sid = sid;
+
+	subreq = ctdb_fetch_lock_send(state, ev, client, db, state->key,
+				      false);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_g_lock_unlock_fetched, req);
+
+	return req;
+}
+
+static void ctdb_g_lock_unlock_fetched(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_g_lock_unlock_state *state = tevent_req_data(
+		req, struct ctdb_g_lock_unlock_state);
+	TDB_DATA data;
+	int ret = 0;
+
+	state->h = ctdb_fetch_lock_recv(subreq, NULL, state, &data, &ret);
+	TALLOC_FREE(subreq);
+	if (state->h == NULL) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_g_lock_list_pull(data.dptr, data.dsize, state,
+				    &state->lock_list);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_g_lock_unlock_update(req);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+static int ctdb_g_lock_unlock_update(struct tevent_req *req)
+{
+	struct ctdb_g_lock_unlock_state *state = tevent_req_data(
+		req, struct ctdb_g_lock_unlock_state);
+	struct ctdb_g_lock *lock;
+	int ret, i;
+
+	for (i=0; i<state->lock_list->num; i++) {
+		lock = &state->lock_list->lock[i];
+
+		if (ctdb_server_id_equal(&lock->sid, &state->my_sid)) {
+			break;
+		}
+	}
+
+	if (i < state->lock_list->num) {
+		state->lock_list->lock[i] =
+			state->lock_list->lock[state->lock_list->num-1];
+		state->lock_list->num -= 1;
+	}
+
+	if (state->lock_list->num == 0) {
+		ctdb_delete_record(state->h);
+	} else {
+		TDB_DATA data;
+
+		data.dsize = ctdb_g_lock_list_len(state->lock_list);
+		data.dptr = talloc_size(state, data.dsize);
+		if (data.dptr == NULL) {
+			return ENOMEM;
+		}
+
+		ctdb_g_lock_list_push(state->lock_list, data.dptr);
+		ret = ctdb_store_record(state->h, data);
+		talloc_free(data.dptr);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+bool ctdb_g_lock_unlock_recv(struct tevent_req *req, int *perr)
+{
+	struct ctdb_g_lock_unlock_state *state = tevent_req_data(
+		req, struct ctdb_g_lock_unlock_state);
+	int err;
+
+	TALLOC_FREE(state->h);
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * Persistent database functions
+ */
+struct ctdb_transaction_start_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	struct timeval timeout;
+	struct ctdb_transaction_handle *h;
+	uint32_t destnode;
+};
+
+static void ctdb_transaction_g_lock_attached(struct tevent_req *subreq);
+static void ctdb_transaction_register_done(struct tevent_req *subreq);
+static void ctdb_transaction_g_lock_done(struct tevent_req *subreq);
+static int ctdb_transaction_handle_destructor(struct ctdb_transaction_handle *h);
+
+struct tevent_req *ctdb_transaction_start_send(TALLOC_CTX *mem_ctx,
+					       struct tevent_context *ev,
+					       struct ctdb_client_context *client,
+					       struct timeval timeout,
+					       struct ctdb_db_context *db,
+					       bool readonly)
+{
+	struct ctdb_transaction_start_state *state;
+	struct tevent_req *req, *subreq;
+	struct ctdb_transaction_handle *h;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_transaction_start_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	if (! db->persistent) {
+		tevent_req_error(req, EINVAL);
+		return tevent_req_post(req, ev);
+	}
+
+	state->ev = ev;
+	state->client = client;
+	state->destnode = ctdb_client_pnn(client);
+
+	h = talloc_zero(db, struct ctdb_transaction_handle);
+	if (tevent_req_nomem(h, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	h->ev = ev;
+	h->client = client;
+	h->db = db;
+	h->readonly = readonly;
+	h->updated = false;
+
+	/* SRVID is unique for databases, so client can have transactions active
+	 * for multiple databases */
+	h->sid.pid = getpid();
+	h->sid.task_id = db->db_id;
+	h->sid.vnn = state->destnode;
+	h->sid.unique_id = h->sid.task_id;
+	h->sid.unique_id = (h->sid.unique_id << 32) | h->sid.pid;
+
+	h->recbuf = ctdb_rec_buffer_init(h, db->db_id);
+	if (tevent_req_nomem(h->recbuf, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	h->lock_name = talloc_asprintf(h, "transaction_db_0x%08x", db->db_id);
+	if (tevent_req_nomem(h->lock_name, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	state->h = h;
+
+	subreq = ctdb_attach_send(state, ev, client, timeout, "g_lock.tdb", 0);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_transaction_g_lock_attached, req);
+
+	return req;
+}
+
+static void ctdb_transaction_g_lock_attached(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_transaction_start_state *state = tevent_req_data(
+		req, struct ctdb_transaction_start_state);
+	struct ctdb_req_control request;
+	bool status;
+	int ret;
+
+	status = ctdb_attach_recv(subreq, &ret, &state->h->db_g_lock);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_req_control_register_srvid(&request, state->h->sid.unique_id);
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->destnode, state->timeout,
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, ctdb_transaction_register_done, req);
+}
+
+static void ctdb_transaction_register_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_transaction_start_state *state = tevent_req_data(
+		req, struct ctdb_transaction_start_state);
+	struct ctdb_reply_control *reply;
+	bool status;
+	int ret;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_register_srvid(reply);
+	talloc_free(reply);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	subreq = ctdb_g_lock_lock_send(state, state->ev, state->client,
+				       state->h->db_g_lock, state->h->lock_name,
+				       &state->h->sid, state->h->readonly);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, ctdb_transaction_g_lock_done, req);
+}
+
+static void ctdb_transaction_g_lock_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	int ret;
+	bool status;
+
+	status = ctdb_g_lock_lock_recv(subreq, &ret);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+struct ctdb_transaction_handle *ctdb_transaction_start_recv(
+					struct tevent_req *req,
+					int *perr)
+{
+	struct ctdb_transaction_start_state *state = tevent_req_data(
+		req, struct ctdb_transaction_start_state);
+	struct ctdb_transaction_handle *h = state->h;
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return NULL;
+	}
+
+	talloc_set_destructor(h, ctdb_transaction_handle_destructor);
+	return h;
+}
+
+static int ctdb_transaction_handle_destructor(struct ctdb_transaction_handle *h)
+{
+	int ret;
+
+	ret = ctdb_ctrl_deregister_srvid(h, h->ev, h->client, h->client->pnn,
+					 tevent_timeval_zero(),
+					 h->sid.unique_id);
+	if (ret != 0) {
+		DEBUG(DEBUG_WARNING, ("Failed to deregister SRVID\n"));
+	}
+
+	return 0;
+}
+
+int ctdb_transaction_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			   struct ctdb_client_context *client,
+			   struct timeval timeout,
+			   struct ctdb_db_context *db, bool readonly,
+			   struct ctdb_transaction_handle **out)
+{
+	struct tevent_req *req;
+	struct ctdb_transaction_handle *h;
+	int ret;
+
+	req = ctdb_transaction_start_send(mem_ctx, ev, client, timeout, db,
+					  readonly);
+	if (req == NULL) {
+		return ENOMEM;
+	}
+
+	tevent_req_poll(req, ev);
+
+	h = ctdb_transaction_start_recv(req, &ret);
+	if (h == NULL) {
+		return ret;
+	}
+
+	*out = h;
+	return 0;
+}
+
+struct ctdb_transaction_record_fetch_state {
+	TDB_DATA key, data;
+	struct ctdb_ltdb_header header;
+	bool found;
+};
+
+static int ctdb_transaction_record_fetch_traverse(uint32_t reqid,
+						  struct ctdb_ltdb_header *header,
+						  TDB_DATA key,
+						  TDB_DATA data,
+						  void *private_data)
+{
+	struct ctdb_transaction_record_fetch_state *state =
+		(struct ctdb_transaction_record_fetch_state *)private_data;
+
+	if (state->key.dsize == key.dsize &&
+	    memcmp(state->key.dptr, key.dptr, key.dsize) == 0) {
+		state->data = data;
+		state->header = *header;
+		state->found = true;
+	}
+
+	return 0;
+}
+
+static int ctdb_transaction_record_fetch(struct ctdb_transaction_handle *h,
+					 TDB_DATA key,
+					 struct ctdb_ltdb_header *header,
+					 TDB_DATA *data)
+{
+	struct ctdb_transaction_record_fetch_state state;
+	int ret;
+
+	state.key = key;
+	state.found = false;
+
+	ret = ctdb_rec_buffer_traverse(h->recbuf,
+				       ctdb_transaction_record_fetch_traverse,
+				       &state);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (state.found) {
+		if (header != NULL) {
+			*header = state.header;
+		}
+		if (data != NULL) {
+			*data = state.data;
+		}
+		return 0;
+	}
+
+	return ENOENT;
+}
+
+int ctdb_transaction_fetch_record(struct ctdb_transaction_handle *h,
+				  TDB_DATA key,
+				  TALLOC_CTX *mem_ctx, TDB_DATA *data)
+{
+	TDB_DATA tmp_data;
+	struct ctdb_ltdb_header header;
+	int ret;
+
+	ret = ctdb_transaction_record_fetch(h, key, NULL, &tmp_data);
+	if (ret == 0) {
+		data->dptr = talloc_memdup(mem_ctx, tmp_data.dptr,
+					   tmp_data.dsize);
+		if (data->dptr == NULL) {
+			return ENOMEM;
+		}
+		data->dsize = tmp_data.dsize;
+		return 0;
+	}
+
+	ret = ctdb_ltdb_fetch(h->db, key, &header, mem_ctx, data);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = ctdb_rec_buffer_add(h, h->recbuf, 0, &header, key, *data);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_transaction_store_record(struct ctdb_transaction_handle *h,
+				  TDB_DATA key, TDB_DATA data)
+{
+	TALLOC_CTX *tmp_ctx;
+	struct ctdb_ltdb_header header;
+	TDB_DATA old_data;
+	int ret;
+
+	if (h->readonly) {
+		return EINVAL;
+	}
+
+	tmp_ctx = talloc_new(h);
+	if (tmp_ctx == NULL) {
+		return ENOMEM;
+	}
+
+	ret = ctdb_transaction_record_fetch(h, key, &header, &old_data);
+	if (ret != 0) {
+		ret = ctdb_ltdb_fetch(h->db, key, &header, tmp_ctx, &old_data);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	if (old_data.dsize == data.dsize &&
+	    memcmp(old_data.dptr, data.dptr, data.dsize) == 0) {
+		talloc_free(tmp_ctx);
+		return 0;
+	}
+
+	header.dmaster = ctdb_client_pnn(h->client);
+	header.rsn += 1;
+
+	ret = ctdb_rec_buffer_add(h, h->recbuf, 0, &header, key, data);
+	talloc_free(tmp_ctx);
+	if (ret != 0) {
+		return ret;
+	}
+	h->updated = true;
+
+	return 0;
+}
+
+int ctdb_transaction_delete_record(struct ctdb_transaction_handle *h,
+				   TDB_DATA key)
+{
+	return ctdb_transaction_store_record(h, key, tdb_null);
+}
+
+static int ctdb_transaction_store_db_seqnum(struct ctdb_transaction_handle *h,
+					    uint64_t seqnum)
+{
+	const char *keyname = CTDB_DB_SEQNUM_KEY;
+	TDB_DATA key, data;
+
+	key.dptr = discard_const(keyname);
+	key.dsize = strlen(keyname) + 1;
+
+	data.dptr = (uint8_t *)&seqnum;
+	data.dsize = sizeof(seqnum);
+
+	return ctdb_transaction_store_record(h, key, data);
+}
+
+struct ctdb_transaction_commit_state {
+	struct tevent_context *ev;
+	struct ctdb_transaction_handle *h;
+	uint64_t seqnum;
+};
+
+static void ctdb_transaction_commit_done(struct tevent_req *subreq);
+static void ctdb_transaction_commit_try(struct tevent_req *subreq);
+
+struct tevent_req *ctdb_transaction_commit_send(
+					TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct ctdb_transaction_handle *h)
+{
+	struct tevent_req *req, *subreq;
+	struct ctdb_transaction_commit_state *state;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_transaction_commit_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->h = h;
+
+	ret = ctdb_ctrl_get_db_seqnum(state, ev, h->client,
+				      h->client->pnn, tevent_timeval_zero(),
+				      h->db->db_id, &state->seqnum);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return tevent_req_post(req, ev);
+	}
+
+	ret = ctdb_transaction_store_db_seqnum(h, state->seqnum+1);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return tevent_req_post(req, ev);
+	}
+
+	subreq = ctdb_recovery_wait_send(state, ev, h->client);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_transaction_commit_try, req);
+
+	return req;
+}
+
+static void ctdb_transaction_commit_try(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_transaction_commit_state *state = tevent_req_data(
+		req, struct ctdb_transaction_commit_state);
+	struct ctdb_req_control request;
+	int ret;
+	bool status;
+
+	status = ctdb_recovery_wait_recv(subreq, &ret);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_req_control_trans3_commit(&request, state->h->recbuf);
+	subreq = ctdb_client_control_send(state, state->ev, state->h->client,
+					  state->h->client->pnn,
+					  tevent_timeval_zero(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, ctdb_transaction_commit_done, req);
+}
+
+static void ctdb_transaction_commit_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct ctdb_transaction_commit_state *state = tevent_req_data(
+		req, struct ctdb_transaction_commit_state);
+	struct ctdb_reply_control *reply;
+	uint64_t seqnum;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_trans3_commit(reply);
+	if (ret < 0) {
+		/* Control failed due to recovery */
+		subreq = ctdb_recovery_wait_send(state, state->ev,
+						 state->h->client);
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		tevent_req_set_callback(subreq, ctdb_transaction_commit_try,
+					req);
+		return;
+	}
+
+	ret = ctdb_ctrl_get_db_seqnum(state, state->ev, state->h->client,
+				      state->h->client->pnn,
+				      tevent_timeval_zero(),
+				      state->h->db->db_id, &seqnum);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	if (seqnum == state->seqnum) {
+		subreq = ctdb_recovery_wait_send(state, state->ev,
+						 state->h->client);
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		tevent_req_set_callback(subreq, ctdb_transaction_commit_try,
+					req);
+		return;
+	}
+
+	if (seqnum != state->seqnum + 1) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+bool ctdb_transaction_commit_recv(struct tevent_req *req, int *perr)
+{
+	struct ctdb_transaction_commit_state *state = tevent_req_data(
+		req, struct ctdb_transaction_commit_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		TALLOC_FREE(state->h);
+		return false;
+	}
+
+	TALLOC_FREE(state->h);
+	return true;
+}
+
+int ctdb_transaction_commit(struct ctdb_transaction_handle *h)
+{
+	struct tevent_req *req;
+	int ret;
+	bool status;
+
+	if (h->readonly || ! h->updated) {
+		talloc_free(h);
+		return 0;
+	}
+
+	req = ctdb_transaction_commit_send(h, h->ev, h);
+	if (req == NULL) {
+		talloc_free(h);
+		return ENOMEM;
+	}
+
+	tevent_req_poll(req, h->ev);
+
+	status = ctdb_transaction_commit_recv(req, &ret);
+	if (! status) {
+		talloc_free(h);
+		return ret;
+	}
+
+	talloc_free(h);
+	return 0;
+}
+
+int ctdb_transaction_cancel(struct ctdb_transaction_handle *h)
+{
+	talloc_free(h);
+	return 0;
+}
+
+/*
+ * TODO:
+ *
+ * In future Samba should register SERVER_ID.
+ * Make that structure same as struct srvid {}.
+ */
diff --git a/ctdb/client/client_message.c b/ctdb/client/client_message.c
new file mode 100644
index 0000000..bfa9ba2
--- /dev/null
+++ b/ctdb/client/client_message.c
@@ -0,0 +1,227 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/tevent_unix.h"
+
+#include "common/reqid.h"
+#include "common/srvid.h"
+#include "common/comm.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+
+#include "client/client_private.h"
+#include "client/client.h"
+
+
+/*
+ * Handle REQ_MESSAGE
+ */
+
+struct ctdb_client_message_state {
+	struct ctdb_client_context *client;
+	uint32_t reqid;
+};
+
+static int ctdb_client_message_state_destructor(
+	struct ctdb_client_message_state *state);
+static void ctdb_client_message_done(struct tevent_req *subreq);
+
+struct tevent_req *ctdb_client_message_send(TALLOC_CTX *mem_ctx,
+					    struct tevent_context *ev,
+					    struct ctdb_client_context *client,
+					    uint32_t destnode,
+					    struct ctdb_req_message *message)
+{
+	struct tevent_req *req, *subreq;
+	struct ctdb_client_message_state *state;
+	struct ctdb_req_header h;
+	uint32_t reqid;
+	uint8_t *buf;
+	size_t buflen;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ctdb_client_message_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	reqid = reqid_new(client->idr, state);
+	if (reqid == REQID_INVALID) {
+		talloc_free(req);
+		return NULL;
+	}
+
+	state->client = client;
+	state->reqid = reqid;
+
+	talloc_set_destructor(state, ctdb_client_message_state_destructor);
+
+	ctdb_req_header_fill(&h, 0, CTDB_REQ_MESSAGE, destnode,
+			     client->pnn, reqid);
+
+	ret = ctdb_req_message_push(&h, message, state, &buf, &buflen);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return tevent_req_post(req, ev);
+	}
+
+	subreq = comm_write_send(state, ev, client->comm, buf, buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, ctdb_client_message_done, req);
+
+	return req;
+}
+
+static int ctdb_client_message_state_destructor(
+	struct ctdb_client_message_state *state)
+{
+	reqid_remove(state->client->idr, state->reqid);
+	return 0;
+}
+
+static void ctdb_client_message_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	int ret;
+	bool status;
+
+	status = comm_write_recv(subreq, &ret);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+bool ctdb_client_message_recv(struct tevent_req *req, int *perr)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+void ctdb_client_req_message(struct ctdb_client_context *client,
+			     uint8_t *buf, size_t buflen, uint32_t reqid)
+{
+	struct ctdb_req_header h;
+	struct ctdb_req_message_data message;
+	TALLOC_CTX *tmp_ctx = talloc_new(client);
+	int ret;
+
+	ret = ctdb_req_message_data_pull(buf, buflen, &h, tmp_ctx, &message);
+	if (ret != 0) {
+		return;
+	}
+
+	srvid_dispatch(client->srv, message.srvid, CTDB_SRVID_ALL,
+		       message.data);
+	talloc_free(tmp_ctx);
+}
+
+/*
+ * sync version of message send
+ */
+
+int ctdb_client_message(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			uint32_t destnode, struct ctdb_req_message *message)
+{
+	TALLOC_CTX *tmp_ctx;
+	struct tevent_req *req;
+	int ret;
+	bool status;
+
+	tmp_ctx = talloc_new(client);
+	if (tmp_ctx == NULL) {
+		return ENOMEM;
+	}
+
+	req = ctdb_client_message_send(tmp_ctx, ev, client, destnode, message);
+	if (req == NULL) {
+		talloc_free(tmp_ctx);
+		return ENOMEM;
+	}
+
+	tevent_req_poll(req, ev);
+
+	status = ctdb_client_message_recv(req, &ret);
+	if (! status) {
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+int ctdb_client_set_message_handler(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    uint64_t srvid, srvid_handler_fn handler,
+				    void *private_data)
+{
+	int ret;
+
+	ret = ctdb_ctrl_register_srvid(mem_ctx, ev, client, client->pnn,
+				       tevent_timeval_zero(), srvid);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return srvid_register(client->srv, client, srvid,
+			      handler, private_data);
+}
+
+int ctdb_client_remove_message_handler(TALLOC_CTX *mem_ctx,
+				       struct tevent_context *ev,
+				       struct ctdb_client_context *client,
+				       uint64_t srvid, void *private_data)
+{
+	int ret;
+
+	ret = ctdb_ctrl_deregister_srvid(mem_ctx, ev, client, client->pnn,
+					 tevent_timeval_zero(), srvid);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return srvid_deregister(client->srv, srvid, private_data);
+}
diff --git a/ctdb/client/client_message_sync.c b/ctdb/client/client_message_sync.c
new file mode 100644
index 0000000..4bcc122
--- /dev/null
+++ b/ctdb/client/client_message_sync.c
@@ -0,0 +1,196 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "common/logging.h"
+
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+#include "client/client_private.h"
+#include "client/client.h"
+
+int ctdb_message_recd_update_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, struct ctdb_public_ip *pubip)
+{
+	struct ctdb_req_message message;
+	int ret;
+
+	message.srvid = CTDB_SRVID_RECD_UPDATE_IP;
+	message.data.pubip = pubip;
+
+	ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Message RECD_UPDATE_IP failed to node %u\n",
+		       destnode));
+	}
+
+	return ret;
+}
+
+int ctdb_message_mem_dump(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  int destnode, struct ctdb_srvid_message *msg)
+{
+	struct ctdb_req_message message;
+	int ret;
+
+	message.srvid = CTDB_SRVID_MEM_DUMP;
+	message.data.msg = msg;
+
+	ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Message MEM_DUMP failed to node %u\n", destnode));
+	}
+
+	return ret;
+}
+
+int ctdb_message_reload_nodes(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode)
+{
+	struct ctdb_req_message message;
+	int ret;
+
+	message.srvid = CTDB_SRVID_RELOAD_NODES;
+
+	ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Message RELOAD_NODES failed to node %u\n", destnode));
+	}
+
+	return ret;
+}
+
+int ctdb_message_takeover_run(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			      struct ctdb_client_context *client,
+			      int destnode, struct ctdb_srvid_message *msg)
+{
+	struct ctdb_req_message message;
+	int ret;
+
+	message.srvid = CTDB_SRVID_TAKEOVER_RUN;
+	message.data.msg = msg;
+
+	ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Message TAKEOVER_RUN failed to node %u\n", destnode));
+	}
+
+	return ret;
+}
+
+int ctdb_message_rebalance_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+				struct ctdb_client_context *client,
+				int destnode, uint32_t pnn)
+{
+	struct ctdb_req_message message;
+	int ret;
+
+	message.srvid = CTDB_SRVID_REBALANCE_NODE;
+	message.data.pnn = pnn;
+
+	ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Message REBALANCE_NODE failed to node %u\n",
+		       destnode));
+	}
+
+	return ret;
+}
+
+int ctdb_message_disable_takeover_runs(TALLOC_CTX *mem_ctx,
+				       struct tevent_context *ev,
+				       struct ctdb_client_context *client,
+				       int destnode,
+				       struct ctdb_disable_message *disable)
+{
+	struct ctdb_req_message message;
+	int ret;
+
+	message.srvid = CTDB_SRVID_DISABLE_TAKEOVER_RUNS;
+	message.data.disable = disable;
+
+	ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Message DISABLE_TAKEOVER_RUNS failed to node %u\n",
+		       destnode));
+	}
+
+	return ret;
+}
+
+int ctdb_message_disable_recoveries(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct ctdb_client_context *client,
+				    int destnode,
+				    struct ctdb_disable_message *disable)
+{
+	struct ctdb_req_message message;
+	int ret;
+
+	message.srvid = CTDB_SRVID_DISABLE_RECOVERIES;
+	message.data.disable = disable;
+
+	ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Message DISABLE_RECOVERIES failed to node %u\n",
+		       destnode));
+	}
+
+	return ret;
+}
+
+int ctdb_message_disable_ip_check(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  struct ctdb_client_context *client,
+				  int destnode, uint32_t timeout)
+{
+	struct ctdb_req_message message;
+	int ret;
+
+	message.srvid = CTDB_SRVID_DISABLE_IP_CHECK;
+	message.data.timeout = timeout;
+
+	ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Message DISABLE_IP_CHECK failed to node %u\n",
+		       destnode));
+	}
+
+	return ret;
+}
diff --git a/ctdb/client/client_private.h b/ctdb/client/client_private.h
new file mode 100644
index 0000000..7ea9b12
--- /dev/null
+++ b/ctdb/client/client_private.h
@@ -0,0 +1,82 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_CLIENT_PRIVATE_H__
+#define __CTDB_CLIENT_PRIVATE_H__
+
+#include "protocol/protocol.h"
+#include "client/client.h"
+
+struct ctdb_db_context {
+	struct ctdb_db_context *prev, *next;
+	uint32_t db_id;
+	const char *db_name;
+	const char *db_path;
+	struct tdb_wrap *ltdb;
+	bool persistent;
+};
+
+struct ctdb_client_context {
+	struct reqid_context *idr;
+	struct srvid_context *srv;
+	struct comm_context *comm;
+	ctdb_client_callback_func_t callback;
+	void *private_data;
+	int fd;
+	uint32_t pnn;
+	struct ctdb_db_context *db;
+};
+
+struct ctdb_record_handle {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	struct ctdb_db_context *db;
+	struct ctdb_ltdb_header header;
+	TDB_DATA key;
+	TDB_DATA data; /* This is returned from tdb_fetch() */
+	bool readonly;
+};
+
+struct ctdb_transaction_handle {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	struct ctdb_db_context *db, *db_g_lock;
+	struct ctdb_rec_buffer *recbuf;
+	struct ctdb_server_id sid;
+	const char *lock_name;
+	bool readonly;
+	bool updated;
+};
+
+/* From client_call.c */
+
+void ctdb_client_reply_call(struct ctdb_client_context *client,
+			    uint8_t *buf, size_t buflen, uint32_t reqid);
+
+/* From client_message.c */
+
+void ctdb_client_req_message(struct ctdb_client_context *client,
+			     uint8_t *buf, size_t buflen, uint32_t reqid);
+
+/* From client_control.c */
+
+void ctdb_client_reply_control(struct ctdb_client_context *client,
+			       uint8_t *buf, size_t buflen, uint32_t reqid);
+
+#endif /* __CTDB_CLIENT_PRIVATE_H__ */
diff --git a/ctdb/client/client_util.c b/ctdb/client/client_util.c
new file mode 100644
index 0000000..c4dbe04
--- /dev/null
+++ b/ctdb/client/client_util.c
@@ -0,0 +1,155 @@
+/*
+   CTDB client code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "common/logging.h"
+
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+#include "client/client_private.h"
+#include "client/client.h"
+
+int list_of_nodes(struct ctdb_node_map *nodemap,
+		  uint32_t flags_mask, uint32_t exclude_pnn,
+		  TALLOC_CTX *mem_ctx, uint32_t **pnn_list)
+{
+	int num_nodes = 0;
+	uint32_t *list;
+	int i;
+
+	/* Allocate the list of same number of nodes */
+	list = talloc_array(mem_ctx, uint32_t, nodemap->num);
+	if (list == NULL) {
+		return -1;
+	}
+
+	for (i=0; i<nodemap->num; i++) {
+		if (nodemap->node[i].flags & flags_mask) {
+			continue;
+		}
+		if (nodemap->node[i].pnn == exclude_pnn) {
+			continue;
+		}
+		list[num_nodes] = nodemap->node[i].pnn;
+		num_nodes++;
+	}
+
+	*pnn_list = list;
+	return num_nodes;
+}
+
+int list_of_active_nodes(struct ctdb_node_map *nodemap, uint32_t exclude_pnn,
+			 TALLOC_CTX *mem_ctx, uint32_t **pnn_list)
+{
+	return list_of_nodes(nodemap, NODE_FLAGS_INACTIVE, exclude_pnn,
+			     mem_ctx, pnn_list);
+}
+
+int list_of_connected_nodes(struct ctdb_node_map *nodemap,
+			    uint32_t exclude_pnn,
+			    TALLOC_CTX *mem_ctx, uint32_t **pnn_list)
+{
+	return list_of_nodes(nodemap, NODE_FLAGS_DISCONNECTED, exclude_pnn,
+			     mem_ctx, pnn_list);
+}
+
+int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+		       struct ctdb_client_context *client,
+		       uint32_t destnode, struct timeval timeout,
+		       uint32_t set, uint32_t clear)
+{
+	struct ctdb_node_map *nodemap;
+	struct ctdb_node_flag_change flag_change;
+	struct ctdb_req_control request;
+	uint32_t *pnn_list;
+	int ret, count;
+
+	ret = ctdb_ctrl_get_nodemap(mem_ctx, ev, client, destnode,
+				    tevent_timeval_zero(), &nodemap);
+	if (ret != 0) {
+		return ret;
+	}
+
+	flag_change.pnn = destnode;
+	flag_change.old_flags = nodemap->node[destnode].flags;
+	flag_change.new_flags = flag_change.old_flags | set;
+	flag_change.new_flags &= ~clear;
+
+	count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list);
+	if (count == -1) {
+		return ENOMEM;
+	}
+
+	ctdb_req_control_modify_flags(&request, &flag_change);
+	ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count,
+					tevent_timeval_zero(), &request,
+					NULL, NULL);
+	return ret;
+}
+
+bool ctdb_server_id_equal(struct ctdb_server_id *sid1,
+			  struct ctdb_server_id *sid2)
+{
+	if (sid1->pid != sid2->pid) {
+		return false;
+	}
+	if (sid1->task_id != sid2->task_id) {
+		return false;
+	}
+	if (sid1->vnn != sid2->vnn) {
+		return false;
+	}
+	if (sid1->unique_id != sid2->unique_id) {
+		return false;
+	}
+
+	return true;
+}
+
+int ctdb_server_id_exists(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			  struct ctdb_client_context *client,
+			  struct ctdb_server_id *sid, bool *exists)
+{
+	uint8_t *result;
+	int ret;
+
+	ret = ctdb_ctrl_check_srvids(mem_ctx, ev, client, sid->vnn,
+				     tevent_timeval_zero(),
+				     &sid->unique_id, 1, &result);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (result[0] == 1) {
+		*exists = true;
+	} else {
+		*exists = false;
+	}
+
+	return 0;
+}
diff --git a/ctdb/client/ctdb_client.c b/ctdb/client/ctdb_client.c
index 7bffefe..6615730 100644
--- a/ctdb/client/ctdb_client.c
+++ b/ctdb/client/ctdb_client.c
@@ -18,16 +18,30 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "lib/tdb_wrap/tdb_wrap.h"
-#include "tdb.h"
-#include "lib/util/dlinklist.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/locale.h"
-#include <stdlib.h>
-#include "../include/ctdb_private.h"
+
+#include <talloc.h>
+/* Allow use of deprecated function tevent_loop_allow_nesting() */
+#define TEVENT_DEPRECATED
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/tdb_wrap/tdb_wrap.h"
 #include "lib/util/dlinklist.h"
+#include "lib/util/time.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/reqid.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 /*
   allocate a packet for use in client<->daemon communication
@@ -150,10 +164,10 @@ static int ctdb_client_queue_pkt(struct ctdb_context *ctdb, struct ctdb_req_head
 */
 static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 {
-	struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr;
+	struct ctdb_reply_call_old *c = (struct ctdb_reply_call_old *)hdr;
 	struct ctdb_client_call_state *state;
 
-	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_call_state);
+	state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_client_call_state);
 	if (state == NULL) {
 		DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
 		return;
@@ -178,6 +192,22 @@ static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_he
 	}
 }
 
+void ctdb_request_message(struct ctdb_context *ctdb,
+			  struct ctdb_req_header *hdr)
+{
+	struct ctdb_req_message_old *c = (struct ctdb_req_message_old *)hdr;
+	TDB_DATA data;
+
+	data.dsize = c->datalen;
+	data.dptr = talloc_memdup(c, &c->data[0], c->datalen);
+	if (data.dptr == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Memory allocation failure\n"));
+		return;
+	}
+
+	srvid_dispatch(ctdb->srv, c->srvid, CTDB_SRVID_ALL, data);
+}
+
 static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
 
 /*
@@ -297,7 +327,7 @@ int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call)
 	}
 
 	while (state->state < CTDB_CALL_DONE) {
-		event_loop_once(state->ctdb_db->ctdb->ev);
+		tevent_loop_once(state->ctdb_db->ctdb->ev);
 	}
 	if (state->state != CTDB_CALL_DONE) {
 		DEBUG(DEBUG_ERR,(__location__ " ctdb_call_recv failed\n"));
@@ -328,7 +358,7 @@ int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call)
 */
 static int ctdb_client_call_destructor(struct ctdb_client_call_state *state)	
 {
-	ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid);
+	reqid_remove(state->ctdb_db->ctdb->idr, state->reqid);
 	return 0;
 }
 
@@ -381,7 +411,7 @@ struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db,
 	TDB_DATA data;
 	int ret;
 	size_t len;
-	struct ctdb_req_call *c;
+	struct ctdb_req_call_old *c;
 
 	/* if the domain socket is not yet open, open it */
 	if (ctdb->daemon.sd==-1) {
@@ -421,14 +451,14 @@ struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db,
 		return NULL;
 	}
 
-	len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize;
-	c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CALL, len, struct ctdb_req_call);
+	len = offsetof(struct ctdb_req_call_old, data) + call->key.dsize + call->call_data.dsize;
+	c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CALL, len, struct ctdb_req_call_old);
 	if (c == NULL) {
 		DEBUG(DEBUG_ERR, (__location__ " failed to allocate packet\n"));
 		return NULL;
 	}
 
-	state->reqid     = ctdb_reqid_new(ctdb, state);
+	state->reqid     = reqid_new(ctdb->idr, state);
 	state->ctdb_db = ctdb_db;
 	talloc_set_destructor(state, ctdb_client_call_destructor);
 
@@ -471,41 +501,48 @@ int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call)
   tell the daemon what messaging srvid we will use, and register the message
   handler function in the client
 */
-int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			     ctdb_msg_fn_t handler,
-			     void *private_data)
+int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
+				    srvid_handler_fn handler,
+				    void *private_data)
 {
 	int res;
 	int32_t status;
 
-	res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_REGISTER_SRVID, 0, 
+	res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid,
+			   CTDB_CONTROL_REGISTER_SRVID, 0,
 			   tdb_null, NULL, NULL, &status, NULL, NULL);
 	if (res != 0 || status != 0) {
-		DEBUG(DEBUG_ERR,("Failed to register srvid %llu\n", (unsigned long long)srvid));
+		DEBUG(DEBUG_ERR,
+		      ("Failed to register srvid %llu\n",
+		       (unsigned long long)srvid));
 		return -1;
 	}
 
 	/* also need to register the handler with our own ctdb structure */
-	return ctdb_register_message_handler(ctdb, ctdb, srvid, handler, private_data);
+	return srvid_register(ctdb->srv, ctdb, srvid, handler, private_data);
 }
 
 /*
   tell the daemon we no longer want a srvid
 */
-int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data)
+int ctdb_client_remove_message_handler(struct ctdb_context *ctdb,
+				       uint64_t srvid, void *private_data)
 {
 	int res;
 	int32_t status;
 
-	res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_DEREGISTER_SRVID, 0, 
+	res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid,
+			   CTDB_CONTROL_DEREGISTER_SRVID, 0,
 			   tdb_null, NULL, NULL, &status, NULL, NULL);
 	if (res != 0 || status != 0) {
-		DEBUG(DEBUG_ERR,("Failed to deregister srvid %llu\n", (unsigned long long)srvid));
+		DEBUG(DEBUG_ERR,
+		      ("Failed to deregister srvid %llu\n",
+		       (unsigned long long)srvid));
 		return -1;
 	}
 
 	/* also need to register the handler with our own ctdb structure */
-	ctdb_deregister_message_handler(ctdb, srvid, private_data);
+	srvid_deregister(ctdb->srv, srvid, private_data);
 	return 0;
 }
 
@@ -552,12 +589,12 @@ int ctdb_client_check_message_handlers(struct ctdb_context *ctdb, uint64_t *ids,
 int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t pnn,
 		      uint64_t srvid, TDB_DATA data)
 {
-	struct ctdb_req_message *r;
+	struct ctdb_req_message_old *r;
 	int len, res;
 
-	len = offsetof(struct ctdb_req_message, data) + data.dsize;
+	len = offsetof(struct ctdb_req_message_old, data) + data.dsize;
 	r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_MESSAGE, 
-			       len, struct ctdb_req_message);
+			       len, struct ctdb_req_message_old);
 	CTDB_NO_MEMORY(ctdb, r);
 
 	r->hdr.destnode  = pnn;
@@ -922,8 +959,9 @@ int ctdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx,
    called when a control completes or timesout to invoke the callback
    function the user provided
 */
-static void invoke_control_callback(struct event_context *ev, struct timed_event *te, 
-	struct timeval t, void *private_data)
+static void invoke_control_callback(struct tevent_context *ev,
+				    struct tevent_timer *te,
+				    struct timeval t, void *private_data)
 {
 	struct ctdb_client_control_state *state;
 	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
@@ -952,10 +990,10 @@ static void invoke_control_callback(struct event_context *ev, struct timed_event
 static void ctdb_client_reply_control(struct ctdb_context *ctdb, 
 				      struct ctdb_req_header *hdr)
 {
-	struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
+	struct ctdb_reply_control_old *c = (struct ctdb_reply_control_old *)hdr;
 	struct ctdb_client_control_state *state;
 
-	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_control_state);
+	state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_client_control_state);
 	if (state == NULL) {
 		DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
 		return;
@@ -976,7 +1014,7 @@ static void ctdb_client_reply_control(struct ctdb_context *ctdb,
 						 c->errorlen);
 	}
 
-	/* state->outdata now uses resources from c so we dont want c
+	/* state->outdata now uses resources from c so we don't want c
 	   to just dissappear from under us while state is still alive
 	*/
 	talloc_steal(state, c);
@@ -987,7 +1025,8 @@ static void ctdb_client_reply_control(struct ctdb_context *ctdb,
 	   and call the callback.
 	*/
 	if (state->async.fn) {
-		event_add_timed(ctdb->ev, state, timeval_zero(), invoke_control_callback, state);
+		tevent_add_timer(ctdb->ev, state, timeval_zero(),
+				 invoke_control_callback, state);
 	}
 }
 
@@ -997,14 +1036,15 @@ static void ctdb_client_reply_control(struct ctdb_context *ctdb,
 */
 static int ctdb_client_control_destructor(struct ctdb_client_control_state *state)
 {
-	ctdb_reqid_remove(state->ctdb, state->reqid);
+	reqid_remove(state->ctdb->idr, state->reqid);
 	return 0;
 }
 
 
 /* time out handler for ctdb_control */
-static void control_timeout_func(struct event_context *ev, struct timed_event *te, 
-	struct timeval t, void *private_data)
+static void control_timeout_func(struct tevent_context *ev,
+				 struct tevent_timer *te,
+				 struct timeval t, void *private_data)
 {
 	struct ctdb_client_control_state *state = talloc_get_type(private_data, struct ctdb_client_control_state);
 
@@ -1018,7 +1058,8 @@ static void control_timeout_func(struct event_context *ev, struct timed_event *t
 	   and call the callback.
 	*/
 	if (state->async.fn) {
-		event_add_timed(state->ctdb->ev, state, timeval_zero(), invoke_control_callback, state);
+		tevent_add_timer(state->ctdb->ev, state, timeval_zero(),
+				 invoke_control_callback, state);
 	}
 }
 
@@ -1032,7 +1073,7 @@ struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb,
 {
 	struct ctdb_client_control_state *state;
 	size_t len;
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	int ret;
 
 	if (errormsg) {
@@ -1048,15 +1089,15 @@ struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb,
 	CTDB_NO_MEMORY_NULL(ctdb, state);
 
 	state->ctdb       = ctdb;
-	state->reqid      = ctdb_reqid_new(ctdb, state);
+	state->reqid      = reqid_new(ctdb->idr, state);
 	state->state      = CTDB_CONTROL_WAIT;
 	state->errormsg   = NULL;
 
 	talloc_set_destructor(state, ctdb_client_control_destructor);
 
-	len = offsetof(struct ctdb_req_control, data) + data.dsize;
+	len = offsetof(struct ctdb_req_control_old, data) + data.dsize;
 	c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CONTROL, 
-			       len, struct ctdb_req_control);
+			       len, struct ctdb_req_control_old);
 	state->c            = c;	
 	CTDB_NO_MEMORY_NULL(ctdb, c);
 	c->hdr.reqid        = state->reqid;
@@ -1072,7 +1113,8 @@ struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb,
 
 	/* timeout */
 	if (timeout && !timeval_is_zero(timeout)) {
-		event_add_timed(ctdb->ev, state, *timeout, control_timeout_func, state);
+		tevent_add_timer(ctdb->ev, state, *timeout,
+				 control_timeout_func, state);
 	}
 
 	ret = ctdb_client_queue_pkt(ctdb, &(c->hdr));
@@ -1117,7 +1159,7 @@ int ctdb_control_recv(struct ctdb_context *ctdb,
 	   completes.
 	*/
 	while (state->state == CTDB_CONTROL_WAIT) {
-		event_loop_once(ctdb->ev);
+		tevent_loop_once(ctdb->ev);
 	}
 
 	if (state->state != CTDB_CONTROL_DONE) {
@@ -1138,7 +1180,7 @@ int ctdb_control_recv(struct ctdb_context *ctdb,
 			state->async.fn(state);
 		}
 		talloc_free(tmp_ctx);
-		return -1;
+		return (status == 0 ? -1 : state->status);
 	}
 
 	if (outdata) {
@@ -1250,12 +1292,12 @@ int ctdb_ctrl_statistics(struct ctdb_context *ctdb, uint32_t destnode, struct ct
  * get db statistics
  */
 int ctdb_ctrl_dbstatistics(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
-			   TALLOC_CTX *mem_ctx, struct ctdb_db_statistics **dbstat)
+			   TALLOC_CTX *mem_ctx, struct ctdb_db_statistics_old **dbstat)
 {
 	int ret;
 	TDB_DATA indata, outdata;
 	int32_t res;
-	struct ctdb_db_statistics *wire, *s;
+	struct ctdb_db_statistics_old *wire, *s;
 	char *ptr;
 	int i;
 
@@ -1269,21 +1311,21 @@ int ctdb_ctrl_dbstatistics(struct ctdb_context *ctdb, uint32_t destnode, uint32_
 		return -1;
 	}
 
-	if (outdata.dsize < offsetof(struct ctdb_db_statistics, hot_keys_wire)) {
+	if (outdata.dsize < offsetof(struct ctdb_db_statistics_old, hot_keys_wire)) {
 		DEBUG(DEBUG_ERR,(__location__ " Wrong dbstatistics size %zi - expected >= %lu\n",
 				 outdata.dsize,
 				 (long unsigned int)sizeof(struct ctdb_statistics)));
 		return -1;
 	}
 
-	s = talloc_zero(mem_ctx, struct ctdb_db_statistics);
+	s = talloc_zero(mem_ctx, struct ctdb_db_statistics_old);
 	if (s == NULL) {
 		talloc_free(outdata.dptr);
 		CTDB_NO_MEMORY(ctdb, s);
 	}
 
-	wire = (struct ctdb_db_statistics *)outdata.dptr;
-	memcpy(s, wire, offsetof(struct ctdb_db_statistics, hot_keys_wire));
+	wire = (struct ctdb_db_statistics_old *)outdata.dptr;
+	memcpy(s, wire, offsetof(struct ctdb_db_statistics_old, hot_keys_wire));
 	ptr = &wire->hot_keys_wire[0];
 	for (i=0; i<wire->num_hot_keys; i++) {
 		s->hot_keys[i].key.dptr = talloc_size(mem_ctx, s->hot_keys[i].key.dsize);
@@ -1491,7 +1533,7 @@ int ctdb_ctrl_setrecmaster(struct ctdb_context *ctdb, struct timeval timeout, ui
   get a list of databases off a remote node
  */
 int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, 
-		       TALLOC_CTX *mem_ctx, struct ctdb_dbid_map **dbmap)
+		       TALLOC_CTX *mem_ctx, struct ctdb_dbid_map_old **dbmap)
 {
 	int ret;
 	TDB_DATA outdata;
@@ -1505,7 +1547,7 @@ int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, struct timeval timeout, uint32
 		return -1;
 	}
 
-	*dbmap = (struct ctdb_dbid_map *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+	*dbmap = (struct ctdb_dbid_map_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
 	talloc_free(outdata.dptr);
 		    
 	return 0;
@@ -1516,7 +1558,7 @@ int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, struct timeval timeout, uint32
  */
 int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb, 
 		struct timeval timeout, uint32_t destnode, 
-		TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap)
+		TALLOC_CTX *mem_ctx, struct ctdb_node_map_old **nodemap)
 {
 	int ret;
 	TDB_DATA outdata;
@@ -1530,7 +1572,7 @@ int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	*nodemap = (struct ctdb_node_map *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+	*nodemap = (struct ctdb_node_map_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
 	talloc_free(outdata.dptr);
 	return 0;
 }
@@ -1540,7 +1582,7 @@ int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb,
  */
 int ctdb_ctrl_getnodesfile(struct ctdb_context *ctdb,
 			   struct timeval timeout, uint32_t destnode,
-			   TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap)
+			   TALLOC_CTX *mem_ctx, struct ctdb_node_map_old **nodemap)
 {
 	int ret;
 	TDB_DATA outdata;
@@ -1554,7 +1596,7 @@ int ctdb_ctrl_getnodesfile(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	*nodemap = (struct ctdb_node_map *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+	*nodemap = (struct ctdb_node_map_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
 	talloc_free(outdata.dptr);
 
 	return 0;
@@ -1626,16 +1668,16 @@ struct ctdb_client_control_state *ctdb_ctrl_pulldb_send(
 	uint32_t lmaster, TALLOC_CTX *mem_ctx, struct timeval timeout)
 {
 	TDB_DATA indata;
-	struct ctdb_control_pulldb *pull;
+	struct ctdb_pulldb *pull;
 	struct ctdb_client_control_state *state;
 
-	pull = talloc(mem_ctx, struct ctdb_control_pulldb);
+	pull = talloc(mem_ctx, struct ctdb_pulldb);
 	CTDB_NO_MEMORY_NULL(ctdb, pull);
 
 	pull->db_id   = dbid;
 	pull->lmaster = lmaster;
 
-	indata.dsize = sizeof(struct ctdb_control_pulldb);
+	indata.dsize = sizeof(struct ctdb_pulldb);
 	indata.dptr  = (unsigned char *)pull;
 
 	state = ctdb_control_send(ctdb, destnode, 0, 
@@ -1978,7 +2020,7 @@ uint32_t *ctdb_get_connected_nodes(struct ctdb_context *ctdb,
 				TALLOC_CTX *mem_ctx,
 				uint32_t *num_nodes)
 {
-	struct ctdb_node_map *map=NULL;
+	struct ctdb_node_map_old *map=NULL;
 	int ret, i;
 	uint32_t *nodes;
 
@@ -2182,15 +2224,15 @@ struct traverse_state {
 /*
   called on each key during a ctdb_traverse
  */
-static void traverse_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data, void *p)
+static void traverse_handler(uint64_t srvid, TDB_DATA data, void *p)
 {
 	struct traverse_state *state = (struct traverse_state *)p;
-	struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr;
+	struct ctdb_rec_data_old *d = (struct ctdb_rec_data_old *)data.dptr;
 	TDB_DATA key;
 
-	if (data.dsize < sizeof(uint32_t) ||
-	    d->length != data.dsize) {
-		DEBUG(DEBUG_ERR,("Bad data size %u in traverse_handler\n", (unsigned)data.dsize));
+	if (data.dsize < sizeof(uint32_t) || d->length != data.dsize) {
+		DEBUG(DEBUG_ERR, ("Bad data size %u in traverse_handler\n",
+				  (unsigned)data.dsize));
 		state->done = true;
 		return;
 	}
@@ -2213,7 +2255,7 @@ static void traverse_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA
 		return;
 	}
 
-	if (state->fn(ctdb, key, data, state->private_data) != 0) {
+	if (state->fn(key, data, state->private_data) != 0) {
 		state->done = true;
 	}
 
@@ -2268,7 +2310,7 @@ static int ctdb_traverse_ext(struct ctdb_db_context *ctdb_db,
 	}
 
 	while (!state.done) {
-		event_loop_once(ctdb_db->ctdb->ev);
+		tevent_loop_once(ctdb_db->ctdb->ev);
 	}
 
 	ret = ctdb_client_remove_message_handler(ctdb_db->ctdb, srvid, &state);
@@ -2296,7 +2338,7 @@ int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *
 /*
   called on each key during a catdb
  */
-int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p)
+int ctdb_dumpdb_record(TDB_DATA key, TDB_DATA data, void *p)
 {
 	int i;
 	struct ctdb_dump_db_context *c = (struct ctdb_dump_db_context *)p;
@@ -2316,8 +2358,8 @@ int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, v
 	fprintf(f, "dmaster: %u\n", h->dmaster);
 	fprintf(f, "rsn: %llu\n", (unsigned long long)h->rsn);
 
-	if (c->printlmaster && ctdb->vnn_map != NULL) {
-		fprintf(f, "lmaster: %u\n", ctdb_lmaster(ctdb, &key));
+	if (c->printlmaster && c->ctdb->vnn_map != NULL) {
+		fprintf(f, "lmaster: %u\n", ctdb_lmaster(c->ctdb, &key));
 	}
 
 	if (c->printhash) {
@@ -2651,16 +2693,16 @@ int ctdb_ctrl_set_tunable(struct ctdb_context *ctdb,
 			  uint32_t destnode,
 			  const char *name, uint32_t value)
 {
-	struct ctdb_control_set_tunable *t;
+	struct ctdb_tunable_old *t;
 	TDB_DATA data;
 	int32_t res;
 	int ret;
 
-	data.dsize = offsetof(struct ctdb_control_set_tunable, name) + strlen(name) + 1;
+	data.dsize = offsetof(struct ctdb_tunable_old, name) + strlen(name) + 1;
 	data.dptr  = talloc_size(ctdb, data.dsize);
 	CTDB_NO_MEMORY(ctdb, data.dptr);
 
-	t = (struct ctdb_control_set_tunable *)data.dptr;
+	t = (struct ctdb_tunable_old *)data.dptr;
 	t->length = strlen(name)+1;
 	memcpy(t->name, name, t->length);
 	t->value = value;
@@ -2732,7 +2774,7 @@ int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
 				   struct timeval timeout, uint32_t destnode,
 				   TALLOC_CTX *mem_ctx,
 				   uint32_t flags,
-				   struct ctdb_all_public_ips **ips)
+				   struct ctdb_public_ip_list_old **ips)
 {
 	int ret;
 	TDB_DATA outdata;
@@ -2748,7 +2790,7 @@ int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	*ips = (struct ctdb_all_public_ips *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+	*ips = (struct ctdb_public_ip_list_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
 	talloc_free(outdata.dptr);
 
 	return 0;
@@ -2757,7 +2799,7 @@ int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
 int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
 			     struct timeval timeout, uint32_t destnode,
 			     TALLOC_CTX *mem_ctx,
-			     struct ctdb_all_public_ips **ips)
+			     struct ctdb_public_ip_list_old **ips)
 {
 	return ctdb_ctrl_get_public_ips_flags(ctdb, timeout,
 					      destnode, mem_ctx,
@@ -2768,13 +2810,13 @@ int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
 				 struct timeval timeout, uint32_t destnode,
 				 TALLOC_CTX *mem_ctx,
 				 const ctdb_sock_addr *addr,
-				 struct ctdb_control_public_ip_info **_info)
+				 struct ctdb_public_ip_info_old **_info)
 {
 	int ret;
 	TDB_DATA indata;
 	TDB_DATA outdata;
 	int32_t res;
-	struct ctdb_control_public_ip_info *info;
+	struct ctdb_public_ip_info_old *info;
 	uint32_t len;
 	uint32_t i;
 
@@ -2791,7 +2833,7 @@ int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	len = offsetof(struct ctdb_control_public_ip_info, ifaces);
+	len = offsetof(struct ctdb_public_ip_info_old, ifaces);
 	if (len > outdata.dsize) {
 		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
 				"returned invalid data with size %u > %u\n",
@@ -2801,8 +2843,8 @@ int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	info = (struct ctdb_control_public_ip_info *)outdata.dptr;
-	len += info->num*sizeof(struct ctdb_control_iface_info);
+	info = (struct ctdb_public_ip_info_old *)outdata.dptr;
+	len += info->num*sizeof(struct ctdb_iface);
 
 	if (len > outdata.dsize) {
 		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
@@ -2818,7 +2860,7 @@ int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
 		info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
 	}
 
-	*_info = (struct ctdb_control_public_ip_info *)talloc_memdup(mem_ctx,
+	*_info = (struct ctdb_public_ip_info_old *)talloc_memdup(mem_ctx,
 								outdata.dptr,
 								outdata.dsize);
 	talloc_free(outdata.dptr);
@@ -2835,12 +2877,12 @@ int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
 int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
 			 struct timeval timeout, uint32_t destnode,
 			 TALLOC_CTX *mem_ctx,
-			 struct ctdb_control_get_ifaces **_ifaces)
+			 struct ctdb_iface_list_old **_ifaces)
 {
 	int ret;
 	TDB_DATA outdata;
 	int32_t res;
-	struct ctdb_control_get_ifaces *ifaces;
+	struct ctdb_iface_list_old *ifaces;
 	uint32_t len;
 	uint32_t i;
 
@@ -2854,7 +2896,7 @@ int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	len = offsetof(struct ctdb_control_get_ifaces, ifaces);
+	len = offsetof(struct ctdb_iface_list_old, ifaces);
 	if (len > outdata.dsize) {
 		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
 				"returned invalid data with size %u > %u\n",
@@ -2864,8 +2906,8 @@ int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	ifaces = (struct ctdb_control_get_ifaces *)outdata.dptr;
-	len += ifaces->num*sizeof(struct ctdb_control_iface_info);
+	ifaces = (struct ctdb_iface_list_old *)outdata.dptr;
+	len += ifaces->num*sizeof(struct ctdb_iface);
 
 	if (len > outdata.dsize) {
 		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
@@ -2881,7 +2923,7 @@ int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
 		ifaces->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
 	}
 
-	*_ifaces = (struct ctdb_control_get_ifaces *)talloc_memdup(mem_ctx,
+	*_ifaces = (struct ctdb_iface_list_old *)talloc_memdup(mem_ctx,
 								  outdata.dptr,
 								  outdata.dsize);
 	talloc_free(outdata.dptr);
@@ -2898,7 +2940,7 @@ int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
 int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb,
 			     struct timeval timeout, uint32_t destnode,
 			     TALLOC_CTX *mem_ctx,
-			     const struct ctdb_control_iface_info *info)
+			     const struct ctdb_iface *info)
 {
 	int ret;
 	TDB_DATA indata;
@@ -2928,7 +2970,7 @@ int ctdb_ctrl_modflags(struct ctdb_context *ctdb, struct timeval timeout, uint32
 {
 	int ret;
 	TDB_DATA data;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	struct ctdb_node_flag_change c;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	uint32_t recmaster;
@@ -2988,10 +3030,10 @@ int ctdb_ctrl_modflags(struct ctdb_context *ctdb, struct timeval timeout, uint32
 /*
   get all tunables
  */
-int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb, 
-			       struct timeval timeout, 
+int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb,
+			       struct timeval timeout,
 			       uint32_t destnode,
-			       struct ctdb_tunable *tunables)
+			       struct ctdb_tunable_list *tunables)
 {
 	TDB_DATA outdata;
 	int ret;
@@ -3007,10 +3049,10 @@ int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb,
 	if (outdata.dsize != sizeof(*tunables)) {
 		DEBUG(DEBUG_ERR,(__location__ " bad data size %u in ctdb_ctrl_get_all_tunables should be %u\n",
 			 (unsigned)outdata.dsize, (unsigned)sizeof(*tunables)));
-		return -1;		
+		return -1;
 	}
 
-	*tunables = *(struct ctdb_tunable *)outdata.dptr;
+	*tunables = *(struct ctdb_tunable_list *)outdata.dptr;
 	talloc_free(outdata.dptr);
 	return 0;
 }
@@ -3018,16 +3060,15 @@ int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb,
 /*
   add a public address to a node
  */
-int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      uint32_t destnode,
-		      struct ctdb_control_ip_iface *pub)
+int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb,
+			    struct timeval timeout, uint32_t destnode,
+			    struct ctdb_addr_info_old *pub)
 {
 	TDB_DATA data;
 	int32_t res;
 	int ret;
 
-	data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len;
+	data.dsize = offsetof(struct ctdb_addr_info_old, iface) + pub->len;
 	data.dptr  = (unsigned char *)pub;
 
 	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_ADD_PUBLIC_IP, 0, data, NULL,
@@ -3043,16 +3084,15 @@ int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb,
 /*
   delete a public address from a node
  */
-int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      uint32_t destnode,
-		      struct ctdb_control_ip_iface *pub)
+int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb,
+			    struct timeval timeout, uint32_t destnode,
+			    struct ctdb_addr_info_old *pub)
 {
 	TDB_DATA data;
 	int32_t res;
 	int ret;
 
-	data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len;
+	data.dsize = offsetof(struct ctdb_addr_info_old, iface) + pub->len;
 	data.dptr  = (unsigned char *)pub;
 
 	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_DEL_PUBLIC_IP, 0, data, NULL,
@@ -3071,13 +3111,13 @@ int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb,
 int ctdb_ctrl_killtcp(struct ctdb_context *ctdb, 
 		      struct timeval timeout, 
 		      uint32_t destnode,
-		      struct ctdb_control_killtcp *killtcp)
+		      struct ctdb_connection *killtcp)
 {
 	TDB_DATA data;
 	int32_t res;
 	int ret;
 
-	data.dsize = sizeof(struct ctdb_control_killtcp);
+	data.dsize = sizeof(struct ctdb_connection);
 	data.dptr  = (unsigned char *)killtcp;
 
 	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_KILL_TCP, 0, data, NULL,
@@ -3093,22 +3133,20 @@ int ctdb_ctrl_killtcp(struct ctdb_context *ctdb,
 /*
   send a gratious arp
  */
-int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      uint32_t destnode,
-		      ctdb_sock_addr *addr,
-		      const char *ifname)
+int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb,
+			   struct timeval timeout, uint32_t destnode,
+			   ctdb_sock_addr *addr, const char *ifname)
 {
 	TDB_DATA data;
 	int32_t res;
 	int ret, len;
-	struct ctdb_control_gratious_arp *gratious_arp;
+	struct ctdb_addr_info_old *gratious_arp;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 
 
 	len = strlen(ifname)+1;
-	gratious_arp = talloc_size(tmp_ctx, 
-		offsetof(struct ctdb_control_gratious_arp, iface) + len);
+	gratious_arp = talloc_size(tmp_ctx,
+		offsetof(struct ctdb_addr_info_old, iface) + len);
 	CTDB_NO_MEMORY(ctdb, gratious_arp);
 
 	gratious_arp->addr = *addr;
@@ -3116,10 +3154,10 @@ int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb,
 	memcpy(&gratious_arp->iface[0], ifname, len);
 
 
-	data.dsize = offsetof(struct ctdb_control_gratious_arp, iface) + len;
+	data.dsize = offsetof(struct ctdb_addr_info_old, iface) + len;
 	data.dptr  = (unsigned char *)gratious_arp;
 
-	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SEND_GRATIOUS_ARP, 0, data, NULL,
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SEND_GRATUITOUS_ARP, 0, data, NULL,
 			   NULL, &res, &timeout, NULL);
 	if (ret != 0 || res != 0) {
 		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for gratious_arp failed\n"));
@@ -3138,7 +3176,7 @@ int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb,
 			      struct timeval timeout, uint32_t destnode, 
 			      TALLOC_CTX *mem_ctx, 
 			      ctdb_sock_addr *addr,
-			      struct ctdb_control_tcp_tickle_list **list)
+			      struct ctdb_tickle_list_old **list)
 {
 	int ret;
 	TDB_DATA data, outdata;
@@ -3155,7 +3193,7 @@ int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	*list = (struct ctdb_control_tcp_tickle_list *)outdata.dptr;
+	*list = (struct ctdb_tickle_list_old *)outdata.dptr;
 
 	return status;
 }
@@ -3163,15 +3201,15 @@ int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb,
 /*
   register a server id
  */
-int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      struct ctdb_server_id *id)
+int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb,
+				 struct timeval timeout,
+				 struct ctdb_client_id *id)
 {
 	TDB_DATA data;
 	int32_t res;
 	int ret;
 
-	data.dsize = sizeof(struct ctdb_server_id);
+	data.dsize = sizeof(struct ctdb_client_id);
 	data.dptr  = (unsigned char *)id;
 
 	ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, 
@@ -3189,15 +3227,15 @@ int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb,
 /*
   unregister a server id
  */
-int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      struct ctdb_server_id *id)
+int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb,
+				   struct timeval timeout,
+				   struct ctdb_client_id *id)
 {
 	TDB_DATA data;
 	int32_t res;
 	int ret;
 
-	data.dsize = sizeof(struct ctdb_server_id);
+	data.dsize = sizeof(struct ctdb_client_id);
 	data.dptr  = (unsigned char *)id;
 
 	ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, 
@@ -3218,17 +3256,15 @@ int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb,
 
   if a server id does exist, return *status == 1, otherwise *status == 0
  */
-int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      uint32_t destnode,
-		      struct ctdb_server_id *id,
-		      uint32_t *status)
+int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb,
+			      struct timeval timeout, uint32_t destnode,
+			      struct ctdb_client_id *id, uint32_t *status)
 {
 	TDB_DATA data;
 	int32_t res;
 	int ret;
 
-	data.dsize = sizeof(struct ctdb_server_id);
+	data.dsize = sizeof(struct ctdb_client_id);
 	data.dptr  = (unsigned char *)id;
 
 	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_CHECK_SERVER_ID, 
@@ -3252,9 +3288,9 @@ int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb,
    get the list of server ids that are registered on a node
 */
 int ctdb_ctrl_get_server_id_list(struct ctdb_context *ctdb,
-		TALLOC_CTX *mem_ctx,
-		struct timeval timeout, uint32_t destnode, 
-		struct ctdb_server_id_list **svid_list)
+				 TALLOC_CTX *mem_ctx,
+				 struct timeval timeout, uint32_t destnode,
+				 struct ctdb_client_id_list_old **svid_list)
 {
 	int ret;
 	TDB_DATA outdata;
@@ -3268,8 +3304,8 @@ int ctdb_ctrl_get_server_id_list(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	*svid_list = (struct ctdb_server_id_list *)talloc_steal(mem_ctx, outdata.dptr);
-		    
+	*svid_list = (struct ctdb_client_id_list_old *)talloc_steal(mem_ctx, outdata.dptr);
+
 	return 0;
 }
 
@@ -3279,7 +3315,7 @@ int ctdb_ctrl_get_server_id_list(struct ctdb_context *ctdb,
   NOTE: In current code the daemon does not fork. This is for testing purposes only
   and to simplify the code.
 */
-struct ctdb_context *ctdb_init(struct event_context *ev)
+struct ctdb_context *ctdb_init(struct tevent_context *ev)
 {
 	int ret;
 	struct ctdb_context *ctdb;
@@ -3290,10 +3326,20 @@ struct ctdb_context *ctdb_init(struct event_context *ev)
 		return NULL;
 	}
 	ctdb->ev  = ev;
-	ctdb->idr = idr_init(ctdb);
 	/* Wrap early to exercise code. */
-	ctdb->lastid = INT_MAX-200;
-	CTDB_NO_MEMORY_NULL(ctdb, ctdb->idr);
+	ret = reqid_init(ctdb, INT_MAX-200, &ctdb->idr);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("reqid_init failed (%s)\n", strerror(ret)));
+		talloc_free(ctdb);
+		return NULL;
+	}
+
+	ret = srvid_init(ctdb, &ctdb->srv);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("srvid_init failed (%s)\n", strerror(ret)));
+		talloc_free(ctdb);
+		return NULL;
+	}
 
 	ret = ctdb_set_socketname(ctdb, CTDB_SOCKET);
 	if (ret != 0) {
@@ -3472,7 +3518,7 @@ void ctdb_client_async_add(struct client_async_data *data, struct ctdb_client_co
 int ctdb_client_async_wait(struct ctdb_context *ctdb, struct client_async_data *data)
 {
 	while (data->count > 0) {
-		event_loop_once(ctdb->ev);
+		tevent_loop_once(ctdb->ev);
 	}
 	if (data->fail_count != 0) {
 		if (!data->dont_log_errors) {
@@ -3570,7 +3616,7 @@ uint32_t *list_of_vnnmap_nodes(struct ctdb_context *ctdb,
  * If exclude_pnn is not -1 then exclude that pnn from the list.
  */
 uint32_t *list_of_nodes(struct ctdb_context *ctdb,
-			struct ctdb_node_map *node_map,
+			struct ctdb_node_map_old *node_map,
 			TALLOC_CTX *mem_ctx,
 			uint32_t mask,
 			int exclude_pnn)
@@ -3605,7 +3651,7 @@ uint32_t *list_of_nodes(struct ctdb_context *ctdb,
 }
 
 uint32_t *list_of_active_nodes(struct ctdb_context *ctdb,
-				struct ctdb_node_map *node_map,
+				struct ctdb_node_map_old *node_map,
 				TALLOC_CTX *mem_ctx,
 				bool include_self)
 {
@@ -3614,7 +3660,7 @@ uint32_t *list_of_active_nodes(struct ctdb_context *ctdb,
 }
 
 uint32_t *list_of_connected_nodes(struct ctdb_context *ctdb,
-				struct ctdb_node_map *node_map,
+				struct ctdb_node_map_old *node_map,
 				TALLOC_CTX *mem_ctx,
 				bool include_self)
 {
@@ -3725,13 +3771,13 @@ struct ctdb_node_capabilities *
 ctdb_get_capabilities(struct ctdb_context *ctdb,
 		      TALLOC_CTX *mem_ctx,
 		      struct timeval timeout,
-		      struct ctdb_node_map *nodemap)
+		      struct ctdb_node_map_old *nodemap)
 {
 	uint32_t *nodes;
 	uint32_t i, res;
 	struct ctdb_node_capabilities *ret;
 
-	nodes = list_of_connected_nodes(ctdb, nodemap, mem_ctx, true);
+	nodes = list_of_active_nodes(ctdb, nodemap, mem_ctx, true);
 
 	ret = talloc_array(mem_ctx, struct ctdb_node_capabilities,
 			   nodemap->num);
@@ -3776,16 +3822,9 @@ bool ctdb_node_has_capabilities(struct ctdb_node_capabilities *caps,
 }
 
 
-struct server_id {
-	uint64_t pid;
-	uint32_t task_id;
-	uint32_t vnn;
-	uint64_t unique_id;
-};
-
-static struct server_id server_id_fetch(struct ctdb_context *ctdb, uint32_t reqid)
+static struct ctdb_server_id server_id_fetch(struct ctdb_context *ctdb, uint32_t reqid)
 {
-	struct server_id id;
+	struct ctdb_server_id id;
 
 	id.pid = getpid();
 	id.task_id = reqid;
@@ -3799,7 +3838,7 @@ static struct server_id server_id_fetch(struct ctdb_context *ctdb, uint32_t reqi
 /* This is basically a copy from Samba's server_id.*.  However, a
  * dependency chain stops us from using Samba's version, so use a
  * renamed copy until a better solution is found. */
-static bool ctdb_server_id_equal(struct server_id *id1, struct server_id *id2)
+static bool ctdb_server_id_equal(struct ctdb_server_id *id1, struct ctdb_server_id *id2)
 {
 	if (id1->pid != id2->pid) {
 		return false;
@@ -3820,9 +3859,9 @@ static bool ctdb_server_id_equal(struct server_id *id1, struct server_id *id2)
 	return true;
 }
 
-static bool server_id_exists(struct ctdb_context *ctdb, struct server_id *id)
+static bool server_id_exists(struct ctdb_context *ctdb, struct ctdb_server_id *id)
 {
-	struct ctdb_server_id sid;
+	struct ctdb_client_id sid;
 	int ret;
 	uint32_t result = 0;
 
@@ -3844,28 +3883,12 @@ static bool server_id_exists(struct ctdb_context *ctdb, struct server_id *id)
 	return false;
 }
 
-
-enum g_lock_type {
-	G_LOCK_READ = 0,
-	G_LOCK_WRITE = 1,
-};
-
-struct g_lock_rec {
-	enum g_lock_type type;
-	struct server_id id;
-};
-
-struct g_lock_recs {
-	unsigned int num;
-	struct g_lock_rec *lock;
-};
-
 static bool g_lock_parse(TALLOC_CTX *mem_ctx, TDB_DATA data,
-			 struct g_lock_recs **locks)
+			 struct ctdb_g_lock_list **locks)
 {
-	struct g_lock_recs *recs;
+	struct ctdb_g_lock_list *recs;
 
-	recs = talloc_zero(mem_ctx, struct g_lock_recs);
+	recs = talloc_zero(mem_ctx, struct ctdb_g_lock_list);
 	if (recs == NULL) {
 		return false;
 	}
@@ -3874,14 +3897,14 @@ static bool g_lock_parse(TALLOC_CTX *mem_ctx, TDB_DATA data,
 		goto done;
 	}
 
-	if (data.dsize % sizeof(struct g_lock_rec) != 0) {
+	if (data.dsize % sizeof(struct ctdb_g_lock) != 0) {
 		DEBUG(DEBUG_ERR, (__location__ "invalid data size %lu in g_lock record\n",
 				  (unsigned long)data.dsize));
 		talloc_free(recs);
 		return false;
 	}
 
-	recs->num = data.dsize / sizeof(struct g_lock_rec);
+	recs->num = data.dsize / sizeof(struct ctdb_g_lock);
 	recs->lock = talloc_memdup(mem_ctx, data.dptr, data.dsize);
 	if (recs->lock == NULL) {
 		talloc_free(recs);
@@ -3903,8 +3926,8 @@ static bool g_lock_lock(TALLOC_CTX *mem_ctx,
 {
 	TDB_DATA key, data;
 	struct ctdb_record_handle *h;
-	struct g_lock_recs *locks;
-	struct server_id id;
+	struct ctdb_g_lock_list *locks;
+	struct ctdb_server_id id;
 	struct timeval t_start;
 	int i;
 
@@ -3937,13 +3960,13 @@ again:
 
 	i = 0;
 	while (i < locks->num) {
-		if (ctdb_server_id_equal(&locks->lock[i].id, &id)) {
+		if (ctdb_server_id_equal(&locks->lock[i].sid, &id)) {
 			/* Internal error */
 			talloc_free(h);
 			return false;
 		}
 
-		if (!server_id_exists(ctdb_db->ctdb, &locks->lock[i].id)) {
+		if (!server_id_exists(ctdb_db->ctdb, &locks->lock[i].sid)) {
 			if (i < locks->num-1) {
 				locks->lock[i] = locks->lock[locks->num-1];
 			}
@@ -3961,19 +3984,19 @@ again:
 		goto again;
 	}
 
-	locks->lock = talloc_realloc(locks, locks->lock, struct g_lock_rec,
+	locks->lock = talloc_realloc(locks, locks->lock, struct ctdb_g_lock,
 				     locks->num+1);
 	if (locks->lock == NULL) {
 		talloc_free(h);
 		return false;
 	}
 
-	locks->lock[locks->num].type = G_LOCK_WRITE;
-	locks->lock[locks->num].id = id;
+	locks->lock[locks->num].type = CTDB_G_LOCK_WRITE;
+	locks->lock[locks->num].sid = id;
 	locks->num++;
 
 	data.dptr = (uint8_t *)locks->lock;
-	data.dsize = locks->num * sizeof(struct g_lock_rec);
+	data.dsize = locks->num * sizeof(struct ctdb_g_lock);
 
 	if (ctdb_record_store(h, data) != 0) {
 		DEBUG(DEBUG_ERR, ("g_lock: failed to write transaction lock for "
@@ -4001,8 +4024,8 @@ static bool g_lock_unlock(TALLOC_CTX *mem_ctx,
 {
 	TDB_DATA key, data;
 	struct ctdb_record_handle *h;
-	struct g_lock_recs *locks;
-	struct server_id id;
+	struct ctdb_g_lock_list *locks;
+	struct ctdb_server_id id;
 	int i;
 	bool found = false;
 
@@ -4025,7 +4048,7 @@ static bool g_lock_unlock(TALLOC_CTX *mem_ctx,
 	id = server_id_fetch(ctdb_db->ctdb, reqid);
 
 	for (i=0; i<locks->num; i++) {
-		if (ctdb_server_id_equal(&locks->lock[i].id, &id)) {
+		if (ctdb_server_id_equal(&locks->lock[i].sid, &id)) {
 			if (i < locks->num-1) {
 				locks->lock[i] = locks->lock[locks->num-1];
 			}
@@ -4042,7 +4065,7 @@ static bool g_lock_unlock(TALLOC_CTX *mem_ctx,
 	}
 
 	data.dptr = (uint8_t *)locks->lock;
-	data.dsize = locks->num * sizeof(struct g_lock_rec);
+	data.dsize = locks->num * sizeof(struct ctdb_g_lock);
 
 	if (ctdb_record_store(h, data) != 0) {
 		talloc_free(h);
@@ -4071,7 +4094,7 @@ struct ctdb_transaction_handle {
 static int ctdb_transaction_destructor(struct ctdb_transaction_handle *h)
 {
 	g_lock_unlock(h, h->g_lock_db, h->lock_name, h->reqid);
-	ctdb_reqid_remove(h->ctdb_db->ctdb, h->reqid);
+	reqid_remove(h->ctdb_db->ctdb->idr, h->reqid);
 	return 0;
 }
 
@@ -4083,7 +4106,7 @@ struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *c
 						       TALLOC_CTX *mem_ctx)
 {
 	struct ctdb_transaction_handle *h;
-	struct ctdb_server_id id;
+	struct ctdb_client_id id;
 
 	h = talloc_zero(mem_ctx, struct ctdb_transaction_handle);
 	if (h == NULL) {
@@ -4119,7 +4142,7 @@ struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *c
 		return NULL;
 	}
 
-	h->reqid = ctdb_reqid_new(h->ctdb_db->ctdb, h);
+	h->reqid = reqid_new(h->ctdb_db->ctdb->idr, h);
 
 	if (!g_lock_lock(h, h->g_lock_db, h->lock_name, h->reqid)) {
 		DEBUG(DEBUG_ERR, (__location__ " Error locking g_lock.tdb\n"));
@@ -4365,45 +4388,14 @@ int ctdb_ctrl_recd_ping(struct ctdb_context *ctdb)
 	return 0;
 }
 
-/* When forking the main daemon and the child process needs to connect
- * back to the daemon as a client process, this function can be used
- * to change the ctdb context from daemon into client mode.  The child
- * process must be created using ctdb_fork() and not fork() -
- * ctdb_fork() does some necessary housekeeping.
- */
-int switch_from_server_to_client(struct ctdb_context *ctdb, const char *fmt, ...)
-{
-	int ret;
-	va_list ap;
-
-	/* Add extra information so we can identify this in the logs */
-	va_start(ap, fmt);
-	debug_extra = talloc_strdup_append(talloc_vasprintf(NULL, fmt, ap), ":");
-	va_end(ap);
-
-	/* get a new event context */
-	ctdb->ev = event_context_init(ctdb);
-	tevent_loop_allow_nesting(ctdb->ev);
-
-	/* Connect to main CTDB daemon */
-	ret = ctdb_socket_connect(ctdb);
-	if (ret != 0) {
-		DEBUG(DEBUG_ALERT, (__location__ " Failed to init ctdb client\n"));
-		return -1;
-	}
-
-	ctdb->can_send_controls = true;
-
-	return 0;
-}
-
 /*
   get the status of running the monitor eventscripts: NULL means never run.
  */
-int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb, 
-		struct timeval timeout, uint32_t destnode, 
-		TALLOC_CTX *mem_ctx, enum ctdb_eventscript_call type,
-		struct ctdb_scripts_wire **scripts)
+int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb,
+			      struct timeval timeout, uint32_t destnode,
+			      TALLOC_CTX *mem_ctx,
+			      enum ctdb_event type,
+			      struct ctdb_script_list_old **scripts)
 {
 	int ret;
 	TDB_DATA outdata, indata;
@@ -4424,10 +4416,10 @@ int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb,
 	if (outdata.dsize == 0) {
 		*scripts = NULL;
 	} else {
-		*scripts = (struct ctdb_scripts_wire *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+		*scripts = (struct ctdb_script_list_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
 		talloc_free(outdata.dptr);
 	}
-		    
+
 	return 0;
 }
 
@@ -4658,7 +4650,8 @@ int ctdb_ctrl_disablescript(struct ctdb_context *ctdb, struct timeval timeout, u
 }
 
 
-int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_ban_time *bantime)
+int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout,
+		      uint32_t destnode, struct ctdb_ban_state *bantime)
 {
 	int ret;
 	TDB_DATA data;
@@ -4679,7 +4672,9 @@ int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_
 }
 
 
-int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_ban_time **bantime)
+int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout,
+		      uint32_t destnode, TALLOC_CTX *mem_ctx,
+		      struct ctdb_ban_state **bantime)
 {
 	int ret;
 	TDB_DATA outdata;
@@ -4695,7 +4690,7 @@ int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_
 		return -1;
 	}
 
-	*bantime = (struct ctdb_ban_time *)talloc_steal(mem_ctx, outdata.dptr);
+	*bantime = (struct ctdb_ban_state *)talloc_steal(mem_ctx, outdata.dptr);
 	talloc_free(tmp_ctx);
 
 	return 0;
@@ -4754,7 +4749,10 @@ int ctdb_ctrl_get_db_priority(struct ctdb_context *ctdb, struct timeval timeout,
 	return 0;
 }
 
-int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_statistics_wire **stats)
+int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb,
+			     struct timeval timeout, uint32_t destnode,
+			     TALLOC_CTX *mem_ctx,
+			     struct ctdb_statistics_list_old **stats)
 {
 	int ret;
 	TDB_DATA outdata;
@@ -4768,9 +4766,11 @@ int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb, struct timeval timeout,
 		return -1;
 	}
 
-	*stats = (struct ctdb_statistics_wire *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+	*stats = (struct ctdb_statistics_list_old *)talloc_memdup(mem_ctx,
+								  outdata.dptr,
+								  outdata.dsize);
 	talloc_free(outdata.dptr);
-		    
+
 	return 0;
 }
 
@@ -4789,7 +4789,7 @@ ctdb_ctrl_updaterecord_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, stru
 {
 	struct ctdb_client_control_state *handle;
 	struct ctdb_marshall_buffer *m;
-	struct ctdb_rec_data *rec;
+	struct ctdb_rec_data_old *rec;
 	TDB_DATA outdata;
 
 	m = talloc_zero(mem_ctx, struct ctdb_marshall_buffer);
diff --git a/ctdb/common/cmdline.c b/ctdb/common/cmdline.c
index 7fcb91f..02083e8 100644
--- a/ctdb/common/cmdline.c
+++ b/ctdb/common/cmdline.c
@@ -17,15 +17,25 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
+#include "system/network.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
 #include <ctype.h>
 
-#include "internal/cmdline.h"
+#include "lib/util/debug.h"
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/rb_tree.h"
+#include "common/common.h"
+#include "common/logging.h"
+#include "common/cmdline.h"
+
+
 
 /* Handle common command line options for ctdb test progs
  */
@@ -49,7 +59,7 @@ static void ctdb_cmdline_callback(poptContext con,
 {
 	switch (opt->val) {
 	case OPT_EVENTSYSTEM:
-		event_set_default_backend(arg);
+		tevent_set_default_backend(arg);
 		break;
 	}
 }
@@ -68,9 +78,10 @@ struct poptOption popt_ctdb_cmdline[] = {
 /*
   startup daemon side of ctdb according to command line options
  */
-struct ctdb_context *ctdb_cmdline_init(struct event_context *ev)
+struct ctdb_context *ctdb_cmdline_init(struct tevent_context *ev)
 {
 	struct ctdb_context *ctdb;
+	enum debug_level log_level;
 	int ret;
 
 	/* initialise ctdb */
@@ -96,8 +107,10 @@ struct ctdb_context *ctdb_cmdline_init(struct event_context *ev)
 	}
 
 	/* Set the debug level */
-	if (!parse_debug(ctdb_cmdline.debuglevel, &DEBUGLEVEL)) {
-		DEBUGLEVEL = DEBUG_NOTICE;
+	if (debug_level_parse(ctdb_cmdline.debuglevel, &log_level)) {
+		DEBUGLEVEL = debug_level_to_int(log_level);
+	} else {
+		DEBUGLEVEL = debug_level_to_int(DEBUG_NOTICE);
 	}
 
 	/* set up the tree to store server ids */
@@ -114,6 +127,7 @@ struct ctdb_context *ctdb_cmdline_client(struct tevent_context *ev,
 					 struct timeval req_timeout)
 {
 	struct ctdb_context *ctdb;
+	enum debug_level log_level;
 	char *socket_name;
 	int ret;
 
@@ -145,8 +159,10 @@ struct ctdb_context *ctdb_cmdline_client(struct tevent_context *ev,
 	}
 
 	/* Set the debug level */
-	if (!parse_debug(ctdb_cmdline.debuglevel, &DEBUGLEVEL)) {
-		DEBUGLEVEL = DEBUG_NOTICE;
+	if (debug_level_parse(ctdb_cmdline.debuglevel, &log_level)) {
+		DEBUGLEVEL = debug_level_to_int(log_level);
+	} else {
+		DEBUGLEVEL = debug_level_to_int(DEBUG_NOTICE);
 	}
 
 	ret = ctdb_socket_connect(ctdb);
diff --git a/ctdb/common/cmdline.h b/ctdb/common/cmdline.h
new file mode 100644
index 0000000..0285b4d
--- /dev/null
+++ b/ctdb/common/cmdline.h
@@ -0,0 +1,13 @@
+#ifndef CTDB_CMDLINE_H
+#define CTDB_CMDLINE_H
+
+extern struct poptOption popt_ctdb_cmdline[];
+
+#define POPT_CTDB_CMDLINE { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_ctdb_cmdline, 0, "Common ctdb options:", NULL },
+
+struct ctdb_context *ctdb_cmdline_init(struct tevent_context *ev);
+
+struct ctdb_context *ctdb_cmdline_client(struct tevent_context *ev,
+					 struct timeval req_timeout);
+
+#endif /* CTDB_CMDLINE_H */
diff --git a/ctdb/common/comm.c b/ctdb/common/comm.c
new file mode 100644
index 0000000..1bbb460
--- /dev/null
+++ b/ctdb/common/comm.c
@@ -0,0 +1,404 @@
+/*
+   Communication endpoint implementation
+
+   Copyright (C) Amitay Isaacs 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "lib/util/tevent_unix.h"
+
+#include "pkt_read.h"
+#include "pkt_write.h"
+#include "comm.h"
+
+static bool set_nonblocking(int fd)
+{
+	int v;
+
+	v = fcntl(fd, F_GETFL, 0);
+	if (v == -1) {
+		return false;
+	}
+        if (fcntl(fd, F_SETFL, v | O_NONBLOCK) == -1) {
+		return false;
+	}
+	return true;
+}
+
+/*
+ * Communication endpoint around a socket
+ */
+
+#define SMALL_PKT_SIZE	1024
+
+struct comm_context {
+	int fd;
+	comm_read_handler_fn read_handler;
+	void *read_private_data;
+	comm_dead_handler_fn dead_handler;
+	void *dead_private_data;
+	uint8_t small_pkt[SMALL_PKT_SIZE];
+	struct tevent_req *read_req, *write_req;
+	struct tevent_fd *fde;
+	struct tevent_queue *queue;
+};
+
+static void comm_fd_handler(struct tevent_context *ev,
+			    struct tevent_fd *fde,
+			    uint16_t flags, void *private_data);
+static struct tevent_req *comm_read_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct comm_context *comm,
+					 uint8_t *buf, size_t buflen);
+static void comm_read_failed(struct tevent_req *req);
+
+
+int comm_setup(TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd,
+	       comm_read_handler_fn read_handler, void *read_private_data,
+	       comm_dead_handler_fn dead_handler, void *dead_private_data,
+	       struct comm_context **result)
+{
+	struct comm_context *comm;
+
+	if (fd < 0) {
+		return EINVAL;
+	}
+
+	if (dead_handler == NULL) {
+		return EINVAL;
+	}
+
+	/* Socket queue relies on non-blocking sockets. */
+	if (!set_nonblocking(fd)) {
+		return EIO;
+	}
+
+	comm = talloc_zero(mem_ctx, struct comm_context);
+	if (comm == NULL) {
+		return ENOMEM;
+	}
+
+	comm->fd = fd;
+	comm->read_handler = read_handler;
+	comm->read_private_data = read_private_data;
+	comm->dead_handler = dead_handler;
+	comm->dead_private_data = dead_private_data;
+
+	comm->queue = tevent_queue_create(comm, "comm write queue");
+	if (comm->queue == NULL) {
+		goto fail;
+	}
+
+	/* Set up to write packets */
+	comm->fde = tevent_add_fd(ev, comm, fd, TEVENT_FD_READ,
+				  comm_fd_handler, comm);
+	if (comm->fde == NULL) {
+		goto fail;
+	}
+
+	/* Set up to read packets */
+	if (read_handler != NULL) {
+		struct tevent_req *req;
+
+		req = comm_read_send(comm, ev, comm, comm->small_pkt,
+				     SMALL_PKT_SIZE);
+		if (req == NULL) {
+			goto fail;
+		}
+
+		tevent_req_set_callback(req, comm_read_failed, comm);
+		comm->read_req = req;
+	}
+
+	*result = comm;
+	return 0;
+
+fail:
+	talloc_free(comm);
+	return ENOMEM;
+}
+
+
+/*
+ * Read packets
+ */
+
+struct comm_read_state {
+	struct tevent_context *ev;
+	struct comm_context *comm;
+	uint8_t *buf;
+	size_t buflen;
+	struct tevent_req *subreq;
+};
+
+static ssize_t comm_read_more(uint8_t *buf, size_t buflen, void *private_data);
+static void comm_read_done(struct tevent_req *subreq);
+
+static struct tevent_req *comm_read_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct comm_context *comm,
+					 uint8_t *buf, size_t buflen)
+{
+	struct tevent_req *req, *subreq;
+	struct comm_read_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct comm_read_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->comm = comm;
+	state->buf = buf;
+	state->buflen = buflen;
+
+	subreq = pkt_read_send(state, state->ev, comm->fd, sizeof(uint32_t),
+			       state->buf, state->buflen,
+			       comm_read_more, NULL);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	state->subreq = subreq;
+
+	tevent_req_set_callback(subreq, comm_read_done, req);
+	return req;
+}
+
+static ssize_t comm_read_more(uint8_t *buf, size_t buflen, void *private_data)
+{
+	uint32_t packet_len;
+
+	if (buflen < sizeof(uint32_t)) {
+		return sizeof(uint32_t) - buflen;
+	}
+
+	packet_len = *(uint32_t *)buf;
+
+	return packet_len - buflen;
+}
+
+static void comm_read_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct comm_read_state *state = tevent_req_data(
+		req, struct comm_read_state);
+	struct comm_context *comm = state->comm;
+	ssize_t nread;
+	uint8_t *buf;
+	bool free_buf;
+	int err = 0;
+
+	nread = pkt_read_recv(subreq, state, &buf, &free_buf, &err);
+	TALLOC_FREE(subreq);
+	state->subreq = NULL;
+	if (nread == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	comm->read_handler(buf, nread, comm->read_private_data);
+
+	if (free_buf) {
+		talloc_free(buf);
+	}
+
+	subreq = pkt_read_send(state, state->ev, comm->fd, sizeof(uint32_t),
+			       state->buf, state->buflen,
+			       comm_read_more, NULL);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	state->subreq = subreq;
+
+	tevent_req_set_callback(subreq, comm_read_done, req);
+}
+
+static void comm_read_recv(struct tevent_req *req, int *perr)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+	}
+}
+
+static void comm_read_failed(struct tevent_req *req)
+{
+	struct comm_context *comm = tevent_req_callback_data(
+		req, struct comm_context);
+
+	comm_read_recv(req, NULL);
+	TALLOC_FREE(req);
+	comm->read_req = NULL;
+	if (comm->dead_handler != NULL) {
+		comm->dead_handler(comm->dead_private_data);
+	}
+}
+
+
+/*
+ * Write packets
+ */
+
+struct comm_write_state {
+	struct tevent_context *ev;
+	struct comm_context *comm;
+	struct tevent_req *subreq;
+	uint8_t *buf;
+	size_t buflen, nwritten;
+};
+
+static void comm_write_trigger(struct tevent_req *req, void *private_data);
+static void comm_write_done(struct tevent_req *subreq);
+
+struct tevent_req *comm_write_send(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct comm_context *comm,
+				   uint8_t *buf, size_t buflen)
+{
+	struct tevent_req *req;
+	struct comm_write_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct comm_write_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->comm = comm;
+	state->buf = buf;
+	state->buflen = buflen;
+
+	if (!tevent_queue_add_entry(comm->queue, ev, req,
+				    comm_write_trigger, NULL)) {
+		talloc_free(req);
+		return NULL;
+	}
+
+	return req;
+}
+
+static void comm_write_trigger(struct tevent_req *req, void *private_data)
+{
+	struct comm_write_state *state = tevent_req_data(
+		req, struct comm_write_state);
+	struct comm_context *comm = state->comm;
+	struct tevent_req *subreq;
+
+	comm->write_req = req;
+
+	subreq = pkt_write_send(state, state->ev, comm->fd,
+				state->buf, state->buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+
+	state->subreq = subreq;
+	tevent_req_set_callback(subreq, comm_write_done, req);
+	TEVENT_FD_WRITEABLE(comm->fde);
+}
+
+static void comm_write_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct comm_write_state *state = tevent_req_data(
+		req, struct comm_write_state);
+	struct comm_context *comm = state->comm;
+	ssize_t nwritten;
+	int err = 0;
+
+	TEVENT_FD_NOT_WRITEABLE(comm->fde);
+	nwritten = pkt_write_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	state->subreq = NULL;
+	comm->write_req = NULL;
+	if (nwritten == -1) {
+		if (err == EPIPE) {
+			comm->dead_handler(comm->dead_private_data);
+		}
+		tevent_req_error(req, err);
+		return;
+	}
+
+	state->nwritten = nwritten;
+	tevent_req_done(req);
+}
+
+bool comm_write_recv(struct tevent_req *req, int *perr)
+{
+	struct comm_write_state *state = tevent_req_data(
+		req, struct comm_write_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	if (state->nwritten != state->buflen) {
+		*perr = EIO;
+		return false;
+	}
+
+	*perr = 0;
+	return true;
+}
+
+static void comm_fd_handler(struct tevent_context *ev,
+			    struct tevent_fd *fde,
+			    uint16_t flags, void *private_data)
+{
+	struct comm_context *comm = talloc_get_type_abort(
+		private_data, struct comm_context);
+
+	if (flags & TEVENT_FD_READ) {
+		struct comm_read_state *read_state;
+
+		if (comm->read_req == NULL) {
+			/* This should never happen */
+			abort();
+		}
+
+		read_state = tevent_req_data(comm->read_req,
+					     struct comm_read_state);
+		pkt_read_handler(ev, fde, flags, read_state->subreq);
+	}
+
+	if (flags & TEVENT_FD_WRITE) {
+		struct comm_write_state *write_state;
+
+		if (comm->write_req == NULL) {
+			/* This should never happen */
+			abort();
+		}
+
+		write_state = tevent_req_data(comm->write_req,
+					      struct comm_write_state);
+		pkt_write_handler(ev, fde, flags, write_state->subreq);
+	}
+}
diff --git a/ctdb/common/comm.h b/ctdb/common/comm.h
new file mode 100644
index 0000000..27021e9
--- /dev/null
+++ b/ctdb/common/comm.h
@@ -0,0 +1,101 @@
+/*
+   Communication endpoint API
+
+   Copyright (C) Amitay Isaacs 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_COMM_H__
+#define __CTDB_COMM_H__
+
+#include <talloc.h>
+#include <tevent.h>
+
+/**
+ * @file comm.h
+ *
+ * @brief Communication over a socket or file descriptor
+ *
+ * This abstraction is a wrapper around a socket or file descriptor to
+ * send/receive complete packets.
+ */
+
+/**
+ * @brief Packet handler function
+ *
+ * This function is registered while setting up communication endpoint.  Any
+ * time packets are read, this function is called.
+ */
+typedef void (*comm_read_handler_fn)(uint8_t *buf, size_t buflen,
+				     void *private_data);
+
+/**
+ * @brief Communication endpoint dead handler function
+ *
+ * This function is called when the communication endpoint is closed.
+ */
+typedef void (*comm_dead_handler_fn)(void *private_data);
+
+/**
+ * @brief Abstract struct to store communication endpoint details
+ */
+struct comm_context;
+
+/**
+ * @brief Initialize the communication endpoint
+ *
+ * This return a new communication context. Freeing this context will free all
+ * memory assoicated with it.
+ *
+ * @param[in] mem_ctx Talloc memory context
+ * @param[in] ev Tevent context
+ * @param[in] fd The socket or file descriptor
+ * @param[in] read_handler The packet handler function
+ * @param[in] read_private_data Private data for read handler function
+ * @param[in] dead_handler The communication dead handler function
+ * @param[in] dead_private_data Private data for dead handler function
+ * @param[out] result The new comm_context structure
+ * @return 0 on success, errno on failure
+ */
+int comm_setup(TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd,
+	       comm_read_handler_fn read_handler, void *read_private_data,
+	       comm_dead_handler_fn dead_handler, void *dead_private_data,
+	       struct comm_context **result);
+
+/**
+ * @brief Async computation start to send a packet
+ *
+ * @param[in] mem_ctx Talloc memory context
+ * @param[in] ev Tevent context
+ * @param[in] comm Communication context
+ * @param[in] buf The packet data
+ * @param[in] buflen The size of the packet
+ * @return new tevent request, or NULL on failure
+ */
+struct tevent_req *comm_write_send(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct comm_context *comm,
+				   uint8_t *buf, size_t buflen);
+
+/**
+ * @brief Async computation end to send a packet
+ *
+ * @param[in] req Tevent request
+ * @param[out] perr errno in case of failure
+ * @return true on success, false on failure
+ */
+bool comm_write_recv(struct tevent_req *req, int *perr);
+
+#endif /* __CTDB_COMM_H__ */
diff --git a/ctdb/common/common.h b/ctdb/common/common.h
new file mode 100644
index 0000000..b89a84c
--- /dev/null
+++ b/ctdb/common/common.h
@@ -0,0 +1,146 @@
+/*
+   ctdb database library
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_COMMON_H__
+#define __CTDB_COMMON_H__
+
+/* From common/ctdb_io.c */
+
+int ctdb_queue_length(struct ctdb_queue *queue);
+
+int ctdb_queue_send(struct ctdb_queue *queue, uint8_t *data, uint32_t length);
+
+int ctdb_queue_set_fd(struct ctdb_queue *queue, int fd);
+
+struct ctdb_queue *ctdb_queue_setup(struct ctdb_context *ctdb,
+				    TALLOC_CTX *mem_ctx, int fd, int alignment,
+				    ctdb_queue_cb_fn_t callback,
+				    void *private_data, const char *fmt, ...)
+				    PRINTF_ATTRIBUTE(7,8);
+
+/* From common/ctdb_ltdb.c */
+
+struct ctdb_db_context *ctdb_db_handle(struct ctdb_context *ctdb,
+				       const char *name);
+
+uint32_t ctdb_lmaster(struct ctdb_context *ctdb, const TDB_DATA *key);
+
+int ctdb_ltdb_fetch(struct ctdb_db_context *ctdb_db,
+		    TDB_DATA key, struct ctdb_ltdb_header *header,
+		    TALLOC_CTX *mem_ctx, TDB_DATA *data);
+
+int ctdb_ltdb_fetch_with_header(struct ctdb_db_context *ctdb_db,
+				TDB_DATA key, struct ctdb_ltdb_header *header,
+				TALLOC_CTX *mem_ctx, TDB_DATA *data);
+
+int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key,
+		    struct ctdb_ltdb_header *header, TDB_DATA data);
+
+int ctdb_ltdb_lock(struct ctdb_db_context *ctdb_db, TDB_DATA key);
+
+int ctdb_ltdb_unlock(struct ctdb_db_context *ctdb_db, TDB_DATA key);
+
+int ctdb_ltdb_delete(struct ctdb_db_context *ctdb_db, TDB_DATA key);
+
+int ctdb_trackingdb_add_pnn(struct ctdb_context *ctdb, TDB_DATA *data, uint32_t pnn);
+
+typedef void (*ctdb_trackingdb_cb)(struct ctdb_context *ctdb, uint32_t pnn,
+				   void *private_data);
+
+void ctdb_trackingdb_traverse(struct ctdb_context *ctdb, TDB_DATA data,
+			      ctdb_trackingdb_cb cb, void *private_data);
+
+int ctdb_null_func(struct ctdb_call_info *call);
+
+int ctdb_fetch_func(struct ctdb_call_info *call);
+
+int ctdb_fetch_with_header_func(struct ctdb_call_info *call);
+
+/* from common/ctdb_util.c */
+
+const char *ctdb_errstr(struct ctdb_context *ctdb);
+
+void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...);
+
+void ctdb_fatal(struct ctdb_context *ctdb, const char *msg);
+
+void ctdb_die(struct ctdb_context *ctdb, const char *msg);
+
+bool ctdb_set_helper(const char *type, char *helper, size_t size,
+		     const char *envvar,
+		     const char *dir, const char *file);
+
+void ctdb_external_trace(void);
+
+int ctdb_parse_address(TALLOC_CTX *mem_ctx, const char *str,
+		       ctdb_sock_addr *address);
+
+bool ctdb_same_address(ctdb_sock_addr *a1, ctdb_sock_addr *a2);
+
+uint32_t ctdb_hash(const TDB_DATA *key);
+
+struct ctdb_rec_data_old *ctdb_marshall_record(TALLOC_CTX *mem_ctx,
+					       uint32_t reqid,
+					       TDB_DATA key,
+					       struct ctdb_ltdb_header *header,
+					       TDB_DATA data);
+
+struct ctdb_marshall_buffer *ctdb_marshall_add(TALLOC_CTX *mem_ctx,
+					       struct ctdb_marshall_buffer *m,
+					       uint64_t db_id,
+					       uint32_t reqid,
+					       TDB_DATA key,
+					       struct ctdb_ltdb_header *header,
+					       TDB_DATA data);
+
+TDB_DATA ctdb_marshall_finish(struct ctdb_marshall_buffer *m);
+
+struct ctdb_rec_data_old *ctdb_marshall_loop_next(
+					struct ctdb_marshall_buffer *m,
+					struct ctdb_rec_data_old *r,
+					uint32_t *reqid,
+					struct ctdb_ltdb_header *header,
+					TDB_DATA *key, TDB_DATA *data);
+
+void ctdb_canonicalize_ip(const ctdb_sock_addr *ip, ctdb_sock_addr *cip);
+
+bool ctdb_same_ip(const ctdb_sock_addr *tip1, const ctdb_sock_addr *tip2);
+
+bool ctdb_same_sockaddr(const ctdb_sock_addr *ip1, const ctdb_sock_addr *ip2);
+
+char *ctdb_addr_to_str(ctdb_sock_addr *addr);
+
+unsigned ctdb_addr_to_port(ctdb_sock_addr *addr);
+
+struct ctdb_node_map_old *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
+					       const char *nlist);
+
+struct ctdb_node_map_old *ctdb_node_list_to_map(struct ctdb_node **nodes,
+						uint32_t num_nodes,
+						TALLOC_CTX *mem_ctx);
+
+const char *runstate_to_string(enum ctdb_runstate runstate);
+
+enum ctdb_runstate runstate_from_string(const char *label);
+
+void ctdb_set_runstate(struct ctdb_context *ctdb, enum ctdb_runstate runstate);
+
+uint32_t *ctdb_key_to_idkey(TALLOC_CTX *mem_ctx, TDB_DATA key);
+
+#endif /* __CTDB_COMMON_H__ */
diff --git a/ctdb/common/ctdb_fork.c b/ctdb/common/ctdb_fork.c
deleted file mode 100644
index 8d38150..0000000
--- a/ctdb/common/ctdb_fork.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/* 
-   functions to track and manage processes
-
-   Copyright (C) Ronnie Sahlberg 2012
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "system/wait.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
-
-void ctdb_set_child_info(TALLOC_CTX *mem_ctx, const char *child_name_fmt, ...)
-{
-	if (child_name_fmt != NULL) {
-		va_list ap;
-		char *t;
-
-		va_start(ap, child_name_fmt);
-		t = talloc_vasprintf(mem_ctx, child_name_fmt, ap);
-		debug_extra = talloc_asprintf(mem_ctx, "%s:", t);
-		talloc_free(t);
-		va_end(ap);
-	}
-}
-
-void ctdb_track_child(struct ctdb_context *ctdb, pid_t pid)
-{
-	char *process;
-
-	/* Only CTDB main daemon should track child processes */
-	if (getpid() != ctdb->ctdbd_pid) {
-		return;
-	}
-
-	process = talloc_asprintf(ctdb->child_processes, "process:%d", (int)pid);
-	trbt_insert32(ctdb->child_processes, pid, process);
-}
-
-/*
- * This function forks a child process and drops the realtime 
- * scheduler for the child process.
- */
-pid_t ctdb_fork(struct ctdb_context *ctdb)
-{
-	pid_t pid;
-
-	pid = fork();
-	if (pid == -1) {
-		return -1;
-	}
-	if (pid == 0) {
-		ctdb_set_child_info(ctdb, NULL);
-
-		/* Close the Unix Domain socket and the TCP socket.
-		 * This ensures that none of the child processes will
-		 * look like the main daemon when it is not running.
-		 * tevent needs to be stopped before closing sockets.
-		 */
-		if (ctdb->ev != NULL) {
-			talloc_free(ctdb->ev);
-			ctdb->ev = NULL;
-		}
-		if (ctdb->daemon.sd != -1) {
-			close(ctdb->daemon.sd);
-			ctdb->daemon.sd = -1;
-		}
-		if (ctdb->methods != NULL) {
-			ctdb->methods->shutdown(ctdb);
-		}
-
-		/* The child does not need to be realtime */
-		if (ctdb->do_setsched) {
-			reset_scheduler();
-		}
-		ctdb->can_send_controls = false;
-
-		return 0;
-	}
-
-	ctdb_track_child(ctdb, pid);
-	return pid;
-}
-
-static void ctdb_sigchld_handler(struct tevent_context *ev,
-	struct tevent_signal *te, int signum, int count,
-	void *dont_care, 
-	void *private_data)
-{
-	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
-	int status;
-	pid_t pid = -1;
-
-	while (pid != 0) {
-		pid = waitpid(-1, &status, WNOHANG);
-		if (pid == -1) {
-			DEBUG(DEBUG_ERR, (__location__ " waitpid() returned error. errno:%d\n", errno));
-			return;
-		}
-		if (pid > 0) {
-			char *process;
-
-			if (getpid() != ctdb->ctdbd_pid) {
-				continue;
-			}
-
-			process = trbt_lookup32(ctdb->child_processes, pid);
-			if (process == NULL) {
-				DEBUG(DEBUG_ERR,("Got SIGCHLD from pid:%d we didn not spawn with ctdb_fork\n", pid));
-			}
-
-			DEBUG(DEBUG_DEBUG, ("SIGCHLD from %d %s\n", (int)pid, process));
-			talloc_free(process);
-		}
-	}
-}
-
-
-struct tevent_signal *
-ctdb_init_sigchld(struct ctdb_context *ctdb)
-{
-	struct tevent_signal *se;
-
-	ctdb->child_processes = trbt_create(ctdb, 0);
-
-	se = tevent_add_signal(ctdb->ev, ctdb, SIGCHLD, 0, ctdb_sigchld_handler, ctdb);
-	return se;
-}
-
-int
-ctdb_kill(struct ctdb_context *ctdb, pid_t pid, int signum)
-{
-	char *process;
-
-	if (signum == 0) {
-		return kill(pid, signum);
-	}
-
-	if (getpid() != ctdb->ctdbd_pid) {
-		return kill(pid, signum);
-	}
-
-	process = trbt_lookup32(ctdb->child_processes, pid);
-	if (process == NULL) {
-		DEBUG(DEBUG_ERR,("ctdb_kill: trying to kill(%d, %d) a process that does not exist\n", pid, signum));
-		return 0;
-	}
-
-	return kill(pid, signum);
-}
diff --git a/ctdb/common/ctdb_io.c b/ctdb/common/ctdb_io.c
index 53486f4..894935e 100644
--- a/ctdb/common/ctdb_io.c
+++ b/ctdb/common/ctdb_io.c
@@ -20,14 +20,23 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "tdb.h"
-#include "lib/util/dlinklist.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
-#include "../include/ctdb_private.h"
-#include "../include/ctdb_client.h"
-#include <stdarg.h>
+
+#include <tdb.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/system.h"
+#include "common/logging.h"
+#include "common/common.h"
 
 #define QUEUE_BUFFER_SIZE	(16*1024)
 
@@ -53,7 +62,7 @@ struct ctdb_queue {
 	struct ctdb_buffer buffer; /* input buffer */
 	struct ctdb_queue_pkt *out_queue, *out_queue_tail;
 	uint32_t out_queue_length;
-	struct fd_event *fde;
+	struct tevent_fd *fde;
 	int fd;
 	size_t alignment;
 	void *private_data;
@@ -215,7 +224,7 @@ failed:
 
 
 /* used when an event triggers a dead queue */
-static void queue_dead(struct event_context *ev, struct tevent_immediate *im,
+static void queue_dead(struct tevent_context *ev, struct tevent_immediate *im,
 		       void *private_data)
 {
 	struct ctdb_queue *queue = talloc_get_type(private_data, struct ctdb_queue);
@@ -264,18 +273,18 @@ static void queue_io_write(struct ctdb_queue *queue)
 		talloc_free(pkt);
 	}
 
-	EVENT_FD_NOT_WRITEABLE(queue->fde);
+	TEVENT_FD_NOT_WRITEABLE(queue->fde);
 }
 
 /*
   called when an incoming connection is readable or writeable
 */
-static void queue_io_handler(struct event_context *ev, struct fd_event *fde, 
+static void queue_io_handler(struct tevent_context *ev, struct tevent_fd *fde,
 			     uint16_t flags, void *private_data)
 {
 	struct ctdb_queue *queue = talloc_get_type(private_data, struct ctdb_queue);
 
-	if (flags & EVENT_FD_READ) {
+	if (flags & TEVENT_FD_READ) {
 		queue_io_read(queue);
 	} else {
 		queue_io_write(queue);
@@ -340,23 +349,23 @@ int ctdb_queue_send(struct ctdb_queue *queue, uint8_t *data, uint32_t length)
 	pkt->full_length = full_length;
 
 	if (queue->out_queue == NULL && queue->fd != -1) {
-		EVENT_FD_WRITEABLE(queue->fde);
+		TEVENT_FD_WRITEABLE(queue->fde);
 	}
 
-	DLIST_ADD_END(queue->out_queue, pkt, NULL);
+	DLIST_ADD_END(queue->out_queue, pkt);
 
 	queue->out_queue_length++;
 
 	if (queue->ctdb->tunable.verbose_memory_names != 0) {
 		switch (hdr->operation) {
 		case CTDB_REQ_CONTROL: {
-			struct ctdb_req_control *c = (struct ctdb_req_control *)hdr;
+			struct ctdb_req_control_old *c = (struct ctdb_req_control_old *)hdr;
 			talloc_set_name(pkt, "ctdb_queue_pkt: %s control opcode=%u srvid=%llu datalen=%u",
 					queue->name, (unsigned)c->opcode, (unsigned long long)c->srvid, (unsigned)c->datalen);
 			break;
 		}
 		case CTDB_REQ_MESSAGE: {
-			struct ctdb_req_message *m = (struct ctdb_req_message *)hdr;
+			struct ctdb_req_message_old *m = (struct ctdb_req_message_old *)hdr;
 			talloc_set_name(pkt, "ctdb_queue_pkt: %s message srvid=%llu datalen=%u",
 					queue->name, (unsigned long long)m->srvid, (unsigned)m->datalen);
 			break;
@@ -383,15 +392,16 @@ int ctdb_queue_set_fd(struct ctdb_queue *queue, int fd)
 	queue->fde = NULL;
 
 	if (fd != -1) {
-		queue->fde = event_add_fd(queue->ctdb->ev, queue, fd, EVENT_FD_READ,
-					  queue_io_handler, queue);
+		queue->fde = tevent_add_fd(queue->ctdb->ev, queue, fd,
+					   TEVENT_FD_READ,
+					   queue_io_handler, queue);
 		if (queue->fde == NULL) {
 			return -1;
 		}
 		tevent_fd_set_auto_close(queue->fde);
 
 		if (queue->out_queue) {
-			EVENT_FD_WRITEABLE(queue->fde);		
+			TEVENT_FD_WRITEABLE(queue->fde);
 		}
 	}
 
diff --git a/ctdb/common/ctdb_logging.c b/ctdb/common/ctdb_logging.c
deleted file mode 100644
index e76966c..0000000
--- a/ctdb/common/ctdb_logging.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* 
-   ctdb logging code
-
-   Copyright (C) Ronnie Sahlberg 2009
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ctype.h>
-#include "replace.h"
-#include "ctdb_logging.h"
-
-const char *debug_extra = "";
-
-struct debug_levels {
-	int32_t	level;
-	const char *description;
-};
-
-static struct debug_levels debug_levels[] = {
-	{DEBUG_ERR,	"ERR"},
-	{DEBUG_WARNING,	"WARNING"},
-	{DEBUG_NOTICE,	"NOTICE"},
-	{DEBUG_INFO,	"INFO"},
-	{DEBUG_DEBUG,	"DEBUG"},
-	{0, NULL}
-};
-
-const char *get_debug_by_level(int32_t level)
-{
-	int i;
-
-	for (i=0; debug_levels[i].description != NULL; i++) {
-		if (debug_levels[i].level == level) {
-			return debug_levels[i].description;
-		}
-	}
-	return NULL;
-}
-
-static bool get_debug_by_desc(const char *desc, int32_t *level)
-{
-	int i;
-
-	for (i=0; debug_levels[i].description != NULL; i++) {
-		if (!strcasecmp(debug_levels[i].description, desc)) {
-			*level = debug_levels[i].level;
-			return true;
-		}
-	}
-
-	return false;
-}
-
-bool parse_debug(const char *str, int32_t *level)
-{
-	if (isalpha(str[0])) {
-		return get_debug_by_desc(str, level);
-	} else {
-		*level = strtol(str, NULL, 0);
-		return get_debug_by_level(*level) != NULL;
-	}
-}
-
-void print_debug_levels(FILE *stream)
-{
-	int i;
-
-	for (i=0; debug_levels[i].description != NULL; i++) {
-		fprintf(stream,
-			"%s (%d)\n",
-			debug_levels[i].description, debug_levels[i].level);
-	}
-}
diff --git a/ctdb/common/ctdb_ltdb.c b/ctdb/common/ctdb_ltdb.c
index f4d571e..6c941d8 100644
--- a/ctdb/common/ctdb_ltdb.c
+++ b/ctdb/common/ctdb_ltdb.c
@@ -18,13 +18,20 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
-#include "../include/ctdb_private.h"
+
+#include <tdb.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
 #include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+
+#include "common/common.h"
+#include "common/logging.h"
 
 /*
   find an attached ctdb_db handle given a name
diff --git a/ctdb/common/ctdb_message.c b/ctdb/common/ctdb_message.c
deleted file mode 100644
index 0e19761..0000000
--- a/ctdb/common/ctdb_message.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/* 
-   ctdb_message protocol code
-
-   Copyright (C) Andrew Tridgell  2007
-   Copyright (C) Amitay Isaacs  2013
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-/*
-  see http://wiki.samba.org/index.php/Samba_%26_Clustering for
-  protocol design and packet details
-*/
-#include "includes.h"
-#include "tdb.h"
-#include "system/network.h"
-#include "system/filesys.h"
-#include "../include/ctdb_private.h"
-#include "lib/util/dlinklist.h"
-
-static int message_list_db_init(struct ctdb_context *ctdb)
-{
-	ctdb->message_list_indexdb = tdb_open("messagedb", 8192,
-					      TDB_INTERNAL|
-					      TDB_INCOMPATIBLE_HASH|
-					      TDB_DISALLOW_NESTING,
-					      O_RDWR|O_CREAT, 0);
-	if (ctdb->message_list_indexdb == NULL) {
-		DEBUG(DEBUG_ERR, ("Failed to create message list indexdb\n"));
-		return -1;
-	}
-
-	return 0;
-}
-
-static int message_list_db_add(struct ctdb_context *ctdb, uint64_t srvid,
-			       struct ctdb_message_list_header *h)
-{
-	int ret;
-	TDB_DATA key, data;
-
-	if (ctdb->message_list_indexdb == NULL) {
-		ret = message_list_db_init(ctdb);
-		if (ret < 0) {
-			return -1;
-		}
-	}
-
-	key.dptr = (uint8_t *)&srvid;
-	key.dsize = sizeof(uint64_t);
-
-	data.dptr = (uint8_t *)&h;
-	data.dsize = sizeof(struct ctdb_message_list_header *);
-
-	ret = tdb_store(ctdb->message_list_indexdb, key, data, TDB_INSERT);
-	if (ret < 0) {
-		DEBUG(DEBUG_ERR, ("Failed to add message list handler (%s)\n",
-				  tdb_errorstr(ctdb->message_list_indexdb)));
-		return -1;
-	}
-
-	return 0;
-}
-
-static int message_list_db_delete(struct ctdb_context *ctdb, uint64_t srvid)
-{
-	int ret;
-	TDB_DATA key;
-
-	if (ctdb->message_list_indexdb == NULL) {
-		return -1;
-	}
-
-	key.dptr = (uint8_t *)&srvid;
-	key.dsize = sizeof(uint64_t);
-
-	ret = tdb_delete(ctdb->message_list_indexdb, key);
-	if (ret < 0) {
-		DEBUG(DEBUG_ERR, ("Failed to delete message list handler (%s)\n",
-				  tdb_errorstr(ctdb->message_list_indexdb)));
-		return -1;
-	}
-
-	return 0;
-}
-
-static int message_list_db_fetch_parser(TDB_DATA key, TDB_DATA data,
-					void *private_data)
-{
-	struct ctdb_message_list_header **h =
-		(struct ctdb_message_list_header **)private_data;
-
-	if (data.dsize != sizeof(struct ctdb_message_list_header *)) {
-		return -1;
-	}
-
-	*h = *(struct ctdb_message_list_header **)data.dptr;
-	return 0;
-}
-
-static int message_list_db_fetch(struct ctdb_context *ctdb, uint64_t srvid,
-				 struct ctdb_message_list_header **h)
-{
-	TDB_DATA key;
-
-	if (ctdb->message_list_indexdb == NULL) {
-		return -1;
-	}
-
-	key.dptr = (uint8_t *)&srvid;
-	key.dsize = sizeof(uint64_t);
-
-	return tdb_parse_record(ctdb->message_list_indexdb, key,
-				message_list_db_fetch_parser, h);
-}
-
-/*
-  this dispatches the messages to the registered ctdb message handler
-*/
-int ctdb_dispatch_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data)
-{
-	struct ctdb_message_list_header *h;
-	struct ctdb_message_list *m;
-	uint64_t srvid_all = CTDB_SRVID_ALL;
-	int ret;
-
-	ret = message_list_db_fetch(ctdb, srvid, &h);
-	if (ret == 0) {
-		for (m=h->m; m; m=m->next) {
-			m->message_handler(ctdb, srvid, data, m->message_private);
-		}
-	}
-
-	ret = message_list_db_fetch(ctdb, srvid_all, &h);
-	if (ret == 0) {
-		for(m=h->m; m; m=m->next) {
-			m->message_handler(ctdb, srvid, data, m->message_private);
-		}
-	}
-
-	return 0;
-}
-
-/*
-  called when a CTDB_REQ_MESSAGE packet comes in
-*/
-void ctdb_request_message(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
-{
-	struct ctdb_req_message *c = (struct ctdb_req_message *)hdr;
-	TDB_DATA data;
-
-	data.dsize = c->datalen;
-	data.dptr = talloc_memdup(c, &c->data[0], c->datalen);
-
-	ctdb_dispatch_message(ctdb, c->srvid, data);
-}
-
-/*
- * When header is freed, remove all the srvid handlers
- */
-static int message_header_destructor(struct ctdb_message_list_header *h)
-{
-	struct ctdb_message_list *m;
-
-	while (h->m != NULL) {
-		m = h->m;
-		DLIST_REMOVE(h->m, m);
-		TALLOC_FREE(m);
-	}
-
-	message_list_db_delete(h->ctdb, h->srvid);
-	DLIST_REMOVE(h->ctdb->message_list_header, h);
-
-	return 0;
-}
-
-/*
-  when a client goes away, we need to remove its srvid handler from the list
- */
-static int message_handler_destructor(struct ctdb_message_list *m)
-{
-	struct ctdb_message_list_header *h = m->h;
-
-	DLIST_REMOVE(h->m, m);
-	if (h->m == NULL) {
-		talloc_free(h);
-	}
-	return 0;
-}
-
-/*
-  setup handler for receipt of ctdb messages from ctdb_send_message()
-*/
-int ctdb_register_message_handler(struct ctdb_context *ctdb, 
-				  TALLOC_CTX *mem_ctx,
-				  uint64_t srvid,
-				  ctdb_msg_fn_t handler,
-				  void *private_data)
-{
-	struct ctdb_message_list_header *h;
-	struct ctdb_message_list *m;
-	int ret;
-
-	m = talloc_zero(mem_ctx, struct ctdb_message_list);
-	CTDB_NO_MEMORY(ctdb, m);
-
-	m->message_handler = handler;
-	m->message_private = private_data;
-
-	ret = message_list_db_fetch(ctdb, srvid, &h);
-	if (ret != 0) {
-		/* srvid not registered yet */
-		h = talloc_zero(ctdb, struct ctdb_message_list_header);
-		CTDB_NO_MEMORY(ctdb, h);
-
-		h->ctdb = ctdb;
-		h->srvid = srvid;
-
-		ret = message_list_db_add(ctdb, srvid, h);
-		if (ret < 0) {
-			talloc_free(m);
-			talloc_free(h);
-			return -1;
-		}
-
-		DLIST_ADD(ctdb->message_list_header, h);
-		talloc_set_destructor(h, message_header_destructor);
-	}
-
-	m->h = h;
-	DLIST_ADD(h->m, m);
-	talloc_set_destructor(m, message_handler_destructor);
-	return 0;
-}
-
-
-/*
-  setup handler for receipt of ctdb messages from ctdb_send_message()
-*/
-int ctdb_deregister_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data)
-{
-	struct ctdb_message_list_header *h;
-	struct ctdb_message_list *m;
-	int ret;
-
-	ret = message_list_db_fetch(ctdb, srvid, &h);
-	if (ret != 0) {
-		return -1;
-	}
-
-	for (m=h->m; m; m=m->next) {
-		if (m->message_private == private_data) {
-			talloc_free(m);
-			return 0;
-		}
-	}
-
-	return -1;
-}
-
-
-/*
- * check if the given srvid exists
- */
-bool ctdb_check_message_handler(struct ctdb_context *ctdb, uint64_t srvid)
-{
-	struct ctdb_message_list_header *h;
-	int ret;
-
-	ret = message_list_db_fetch(ctdb, srvid, &h);
-	if (ret != 0 || h->m == NULL) {
-		return false;
-	}
-
-	return true;
-}
diff --git a/ctdb/common/ctdb_util.c b/ctdb/common/ctdb_util.c
index 709c7a1..39108bc 100644
--- a/ctdb/common/ctdb_util.c
+++ b/ctdb/common/ctdb_util.c
@@ -17,12 +17,22 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
+
+#include <tdb.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+
+#include "common/reqid.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 /*
   return error string for last error
@@ -199,64 +209,16 @@ uint32_t ctdb_hash(const TDB_DATA *key)
 	return tdb_jenkins_hash(discard_const(key));
 }
 
-/*
-  a type checking varient of idr_find
- */
-static void *_idr_find_type(struct idr_context *idp, int id, const char *type, const char *location)
-{
-	void *p = idr_find(idp, id);
-	if (p && talloc_check_name(p, type) == NULL) {
-		DEBUG(DEBUG_ERR,("%s idr_find_type expected type %s  but got %s\n",
-			 location, type, talloc_get_name(p)));
-		return NULL;
-	}
-	return p;
-}
-
-uint32_t ctdb_reqid_new(struct ctdb_context *ctdb, void *state)
-{
-	int id = idr_get_new_above(ctdb->idr, state, ctdb->lastid+1, INT_MAX);
-	if (id < 0) {
-		DEBUG(DEBUG_DEBUG, ("Reqid wrap!\n"));
-		id = idr_get_new(ctdb->idr, state, INT_MAX);
-	}
-	ctdb->lastid = id;
-	return id;
-}
-
-void *_ctdb_reqid_find(struct ctdb_context *ctdb, uint32_t reqid, const char *type, const char *location)
-{
-	void *p;
-
-	p = _idr_find_type(ctdb->idr, reqid, type, location);
-	if (p == NULL) {
-		DEBUG(DEBUG_WARNING, ("Could not find idr:%u\n",reqid));
-	}
-
-	return p;
-}
-
-
-void ctdb_reqid_remove(struct ctdb_context *ctdb, uint32_t reqid)
-{
-	int ret;
-
-	ret = idr_remove(ctdb->idr, reqid);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, ("Removing idr that does not exist\n"));
-	}
-}
-
 
 static uint32_t ctdb_marshall_record_size(TDB_DATA key,
 					  struct ctdb_ltdb_header *header,
 					  TDB_DATA data)
 {
-	return offsetof(struct ctdb_rec_data, data) + key.dsize +
+	return offsetof(struct ctdb_rec_data_old, data) + key.dsize +
 	       data.dsize + (header ? sizeof(*header) : 0);
 }
 
-static void ctdb_marshall_record_copy(struct ctdb_rec_data *rec,
+static void ctdb_marshall_record_copy(struct ctdb_rec_data_old *rec,
 				      uint32_t reqid,
 				      TDB_DATA key,
 				      struct ctdb_ltdb_header *header,
@@ -287,17 +249,18 @@ static void ctdb_marshall_record_copy(struct ctdb_rec_data *rec,
   note that header may be NULL. If not NULL then it is included in the data portion
   of the record
  */
-struct ctdb_rec_data *ctdb_marshall_record(TALLOC_CTX *mem_ctx, uint32_t reqid,
-					   TDB_DATA key,
-					   struct ctdb_ltdb_header *header,
-					   TDB_DATA data)
+struct ctdb_rec_data_old *ctdb_marshall_record(TALLOC_CTX *mem_ctx,
+					       uint32_t reqid,
+					       TDB_DATA key,
+					       struct ctdb_ltdb_header *header,
+					       TDB_DATA data)
 {
 	size_t length;
-	struct ctdb_rec_data *d;
+	struct ctdb_rec_data_old *d;
 
 	length = ctdb_marshall_record_size(key, header, data);
 
-	d = (struct ctdb_rec_data *)talloc_size(mem_ctx, length);
+	d = (struct ctdb_rec_data_old *)talloc_size(mem_ctx, length);
 	if (d == NULL) {
 		return NULL;
 	}
@@ -316,7 +279,7 @@ struct ctdb_marshall_buffer *ctdb_marshall_add(TALLOC_CTX *mem_ctx,
 					       struct ctdb_ltdb_header *header,
 					       TDB_DATA data)
 {
-	struct ctdb_rec_data *r;
+	struct ctdb_rec_data_old *r;
 	struct ctdb_marshall_buffer *m2;
 	uint32_t length, offset;
 
@@ -338,7 +301,7 @@ struct ctdb_marshall_buffer *ctdb_marshall_add(TALLOC_CTX *mem_ctx,
 		m2->db_id = db_id;
 	}
 
-	r = (struct ctdb_rec_data *)((uint8_t *)m2 + offset);
+	r = (struct ctdb_rec_data_old *)((uint8_t *)m2 + offset);
 	ctdb_marshall_record_copy(r, reqid, key, header, data, length);
 	m2->count++;
 
@@ -360,15 +323,17 @@ TDB_DATA ctdb_marshall_finish(struct ctdb_marshall_buffer *m)
      - pass r==NULL to start
      - loop the number of times indicated by m->count
 */
-struct ctdb_rec_data *ctdb_marshall_loop_next(struct ctdb_marshall_buffer *m, struct ctdb_rec_data *r,
-					      uint32_t *reqid,
-					      struct ctdb_ltdb_header *header,
-					      TDB_DATA *key, TDB_DATA *data)
+struct ctdb_rec_data_old *ctdb_marshall_loop_next(
+				struct ctdb_marshall_buffer *m,
+				struct ctdb_rec_data_old *r,
+				uint32_t *reqid,
+				struct ctdb_ltdb_header *header,
+				TDB_DATA *key, TDB_DATA *data)
 {
 	if (r == NULL) {
-		r = (struct ctdb_rec_data *)&m->data[0];
+		r = (struct ctdb_rec_data_old *)&m->data[0];
 	} else {
-		r = (struct ctdb_rec_data *)(r->length + (uint8_t *)r);
+		r = (struct ctdb_rec_data_old *)(r->length + (uint8_t *)r);
 	}
 
 	if (reqid != NULL) {
@@ -491,7 +456,7 @@ unsigned ctdb_addr_to_port(ctdb_sock_addr *addr)
 /* Add a node to a node map with given address and flags */
 static bool node_map_add(TALLOC_CTX *mem_ctx,
 			 const char *nstr, uint32_t flags,
-			 struct ctdb_node_map **node_map)
+			 struct ctdb_node_map_old **node_map)
 {
 	ctdb_sock_addr addr;
 	uint32_t num;
@@ -504,7 +469,7 @@ static bool node_map_add(TALLOC_CTX *mem_ctx,
 	}
 
 	num = (*node_map)->num + 1;
-	s = offsetof(struct ctdb_node_map, nodes) +
+	s = offsetof(struct ctdb_node_map_old, nodes) +
 		num * sizeof(struct ctdb_node_and_flags);
 	*node_map = talloc_realloc_size(mem_ctx, *node_map, s);
 	if (*node_map == NULL) {
@@ -523,16 +488,16 @@ static bool node_map_add(TALLOC_CTX *mem_ctx,
 }
 
 /* Read a nodes file into a node map */
-struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
+struct ctdb_node_map_old *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
 					   const char *nlist)
 {
 	char **lines;
 	int nlines;
 	int i;
-	struct ctdb_node_map *ret;
+	struct ctdb_node_map_old *ret;
 
 	/* Allocate node map header */
-	ret = talloc_zero_size(mem_ctx, offsetof(struct ctdb_node_map, nodes));
+	ret = talloc_zero_size(mem_ctx, offsetof(struct ctdb_node_map_old, nodes));
 	if (ret == NULL) {
 		DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
 		return false;
@@ -592,17 +557,17 @@ struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
 	return ret;
 }
 
-struct ctdb_node_map *
+struct ctdb_node_map_old *
 ctdb_node_list_to_map(struct ctdb_node **nodes, uint32_t num_nodes,
 		      TALLOC_CTX *mem_ctx)
 {
 	uint32_t i;
 	size_t size;
-	struct ctdb_node_map *node_map;
+	struct ctdb_node_map_old *node_map;
 
-	size = offsetof(struct ctdb_node_map, nodes) +
+	size = offsetof(struct ctdb_node_map_old, nodes) +
 		num_nodes * sizeof(struct ctdb_node_and_flags);
-	node_map  = (struct ctdb_node_map *)talloc_zero_size(mem_ctx, size);
+	node_map  = (struct ctdb_node_map_old *)talloc_zero_size(mem_ctx, size);
 	if (node_map == NULL) {
 		DEBUG(DEBUG_ERR,
 		      (__location__ " Failed to allocate nodemap array\n"));
diff --git a/ctdb/common/db_hash.c b/ctdb/common/db_hash.c
new file mode 100644
index 0000000..6a23337
--- /dev/null
+++ b/ctdb/common/db_hash.c
@@ -0,0 +1,268 @@
+/*
+   Using tdb as a hash table
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "common/db_hash.h"
+
+struct db_hash_context {
+	struct tdb_context *db;
+};
+
+
+static int db_hash_destructor(struct db_hash_context *dh)
+{
+	if (dh->db != NULL) {
+		tdb_close(dh->db);
+		dh->db = NULL;
+	}
+	return 0;
+}
+
+int db_hash_init(TALLOC_CTX *mem_ctx, const char *name, int hash_size,
+		 enum db_hash_type type, struct db_hash_context **result)
+{
+	struct db_hash_context *dh;
+	int tdb_flags = TDB_INTERNAL | TDB_DISALLOW_NESTING;
+
+	dh = talloc_zero(mem_ctx, struct db_hash_context);
+	if (dh == NULL) {
+		return ENOMEM;
+	}
+
+	if (type == DB_HASH_COMPLEX) {
+		tdb_flags |= TDB_INCOMPATIBLE_HASH;
+	}
+
+	dh->db = tdb_open(name, hash_size, tdb_flags, O_RDWR|O_CREAT, 0);
+	if (dh->db == NULL) {
+		talloc_free(dh);
+		return ENOMEM;
+	}
+
+	talloc_set_destructor(dh, db_hash_destructor);
+	*result = dh;
+	return 0;
+}
+
+static int db_hash_map_tdb_error(struct db_hash_context *dh)
+{
+	enum TDB_ERROR tdb_err;
+	int ret;
+
+	tdb_err = tdb_error(dh->db);
+	switch (tdb_err) {
+		case TDB_SUCCESS:
+			ret = 0; break;
+		case TDB_ERR_OOM:
+			ret = ENOMEM; break;
+		case TDB_ERR_EXISTS:
+			ret = EEXIST; break;
+		case TDB_ERR_NOEXIST:
+			ret = ENOENT; break;
+		case TDB_ERR_EINVAL:
+			ret = EINVAL; break;
+		default:
+			ret = EIO; break;
+	}
+	return ret;
+}
+
+int db_hash_insert(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen,
+		   uint8_t *databuf, size_t datalen)
+{
+	TDB_DATA key, data;
+	int ret;
+
+	if (dh == NULL) {
+		return EINVAL;
+	}
+
+	key.dptr = keybuf;
+	key.dsize = keylen;
+
+	data.dptr = databuf;
+	data.dsize = datalen;
+
+	ret = tdb_store(dh->db, key, data, TDB_INSERT);
+	if (ret != 0) {
+		ret = db_hash_map_tdb_error(dh);
+	}
+	return ret;
+}
+
+int db_hash_add(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen,
+		uint8_t *databuf, size_t datalen)
+{
+	TDB_DATA key, data;
+	int ret;
+
+	if (dh == NULL) {
+		return EINVAL;
+	}
+
+	key.dptr = keybuf;
+	key.dsize = keylen;
+
+	data.dptr = databuf;
+	data.dsize = datalen;
+
+	ret = tdb_store(dh->db, key, data, TDB_REPLACE);
+	if (ret != 0) {
+		ret = db_hash_map_tdb_error(dh);
+	}
+	return ret;
+}
+
+int db_hash_delete(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen)
+{
+	TDB_DATA key;
+	int ret;
+
+	key.dptr = keybuf;
+	key.dsize = keylen;
+
+	if (dh == NULL) {
+		return EINVAL;
+	}
+
+	ret = tdb_delete(dh->db, key);
+	if (ret != 0) {
+		ret = db_hash_map_tdb_error(dh);
+	}
+	return ret;
+}
+
+struct db_hash_fetch_state {
+	db_hash_record_parser_fn parser;
+	void *private_data;
+};
+
+static int db_hash_fetch_parser(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+	struct db_hash_fetch_state *state =
+		(struct db_hash_fetch_state *)private_data;
+	int ret;
+
+	ret = state->parser(key.dptr, key.dsize, data.dptr, data.dsize,
+			    state->private_data);
+	return ret;
+}
+
+int db_hash_fetch(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen,
+		  db_hash_record_parser_fn parser, void *private_data)
+{
+	struct db_hash_fetch_state state;
+	TDB_DATA key;
+	int ret;
+
+	if (dh == NULL || parser == NULL) {
+		return EINVAL;
+	}
+
+	state.parser = parser;
+	state.private_data = private_data;
+
+	key.dptr = keybuf;
+	key.dsize = keylen;
+
+	ret = tdb_parse_record(dh->db, key, db_hash_fetch_parser, &state);
+	if (ret == -1) {
+		return ENOENT;
+	}
+	return ret;
+}
+
+int db_hash_exists(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen)
+{
+	TDB_DATA key;
+	int ret;
+
+	if (dh == NULL) {
+		return EINVAL;
+	}
+
+	key.dptr = keybuf;
+	key.dsize = keylen;
+
+	ret = tdb_exists(dh->db, key);
+	if (ret == 1) {
+		/* Key found */
+		ret = 0;
+	} else {
+		ret = db_hash_map_tdb_error(dh);
+		if (ret == 0) {
+			ret = ENOENT;
+		}
+	}
+	return ret;
+}
+
+struct db_hash_traverse_state {
+	db_hash_record_parser_fn parser;
+	void *private_data;
+};
+
+static int db_hash_traverse_parser(struct tdb_context *tdb,
+				   TDB_DATA key, TDB_DATA data,
+				   void *private_data)
+{
+	struct db_hash_traverse_state *state =
+		(struct db_hash_traverse_state *)private_data;
+
+	return state->parser(key.dptr, key.dsize, data.dptr, data.dsize,
+			     state->private_data);
+}
+
+int db_hash_traverse(struct db_hash_context *dh,
+		     db_hash_record_parser_fn parser, void *private_data,
+		     int *count)
+{
+	struct db_hash_traverse_state state;
+	int ret;
+
+	if (dh == NULL) {
+		return EINVAL;
+	}
+
+	/* Special case, for counting records */
+	if (parser == NULL) {
+		ret = tdb_traverse_read(dh->db, NULL, NULL);
+	} else {
+		state.parser = parser;
+		state.private_data = private_data;
+
+		ret = tdb_traverse_read(dh->db, db_hash_traverse_parser, &state);
+	}
+
+	if (ret == -1) {
+		ret = db_hash_map_tdb_error(dh);
+	} else {
+		if (count != NULL) {
+			*count = ret;
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
diff --git a/ctdb/common/db_hash.h b/ctdb/common/db_hash.h
new file mode 100644
index 0000000..8f0e50b
--- /dev/null
+++ b/ctdb/common/db_hash.h
@@ -0,0 +1,159 @@
+/*
+   Using tdb as a hash table
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_DB_HASH_H__
+#define __CTDB_DB_HASH_H__
+
+#include <talloc.h>
+#include <tdb.h>
+
+/**
+ * @file db_hash.h
+ *
+ * @brief Use tdb database as a hash table
+ *
+ * This uses in-memory tdb databases to create a fixed sized hash table.
+ */
+
+/**
+ * @brief Hash type to indicate the hashing function to use.
+ *
+ * DB_HASH_SIMPLE uses default hashing function
+ * DB_HASH_COMPLEX uses jenkins hashing function
+ */
+enum db_hash_type {
+	DB_HASH_SIMPLE,
+	DB_HASH_COMPLEX,
+};
+
+/**
+ * @brief Parser callback function called when fetching a record
+ *
+ * This function is called when fetching a record. This function should
+ * not modify key and data arguments.
+ *
+ * The function should return 0 on success and errno on error.
+ */
+typedef int (*db_hash_record_parser_fn)(uint8_t *keybuf, size_t keylen,
+					uint8_t *databuf, size_t datalen,
+					void *private_data);
+
+/**
+ * @brief Abstract structure representing tdb hash table
+ */
+struct db_hash_context;
+
+/**
+ * @brief Initialize tdb hash table
+ *
+ * This returns a new tdb hash table context which is a talloc context.  Freeing
+ * this context will free all the memory associated with the hash table.
+ *
+ * @param[in] mem_ctx Talloc memory context
+ * @param[in] name The name for the hash table
+ * @param[in] hash_size The size of the hash table
+ * @param[in] type The type of hashing function to use
+ * @param[out] result The new db_hash_context structure
+ * @return 0 on success, errno on failure
+ */
+int db_hash_init(TALLOC_CTX *mem_ctx, const char *name, int hash_size,
+		 enum db_hash_type type, struct db_hash_context **result);
+
+/**
+ * @brief Insert a record into the hash table
+ *
+ * The key and data can be any binary data.  Insert only if the record does not
+ * exist.  If the record already exists, return error.
+ *
+ * @param[in] dh The tdb hash table context
+ * @param[in] keybuf The key buffer
+ * @param[in] keylen The key length
+ * @param[in] databuf The data buffer
+ * @param[in] datalen The data length
+ * @return 0 on success, errno on failure
+ */
+int db_hash_insert(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen,
+		   uint8_t *databuf, size_t datalen);
+
+/**
+ * @brief Add a record into the hash table
+ *
+ * The key and data can be any binary data.  If the record does not exist,
+ * insert the record.  If the record already exists, replace the record.
+ *
+ * @param[in] dh The tdb hash table context
+ * @param[in] keybuf The key buffer
+ * @param[in] keylen The key length
+ * @param[in] databuf The data buffer
+ * @param[in] datalen The data length
+ * @return 0 on success, errno on failure
+ */
+int db_hash_add(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen,
+		uint8_t *databuf, size_t datalen); 
+/**
+ * @brief Delete a record from the hash table
+ *
+ * @param[in] dh The tdb hash table context
+ * @param[in] keybuf The key buffer
+ * @param[in] keylen The key length
+ * @return 0 on success, errno on failure
+ */
+int db_hash_delete(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen);
+
+/**
+ * @brief Fetch a record from the hash table
+ *
+ * The key and data can be any binary data.
+ *
+ * @param[in] dh The tdb hash table context
+ * @param[in] keybuf The key buffer
+ * @param[in] keylen The key length
+ * @param[in] parser Function called when the matching record is found
+ * @param[in] private_data Private data to parser function
+ * @return 0 on success, errno on failure
+ */
+int db_hash_fetch(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen,
+		  db_hash_record_parser_fn parser, void *private_data);
+
+/**
+ * @brief Check if a record exists in the hash table
+ *
+ * @param[in] dh The tdb hash table context
+ * @param[in] keybuf The key buffer
+ * @param[in] keylen The key length
+ * @return 0 if the record exists, errno on failure
+ */
+int db_hash_exists(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen);
+
+/**
+ * @brief Traverse the database
+ *
+ * The parser function should non-zero value to stop traverse.
+ *
+ * @param[in] dh The tdb hash table context
+ * @param[in] parser Function called for each record
+ * @param[in] private_data Private data to parser function
+ * @param[out] count Number of records traversed
+ * @return 0 on success, errno on failure
+ */
+int db_hash_traverse(struct db_hash_context *dh,
+		     db_hash_record_parser_fn parser, void *private_data,
+		     int *count);
+
+#endif /* __CTDB_DB_HASH_H__ */
diff --git a/ctdb/common/logging.c b/ctdb/common/logging.c
new file mode 100644
index 0000000..f230471
--- /dev/null
+++ b/ctdb/common/logging.c
@@ -0,0 +1,103 @@
+/*
+   Logging utilities
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <replace.h>
+#include <system/locale.h>
+
+#include "common/logging.h"
+
+struct {
+	enum debug_level log_level;
+	const char *log_string;
+} log_string_map[] = {
+	{ DEBUG_ERR,     "ERROR" },
+	{ DEBUG_WARNING, "WARNING" },
+	{ DEBUG_NOTICE,  "NOTICE" },
+	{ DEBUG_INFO,    "INFO" },
+	{ DEBUG_DEBUG,   "DEBUG" },
+};
+
+bool debug_level_parse(const char *log_string, enum debug_level *log_level)
+{
+	int i;
+
+	if (isdigit(log_string[0])) {
+		int level = atoi(log_string);
+
+		if (level >= 0 && level < ARRAY_SIZE(log_string_map)) {
+			*log_level = debug_level_from_int(level);
+			return true;
+		}
+		return false;
+	}
+
+	for (i=0; i<ARRAY_SIZE(log_string_map); i++) {
+		if (strncasecmp(log_string_map[i].log_string,
+				log_string, strlen(log_string)) == 0) {
+			*log_level = log_string_map[i].log_level;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+const char *debug_level_to_string(enum debug_level log_level)
+{
+	int i;
+
+	for (i=0; ARRAY_SIZE(log_string_map); i++) {
+		if (log_string_map[i].log_level == log_level) {
+			return log_string_map[i].log_string;
+		}
+	}
+	return "UNKNOWN";
+}
+
+enum debug_level debug_level_from_string(const char *log_string)
+{
+	bool found;
+	enum debug_level log_level;
+
+	found = debug_level_parse(log_string, &log_level);
+	if (found) {
+		return log_level;
+	}
+
+	/* Default debug level */
+	return DEBUG_ERR;
+}
+
+int debug_level_to_int(enum debug_level log_level)
+{
+	return (int)log_level;
+}
+
+enum debug_level debug_level_from_int(int level)
+{
+	enum debug_level log_level;
+
+	if (level >= 0 && level < ARRAY_SIZE(log_string_map)) {
+		log_level = log_string_map[level].log_level;
+	} else {
+		log_level = DEBUG_ERR;
+	}
+
+	return log_level;
+}
diff --git a/ctdb/common/logging.h b/ctdb/common/logging.h
new file mode 100644
index 0000000..64b835c
--- /dev/null
+++ b/ctdb/common/logging.h
@@ -0,0 +1,41 @@
+/*
+   Logging utilities
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_LOGGING_H__
+#define __CTDB_LOGGING_H__
+
+enum debug_level {
+	DEBUG_ERR     =  0,
+	DEBUG_WARNING =  1,
+	DEBUG_NOTICE  =  2,
+	DEBUG_INFO    =  3,
+	DEBUG_DEBUG   =  4,
+};
+
+/* These are used in many places, so define them here to avoid churn */
+#define DEBUG_ALERT DEBUG_ERR
+#define	DEBUG_CRIT  DEBUG_ERR
+
+bool debug_level_parse(const char *log_string, enum debug_level *log_level);
+const char *debug_level_to_string(enum debug_level log_level);
+enum debug_level debug_level_from_string(const char *log_string);
+int debug_level_to_int(enum debug_level log_level);
+enum debug_level debug_level_from_int(int log_int);
+
+#endif /* __CTDB_LOGGING_H__ */
diff --git a/ctdb/common/pkt_read.c b/ctdb/common/pkt_read.c
new file mode 100644
index 0000000..212ace5
--- /dev/null
+++ b/ctdb/common/pkt_read.c
@@ -0,0 +1,190 @@
+/*
+   Reading packets using fixed and dynamic buffer
+
+   Copyright (C) Amitay Isaacs 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This is similar to read_packet abstraction.  The main different is that
+ * tevent fd event is created only once.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/tevent_unix.h"
+
+#include "pkt_read.h"
+
+/*
+ * Read a packet using fixed buffer
+ */
+
+struct pkt_read_state {
+	int fd;
+	uint8_t *buf;
+	size_t buflen;
+	size_t nread, total;
+	bool use_fixed;
+	ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
+	void *private_data;
+};
+
+struct tevent_req *pkt_read_send(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 int fd, size_t initial,
+				 uint8_t *buf, size_t buflen,
+				 ssize_t (*more)(uint8_t *buf,
+						 size_t buflen,
+						 void *private_data),
+				 void *private_data)
+{
+	struct tevent_req *req;
+	struct pkt_read_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct pkt_read_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->fd = fd;
+
+	if (buf == NULL || buflen == 0) {
+		state->use_fixed = false;
+		state->buf = talloc_array(state, uint8_t, initial);
+		if (state->buf == NULL) {
+			talloc_free(req);
+			return NULL;
+		}
+		state->buflen = initial;
+	} else {
+		state->use_fixed = true;
+		state->buf = buf;
+		state->buflen = buflen;
+	}
+
+	state->nread = 0;
+	state->total = initial;
+
+	state->more = more;
+	state->private_data = private_data;
+
+	return req;
+}
+
+void pkt_read_handler(struct tevent_context *ev, struct tevent_fd *fde,
+		      uint16_t flags, struct tevent_req *req)
+{
+	struct pkt_read_state *state = tevent_req_data(
+		req, struct pkt_read_state);
+	ssize_t nread, more;
+	uint8_t *tmp;
+
+	nread = read(state->fd, state->buf + state->nread,
+		     state->total - state->nread);
+	if ((nread == -1) && (errno == EINTR)) {
+		/* retry */
+		return;
+	}
+	if (nread == -1) {
+		tevent_req_error(req, errno);
+		return;
+	}
+	if (nread == 0) {
+		/* fd closed */
+		tevent_req_error(req, EPIPE);
+		return;
+	}
+
+	state->nread += nread;
+	if (state->nread < state->total) {
+		/* come back later */
+		return;
+	}
+
+	/* Check if "more" asks for more data */
+	if (state->more == NULL) {
+		tevent_req_done(req);
+		return;
+	}
+
+	more = state->more(state->buf, state->nread, state->private_data);
+	if (more == -1) {
+		/* invalid packet */
+		tevent_req_error(req, EIO);
+		return;
+	}
+	if (more == 0) {
+		tevent_req_done(req);
+		return;
+	}
+
+	if (state->total + more < state->total) {
+		/* int wrapped */
+		tevent_req_error(req, EMSGSIZE);
+		return;
+	}
+
+	if (state->total + more < state->buflen) {
+		/* continue using fixed buffer */
+		state->total += more;
+		return;
+	}
+
+	if (state->use_fixed) {
+		/* switch to dynamic buffer */
+		tmp = talloc_array(state, uint8_t, state->total + more);
+		if (tevent_req_nomem(tmp, req)) {
+			return;
+		}
+
+		memcpy(tmp, state->buf, state->total);
+		state->use_fixed = false;
+	} else {
+		tmp = talloc_realloc(state, state->buf, uint8_t,
+				     state->total + more);
+		if (tevent_req_nomem(tmp, req)) {
+			return;
+		}
+	}
+
+	state->buf = tmp;
+	state->buflen = state->total + more;
+	state->total += more;
+}
+
+ssize_t pkt_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+		      uint8_t **pbuf, bool *free_buf, int *perrno)
+{
+	struct pkt_read_state *state = tevent_req_data(
+		req, struct pkt_read_state);
+
+	if (tevent_req_is_unix_error(req, perrno)) {
+		return -1;
+	}
+
+	if (state->use_fixed) {
+		*pbuf = state->buf;
+		*free_buf = false;
+	} else {
+		*pbuf = talloc_steal(mem_ctx, state->buf);
+		*free_buf = true;
+	}
+
+	return state->total;
+}
diff --git a/ctdb/common/pkt_read.h b/ctdb/common/pkt_read.h
new file mode 100644
index 0000000..25d4a51
--- /dev/null
+++ b/ctdb/common/pkt_read.h
@@ -0,0 +1,98 @@
+/*
+   API for reading packets using fixed and dynamic buffer
+
+   Copyright (C) Amitay Isaacs 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_PKT_READ_H__
+#define __CTDB_PKT_READ_H__
+
+#include <talloc.h>
+#include <tevent.h>
+
+/**
+ * @file pkt_read.h
+ *
+ * @brief Read a packet using fixed size buffer or allocated memory.
+ *
+ * CTDB communication uses lots of small packets.  This abstraction avoids the
+ * need to allocate memory for small packets.  Only if the received packet is
+ * larger than the fixed memory buffer, use talloc to allocate memory.
+ */
+
+/**
+ * @brief Start async computation to read a packet
+ *
+ * This returns a tevent request to read a packet from given fd.  The fd
+ * should be nonblocking. Freeing this request will free all the memory
+ * associated with the request.
+ *
+ * @param[in] mem_ctx Talloc memory context
+ * @param[in] ev Tevent context
+ * @param[in] fd The non-blocking file/socket descriptor to read from
+ * @param[in] initial Initial amount of data to read
+ * @param[in] buf The static buffer to read data in
+ * @param[in] buflen The size of the static buffer
+ * @param[in] more The function to check if the bytes read forms a packet
+ * @param[in] private_data Private data to pass to more function
+ * @return new tevent request or NULL on failure
+ */
+struct tevent_req *pkt_read_send(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 int fd, size_t initial,
+				 uint8_t *buf, size_t buflen,
+				 ssize_t (*more)(uint8_t *buf,
+						 size_t buflen,
+						 void *private_data),
+				 void *private_data);
+
+/**
+ * @brief Function to actually read data from the socket
+ *
+ * This function should be called, when tevent fd event is triggered.  This
+ * function has the syntax of tevent_fd_handler_t.  The private_data for this
+ * function is the tevent request created by pkt_read_send function.
+ *
+ * @param[in] ev Tevent context
+ * @param[in] fde Tevent fd context
+ * @param[in] flags Tevent fd flags
+ * @param[in] req The active tevent request
+ */
+void pkt_read_handler(struct tevent_context *ev, struct tevent_fd *fde,
+		      uint16_t flags, struct tevent_req *req);
+
+/**
+ * @brief Retrieve a packet
+ *
+ * This function returns the pkt read from fd.
+ *
+ * @param[in] req Tevent request
+ * @param[in] mem_ctx Talloc memory context
+ * @param[out] pbuf The pointer to the buffer
+ * @param[out] free_buf Boolean to indicate that caller should free buffer
+ * @param[out] perrno errno in case of failure
+ * @return the size of the pkt, or -1 on failure
+ *
+ * If the pkt data is dynamically allocated, then it is moved under the
+ * specified talloc memory context and free_buf is set to true.  It is the
+ * responsibility of the caller to the free the memory returned.
+ *
+ * If the pkt data is stored in the fixed buffer, then free_buf is set to false.
+ */
+ssize_t pkt_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+		      uint8_t **pbuf, bool *free_buf, int *perrno);
+
+#endif /* __CTDB_PKT_READ_H__ */
diff --git a/ctdb/common/pkt_write.c b/ctdb/common/pkt_write.c
new file mode 100644
index 0000000..b1c1730
--- /dev/null
+++ b/ctdb/common/pkt_write.c
@@ -0,0 +1,101 @@
+/*
+   Write a packet
+
+   Copyright (C) Amitay Isaacs 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/tevent_unix.h"
+
+#include "pkt_write.h"
+
+/*
+ * Write a packet
+ */
+
+struct pkt_write_state {
+	int fd;
+	uint8_t *buf;
+	size_t buflen, offset;
+};
+
+struct tevent_req *pkt_write_send(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  int fd, uint8_t *buf, size_t buflen)
+{
+	struct tevent_req *req;
+	struct pkt_write_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct pkt_write_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->fd = fd;
+	state->buf = buf;
+	state->buflen = buflen;
+	state->offset = 0;
+
+	return req;
+}
+
+void pkt_write_handler(struct tevent_context *ev, struct tevent_fd *fde,
+		       uint16_t flags, struct tevent_req *req)
+{
+	struct pkt_write_state *state = tevent_req_data(
+		req, struct pkt_write_state);
+	ssize_t nwritten;
+
+	nwritten = write(state->fd, state->buf + state->offset,
+			 state->buflen - state->offset);
+	if ((nwritten == -1) && (errno == EINTR)) {
+		/* retry */
+		return;
+	}
+	if (nwritten == -1) {
+		tevent_req_error(req, errno);
+		return;
+	}
+	if (nwritten == 0) {
+		/* retry */
+		return;
+	}
+
+	state->offset += nwritten;
+	if (state->offset < state->buflen) {
+		/* come back later */
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+ssize_t pkt_write_recv(struct tevent_req *req, int *perrno)
+{
+	struct pkt_write_state *state = tevent_req_data(
+		req, struct pkt_write_state);
+
+	if (tevent_req_is_unix_error(req, perrno)) {
+		return -1;
+	}
+
+	return state->offset;
+}
diff --git a/ctdb/common/pkt_write.h b/ctdb/common/pkt_write.h
new file mode 100644
index 0000000..19d8045
--- /dev/null
+++ b/ctdb/common/pkt_write.h
@@ -0,0 +1,79 @@
+/*
+   API for writing a packet
+
+   Copyright (C) Amitay Isaacs 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_PKT_WRITE_H__
+#define __CTDB_PKT_WRITE_H__
+
+#include <talloc.h>
+#include <tevent.h>
+
+/**
+ * @file pkt_write.h
+ *
+ * @brief Write a packet.
+ *
+ * Write a complete packet with possibly multiple system calls.
+ */
+
+/**
+ * @brief Start async computation to write a packet
+ *
+ * This returns a tevent request to write a packet to given fd.  The fd
+ * should be nonblocking. Freeing this request will free all the memory
+ * associated with the request.
+ *
+ * @param[in] mem_ctx Talloc memory context
+ * @param[in] ev Tevent context
+ * @param[in] fd The non-blocking file/socket descriptor to write to
+ * @param[in] buf The data
+ * @param[in] buflen The size of the data
+ * @return new tevent request or NULL on failure
+ */
+struct tevent_req *pkt_write_send(TALLOC_CTX *mem_ctx,
+				  struct tevent_context *ev,
+				  int fd, uint8_t *buf, size_t buflen);
+
+/**
+ * @brief Function to actually write data to the socket
+ *
+ * This function should be called, when tevent fd event is triggered
+ * for TEVENT_FD_WRITE event.  This function has the syntax of
+ * tevent_fd_handler_t.  The private_data for this function is the tevent
+ * request created by pkt_write_send function.
+ *
+ * @param[in] ev Tevent context
+ * @param[in] fde Tevent fd context
+ * @param[in] flags Tevent fd flags
+ * @param[in] req The active tevent request
+ */
+void pkt_write_handler(struct tevent_context *ev, struct tevent_fd *fde,
+		       uint16_t flags, struct tevent_req *req);
+
+/**
+ * @brief Packet is sent
+ *
+ * This function returns the number of bytes written.
+ *
+ * @param[in] req Tevent request
+ * @param[out] perrno errno in case of failure
+ * @return the number of bytes written, or -1 on failure
+ */
+ssize_t pkt_write_recv(struct tevent_req *req, int *perrno);
+
+#endif /* __CTDB_PKT_WRITE_H__ */
diff --git a/ctdb/common/rb_tree.c b/ctdb/common/rb_tree.c
index 6b131bc..1c602a7 100644
--- a/ctdb/common/rb_tree.c
+++ b/ctdb/common/rb_tree.c
@@ -17,8 +17,14 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "rb_tree.h"
+#include "replace.h"
+
+#include <talloc.h>
+
+#include "lib/util/debug.h"
+
+#include "common/logging.h"
+#include "common/rb_tree.h"
 
 #define NO_MEMORY_FATAL(p) do { if (!(p)) { \
           DEBUG(DEBUG_CRIT,("Out of memory for %s at %s\n", #p, __location__)); \
@@ -58,9 +64,9 @@ static int tree_destructor(trbt_tree_t *tree)
 
 	/* traverse the tree and remove the node destructor and steal
 	   the node to the temporary context.
-	   we dont want to use the existing destructor for the node
+	   we don't want to use the existing destructor for the node
 	   since that will remove the nodes one by one from the tree.
-	   since the entire tree will be completely destroyed we dont care
+	   since the entire tree will be completely destroyed we don't care
 	   if it is inconsistent or unbalanced while freeing the
 	   individual nodes
 	*/
@@ -498,7 +504,7 @@ delete_node(trbt_node_t *node, bool from_destructor)
 	   Once the delete of the node is finished, we remove this dummy
 	   node, which is simple to do since it is guaranteed that it will
 	   still not have any children after the delete operation.
-	   This is because we dont represent the leaf-nodes as actual nodes
+	   This is because we don't represent the leaf-nodes as actual nodes
 	   in this implementation.
 	 */
 	if (!child) {
diff --git a/ctdb/common/reqid.c b/ctdb/common/reqid.c
new file mode 100644
index 0000000..0e651cf
--- /dev/null
+++ b/ctdb/common/reqid.c
@@ -0,0 +1,89 @@
+/*
+   ctdb request id handling code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include <talloc.h>
+
+#include "lib/util/idtree.h"
+#include "reqid.h"
+
+struct reqid_context {
+	struct idr_context *idr;
+	uint32_t lastid;
+};
+
+int reqid_init(TALLOC_CTX *mem_ctx, int start_id,
+	       struct reqid_context **result)
+{
+	struct reqid_context *reqid_ctx;
+
+	reqid_ctx = talloc_zero(mem_ctx, struct reqid_context);
+	if (reqid_ctx == NULL) {
+		return ENOMEM;
+	}
+
+	reqid_ctx->idr = idr_init(reqid_ctx);
+	if (reqid_ctx->idr == NULL) {
+		talloc_free(reqid_ctx);
+		return ENOMEM;
+	}
+
+	if (start_id <= 0) {
+		start_id = 1;
+	}
+	reqid_ctx->lastid = start_id;
+
+	*result = reqid_ctx;
+	return 0;
+}
+
+uint32_t reqid_new(struct reqid_context *reqid_ctx, void *private_data)
+{
+	int id;
+
+	id = idr_get_new_above(reqid_ctx->idr, private_data,
+			       reqid_ctx->lastid+1, INT_MAX);
+	if (id < 0) {
+		/* reqid wrapped */
+		id = idr_get_new(reqid_ctx->idr, private_data, INT_MAX);
+	}
+	if (id == -1) {
+		return REQID_INVALID;
+	}
+
+	reqid_ctx->lastid = id;
+	return id;
+}
+
+void *_reqid_find(struct reqid_context *reqid_ctx, uint32_t reqid)
+{
+	return idr_find(reqid_ctx->idr, reqid);
+}
+
+int reqid_remove(struct reqid_context *reqid_ctx, uint32_t reqid)
+{
+	int ret;
+
+	ret = idr_remove(reqid_ctx->idr, reqid);
+	if (ret < 0) {
+		return ENOENT;
+	}
+	return 0;
+}
diff --git a/ctdb/common/reqid.h b/ctdb/common/reqid.h
new file mode 100644
index 0000000..736e5b3
--- /dev/null
+++ b/ctdb/common/reqid.h
@@ -0,0 +1,89 @@
+/*
+   Request id database
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_REQID_H__
+#define __CTDB_REQID_H__
+
+#include <talloc.h>
+
+/**
+ * @file reqid.h
+ *
+ * @brief Request id database
+ *
+ * CTDB tracks messsages using request id. CTDB stores client state for each
+ * request id to process the replies correctly.
+ */
+
+/**
+ * @brief Abstract struct to store request id database
+ */
+struct reqid_context;
+
+#define REQID_INVALID	0xffffffff
+
+/**
+ * @brief Initialize request id database
+ *
+ * This returns a new request id context. Freeing this context will free
+ * all the memory associated with request id database.
+ *
+ * @param[in] mem_ctx Talloc memory context
+ * @param[in] start_id The initial id
+ * @param[out] result The new talloc_context structure
+ * @return 0 on success, errno on failure
+ */
+int reqid_init(TALLOC_CTX *mem_ctx, int start_id,
+	       struct reqid_context **result);
+
+/**
+ * @brief Generate new request id and associate given data with the request id
+ *
+ * @param[in] reqid_ctx The request id context
+ * @param[in] private_data The state to associate with new request id
+ * @return new request id, REQID_INVALID on failure
+ */
+uint32_t reqid_new(struct reqid_context *reqid_ctx, void *private_data);
+
+#ifdef DOXYGEN
+/**
+ * @brief Fetch the data associated with the request id
+ *
+ * @param[in] reqid_ctx The request id context
+ * @param[in] reqid The request id
+ * @param[in] type The data type of the stored data
+ * @return the data stored for the reqid, NULL on failure
+ */
+type *reqid_find(struct reqid_context *reqid_ctx, uint32_t reqid, #type);
+#else
+void *_reqid_find(struct reqid_context *reqid_ctx, uint32_t reqid);
+#define reqid_find(ctx, reqid, type) \
+	(type *)talloc_check_name(_reqid_find(ctx, reqid), #type)
+#endif
+
+/**
+ * @brief Remove the data associated with the request id
+ *
+ * @param[in] reqid_ctx The request id context
+ * @param[in] reqid The request id
+ * @return 0 on success, errno on failure
+ */
+int reqid_remove(struct reqid_context *reqid_ctx, uint32_t reqid);
+
+#endif /* __CTDB_REQID_H__ */
diff --git a/ctdb/common/srvid.c b/ctdb/common/srvid.c
new file mode 100644
index 0000000..f9cd49b
--- /dev/null
+++ b/ctdb/common/srvid.c
@@ -0,0 +1,269 @@
+/*
+   Message handler database based on srvid
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+
+#include <tdb.h>
+
+#include "lib/util/dlinklist.h"
+#include "common/db_hash.h"
+#include "common/srvid.h"
+
+struct srvid_handler_list;
+
+struct srvid_context {
+	struct db_hash_context *dh;
+	struct srvid_handler_list *list;
+};
+
+struct srvid_handler {
+	struct srvid_handler *prev, *next;
+	struct srvid_handler_list *list;
+	srvid_handler_fn handler;
+	void *private_data;
+};
+
+struct srvid_handler_list {
+	struct srvid_handler_list *prev, *next;
+	struct srvid_context *srv;
+	uint64_t srvid;
+	struct srvid_handler *h;
+};
+
+
+/*
+ * Initialise message srvid context and database
+ */
+int srvid_init(TALLOC_CTX *mem_ctx, struct srvid_context **result)
+{
+	struct srvid_context *srv;
+	int ret;
+
+	srv = talloc_zero(mem_ctx, struct srvid_context);
+	if (srv == NULL) {
+		return ENOMEM;
+	}
+
+	ret = db_hash_init(srv, "messagedb", 8192, DB_HASH_SIMPLE, &srv->dh);
+	if (ret != 0) {
+		talloc_free(srv);
+		return ret;
+	}
+
+	*result = srv;
+	return 0;
+}
+
+/*
+ * Wrapper functions to insert/delete/fetch srvid_hander_list
+ */
+
+static int srvid_insert(struct srvid_context *srv, uint64_t srvid,
+			struct srvid_handler_list *list)
+{
+	return db_hash_insert(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t),
+			      (uint8_t *)&list, sizeof(list));
+}
+
+static int srvid_delete(struct srvid_context *srv, uint64_t srvid)
+{
+	return db_hash_delete(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t));
+}
+
+static int srvid_fetch_parser(uint8_t *keybuf, size_t keylen,
+			      uint8_t *databuf, size_t datalen,
+			      void *private_data)
+{
+	struct srvid_handler_list **list =
+		(struct srvid_handler_list **)private_data;
+
+	if (datalen != sizeof(*list)) {
+		return EIO;
+	}
+
+	*list = *(struct srvid_handler_list **)databuf;
+	return 0;
+}
+
+static int srvid_fetch(struct srvid_context *srv, uint64_t srvid,
+		       struct srvid_handler_list **list)
+{
+	return db_hash_fetch(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t),
+			     srvid_fetch_parser, list);
+}
+
+/*
+ * When a handler is freed, remove it from the list
+ */
+static int srvid_handler_destructor(struct srvid_handler *h)
+{
+	struct srvid_handler_list *list = h->list;
+
+	DLIST_REMOVE(list->h, h);
+	if (list->h == NULL) {
+		talloc_free(list);
+	}
+	return 0;
+}
+
+/*
+ * When a list is freed, remove all handlers and remove db entry
+ */
+static int srvid_handler_list_destructor(struct srvid_handler_list *list)
+{
+	struct srvid_handler *h;
+
+	while (list->h != NULL) {
+		h = list->h;
+		DLIST_REMOVE(list->h, h);
+		TALLOC_FREE(h);
+	}
+
+	srvid_delete(list->srv, list->srvid);
+	DLIST_REMOVE(list->srv->list, list);
+	return 0;
+}
+
+/*
+ * Register a message handler
+ */
+int srvid_register(struct srvid_context *srv, TALLOC_CTX *mem_ctx,
+		   uint64_t srvid, srvid_handler_fn handler,
+		   void *private_data)
+{
+	struct srvid_handler_list *list;
+	struct srvid_handler *h;
+	int ret;
+
+	if (srv == NULL) {
+		return EINVAL;
+	}
+
+	h = talloc_zero(mem_ctx, struct srvid_handler);
+	if (h == NULL) {
+		return ENOMEM;
+	}
+
+	h->handler = handler;
+	h->private_data = private_data;
+
+	ret = srvid_fetch(srv, srvid, &list);
+	if (ret != 0) {
+		/* srvid not yet registered */
+		list = talloc_zero(srv, struct srvid_handler_list);
+		if (list == NULL) {
+			talloc_free(h);
+			return ENOMEM;
+		}
+
+		list->srv = srv;
+		list->srvid = srvid;
+
+		ret = srvid_insert(srv, srvid, list);
+		if (ret != 0) {
+			talloc_free(h);
+			talloc_free(list);
+			return ret;
+		}
+
+		DLIST_ADD(srv->list, list);
+		talloc_set_destructor(list, srvid_handler_list_destructor);
+	}
+
+	h->list = list;
+	DLIST_ADD(list->h, h);
+	talloc_set_destructor(h, srvid_handler_destructor);
+	return 0;
+}
+
+/*
+ * Deregister a message handler
+ */
+int srvid_deregister(struct srvid_context *srv, uint64_t srvid,
+		     void *private_data)
+{
+	struct srvid_handler_list *list;
+	struct srvid_handler *h;
+	int ret;
+
+	ret = srvid_fetch(srv, srvid, &list);
+	if (ret != 0) {
+		return ret;
+	}
+
+	for (h = list->h; h != NULL; h = h->next) {
+		if (h->private_data == private_data) {
+			talloc_free(h);
+			return 0;
+		}
+	}
+
+	return ENOENT;
+}
+
+/*
+ * Check if a message handler exists
+ */
+int srvid_exists(struct srvid_context *srv, uint64_t srvid)
+{
+	struct srvid_handler_list *list;
+	int ret;
+
+	ret = srvid_fetch(srv, srvid, &list);
+	if (ret != 0) {
+		return ret;
+	}
+	if (list->h == NULL) {
+		return ENOENT;
+	}
+
+	return 0;
+}
+
+/*
+ * Send a message to registered srvid and srvid_all
+ */
+int srvid_dispatch(struct srvid_context *srv, uint64_t srvid,
+		    uint64_t srvid_all, TDB_DATA data)
+{
+	struct srvid_handler_list *list;
+	struct srvid_handler *h;
+	int ret;
+
+	ret = srvid_fetch(srv, srvid, &list);
+	if (ret == 0) {
+		for (h = list->h; h != NULL; h = h->next) {
+			h->handler(srvid, data, h->private_data);
+		}
+	}
+
+	if (srvid_all == 0) {
+		return ret;
+	}
+
+	ret = srvid_fetch(srv, srvid_all, &list);
+	if (ret == 0) {
+		for (h = list->h; h != NULL; h = h->next) {
+			h->handler(srvid, data, h->private_data);
+		}
+	}
+
+	return ret;
+}
diff --git a/ctdb/common/srvid.h b/ctdb/common/srvid.h
new file mode 100644
index 0000000..f048b5c
--- /dev/null
+++ b/ctdb/common/srvid.h
@@ -0,0 +1,115 @@
+/*
+   Message handler database based on srvid
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_SRVID_H__
+#define __CTDB_SRVID_H__
+
+#include <talloc.h>
+#include <tdb.h>
+
+/**
+ * @file srvid.h
+ *
+ * @brief Database of message handlers based on srvid
+ *
+ * CTDB can be used to send messages between clients across nodes using
+ * CTDB_REQ_MESSAGE. Clients register for mesages based on srvid. CTDB itself
+ * uses a small set of srvid messages. A large range (2^56) of srvid messages
+ * is reserved for Samba.
+ */
+
+/**
+ * @brief Message handler function
+ *
+ * To receive messages for a specific srvid, register a message handler function
+ * for the srvid.
+ */
+typedef void (*srvid_handler_fn)(uint64_t srvid, TDB_DATA data,
+				 void *private_data);
+
+/**
+ * @brief Abstract struct to store srvid message handler database
+ */
+struct srvid_context;
+
+/**
+ * @brief Initialize srvid message handler database
+ *
+ * This returns a new srvid message handler database context. Freeing
+ * this context will free all the memory associated with the hash table.
+ *
+ * @param[in] mem_ctx Talloc memory context
+ * @param[out] result The new db_hash_context structure
+ * @return 0 on success, errno on failure
+ */
+int srvid_init(TALLOC_CTX *mem_ctx, struct srvid_context **result);
+
+/**
+ * @brief Register a message handler for a srvid
+ *
+ * The message handler is allocated using the specified talloc context. Freeing
+ * this talloc context, removes the message handler.
+ *
+ * @param[in] srv The srvid message handler database context
+ * @param[in] mem_ctx Talloc memory context for message handler
+ * @param[in] srvid The srvid
+ * @param[in] handler The message handler function for srvid
+ * @param[in] private_data Private data for message handler function
+ * @return 0 on success, errno on failure
+ */
+int srvid_register(struct srvid_context *srv, TALLOC_CTX *mem_ctx,
+		   uint64_t srvid, srvid_handler_fn handler,
+		   void *private_data);
+
+/**
+ * @brief Unregister a message handler for a srvid
+ *
+ * @param[in] srv The srvid message handler database context
+ * @param[in] srvid The srvid
+ * @param[in] private_data Private data of message handler function
+ * @return 0 on success, errno on failure
+ */
+int srvid_deregister(struct srvid_context *srv, uint64_t srvid,
+		     void *private_data);
+
+/**
+ * @brief Check if any message handler is registered for srvid
+ *
+ * @param[in] srv The srvid message handler database context
+ * @param[in] srvid The srvid
+ * @return 0 on success, errno on failure
+ */
+int srvid_exists(struct srvid_context *srv, uint64_t srvid);
+
+/**
+ * @brief Call message handlers for given srvid
+ *
+ * @param[in] srv The srvid message handler database context
+ * @param[in] srvid The srvid
+ * @param[in] srvid_all The srvid that gets all messages
+ * @param[in] data The data passed to each message handler
+ * @return 0 on success, errno on failure
+ *
+ * If srvid_all passed is 0, the message is not sent to message handlers
+ * registered with special srvid to receive all messages.
+ */
+int srvid_dispatch(struct srvid_context *srv, uint64_t srvid,
+		   uint64_t srvid_all, TDB_DATA data);
+
+#endif /* __CTDB_SRVID_H__ */
diff --git a/ctdb/common/system.h b/ctdb/common/system.h
new file mode 100644
index 0000000..ba11d20
--- /dev/null
+++ b/ctdb/common/system.h
@@ -0,0 +1,65 @@
+/*
+   System specific code
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_SYSTEM_H__
+#define __CTDB_SYSTEM_H__
+
+/* From system_common.c */
+
+uint32_t uint16_checksum(uint16_t *data, size_t n);
+bool ctdb_sys_have_ip(ctdb_sock_addr *_addr);
+char *ctdb_sys_find_ifname(ctdb_sock_addr *addr);
+
+/* From system_<os>.c */
+
+int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface);
+int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
+		      const ctdb_sock_addr *src,
+		      uint32_t seq, uint32_t ack, int rst);
+int ctdb_sys_open_capture_socket(const char *iface, void **private_data);
+int ctdb_sys_close_capture_socket(void *private_data);
+int ctdb_sys_read_tcp_packet(int s, void *private_data,
+			ctdb_sock_addr *src, ctdb_sock_addr *dst,
+			uint32_t *ack_seq, uint32_t *seq);
+bool ctdb_sys_check_iface_exists(const char *iface);
+int ctdb_get_peer_pid(const int fd, pid_t *peer_pid);
+
+/* From system_util.c */
+
+bool set_scheduler(void);
+void reset_scheduler(void);
+void set_nonblocking(int fd);
+void set_close_on_exec(int fd);
+
+bool parse_ipv4(const char *s, unsigned port, struct sockaddr_in *sin);
+bool parse_ip(const char *addr, const char *ifaces, unsigned port,
+	      ctdb_sock_addr *saddr);
+bool parse_ip_mask(const char *str, const char *ifaces, ctdb_sock_addr *addr,
+		   unsigned *mask);
+bool parse_ip_port(const char *addr, ctdb_sock_addr *saddr);
+
+void lockdown_memory(bool valgrinding);
+
+int mkdir_p(const char *dir, int mode);
+void mkdir_p_or_die(const char *dir, int mode);
+
+ssize_t sys_read(int fd, void *buf, size_t count);
+ssize_t sys_write(int fd, const void *buf, size_t count);
+
+#endif /* __CTDB_SYSTEM_H__ */
diff --git a/ctdb/common/system_aix.c b/ctdb/common/system_aix.c
index 2637442..2d35a22 100644
--- a/ctdb/common/system_aix.c
+++ b/ctdb/common/system_aix.c
@@ -19,11 +19,15 @@
 */
 
 
-#include "includes.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
+
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+
 #include <netinet/if_ether.h>
 #include <netinet/ip6.h>
 #include <net/if_arp.h>
@@ -31,6 +35,8 @@
 #include <sys/kinfo.h>
 #include <pcap.h>
 
+#include "common/logging.h"
+#include "common/system.h"
 
 
 #if 0
@@ -206,7 +212,7 @@ int ctdb_sys_close_capture_socket(void *private_data)
  */
 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 {
-	/* FIXME AIX: We dont do gratuitous arp yet */
+	/* FIXME AIX: We don't do gratuitous arp yet */
 	return -1;
 }
 
@@ -373,27 +379,3 @@ int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
 	}
 	return ret;
 }
-
-char *ctdb_get_process_name(pid_t pid)
-{
-	/* FIXME AIX: get_process_name not implemented */
-	return NULL;
-}
-
-int ctdb_set_process_name(const char *name)
-{
-	/* FIXME AIX: set_process_name not implemented */
-	return -ENOSYS;
-}
-
-bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
-{
-	/* FIXME AIX: get_lock_info not implemented */
-	return false;
-}
-
-bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
-{
-	/* FIXME AIX: get_blocker_pid not implemented */
-	return false;
-}
diff --git a/ctdb/common/system_common.c b/ctdb/common/system_common.c
index 3e30a6c..a80189c 100644
--- a/ctdb/common/system_common.c
+++ b/ctdb/common/system_common.c
@@ -18,10 +18,15 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/network.h"
 
-#include "ctdb_private.h"
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+
+#include "common/logging.h"
+#include "common/system.h"
 
 /*
   uint16 checksum for n bytes
diff --git a/ctdb/common/system_freebsd.c b/ctdb/common/system_freebsd.c
index 02f7cce..37e4bae 100644
--- a/ctdb/common/system_freebsd.c
+++ b/ctdb/common/system_freebsd.c
@@ -24,16 +24,22 @@
   needs, and inspired by 'common/system_aix.c' for the pcap usage.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
+
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+
 #include <net/ethernet.h>
 #include <netinet/ip6.h>
 #include <net/if_arp.h>
 #include <pcap.h>
 
+#include "common/logging.h"
+#include "common/system.h"
 
 #ifndef ETHERTYPE_IP6
 #define ETHERTYPE_IP6 0x86dd
@@ -75,7 +81,7 @@ static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
  */
 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 {
-	/* FIXME FreeBSD: We dont do gratuitous arp yet */
+	/* FIXME FreeBSD: We don't do gratuitous arp yet */
 	return -1;
 }
 
@@ -214,7 +220,7 @@ int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
 			return -1;
 
 		}
-		/* sendto() dont like if the port is set and the socket is
+		/* sendto() don't like if the port is set and the socket is
 		   in raw mode.
 		*/
 		tmpdest = discard_const(dest);
@@ -369,41 +375,3 @@ int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
 	/* FIXME FreeBSD: get_peer_pid not implemented */
 	return 1;
 }
-
-char *ctdb_get_process_name(pid_t pid)
-{
-	char path[32];
-	char buf[PATH_MAX];
-	char *ptr;
-	int n;
-
-	snprintf(path, sizeof(path), "/proc/%d/exe", pid);
-	n = readlink(path, buf, sizeof(buf));
-	if (n < 0) {
-		return NULL;
-	}
-
-	/* Remove any extra fields */
-	buf[n] = '\0';
-	ptr = strtok(buf, " ");
-	return strdup(ptr);
-	return NULL;
-}
-
-int ctdb_set_process_name(const char *name)
-{
-	/* FIXME FreeBSD: set_process_name not implemented */
-	return -ENOSYS;
-}
-
-bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
-{
-	/* FIXME FreeBSD: get_lock_info not implemented */
-	return false;
-}
-
-bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
-{
-	/* FIXME FreeBSD: get_blocker_pid not implemented */
-	return false;
-}
diff --git a/ctdb/common/system_gnu.c b/ctdb/common/system_gnu.c
index 1e0ae4c..e5b8e05 100644
--- a/ctdb/common/system_gnu.c
+++ b/ctdb/common/system_gnu.c
@@ -23,16 +23,22 @@
   and inspired by 'common/system_aix.c' for the pcap usage.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
+
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+
 #include <net/ethernet.h>
 #include <netinet/ip6.h>
 #include <net/if_arp.h>
 #include <pcap.h>
 
+#include "common/logging.h"
+#include "common/system.h"
 
 #ifndef ETHERTYPE_IP6
 #define ETHERTYPE_IP6 0x86dd
@@ -74,7 +80,7 @@ static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
  */
 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 {
-	/* FIXME GNU/Hurd: We dont do gratuitous arp yet */
+	/* FIXME GNU/Hurd: We don't do gratuitous arp yet */
 	return -1;
 }
 
@@ -209,7 +215,7 @@ int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
 			return -1;
 
 		}
-		/* sendto() dont like if the port is set and the socket is
+		/* sendto() don't like if the port is set and the socket is
 		   in raw mode.
 		*/
 		tmpdest = discard_const(dest);
@@ -362,27 +368,3 @@ int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
 	/* FIXME GNU/Hurd: get_peer_pid not implemented */
 	return 1;
 }
-
-char *ctdb_get_process_name(pid_t pid)
-{
-	/* FIXME GNU/Hurd: get_process_name not implemented */
-	return NULL;
-}
-
-int ctdb_set_process_name(const char *name)
-{
-	/* FIXME GNU/Hurd: set_process_name not implemented */
-	return -ENOSYS;
-}
-
-bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
-{
-	/* FIXME GNU/Hurd: get_lock_info not implemented */
-	return false;
-}
-
-bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
-{
-	/* FIXME GNU/Hurd: get_blocker_pid not implemented */
-	return false;
-}
diff --git a/ctdb/common/system_kfreebsd.c b/ctdb/common/system_kfreebsd.c
index 7cb6d92..4be678d 100644
--- a/ctdb/common/system_kfreebsd.c
+++ b/ctdb/common/system_kfreebsd.c
@@ -23,16 +23,22 @@
   needs, and inspired by 'common/system_aix.c' for the pcap usage.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
+
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+
 #include <net/ethernet.h>
 #include <netinet/ip6.h>
 #include <net/if_arp.h>
 #include <pcap.h>
 
+#include "common/logging.h"
+#include "common/system.h"
 
 #ifndef ETHERTYPE_IP6
 #define ETHERTYPE_IP6 0x86dd
@@ -74,7 +80,7 @@ static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
  */
 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 {
-	/* FIXME kFreeBSD: We dont do gratuitous arp yet */
+	/* FIXME kFreeBSD: We don't do gratuitous arp yet */
 	return -1;
 }
 
@@ -209,7 +215,7 @@ int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
 			return -1;
 
 		}
-		/* sendto() dont like if the port is set and the socket is
+		/* sendto() don't like if the port is set and the socket is
 		   in raw mode.
 		*/
 		tmpdest = discard_const(dest);
@@ -362,40 +368,3 @@ int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
 	/* FIXME kFreeBSD: get_peer_pid not implemented */
 	return 1;
 }
-
-char *ctdb_get_process_name(pid_t pid)
-{
-	char path[32];
-	char buf[PATH_MAX];
-	char *ptr;
-	int n;
-
-	snprintf(path, sizeof(path), "/proc/%d/exe", pid);
-	n = readlink(path, buf, sizeof(buf));
-	if (n < 0) {
-		return NULL;
-	}
-
-	/* Remove any extra fields */
-	buf[n] = '\0';
-	ptr = strtok(buf, " ");
-	return strdup(ptr);
-}
-
-int ctdb_set_process_name(const char *name)
-{
-	/* FIXME kFreeBSD: set_process_name not implemented */
-	return -ENOSYS;
-}
-
-bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
-{
-	/* FIXME kFreeBSD: get_lock_info not implemented */
-	return false;
-}
-
-bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
-{
-	/* FIXME kFreeBSD: get_blocker_pid not implemented */
-	return false;
-}
diff --git a/ctdb/common/system_linux.c b/ctdb/common/system_linux.c
index 2e58853..6d01699 100644
--- a/ctdb/common/system_linux.c
+++ b/ctdb/common/system_linux.c
@@ -18,11 +18,15 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
+
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+
 #include <netinet/if_ether.h>
 #include <netinet/ip6.h>
 #include <netinet/icmp6.h>
@@ -30,6 +34,9 @@
 #include <netpacket/packet.h>
 #include <sys/prctl.h>
 
+#include "common/logging.h"
+#include "common/system.h"
+
 #ifndef ETHERTYPE_IP6
 #define ETHERTYPE_IP6 0x86dd
 #endif
@@ -93,7 +100,7 @@ int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 
 	switch (addr->ip.sin_family) {
 	case AF_INET:
-		s = socket(AF_PACKET, SOCK_RAW, ETHERTYPE_ARP);
+		s = socket(AF_PACKET, SOCK_RAW, 0);
 		if (s == -1){
 			DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
 			return -1;
@@ -187,7 +194,7 @@ int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 		close(s);
 		break;
 	case AF_INET6:
-		s = socket(AF_PACKET, SOCK_RAW, ETHERTYPE_ARP);
+		s = socket(AF_PACKET, SOCK_RAW, 0);
 		if (s == -1){
 			DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
 			return -1;
@@ -240,7 +247,13 @@ int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 		ip6->ip6_hlim = 255;
 		ip6->ip6_src  = addr->ip6.sin6_addr;
 		/* all-nodes multicast */
-		inet_pton(AF_INET6, "ff02::1", &ip6->ip6_dst);
+
+		ret = inet_pton(AF_INET6, "ff02::1", &ip6->ip6_dst);
+		if (ret != 1) {
+			close(s);
+			DEBUG(DEBUG_CRIT,(__location__ " failed inet_pton\n"));
+			return -1;
+		}
 
 		nd_na = (struct nd_neighbor_advert *)(ip6+1);
 		nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
@@ -412,7 +425,7 @@ int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
 			return -1;
 
 		}
-		/* sendto() dont like if the port is set and the socket is
+		/* sendto() don't like if the port is set and the socket is
 		   in raw mode.
 		*/
 		tmpdest = discard_const(dest);
@@ -447,7 +460,7 @@ int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
 	int s;
 
 	/* Open a socket to capture all traffic */
-	s = socket(AF_PACKET, SOCK_RAW, ETH_P_ALL);
+	s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 	if (s == -1) {
 		DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
 		return -1;
@@ -570,7 +583,7 @@ bool ctdb_sys_check_iface_exists(const char *iface)
 
 	s = socket(AF_PACKET, SOCK_RAW, 0);
 	if (s == -1){
-		/* We dont know if the interface exists, so assume yes */
+		/* We don't know if the interface exists, so assume yes */
 		DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
 		return true;
 	}
@@ -596,192 +609,3 @@ int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
 	}
 	return ret;
 }
-
-/*
- * Find the process name from process ID
- */
-char *ctdb_get_process_name(pid_t pid)
-{
-	char path[32];
-	char buf[PATH_MAX];
-	char *ptr;
-	int n;
-
-	snprintf(path, sizeof(path), "/proc/%d/exe", pid);
-	n = readlink(path, buf, sizeof(buf)-1);
-	if (n < 0) {
-		return NULL;
-	}
-
-	/* Remove any extra fields */
-	buf[n] = '\0';
-	ptr = strtok(buf, " ");
-	return (ptr == NULL ? ptr : strdup(ptr));
-}
-
-/*
- * Set process name
- */
-int ctdb_set_process_name(const char *name)
-{
-	char procname[16];
-
-	strncpy(procname, name, 15);
-	procname[15] = '\0';
-	return prctl(PR_SET_NAME, (unsigned long)procname, 0, 0, 0);
-}
-
-/*
- * Parsing a line from /proc/locks,
- */
-static bool parse_proc_locks_line(char *line, pid_t *pid,
-				  struct ctdb_lock_info *curlock)
-{
-	char *ptr, *saveptr;
-
-	/* output of /proc/locks
-	 *
-	 * lock assigned
-	 * 1: POSIX  ADVISORY  WRITE 25945 fd:00:6424820 212 212
-	 *
-	 * lock waiting
-	 * 1: -> POSIX  ADVISORY  WRITE 25946 fd:00:6424820 212 212
-	 */
-
-	/* Id: */
-	ptr = strtok_r(line, " ", &saveptr);
-	if (ptr == NULL) return false;
-
-	/* -> */
-	ptr = strtok_r(NULL, " ", &saveptr);
-	if (ptr == NULL) return false;
-	if (strcmp(ptr, "->") == 0) {
-		curlock->waiting = true;
-		ptr = strtok_r(NULL, " ", &saveptr);
-	} else {
-		curlock->waiting = false;
-	}
-
-	/* POSIX */
-	if (ptr == NULL || strcmp(ptr, "POSIX") != 0) {
-		return false;
-	}
-
-	/* ADVISORY */
-	ptr = strtok_r(NULL, " ", &saveptr);
-	if (ptr == NULL) return false;
-
-	/* WRITE */
-	ptr = strtok_r(NULL, " ", &saveptr);
-	if (ptr == NULL) return false;
-	if (strcmp(ptr, "READ") == 0) {
-		curlock->read_only = true;
-	} else if (strcmp(ptr, "WRITE") == 0) {
-		curlock->read_only = false;
-	} else {
-		return false;
-	}
-
-	/* PID */
-	ptr = strtok_r(NULL, " ", &saveptr);
-	if (ptr == NULL) return false;
-	*pid = atoi(ptr);
-
-	/* MAJOR:MINOR:INODE */
-	ptr = strtok_r(NULL, " :", &saveptr);
-	if (ptr == NULL) return false;
-	ptr = strtok_r(NULL, " :", &saveptr);
-	if (ptr == NULL) return false;
-	ptr = strtok_r(NULL, " :", &saveptr);
-	if (ptr == NULL) return false;
-	curlock->inode = atol(ptr);
-
-	/* START OFFSET */
-	ptr = strtok_r(NULL, " ", &saveptr);
-	if (ptr == NULL) return false;
-	curlock->start = atol(ptr);
-
-	/* END OFFSET */
-	ptr = strtok_r(NULL, " ", &saveptr);
-	if (ptr == NULL) return false;
-	if (strncmp(ptr, "EOF", 3) == 0) {
-		curlock->end = (off_t)-1;
-	} else {
-		curlock->end = atol(ptr);
-	}
-
-	return true;
-}
-
-/*
- * Find information of lock being waited on for given process ID
- */
-bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
-{
-	FILE *fp;
-	struct ctdb_lock_info curlock;
-	pid_t pid;
-	char buf[1024];
-	bool status = false;
-
-	if ((fp = fopen("/proc/locks", "r")) == NULL) {
-		DEBUG(DEBUG_ERR, ("Failed to read locks information"));
-		return false;
-	}
-	while (fgets(buf, sizeof(buf), fp) != NULL) {
-		if (! parse_proc_locks_line(buf, &pid, &curlock)) {
-			continue;
-		}
-		if (pid == req_pid && curlock.waiting) {
-			*lock_info = curlock;
-			status = true;
-			break;
-		}
-	}
-	fclose(fp);
-
-	return status;
-}
-
-/*
- * Find process ID which holds an overlapping byte lock for required
- * inode and byte range.
- */
-bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
-{
-	FILE *fp;
-	struct ctdb_lock_info curlock;
-	pid_t pid;
-	char buf[1024];
-	bool status = false;
-
-	if ((fp = fopen("/proc/locks", "r")) == NULL) {
-		DEBUG(DEBUG_ERR, ("Failed to read locks information"));
-		return false;
-	}
-	while (fgets(buf, sizeof(buf), fp) != NULL) {
-		if (! parse_proc_locks_line(buf, &pid, &curlock)) {
-			continue;
-		}
-
-		if (curlock.waiting) {
-			continue;
-		}
-
-		if (curlock.inode != reqlock->inode) {
-			continue;
-		}
-
-		if (curlock.start > reqlock->end ||
-		    curlock.end < reqlock->start) {
-			/* Outside the required range */
-			continue;
-		}
-		*blocker_pid = pid;
-		status = true;
-		break;
-	}
-	fclose(fp);
-
-	return status;
-}
diff --git a/ctdb/common/system_util.c b/ctdb/common/system_util.c
index 663df6e..e6c4f17 100644
--- a/ctdb/common/system_util.c
+++ b/ctdb/common/system_util.c
@@ -18,13 +18,19 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
 #include "system/shmem.h"
+#include "system/network.h"
 
 #include <libgen.h>
 
-#include "ctdb_private.h"
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+
+#include "common/logging.h"
+#include "common/system.h"
 
 #if HAVE_SCHED_H
 #include <sched.h>
diff --git a/ctdb/config/ctdb.sudoers b/ctdb/config/ctdb.sudoers
index 1c6619b..1c23818 100644
--- a/ctdb/config/ctdb.sudoers
+++ b/ctdb/config/ctdb.sudoers
@@ -1,3 +1,3 @@
-Defaults!/etc/ctdb/statd-callout	!requiretty
+Defaults!/usr/local/etc/ctdb/statd-callout	!requiretty
 
-rpcuser		ALL=(ALL) 	NOPASSWD: /etc/ctdb/statd-callout
+rpcuser		ALL=(ALL) 	NOPASSWD: /usr/local/etc/ctdb/statd-callout
diff --git a/ctdb/config/ctdbd_wrapper b/ctdb/config/ctdbd_wrapper
index c5fe004..be251e6 100755
--- a/ctdb/config/ctdbd_wrapper
+++ b/ctdb/config/ctdbd_wrapper
@@ -15,14 +15,16 @@ action="$2"
 
 ############################################################
 
-[ -n "$CTDB_BASE" ] || export CTDB_BASE="/etc/ctdb"
+if [ -z "$CTDB_BASE" ] ; then
+    export CTDB_BASE="/usr/local/etc/ctdb"
+fi
 
 . "${CTDB_BASE}/functions"
 loadconfig "ctdb"
 
 [ -n "$CTDB_SOCKET" ] && export CTDB_SOCKET
 
-ctdbd="${CTDBD:-/usr/sbin/ctdbd}"
+ctdbd="${CTDBD:-/usr/local/sbin/ctdbd}"
 
 ############################################################
 
@@ -77,6 +79,39 @@ ctdbd_is_running ()
 
 ############################################################
 
+# If necessary, mount volatile database directory on tmpfs
+dbdir_tmpfs_start ()
+{
+    if [ -z "$CTDB_DBDIR_TMPFS_OPTIONS" ] ; then
+	return
+    fi
+
+    # Shortcut for readability
+    _opts="$CTDB_DBDIR_TMPFS_OPTIONS"
+
+    mkdir -p "$CTDB_DBDIR" || exit $?
+
+    # If already mounted then remount, otherwise mount
+    if findmnt -t tmpfs "$CTDB_DBDIR" >/dev/null ; then
+	mount -t tmpfs -o "remount,$_opts" none "$CTDB_DBDIR" || \
+	    exit $?
+    else
+	mount -t tmpfs -o "$_opts" none "$CTDB_DBDIR" || exit $?
+    fi
+}
+
+# If necessary, unmount volatile database tmpfs directory on exit
+dbdir_tmpfs_stop ()
+{
+    if [ -z "$CTDB_DBDIR_TMPFS_OPTIONS" ] ; then
+	return
+    fi
+
+    if [ -d "$CTDB_DBDIR" ] && findmnt -t tmpfs "$CTDB_DBDIR" >/dev/null ; then
+	umount "$CTDB_DBDIR"
+    fi
+}
+
 build_ctdb_options ()
 {
     ctdb_options=""
@@ -146,8 +181,8 @@ kill_ctdbd ()
 
     if [ -n "$_session" ] ; then
 	pkill -9 -s "$_session" 2>/dev/null
+	rm -f "$pidfile"
     fi
-    rm -f "$pidfile"
 }
 
 ############################################################
@@ -161,11 +196,10 @@ start()
 
     # About to start new $ctdbd.  The main daemon is not running but
     # there may still be other processes around, so do some cleanup.
-    # Note that starting ctdbd below will destroy the Unix domain
-    # socket, so any processes that aren't yet completely useless soon
-    # will be, so this can really do no harm.
     kill_ctdbd "$_session"
 
+    dbdir_tmpfs_start
+
     build_ctdb_options
 
     export_debug_variables
@@ -184,7 +218,7 @@ start()
 
     if [ -n "$CTDB_VALGRIND" -a "$CTDB_VALGRIND" != "no" ] ; then
 	if [ "$CTDB_VALGRIND" = "yes" ] ; then
-	    ctdbd="valgrind -q --log-file=/var/log/ctdb_valgrind ${ctdbd}"
+	    ctdbd="valgrind -q --log-file=/usr/local/var/log/ctdb_valgrind ${ctdbd}"
 	else
 	    ctdbd="${CTDB_VALGRIND} ${ctdbd}"
 	fi
@@ -250,25 +284,33 @@ stop()
     # Wait for remaining CTDB processes to exit...
     _timeout=${CTDB_SHUTDOWN_TIMEOUT:-30}
     _count=0
+    _terminated=false
     while [ $_count -lt $_timeout ] ; do
-	pkill -0 -s "$_session" 2>/dev/null || return 0
+	if ! pkill -0 -s "$_session" 2>/dev/null ; then
+	    _terminated=true
+	    break
+	fi
 
 	_count=$(($_count + 1))
 	sleep 1
     done
 
-    echo "Timed out waiting for CTDB to shutdown.  Killing CTDB processes."
-    kill_ctdbd "$_session"
-    drop_all_public_ips >/dev/null 2>&1
+    if ! $_terminated ; then
+	echo "Timed out waiting for CTDB to shutdown.  Killing CTDB processes."
+	kill_ctdbd "$_session"
+	drop_all_public_ips >/dev/null 2>&1
 
-    sleep 1
+	sleep 1
 
-    if pkill -0 -s "$_session" ; then
-	# If SIGKILL didn't work then things are bad...
-	echo "Failed to kill all CTDB processes.  Giving up."
-	return 1
+	if pkill -0 -s "$_session" ; then
+	    # If SIGKILL didn't work then things are bad...
+	    echo "Failed to kill all CTDB processes.  Giving up."
+	    return 1
+	fi
     fi
 
+    dbdir_tmpfs_stop
+
     return 0
 }
 
diff --git a/ctdb/config/debug-hung-script.sh b/ctdb/config/debug-hung-script.sh
index 3f800fc..9bde684 100755
--- a/ctdb/config/debug-hung-script.sh
+++ b/ctdb/config/debug-hung-script.sh
@@ -56,4 +56,4 @@ fi
 	mv "$tmp" "$CTDB_DEBUG_HUNG_SCRIPT_LOGFILE"
     fi
 
-) 9>"${CTDB_VARDIR}/debug-hung-script.lock"
+) 9>"${CTDB_SCRIPT_VARDIR}/debug-hung-script.lock"
diff --git a/ctdb/config/debug_locks.sh b/ctdb/config/debug_locks.sh
index 33bf3e6..8e33751 100755
--- a/ctdb/config/debug_locks.sh
+++ b/ctdb/config/debug_locks.sh
@@ -2,7 +2,7 @@
 
 # This script parses /proc/locks and finds the processes that are holding
 # locks on CTDB databases.  For all those processes the script dumps a
-# stack trace using gstack.
+# stack trace.
 #
 # This script can be used only if Samba is configured to use fcntl locks
 # rather than mutex locks.
@@ -56,13 +56,27 @@ loadconfig ctdb
 	# For each process waiting, log stack trace
 	for pid in $pids ; do
 	    echo "----- Stack trace for PID=$pid -----"
-	    gstack $pid
-	    # gcore -o /var/log/core-deadlock-ctdb $pid
+	    read x x state x </proc/$pid/stat
+	    if [ "$state" = "D" ] ; then
+		# Don't run gstack on a process in D state since
+		# gstack will hang until the process exits D state.
+		# Although it is possible for a process to transition
+		# to D state after this check, it is unlikely because
+		# if a process is stuck in D state then it is probably
+		# the reason why this script was called.  Note that a
+		# kernel stack almost certainly won't help diagnose a
+		# deadlock... but it will probably give us someone to
+		# blame!
+		echo "----- Process in D state, printing kernel stack only"
+		cat /proc/$pid/stack
+	    else
+		gstack $pid
+		# gcore -o /var/log/core-deadlock-ctdb $pid
+	    fi
 	done
     fi
 
     echo "===== End of debug locks PID=$$ ====="
-
-) 9>"${CTDB_VARDIR}/debug_locks.lock" | script_log "ctdbd-lock"
+)9>"${CTDB_SCRIPT_VARDIR}/debug_locks.lock" | script_log "ctdbd-lock"
 
 exit 0
diff --git a/ctdb/config/events.d/00.ctdb b/ctdb/config/events.d/00.ctdb
index 0e25e50..3bc20d7 100755
--- a/ctdb/config/events.d/00.ctdb
+++ b/ctdb/config/events.d/00.ctdb
@@ -65,7 +65,7 @@ check_tdb ()
 check_persistent_databases ()
 {
     _dir="${CTDB_DBDIR_PERSISTENT:-${CTDB_DBDIR:-${CTDB_VARDIR}}/persistent}"
-    mkdir -p "$_dir" 2>/dev/null
+    [ -d "$_dir" ] || return 0
 
     [ "${CTDB_MAX_PERSISTENT_CHECK_ERRORS:-0}" = "0" ] || return 0
 
@@ -80,7 +80,7 @@ check_persistent_databases ()
 check_non_persistent_databases ()
 {
     _dir="${CTDB_DBDIR:-${CTDB_VARDIR}}"
-    mkdir -p "$_dir" 2>/dev/null
+    [ -d "$_dir" ] || return 0
 
     for _db in $(ls "${_dir}/"*.tdb.*[0-9] 2>/dev/null) ; do
 	check_tdb $_db || {
@@ -116,61 +116,16 @@ set_ctdb_variables ()
     done
 }
 
-monitor_system_memory ()
-{
-    # If monitoring free memory then calculate how much there is
-    if [ -n "$CTDB_MONITOR_FREE_MEMORY_WARN" -o \
-	-n "$CTDB_MONITOR_FREE_MEMORY" ] ; then
-	free_mem=$(free -m | awk '$2 == "buffers/cache:" { print $4 }')
-    fi
-
-    # Shutdown CTDB when memory is below the configured limit
-    if [ -n "$CTDB_MONITOR_FREE_MEMORY" ] ; then
-	if [ $free_mem -le $CTDB_MONITOR_FREE_MEMORY ] ; then
-	    echo "CRITICAL: OOM - ${free_mem}MB free <= ${CTDB_MONITOR_FREE_MEMORY}MB (CTDB threshold)"
-	    echo "CRITICAL: Shutting down CTDB!!!"
-	    get_proc "meminfo"
-	    ps auxfww
-	    set_proc "sysrq-trigger" "m"
-	    ctdb disable
-	    sleep 3
-	    ctdb shutdown
-	fi
-    fi
-
-    # Warn when low on memory
-    if [ -n "$CTDB_MONITOR_FREE_MEMORY_WARN" ] ; then
-	if [ $free_mem -le $CTDB_MONITOR_FREE_MEMORY_WARN ] ; then
-	    echo "WARNING: free memory is low - ${free_mem}MB free <=  ${CTDB_MONITOR_FREE_MEMORY_WARN}MB (CTDB threshold)"
-	fi
-    fi
-
-    # We should never enter swap, so SwapTotal == SwapFree.
-    if [ "$CTDB_CHECK_SWAP_IS_NOT_USED" = "yes" ] ; then
-	set -- $(get_proc "meminfo" | awk '$1 ~ /Swap(Total|Free):/ { print $2 }')
-	if [ "$1" != "$2" ] ; then
-	    echo We are swapping:
-	    get_proc "meminfo"
-	    ps auxfww
-	fi
-    fi
-}
-
 ############################################################
 
 ctdb_check_args "$@"
 
-case "$1" in 
+case "$1" in
      init)
         # make sure we have a blank state directory for the scripts to work with
-	rm -rf $CTDB_VARDIR/state
-	# Look at the pattern - this should not be -rf!!!
-	rm -f $ctdb_managed_dir/*
-	mkdir -p $CTDB_VARDIR/state || {
-	    ret=$?
-	    echo "mkdir -p $CTDB_VARDIR/state - failed - $ret"
-	    exit $ret
-	}
+	rm -rf "$CTDB_SCRIPT_VARDIR"
+	mkdir -p "$CTDB_SCRIPT_VARDIR" || \
+	    die "mkdir -p ${CTDB_SCRIPT_VARDIR} - failed - ${ret}" $?
 
 	if select_tdb_checker ; then
 	    check_persistent_databases || exit $?
@@ -187,9 +142,6 @@ case "$1" in
     startup)
 	ctdb attach ctdb.tdb persistent
 	;;
-    monitor)
-	monitor_system_memory
-	;;
 
     *)
 	ctdb_standard_event_handler "$@"
diff --git a/ctdb/config/events.d/05.system b/ctdb/config/events.d/05.system
new file mode 100755
index 0000000..69fcec2
--- /dev/null
+++ b/ctdb/config/events.d/05.system
@@ -0,0 +1,176 @@
+#!/bin/sh
+# ctdb event script for checking local file system utilization
+
+[ -n "$CTDB_BASE" ] || \
+    export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD")
+
+. $CTDB_BASE/functions
+loadconfig
+
+ctdb_setup_service_state_dir "system-monitoring"
+
+validate_percentage ()
+{
+    case "$1" in
+	"") return 1 ;;  # A failure that doesn't need a warning
+	[0-9]|[0-9][0-9]|100) return 0 ;;
+	*) echo "WARNING: ${1} is an invalid percentage${2:+ in \"}${2}${2:+\"} check"
+	   return 1
+    esac
+}
+
+check_thresholds ()
+{
+    _thing="$1"
+    _thresholds="$2"
+    _usage="$3"
+    _unhealthy_callout="$4"
+
+    case "$_thresholds" in
+	*:*)
+	    _warn_threshold="${_thresholds%:*}"
+	    _unhealthy_threshold="${_thresholds#*:}"
+	    ;;
+	*)
+	    _warn_threshold="$_thresholds"
+	    _unhealthy_threshold=""
+    esac
+
+    _t=$(echo "$_thing" | sed -e 's@/@SLASH_ at g' -e 's@ @_ at g')
+    _cache="${service_state_dir}/cache_${_t}"
+    if validate_percentage "$_unhealthy_threshold" "$_thing" ; then
+        if [ "$_usage" -ge "$_unhealthy_threshold" ] ; then
+	    echo "ERROR: ${_thing} utilization ${_usage}% >= threshold ${_unhealthy_threshold}%"
+	    eval "$_unhealthy_callout"
+	    echo "$_usage" >"$_cache"
+	    exit 1
+        fi
+    fi
+
+    if validate_percentage "$_warn_threshold" "$_what" ; then
+        if [ "$_usage" -ge "$_warn_threshold" ] ; then
+	    if [ -r "$_cache" ] ; then
+		read _prev <"$_cache"
+	    else
+		_prev=""
+	    fi
+	    if [ "$_usage" != "$_prev" ] ; then
+		echo "WARNING: ${_thing} utilization ${_usage}% >= threshold ${_warn_threshold}%"
+		echo "$_usage" >"$_cache"
+	    fi
+	else
+	    if [ -r "$_cache" ] ; then
+		echo "NOTICE: ${_thing} utilization ${_usage}% < threshold ${_warn_threshold}%"
+	    fi
+	    rm -f "$_cache"
+        fi
+    fi
+}
+
+set_monitor_filsystem_usage_defaults ()
+{
+    _fs_defaults_cache="${service_state_dir}/cache_monitor_filsystem_usage_defaults"
+
+    if [ ! -r "$_fs_defaults_cache" ] ; then
+	# Determine filesystem for each database directory, generate
+	# an entry to warn at 90%, de-duplicate entries, put all items
+	# on 1 line (so the read below gets everything)
+	for _t in "${CTDB_DBDIR:-${CTDB_VARDIR}}" \
+		      "${CTDB_DBDIR_PERSISTENT:-${CTDB_VARDIR}/persistent}" \
+		      "${CTDB_DBDIR_STATE:-${CTDB_VARDIR}/state}" ; do
+	    df -kP "$_t" | awk 'NR == 2 { printf "%s:90\n", $6 }'
+	done | sort -u | xargs >"$_fs_defaults_cache"
+    fi
+
+    read CTDB_MONITOR_FILESYSTEM_USAGE <"$_fs_defaults_cache"
+}
+
+monitor_filesystem_usage ()
+{
+    if [ -z "$CTDB_MONITOR_FILESYSTEM_USAGE" ] ; then
+	set_monitor_filsystem_usage_defaults
+    fi
+
+    # Check each specified filesystem, specified in format
+    # <fs_mount>:<fs_warn_threshold>[:fs_unhealthy_threshold]
+    for _fs in $CTDB_MONITOR_FILESYSTEM_USAGE ; do
+	_fs_mount="${_fs%%:*}"
+	_fs_thresholds="${_fs#*:}"
+
+        if [ ! -d "$_fs_mount" ]; then
+            echo "WARNING: Directory ${_fs_mount} does not exist"
+	    continue
+        fi
+
+        # Get current utilization
+        _fs_usage=$(df -kP "$_fs_mount" | \
+			   sed -n -e 's at .*[[:space:]]\([[:digit:]]*\)%.*@\1 at p')
+        if [ -z "$_fs_usage" ] ; then
+            echo "WARNING: Unable to get FS utilization for ${_fs_mount}"
+	    continue
+        fi
+
+	check_thresholds "Filesystem ${_fs_mount}" \
+			 "$_fs_thresholds" \
+			 "$_fs_usage"
+    done
+}
+
+dump_memory_info ()
+{
+    get_proc "meminfo"
+    ps auxfww
+    set_proc "sysrq-trigger" "m"
+}
+
+monitor_memory_usage ()
+{
+    # Defaults
+    if [ -z "$CTDB_MONITOR_MEMORY_USAGE" ] ; then
+	CTDB_MONITOR_MEMORY_USAGE=80
+    fi
+    if [ -z "$CTDB_MONITOR_SWAP_USAGE" ] ; then
+	CTDB_MONITOR_SWAP_USAGE=25
+    fi
+
+    _meminfo=$(get_proc "meminfo")
+    set -- $(echo "$_meminfo" | awk '
+$1 == "MemAvailable:" { memavail += $2 }
+$1 == "MemFree:"      { memfree  += $2 }
+$1 == "Cached:"       { memfree  += $2 }
+$1 == "Buffers:"      { memfree  += $2 }
+$1 == "MemTotal:"     { memtotal  = $2 }
+$1 == "SwapFree:"     { swapfree  = $2 }
+$1 == "SwapTotal:"    { swaptotal = $2 }
+END {
+    if (memavail != 0) { memfree = memavail ; }
+    print int((memtotal -  memfree)  / memtotal * 100),
+          int((swaptotal - swapfree) / swaptotal * 100)
+}')
+    _mem_usage="$1"
+    _swap_usage="$2"
+
+    check_thresholds "System memory" \
+		     "$CTDB_MONITOR_MEMORY_USAGE" \
+		     "$_mem_usage" \
+		     dump_memory_info
+
+    check_thresholds "System swap" \
+		     "$CTDB_MONITOR_SWAP_USAGE" \
+		     "$_swap_usage" \
+		     dump_memory_info
+}
+
+
+case "$1" in
+    monitor)
+	monitor_filesystem_usage
+	monitor_memory_usage
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0
diff --git a/ctdb/config/events.d/10.interface b/ctdb/config/events.d/10.interface
index acc0fc8..4fb3524 100755
--- a/ctdb/config/events.d/10.interface
+++ b/ctdb/config/events.d/10.interface
@@ -22,18 +22,6 @@ loadconfig
 	exit 0
 }
 
-mark_up ()
-{
-    up_interfaces_found=true
-    ctdb setifacelink $1 up >/dev/null 2>&1
-}
-
-mark_down ()
-{
-    fail=true
-    ctdb setifacelink $1 down >/dev/null 2>&1
-}
-
 # This sets $all_interfaces as a side-effect.
 get_all_interfaces ()
 {
@@ -42,7 +30,6 @@ get_all_interfaces ()
 
     # Add some special interfaces if they're defined
     [ "$CTDB_PUBLIC_INTERFACE" ] && all_interfaces="$CTDB_PUBLIC_INTERFACE $all_interfaces"
-    [ "$CTDB_NATGW_PUBLIC_IFACE" ] && all_interfaces="$CTDB_NATGW_PUBLIC_IFACE $all_interfaces"
 
     # Get the interfaces for which CTDB has public IPs configured.
     # That is, for all but the 1st line, get the 1st field.
@@ -52,113 +39,39 @@ get_all_interfaces ()
     all_interfaces=$(echo $all_interfaces $ctdb_ifaces | tr ' ' '\n' | sort -u)
 }
 
-get_real_iface ()
-{
-    # Output of "ip link show <iface>"
-    _iface_info="$1"
-
-    # Extract the full interface description to see if it is a VLAN
-    _t=$(echo "$_iface_info" |
-		awk 'NR == 1 { iface = $2; sub(":$", "", iface) ; \
-			       print iface }')
-    case "$_t" in
-	*@*)
-	    # VLAN: use the underlying interface, after the '@'
-	    echo "${_t##*@}"
-	    ;;
-	*)
-	    # Not a regular VLAN.  For backward compatibility, assume
-	    # there is some other sort of VLAN that doesn't have the
-	    # '@' in the output and only use what is before a '.'.  If
-	    # there is no '.' then this will be the whole interface
-	    # name.
-	    echo "${_t%%.*}"
-    esac
-}
-
 monitor_interfaces()
 {
 	get_all_interfaces
 
-	fail=false
+	down_interfaces_found=false
 	up_interfaces_found=false
 
 	# Note that this loop must not exit early.  It must process
 	# all interfaces so that the correct state for each interface
-	# is set in CTDB using mark_up/mark_down.  If there is a
-	# problem with an interface then set fail=true and continue.
-	for iface in $all_interfaces ; do
-
-	    _iface_info=$(ip link show $iface 2>&1) || {
-		echo "ERROR: Interface $iface does not exist but it is used by public addresses."
-		mark_down $iface
-		continue
-	    }
-
-	    # These interfaces are sometimes bond devices
-	    # When we use VLANs for bond interfaces, there will only
-	    # be an entry in /proc for the underlying real interface
-	    realiface=$(get_real_iface "$_iface_info")
-	    bi=$(get_proc "net/bonding/$realiface" 2>/dev/null) && {
-		echo "$bi" | grep -q 'Currently Active Slave: None' && {
-			echo "ERROR: No active slaves for bond device $realiface"
-			mark_down $iface
-			continue
-		}
-		echo "$bi" | grep -q '^MII Status: up' || {
-			echo "ERROR: public network interface $realiface is down"
-			mark_down $iface
-			continue
-		}
-		echo "$bi" | grep -q '^Bonding Mode: IEEE 802.3ad Dynamic link aggregation' && {
-			# This works around a bug in the driver where the
-			# overall bond status can be up but none of the actual
-			# physical interfaces have a link.
-			echo "$bi" | grep 'MII Status:' | tail -n +2 | grep -q '^MII Status: up' || {
-				echo "ERROR: No active slaves for 802.ad bond device $realiface"
-				mark_down $iface
-				continue
-			}
-		}
-		mark_up $iface
-		continue
-	    }
-
-	    case $iface in
-	    lo*)
-		# loopback is always working
-		mark_up $iface
-		;;
-	    ib*)
-		# we dont know how to test ib links
-		mark_up $iface
-		;;
-	    *)
-		ethtool $iface | grep -q 'Link detected: yes' || {
-		    # On some systems, this is not successful when a
-		    # cable is plugged but the interface has not been
-		    # brought up previously. Bring the interface up
-		    # and try again...
-		    ip link set $iface up
-		    ethtool $iface | grep -q 'Link detected: yes' || {
-			echo "ERROR: No link on the public network interface $iface"
-			mark_down $iface
-			continue
-		    }
-		}
-		mark_up $iface
-		;;
-	    esac
-
+	# is set in CTDB using setifacelink.
+	for _iface in $all_interfaces ; do
+		if interface_monitor "$_iface" ; then
+			up_interfaces_found=true
+			ctdb setifacelink "$_iface" up >/dev/null 2>&1
+		else
+			down_interfaces_found=true
+			ctdb setifacelink "$_iface" down >/dev/null 2>&1
+		fi
 	done
 
-	$fail || return 0
+	if ! $down_interfaces_found ; then
+		return 0
+	fi
 
-	$up_interfaces_found && \
-	    [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" = "yes" ] && \
-	    return 0
+	if ! $up_interfaces_found ; then
+		return 1
+	fi
 
-	return 1
+	if [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" != "yes" ]; then
+		return 1
+	fi
+
+	return 0
 }
 
 # Sets: iface, ip, maskbits, family
@@ -191,10 +104,8 @@ get_iface_ip_maskbits_family ()
 
 ctdb_check_args "$@"
 
-case "$1" in 
-     #############################
-     # called when ctdbd starts up
-     init)
+case "$1" in
+    init)
 	# make sure that we only respond to ARP messages from the NIC where
 	# a particular ip address is associated.
 	get_proc sys/net/ipv4/conf/all/arp_filter >/dev/null 2>&1 && {
@@ -210,17 +121,11 @@ case "$1" in
 	drop_all_public_ips
 	;;
 
-     #############################
-     # called after ctdbd has done its initial recovery
-     # and we start the services to become healthy
-     startup)
+    startup)
 	monitor_interfaces
 	;;
 
-
-     ################################################
-     # called when ctdbd wants to claim an IP address
-     takeip)
+    takeip)
 	iface=$2
 	ip=$3
 	maskbits=$4
@@ -239,10 +144,7 @@ case "$1" in
 	flush_route_cache
 	;;
 
-
-     ##################################################
-     # called when ctdbd wants to release an IP address
-     releaseip)
+    releaseip)
 	# releasing an IP is a bit more complex than it seems. Once the IP
 	# is released, any open tcp connections to that IP on this host will end
 	# up being stuck. Some of them (such as NFS connections) will be unkillable
@@ -272,9 +174,7 @@ case "$1" in
 	flush_route_cache
 	;;
 
-     ##################################################
-     # called when ctdbd wants to update an IP address
-     updateip)
+    updateip)
 	# moving an IP is a bit more complex than it seems.
 	# First we drop all traffic on the old interface.
 	# Then we try to add the ip to the new interface and before
@@ -291,7 +191,7 @@ case "$1" in
 	_ip=$4
 	_maskbits=$5
 
-	get_iface_ip_maskbits_family "$_oiface" "$ip" "$maskbits"
+	get_iface_ip_maskbits_family "$_oiface" "$_ip" "$_maskbits"
 	oiface="$iface"
 
 	# we do an extra delete to cope with the script being killed
@@ -317,12 +217,10 @@ case "$1" in
 
 	# tickle all existing connections, so that dropped packets
 	# are retransmited and the tcp streams work
-
 	tickle_tcp_connections $ip
-
 	;;
 
-     monitor)
+    monitor)
 	monitor_interfaces || exit 1
 	;;
     *)
@@ -331,4 +229,3 @@ case "$1" in
 esac
 
 exit 0
-
diff --git a/ctdb/config/events.d/11.natgw b/ctdb/config/events.d/11.natgw
index 29339f4..25cf27f 100755
--- a/ctdb/config/events.d/11.natgw
+++ b/ctdb/config/events.d/11.natgw
@@ -23,18 +23,44 @@ natgw_cfg_new="${service_state_dir}/cfg_new"
 natgw_cfg_old="${service_state_dir}/cfg_old"
 natgw_master_old="${service_state_dir}/master_old"
 
+# Cached retrieval of private IP address from local node.  This never
+# changes.  Sets $ip_address to avoid an unnecessary subprocess.
+ctdb_get_ip_address ()
+{
+    _ip_addr_file="${service_state_dir}/my-ip-address"
+    if [ ! -f "$_ip_addr_file" ] ; then
+	ctdb -X nodestatus |
+	    awk -F '|' 'NR == 2 { print $3 }' >"$_ip_addr_file"
+    fi
+
+    read ip_address <"$_ip_addr_file"
+}
+
+ctdb_natgw_slave_only ()
+{
+    ctdb_get_ip_address
+
+    awk -v my_ip="$ip_address" \
+	'$1 == my_ip { if ($2 ~ "slave-only") { exit 0 } else { exit 1 } }' \
+	"$CTDB_NATGW_NODES"
+}
+
 natgw_check_config ()
 {
     [ -r "$CTDB_NATGW_NODES" ] || \
 	die "error: CTDB_NATGW_NODES=${CTDB_NATGW_NODES} unreadable"
-    if [ "$CTDB_NATGW_SLAVE_ONLY" != "yes" ] ; then
+    if ! ctdb_natgw_slave_only ; then
 	[ -n "$CTDB_NATGW_PUBLIC_IP" ] || \
 	    die "Invalid configuration: CTDB_NATGW_PUBLIC_IP not set"
 	[ -n "$CTDB_NATGW_PUBLIC_IFACE" ] || \
 	    die "Invalid configuration: CTDB_NATGW_PUBLIC_IFACE not set"
     fi
     [ -n "$CTDB_NATGW_PRIVATE_NETWORK" ] || \
-	die "Invalid configuration: CTDB_NATGW_PRIVATE_NETWORK not set"
+	    die "Invalid configuration: CTDB_NATGW_PRIVATE_NETWORK not set"
+
+    if [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" = "yes" ] ; then
+	    die "Invalid configuration: CTDB_PARTIALLY_ONLINE_INTERFACES=yes incompatible with NAT gateway"
+    fi
 
     # The default is to create a single default route
     [ -n "$CTDB_NATGW_STATIC_ROUTES" ] || CTDB_NATGW_STATIC_ROUTES="0.0.0.0/0"
@@ -51,7 +77,6 @@ CTDB_NATGW_PUBLIC_IFACE="$CTDB_NATGW_PUBLIC_IFACE"
 CTDB_NATGW_DEFAULT_GATEWAY="$CTDB_NATGW_DEFAULT_GATEWAY"
 CTDB_NATGW_PRIVATE_NETWORK="$CTDB_NATGW_PRIVATE_NETWORK"
 CTDB_NATGW_STATIC_ROUTES="$CTDB_NATGW_STATIC_ROUTES"
-CTDB_NATGW_SLAVE_ONLY="$CTDB_NATGW_SLAVE_ONLY"
 EOF
 }
 
@@ -73,16 +98,6 @@ natgw_config_has_changed ()
     return 0
 }
 
-natgw_set_capability ()
-{
-    # Set NATGW capability depending on configuration
-    if [ "$CTDB_NATGW_SLAVE_ONLY" = "yes" ] ; then
-	ctdb setnatgwstate off
-    else
-	ctdb setnatgwstate on
-    fi
-}
-
 _natgw_clear ()
 {
     _ip="${CTDB_NATGW_PUBLIC_IP%/*}"
@@ -153,7 +168,7 @@ natgw_set_slave ()
 
 natgw_ensure_master ()
 {
-    set -- $(ctdb natgwlist)
+    set -- $("${CTDB_HELPER_BINDIR}/ctdb_natgw" master)
     natgwmaster="${1:--1}" # Default is -1 if natgwlist fails
     natgwip="$2"
 
@@ -181,10 +196,9 @@ natgw_save_state ()
 }
 
 
-case "$1" in 
+case "$1" in
     setup)
 	natgw_check_config
-	natgw_set_capability
 	;;
 
     startup)
@@ -206,7 +220,6 @@ case "$1" in
 
 	ctdb_get_pnn
 
-	natgw_set_capability
 	natgw_ensure_master
 
 	natgw_config_has_changed || natgw_master_has_changed || exit 0
@@ -231,6 +244,14 @@ case "$1" in
 	natgw_clear
 	;;
 
+    monitor)
+	natgw_check_config
+
+	if [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] ; then
+	    interface_monitor "$CTDB_NATGW_PUBLIC_IFACE" || exit 1
+	fi
+	;;
+
     *)
 	ctdb_standard_event_handler "@"
 	;;
diff --git a/ctdb/config/events.d/13.per_ip_routing b/ctdb/config/events.d/13.per_ip_routing
index cd0020e..56dfc34 100755
--- a/ctdb/config/events.d/13.per_ip_routing
+++ b/ctdb/config/events.d/13.per_ip_routing
@@ -93,6 +93,19 @@ ipv4_host_addr_to_net ()
 
 ######################################################################
 
+ensure_rt_tables ()
+{
+    rt_tables="$CTDB_SYS_ETCDIR/iproute2/rt_tables"
+
+    # This file should always exist.  Even if this didn't exist on the
+    # system, adding a route will have created it.  What if we startup
+    # and immediately shutdown?  Let's be sure.
+    if [ ! -f "$rt_tables" ] ; then
+	mkdir -p "${rt_tables%/*}" # dirname
+	touch "$rt_tables"
+    fi
+}
+
 # Setup a table id to use for the given IP.  We don't need to know it,
 # it just needs to exist in /etc/iproute2/rt_tables.  Fail if no free
 # table id could be found in the configured range.
@@ -100,12 +113,7 @@ ensure_table_id_for_ip ()
 {
     _ip=$1
 
-    _f="$CTDB_ETCDIR/iproute2/rt_tables"
-    # This file should always exist, but...
-    if [ ! -f "$_f" ] ; then
-	mkdir -p $(dirname "$_f")
-	touch "$_f"
-    fi
+    ensure_rt_tables
 
     # Maintain a table id for each IP address we've ever seen in
     # rt_tables.  We use a "ctdb." prefix on the label.
@@ -117,7 +125,7 @@ ensure_table_id_for_ip ()
     (
 	# Note that die() just gets us out of the subshell...
 	flock --timeout 30 0 || \
-	    die "ensure_table_id_for_ip: failed to lock file $_f"
+	    die "ensure_table_id_for_ip: failed to lock file $rt_tables"
 
 	_new=$CTDB_PER_IP_ROUTING_TABLE_ID_LOW
 	while read _t _l ; do
@@ -140,44 +148,38 @@ ensure_table_id_for_ip ()
 	# If the new table id is legal then add it to the file and
 	# print it.
 	if [ $_new -le $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH ] ; then
-	    printf "%d\t%s\n" "$_new" "$_label" >>"$_f"
+	    printf "%d\t%s\n" "$_new" "$_label" >>"$rt_tables"
 	    return 0
 	else
 	    return 1
 	fi
-    ) <"$_f"
+    ) <"$rt_tables"
 }
 
 # Clean up all the table ids that we might own.
 clean_up_table_ids ()
 {
-    _f="$CTDB_ETCDIR/iproute2/rt_tables"
-    # Even if this didn't exist on the system, adding a route will
-    # have created it.  What if we startup and immediately shutdown?
-    if [ ! -f "$_f" ] ; then
-	mkdir -p $(dirname "$_f")
-	touch "$_f"
-    fi
+    ensure_rt_tables
 
     (
 	# Note that die() just gets us out of the subshell...
 	flock --timeout 30 0 || \
-	    die "clean_up_table_ids: failed to lock file $_f"
+	    die "clean_up_table_ids: failed to lock file $rt_tables"
 
 	# Delete any items from the file that have a table id in our
 	# range or a label matching our label.  Preserve comments.
-	_tmp="${_f}.$$.ctdb"
+	_tmp="${rt_tables}.$$.ctdb"
 	awk -v min="$CTDB_PER_IP_ROUTING_TABLE_ID_LOW" \
 	    -v max="$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" \
 	    -v pre="$table_id_prefix" \
 	    '/^#/ || \
 	     !(min <= $1 && $1 <= max) && \
 	     !(index($2, pre) == 1) \
-	     { print $0 }' "$_f" >"$_tmp"
+	     { print $0 }' "$rt_tables" >"$_tmp"
 
-	mv "$_tmp" "$_f"
+	mv "$_tmp" "$rt_tables"
 	# The lock is gone - don't do anything else here
-    ) <"$_f"
+    ) <"$rt_tables"
 }
 
 ######################################################################
diff --git a/ctdb/config/events.d/40.fs_use b/ctdb/config/events.d/40.fs_use
deleted file mode 100644
index 603b463..0000000
--- a/ctdb/config/events.d/40.fs_use
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/sh
-# ctdb event script for checking local file system utilization
-
-[ -n "$CTDB_BASE" ] || \
-    export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD")
-
-. $CTDB_BASE/functions
-loadconfig
-
-case "$1" in 
-    monitor)
-        # check each specified fs to be checked
-        # config format is <fs_mount>:<fs_threshold>
-        for fs in $CTDB_CHECK_FS_USE
-        do
-            # parse fs_mount and fs_threshold
-            fs_mount="${fs%:*}"
-            fs_threshold="${fs#*:}"
-
-            # check if given fs_mount is existing directory
-            if [ ! -d "$fs_mount" ]; then
-                echo "Directory $fs_mount does not exist"
-                exit 1
-            fi
-
-            # check if given fs_threshold is number
-            if ! (echo "$fs_threshold" | egrep -q '^[0-9]+$')  ; then
-                echo "Threshold $fs_threshold is invalid number"
-                exit 1
-            fi
-
-            # get utilization of given fs from df
-            fs_usage=$(df -kP $fs_mount | sed -n -e 's at .*[[:space:]]\([[:digit:]]*\)%.*@\1 at p')
-
-            # check if fs_usage is number
-            if [ -z "$fs_usage" ] ; then
-                echo "Unable to get FS utilization for $fs_mount"
-                exit 1
-            fi
-
-            # check if fs_usage is higher than or equal to fs_threshold
-            if [ "$fs_usage" -ge "$fs_threshold" ] ; then
-                echo "ERROR: Utilization of $fs_mount ($fs_usage%) is higher than threshold ($fs_threshold%)"
-                exit 1
-            fi
-        done
-
-	;;
-
-    *)
-	ctdb_standard_event_handler "$@"
-	;;
-esac
-
-exit 0
diff --git a/ctdb/config/events.d/50.samba b/ctdb/config/events.d/50.samba
index 4b53cba..1742ff1 100755
--- a/ctdb/config/events.d/50.samba
+++ b/ctdb/config/events.d/50.samba
@@ -78,19 +78,42 @@ testparm_foreground_update ()
 {
     _timeout="$1"
 
-    if ! _out=$(timeout $_timeout testparm -v -s 2>/dev/null) ; then
-	if [ -f "$smbconf_cache" ] ; then
-	    echo "WARNING: smb.conf cache update failed - using old cache file"
-	    return 1
-	else
-	    die "ERROR: smb.conf cache create failed"
-	fi
-    fi
-
+    # No need to remove these temporary files, since there are only 2
+    # of them.
+    _out="${smbconf_cache}.out"
+    _err="${smbconf_cache}.err"
+
+    timeout $_timeout testparm -v -s >"$_out" 2>"$_err"
+    case $? in
+	0) : ;;
+	124)
+	    if [ -f "$smbconf_cache" ] ; then
+		echo "WARNING: smb.conf cache update timed out - using old cache file"
+		return 1
+	    else
+		echo "ERROR: smb.conf cache create failed - testparm command timed out"
+		exit 1
+	    fi
+	    ;;
+	*)
+	    if [ -f "$smbconf_cache" ] ; then
+		echo "WARNING: smb.conf cache update failed - using old cache file"
+		cat "$_err"
+		return 1
+	    else
+		echo "ERROR: smb.conf cache create failed - testparm failed with:"
+		cat "$_err"
+		exit 1
+	    fi
+    esac
+
+    # Only using $$ here to avoid a collision.  This is written into
+    # CTDB's own state directory so there is no real need for a secure
+    # temporary file.
     _tmpfile="${smbconf_cache}.$$"
     # Patterns to exclude...
-    pat='^[[:space:]]+(registry[[:space:]]+shares|include|copy|winbind[[:space:]]+separator)[[:space:]]+='    
-    echo "$_out" | grep -Ev "$pat" >"$_tmpfile"
+    _pat='^[[:space:]]+(registry[[:space:]]+shares|include|copy|winbind[[:space:]]+separator)[[:space:]]+='
+    grep -Ev "$_pat" <"$_out" >"$_tmpfile"
     mv "$_tmpfile" "$smbconf_cache" # atomic
 
     return 0
diff --git a/ctdb/config/events.d/60.nfs b/ctdb/config/events.d/60.nfs
index 46ed29a..d6b978f 100755
--- a/ctdb/config/events.d/60.nfs
+++ b/ctdb/config/events.d/60.nfs
@@ -18,6 +18,9 @@ fi
 # Always export, for statd callout
 export CTDB_NFS_CALLOUT
 
+# If the callout wants to use this then it must create it
+export CTDB_NFS_CALLOUT_STATE_DIR="${service_state_dir}/callout-state"
+
 nfs_callout_cache="${service_state_dir}/nfs_callout_cache"
 nfs_callout_cache_callout="${nfs_callout_cache}/CTDB_NFS_CALLOUT"
 nfs_callout_cache_ops="${nfs_callout_cache}/ops"
diff --git a/ctdb/config/events.d/62.cnfs b/ctdb/config/events.d/62.cnfs
deleted file mode 100755
index 339eaef..0000000
--- a/ctdb/config/events.d/62.cnfs
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/sh
-# event script to integrate with gpfs cnfs
-
-[ -n "$CTDB_BASE" ] || \
-    export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD")
-
-. $CTDB_BASE/functions
-
-loadconfig
-
-ctdb_setup_service_state_dir "gpfs"
-
-check_if_healthy() {
-        mkdir -p "$service_state_dir/fs"
-
-        [ -f "$service_state_dir/gpfsnoquorum" ] && {
-                logger No GPFS quorum. Node is UNHEALTHY
-                $CTDB_BASE/events.d/62.cnfs unhealthy "No GPFS quorum. Nodfe is UNHEALTHY."
-		exit 0
-	}
-
-        logger All required GPFS resources are available. CNFS part is healthy.
-        $CTDB_BASE/events.d/62.cnfs healthy
-}
-
-case "$1" in
-    startup)
-        check_if_healthy
-        ;;
-
-
-    gpfsquorumreached)
-        rm -f "$service_state_dir/gpfsnoquorum"
-        logger "GPFS quorum has been reached."
-        check_if_healthy
-        ;;
-
-    gpfsquorumloss)
-        touch "$service_state_dir/gpfsnoquorum"
-        logger "GPFS quorum has been lost."
-        $CTDB_BASE/events.d/62.cnfs unhealthy "GPFS quorum was lost! Marking node as UNHEALTHY."
-        ;;
-
-    unhealthy)
-        # Mark the node as UNHEALTHY which means all public addresses
-        # will be migrated off the node.
-        shift
-        echo "$*" | ctdb_setstatus unhealthy -
-
-        # force a monitor event so we pick up immediately that this script
-        # will now fail and make the node unhealthy.
-        ctdb eventscript monitor
-
-        # Wait until we no longer serve any ip addresses at all
-	ctdb_get_pnn
-	while ctdb -X ip | grep -q "^|.*|${pnn}|\$" ; do
-                sleep 1
-        done
-        ;;
-
-    healthy)
-        # mark the node as healthy
-        ctdb_setstatus healthy
-        ;;
-
-
-    monitor)
-        ctdb_checkstatus
-        exit $?
-        ;;
-
-    *)
-        ctdb_standard_event_handler "$@"
-        ;;
-esac
-
-exit 0
-
diff --git a/ctdb/config/events.d/README b/ctdb/config/events.d/README
index ea9048f..11da702 100644
--- a/ctdb/config/events.d/README
+++ b/ctdb/config/events.d/README
@@ -1,170 +1,191 @@
-This directory is where you should put any local or application
-specific event scripts for ctdb to call.
+The events.d/ directory contains event scripts used by CTDB.  Event
+scripts are triggered on certain events, such as startup, monitoring
+or public IP allocation.  Scripts may be specific to services,
+networking or internal CTDB operations.
+
+All event scripts start with the prefix 'NN.' where N is a digit.  The
+event scripts are run in sequence based on NN.  Thus 10.interface will
+be run before 60.nfs.  It is recommended to keep each NN unique.
+However, scripts with the same NN prefix will be executed in
+alphanumeric sort order.
+
+As a special case, any eventscript that ends with a '~' character will be
+ignored since this is a common postfix that some editors will append to
+older versions of a file.
 
-All event scripts start with the prefic 'NN.' where N is a digit.
-The event scripts are run in sequence based on NN.
-Thus 10.interfaces will be run before 60.nfs.
+Only executable event scripts are run by CTDB.  Any event script that
+does not have execute permission is ignored.
 
-Each NN must be unique and duplicates will cause undefined behaviour.
-I.e. having both 10.interfaces and 10.otherstuff is not allowed.
+The eventscripts are called with varying number of arguments.  The
+first argument is the event name and the rest of the arguments depend
+on the event name.
 
+Event scripts must return 0 for success and non-zero for failure.
 
-As a special case, any eventscript that ends with a '~' character will be 
-ignored since this is a common postfix that some editors will append to 
-older versions of a file.
+Output of event scripts is logged.  On failure the output of the
+failing event script is included in the output of "ctdb scriptstatus".
 
-Only event scripts with executable permissions are run from CTDB. Any event
-script that does not have executable permission is ignored.
+The following events are supported (with arguments shown):
 
-The eventscripts are called with varying number of arguments.
-The first argument is the "event" and the rest of the arguments depend
-on which event was triggered.
+init
 
-All of the events except the 'shutdown' and 'startrecovery' events will be
-called with the ctdb daemon in NORMAL mode (ie. not in recovery)
+	This event is triggered once when CTDB is starting up.  This
+	event is used to do some basic cleanup and initialisation.
 
-The events currently implemented are
-init
-	This event does not take any additional arguments.
-	This event is only invoked once, when ctdb is starting up.
-	This event is used to do some cleanup work from earlier runs
-	and prepare the basic setup.
-	At this stage 'ctdb' commands won't work.
+	During the "init" event CTDB is not listening on its Unix
+	domain socket, so the "ctdb" CLI will not work.
 
-	Example: 00.ctdb cleans up $CTDB_VARDIR/state
+	Failure of this event will cause CTDB to terminate.
+
+	Example: 00.ctdb creates $CTDB_SCRIPT_VARDIR
 
 setup
-	This event does not take any additional arguments.
-	This event is only invoked once, after init event is completed.
-	This event is used to do setup any tunables defined in ctdb 
-        configuration file.
+
+	This event is triggered once, after the "init" event has
+	completed.
+
+	For this and any subsequent events the CTDB Unix domain socket
+	is available, so the "ctdb" CLI will work.
+
+	Failure of this event will cause CTDB to terminate.
+
+	Example: 00.ctdb processes tunables defined in the CTDB
+        configuration using CTDB_SET_<TunableName>=<TunableValue>.
 
 startup
-	This event does not take any additional arguments.
-	This event is only invoked once, when ctdb has finished
-	the initial recoveries. This event is used to wait for
-	the service to start and all resources for the service
-	becoming available.
 
-	This is used to prevent ctdb from starting up and advertize its
-	services until all dependent services have become available.
+	This event is triggered after the "setup" event has completed
+	and CTDB has finished its initial database recovery.
+
+	This event starts all services that are managed by CTDB.  Each
+	service that is managed by CTDB should implement this event
+	and use it to (re)start the service.
 
-	All services that are managed by ctdb should implement this
-	event and use it to start the service.
+	If the "startup" event fails then CTDB will retry it until it
+	succeeds.  There is no limit on the number of retries.
 
-	Example: 50.samba uses this event to start the samba daemon
-	and then wait until samba and all its associated services have
-	become available. It then also proceeds to wait until all
-	shares have become available.
+	Example: 50.samba uses this event to start the Samba daemon if
+	CTDB_MANAGES_SAMBA=yes.
 
 shutdown
-	This event is called when the ctdb service is shuting down.
-	
-	All services that are managed by ctdb should implement this event
-	and use it to perform a controlled shutdown of the service.
 
-	Example: 60.nfs uses this event to shut down nfs and all associated
-	services and stop exporting any shares when this event is invoked.
+	This event is triggered when CTDB is shutting down.
+
+	This event shuts down all services that are managed by CTDB.
+	Each service that is managed by CTDB should implement this
+	event and use it to stop the service.
+
+	Example: 50.samba uses this event to shut down the Samba
+	daemon if CTDB_MANAGES_SAMBA=yes.
 
 monitor
-	This event is invoked every X number of seconds.
-	The interval can be configured using the MonitorInterval tunable
-	but defaults to 15 seconds.
 
-	This event is triggered by ctdb to continuously monitor that all
-	managed services are healthy.
-	When invoked, the event script will check that the service is healthy
-	and return 0 if so. If the service is not healthy the event script
-	should return non zero.
+	This event is run periodically.  The interval between
+	successive "monitor" events is configured using the
+	MonitorInterval tunable, which defaults to 15 seconds.
 
-	If a service returns nonzero from this script this will cause ctdb
-	to consider the node status as UNHEALTHY and will cause the public
-	address and all associated services to be failed over to a different
-	node in the cluster.
+	This event is triggered by CTDB to continuously monitor that
+	all managed services are healthy.  If all event scripts
+	complete then the monitor event successfully then the node is
+	marked HEALTHY.  If any event script fails then no subsequent
+	scripts will be run for that event and the node is marked
+	UNHEALTHY.
 
-	All managed services should implement this event.
+	Each service that is managed by CTDB should implement this
+	event and use it to monitor the service.
 
-	Example: 10.interfaces which checks that the public interface (if used)
-	is healthy, i.e. it has a physical link established.
+	Example: 10.interface checks that each configured interface
+	for public IP addresses has a physical link established.
 
-takeip
-	This event is triggered everytime the node takes over a public ip
-	address during recovery.
-	This event takes three additional arguments :
-	'interface' 'ipaddress' and 'netmask'
+startrecovery
 
-	Before this event there will always be a 'startrecovery' event.
+	This event is triggered every time a database recovery process
+	is started.
 
-	This event will always be followed by a 'recovered' event once
-	all ipaddresses have been reassigned to new nodes and the ctdb database
-	has been recovered.
-	If multiple ip addresses are reassigned during recovery it is
-	possible to get several 'takeip' events followed by a single 
-	'recovered' event.
+	This is rarely used.
 
-	Since there might involve substantial work for the service when an ip
-	address is taken over and since multiple ip addresses might be taken 
-	over in a single recovery it is often best to only mark which addresses
-	are being taken over in this event and defer the actual work to 
-	reconfigure or restart the services until the 'recovered' event.
+recovered
 
-	Example: 60.nfs which just records which ip addresses are being taken
-	over into a local state directory   and which defers the actual
-	restart of the services until the 'recovered' event.
+	This event is triggered every time a database recovery process
+	is completed.
 
+	This is rarely used.
 
-releaseip
-	This event is triggered everytime the node releases a public ip
-	address during recovery.
-	This event takes three additional arguments :
-	'interface' 'ipaddress' and 'netmask'
+takeip <interface> <ip-address> <netmask-bits>
 
-	In all other regards this event is analog to the 'takeip' event above.
+	This event is triggered for each public IP address taken by a
+	node during IP address (re)assignment.  Multiple "takeip"
+	events can be run in parallel if multiple IP addresses are
+	being assigned.
 
-	Example: 60.nfs
+	Example: In 10.interface the "ip" command (from the Linux
+	iproute2 package) is used to add the specified public IP
+	address to the specified interface.  The "ip" command can
+	safely be run concurrently.  However, the "iptables" command
+	cannot be run concurrently so a wrapper is used to serialise
+	runs using exclusive locking.
 
-updateip
-	This event is triggered everytime the node moves a public ip
-	address between interfaces
-	This event takes four additional arguments :
-	'old-interface' 'new-interface' 'ipaddress' and 'netmask'
+	If substantial work is required to reconfigure a service when
+	a public IP address is taken over it can be better to defer
+	service reconfiguration to the "ipreallocated" event, after
+	all IP addresses have been assigned.
 
-	Example: 10.interface
+	Example: 60.nfs uses ctdb_service_set_reconfigure() to flag
+	that public IP addresses have changed so that service
+	reconfiguration will occur in the "ipreallocated" event.
 
-startrecovery
-	This event is triggered everytime we start a recovery process
-	or before we start changing ip address allocations.
+releaseip <interface> <ip-address> <netmask-bits>
+
+	This event is triggered for each public IP address released by
+	a node during IP address (re)assignment.  Multiple "releaseip"
+	events can be run in parallel if multiple IP addresses are
+	being unassigned.
+
+	In all other regards, this event is analogous to the "takeip"
+	event above.
+
+updateip <old-interface> <new-interface> <ip-address> <netmask-bits>
+
+	This event is triggered for each public IP address moved
+	between interfaces on a node during IP address (re)assignment.
+	Multiple "updateip" events can be run in parallel if multiple
+	IP addresses are being moved.
+
+        This event is only used if multiple interfaces are capable of
+        hosting an IP address, as specified in the public addresses
+        configuration file.
+
+	This event is similar to the "takeip" event above.
 
-recovered
-	This event is triggered every time we have finished a full recovery
-	and also after we have finished reallocating the public ip addresses
-	across the cluster.
-
-	Example: 60.nfs which if the ip address configuration has changed
-	during the recovery (i.e. if addresses have been taken over or
-	released) will kill off any tcp connections that exist for that
-	service and also send out statd notifications to all registered 
-	clients.
-	
 ipreallocated
 
-	This event is triggered after releaseip and takeip events in a
-	takeover run.  It can be used to reconfigure services, update
-	routing and many other things.
+	This event is triggered after "releaseip", "takeip" and
+	"updateip" events during public IP address (re)assignment.
+
+	This event is used to reconfigure services.
+
+        This event runs even if public IP addresses on a node have not
+	been changed.  This allows reconfiguration to depend on the
+	states of other nodes rather that just IP addresses.
+
+	Example: 11.natgw recalculates the NAT gateway master and
+	updates the relevant network configuration on each node if the
+	NAT gateway master has changed.
 
-Additional note for takeip, releaseip, recovered:
+Additional notes for "takeip", "releaseip", "updateip",
+ipreallocated":
 
-ALL services that depend on the ip address configuration of the node must 
-implement all three of these events.
+* Failure of any of these events causes IP allocation to be retried.
 
-ALL services that use TCP should also implement these events and at least
-kill off any tcp connections to the service if the ip address config has 
-changed in a similar fashion to how 60.nfs does it.
-The reason one must do this is that ESTABLISHED tcp connections may survive
-when an ip address is released and removed from the host until the ip address
-is re-takenover.
-Any tcp connections that survive a release/takeip sequence can potentially
-cause the client/server tcp connection to get out of sync with sequence and 
-ack numbers and cause a disruptive ack storm.
+* The "ipreallocated" event is run on all nodes.  It is even run if no
+  "takeip", "releaseip" or "updateip" events were triggered.
 
+* An event script can use ctdb_service_set_reconfigure() in "takeip"
+  or "releaseip" events to flag that its service needs to be
+  reconfigured.  The event script can then define a
+  service_reconfigure() function, which will be implicitly run before
+  the "ipreallocated" event.  This is a useful way of performing
+  reconfiguration that is conditional upon public IP address changes.
 
+  This means an explicit "ipreallocated" event handler is usually not
+  necessary.
diff --git a/ctdb/config/functions b/ctdb/config/functions
index 42b467b..eab5563 100755
--- a/ctdb/config/functions
+++ b/ctdb/config/functions
@@ -2,19 +2,53 @@
 
 # utility functions for ctdb event scripts
 
-[ -z "$CTDB_VARDIR" ] && {
-    if [ -d "/var/lib/ctdb" ] ; then
-	export CTDB_VARDIR="/var/lib/ctdb"
-    else
-	export CTDB_VARDIR="/var/ctdb"
-    fi
-}
-[ -z "$CTDB_ETCDIR" ] && {
-    export CTDB_ETCDIR="/etc"
-}
+if [ -z "$CTDB_BASE" ] ; then
+    echo 'CTDB_BASE unset in CTDB functions file'
+    exit 1
+fi
+
+CTDB_VARDIR="/usr/local/var/lib/ctdb"
+ctdb_rundir="/usr/local/var/run/ctdb"
+
+# Only (and always) override these variables in test code
+
+if [ -z "$CTDB_SCRIPT_VARDIR" ] ; then
+    CTDB_SCRIPT_VARDIR="/usr/local/var/lib/ctdb/state"
+fi
+
+if [ -z "$CTDB_SYS_ETCDIR" ] ; then
+    CTDB_SYS_ETCDIR="/etc"
+fi
+
+if [ -z "$CTDB_HELPER_BINDIR" ] ; then
+    CTDB_HELPER_BINDIR="/usr/local/libexec/ctdb"
+fi
 
 #######################################
 # pull in a system config file, if any
+
+rewrite_ctdb_options ()
+{
+    case "$CTDB_DBDIR" in
+	tmpfs|tmpfs:*)
+	    _opts_defaults="mode=700"
+	    # Get any extra options specified after colon
+	    if [ "$CTDB_DBDIR" = "tmpfs" ] ; then
+		_opts=""
+	    else
+		_opts="${CTDB_DBDIR#tmpfs:}"
+	    fi
+	    # This is an internal variable, only used by ctdbd_wrapper.
+	    # It is OK to repeat mount options - last value wins
+	    CTDB_DBDIR_TMPFS_OPTIONS="${_opts_defaults}${_opts:+,}${_opts}"
+
+	    CTDB_DBDIR="${ctdb_rundir}/CTDB_DBDIR"
+	    ;;
+	*)
+	    CTDB_DBDIR_TMPFS_OPTIONS=""
+    esac
+}
+
 _loadconfig() {
 
     if [ -z "$1" ] ; then
@@ -33,10 +67,10 @@ _loadconfig() {
 	return
     fi
 
-    if [ -f $CTDB_ETCDIR/sysconfig/$1 ]; then
-	. $CTDB_ETCDIR/sysconfig/$1
-    elif [ -f $CTDB_ETCDIR/default/$1 ]; then
-	. $CTDB_ETCDIR/default/$1
+    if [ -f $CTDB_SYS_ETCDIR/sysconfig/$1 ]; then
+	. $CTDB_SYS_ETCDIR/sysconfig/$1
+    elif [ -f $CTDB_SYS_ETCDIR/default/$1 ]; then
+	. $CTDB_SYS_ETCDIR/default/$1
     elif [ -f $CTDB_BASE/sysconfig/$1 ]; then
 	. $CTDB_BASE/sysconfig/$1
     fi
@@ -46,6 +80,7 @@ _loadconfig() {
 	if [ -r "$_config" ] ; then
 	    . "$_config"
 	fi
+	rewrite_ctdb_options
     fi
 }
 
@@ -95,7 +130,7 @@ script_log ()
 	    if [ -n "$CTDB_LOGGING" ] ; then
 		_file="${CTDB_LOGGING#file:}"
 	    else
-		_file="/var/log/log.ctdb"
+		_file="/usr/local/var/log/log.ctdb"
 	    fi
 	    {
 		if [ -n "$*" ] ; then
@@ -177,10 +212,10 @@ _service ()
       $_nice /sbin/service "$_service_name" "$_op"
   elif [ -x /usr/sbin/service ]; then
       $_nice /usr/sbin/service "$_service_name" "$_op"
-  elif [ -x $CTDB_ETCDIR/init.d/$_service_name ]; then
-      $_nice $CTDB_ETCDIR/init.d/$_service_name "$_op"
-  elif [ -x $CTDB_ETCDIR/rc.d/init.d/$_service_name ]; then
-      $_nice $CTDB_ETCDIR/rc.d/init.d/$_service_name "$_op"
+  elif [ -x $CTDB_SYS_ETCDIR/init.d/$_service_name ]; then
+      $_nice $CTDB_SYS_ETCDIR/init.d/$_service_name "$_op"
+  elif [ -x $CTDB_SYS_ETCDIR/rc.d/init.d/$_service_name ]; then
+      $_nice $CTDB_SYS_ETCDIR/rc.d/init.d/$_service_name "$_op"
   fi
 }
 
@@ -204,7 +239,7 @@ nice_service()
 # This sets $pnn - this avoid an unnecessary subprocess.
 ctdb_get_pnn ()
 {
-    _pnn_file="$CTDB_VARDIR/state/my-pnn"
+    _pnn_file="${CTDB_SCRIPT_VARDIR}/my-pnn"
     if [ ! -f "$_pnn_file" ] ; then
 	ctdb pnn | sed -e 's at .*:@@' >"$_pnn_file"
     fi
@@ -307,7 +342,8 @@ ctdb_check_directories()
 _ctdb_check_tcp_common ()
 {
     assert_service_name
-    _ctdb_service_started_file="$ctdb_fail_dir/$service_name.started"
+    _d="${CTDB_SCRIPT_VARDIR}/failcount"
+    _ctdb_service_started_file="${_d}/${service_name}.started"
 }
 
 ctdb_check_tcp_init ()
@@ -607,10 +643,104 @@ flush_route_cache ()
 }
 
 ########################################################
+# Interface monitoring
+
+# If the interface is a virtual one (e.g. VLAN) then get the
+# underlying interface
+interface_get_real ()
+{
+    # Output of "ip link show <iface>"
+    _iface_info="$1"
+
+    # Extract the full interface description to see if it is a VLAN
+    _t=$(echo "$_iface_info" |
+		awk 'NR == 1 { iface = $2; sub(":$", "", iface) ; \
+			       print iface }')
+    case "$_t" in
+	*@*)
+	    # VLAN: use the underlying interface, after the '@'
+	    echo "${_t##*@}"
+	    ;;
+	*)
+	    # Not a regular VLAN.  For backward compatibility, assume
+	    # there is some other sort of VLAN that doesn't have the
+	    # '@' in the output and only use what is before a '.'.  If
+	    # there is no '.' then this will be the whole interface
+	    # name.
+	    echo "${_t%%.*}"
+    esac
+}
+
+# Check whether an interface is operational
+interface_monitor ()
+{
+    _iface="$1"
+
+    _iface_info=$(ip link show "$_iface" 2>&1) || {
+	echo "ERROR: Monitored interface ${_iface} does not exist"
+	return 1
+    }
+
+
+    # If the interface is a virtual one (e.g. VLAN) then get the
+    # underlying interface.
+    _realiface=$(interface_get_real "$_iface_info")
+
+    if _bi=$(get_proc "net/bonding/${_realiface}" 2>/dev/null) ; then
+	# This is a bond: various monitoring strategies
+	echo "$_bi" | grep -q 'Currently Active Slave: None' && {
+	    echo "ERROR: No active slaves for bond device ${_realiface}"
+	    return 1
+	}
+	echo "$_bi" | grep -q '^MII Status: up' || {
+	    echo "ERROR: public network interface ${_realiface} is down"
+	    return 1
+	}
+	echo "$_bi" | grep -q '^Bonding Mode: IEEE 802.3ad Dynamic link aggregation' && {
+	    # This works around a bug in the driver where the
+	    # overall bond status can be up but none of the actual
+	    # physical interfaces have a link.
+	    echo "$_bi" | grep 'MII Status:' | tail -n +2 | grep -q '^MII Status: up' || {
+		echo "ERROR: No active slaves for 802.ad bond device ${_realiface}"
+		return 1
+	    }
+	}
+
+	return 0
+    else
+	# Not a bond
+	case "$_iface" in
+	    lo*)
+		# loopback is always working
+		return 0
+		;;
+	    ib*)
+		# we don't know how to test ib links
+		return 0
+		;;
+	    *)
+		ethtool "$_iface" | grep -q 'Link detected: yes' || {
+		    # On some systems, this is not successful when a
+		    # cable is plugged but the interface has not been
+		    # brought up previously. Bring the interface up
+		    # and try again...
+		    ip link set "$_iface" up
+		    ethtool "$_iface" | grep -q 'Link detected: yes' || {
+			echo "ERROR: No link on the public network interface ${_iface}"
+			return 1
+		    }
+		}
+		return 0
+		;;
+	esac
+    fi
+}
+
+########################################################
 # Simple counters
 _ctdb_counter_common () {
     _service_name="${1:-${service_name:-${script_name}}}"
-    _counter_file="$ctdb_fail_dir/$_service_name"
+    _counter_file="${CTDB_SCRIPT_VARDIR}/failcount/${_service_name}"
     mkdir -p "${_counter_file%/*}" # dirname
 }
 ctdb_counter_init () {
@@ -659,12 +789,9 @@ ctdb_check_counter () {
 
 ########################################################
 
-ctdb_status_dir="$CTDB_VARDIR/state/service_status"
-ctdb_fail_dir="$CTDB_VARDIR/state/failcount"
-
 ctdb_setup_service_state_dir ()
 {
-    service_state_dir="$CTDB_VARDIR/state/service_state/${1:-${service_name}}"
+    service_state_dir="${CTDB_SCRIPT_VARDIR}/service_state/${1:-${service_name}}"
     mkdir -p "$service_state_dir" || {
 	echo "Error creating state dir \"$service_state_dir\""
 	exit 1
@@ -674,17 +801,15 @@ ctdb_setup_service_state_dir ()
 ########################################################
 # Managed status history, for auto-start/stop
 
-ctdb_managed_dir="$CTDB_VARDIR/state/managed_history"
-
 _ctdb_managed_common ()
 {
-    _ctdb_managed_file="$ctdb_managed_dir/$service_name"
+    _ctdb_managed_file="${CTDB_SCRIPT_VARDIR}/managed_history/${service_name}"
 }
 
 ctdb_service_managed ()
 {
     _ctdb_managed_common
-    mkdir -p "$ctdb_managed_dir"
+    mkdir -p "${_ctdb_managed_file%/*}" # dirname
     touch "$_ctdb_managed_file"
 }
 
@@ -700,49 +825,12 @@ is_ctdb_previously_managed_service ()
     [ -f "$_ctdb_managed_file" ]
 }
 
-########################################################
-# Check and set status
-
-log_status_cat ()
-{
-    echo "node is \"$1\", \"${script_name}\" reports problem: $(cat $2)"
-}
-
-ctdb_checkstatus ()
-{
-    if [ -r "$ctdb_status_dir/$script_name/unhealthy" ] ; then
-	log_status_cat "unhealthy" "$ctdb_status_dir/$script_name/unhealthy"
-	return 1
-    elif [ -r "$ctdb_status_dir/$script_name/banned" ] ; then
-	log_status_cat "banned" "$ctdb_status_dir/$script_name/banned"
-	return 2
-    else
-	return 0
-    fi
-}
-
-ctdb_setstatus ()
-{
-    d="$ctdb_status_dir/$script_name"
-    case "$1" in
-	unhealthy|banned)
-	    mkdir -p "$d"
-	    cat "$2" >"$d/$1"
-	    ;;
-	*)
-	    for i in "banned" "unhealthy" ; do
-		rm -f "$d/$i"
-	    done
-	    ;;
-    esac
-}
-
 ##################################################################
 # Reconfigure a service on demand
 
 _ctdb_service_reconfigure_common ()
 {
-    _d="$ctdb_status_dir/${service_name}"
+    _d="${CTDB_SCRIPT_VARDIR}/service_status/${service_name}"
     mkdir -p "$_d"
     _ctdb_service_reconfigure_flag="$_d/reconfigure"
 }
@@ -1031,17 +1119,7 @@ service_stop ()
 
 ctdb_standard_event_handler ()
 {
-    case "$1" in
-	status)
-	    ctdb_checkstatus
-	    exit
-	    ;;
-	setstatus)
-            shift
-	    ctdb_setstatus "$@"
-	    exit
-	    ;;
-    esac
+    :
 }
 
 iptables_wrapper ()
@@ -1054,7 +1132,7 @@ iptables_wrapper ()
     fi
 
     # iptables doesn't like being re-entered, so flock-wrap it.
-    flock -w 30 "${CTDB_VARDIR}/iptables-ctdb.flock" "$_iptables_cmd" "$@"
+    flock -w 30 "${CTDB_SCRIPT_VARDIR}/iptables.flock" "$_iptables_cmd" "$@"
 }
 
 # AIX (and perhaps others?) doesn't have mktemp
@@ -1091,7 +1169,7 @@ update_tickles ()
 {
 	_port="$1"
 
-	tickledir="$CTDB_VARDIR/state/tickles"
+	tickledir="${CTDB_SCRIPT_VARDIR}/tickles"
 	mkdir -p "$tickledir"
 
 	ctdb_get_pnn
@@ -1102,17 +1180,18 @@ update_tickles ()
 	# IPs as a regexp choice
 	_ipschoice="($(echo $_ips | sed -e 's/ /|/g' -e 's/\./\\\\./g'))"
 
-	# Record connections to our public IPs in a temporary file
-	_my_connections="${tickledir}/${_port}.connections"
-	rm -f "$_my_connections"
+	# Record connections to our public IPs in a temporary file.
+	# This temporary file is in CTDB's private state directory and
+	# $$ is used to avoid a very rare race involving CTDB's script
+	# debugging.  No security issue, nothing to see here...
+	_my_connections="${tickledir}/${_port}.connections.$$"
 	netstat -tn |
 	awk -v destpat="^${_ipschoice}:${_port}\$" \
 	  '$1 == "tcp" && $6 == "ESTABLISHED" && $4 ~ destpat {print $5, $4}' |
 	sort >"$_my_connections"
 
 	# Record our current tickles in a temporary file
-	_my_tickles="${tickledir}/${_port}.tickles"
-	rm -f "$_my_tickles"
+	_my_tickles="${tickledir}/${_port}.tickles.$$"
 	for _i in $_ips ; do
 		ctdb -X gettickles $_i $_port |
 		awk -F'|' 'NR > 1 { printf "%s:%s %s:%s\n", $2, $3, $4, $5 }'
@@ -1131,7 +1210,10 @@ update_tickles ()
 		ctdb deltickle $_src $_dst
 	done
 
-	rm -f "$_my_connections" "$_my_tickles" 
+	rm -f "$_my_connections" "$_my_tickles"
+
+	# Remove stale files from killed scripts
+	find "$tickledir" -type f -mmin +10 | xargs -r rm
 }
 
 ########################################################
diff --git a/ctdb/config/nfs-linux-kernel-callout b/ctdb/config/nfs-linux-kernel-callout
index 5e77031..9532906 100755
--- a/ctdb/config/nfs-linux-kernel-callout
+++ b/ctdb/config/nfs-linux-kernel-callout
@@ -3,6 +3,15 @@
 # Exit on 1st error
 set -e
 
+# NFS exports file.  Some code below keeps a cache of output derived
+# from exportfs(8).  When this file is updated the cache is invalid
+# and needs to be regenerated.
+#
+# To change the file, edit the default value below.  Do not set
+# CTDB_NFS_EXPORTS_FILE - it isn't a configuration variable, just a
+# hook for testing.
+nfs_exports_file="${CTDB_NFS_EXPORTS_FILE:-/var/lib/nfs/etab}"
+
 # Red Hat
 nfs_service="nfs"
 nfslock_service="nfslock"
@@ -170,10 +179,25 @@ nfs_check_thread_count ()
 
 nfs_monitor_list_shares ()
 {
-    exportfs -v |
-	grep '^/' |
-	sed -e 's@[[:space:]][[:space:]]*[^[:space:]()][^[:space:]()]*([^[:space:]()][^[:space:]()]*)$@@' |
-	sort -u
+    _cache_file="${CTDB_NFS_CALLOUT_STATE_DIR}/list_shares_cache"
+    if  [ ! -r "$nfs_exports_file" ] || [ ! -r "$_cache_file" ] || \
+	    [ "$nfs_exports_file" -nt "$_cache_file" ] ; then
+	mkdir -p "$CTDB_NFS_CALLOUT_STATE_DIR"
+	# We could just use the contents of $nfs_exports_file.
+	# However, let's regard that file as internal to NFS and use
+	# exportfs, which is the public API.
+	if ! _exports=$(exportfs -v) ; then
+	    echo "WARNING: failed to run exportfs to list NFS shares" >&2
+	    return
+	fi
+
+	echo "$_exports" |
+	    grep '^/' |
+	    sed -e 's@[[:space:]][[:space:]]*[^[:space:]()][^[:space:]()]*([^[:space:]()][^[:space:]()]*)$@@' |
+	    sort -u >"$_cache_file"
+    fi
+
+    cat "$_cache_file"
 }
 
 ##################################################
diff --git a/ctdb/config/statd-callout b/ctdb/config/statd-callout
index 3b83446..a923d8a 100755
--- a/ctdb/config/statd-callout
+++ b/ctdb/config/statd-callout
@@ -93,7 +93,7 @@ case "$1" in
 
     notify)
 	# we must restart the lockmanager (on all nodes) so that we get
-	# a clusterwide grace period (so other clients dont take out
+	# a clusterwide grace period (so other clients don't take out
 	# conflicting locks through other nodes before all locks have been
 	# reclaimed)
 
@@ -103,7 +103,7 @@ case "$1" in
 	#echo 0 > /proc/sys/net/ipv4/tcp_max_tw_buckets
 	#echo 0 > /proc/sys/net/ipv4/tcp_max_orphans
 
-	# Delete the notification list for statd, we dont want it to 
+	# Delete the notification list for statd, we don't want it to 
 	# ping any clients
 	rm -f /var/lib/nfs/statd/sm/*
 	rm -f /var/lib/nfs/statd/sm.bak/*
@@ -159,7 +159,7 @@ case "$1" in
 	# Construct a sed expression to take catdb output and produce pairs of:
 	#   server-IP client-IP
 	# but only for the server-IPs that are hosted on this node.
-	ctdb_all_ips=$(ctdb ip -n all | tail -n +2)
+	ctdb_all_ips=$(ctdb ip all | tail -n +2)
 	sed_expr=$(echo "$ctdb_all_ips" |
 	    awk -v pnn=$pnn 'pnn == $2 { \
                 ip = $1; gsub(/\./, "\\.", ip); \
@@ -168,6 +168,7 @@ case "$1" in
 	statd_state=$(ctdb catdb ctdb.tdb | sed -n "$sed_expr" | sort)
 	[ -n "$statd_state" ] || exit 0
 
+	smnotify="${CTDB_HELPER_BINDIR}/smnotify"
 	prev=""
 	echo "$statd_state" | {
 	    # This all needs to be in the same command group at the
@@ -186,12 +187,12 @@ case "$1" in
 		# Reset stateval for each serverip
 		[ "$sip" = "$prev" ] || stateval="$state_even"
 		# Send notifies for server shutdown
-		smnotify --client=$cip --ip=$sip --server=$sip --stateval=$stateval
-		smnotify --client=$cip --ip=$sip --server=$NFS_HOSTNAME --stateval=$stateval
+		"$smnotify" --client=$cip --ip=$sip --server=$sip --stateval=$stateval
+		"$smnotify" --client=$cip --ip=$sip --server=$NFS_HOSTNAME --stateval=$stateval
 		# Send notifies for server startup
 		stateval=$(($stateval + 1))
-		smnotify --client=$cip --ip=$sip --server=$sip --stateval=$stateval
-		smnotify --client=$cip --ip=$sip --server=$NFS_HOSTNAME --stateval=$stateval
+		"$smnotify" --client=$cip --ip=$sip --server=$sip --stateval=$stateval
+		"$smnotify" --client=$cip --ip=$sip --server=$NFS_HOSTNAME --stateval=$stateval
 	    done
 
 	    echo "$items" | ctdb ptrans "ctdb.tdb"
diff --git a/ctdb/ctdb.pc.in b/ctdb/ctdb.pc.in
deleted file mode 100644
index 5f5bfab..0000000
--- a/ctdb/ctdb.pc.in
+++ /dev/null
@@ -1,19 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-datarootdir=@datarootdir@
-includedir=@includedir@
-libdir=@libdir@
-bindir=@bindir@
-sbindir=@sbindir@
-mandir=@mandir@
-localstatedir=@localstatedir@
-srcdir=@srcdir@
-etcdir=@sysconfdir@
-
-Name: ctdb
-Description: A clustered database to store temporary data
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir}
-Cflags: -I${includedir}
-URL: http://ctdb.samba.org/
-
diff --git a/ctdb/doc/ctdb-statistics.7 b/ctdb/doc/ctdb-statistics.7
index fd48f62..4f440ee 100644
--- a/ctdb/doc/ctdb-statistics.7
+++ b/ctdb/doc/ctdb-statistics.7
@@ -2,12 +2,12 @@
 .\"     Title: ctdb-statistics
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB\-STATISTICS" "7" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-STATISTICS" "7" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/ctdb/doc/ctdb-statistics.7.html b/ctdb/doc/ctdb-statistics.7.html
index 3ee766a..e9cfa89 100644
--- a/ctdb/doc/ctdb-statistics.7.html
+++ b/ctdb/doc/ctdb-statistics.7.html
@@ -1,10 +1,10 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-statistics</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-statistics.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-statistics — CTDB statistics output</p></div><div class="refsect1"><a name="idp53041024">< [...]
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-statistics</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-statistics.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-statistics — CTDB statistics output</p></div><div class="refsect1"><a name="idp52032112">< [...]
       CTDB maintains information about various messages communicated
       and some of the important operations per node.  See the
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span> commands
       <span class="command"><strong>statistics</strong></span> and <span class="command"><strong>statisticsreset</strong></span>
       for displaying statistics.
-    </p><div class="refsect2"><a name="idp50875296"></a><h3>Example: ctdb statistics</h3><pre class="screen">
+    </p><div class="refsect2"><a name="idp52333936"></a><h3>Example: ctdb statistics</h3><pre class="screen">
 CTDB version 1
 Current time of statistics  :                Fri Sep 12 13:32:32 2014
 Statistics collected since  : (000 01:49:20) Fri Sep 12 11:43:12 2014
@@ -55,151 +55,151 @@ Statistics collected since  : (000 01:49:20) Fri Sep 12 11:43:12 2014
  reclock_recd       MIN/AVG/MAX     0.000000/0.000000/0.000000 sec out of 0
  call_latency       MIN/AVG/MAX     0.000006/0.000719/4.562991 sec out of 126626
  childwrite_latency MIN/AVG/MAX     0.014527/0.014527/0.014527 sec out of 1
-	</pre></div><div class="refsect2"><a name="idp53698272"></a><h3>CTDB version</h3><p>
+	</pre></div><div class="refsect2"><a name="idp52992976"></a><h3>CTDB version</h3><p>
         Version of the ctdb protocol used by the node.
-      </p></div><div class="refsect2"><a name="idp53531952"></a><h3>Current time of statistics</h3><p>
+      </p></div><div class="refsect2"><a name="idp52639696"></a><h3>Current time of statistics</h3><p>
         Time when the statistics are generated.
       </p><p>
         This is useful when collecting statistics output periodically
         for post-processing.
-      </p></div><div class="refsect2"><a name="idp51198640"></a><h3>Statistics collected since</h3><p>
+      </p></div><div class="refsect2"><a name="idp52827040"></a><h3>Statistics collected since</h3><p>
 	Time when ctdb was started or the last time statistics was reset.
 	The output shows the duration and the timestamp.
-      </p></div><div class="refsect2"><a name="idp53599296"></a><h3>num_clients</h3><p>
+      </p></div><div class="refsect2"><a name="idp52657472"></a><h3>num_clients</h3><p>
         Number of processes currently connected to CTDB's unix socket.
         This includes recovery daemon, ctdb tool and samba processes
         (smbd, winbindd).
-      </p></div><div class="refsect2"><a name="idp54074992"></a><h3>frozen</h3><p>
+      </p></div><div class="refsect2"><a name="idp50156720"></a><h3>frozen</h3><p>
 	1 if the the databases are currently frozen, 0 otherwise.
-      </p></div><div class="refsect2"><a name="idp50448784"></a><h3>recovering</h3><p>
+      </p></div><div class="refsect2"><a name="idp49233296"></a><h3>recovering</h3><p>
 	1 if recovery is active, 0 otherwise.
-      </p></div><div class="refsect2"><a name="idp52810576"></a><h3>num_recoveries</h3><p>
+      </p></div><div class="refsect2"><a name="idp49234480"></a><h3>num_recoveries</h3><p>
 	Number of recoveries since the start of ctdb or since the last
 	statistics reset.
-      </p></div><div class="refsect2"><a name="idp52880800"></a><h3>client_packets_sent</h3><p>
+      </p></div><div class="refsect2"><a name="idp49235664"></a><h3>client_packets_sent</h3><p>
 	Number of packets sent to client processes via unix domain socket.
-      </p></div><div class="refsect2"><a name="idp53416128"></a><h3>client_packets_recv</h3><p>
+      </p></div><div class="refsect2"><a name="idp53887440"></a><h3>client_packets_recv</h3><p>
 	Number of packets received from client processes via unix domain socket.
-      </p></div><div class="refsect2"><a name="idp54195824"></a><h3>node_packets_sent</h3><p>
+      </p></div><div class="refsect2"><a name="idp53888624"></a><h3>node_packets_sent</h3><p>
 	Number of packets sent to the other nodes in the cluster via TCP.
-      </p></div><div class="refsect2"><a name="idp52658384"></a><h3>node_packets_recv</h3><p>
+      </p></div><div class="refsect2"><a name="idp53889808"></a><h3>node_packets_recv</h3><p>
 	Number of packets received from the other nodes in the cluster via TCP.
-      </p></div><div class="refsect2"><a name="idp53067152"></a><h3>keepalive_packets_sent</h3><p>
+      </p></div><div class="refsect2"><a name="idp53890992"></a><h3>keepalive_packets_sent</h3><p>
 	Number of keepalive messages sent to other nodes.
       </p><p>
 	CTDB periodically sends keepalive messages to other nodes.
 	See <em class="citetitle">KeepaliveInterval</em> tunable in
 	<span class="citerefentry"><span class="refentrytitle">ctdb-tunables</span>(7)</span> for more details.
-      </p></div><div class="refsect2"><a name="idp49083072"></a><h3>keepalive_packets_recv</h3><p>
+      </p></div><div class="refsect2"><a name="idp53893984"></a><h3>keepalive_packets_recv</h3><p>
 	Number of keepalive messages received from other nodes.
-      </p></div><div class="refsect2"><a name="idp49084256"></a><h3>node</h3><p>
+      </p></div><div class="refsect2"><a name="idp53895168"></a><h3>node</h3><p>
 	This section lists various types of messages processed which
 	originated from other nodes via TCP.
-      </p><div class="refsect3"><a name="idp49004400"></a><h4>req_call</h4><p>
+      </p><div class="refsect3"><a name="idp53896352"></a><h4>req_call</h4><p>
         Number of REQ_CALL messages from the other nodes.
-      </p></div><div class="refsect3"><a name="idp49005584"></a><h4>reply_call</h4><p>
+      </p></div><div class="refsect3"><a name="idp53897536"></a><h4>reply_call</h4><p>
         Number of REPLY_CALL messages from the other nodes.
-      </p></div><div class="refsect3"><a name="idp49006768"></a><h4>req_dmaster</h4><p>
+      </p></div><div class="refsect3"><a name="idp53898720"></a><h4>req_dmaster</h4><p>
         Number of REQ_DMASTER messages from the other nodes.
-      </p></div><div class="refsect3"><a name="idp49007952"></a><h4>reply_dmaster</h4><p>
+      </p></div><div class="refsect3"><a name="idp53899904"></a><h4>reply_dmaster</h4><p>
         Number of REPLY_DMASTER messages from the other nodes.
-      </p></div><div class="refsect3"><a name="idp49009136"></a><h4>reply_error</h4><p>
+      </p></div><div class="refsect3"><a name="idp53901088"></a><h4>reply_error</h4><p>
         Number of REPLY_ERROR messages from the other nodes.
-      </p></div><div class="refsect3"><a name="idp49010320"></a><h4>req_message</h4><p>
+      </p></div><div class="refsect3"><a name="idp53902352"></a><h4>req_message</h4><p>
         Number of REQ_MESSAGE messages from the other nodes.
-      </p></div><div class="refsect3"><a name="idp49011504"></a><h4>req_control</h4><p>
+      </p></div><div class="refsect3"><a name="idp49113072"></a><h4>req_control</h4><p>
         Number of REQ_CONTROL messages from the other nodes.
-      </p></div><div class="refsect3"><a name="idp49134368"></a><h4>reply_control</h4><p>
+      </p></div><div class="refsect3"><a name="idp49114336"></a><h4>reply_control</h4><p>
         Number of REPLY_CONTROL messages from the other nodes.
-      </p></div></div><div class="refsect2"><a name="idp49135680"></a><h3>client</h3><p>
+      </p></div></div><div class="refsect2"><a name="idp49115728"></a><h3>client</h3><p>
 	This section lists various types of messages processed which
 	originated from clients via unix domain socket.
-      </p><div class="refsect3"><a name="idp49136864"></a><h4>req_call</h4><p>
+      </p><div class="refsect3"><a name="idp49116912"></a><h4>req_call</h4><p>
         Number of REQ_CALL messages from the clients.
-      </p></div><div class="refsect3"><a name="idp49138048"></a><h4>req_message</h4><p>
+      </p></div><div class="refsect3"><a name="idp49118176"></a><h4>req_message</h4><p>
         Number of REQ_MESSAGE messages from the clients.
-      </p></div><div class="refsect3"><a name="idp49139232"></a><h4>req_control</h4><p>
+      </p></div><div class="refsect3"><a name="idp49119440"></a><h4>req_control</h4><p>
         Number of REQ_CONTROL messages from the clients.
-      </p></div></div><div class="refsect2"><a name="idp49140544"></a><h3>timeouts</h3><p>
+      </p></div></div><div class="refsect2"><a name="idp49120832"></a><h3>timeouts</h3><p>
 	This section lists timeouts occurred when sending various messages.
-      </p><div class="refsect3"><a name="idp49141696"></a><h4>call</h4><p>
+      </p><div class="refsect3"><a name="idp49121888"></a><h4>call</h4><p>
         Number of timeouts for REQ_CALL messages.
-      </p></div><div class="refsect3"><a name="idp49142880"></a><h4>control</h4><p>
+      </p></div><div class="refsect3"><a name="idp49123152"></a><h4>control</h4><p>
         Number of timeouts for REQ_CONTROL messages.
-      </p></div><div class="refsect3"><a name="idp49144064"></a><h4>traverse</h4><p>
+      </p></div><div class="refsect3"><a name="idp49124416"></a><h4>traverse</h4><p>
         Number of timeouts for database traverse operations.
-      </p></div></div><div class="refsect2"><a name="idp49145456"></a><h3>locks</h3><p>
+      </p></div></div><div class="refsect2"><a name="idp49125808"></a><h3>locks</h3><p>
 	This section lists locking statistics.
-      </p><div class="refsect3"><a name="idp49146512"></a><h4>num_calls</h4><p>
+      </p><div class="refsect3"><a name="idp49126864"></a><h4>num_calls</h4><p>
         Number of completed lock calls.  This includes database locks
         and record locks.
-      </p></div><div class="refsect3"><a name="idp49147696"></a><h4>num_current</h4><p>
+      </p></div><div class="refsect3"><a name="idp49128160"></a><h4>num_current</h4><p>
         Number of scheduled lock calls.  This includes database locks
         and record locks.
-      </p></div><div class="refsect3"><a name="idp49148992"></a><h4>num_pending</h4><p>
+      </p></div><div class="refsect3"><a name="idp49129456"></a><h4>num_pending</h4><p>
         Number of queued lock calls.  This includes database locks and
         record locks.
-      </p></div><div class="refsect3"><a name="idp48962640"></a><h4>num_failed</h4><p>
+      </p></div><div class="refsect3"><a name="idp49135552"></a><h4>num_failed</h4><p>
         Number of failed lock calls.  This includes database locks and
         record locks.
-      </p></div></div><div class="refsect2"><a name="idp48964064"></a><h3>total_calls</h3><p>
+      </p></div></div><div class="refsect2"><a name="idp49136976"></a><h3>total_calls</h3><p>
 	Number of req_call messages processed from clients.  This number
 	should be same as client --> req_call.
-      </p></div><div class="refsect2"><a name="idp48965376"></a><h3>pending_calls</h3><p>
+      </p></div><div class="refsect2"><a name="idp49138288"></a><h3>pending_calls</h3><p>
 	Number of req_call messages which are currenly being processed.
 	This number indicates the number of record migrations in flight.
-      </p></div><div class="refsect2"><a name="idp48966720"></a><h3>childwrite_calls</h3><p>
+      </p></div><div class="refsect2"><a name="idp49139632"></a><h3>childwrite_calls</h3><p>
 	Number of record update calls.	Record update calls are used to
 	update a record under a transaction.
-      </p></div><div class="refsect2"><a name="idp48968032"></a><h3>pending_childwrite_calls</h3><p>
+      </p></div><div class="refsect2"><a name="idp49140944"></a><h3>pending_childwrite_calls</h3><p>
 	Number of record update calls currently active.
-      </p></div><div class="refsect2"><a name="idp48969264"></a><h3>memory_used</h3><p>
+      </p></div><div class="refsect2"><a name="idp49142224"></a><h3>memory_used</h3><p>
 	The amount of memory in bytes currently used by CTDB using
 	talloc.  This includes all the memory used for CTDB's internal
 	data structures.  This does not include the memory mapped TDB
 	databases.
-      </p></div><div class="refsect2"><a name="idp48970672"></a><h3>max_hop_count</h3><p>
+      </p></div><div class="refsect2"><a name="idp49143632"></a><h3>max_hop_count</h3><p>
 	The maximum number of hops required for a record migration request
 	to obtain the record.  High numbers indicate record contention.
-      </p></div><div class="refsect2"><a name="idp48972016"></a><h3>total_ro_delegations</h3><p>
+      </p></div><div class="refsect2"><a name="idp49144976"></a><h3>total_ro_delegations</h3><p>
 	Number of readonly delegations created.
-      </p></div><div class="refsect2"><a name="idp48973200"></a><h3>total_ro_revokes</h3><p>
+      </p></div><div class="refsect2"><a name="idp49146160"></a><h3>total_ro_revokes</h3><p>
 	Number of readonly delegations that were revoked.  The difference
 	between total_ro_revokes and total_ro_delegations gives the
 	number of currently active readonly delegations.
-      </p></div><div class="refsect2"><a name="idp48974592"></a><h3>hop_count_buckets</h3><p>
+      </p></div><div class="refsect2"><a name="idp49147552"></a><h3>hop_count_buckets</h3><p>
 	Distribution of migration requests based on hop counts values.
 	Buckets are 1, < 4, < 8, < 16, < 32, < 64, <
 	128, < 256, < 512, ≥ 512.
-      </p></div><div class="refsect2"><a name="idp48975856"></a><h3>lock_buckets</h3><p>
+      </p></div><div class="refsect2"><a name="idp49154896"></a><h3>lock_buckets</h3><p>
 	Distribution of record lock requests based on time required to
 	obtain locks.  Buckets are < 1ms, < 10ms, < 100ms,
 	< 1s, < 2s, < 4s, < 8s, < 16s, < 32s, <
 	64s, ≥ 64s.
-      </p></div><div class="refsect2"><a name="idp48977664"></a><h3>locks_latency</h3><p>
+      </p></div><div class="refsect2"><a name="idp49156320"></a><h3>locks_latency</h3><p>
 	The minimum, the average and the maximum time (in seconds)
 	required to obtain record locks.
-      </p></div><div class="refsect2"><a name="idp48978928"></a><h3>reclock_ctdbd</h3><p>
+      </p></div><div class="refsect2"><a name="idp49157472"></a><h3>reclock_ctdbd</h3><p>
 	The minimum, the average and the maximum time (in seconds)
 	required to check if recovery lock is still held by recovery
 	daemon when recovery mode is changed.  This check is done in ctdb daemon.
-      </p></div><div class="refsect2"><a name="idp48980304"></a><h3>reclock_recd</h3><p>
+      </p></div><div class="refsect2"><a name="idp49149392"></a><h3>reclock_recd</h3><p>
         The minimum, the average and the maximum time (in seconds)
         required to check if recovery lock is still held by recovery
         daemon during recovery.  This check is done in recovery daemon.
-      </p></div><div class="refsect2"><a name="idp48990560"></a><h3>call_latency</h3><p>
+      </p></div><div class="refsect2"><a name="idp49150768"></a><h3>call_latency</h3><p>
 	The minimum, the average and the maximum time (in seconds) required
 	to process a REQ_CALL message from client.  This includes the time
 	required to migrate a record from remote node, if the record is
 	not available on the local node.
-      </p></div><div class="refsect2"><a name="idp48992000"></a><h3>childwrite_latency</h3><p>Default: 0</p><p>
+      </p></div><div class="refsect2"><a name="idp49152208"></a><h3>childwrite_latency</h3><p>Default: 0</p><p>
 	The minimum, the average and the maximum time (in seconds)
 	required to update records under a transaction.
-      </p></div></div><div class="refsect1"><a name="idp48993856"></a><h2>DATABASE STATISTICS</h2><p>
+      </p></div></div><div class="refsect1"><a name="idp55020752"></a><h2>DATABASE STATISTICS</h2><p>
       CTDB maintains per database statistics about important operations.
       See the <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span> command
       <span class="command"><strong>dbstatistics</strong></span> for displaying database statistics.
-    </p><div class="refsect2"><a name="idp48983600"></a><h3>Example: ctdb dbstatistics notify_index.tdb</h3><pre class="screen">
+    </p><div class="refsect2"><a name="idp55023408"></a><h3>Example: ctdb dbstatistics notify_index.tdb</h3><pre class="screen">
 DB Statistics: notify_index.tdb
  ro_delegations                     0
  ro_revokes                         0
@@ -215,45 +215,45 @@ DB Statistics: notify_index.tdb
      Count:7 Key:2f636c75737465726673
      Count:18 Key:2f636c757374657266732f64617461
      Count:7 Key:2f636c757374657266732f646174612f636c69656e7473
-	</pre></div><div class="refsect2"><a name="idp48985664"></a><h3>DB Statistics</h3><p>
+	</pre></div><div class="refsect2"><a name="idp55025440"></a><h3>DB Statistics</h3><p>
 	Name of the database.
-      </p></div><div class="refsect2"><a name="idp48986848"></a><h3>ro_delegations</h3><p>
+      </p></div><div class="refsect2"><a name="idp55026592"></a><h3>ro_delegations</h3><p>
 	Number of readonly delegations created in the database.
-      </p></div><div class="refsect2"><a name="idp48988032"></a><h3>ro_revokes</h3><p>
+      </p></div><div class="refsect2"><a name="idp55027744"></a><h3>ro_revokes</h3><p>
 	Number of readonly delegations revoked.  The difference in
 	ro_delegations and ro_revokes indicates the currently active
 	readonly delegations.
-      </p></div><div class="refsect2"><a name="idp48989392"></a><h3>locks</h3><p>
+      </p></div><div class="refsect2"><a name="idp55029072"></a><h3>locks</h3><p>
 	This section lists locking statistics.
-      </p><div class="refsect3"><a name="idp54477424"></a><h4>total</h4><p>
+      </p><div class="refsect3"><a name="idp55030096"></a><h4>total</h4><p>
         Number of completed lock calls.  This includes database locks
         and record locks.
-      </p></div><div class="refsect3"><a name="idp54478688"></a><h4>failed</h4><p>
+      </p></div><div class="refsect3"><a name="idp55031360"></a><h4>failed</h4><p>
         Number of failed lock calls.  This includes database locks and
         record locks.
-      </p></div><div class="refsect3"><a name="idp54479952"></a><h4>current</h4><p>
+      </p></div><div class="refsect3"><a name="idp55032624"></a><h4>current</h4><p>
         Number of scheduled lock calls.  This includes database locks
         and record locks.
-      </p></div><div class="refsect3"><a name="idp54481216"></a><h4>pending</h4><p>
+      </p></div><div class="refsect3"><a name="idp55033888"></a><h4>pending</h4><p>
         Number of queued lock calls.  This includes database locks and
         record locks.
-      </p></div></div><div class="refsect2"><a name="idp54482608"></a><h3>hop_count_buckets</h3><p>
+      </p></div></div><div class="refsect2"><a name="idp55035280"></a><h3>hop_count_buckets</h3><p>
 	Distribution of migration requests based on hop counts values.
 	Buckets are 1, < 4, < 8, < 16, < 32, < 64, <
 	128, < 256, < 512, ≥ 512.
-      </p></div><div class="refsect2"><a name="idp54483968"></a><h3>lock_buckets</h3><p>
+      </p></div><div class="refsect2"><a name="idp55036640"></a><h3>lock_buckets</h3><p>
 	Distribution of record lock requests based on time required to
 	obtain locks.  Buckets are < 1ms, < 10ms, < 100ms,
 	< 1s, < 2s, < 4s, < 8s, < 16s, < 32s, <
 	64s, ≥ 64s.
-      </p></div><div class="refsect2"><a name="idp54485392"></a><h3>locks_latency</h3><p>
+      </p></div><div class="refsect2"><a name="idp55038064"></a><h3>locks_latency</h3><p>
 	The minimum, the average and the maximum time (in seconds)
 	required to obtain record locks.
-      </p></div><div class="refsect2"><a name="idp54486656"></a><h3>Num Hot Keys</h3><p>
+      </p></div><div class="refsect2"><a name="idp55039328"></a><h3>Num Hot Keys</h3><p>
         Number of contended records determined by hop count.  CTDB keeps
         track of top 10 hot records and the output shows hex encoded
         keys for the hot records.
-      </p></div></div><div class="refsect1"><a name="idp54488128"></a><h2>SEE ALSO</h2><p>
+      </p></div></div><div class="refsect1"><a name="idp55040800"></a><h2>SEE ALSO</h2><p>
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span>,
 
       <span class="citerefentry"><span class="refentrytitle">ctdbd</span>(1)</span>,
diff --git a/ctdb/doc/ctdb-tunables.7 b/ctdb/doc/ctdb-tunables.7
index f830b02..e846437 100644
--- a/ctdb/doc/ctdb-tunables.7
+++ b/ctdb/doc/ctdb-tunables.7
@@ -2,12 +2,12 @@
 .\"     Title: ctdb-tunables
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB\-TUNABLES" "7" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-TUNABLES" "7" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -105,19 +105,16 @@ Default: 20
 How often will ctdb record and store the "tickle" information used to kickstart stalled tcp connections after a recovery\&.
 .SS "EventScriptTimeout"
 .PP
-Default: 20
-.PP
-How long should ctdb let an event script run before aborting it and marking the node unhealthy\&.
-.SS "EventScriptTimeoutCount"
+Default: 30
 .PP
-Default: 1
+Maximum time in seconds to allow an event to run before timing out\&. This is the total time for all enabled scripts that are run for an event, not just a single event script\&.
 .PP
-How many events in a row needs to timeout before we flag the node UNHEALTHY\&. This setting is useful if your scripts can not be written so that they do not hang for benign reasons\&.
-.SS "EventScriptUnhealthyOnTimeout"
+Note that timeouts are ignored for some events ("takeip", "releaseip", "startrecovery", "recovered") and converted to success\&. The logic here is that the callers of these events implement their own additional timeout\&.
+.SS "MonitorTimeoutCount"
 .PP
-Default: 0
+Default: 20
 .PP
-This setting can be be used to make ctdb never become UNHEALTHY if your eventscripts keep hanging/timing out\&.
+How many monitor events in a row need to timeout before a node is flagged as UNHEALTHY\&. This setting is useful if scripts can not be written so that they do not hang for benign reasons\&.
 .SS "RecoveryGracePeriod"
 .PP
 Default: 120
diff --git a/ctdb/doc/ctdb-tunables.7.html b/ctdb/doc/ctdb-tunables.7.html
index 84efc84..f01ad48 100644
--- a/ctdb/doc/ctdb-tunables.7.html
+++ b/ctdb/doc/ctdb-tunables.7.html
@@ -1,10 +1,10 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-tunables</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-tunables.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-tunables — CTDB tunable configuration variables</p></div><div class="refsect1"><a name="idp539 [...]
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-tunables</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-tunables.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-tunables — CTDB tunable configuration variables</p></div><div class="refsect1"><a name="idp520 [...]
       CTDB's behaviour can be configured by setting run-time tunable
       variables.  This lists and describes all tunables.  See the
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span>
       <span class="command"><strong>listvars</strong></span>, <span class="command"><strong>setvar</strong></span> and
       <span class="command"><strong>getvar</strong></span> commands for more details.
-    </p><div class="refsect2"><a name="idp53113904"></a><h3>MaxRedirectCount</h3><p>Default: 3</p><p>
+    </p><div class="refsect2"><a name="idp52844128"></a><h3>MaxRedirectCount</h3><p>Default: 3</p><p>
 	If we are not the DMASTER and need to fetch a record across the network
 	we first send the request to the LMASTER after which the record
 	is passed onto the current DMASTER. If the DMASTER changes before
@@ -18,7 +18,7 @@
       </p><p>
 	When chasing a record, this is how many hops we will chase the record
 	for before going back to the LMASTER to ask for new guidance.
-      </p></div><div class="refsect2"><a name="idp53710496"></a><h3>SeqnumInterval</h3><p>Default: 1000</p><p>
+      </p></div><div class="refsect2"><a name="idp52639696"></a><h3>SeqnumInterval</h3><p>Default: 1000</p><p>
 	Some databases have seqnum tracking enabled, so that samba will be able
 	to detect asynchronously when there has been updates to the database.
 	Everytime a database is updated its sequence number is increased.
@@ -26,17 +26,17 @@
 	This tunable is used to specify in 'ms' how frequently ctdb will
 	send out updates to remote nodes to inform them that the sequence
 	number is increased.
-      </p></div><div class="refsect2"><a name="idp52645584"></a><h3>ControlTimeout</h3><p>Default: 60</p><p>
+      </p></div><div class="refsect2"><a name="idp52023488"></a><h3>ControlTimeout</h3><p>Default: 60</p><p>
 	This is the default
 	setting for timeout for when sending a control message to either the
 	local or a remote ctdb daemon.
-      </p></div><div class="refsect2"><a name="idp54101312"></a><h3>TraverseTimeout</h3><p>Default: 20</p><p>
+      </p></div><div class="refsect2"><a name="idp51243376"></a><h3>TraverseTimeout</h3><p>Default: 20</p><p>
 	This setting controls how long we allow a traverse process to run.
 	After this timeout triggers, the main ctdb daemon will abort the
 	traverse if it has not yet finished.
-      </p></div><div class="refsect2"><a name="idp53520528"></a><h3>KeepaliveInterval</h3><p>Default: 5</p><p>
+      </p></div><div class="refsect2"><a name="idp50157008"></a><h3>KeepaliveInterval</h3><p>Default: 5</p><p>
 	How often in seconds should the nodes send keepalives to eachother.
-      </p></div><div class="refsect2"><a name="idp52258400"></a><h3>KeepaliveLimit</h3><p>Default: 5</p><p>
+      </p></div><div class="refsect2"><a name="idp49234000"></a><h3>KeepaliveLimit</h3><p>Default: 5</p><p>
 	After how many keepalive intervals without any traffic should a node
 	wait until marking the peer as DISCONNECTED.
       </p><p>
@@ -45,61 +45,65 @@
 	require a recovery. This limitshould not be set too high since we want
 	a hung node to be detectec, and expunged from the cluster well before
 	common CIFS timeouts (45-90 seconds) kick in.
-      </p></div><div class="refsect2"><a name="idp53046368"></a><h3>RecoverTimeout</h3><p>Default: 20</p><p>
+      </p></div><div class="refsect2"><a name="idp53887184"></a><h3>RecoverTimeout</h3><p>Default: 20</p><p>
 	This is the default setting for timeouts for controls when sent from the
 	recovery daemon. We allow longer control timeouts from the recovery daemon
 	than from normal use since the recovery dameon often use controls that 
 	can take a lot longer than normal controls.
-      </p></div><div class="refsect2"><a name="idp50061840"></a><h3>RecoverInterval</h3><p>Default: 1</p><p>
+      </p></div><div class="refsect2"><a name="idp53889072"></a><h3>RecoverInterval</h3><p>Default: 1</p><p>
 	How frequently in seconds should the recovery daemon perform the
 	consistency checks that determine if we need to perform a recovery or not.
-      </p></div><div class="refsect2"><a name="idp49094448"></a><h3>ElectionTimeout</h3><p>Default: 3</p><p>
+      </p></div><div class="refsect2"><a name="idp53890832"></a><h3>ElectionTimeout</h3><p>Default: 3</p><p>
 	When electing a new recovery master, this is how many seconds we allow
 	the election to take before we either deem the election finished
 	or we fail the election and start a new one.
-      </p></div><div class="refsect2"><a name="idp49096224"></a><h3>TakeoverTimeout</h3><p>Default: 9</p><p>
+      </p></div><div class="refsect2"><a name="idp53892640"></a><h3>TakeoverTimeout</h3><p>Default: 9</p><p>
 	This is how many seconds we allow controls to take for IP failover events.
-      </p></div><div class="refsect2"><a name="idp49146688"></a><h3>MonitorInterval</h3><p>Default: 15</p><p>
+      </p></div><div class="refsect2"><a name="idp53894240"></a><h3>MonitorInterval</h3><p>Default: 15</p><p>
 	How often should ctdb run the event scripts to check for a nodes health.
-      </p></div><div class="refsect2"><a name="idp49148288"></a><h3>TickleUpdateInterval</h3><p>Default: 20</p><p>
+      </p></div><div class="refsect2"><a name="idp53895840"></a><h3>TickleUpdateInterval</h3><p>Default: 20</p><p>
 	How often will ctdb record and store the "tickle" information used to
 	kickstart stalled tcp connections after a recovery.
-      </p></div><div class="refsect2"><a name="idp49150032"></a><h3>EventScriptTimeout</h3><p>Default: 20</p><p>
-	How long should ctdb let an event script run before aborting it and
-	marking the node unhealthy.
-      </p></div><div class="refsect2"><a name="idp49151760"></a><h3>EventScriptTimeoutCount</h3><p>Default: 1</p><p>
-	How many events in a row needs to timeout before we flag the node UNHEALTHY.
-	This setting is useful if your scripts can not be written so that they
-	do not hang for benign reasons.
-      </p></div><div class="refsect2"><a name="idp49153568"></a><h3>EventScriptUnhealthyOnTimeout</h3><p>Default: 0</p><p>
-	This setting can be be used to make ctdb never become UNHEALTHY if your
-	eventscripts keep hanging/timing out.
-      </p></div><div class="refsect2"><a name="idp49155312"></a><h3>RecoveryGracePeriod</h3><p>Default: 120</p><p>
+      </p></div><div class="refsect2"><a name="idp53897584"></a><h3>EventScriptTimeout</h3><p>Default: 30</p><p>
+	Maximum time in seconds to allow an event to run before timing
+	out.  This is the total time for all enabled scripts that are
+	run for an event, not just a single event script.
+      </p><p>
+	Note that timeouts are ignored for some events ("takeip",
+	"releaseip", "startrecovery", "recovered") and converted to
+	success.  The logic here is that the callers of these events
+	implement their own additional timeout.
+      </p></div><div class="refsect2"><a name="idp53900064"></a><h3>MonitorTimeoutCount</h3><p>Default: 20</p><p>
+	How many monitor events in a row need to timeout before a node
+	is flagged as UNHEALTHY.  This setting is useful if scripts
+	can not be written so that they do not hang for benign
+	reasons.
+      </p></div><div class="refsect2"><a name="idp53901872"></a><h3>RecoveryGracePeriod</h3><p>Default: 120</p><p>
 	During recoveries, if a node has not caused recovery failures during the
 	last grace period, any records of transgressions that the node has caused
 	recovery failures will be forgiven. This resets the ban-counter back to 
 	zero for that node.
-      </p></div><div class="refsect2"><a name="idp49157184"></a><h3>RecoveryBanPeriod</h3><p>Default: 300</p><p>
+      </p></div><div class="refsect2"><a name="idp49113200"></a><h3>RecoveryBanPeriod</h3><p>Default: 300</p><p>
 	If a node becomes banned causing repetitive recovery failures. The node will
 	eventually become banned from the cluster.
 	This controls how long the culprit node will be banned from the cluster
 	before it is allowed to try to join the cluster again.
 	Don't set to small. A node gets banned for a reason and it is usually due
 	to real problems with the node.
-      </p></div><div class="refsect2"><a name="idp49159168"></a><h3>DatabaseHashSize</h3><p>Default: 100001</p><p>
+      </p></div><div class="refsect2"><a name="idp49115184"></a><h3>DatabaseHashSize</h3><p>Default: 100001</p><p>
 	Size of the hash chains for the local store of the tdbs that ctdb manages.
-      </p></div><div class="refsect2"><a name="idp49160768"></a><h3>DatabaseMaxDead</h3><p>Default: 5</p><p>
+      </p></div><div class="refsect2"><a name="idp49116784"></a><h3>DatabaseMaxDead</h3><p>Default: 5</p><p>
 	How many dead records per hashchain in the TDB database do we allow before
 	the freelist needs to be processed.
-      </p></div><div class="refsect2"><a name="idp49162512"></a><h3>RerecoveryTimeout</h3><p>Default: 10</p><p>
+      </p></div><div class="refsect2"><a name="idp49118528"></a><h3>RerecoveryTimeout</h3><p>Default: 10</p><p>
 	Once a recovery has completed, no additional recoveries are permitted
 	until this timeout has expired.
-      </p></div><div class="refsect2"><a name="idp48975664"></a><h3>EnableBans</h3><p>Default: 1</p><p>
+      </p></div><div class="refsect2"><a name="idp49120256"></a><h3>EnableBans</h3><p>Default: 1</p><p>
 	When set to 0, this disables BANNING completely in the cluster and thus
 	nodes can not get banned, even it they break. Don't set to 0 unless you
 	know what you are doing.  You should set this to the same value on
 	all nodes to avoid unexpected behaviour.
-      </p></div><div class="refsect2"><a name="idp48977536"></a><h3>DeterministicIPs</h3><p>Default: 0</p><p>
+      </p></div><div class="refsect2"><a name="idp49122128"></a><h3>DeterministicIPs</h3><p>Default: 0</p><p>
 	When enabled, this tunable makes ctdb try to keep public IP addresses
 	locked to specific nodes as far as possible. This makes it easier for
 	debugging since you can know that as long as all nodes are healthy
@@ -110,12 +114,12 @@
 	public IP assignment changes in the cluster. This tunable may increase
 	the number of IP failover/failbacks that are performed on the cluster
 	by a small margin.
-      </p></div><div class="refsect2"><a name="idp48980128"></a><h3>LCP2PublicIPs</h3><p>Default: 1</p><p>
+      </p></div><div class="refsect2"><a name="idp49124720"></a><h3>LCP2PublicIPs</h3><p>Default: 1</p><p>
 	When enabled this switches ctdb to use the LCP2 ip allocation
 	algorithm.
-      </p></div><div class="refsect2"><a name="idp48981824"></a><h3>ReclockPingPeriod</h3><p>Default: x</p><p>
+      </p></div><div class="refsect2"><a name="idp49126320"></a><h3>ReclockPingPeriod</h3><p>Default: x</p><p>
 	Obsolete
-      </p></div><div class="refsect2"><a name="idp48983456"></a><h3>NoIPFailback</h3><p>Default: 0</p><p>
+      </p></div><div class="refsect2"><a name="idp49127952"></a><h3>NoIPFailback</h3><p>Default: 0</p><p>
 	When set to 1, ctdb will not perform failback of IP addresses when a node
 	becomes healthy. Ctdb WILL perform failover of public IP addresses when a
 	node becomes UNHEALTHY, but when the node becomes HEALTHY again, ctdb
@@ -133,7 +137,7 @@
 	intervention from the administrator. When this parameter is set, you can
 	manually fail public IP addresses over to the new node(s) using the
 	'ctdb moveip' command.
-      </p></div><div class="refsect2"><a name="idp48986832"></a><h3>DisableIPFailover</h3><p>Default: 0</p><p>
+      </p></div><div class="refsect2"><a name="idp49136144"></a><h3>DisableIPFailover</h3><p>Default: 0</p><p>
 	When enabled, ctdb will not perform failover or failback. Even if a
 	node fails while holding public IPs, ctdb will not recover the IPs or
 	assign them to another node.
@@ -142,12 +146,12 @@
 	the cluster by failing IP addresses over to other nodes. This leads to
 	a service outage until the administrator has manually performed failover
 	to replacement nodes using the 'ctdb moveip' command.
-      </p></div><div class="refsect2"><a name="idp48989296"></a><h3>NoIPTakeover</h3><p>Default: 0</p><p>
+      </p></div><div class="refsect2"><a name="idp49138608"></a><h3>NoIPTakeover</h3><p>Default: 0</p><p>
 	When set to 1, ctdb will not allow IP addresses to be failed over
 	onto this node. Any IP addresses that the node currently hosts
 	will remain on the node but no new IP addresses can be failed over
 	to the node.
-      </p></div><div class="refsect2"><a name="idp48995728"></a><h3>NoIPHostOnAllDisabled</h3><p>Default: 0</p><p>
+      </p></div><div class="refsect2"><a name="idp49140448"></a><h3>NoIPHostOnAllDisabled</h3><p>Default: 0</p><p>
 	If no nodes are healthy then by default ctdb will happily host
 	public IPs on disabled (unhealthy or administratively disabled)
 	nodes.  This can cause problems, for example if the underlying
@@ -155,52 +159,52 @@
 	that node is disabled it, any IPs hosted by this node will be
 	released and the node will not takeover any IPs until it is no
 	longer disabled.
-      </p></div><div class="refsect2"><a name="idp48997760"></a><h3>DBRecordCountWarn</h3><p>Default: 100000</p><p>
+      </p></div><div class="refsect2"><a name="idp49142480"></a><h3>DBRecordCountWarn</h3><p>Default: 100000</p><p>
 	When set to non-zero, ctdb will log a warning when we try to recover a
 	database with more than this many records. This will produce a warning
 	if a database grows uncontrollably with orphaned records.
-      </p></div><div class="refsect2"><a name="idp48999584"></a><h3>DBRecordSizeWarn</h3><p>Default: 10000000</p><p>
+      </p></div><div class="refsect2"><a name="idp49144304"></a><h3>DBRecordSizeWarn</h3><p>Default: 10000000</p><p>
 	When set to non-zero, ctdb will log a warning when we try to recover a
 	database where a single record is bigger than this. This will produce
 	a warning if a database record grows uncontrollably with orphaned
 	sub-records.
-      </p></div><div class="refsect2"><a name="idp49001424"></a><h3>DBSizeWarn</h3><p>Default: 1000000000</p><p>
+      </p></div><div class="refsect2"><a name="idp49146144"></a><h3>DBSizeWarn</h3><p>Default: 1000000000</p><p>
 	When set to non-zero, ctdb will log a warning when we try to recover a
 	database bigger than this. This will produce
 	a warning if a database grows uncontrollably.
-      </p></div><div class="refsect2"><a name="idp49003216"></a><h3>VerboseMemoryNames</h3><p>Default: 0</p><p>
+      </p></div><div class="refsect2"><a name="idp49147936"></a><h3>VerboseMemoryNames</h3><p>Default: 0</p><p>
 	This feature consumes additional memory. when used the talloc library
 	will create more verbose names for all talloc allocated objects.
-      </p></div><div class="refsect2"><a name="idp49004976"></a><h3>RecdPingTimeout</h3><p>Default: 60</p><p>
+      </p></div><div class="refsect2"><a name="idp49149696"></a><h3>RecdPingTimeout</h3><p>Default: 60</p><p>
 	If the main dameon has not heard a "ping" from the recovery dameon for
 	this many seconds, the main dameon will log a message that the recovery
 	daemon is potentially hung.
-      </p></div><div class="refsect2"><a name="idp49006768"></a><h3>RecdFailCount</h3><p>Default: 10</p><p>
+      </p></div><div class="refsect2"><a name="idp49151488"></a><h3>RecdFailCount</h3><p>Default: 10</p><p>
 	If the recovery daemon has failed to ping the main dameon for this many
 	consecutive intervals, the main daemon will consider the recovery daemon
 	as hung and will try to restart it to recover.
-      </p></div><div class="refsect2"><a name="idp49008592"></a><h3>LogLatencyMs</h3><p>Default: 0</p><p>
+      </p></div><div class="refsect2"><a name="idp49153312"></a><h3>LogLatencyMs</h3><p>Default: 0</p><p>
 	When set to non-zero, this will make the main daemon log any operation that
 	took longer than this value, in 'ms', to complete.
 	These include "how long time a lockwait child process needed", 
 	"how long time to write to a persistent database" but also
 	"how long did it take to get a response to a CALL from a remote node".
-      </p></div><div class="refsect2"><a name="idp49010544"></a><h3>RecLockLatencyMs</h3><p>Default: 1000</p><p>
+      </p></div><div class="refsect2"><a name="idp49155264"></a><h3>RecLockLatencyMs</h3><p>Default: 1000</p><p>
 	When using a reclock file for split brain prevention, if set to non-zero
 	this tunable will make the recovery dameon log a message if the fcntl()
 	call to lock/testlock the recovery file takes longer than this number of 
 	ms.
-      </p></div><div class="refsect2"><a name="idp49012400"></a><h3>RecoveryDropAllIPs</h3><p>Default: 120</p><p>
+      </p></div><div class="refsect2"><a name="idp49157120"></a><h3>RecoveryDropAllIPs</h3><p>Default: 120</p><p>
 	If we have been stuck in recovery, or stopped, or banned, mode for
 	this many seconds we will force drop all held public addresses.
-      </p></div><div class="refsect2"><a name="idp49014160"></a><h3>VacuumInterval</h3><p>Default: 10</p><p>
+      </p></div><div class="refsect2"><a name="idp55021168"></a><h3>VacuumInterval</h3><p>Default: 10</p><p>
         Periodic interval in seconds when vacuuming is triggered for
         volatile databases.
-      </p></div><div class="refsect2"><a name="idp49015888"></a><h3>VacuumMaxRunTime</h3><p>Default: 120</p><p>
+      </p></div><div class="refsect2"><a name="idp55022832"></a><h3>VacuumMaxRunTime</h3><p>Default: 120</p><p>
         The maximum time in seconds for which the vacuuming process is
         allowed to run.  If vacuuming process takes longer than this
         value, then the vacuuming process is terminated.
-      </p></div><div class="refsect2"><a name="idp49017712"></a><h3>RepackLimit</h3><p>Default: 10000</p><p>
+      </p></div><div class="refsect2"><a name="idp55024592"></a><h3>RepackLimit</h3><p>Default: 10000</p><p>
         During vacuuming, if the number of freelist records are more
         than <code class="varname">RepackLimit</code>, then databases are
         repacked to get rid of the freelist records to avoid
@@ -209,7 +213,7 @@
         Databases are repacked only if both
         <code class="varname">RepackLimit</code> and
         <code class="varname">VacuumLimit</code> are exceeded.
-      </p></div><div class="refsect2"><a name="idp54490736"></a><h3>VacuumLimit</h3><p>Default: 5000</p><p>
+      </p></div><div class="refsect2"><a name="idp55027792"></a><h3>VacuumLimit</h3><p>Default: 5000</p><p>
         During vacuuming, if the number of deleted records are more
         than <code class="varname">VacuumLimit</code>, then databases are
         repacked to avoid fragmentation.
@@ -217,14 +221,14 @@
         Databases are repacked only if both
         <code class="varname">RepackLimit</code> and
         <code class="varname">VacuumLimit</code> are exceeded.
-      </p></div><div class="refsect2"><a name="idp54493808"></a><h3>VacuumFastPathCount</h3><p>Default: 60</p><p>
+      </p></div><div class="refsect2"><a name="idp55030864"></a><h3>VacuumFastPathCount</h3><p>Default: 60</p><p>
         When a record is deleted, it is marked for deletion during
         vacuuming.  Vacuuming process usually processes this list to purge
         the records from the database.  If the number of records marked
         for deletion are more than VacuumFastPathCount, then vacuuming
 	process will scan the complete database for empty records instead
 	of using the list of records marked for deletion.
-      </p></div><div class="refsect2"><a name="idp54495776"></a><h3>DeferredAttachTO</h3><p>Default: 120</p><p>
+      </p></div><div class="refsect2"><a name="idp55032832"></a><h3>DeferredAttachTO</h3><p>Default: 120</p><p>
 	When databases are frozen we do not allow clients to attach to the
 	databases. Instead of returning an error immediately to the application
 	the attach request from the client is deferred until the database
@@ -232,7 +236,7 @@
       </p><p>
 	This timeout controls how long we will defer the request from the client
 	before timing it out and returning an error to the client.
-      </p></div><div class="refsect2"><a name="idp54498160"></a><h3>HopcountMakeSticky</h3><p>Default: 50</p><p>
+      </p></div><div class="refsect2"><a name="idp55035216"></a><h3>HopcountMakeSticky</h3><p>Default: 50</p><p>
 	If the database is set to 'STICKY' mode, using the 'ctdb setdbsticky' 
 	command, any record that is seen as very hot and migrating so fast that
 	hopcount surpasses 50 is set to become a STICKY record for StickyDuration
@@ -243,21 +247,21 @@
 	migrating across the cluster so fast. This will improve performance for
 	certain workloads, such as locking.tdb if many clients are opening/closing
 	the same file concurrently.
-      </p></div><div class="refsect2"><a name="idp54500720"></a><h3>StickyDuration</h3><p>Default: 600</p><p>
+      </p></div><div class="refsect2"><a name="idp55037776"></a><h3>StickyDuration</h3><p>Default: 600</p><p>
 	Once a record has been found to be fetch-lock hot and has been flagged to
 	become STICKY, this is for how long, in seconds, the record will be 
 	flagged as a STICKY record.
-      </p></div><div class="refsect2"><a name="idp54502448"></a><h3>StickyPindown</h3><p>Default: 200</p><p>
+      </p></div><div class="refsect2"><a name="idp55039504"></a><h3>StickyPindown</h3><p>Default: 200</p><p>
 	Once a STICKY record has been migrated onto a node, it will be pinned down
 	on that node for this number of ms. Any request from other nodes to migrate
 	the record off the node will be deferred until the pindown timer expires.
-      </p></div><div class="refsect2"><a name="idp54504240"></a><h3>StatHistoryInterval</h3><p>Default: 1</p><p>
+      </p></div><div class="refsect2"><a name="idp55041296"></a><h3>StatHistoryInterval</h3><p>Default: 1</p><p>
 	Granularity of the statistics collected in the statistics history.
-      </p></div><div class="refsect2"><a name="idp54505872"></a><h3>AllowClientDBAttach</h3><p>Default: 1</p><p>
+      </p></div><div class="refsect2"><a name="idp55042928"></a><h3>AllowClientDBAttach</h3><p>Default: 1</p><p>
 	When set to 0, clients are not allowed to attach to any databases.
 	This can be used to temporarily block any new processes from attaching
 	to and accessing the databases.
-      </p></div><div class="refsect2"><a name="idp54507600"></a><h3>RecoverPDBBySeqNum</h3><p>Default: 1</p><p>
+      </p></div><div class="refsect2"><a name="idp55044656"></a><h3>RecoverPDBBySeqNum</h3><p>Default: 1</p><p>
 	When set to zero, database recovery for persistent databases
 	is record-by-record and recovery process simply collects the
 	most recent version of every individual record.
@@ -270,7 +274,7 @@
       </p><p>
 	By default, recovery of persistent databses is done using
 	__db_sequence_number__ record.
-      </p></div><div class="refsect2"><a name="idp54510528"></a><h3>FetchCollapse</h3><p>Default: 1</p><p>
+      </p></div><div class="refsect2"><a name="idp55047584"></a><h3>FetchCollapse</h3><p>Default: 1</p><p>
 	When many clients across many nodes try to access the same record at the
 	same time this can lead to a fetch storm where the record becomes very
 	active and bounces between nodes very fast. This leads to high CPU
@@ -286,14 +290,14 @@
       </p><p>
 	This timeout controls if we should collapse multiple fetch operations
 	of the same record into a single request and defer all duplicates or not.
-      </p></div><div class="refsect2"><a name="idp54513728"></a><h3>Samba3AvoidDeadlocks</h3><p>Default: 0</p><p>
+      </p></div><div class="refsect2"><a name="idp55050784"></a><h3>Samba3AvoidDeadlocks</h3><p>Default: 0</p><p>
 	Enable code that prevents deadlocks with Samba (only for Samba 3.x).
       </p><p>
 	This should be set to 1 when using Samba version 3.x to enable special
 	code in CTDB to avoid deadlock with Samba version 3.x.  This code
 	is not required for Samba version 4.x and must not be enabled for
 	Samba 4.x.
-      </p></div></div><div class="refsect1"><a name="idp54516112"></a><h2>SEE ALSO</h2><p>
+      </p></div></div><div class="refsect1"><a name="idp55053168"></a><h2>SEE ALSO</h2><p>
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span>,
 
       <span class="citerefentry"><span class="refentrytitle">ctdbd</span>(1)</span>,
diff --git a/ctdb/doc/ctdb-tunables.7.xml b/ctdb/doc/ctdb-tunables.7.xml
index b029fdb..6c164f3 100644
--- a/ctdb/doc/ctdb-tunables.7.xml
+++ b/ctdb/doc/ctdb-tunables.7.xml
@@ -166,29 +166,29 @@
 
     <refsect2>
       <title>EventScriptTimeout</title>
-      <para>Default: 20</para>
+      <para>Default: 30</para>
       <para>
-	How long should ctdb let an event script run before aborting it and
-	marking the node unhealthy.
+	Maximum time in seconds to allow an event to run before timing
+	out.  This is the total time for all enabled scripts that are
+	run for an event, not just a single event script.
       </para>
-    </refsect2>
 
-    <refsect2>
-      <title>EventScriptTimeoutCount</title>
-      <para>Default: 1</para>
       <para>
-	How many events in a row needs to timeout before we flag the node UNHEALTHY.
-	This setting is useful if your scripts can not be written so that they
-	do not hang for benign reasons.
+	Note that timeouts are ignored for some events ("takeip",
+	"releaseip", "startrecovery", "recovered") and converted to
+	success.  The logic here is that the callers of these events
+	implement their own additional timeout.
       </para>
     </refsect2>
 
     <refsect2>
-      <title>EventScriptUnhealthyOnTimeout</title>
-      <para>Default: 0</para>
+      <title>MonitorTimeoutCount</title>
+      <para>Default: 20</para>
       <para>
-	This setting can be be used to make ctdb never become UNHEALTHY if your
-	eventscripts keep hanging/timing out.
+	How many monitor events in a row need to timeout before a node
+	is flagged as UNHEALTHY.  This setting is useful if scripts
+	can not be written so that they do not hang for benign
+	reasons.
       </para>
     </refsect2>
 
diff --git a/ctdb/doc/ctdb.1 b/ctdb/doc/ctdb.1
index 5b961b9..51e73a1 100644
--- a/ctdb/doc/ctdb.1
+++ b/ctdb/doc/ctdb.1
@@ -2,12 +2,12 @@
 .\"     Title: ctdb
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB" "1" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB" "1" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -114,7 +114,7 @@ Change the debug level for the command\&. Default is NOTICE (2)\&.
 \-\-socket=\fIFILENAME\fR
 .RS 4
 Specify that FILENAME is the name of the Unix domain socket to use when connecting to the local CTDB daemon\&. The default is
-/tmp/ctdb\&.socket\&.
+/usr/local/var/run/ctdb/ctdbd\&.socket\&.
 .RE
 .SH "ADMINISTRATIVE COMMANDS"
 .PP
@@ -265,14 +265,6 @@ exits with 0 if it was able to retrieve status for all nodes\&.
 provides status information for all nodes\&.
 \fBctdb nodestatus\fR
 defaults to providing status for only the current node\&. If PNN\-LIST is provided then status is given for the indicated node(s)\&.
-.sp
-By default,
-\fBctdb nodestatus\fR
-gathers status from the local node\&. However, if invoked with "\-n all" (or similar) then status is gathered from the given node(s)\&. In particular
-\fBctdb nodestatus all\fR
-and
-\fBctdb nodestatus \-n all\fR
-will produce different output\&. It is possible to provide 2 different nodespecs (with and without "\-n") but the output is usually confusing!
 .RE
 .PP
 A common invocation in scripts is
@@ -412,11 +404,8 @@ This command will "ping" specified CTDB nodes in the cluster to verify that they
 .RS 4
 .\}
 .nf
-# ctdb ping \-n all
+# ctdb ping
 response from 0 time=0\&.000054 sec  (3 clients)
-response from 1 time=0\&.000144 sec  (2 clients)
-response from 2 time=0\&.000105 sec  (2 clients)
-response from 3 time=0\&.000114 sec  (2 clients)
 	
 .fi
 .if n \{\
@@ -460,7 +449,7 @@ name:eth2 link:up references:1
 .RE
 .SS "ip"
 .PP
-This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip\&. By default this command will ONLY show those public addresses that are known to the node itself\&. To see the full list of all public ips across the cluster you must use "ctdb ip \-n all"\&.
+This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip\&. By default this command will ONLY show those public addresses that are known to the node itself\&. To see the full list of all public ips across the cluster you must use "ctdb ip all"\&.
 .sp
 .it 1 an-trap
 .nr an-no-space-flag 1
@@ -603,7 +592,7 @@ TakeoverTimeout         = 9
 MonitorInterval         = 15
 TickleUpdateInterval    = 20
 EventScriptTimeout      = 30
-EventScriptTimeoutCount = 1
+MonitorTimeoutCount     = 1
 RecoveryGracePeriod     = 120
 RecoveryBanPeriod       = 300
 DatabaseHashSize        = 100001
@@ -709,7 +698,6 @@ Example output:
 RECMASTER: YES
 LMASTER: YES
 LVS: NO
-NATGW: YES
       
 .fi
 .if n \{\
@@ -840,9 +828,7 @@ If no FILE is specified then a recovery lock file will no longer be used\&.
 .PP
 This command only affects the run\-time setting of a single CTDB node\&. This setting
 \fImust\fR
-be changed on all nodes simultaneously by specifying
-\fB\-n all\fR
-(or similar)\&. For information about configuring the recovery lock file please see the
+be changed on all nodes simultaneously\&. For information about configuring the recovery lock file please see the
 CTDB_RECOVERY_LOCK
 entry in
 \fBctdbd.conf\fR(5)
@@ -924,32 +910,152 @@ See also "ctdb getcapabilities"
 .PP
 This command is used when adding new nodes, or removing existing nodes from an existing cluster\&.
 .PP
-Procedure to add a node:
-.PP
-1, To expand an existing cluster, first ensure with \*(Aqctdb status\*(Aq that all nodes are up and running and that they are all healthy\&. Do not try to expand a cluster unless it is completely healthy!
-.PP
-2, On all nodes, edit /etc/ctdb/nodes and add the new node as the last entry to the file\&. The new node MUST be added to the end of this file!
-.PP
-3, Verify that all the nodes have identical /etc/ctdb/nodes files after you edited them and added the new node!
-.PP
-4, Run \*(Aqctdb reloadnodes\*(Aq to force all nodes to reload the nodesfile\&.
-.PP
-5, Use \*(Aqctdb status\*(Aq on all nodes and verify that they now show the additional node\&.
-.PP
-6, Install and configure the new node and bring it online\&.
-.PP
-Procedure to remove a node:
-.PP
-1, To remove a node from an existing cluster, first ensure with \*(Aqctdb status\*(Aq that all nodes, except the node to be deleted, are up and running and that they are all healthy\&. Do not try to remove a node from a cluster unless the cluster is completely healthy!
-.PP
-2, Shutdown and poweroff the node to be removed\&.
-.PP
-3, On all other nodes, edit the /etc/ctdb/nodes file and comment out the node to be removed\&. Do not delete the line for that node, just comment it out by adding a \*(Aq#\*(Aq at the beginning of the line\&.
-.PP
-4, Run \*(Aqctdb reloadnodes\*(Aq to force all nodes to reload the nodesfile\&.
-.PP
-5, Use \*(Aqctdb status\*(Aq on all nodes and verify that the deleted node no longer shows up in the list\&.\&.
+Procedure to add nodes:
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  1." 4.2
+.\}
+To expand an existing cluster, first ensure with
+\fBctdb status\fR
+that all nodes are up and running and that they are all healthy\&. Do not try to expand a cluster unless it is completely healthy!
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  2." 4.2
+.\}
+On all nodes, edit
+/usr/local/etc/ctdb/nodes
+and
+\fIadd the new nodes at the end of this file\fR\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  3." 4.2
+.\}
+Verify that all the nodes have identical
+/usr/local/etc/ctdb/nodes
+files after adding the new nodes\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  4." 4.2
+.\}
+Run
+\fBctdb reloadnodes\fR
+to force all nodes to reload the nodes file\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 5.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  5." 4.2
+.\}
+Use
+\fBctdb status\fR
+on all nodes and verify that they now show the additional nodes\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 6.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  6." 4.2
+.\}
+Install and configure the new node and bring it online\&.
+.RE
 .PP
+Procedure to remove nodes:
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  1." 4.2
+.\}
+To remove nodes from an existing cluster, first ensure with
+\fBctdb status\fR
+that all nodes, except the node to be deleted, are up and running and that they are all healthy\&. Do not try to remove nodes from a cluster unless the cluster is completely healthy!
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  2." 4.2
+.\}
+Shutdown and power off the node to be removed\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  3." 4.2
+.\}
+On all other nodes, edit the
+/usr/local/etc/ctdb/nodes
+file and
+\fIcomment out\fR
+the nodes to be removed\&.
+\fIDo not delete the lines for the deleted nodes\fR, just comment them out by adding a \*(Aq#\*(Aq at the beginning of the lines\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  4." 4.2
+.\}
+Run
+\fBctdb reloadnodes\fR
+to force all nodes to reload the nodes file\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 5.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  5." 4.2
+.\}
+Use
+\fBctdb status\fR
+on all nodes and verify that the deleted nodes are no longer listed\&.
+.RE
 .SS "reloadips [\fIPNN\-LIST\fR]"
 .PP
 This command reloads the public addresses configuration file on the specified nodes\&. When it completes addresses will be reconfigured and reassigned across the cluster as necessary\&.
@@ -977,24 +1083,24 @@ Most databases are not persistent and only store the state information that the
 .nf
 # ctdb getdbmap
 Number of databases:10
-dbid:0x435d3410 name:notify\&.tdb path:/var/ctdb/notify\&.tdb\&.0 
-dbid:0x42fe72c5 name:locking\&.tdb path:/var/ctdb/locking\&.tdb\&.0
-dbid:0x1421fb78 name:brlock\&.tdb path:/var/ctdb/brlock\&.tdb\&.0 
-dbid:0x17055d90 name:connections\&.tdb path:/var/ctdb/connections\&.tdb\&.0 
-dbid:0xc0bdde6a name:sessionid\&.tdb path:/var/ctdb/sessionid\&.tdb\&.0 
-dbid:0x122224da name:test\&.tdb path:/var/ctdb/test\&.tdb\&.0 
-dbid:0x2672a57f name:idmap2\&.tdb path:/var/ctdb/persistent/idmap2\&.tdb\&.0 PERSISTENT
-dbid:0xb775fff6 name:secrets\&.tdb path:/var/ctdb/persistent/secrets\&.tdb\&.0 PERSISTENT
-dbid:0xe98e08b6 name:group_mapping\&.tdb path:/var/ctdb/persistent/group_mapping\&.tdb\&.0 PERSISTENT
-dbid:0x7bbbd26c name:passdb\&.tdb path:/var/ctdb/persistent/passdb\&.tdb\&.0 PERSISTENT
+dbid:0x435d3410 name:notify\&.tdb path:/usr/local/var/lib/ctdb/notify\&.tdb\&.0
+dbid:0x42fe72c5 name:locking\&.tdb path:/usr/local/var/lib/ctdb/locking\&.tdb\&.0
+dbid:0x1421fb78 name:brlock\&.tdb path:/usr/local/var/lib/ctdb/brlock\&.tdb\&.0
+dbid:0x17055d90 name:connections\&.tdb path:/usr/local/var/lib/ctdb/connections\&.tdb\&.0
+dbid:0xc0bdde6a name:sessionid\&.tdb path:/usr/local/var/lib/ctdb/sessionid\&.tdb\&.0
+dbid:0x122224da name:test\&.tdb path:/usr/local/var/lib/ctdb/test\&.tdb\&.0
+dbid:0x2672a57f name:idmap2\&.tdb path:/usr/local/var/lib/ctdb/persistent/idmap2\&.tdb\&.0 PERSISTENT
+dbid:0xb775fff6 name:secrets\&.tdb path:/usr/local/var/lib/ctdb/persistent/secrets\&.tdb\&.0 PERSISTENT
+dbid:0xe98e08b6 name:group_mapping\&.tdb path:/usr/local/var/lib/ctdb/persistent/group_mapping\&.tdb\&.0 PERSISTENT
+dbid:0x7bbbd26c name:passdb\&.tdb path:/usr/local/var/lib/ctdb/persistent/passdb\&.tdb\&.0 PERSISTENT
 
 # ctdb getdbmap  # example for unhealthy database
 Number of databases:1
-dbid:0xb775fff6 name:secrets\&.tdb path:/var/ctdb/persistent/secrets\&.tdb\&.0 PERSISTENT UNHEALTHY
+dbid:0xb775fff6 name:secrets\&.tdb path:/usr/local/var/lib/ctdb/persistent/secrets\&.tdb\&.0 PERSISTENT UNHEALTHY
 
 # ctdb \-X getdbmap
 |ID|Name|Path|Persistent|Unhealthy|
-|0x7bbbd26c|passdb\&.tdb|/var/ctdb/persistent/passdb\&.tdb\&.0|1|0|
+|0x7bbbd26c|passdb\&.tdb|/usr/local/var/lib/ctdb/persistent/passdb\&.tdb\&.0|1|0|
 	
 .fi
 .if n \{\
@@ -1090,9 +1196,6 @@ Set the internal state of network interface IFACE\&. This is typically used in t
 script in the "monitor" event\&.
 .PP
 Example: ctdb setifacelink eth0 up
-.SS "setnatgwstate on|off"
-.PP
-Enable or disable the NAT gateway master capability on a node\&.
 .SS "tickle \fISRC\-IPADDR\fR:\fISRC\-PORT\fR \fIDST\-IPADDR\fR:\fIDST\-PORT\fR"
 .PP
 Send a TCP tickle to the source host for the specified TCP connection\&. A TCP tickle is a TCP ACK packet with an invalid sequence and acknowledge number and will when received by the source host result in it sending an immediate correct ACK back to the other end\&.
@@ -1152,16 +1255,16 @@ This command displays more details about a database\&.
 # ctdb getdbstatus test\&.tdb\&.0
 dbid: 0x122224da
 name: test\&.tdb
-path: /var/ctdb/test\&.tdb\&.0
+path: /usr/local/var/lib/ctdb/test\&.tdb\&.0
 PERSISTENT: no
 HEALTH: OK
 
 # ctdb getdbstatus registry\&.tdb  # with a corrupted TDB
 dbid: 0xf2a58948
 name: registry\&.tdb
-path: /var/ctdb/persistent/registry\&.tdb\&.0
+path: /usr/local/var/lib/ctdb/persistent/registry\&.tdb\&.0
 PERSISTENT: yes
-HEALTH: NO\-HEALTHY\-NODES \- ERROR \- Backup of corrupted TDB in \*(Aq/var/ctdb/persistent/registry\&.tdb\&.0\&.corrupted\&.20091208091949\&.0Z\*(Aq
+HEALTH: NO\-HEALTHY\-NODES \- ERROR \- Backup of corrupted TDB in \*(Aq/usr/local/var/lib/ctdb/persistent/registry\&.tdb\&.0\&.corrupted\&.20091208091949\&.0Z\*(Aq
 	
 .fi
 .if n \{\
diff --git a/ctdb/doc/ctdb.1.html b/ctdb/doc/ctdb.1.html
index cef0592..ecccd5e 100644
--- a/ctdb/doc/ctdb.1.html
+++ b/ctdb/doc/ctdb.1.html
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb — CTDB management utility</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><cod [...]
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb — CTDB management utility</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><cod [...]
       ctdb is a utility to view and manage a CTDB cluster.
     </p><p>
       The following terms are used when referring to nodes in a
@@ -21,7 +21,7 @@
 	      A space separated list of at least one
 	      <em class="parameter"><code>DB</code></em>.
 	    </p></dd></dl></div><p>
-    </p></div><div class="refsect1"><a name="idp49137312"></a><h2>OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-n <em class="parameter"><code>PNN-LIST</code></em></span></dt><dd><p>
+    </p></div><div class="refsect1"><a name="idp50201040"></a><h2>OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-n <em class="parameter"><code>PNN-LIST</code></em></span></dt><dd><p>
 	  The nodes specified by PNN-LIST should be queried for the
 	  requested information.  Default is to query the daemon
 	  running on the local host.
@@ -58,27 +58,27 @@
 	  Specify that FILENAME is the name of the Unix domain
 	  socket to use when connecting to the local CTDB
 	  daemon. The default is
-	  <code class="filename">/tmp/ctdb.socket</code>.
-	</p></dd></dl></div></div><div class="refsect1"><a name="idp48970304"></a><h2>ADMINISTRATIVE COMMANDS</h2><p>
+	  <code class="filename">/usr/local/var/run/ctdb/ctdbd.socket</code>.
+	</p></dd></dl></div></div><div class="refsect1"><a name="idp49122192"></a><h2>ADMINISTRATIVE COMMANDS</h2><p>
       These are commands used to monitor and administer a CTDB cluster.
-    </p><div class="refsect2"><a name="idp48971360"></a><h3>pnn</h3><p>
+    </p><div class="refsect2"><a name="idp49123344"></a><h3>pnn</h3><p>
 	This command displays the PNN of the current node.
-      </p></div><div class="refsect2"><a name="idp48972512"></a><h3>xpnn</h3><p>
+      </p></div><div class="refsect2"><a name="idp49124496"></a><h3>xpnn</h3><p>
 	This command displays the PNN of the current node without
 	contacting the CTDB daemon.  It parses the nodes file
 	directly, so can produce unexpected output if the nodes file
 	has been edited but has not been reloaded.
-      </p></div><div class="refsect2"><a name="idp48973936"></a><h3>status</h3><p>
+      </p></div><div class="refsect2"><a name="idp49125920"></a><h3>status</h3><p>
 	This command shows the current status of all CTDB nodes based
 	on information from the queried node.
       </p><p>
 	Note: If the the queried node is INACTIVE then the status
 	might not be current.
-      </p><div class="refsect3"><a name="idp48975616"></a><h4>Node status</h4><p>
+      </p><div class="refsect3"><a name="idp49127600"></a><h4>Node status</h4><p>
 	  This includes the number of physical nodes and the status of
 	  each node.  See <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for information
 	  about node states.
-	</p></div><div class="refsect3"><a name="idp48977872"></a><h4>Generation</h4><p>
+	</p></div><div class="refsect3"><a name="idp49129856"></a><h4>Generation</h4><p>
 	  The generation id is a number that indicates the current generation 
 	  of a cluster instance. Each time a cluster goes through a 
 	  reconfiguration or a recovery its generation id will be changed.
@@ -99,13 +99,13 @@
 	  All nodes start with generation "INVALID" and are not assigned a real
 	  generation id until they have successfully been merged with a cluster
 	  through a recovery.
-	</p></div><div class="refsect3"><a name="idp48980400"></a><h4>Virtual Node Number (VNN) map</h4><p>
+	</p></div><div class="refsect3"><a name="idp49138416"></a><h4>Virtual Node Number (VNN) map</h4><p>
 	  Consists of the number of virtual nodes and mapping from
 	  virtual node numbers to physical node numbers.  Virtual
 	  nodes host CTDB databases.  Only nodes that are
 	  participating in the VNN map can become lmaster or dmaster
 	  for database records.
-	</p></div><div class="refsect3"><a name="idp48987952"></a><h4>Recovery mode</h4><p>
+	</p></div><div class="refsect3"><a name="idp49139840"></a><h4>Recovery mode</h4><p>
 	  This is the current recovery mode of the cluster. There are two possible modes:
 	</p><p>
 	  NORMAL - The cluster is fully operational.
@@ -125,13 +125,13 @@
 	  databases have been recovered, the node mode will change into
 	  NORMAL mode and the databases will be "thawed", allowing samba
 	  to access the databases again.
-	</p></div><div class="refsect3"><a name="idp48991760"></a><h4>Recovery master</h4><p>
+	</p></div><div class="refsect3"><a name="idp49143744"></a><h4>Recovery master</h4><p>
 	  This is the cluster node that is currently designated as the recovery master. This node is responsible of monitoring the consistency of the cluster and to perform the actual recovery process when reqired.
 	</p><p>
 	  Only one node at a time can be the designated recovery master. Which
 	  node is designated the recovery master is decided by an election
 	  process in the recovery daemons running on each node.
-	</p></div><div class="refsect3"><a name="idp48993760"></a><h4>Example</h4><pre class="screen">
+	</p></div><div class="refsect3"><a name="idp49145744"></a><h4>Example</h4><pre class="screen">
 # ctdb status
 Number of nodes:4
 pnn:0 192.168.2.200       OK (THIS NODE)
@@ -146,7 +146,7 @@ hash:2 lmaster:2
 hash:3 lmaster:3
 Recovery mode:NORMAL (0)
 Recovery master:0
-	</pre></div></div><div class="refsect2"><a name="idp48995664"></a><h3>nodestatus [<span class="optional"><em class="parameter"><code>PNN-LIST</code></em></span>]</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp49147648"></a><h3>nodestatus [<span class="optional"><em class="parameter"><code>PNN-LIST</code></em></span>]</h3><p>
 	This command is similar to the <span class="command"><strong>status</strong></span>
 	command.  It displays the "node status" subset of output.  The
 	main differences are:
@@ -160,20 +160,11 @@ Recovery master:0
 	    defaults to providing status for only the current node.
 	    If PNN-LIST is provided then status is given for
 	    the indicated node(s).
-	  </p><p>
-	    By default, <span class="command"><strong>ctdb nodestatus</strong></span> gathers
-	    status from the local node.  However, if invoked with "-n
-	    all" (or similar) then status is gathered from the given
-	    node(s).  In particular <span class="command"><strong>ctdb nodestatus
-	    all</strong></span> and <span class="command"><strong>ctdb nodestatus -n
-	    all</strong></span> will produce different output.  It is
-	    possible to provide 2 different nodespecs (with and
-	    without "-n") but the output is usually confusing!
 	  </p></li></ul></div><p>
 	A common invocation in scripts is <span class="command"><strong>ctdb nodestatus
 	all</strong></span> to check whether all nodes in a cluster are
 	healthy.
-      </p><div class="refsect3"><a name="idp49006608"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp49155600"></a><h4>Example</h4><pre class="screen">
 # ctdb nodestatus
 pnn:0 10.0.0.30        OK (THIS NODE)
 
@@ -181,33 +172,33 @@ pnn:0 10.0.0.30        OK (THIS NODE)
 Number of nodes:2
 pnn:0 10.0.0.30        OK (THIS NODE)
 pnn:1 10.0.0.31        OK
-	</pre></div></div><div class="refsect2"><a name="idp49008368"></a><h3>recmaster</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp49157360"></a><h3>recmaster</h3><p>
 	This command shows the pnn of the node which is currently the recmaster.
       </p><p>
 	Note: If the the queried node is INACTIVE then the status
 	might not be current.
-      </p></div><div class="refsect2"><a name="idp54721184"></a><h3>uptime</h3><p>
+      </p></div><div class="refsect2"><a name="idp49159136"></a><h3>uptime</h3><p>
 	This command shows the uptime for the ctdb daemon. When the last recovery or ip-failover completed and how long it took. If the "duration" is shown as a negative number, this indicates that there is a recovery/failover in progress and it started that many seconds ago.
-      </p><div class="refsect3"><a name="idp54722496"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp49160480"></a><h4>Example</h4><pre class="screen">
 # ctdb uptime
 Current time of node          :                Thu Oct 29 10:38:54 2009
 Ctdbd start time              : (000 16:54:28) Wed Oct 28 17:44:26 2009
 Time of last recovery/failover: (000 16:53:31) Wed Oct 28 17:45:23 2009
 Duration of last recovery/failover: 2.248552 seconds
-	</pre></div></div><div class="refsect2"><a name="idp54724320"></a><h3>listnodes</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55084192"></a><h3>listnodes</h3><p>
 	This command shows lists the ip addresses of all the nodes in the cluster.
-      </p><div class="refsect3"><a name="idp54725440"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55085312"></a><h4>Example</h4><pre class="screen">
 # ctdb listnodes
 192.168.2.200
 192.168.2.201
 192.168.2.202
 192.168.2.203
-	</pre></div></div><div class="refsect2"><a name="idp54727056"></a><h3>natgwlist</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55086928"></a><h3>natgwlist</h3><p>
 	Show the current NAT gateway master and the status of all
 	nodes in the current NAT gateway group.  See the
 	<em class="citetitle">NAT GATEWAY</em> section in
 	<span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for more details.
-      </p><div class="refsect3"><a name="idp54729488"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55089360"></a><h4>Example</h4><pre class="screen">
 # ctdb natgwlist
 0 192.168.2.200
 Number of nodes:4
@@ -215,19 +206,16 @@ pnn:0 192.168.2.200       OK (THIS NODE)
 pnn:1 192.168.2.201       OK
 pnn:2 192.168.2.202       OK
 pnn:3 192.168.2.203       OK
-	</pre></div></div><div class="refsect2"><a name="idp54731200"></a><h3>ping</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55091072"></a><h3>ping</h3><p>
 	This command will "ping" specified CTDB nodes in the cluster
 	to verify that they are running.
-      </p><div class="refsect3"><a name="idp54732336"></a><h4>Example</h4><pre class="screen">
-# ctdb ping -n all
+      </p><div class="refsect3"><a name="idp55092208"></a><h4>Example</h4><pre class="screen">
+# ctdb ping
 response from 0 time=0.000054 sec  (3 clients)
-response from 1 time=0.000144 sec  (2 clients)
-response from 2 time=0.000105 sec  (2 clients)
-response from 3 time=0.000114 sec  (2 clients)
-	</pre></div></div><div class="refsect2"><a name="idp54734080"></a><h3>ifaces</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55093728"></a><h3>ifaces</h3><p>
 	This command will display the list of network interfaces, which could
 	host public addresses, along with their status.
-      </p><div class="refsect3"><a name="idp54735248"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55094896"></a><h4>Example</h4><pre class="screen">
 # ctdb ifaces
 Interfaces on node 0
 name:eth5 link:up references:2
@@ -241,9 +229,9 @@ name:eth2 link:up references:1
 |eth4|0|0|
 |eth3|1|1|
 |eth2|1|1|
-	</pre></div></div><div class="refsect2"><a name="idp54737040"></a><h3>ip</h3><p>
-	This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip. By default this command will ONLY show those public addresses that are known to the node itself. To see the full list of all public ips across the cluster you must use "ctdb ip -n all".
-      </p><div class="refsect3"><a name="idp54738752"></a><h4>Example</h4><pre class="screen">
+	</pre></div></div><div class="refsect2"><a name="idp55096688"></a><h3>ip</h3><p>
+	This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip. By default this command will ONLY show those public addresses that are known to the node itself. To see the full list of all public ips across the cluster you must use "ctdb ip all".
+      </p><div class="refsect3"><a name="idp55098064"></a><h4>Example</h4><pre class="screen">
 # ctdb ip -v
 Public IPs on node 0
 172.31.91.82 node[1] active[] available[eth2,eth3] configured[eth2,eth3]
@@ -265,9 +253,9 @@ Public IPs on node 0
 |172.31.92.83|0|eth5|eth5|eth4,eth5|
 |172.31.92.84|1||eth5|eth4,eth5|
 |172.31.92.85|0|eth5|eth5|eth4,eth5|
-	</pre></div></div><div class="refsect2"><a name="idp54741296"></a><h3>ipinfo <em class="parameter"><code>IP</code></em></h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55101616"></a><h3>ipinfo <em class="parameter"><code>IP</code></em></h3><p>
 	This command will display details about the specified public addresses.
-      </p><div class="refsect3"><a name="idp54742912"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55103232"></a><h4>Example</h4><pre class="screen">
 # ctdb ipinfo 172.31.92.85
 Public IP[172.31.92.85] info on node 0
 IP:172.31.92.85
@@ -275,9 +263,9 @@ CurrentNode:0
 NumInterfaces:2
 Interface[1]: Name:eth4 Link:down References:0
 Interface[2]: Name:eth5 Link:up References:2 (active)
-	</pre></div></div><div class="refsect2"><a name="idp54744656"></a><h3>scriptstatus</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55104976"></a><h3>scriptstatus</h3><p>
 	This command displays which scripts where run in the previous monitoring cycle and the result of each script. If a script failed with an error, causing the node to become unhealthy, the output from that script is also shown.
-      </p><div class="refsect3"><a name="idp54745936"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55106256"></a><h4>Example</h4><pre class="screen">
 # ctdb scriptstatus
 7 scripts were executed last monitoring cycle
 00.ctdb              Status:OK    Duration:0.056 Tue Mar 24 18:56:57 2009
@@ -289,19 +277,19 @@ Interface[2]: Name:eth5 Link:up References:2 (active)
 41.httpd             Status:OK    Duration:0.039 Tue Mar 24 18:56:57 2009
 50.samba             Status:ERROR    Duration:0.082 Tue Mar 24 18:56:57 2009
 OUTPUT:ERROR: Samba tcp port 445 is not responding
-      </pre></div></div><div class="refsect2"><a name="idp54748160"></a><h3>disablescript <em class="parameter"><code>SCRIPT</code></em></h3><p>
+      </pre></div></div><div class="refsect2"><a name="idp55108480"></a><h3>disablescript <em class="parameter"><code>SCRIPT</code></em></h3><p>
 	This command is used to disable an eventscript.
       </p><p>
 	This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'.
-      </p></div><div class="refsect2"><a name="idp54750368"></a><h3>enablescript <em class="parameter"><code>SCRIPT</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55110768"></a><h3>enablescript <em class="parameter"><code>SCRIPT</code></em></h3><p>
 	This command is used to enable an eventscript.
       </p><p>
 	This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'.
-      </p></div><div class="refsect2"><a name="idp54752576"></a><h3>listvars</h3><p>
+      </p></div><div class="refsect2"><a name="idp55112976"></a><h3>listvars</h3><p>
 	List all tuneable variables, except the values of the obsolete tunables
 	like VacuumMinInterval. The obsolete tunables can be retrieved only
 	explicitly with the "ctdb getvar" command.
-      </p><div class="refsect3"><a name="idp54753808"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55114208"></a><h4>Example</h4><pre class="screen">
 # ctdb listvars
 MaxRedirectCount        = 3
 SeqnumInterval          = 1000
@@ -316,7 +304,7 @@ TakeoverTimeout         = 9
 MonitorInterval         = 15
 TickleUpdateInterval    = 20
 EventScriptTimeout      = 30
-EventScriptTimeoutCount = 1
+MonitorTimeoutCount     = 1
 RecoveryGracePeriod     = 120
 RecoveryBanPeriod       = 300
 DatabaseHashSize        = 100001
@@ -346,16 +334,16 @@ StatHistoryInterval     = 1
 DeferredAttachTO        = 120
 AllowClientDBAttach     = 1
 RecoverPDBBySeqNum      = 0
-	</pre></div></div><div class="refsect2"><a name="idp54757872"></a><h3>getvar <em class="parameter"><code>NAME</code></em></h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55118272"></a><h3>getvar <em class="parameter"><code>NAME</code></em></h3><p>
 	Get the runtime value of a tuneable variable.
-      </p><div class="refsect3"><a name="idp54759392"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55119792"></a><h4>Example</h4><pre class="screen">
 # ctdb getvar MaxRedirectCount
 MaxRedirectCount    = 3
-	</pre></div></div><div class="refsect2"><a name="idp54760912"></a><h3>setvar <em class="parameter"><code>NAME</code></em> <em class="parameter"><code>VALUE</code></em></h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55121392"></a><h3>setvar <em class="parameter"><code>NAME</code></em> <em class="parameter"><code>VALUE</code></em></h3><p>
 	Set the runtime value of a tuneable variable.
       </p><p>
 	Example: ctdb setvar MaxRedirectCount 5
-      </p></div><div class="refsect2"><a name="idp54763568"></a><h3>lvsmaster</h3><p>
+      </p></div><div class="refsect2"><a name="idp55124048"></a><h3>lvsmaster</h3><p>
 	This command shows which node is currently the LVSMASTER. The
 	LVSMASTER is the node in the cluster which drives the LVS system and
 	which receives all incoming traffic from clients.
@@ -366,7 +354,7 @@ MaxRedirectCount    = 3
 	evenly onto the other nodes in the cluster. This is an alternative to using
 	public ip addresses. See the manpage for ctdbd for more information
 	about LVS.
-      </p></div><div class="refsect2"><a name="idp54765696"></a><h3>lvs</h3><p>
+      </p></div><div class="refsect2"><a name="idp55126176"></a><h3>lvs</h3><p>
 	This command shows which nodes in the cluster are currently active in the
 	LVS configuration. I.e. which nodes we are currently loadbalancing
 	the single ip address across.
@@ -381,7 +369,7 @@ MaxRedirectCount    = 3
       </p><pre class="screen">
 2:10.0.0.13
 3:10.0.0.14
-      </pre></div><div class="refsect2"><a name="idp54768736"></a><h3>getcapabilities</h3><p>
+      </pre></div><div class="refsect2"><a name="idp55129216"></a><h3>getcapabilities</h3><p>
 	This command shows the capabilities of the current node.  See
 	the <em class="citetitle">CAPABILITIES</em> section in
 	<span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for more details.
@@ -391,13 +379,12 @@ MaxRedirectCount    = 3
 RECMASTER: YES
 LMASTER: YES
 LVS: NO
-NATGW: YES
-      </pre></div><div class="refsect2"><a name="idp54772176"></a><h3>statistics</h3><p>
+      </pre></div><div class="refsect2"><a name="idp55132736"></a><h3>statistics</h3><p>
         Collect statistics from the CTDB daemon about
         how many calls it has served.  Information about
         various fields in statistics can be found in
 	<span class="citerefentry"><span class="refentrytitle">ctdb-statistics</span>(7)</span>.
-      </p><div class="refsect3"><a name="idp54774272"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55134832"></a><h4>Example</h4><pre class="screen">
 # ctdb statistics
 CTDB version 1
 num_clients                        3
@@ -434,15 +421,15 @@ memory_used                     5040
 max_hop_count                      0
 max_call_latency                   4.948321 sec
 max_lockwait_latency               0.000000 sec
-	</pre></div></div><div class="refsect2"><a name="idp54776976"></a><h3>statisticsreset</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55138704"></a><h3>statisticsreset</h3><p>
 	This command is used to clear all statistics counters in a node.
       </p><p>
 	Example: ctdb statisticsreset
-      </p></div><div class="refsect2"><a name="idp54778608"></a><h3>dbstatistics <em class="parameter"><code>DB</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55140336"></a><h3>dbstatistics <em class="parameter"><code>DB</code></em></h3><p>
 	Display statistics about the database DB.  Information
 	about various fields in dbstatistics can be found in
 	<span class="citerefentry"><span class="refentrytitle">ctdb-statistics</span>(7)</span>.
-      </p><div class="refsect3"><a name="idp54781152"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55142880"></a><h4>Example</h4><pre class="screen">
 # ctdb dbstatistics locking.tdb
 DB Statistics: locking.tdb
  ro_delegations                     0
@@ -457,13 +444,13 @@ DB Statistics: locking.tdb
  locks_latency      MIN/AVG/MAX     0.001066/0.012686/4.202292 sec out of 14356
  Num Hot Keys:     1
      Count:8 Key:ff5bd7cb3ee3822edc1f0000000000000000000000000000
-	</pre></div></div><div class="refsect2"><a name="idp54783264"></a><h3>getreclock</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55144992"></a><h3>getreclock</h3><p>
 	Show the name of the recovery lock file, if any.
       </p><p>
 	Example output:
       </p><pre class="screen">
 	Reclock file:/clusterfs/.ctdb/recovery.lock
-      </pre></div><div class="refsect2"><a name="idp54785424"></a><h3>
+      </pre></div><div class="refsect2"><a name="idp55147232"></a><h3>
 	setreclock [<span class="optional"><em class="parameter"><code>FILE</code></em></span>]
       </h3><p>
 	FILE specifies the name of the recovery lock file.  If the
@@ -476,8 +463,7 @@ DB Statistics: locking.tdb
       </p><p>
 	This command only affects the run-time setting of a single
 	CTDB node.  This setting <span class="emphasis"><em>must</em></span> be changed
-	on all nodes simultaneously by specifying <code class="option">-n
-	all</code> (or similar).  For information about configuring
+	on all nodes simultaneously.  For information about configuring
 	the recovery lock file please see the
 	<em class="citetitle">CTDB_RECOVERY_LOCK</em> entry in
 	<span class="citerefentry"><span class="refentrytitle">ctdbd.conf</span>(5)</span> and the
@@ -486,7 +472,7 @@ DB Statistics: locking.tdb
 	about the recovery lock please see the <em class="citetitle">RECOVERY
 	LOCK</em> section in
 	<span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span>.
-      </p></div><div class="refsect2"><a name="idp54793296"></a><h3>getdebug</h3><p>
+      </p></div><div class="refsect2"><a name="idp55154736"></a><h3>getdebug</h3><p>
 	Get the current debug level for the node. the debug level controls what information is written to the log file.
       </p><p>
 	The debug levels are mapped to the corresponding syslog levels.
@@ -496,42 +482,42 @@ DB Statistics: locking.tdb
 	The list of debug levels from highest to lowest are :
       </p><p>
 	ERR WARNING NOTICE INFO DEBUG
-      </p></div><div class="refsect2"><a name="idp54796016"></a><h3>setdebug <em class="parameter"><code>DEBUGLEVEL</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55157456"></a><h3>setdebug <em class="parameter"><code>DEBUGLEVEL</code></em></h3><p>
 	Set the debug level of a node. This controls what information will be logged.
       </p><p>
 	The debuglevel is one of ERR WARNING NOTICE INFO DEBUG
-      </p></div><div class="refsect2"><a name="idp54798224"></a><h3>getpid</h3><p>
+      </p></div><div class="refsect2"><a name="idp55159664"></a><h3>getpid</h3><p>
 	This command will return the process id of the ctdb daemon.
-      </p></div><div class="refsect2"><a name="idp54799456"></a><h3>disable</h3><p>
+      </p></div><div class="refsect2"><a name="idp55160896"></a><h3>disable</h3><p>
 	This command is used to administratively disable a node in the cluster.
 	A disabled node will still participate in the cluster and host
 	clustered TDB records but its public ip address has been taken over by
 	a different node and it no longer hosts any services.
-      </p></div><div class="refsect2"><a name="idp54800896"></a><h3>enable</h3><p>
+      </p></div><div class="refsect2"><a name="idp55162336"></a><h3>enable</h3><p>
 	Re-enable a node that has been administratively disabled.
-      </p></div><div class="refsect2"><a name="idp54802128"></a><h3>stop</h3><p>
+      </p></div><div class="refsect2"><a name="idp55163568"></a><h3>stop</h3><p>
 	This command is used to administratively STOP a node in the cluster.
 	A STOPPED node is connected to the cluster but will not host any
 	public ip addresse, nor does it participate in the VNNMAP.
 	The difference between a DISABLED node and a STOPPED node is that
 	a STOPPED node does not host any parts of the database which means
 	that a recovery is required to stop/continue nodes.
-      </p></div><div class="refsect2"><a name="idp54803680"></a><h3>continue</h3><p>
+      </p></div><div class="refsect2"><a name="idp55165120"></a><h3>continue</h3><p>
 	Re-start a node that has been administratively stopped.
-      </p></div><div class="refsect2"><a name="idp54804912"></a><h3>addip <em class="parameter"><code>IPADDR</code></em>/<em class="parameter"><code>mask</code></em> <em class="parameter"><code>IFACE</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55166352"></a><h3>addip <em class="parameter"><code>IPADDR</code></em>/<em class="parameter"><code>mask</code></em> <em class="parameter"><code>IFACE</code></em></h3><p>
 	This command is used to add a new public ip to a node during runtime.
 	This allows public addresses to be added to a cluster without having
 	to restart the ctdb daemons.
       </p><p>
 	Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read.
 	If you want this change to be permanent you must also update the public addresses file manually.
-      </p></div><div class="refsect2"><a name="idp54808656"></a><h3>delip <em class="parameter"><code>IPADDR</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55170096"></a><h3>delip <em class="parameter"><code>IPADDR</code></em></h3><p>
 	This command is used to remove a public ip from a node during runtime.
 	If this public ip is currently hosted by the node it being removed from, the ip will first be failed over to another node, if possible, before it is removed.
       </p><p>
 	Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read.
 	If you want this change to be permanent you must also update the public addresses file manually.
-      </p></div><div class="refsect2"><a name="idp54811216"></a><h3>moveip <em class="parameter"><code>IPADDR</code></em> <em class="parameter"><code>PNN</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55172656"></a><h3>moveip <em class="parameter"><code>IPADDR</code></em> <em class="parameter"><code>PNN</code></em></h3><p>
 	This command can be used to manually fail a public ip address to a
 	specific node.
       </p><p>
@@ -542,9 +528,9 @@ DB Statistics: locking.tdb
 	DeterministicIPs = 0
       </p><p>
 	NoIPFailback = 1
-      </p></div><div class="refsect2"><a name="idp54814976"></a><h3>shutdown</h3><p>
+      </p></div><div class="refsect2"><a name="idp55176416"></a><h3>shutdown</h3><p>
 	This command will shutdown a specific CTDB daemon.
-      </p></div><div class="refsect2"><a name="idp54816208"></a><h3>setlmasterrole on|off</h3><p>
+      </p></div><div class="refsect2"><a name="idp55177648"></a><h3>setlmasterrole on|off</h3><p>
 	This command is used ot enable/disable the LMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an LMASTER for records in the database. A node that does not have the LMASTER capability will not show up in the vnnmap.
       </p><p>
 	Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command.
@@ -552,54 +538,69 @@ DB Statistics: locking.tdb
 	Once this setting has been enabled/disabled, you need to perform a recovery for it to take effect.
       </p><p>
 	See also "ctdb getcapabilities"
-      </p></div><div class="refsect2"><a name="idp54819088"></a><h3>setrecmasterrole on|off</h3><p>
+      </p></div><div class="refsect2"><a name="idp55180528"></a><h3>setrecmasterrole on|off</h3><p>
 	This command is used ot enable/disable the RECMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an RECMASTER for the cluster. A node that does not have the RECMASTER capability can not win a recmaster election. A node that already is the recmaster for the cluster when the capability is stripped off the node will remain the recmaster until the next cluster election.
       </p><p>
 	Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command.
       </p><p>
 	See also "ctdb getcapabilities"
-      </p></div><div class="refsect2"><a name="idp54821616"></a><h3>reloadnodes</h3><p>
-	This command is used when adding new nodes, or removing existing nodes from an existing cluster.
-      </p><p>
-	Procedure to add a node:
-      </p><p>
-	1, To expand an existing cluster, first ensure with 'ctdb status' that
-	all nodes are up and running and that they are all healthy.
-	Do not try to expand a cluster unless it is completely healthy!
-      </p><p>
-	2, On all nodes, edit /etc/ctdb/nodes and add the new node as the last
-	entry to the file. The new node MUST be added to the end of this file!
-      </p><p>
-	3, Verify that all the nodes have identical /etc/ctdb/nodes files after you edited them and added the new node!
-      </p><p>
-	4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.
-      </p><p>
-	5, Use 'ctdb status' on all nodes and verify that they now show the additional node.
-      </p><p>
-	6, Install and configure the new node and bring it online.
-      </p><p>
-	Procedure to remove a node:
-      </p><p>
-	1, To remove a node from an existing cluster, first ensure with 'ctdb status' that
-	all nodes, except the node to be deleted, are up and running and that they are all healthy.
-	Do not try to remove a node from a cluster unless the cluster is completely healthy!
-      </p><p>
-	2, Shutdown and poweroff the node to be removed.
-      </p><p>
-	3, On all other nodes, edit the /etc/ctdb/nodes file and comment out the node to be removed. Do not delete the line for that node, just comment it out by adding a '#' at the beginning of the line.
-      </p><p>
-	4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.
-      </p><p>
-	5, Use 'ctdb status' on all nodes and verify that the deleted node no longer shows up in the list..
-      </p><p>
-      </p></div><div class="refsect2"><a name="idp54829904"></a><h3>
+      </p></div><div class="refsect2"><a name="idp55183056"></a><h3>reloadnodes</h3><p>
+	This command is used when adding new nodes, or removing
+	existing nodes from an existing cluster.
+      </p><p>
+	Procedure to add nodes:
+      </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
+	     To expand an existing cluster, first ensure with
+	     <span class="command"><strong>ctdb status</strong></span> that all nodes are up and
+	     running and that they are all healthy.  Do not try to
+	     expand a cluster unless it is completely healthy!
+	  </p></li><li class="listitem"><p>
+	    On all nodes, edit <code class="filename">/usr/local/etc/ctdb/nodes</code>
+	    and <span class="emphasis"><em>add the new nodes at the end of this
+	    file</em></span>.
+	  </p></li><li class="listitem"><p>
+	    Verify that all the nodes have identical
+	    <code class="filename">/usr/local/etc/ctdb/nodes</code> files after adding
+	    the new nodes.
+	  </p></li><li class="listitem"><p>
+	    Run <span class="command"><strong>ctdb reloadnodes</strong></span> to force all nodes
+	    to reload the nodes file.
+	  </p></li><li class="listitem"><p>
+	    Use <span class="command"><strong>ctdb status</strong></span> on all nodes and verify
+	    that they now show the additional nodes.
+	  </p></li><li class="listitem"><p>
+	    Install and configure the new node and bring it online.
+	  </p></li></ol></div><p>
+	Procedure to remove nodes:
+      </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
+	    To remove nodes from an existing cluster, first ensure
+	    with <span class="command"><strong>ctdb status</strong></span> that all nodes, except
+	    the node to be deleted, are up and running and that they
+	    are all healthy.  Do not try to remove nodes from a
+	    cluster unless the cluster is completely healthy!
+	  </p></li><li class="listitem"><p>
+	    Shutdown and power off the node to be removed.
+	  </p></li><li class="listitem"><p>
+	    On all other nodes, edit the
+	    <code class="filename">/usr/local/etc/ctdb/nodes</code> file and
+	    <span class="emphasis"><em>comment out</em></span> the nodes to be removed.
+	    <span class="emphasis"><em>Do not delete the lines for the deleted
+	    nodes</em></span>, just comment them out by adding a '#' at
+	    the beginning of the lines.
+	  </p></li><li class="listitem"><p>
+	    Run <span class="command"><strong>ctdb reloadnodes</strong></span> to force all nodes
+	    to reload the nodes file.
+	  </p></li><li class="listitem"><p>
+	    Use <span class="command"><strong>ctdb status</strong></span> on all nodes and verify
+	    that the deleted nodes are no longer listed.
+	  </p></li></ol></div></div><div class="refsect2"><a name="idp55203040"></a><h3>
 	reloadips
 	[<span class="optional"><em class="parameter"><code>PNN-LIST</code></em></span>]
       </h3><p>
 	This command reloads the public addresses configuration file
 	on the specified nodes.  When it completes addresses will be
 	reconfigured and reassigned across the cluster as necessary.
-      </p></div><div class="refsect2"><a name="idp54832016"></a><h3>getdbmap</h3><p>
+      </p></div><div class="refsect2"><a name="idp55205152"></a><h3>getdbmap</h3><p>
 	This command lists all clustered TDB databases that the CTDB daemon has attached to. Some databases are flagged as PERSISTENT, this means that the database stores data persistently and the data will remain across reboots. One example of such a database is secrets.tdb where information about how the cluster was joined to the domain is stored.
       </p><p>
 	If a PERSISTENT database is not in a healthy state the database is
@@ -613,28 +614,28 @@ DB Statistics: locking.tdb
 	and (if samba or tdb-utils are installed) "tdbtool check".
       </p><p>
 	Most databases are not persistent and only store the state information that the currently running samba daemons need. These databases are always wiped when ctdb/samba starts and when a node is rebooted.
-      </p><div class="refsect3"><a name="idp54835328"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55208464"></a><h4>Example</h4><pre class="screen">
 # ctdb getdbmap
 Number of databases:10
-dbid:0x435d3410 name:notify.tdb path:/var/ctdb/notify.tdb.0 
-dbid:0x42fe72c5 name:locking.tdb path:/var/ctdb/locking.tdb.0
-dbid:0x1421fb78 name:brlock.tdb path:/var/ctdb/brlock.tdb.0 
-dbid:0x17055d90 name:connections.tdb path:/var/ctdb/connections.tdb.0 
-dbid:0xc0bdde6a name:sessionid.tdb path:/var/ctdb/sessionid.tdb.0 
-dbid:0x122224da name:test.tdb path:/var/ctdb/test.tdb.0 
-dbid:0x2672a57f name:idmap2.tdb path:/var/ctdb/persistent/idmap2.tdb.0 PERSISTENT
-dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT
-dbid:0xe98e08b6 name:group_mapping.tdb path:/var/ctdb/persistent/group_mapping.tdb.0 PERSISTENT
-dbid:0x7bbbd26c name:passdb.tdb path:/var/ctdb/persistent/passdb.tdb.0 PERSISTENT
+dbid:0x435d3410 name:notify.tdb path:/usr/local/var/lib/ctdb/notify.tdb.0
+dbid:0x42fe72c5 name:locking.tdb path:/usr/local/var/lib/ctdb/locking.tdb.0
+dbid:0x1421fb78 name:brlock.tdb path:/usr/local/var/lib/ctdb/brlock.tdb.0
+dbid:0x17055d90 name:connections.tdb path:/usr/local/var/lib/ctdb/connections.tdb.0
+dbid:0xc0bdde6a name:sessionid.tdb path:/usr/local/var/lib/ctdb/sessionid.tdb.0
+dbid:0x122224da name:test.tdb path:/usr/local/var/lib/ctdb/test.tdb.0
+dbid:0x2672a57f name:idmap2.tdb path:/usr/local/var/lib/ctdb/persistent/idmap2.tdb.0 PERSISTENT
+dbid:0xb775fff6 name:secrets.tdb path:/usr/local/var/lib/ctdb/persistent/secrets.tdb.0 PERSISTENT
+dbid:0xe98e08b6 name:group_mapping.tdb path:/usr/local/var/lib/ctdb/persistent/group_mapping.tdb.0 PERSISTENT
+dbid:0x7bbbd26c name:passdb.tdb path:/usr/local/var/lib/ctdb/persistent/passdb.tdb.0 PERSISTENT
 
 # ctdb getdbmap  # example for unhealthy database
 Number of databases:1
-dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT UNHEALTHY
+dbid:0xb775fff6 name:secrets.tdb path:/usr/local/var/lib/ctdb/persistent/secrets.tdb.0 PERSISTENT UNHEALTHY
 
 # ctdb -X getdbmap
 |ID|Name|Path|Persistent|Unhealthy|
-|0x7bbbd26c|passdb.tdb|/var/ctdb/persistent/passdb.tdb.0|1|0|
-	</pre></div></div><div class="refsect2"><a name="idp54837920"></a><h3>
+|0x7bbbd26c|passdb.tdb|/usr/local/var/lib/ctdb/persistent/passdb.tdb.0|1|0|
+	</pre></div></div><div class="refsect2"><a name="idp55211216"></a><h3>
 	backupdb
 	<em class="parameter"><code>DB</code></em>
 	<em class="parameter"><code>FILE</code></em>
@@ -643,7 +644,7 @@ dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSIST
 	read back using <span class="command"><strong>restoredb</strong></span>.  This is mainly
 	useful for backing up persistent databases such as
 	<code class="filename">secrets.tdb</code> and similar.
-      </p></div><div class="refsect2"><a name="idp54841744"></a><h3>
+      </p></div><div class="refsect2"><a name="idp55215040"></a><h3>
 	restoredb
 	<em class="parameter"><code>FILE</code></em>
 	[<span class="optional"><em class="parameter"><code>DB</code></em></span>]
@@ -653,30 +654,30 @@ dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSIST
 	be restored back into the same database as it was created
 	from. By specifying dbname you can restore the data into a
 	different database.
-      </p></div><div class="refsect2"><a name="idp54844560"></a><h3>setdbreadonly <em class="parameter"><code>DB</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55217856"></a><h3>setdbreadonly <em class="parameter"><code>DB</code></em></h3><p>
 	This command will enable the read-only record support for a
 	database.  This is an experimental feature to improve
 	performance for contended records primarily in locking.tdb and
 	brlock.tdb.  When enabling this feature you must set it on all
 	nodes in the cluster.
-      </p></div><div class="refsect2"><a name="idp54846496"></a><h3>setdbsticky <em class="parameter"><code>DB</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55219792"></a><h3>setdbsticky <em class="parameter"><code>DB</code></em></h3><p>
 	This command will enable the sticky record support for the
 	specified database.  This is an experimental feature to
 	improve performance for contended records primarily in
 	locking.tdb and brlock.tdb.  When enabling this feature you
 	must set it on all nodes in the cluster.
-      </p></div></div><div class="refsect1"><a name="idp54848576"></a><h2>INTERNAL COMMANDS</h2><p>
+      </p></div></div><div class="refsect1"><a name="idp55221872"></a><h2>INTERNAL COMMANDS</h2><p>
       Internal commands are used by CTDB's scripts and are not
       required for managing a CTDB cluster.  Their parameters and
       behaviour are subject to change.
-    </p><div class="refsect2"><a name="idp54849792"></a><h3>gettickles <em class="parameter"><code>IPADDR</code></em></h3><p>
+    </p><div class="refsect2"><a name="idp55223088"></a><h3>gettickles <em class="parameter"><code>IPADDR</code></em></h3><p>
 	Show TCP connections that are registered with CTDB to be
 	"tickled" if there is a failover.
-      </p></div><div class="refsect2"><a name="idp54851552"></a><h3>gratiousarp <em class="parameter"><code>IPADDR</code></em> <em class="parameter"><code>INTERFACE</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55224848"></a><h3>gratiousarp <em class="parameter"><code>IPADDR</code></em> <em class="parameter"><code>INTERFACE</code></em></h3><p>
 	Send out a gratious ARP for the specified interface through
 	the specified interface. This command is mainly used by the
 	ctdb eventscripts.
-      </p></div><div class="refsect2"><a name="idp54853984"></a><h3>killtcp</h3><p>
+      </p></div><div class="refsect2"><a name="idp55227280"></a><h3>killtcp</h3><p>
 	Read a list of TCP connections, one per line, from standard
 	input and terminate each connection.  A connection is
 	specified as:
@@ -688,22 +689,22 @@ dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSIST
       </p><p>
 	A single connection can be specified on the command-line
 	rather than on standard input.
-      </p></div><div class="refsect2"><a name="idp54859408"></a><h3>
+      </p></div><div class="refsect2"><a name="idp55232704"></a><h3>
 	pdelete <em class="parameter"><code>DB</code></em> <em class="parameter"><code>KEY</code></em>
       </h3><p>
 	Delete KEY from DB.
-      </p></div><div class="refsect2"><a name="idp54861808"></a><h3>
+      </p></div><div class="refsect2"><a name="idp55235104"></a><h3>
 	pfetch <em class="parameter"><code>DB</code></em> <em class="parameter"><code>KEY</code></em>
       </h3><p>
 	Print the value associated with KEY in DB.
-      </p></div><div class="refsect2"><a name="idp54864208"></a><h3>
+      </p></div><div class="refsect2"><a name="idp55237504"></a><h3>
 	pstore
 	<em class="parameter"><code>DB</code></em>
 	<em class="parameter"><code>KEY</code></em>
 	<em class="parameter"><code>FILE</code></em>
       </h3><p>
 	Store KEY in DB with contents of FILE as the associated value.
-      </p></div><div class="refsect2"><a name="idp54867312"></a><h3>
+      </p></div><div class="refsect2"><a name="idp55240608"></a><h3>
 	ptrans
 	<em class="parameter"><code>DB</code></em>
 	[<span class="optional"><em class="parameter"><code>FILE</code></em></span>]
@@ -715,7 +716,7 @@ dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSIST
 	The key and value should be separated by spaces or tabs. Each
 	key/value should be a printable string enclosed in
 	double-quotes.
-      </p></div><div class="refsect2"><a name="idp54870576"></a><h3>runstate [setup|first_recovery|startup|running]</h3><p>
+      </p></div><div class="refsect2"><a name="idp55243872"></a><h3>runstate [setup|first_recovery|startup|running]</h3><p>
 	Print the runstate of the specified node.  Runstates are used
 	to serialise important state transitions in CTDB, particularly
 	during startup.
@@ -723,18 +724,16 @@ dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSIST
 	If one or more optional runstate arguments are specified then
 	the node must be in one of these runstates for the command to
 	succeed.
-      </p><div class="refsect3"><a name="idp54872304"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55245600"></a><h4>Example</h4><pre class="screen">
 # ctdb runstate
 RUNNING
-	</pre></div></div><div class="refsect2"><a name="idp54873824"></a><h3>setifacelink <em class="parameter"><code>IFACE</code></em> up|down</h3><p>
+	</pre></div></div><div class="refsect2"><a name="idp55247120"></a><h3>setifacelink <em class="parameter"><code>IFACE</code></em> up|down</h3><p>
 	Set the internal state of network interface IFACE.  This is
 	typically used in the <code class="filename">10.interface</code> script
 	in the "monitor" event.
       </p><p>
 	Example: ctdb setifacelink eth0 up
-      </p></div><div class="refsect2"><a name="idp54876704"></a><h3>setnatgwstate on|off</h3><p>
-	Enable or disable the NAT gateway master capability on a node.
-      </p></div><div class="refsect2"><a name="idp54877936"></a><h3>tickle <em class="parameter"><code>SRC-IPADDR</code></em>:<em class="parameter"><code>SRC-PORT</code></em> <em class="parameter"><code>DST-IPADDR</code></em>:<em class="parameter"><code>DST-PORT</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55250000"></a><h3>tickle <em class="parameter"><code>SRC-IPADDR</code></em>:<em class="parameter"><code>SRC-PORT</code></em> <em class="parameter"><code>DST-IPADDR</code></em>:<em class="parameter"><code>DST-PORT</code></em></h3><p>
 	Send a TCP tickle to the source host for the specified TCP
 	connection.  A TCP tickle is a TCP ACK packet with an invalid
 	sequence and acknowledge number and will when received by the
@@ -746,12 +745,12 @@ RUNNING
 	TCP connection has been disrupted and that the client will need
 	to reestablish. This greatly speeds up the time it takes for a client
 	to detect and reestablish after an IP failover in the ctdb cluster.
-      </p></div><div class="refsect2"><a name="idp54882496"></a><h3>version</h3><p>
+      </p></div><div class="refsect2"><a name="idp55254560"></a><h3>version</h3><p>
 	Display the CTDB version.
-      </p></div></div><div class="refsect1"><a name="idp54883776"></a><h2>DEBUGGING COMMANDS</h2><p>
+      </p></div></div><div class="refsect1"><a name="idp55255840"></a><h2>DEBUGGING COMMANDS</h2><p>
       These commands are primarily used for CTDB development and testing and
       should not be used for normal administration.
-    </p><div class="refsect2"><a name="idp54884944"></a><h3>OPTIONS</h3><div class="variablelist"><dl class="variablelist"><dt><span class="term">--print-emptyrecords</span></dt><dd><p>
+    </p><div class="refsect2"><a name="idp55257008"></a><h3>OPTIONS</h3><div class="variablelist"><dl class="variablelist"><dt><span class="term">--print-emptyrecords</span></dt><dd><p>
 	    This enables printing of empty records when dumping databases
 	    with the catdb, cattbd and dumpdbbackup commands. Records with
 	    empty data segment are considered deleted by ctdb and cleaned
@@ -769,50 +768,50 @@ RUNNING
 	    This lets catdb and dumpdbbackup print the
 	    record flags for each record. Note that cattdb always
 	    prints the flags.
-	  </p></dd></dl></div></div><div class="refsect2"><a name="idp54893968"></a><h3>process-exists <em class="parameter"><code>PID</code></em></h3><p>
+	  </p></dd></dl></div></div><div class="refsect2"><a name="idp55266032"></a><h3>process-exists <em class="parameter"><code>PID</code></em></h3><p>
 	This command checks if a specific process exists on the CTDB host. This is mainly used by Samba to check if remote instances of samba are still running or not.
-      </p></div><div class="refsect2"><a name="idp54895808"></a><h3>getdbstatus <em class="parameter"><code>DB</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55267872"></a><h3>getdbstatus <em class="parameter"><code>DB</code></em></h3><p>
 	This command displays more details about a database.
-      </p><div class="refsect3"><a name="idp54897408"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55269472"></a><h4>Example</h4><pre class="screen">
 # ctdb getdbstatus test.tdb.0
 dbid: 0x122224da
 name: test.tdb
-path: /var/ctdb/test.tdb.0
+path: /usr/local/var/lib/ctdb/test.tdb.0
 PERSISTENT: no
 HEALTH: OK
 
 # ctdb getdbstatus registry.tdb  # with a corrupted TDB
 dbid: 0xf2a58948
 name: registry.tdb
-path: /var/ctdb/persistent/registry.tdb.0
+path: /usr/local/var/lib/ctdb/persistent/registry.tdb.0
 PERSISTENT: yes
-HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/var/ctdb/persistent/registry.tdb.0.corrupted.20091208091949.0Z'
-	</pre></div></div><div class="refsect2"><a name="idp54899344"></a><h3>catdb <em class="parameter"><code>DB</code></em></h3><p>
+HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/usr/local/var/lib/ctdb/persistent/registry.tdb.0.corrupted.20091208091949.0Z'
+	</pre></div></div><div class="refsect2"><a name="idp55271440"></a><h3>catdb <em class="parameter"><code>DB</code></em></h3><p>
 	Print a dump of the clustered TDB database DB.
-      </p></div><div class="refsect2"><a name="idp54900992"></a><h3>cattdb <em class="parameter"><code>DB</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55273088"></a><h3>cattdb <em class="parameter"><code>DB</code></em></h3><p>
 	Print a dump of the contents of the local TDB database DB.
-      </p></div><div class="refsect2"><a name="idp54902720"></a><h3>dumpdbbackup <em class="parameter"><code>FILE</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55274816"></a><h3>dumpdbbackup <em class="parameter"><code>FILE</code></em></h3><p>
 	Print a dump of the contents from database backup FILE,
 	similar to <span class="command"><strong>catdb</strong></span>.
-      </p></div><div class="refsect2"><a name="idp54905072"></a><h3>wipedb <em class="parameter"><code>DB</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55277168"></a><h3>wipedb <em class="parameter"><code>DB</code></em></h3><p>
 	Remove all contents of database DB.
-      </p></div><div class="refsect2"><a name="idp54906720"></a><h3>recover</h3><p>
+      </p></div><div class="refsect2"><a name="idp55278816"></a><h3>recover</h3><p>
 	This command will trigger the recovery daemon to do a cluster
 	recovery.
-      </p></div><div class="refsect2"><a name="idp54907968"></a><h3>ipreallocate, sync</h3><p>
+      </p></div><div class="refsect2"><a name="idp55280064"></a><h3>ipreallocate, sync</h3><p>
 	This command will force the recovery master to perform a full ip reallocation process and redistribute all ip addresses. This is useful to "reset" the allocations back to its default state if they have been changed using the "moveip" command. While a "recover" will also perform this reallocation, a recovery is much more hevyweight since it will also rebuild all the databases.
-      </p></div><div class="refsect2"><a name="idp48922336"></a><h3>getmonmode</h3><p>
+      </p></div><div class="refsect2"><a name="idp55281616"></a><h3>getmonmode</h3><p>
 	This command returns the monutoring mode of a node. The monitoring mode is either ACTIVE or DISABLED. Normally a node will continuously monitor that all other nodes that are expected are in fact connected and that they respond to commands.
       </p><p>
 	ACTIVE - This is the normal mode. The node is actively monitoring all other nodes, both that the transport is connected and also that the node responds to commands. If a node becomes unavailable, it will be marked as DISCONNECTED and a recovery is initiated to restore the cluster.
       </p><p>
 	DISABLED - This node is not monitoring that other nodes are available. In this mode a node failure will not be detected and no recovery will be performed. This mode is useful when for debugging purposes one wants to attach GDB to a ctdb process but wants to prevent the rest of the cluster from marking this node as DISCONNECTED and do a recovery.
-      </p></div><div class="refsect2"><a name="idp48925200"></a><h3>setmonmode 0|1</h3><p>
+      </p></div><div class="refsect2"><a name="idp55284480"></a><h3>setmonmode 0|1</h3><p>
 	This command can be used to explicitly disable/enable monitoring mode on a node. The main purpose is if one wants to attach GDB to a running ctdb daemon but wants to prevent the other nodes from marking it as DISCONNECTED and issuing a recovery. To do this, set monitoring mode to 0 on all nodes before attaching with GDB. Remember to set monitoring mode back to 1 afterwards.
-      </p></div><div class="refsect2"><a name="idp48926784"></a><h3>attach <em class="parameter"><code>DBNAME</code></em> [persistent]</h3><p>
+      </p></div><div class="refsect2"><a name="idp55286032"></a><h3>attach <em class="parameter"><code>DBNAME</code></em> [persistent]</h3><p>
 	Create a new CTDB database called DBNAME and attach to it on
 	all nodes.
-      </p></div><div class="refsect2"><a name="idp48928784"></a><h3>detach <em class="parameter"><code>DB-LIST</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55287904"></a><h3>detach <em class="parameter"><code>DB-LIST</code></em></h3><p>
 	Detach specified non-persistent database(s) from the cluster. This
 	command will disconnect specified database(s) on all nodes in
 	the cluster.  This command should only be used when none of the
@@ -820,18 +819,18 @@ HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/var/ctdb/persist
       </p><p>
 	All nodes should be active and tunable AllowClientDBAccess should
 	be disabled on all nodes before detaching databases.
-      </p></div><div class="refsect2"><a name="idp48931312"></a><h3>dumpmemory</h3><p>
+      </p></div><div class="refsect2"><a name="idp55290336"></a><h3>dumpmemory</h3><p>
 	This is a debugging command. This command will make the ctdb
 	daemon to write a fill memory allocation map to standard output.
-      </p></div><div class="refsect2"><a name="idp48932640"></a><h3>rddumpmemory</h3><p>
+      </p></div><div class="refsect2"><a name="idp55291632"></a><h3>rddumpmemory</h3><p>
 	This is a debugging command. This command will dump the talloc memory
 	allocation tree for the recovery daemon to standard output.
-      </p></div><div class="refsect2"><a name="idp48933984"></a><h3>thaw</h3><p>
+      </p></div><div class="refsect2"><a name="idp55292944"></a><h3>thaw</h3><p>
 	Thaw a previously frozen node.
-      </p></div><div class="refsect2"><a name="idp48935216"></a><h3>eventscript <em class="parameter"><code>ARGUMENTS</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55294096"></a><h3>eventscript <em class="parameter"><code>ARGUMENTS</code></em></h3><p>
 	This is a debugging command. This command can be used to manually
 	invoke and run the eventscritps with arbitrary arguments.
-      </p></div><div class="refsect2"><a name="idp48937104"></a><h3>ban <em class="parameter"><code>BANTIME</code></em></h3><p>
+      </p></div><div class="refsect2"><a name="idp55295888"></a><h3>ban <em class="parameter"><code>BANTIME</code></em></h3><p>
 	Administratively ban a node for BANTIME seconds.  The node
 	will be unbanned after BANTIME seconds have elapsed.
       </p><p>
@@ -845,11 +844,11 @@ HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/var/ctdb/persist
       </p><p>
 	To administratively exclude a node from a cluster use the
 	<span class="command"><strong>stop</strong></span> command.
-      </p></div><div class="refsect2"><a name="idp54944192"></a><h3>unban</h3><p>
+      </p></div><div class="refsect2"><a name="idp55299872"></a><h3>unban</h3><p>
 	This command is used to unban a node that has either been
 	administratively banned using the ban command or has been
 	automatically banned.
-      </p></div><div class="refsect2"><a name="idp54945504"></a><h3>
+      </p></div><div class="refsect2"><a name="idp55301184"></a><h3>
 	rebalancenode
 	[<span class="optional"><em class="parameter"><code>PNN-LIST</code></em></span>]
       </h3><p>
@@ -857,17 +856,17 @@ HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/var/ctdb/persist
 	LCP2 IP allocation algorithm.  The
 	<span class="command"><strong>reloadips</strong></span> command will do this as necessary
 	so this command should not be needed.
-      </p></div><div class="refsect2"><a name="idp54948240"></a><h3>check_srvids <em class="parameter"><code>SRVID</code></em> ...</h3><p>
+      </p></div><div class="refsect2"><a name="idp55303920"></a><h3>check_srvids <em class="parameter"><code>SRVID</code></em> ...</h3><p>
 	This command checks whether a set of srvid message ports are
 	registered on the node or not. The command takes a list of
 	values to check.
-      </p><div class="refsect3"><a name="idp54950048"></a><h4>Example</h4><pre class="screen">
+      </p><div class="refsect3"><a name="idp55305728"></a><h4>Example</h4><pre class="screen">
 # ctdb check_srvids 1 2 3 14765
 Server id 0:1 does not exist
 Server id 0:2 does not exist
 Server id 0:3 does not exist
 Server id 0:14765 exists
-	</pre></div></div></div><div class="refsect1"><a name="idp54951984"></a><h2>SEE ALSO</h2><p>
+	</pre></div></div></div><div class="refsect1"><a name="idp55307664"></a><h2>SEE ALSO</h2><p>
       <span class="citerefentry"><span class="refentrytitle">ctdbd</span>(1)</span>,
 
       <span class="citerefentry"><span class="refentrytitle">onnode</span>(1)</span>,
diff --git a/ctdb/doc/ctdb.1.xml b/ctdb/doc/ctdb.1.xml
index e95caa0..57eac24 100644
--- a/ctdb/doc/ctdb.1.xml
+++ b/ctdb/doc/ctdb.1.xml
@@ -217,7 +217,7 @@
 	  Specify that FILENAME is the name of the Unix domain
 	  socket to use when connecting to the local CTDB
 	  daemon. The default is
-	  <filename>/tmp/ctdb.socket</filename>.
+	  <filename>/usr/local/var/run/ctdb/ctdbd.socket</filename>.
 	</para>
       </listitem>
       </varlistentry>
@@ -395,17 +395,6 @@ Recovery master:0
 	    If PNN-LIST is provided then status is given for
 	    the indicated node(s).
 	  </para>
-
-	  <para>
-	    By default, <command>ctdb nodestatus</command> gathers
-	    status from the local node.  However, if invoked with "-n
-	    all" (or similar) then status is gathered from the given
-	    node(s).  In particular <command>ctdb nodestatus
-	    all</command> and <command>ctdb nodestatus -n
-	    all</command> will produce different output.  It is
-	    possible to provide 2 different nodespecs (with and
-	    without "-n") but the output is usually confusing!
-	  </para>
 	</listitem>
       </itemizedlist>
 
@@ -510,11 +499,8 @@ pnn:3 192.168.2.203       OK
       <refsect3>
 	<title>Example</title>
 	<screen>
-# ctdb ping -n all
+# ctdb ping
 response from 0 time=0.000054 sec  (3 clients)
-response from 1 time=0.000144 sec  (2 clients)
-response from 2 time=0.000105 sec  (2 clients)
-response from 3 time=0.000114 sec  (2 clients)
 	</screen>
       </refsect3>
     </refsect2>
@@ -548,7 +534,7 @@ name:eth2 link:up references:1
     <refsect2>
       <title>ip</title>
       <para>
-	This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip. By default this command will ONLY show those public addresses that are known to the node itself. To see the full list of all public ips across the cluster you must use "ctdb ip -n all".
+	This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip. By default this command will ONLY show those public addresses that are known to the node itself. To see the full list of all public ips across the cluster you must use "ctdb ip all".
       </para>
       <refsect3>
 	<title>Example</title>
@@ -664,7 +650,7 @@ TakeoverTimeout         = 9
 MonitorInterval         = 15
 TickleUpdateInterval    = 20
 EventScriptTimeout      = 30
-EventScriptTimeoutCount = 1
+MonitorTimeoutCount     = 1
 RecoveryGracePeriod     = 120
 RecoveryBanPeriod       = 300
 DatabaseHashSize        = 100001
@@ -783,7 +769,6 @@ MaxRedirectCount    = 3
 RECMASTER: YES
 LMASTER: YES
 LVS: NO
-NATGW: YES
       </screen>
 
     </refsect2>
@@ -914,8 +899,7 @@ DB Statistics: locking.tdb
       <para>
 	This command only affects the run-time setting of a single
 	CTDB node.  This setting <emphasis>must</emphasis> be changed
-	on all nodes simultaneously by specifying <option>-n
-	all</option> (or similar).  For information about configuring
+	on all nodes simultaneously.  For information about configuring
 	the recovery lock file please see the
 	<citetitle>CTDB_RECOVERY_LOCK</citetitle> entry in
 	<citerefentry><refentrytitle>ctdbd.conf</refentrytitle>
@@ -1088,54 +1072,94 @@ DB Statistics: locking.tdb
     <refsect2>
       <title>reloadnodes</title>
       <para>
-	This command is used when adding new nodes, or removing existing nodes from an existing cluster.
-      </para>
-      <para>
-	Procedure to add a node:
-      </para>
-      <para>
-	1, To expand an existing cluster, first ensure with 'ctdb status' that
-	all nodes are up and running and that they are all healthy.
-	Do not try to expand a cluster unless it is completely healthy!
-      </para>
-      <para>
-	2, On all nodes, edit /etc/ctdb/nodes and add the new node as the last
-	entry to the file. The new node MUST be added to the end of this file!
-      </para>
-      <para>
-	3, Verify that all the nodes have identical /etc/ctdb/nodes files after you edited them and added the new node!
-      </para>
-      <para>
-	4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.
-      </para>
-      <para>
-	5, Use 'ctdb status' on all nodes and verify that they now show the additional node.
-      </para>
-      <para>
-	6, Install and configure the new node and bring it online.
-      </para>
-      <para>
-	Procedure to remove a node:
+	This command is used when adding new nodes, or removing
+	existing nodes from an existing cluster.
       </para>
       <para>
-	1, To remove a node from an existing cluster, first ensure with 'ctdb status' that
-	all nodes, except the node to be deleted, are up and running and that they are all healthy.
-	Do not try to remove a node from a cluster unless the cluster is completely healthy!
-      </para>
-      <para>
-	2, Shutdown and poweroff the node to be removed.
-      </para>
-      <para>
-	3, On all other nodes, edit the /etc/ctdb/nodes file and comment out the node to be removed. Do not delete the line for that node, just comment it out by adding a '#' at the beginning of the line.
-      </para>
-      <para>
-	4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.
-      </para>
-      <para>
-	5, Use 'ctdb status' on all nodes and verify that the deleted node no longer shows up in the list..
+	Procedure to add nodes:
       </para>
+      <orderedlist>
+	<listitem>
+	  <para>
+	     To expand an existing cluster, first ensure with
+	     <command>ctdb status</command> that all nodes are up and
+	     running and that they are all healthy.  Do not try to
+	     expand a cluster unless it is completely healthy!
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    On all nodes, edit <filename>/usr/local/etc/ctdb/nodes</filename>
+	    and <emphasis>add the new nodes at the end of this
+	    file</emphasis>.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    Verify that all the nodes have identical
+	    <filename>/usr/local/etc/ctdb/nodes</filename> files after adding
+	    the new nodes.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    Run <command>ctdb reloadnodes</command> to force all nodes
+	    to reload the nodes file.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    Use <command>ctdb status</command> on all nodes and verify
+	    that they now show the additional nodes.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    Install and configure the new node and bring it online.
+	  </para>
+	</listitem>
+      </orderedlist>
       <para>
+	Procedure to remove nodes:
       </para>
+      <orderedlist>
+	<listitem>
+	  <para>
+	    To remove nodes from an existing cluster, first ensure
+	    with <command>ctdb status</command> that all nodes, except
+	    the node to be deleted, are up and running and that they
+	    are all healthy.  Do not try to remove nodes from a
+	    cluster unless the cluster is completely healthy!
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    Shutdown and power off the node to be removed.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    On all other nodes, edit the
+	    <filename>/usr/local/etc/ctdb/nodes</filename> file and
+	    <emphasis>comment out</emphasis> the nodes to be removed.
+	    <emphasis>Do not delete the lines for the deleted
+	    nodes</emphasis>, just comment them out by adding a '#' at
+	    the beginning of the lines.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    Run <command>ctdb reloadnodes</command> to force all nodes
+	    to reload the nodes file.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    Use <command>ctdb status</command> on all nodes and verify
+	    that the deleted nodes are no longer listed.
+	  </para>
+	</listitem>
+      </orderedlist>
 
     </refsect2>
 
@@ -1177,24 +1201,24 @@ DB Statistics: locking.tdb
 	<screen>
 # ctdb getdbmap
 Number of databases:10
-dbid:0x435d3410 name:notify.tdb path:/var/ctdb/notify.tdb.0 
-dbid:0x42fe72c5 name:locking.tdb path:/var/ctdb/locking.tdb.0
-dbid:0x1421fb78 name:brlock.tdb path:/var/ctdb/brlock.tdb.0 
-dbid:0x17055d90 name:connections.tdb path:/var/ctdb/connections.tdb.0 
-dbid:0xc0bdde6a name:sessionid.tdb path:/var/ctdb/sessionid.tdb.0 
-dbid:0x122224da name:test.tdb path:/var/ctdb/test.tdb.0 
-dbid:0x2672a57f name:idmap2.tdb path:/var/ctdb/persistent/idmap2.tdb.0 PERSISTENT
-dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT
-dbid:0xe98e08b6 name:group_mapping.tdb path:/var/ctdb/persistent/group_mapping.tdb.0 PERSISTENT
-dbid:0x7bbbd26c name:passdb.tdb path:/var/ctdb/persistent/passdb.tdb.0 PERSISTENT
+dbid:0x435d3410 name:notify.tdb path:/usr/local/var/lib/ctdb/notify.tdb.0
+dbid:0x42fe72c5 name:locking.tdb path:/usr/local/var/lib/ctdb/locking.tdb.0
+dbid:0x1421fb78 name:brlock.tdb path:/usr/local/var/lib/ctdb/brlock.tdb.0
+dbid:0x17055d90 name:connections.tdb path:/usr/local/var/lib/ctdb/connections.tdb.0
+dbid:0xc0bdde6a name:sessionid.tdb path:/usr/local/var/lib/ctdb/sessionid.tdb.0
+dbid:0x122224da name:test.tdb path:/usr/local/var/lib/ctdb/test.tdb.0
+dbid:0x2672a57f name:idmap2.tdb path:/usr/local/var/lib/ctdb/persistent/idmap2.tdb.0 PERSISTENT
+dbid:0xb775fff6 name:secrets.tdb path:/usr/local/var/lib/ctdb/persistent/secrets.tdb.0 PERSISTENT
+dbid:0xe98e08b6 name:group_mapping.tdb path:/usr/local/var/lib/ctdb/persistent/group_mapping.tdb.0 PERSISTENT
+dbid:0x7bbbd26c name:passdb.tdb path:/usr/local/var/lib/ctdb/persistent/passdb.tdb.0 PERSISTENT
 
 # ctdb getdbmap  # example for unhealthy database
 Number of databases:1
-dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT UNHEALTHY
+dbid:0xb775fff6 name:secrets.tdb path:/usr/local/var/lib/ctdb/persistent/secrets.tdb.0 PERSISTENT UNHEALTHY
 
 # ctdb -X getdbmap
 |ID|Name|Path|Persistent|Unhealthy|
-|0x7bbbd26c|passdb.tdb|/var/ctdb/persistent/passdb.tdb.0|1|0|
+|0x7bbbd26c|passdb.tdb|/usr/local/var/lib/ctdb/persistent/passdb.tdb.0|1|0|
 	</screen>
       </refsect3>
     </refsect2>
@@ -1380,13 +1404,6 @@ RUNNING
     </refsect2>
 
     <refsect2>
-      <title>setnatgwstate on|off</title>
-      <para>
-	Enable or disable the NAT gateway master capability on a node.
-      </para>
-    </refsect2>
-
-    <refsect2>
       <title>tickle <parameter>SRC-IPADDR</parameter>:<parameter>SRC-PORT</parameter> <parameter>DST-IPADDR</parameter>:<parameter>DST-PORT</parameter></title>
       <para>
 	Send a TCP tickle to the source host for the specified TCP
@@ -1494,16 +1511,16 @@ RUNNING
 # ctdb getdbstatus test.tdb.0
 dbid: 0x122224da
 name: test.tdb
-path: /var/ctdb/test.tdb.0
+path: /usr/local/var/lib/ctdb/test.tdb.0
 PERSISTENT: no
 HEALTH: OK
 
 # ctdb getdbstatus registry.tdb  # with a corrupted TDB
 dbid: 0xf2a58948
 name: registry.tdb
-path: /var/ctdb/persistent/registry.tdb.0
+path: /usr/local/var/lib/ctdb/persistent/registry.tdb.0
 PERSISTENT: yes
-HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/var/ctdb/persistent/registry.tdb.0.corrupted.20091208091949.0Z'
+HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/usr/local/var/lib/ctdb/persistent/registry.tdb.0.corrupted.20091208091949.0Z'
 	</screen>
       </refsect3>
     </refsect2>
diff --git a/ctdb/doc/ctdb.7 b/ctdb/doc/ctdb.7
index 5a5211f..2710c90 100644
--- a/ctdb/doc/ctdb.7
+++ b/ctdb/doc/ctdb.7
@@ -2,12 +2,12 @@
 .\"     Title: ctdb
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB" "7" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB" "7" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -129,14 +129,14 @@ Private addresses are listed in the file specified by the
 \fICTDB_NODES\fR
 configuration variable (see
 \fBctdbd.conf\fR(5), default
-/etc/ctdb/nodes)\&. This file contains the list of private addresses for all nodes in the cluster, one per line\&. This file must be the same on all nodes in the cluster\&.
+/usr/local/etc/ctdb/nodes)\&. This file contains the list of private addresses for all nodes in the cluster, one per line\&. This file must be the same on all nodes in the cluster\&.
 .PP
 Private addresses should not be used by clients to connect to services provided by the cluster\&.
 .PP
 It is strongly recommended that the private addresses are configured on a private network that is separate from client networks\&.
 .PP
 Example
-/etc/ctdb/nodes
+/usr/local/etc/ctdb/nodes
 for a four node cluster:
 .sp
 .if n \{\
@@ -162,10 +162,10 @@ The public address configuration is stored in a file on each node specified by t
 \fICTDB_PUBLIC_ADDRESSES\fR
 configuration variable (see
 \fBctdbd.conf\fR(5), recommended
-/etc/ctdb/public_addresses)\&. This file contains a list of the public addresses that the node is capable of hosting, one per line\&. Each entry also contains the netmask and the interface to which the address should be assigned\&.
+/usr/local/etc/ctdb/public_addresses)\&. This file contains a list of the public addresses that the node is capable of hosting, one per line\&. Each entry also contains the netmask and the interface to which the address should be assigned\&.
 .PP
 Example
-/etc/ctdb/public_addresses
+/usr/local/etc/ctdb/public_addresses
 for a node that can host 4 public addresses, on 2 different interfaces:
 .sp
 .if n \{\
@@ -190,19 +190,19 @@ Example: 4 nodes partitioned into two subgroups:
 .RS 4
 .\}
 .nf
-Node 0:/etc/ctdb/public_addresses
+Node 0:/usr/local/etc/ctdb/public_addresses
 	10\&.1\&.1\&.1/24 eth1
 	10\&.1\&.1\&.2/24 eth1
 
-Node 1:/etc/ctdb/public_addresses
+Node 1:/usr/local/etc/ctdb/public_addresses
 	10\&.1\&.1\&.1/24 eth1
 	10\&.1\&.1\&.2/24 eth1
 
-Node 2:/etc/ctdb/public_addresses
+Node 2:/usr/local/etc/ctdb/public_addresses
 	10\&.1\&.2\&.1/24 eth2
 	10\&.1\&.2\&.2/24 eth2
 
-Node 3:/etc/ctdb/public_addresses
+Node 3:/usr/local/etc/ctdb/public_addresses
 	10\&.1\&.2\&.1/24 eth2
 	10\&.1\&.2\&.2/24 eth2
       
@@ -298,13 +298,6 @@ LVS
 section for more details\&.
 .RE
 .PP
-NATGW
-.RS 4
-Indicates that this node is configured to become the NAT gateway master in a NAT gateway group\&. See the
-NAT GATEWAY
-section for more details\&.
-.RE
-.PP
 The RECMASTER and LMASTER capabilities can be disabled when CTDB is used to create a cluster spanning across WAN links\&. In this case CTDB acts as a WAN accelerator\&.
 .SH "LVS"
 .PP
@@ -397,6 +390,11 @@ CTDB_LVS_PUBLIC_IP=10\&.1\&.1\&.237
 .RE
 .\}
 .sp
+.SH "TRACKING AND RESETTING TCP CONNECTIONS"
+.PP
+CTDB tracks TCP connections from clients to public IP addresses, on known ports\&. When an IP address moves from one node to another, all existing TCP connections to that IP address are reset\&. The node taking over this IP address will also send gratuitous ARPs (for IPv4, or neighbour advertisement, for IPv6)\&. This allows clients to reconnect quickly, rather than waiting for TCP timeouts, which can be very long\&.
+.PP
+It is important that established TCP connections do not survive a release and take of a public IP address on the same node\&. Such connections can get out of sync with sequence and ACK numbers, potentially causing a disruptive ACK storm\&.
 .SH "NAT GATEWAY"
 .PP
 NAT gateway (NATGW) is an optional feature that is used to configure fallback routing for nodes\&. This allows cluster nodes to connect to external services (e\&.g\&. DNS, AD, NIS and LDAP) when they do not host any public addresses (e\&.g\&. when they are unhealthy)\&.
@@ -419,7 +417,7 @@ NATGW is usually configured similar to the following example configuration:
 .RS 4
 .\}
 .nf
-CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+CTDB_NATGW_NODES=/usr/local/etc/ctdb/natgw_nodes
 CTDB_NATGW_PRIVATE_NETWORK=192\&.168\&.1\&.0/24
 CTDB_NATGW_PUBLIC_IP=10\&.0\&.0\&.227/24
 CTDB_NATGW_PUBLIC_IFACE=eth0
@@ -430,14 +428,14 @@ CTDB_NATGW_DEFAULT_GATEWAY=10\&.0\&.0\&.1
 .RE
 .\}
 .PP
-Normally any node in a NATGW group can act as the NATGW master\&. Some configurations may have special nodes that lack connectivity to a public network\&. In such cases,
-\fICTDB_NATGW_SLAVE_ONLY\fR
-can be used to limit the NATGW functionality of thos nodes\&.
+Normally any node in a NATGW group can act as the NATGW master\&. Some configurations may have special nodes that lack connectivity to a public network\&. In such cases, those nodes can be flagged with the "slave\-only" option in the
+\fICTDB_NATGW_NODES\fR
+file to limit the NATGW functionality of those nodes\&.
 .PP
 See the
 NAT GATEWAY
 section in
-\fBctdb.conf\fR(5)
+\fBctdbd.conf\fR(5)
 for more details of NATGW configuration\&.
 .SS "Implementation details"
 .PP
@@ -625,12 +623,12 @@ Here is a more complete example configuration\&.
 .RS 4
 .\}
 .nf
-/etc/ctdb/public_addresses:
+/usr/local/etc/ctdb/public_addresses:
 
   192\&.168\&.1\&.98	eth2,eth3
   192\&.168\&.1\&.99	eth2,eth3
 
-/etc/ctdb/policy_routing:
+/usr/local/etc/ctdb/policy_routing:
 
   192\&.168\&.1\&.98 192\&.168\&.1\&.0/24
   192\&.168\&.1\&.98 192\&.168\&.200\&.0/24	192\&.168\&.1\&.254
@@ -654,9 +652,9 @@ This is activated by setting the
 configuration variable\&. The specified script must be executable\&.
 .PP
 Use of the provided
-/etc/ctdb/notify\&.sh
+/usr/local/etc/ctdb/notify\&.sh
 script is recommended\&. It executes files in
-/etc/ctdb/notify\&.d/\&.
+/usr/local/etc/ctdb/notify\&.d/\&.
 .PP
 CTDB currently generates notifications after CTDB changes to these states:
 .RS 4
diff --git a/ctdb/doc/ctdb.7.html b/ctdb/doc/ctdb.7.html
index a318425..a172c78 100644
--- a/ctdb/doc/ctdb.7.html
+++ b/ctdb/doc/ctdb.7.html
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb — Clustered TDB</p></div><div class="refsect1"><a name="idp51979744"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb — Clustered TDB</p></div><div class="refsect1"><a name="idp53709056"></a><h2>DESCRIPTION</h2><p>
     CTDB is a clustered database component in clustered Samba that
     provides a high-availability load-sharing CIFS server cluster.
   </p><p>
@@ -16,7 +16,7 @@
     Combined with a cluster filesystem CTDB provides a full
     high-availablity (HA) environment for services such as clustered
     Samba, NFS and other services.
-  </p></div><div class="refsect1"><a name="idp52619776"></a><h2>ANATOMY OF A CTDB CLUSTER</h2><p>
+  </p></div><div class="refsect1"><a name="idp52048160"></a><h2>ANATOMY OF A CTDB CLUSTER</h2><p>
     A CTDB cluster is a collection of nodes with 2 or more network
     interfaces.  All nodes provide network (usually file/NAS) services
     to clients.  Data served by file services is stored on shared
@@ -25,7 +25,7 @@
   </p><p>
     CTDB provides an "all active" cluster, where services are load
     balanced across all nodes.
-  </p></div><div class="refsect1"><a name="idp52982864"></a><h2>Recovery Lock</h2><p>
+  </p></div><div class="refsect1"><a name="idp50534928"></a><h2>Recovery Lock</h2><p>
       CTDB uses a <span class="emphasis"><em>recovery lock</em></span> to avoid a
       <span class="emphasis"><em>split brain</em></span>, where a cluster becomes
       partitioned and each partition attempts to operate
@@ -62,7 +62,7 @@
     </p><p>
       CTDB can run without a recovery lock but this is not recommended
       as there will be no protection from split brains.
-    </p></div><div class="refsect1"><a name="idp49232144"></a><h2>Private vs Public addresses</h2><p>
+    </p></div><div class="refsect1"><a name="idp53056000"></a><h2>Private vs Public addresses</h2><p>
       Each node in a CTDB cluster has multiple IP addresses assigned
       to it:
 
@@ -73,7 +73,7 @@
 	    One or more public IP addresses that are used to provide
 	    NAS or other services.
 	  </p></li></ul></div><p>
-    </p><div class="refsect2"><a name="idp53885408"></a><h3>Private address</h3><p>
+    </p><div class="refsect2"><a name="idp49235808"></a><h3>Private address</h3><p>
         Each node is configured with a unique, permanently assigned
         private address.  This address is configured by the operating
         system.  This address uniquely identifies a physical node in
@@ -83,7 +83,7 @@
         Private addresses are listed in the file specified by the
         <code class="varname">CTDB_NODES</code> configuration variable (see
         <span class="citerefentry"><span class="refentrytitle">ctdbd.conf</span>(5)</span>, default
-        <code class="filename">/etc/ctdb/nodes</code>).  This file contains the
+        <code class="filename">/usr/local/etc/ctdb/nodes</code>).  This file contains the
         list of private addresses for all nodes in the cluster, one
         per line. This file must be the same on all nodes in the
         cluster.
@@ -95,14 +95,14 @@
         configured on a private network that is separate from client
         networks.
       </p><p>
-	Example <code class="filename">/etc/ctdb/nodes</code> for a four node
+	Example <code class="filename">/usr/local/etc/ctdb/nodes</code> for a four node
 	cluster:
       </p><pre class="screen">
 192.168.1.1
 192.168.1.2
 192.168.1.3
 192.168.1.4
-      </pre></div><div class="refsect2"><a name="idp53892560"></a><h3>Public addresses</h3><p>
+      </pre></div><div class="refsect2"><a name="idp50980688"></a><h3>Public addresses</h3><p>
 	Public addresses are used to provide services to clients.
 	Public addresses are not configured at the operating system
 	level and are not permanently associated with a particular
@@ -121,13 +121,13 @@
 	node specified by the <code class="varname">CTDB_PUBLIC_ADDRESSES</code>
 	configuration variable (see
 	<span class="citerefentry"><span class="refentrytitle">ctdbd.conf</span>(5)</span>, recommended
-	<code class="filename">/etc/ctdb/public_addresses</code>).  This file
+	<code class="filename">/usr/local/etc/ctdb/public_addresses</code>).  This file
 	contains a list of the public addresses that the node is
 	capable of hosting, one per line.  Each entry also contains
 	the netmask and the interface to which the address should be
 	assigned.
       </p><p>
-	Example <code class="filename">/etc/ctdb/public_addresses</code> for a
+	Example <code class="filename">/usr/local/etc/ctdb/public_addresses</code> for a
 	node that can host 4 public addresses, on 2 different
 	interfaces:
       </p><pre class="screen">
@@ -142,19 +142,19 @@
       </p><p>
 	Example: 4 nodes partitioned into two subgroups:
       </p><pre class="screen">
-Node 0:/etc/ctdb/public_addresses
+Node 0:/usr/local/etc/ctdb/public_addresses
 	10.1.1.1/24 eth1
 	10.1.1.2/24 eth1
 
-Node 1:/etc/ctdb/public_addresses
+Node 1:/usr/local/etc/ctdb/public_addresses
 	10.1.1.1/24 eth1
 	10.1.1.2/24 eth1
 
-Node 2:/etc/ctdb/public_addresses
+Node 2:/usr/local/etc/ctdb/public_addresses
 	10.1.2.1/24 eth2
 	10.1.2.2/24 eth2
 
-Node 3:/etc/ctdb/public_addresses
+Node 3:/usr/local/etc/ctdb/public_addresses
 	10.1.2.1/24 eth2
 	10.1.2.2/24 eth2
       </pre><p>
@@ -173,7 +173,7 @@ Node 3:/etc/ctdb/public_addresses
       </p><p>
         The <span class="command"><strong>ctdb ip</strong></span> command can be used to view the
         current assignment of public addresses to physical nodes.
-      </p></div></div><div class="refsect1"><a name="idp49114720"></a><h2>Node status</h2><p>
+      </p></div></div><div class="refsect1"><a name="idp49115104"></a><h2>Node status</h2><p>
       The current status of each node in the cluster can be viewed by the 
       <span class="command"><strong>ctdb status</strong></span> command.
     </p><p>
@@ -218,7 +218,7 @@ Node 3:/etc/ctdb/public_addresses
 	    like a healthy (OK) node.  Some interfaces to serve public
 	    addresses are down, but at least one interface is up.  See
 	    also <span class="command"><strong>ctdb ifaces</strong></span>.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp49137968"></a><h2>CAPABILITIES</h2><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp49138160"></a><h2>CAPABILITIES</h2><p>
       Cluster nodes can have several different capabilities enabled.
       These are listed below.
     </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">RECMASTER</span></dt><dd><p>
@@ -241,16 +241,11 @@ Node 3:/etc/ctdb/public_addresses
 	    an alternative to using a load-balancing layer-4 switch.
 	    See the <em class="citetitle">LVS</em> section for more
 	    details.
-	  </p></dd><dt><span class="term">NATGW</span></dt><dd><p>
-	    Indicates that this node is configured to become the NAT
-	    gateway master in a NAT gateway group.  See the
-	    <em class="citetitle">NAT GATEWAY</em> section for more
-	    details.
 	  </p></dd></dl></div><p>
       The RECMASTER and LMASTER capabilities can be disabled when CTDB
       is used to create a cluster spanning across WAN links. In this
       case CTDB acts as a WAN accelerator.
-    </p></div><div class="refsect1"><a name="idp49149168"></a><h2>LVS</h2><p>
+    </p></div><div class="refsect1"><a name="idp49147232"></a><h2>LVS</h2><p>
       LVS is a mode where CTDB presents one single IP address for the
       entire cluster. This is an alternative to using public IP
       addresses and round-robin DNS to loadbalance clients across the
@@ -316,7 +311,7 @@ Node 3:/etc/ctdb/public_addresses
       reachable from a node <span class="emphasis"><em>before</em></span> you enable
       LVS.  Also ensure that outgoing traffic to these hosts is routed
       out through the configured public interface.
-    </p><div class="refsect2"><a name="idp55025520"></a><h3>Configuration</h3><p>
+    </p><div class="refsect2"><a name="idp55075776"></a><h3>Configuration</h3><p>
 	To activate LVS on a CTDB node you must specify the
 	<code class="varname">CTDB_PUBLIC_INTERFACE</code> and
 	<code class="varname">CTDB_LVS_PUBLIC_IP</code> configuration variables.
@@ -328,7 +323,20 @@ Node 3:/etc/ctdb/public_addresses
 CTDB_PUBLIC_INTERFACE=eth1
 CTDB_LVS_PUBLIC_IP=10.1.1.237
 	</pre><p>
-      </p></div></div><div class="refsect1"><a name="idp55028704"></a><h2>NAT GATEWAY</h2><p>
+      </p></div></div><div class="refsect1"><a name="idp55078960"></a><h2>TRACKING AND RESETTING TCP CONNECTIONS</h2><p>
+      CTDB tracks TCP connections from clients to public IP addresses,
+      on known ports.  When an IP address moves from one node to
+      another, all existing TCP connections to that IP address are
+      reset.  The node taking over this IP address will also send
+      gratuitous ARPs (for IPv4, or neighbour advertisement, for
+      IPv6).  This allows clients to reconnect quickly, rather than
+      waiting for TCP timeouts, which can be very long.
+    </p><p>
+      It is important that established TCP connections do not survive
+      a release and take of a public IP address on the same node.
+      Such connections can get out of sync with sequence and ACK
+      numbers, potentially causing a disruptive ACK storm.
+    </p></div><div class="refsect1"><a name="idp55081264"></a><h2>NAT GATEWAY</h2><p>
       NAT gateway (NATGW) is an optional feature that is used to
       configure fallback routing for nodes.  This allows cluster nodes
       to connect to external services (e.g. DNS, AD, NIS and LDAP)
@@ -345,7 +353,7 @@ CTDB_LVS_PUBLIC_IP=10.1.1.237
       extra static IP address to a public interface on every node.
       This is simpler but it uses an extra IP address per node, while
       NAT gateway generally uses only one extra IP address.
-    </p><div class="refsect2"><a name="idp55031392"></a><h3>Operation</h3><p>
+    </p><div class="refsect2"><a name="idp55083952"></a><h3>Operation</h3><p>
 	One extra NATGW public address is assigned on the public
 	network to each NATGW group.  Each NATGW group is a set of
 	nodes in the cluster that shares the same NATGW address to
@@ -366,10 +374,10 @@ CTDB_LVS_PUBLIC_IP=10.1.1.237
 	public IP address and routes outgoing connections from
 	slave nodes via this IP address.  It also establishes a
 	fallback default route.
-      </p></div><div class="refsect2"><a name="idp55034928"></a><h3>Configuration</h3><p>
+      </p></div><div class="refsect2"><a name="idp55086960"></a><h3>Configuration</h3><p>
 	NATGW is usually configured similar to the following example configuration:
       </p><pre class="screen">
-CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+CTDB_NATGW_NODES=/usr/local/etc/ctdb/natgw_nodes
 CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24
 CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
 CTDB_NATGW_PUBLIC_IFACE=eth0
@@ -377,14 +385,15 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
       </pre><p>
 	Normally any node in a NATGW group can act as the NATGW
 	master.  Some configurations may have special nodes that lack
-	connectivity to a public network.  In such cases,
-	<code class="varname">CTDB_NATGW_SLAVE_ONLY</code> can be used to limit the
-	NATGW functionality of thos nodes.
+	connectivity to a public network.  In such cases, those nodes
+	can be flagged with the "slave-only" option in the
+	<code class="varname">CTDB_NATGW_NODES</code> file to limit the NATGW
+	functionality of those nodes.
       </p><p>
 	See the <em class="citetitle">NAT GATEWAY</em> section in
-	<span class="citerefentry"><span class="refentrytitle">ctdb.conf</span>(5)</span> for more details of
+	<span class="citerefentry"><span class="refentrytitle">ctdbd.conf</span>(5)</span> for more details of
 	NATGW configuration.
-      </p></div><div class="refsect2"><a name="idp55039632"></a><h3>Implementation details</h3><p>
+      </p></div><div class="refsect2"><a name="idp55091728"></a><h3>Implementation details</h3><p>
 	When the NATGW functionality is used, one of the nodes is
 	selected to act as a NAT gateway for all the other nodes in
 	the group when they need to communicate with the external
@@ -419,7 +428,7 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
 	eventscript.  Please see the eventscript file and the
 	<em class="citetitle">NAT GATEWAY</em> section in
 	<span class="citerefentry"><span class="refentrytitle">ctdbd.conf</span>(5)</span> for more details.
-      </p></div></div><div class="refsect1"><a name="idp55047456"></a><h2>POLICY ROUTING</h2><p>
+      </p></div></div><div class="refsect1"><a name="idp55099552"></a><h2>POLICY ROUTING</h2><p>
       Policy routing is an optional CTDB feature to support complex
       network topologies.  Public addresses may be spread across
       several different networks (or VLANs) and it may not be possible
@@ -429,7 +438,7 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
       This allows routing to be specified for packets sourced from
       each public address.  The routes are added and removed as CTDB
       moves public addresses between nodes.
-    </p><div class="refsect2"><a name="idp55049680"></a><h3>Configuration variables</h3><p>
+    </p><div class="refsect2"><a name="idp55101776"></a><h3>Configuration variables</h3><p>
 	There are 4 configuration variables related to policy routing:
 	<code class="varname">CTDB_PER_IP_ROUTING_CONF</code>,
 	<code class="varname">CTDB_PER_IP_ROUTING_RULE_PREF</code>,
@@ -437,7 +446,7 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
 	<code class="varname">CTDB_PER_IP_ROUTING_TABLE_ID_HIGH</code>.  See the
 	<em class="citetitle">POLICY ROUTING</em> section in
 	<span class="citerefentry"><span class="refentrytitle">ctdbd.conf</span>(5)</span> for more details.
-      </p></div><div class="refsect2"><a name="idp55053648"></a><h3>Configuration</h3><p>
+      </p></div><div class="refsect2"><a name="idp55105744"></a><h3>Configuration</h3><p>
 	The format of each line of
 	<code class="varname">CTDB_PER_IP_ROUTING_CONF</code> is:
       </p><pre class="screen">
@@ -499,15 +508,15 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
       </p><pre class="screen">
   192.168.1.0/24 dev eth2 scope link 
   default via 192.168.1.1 dev eth2 
-      </pre></div><div class="refsect2"><a name="idp55068864"></a><h3>Sample configuration</h3><p>
+      </pre></div><div class="refsect2"><a name="idp55120960"></a><h3>Sample configuration</h3><p>
 	Here is a more complete example configuration.
       </p><pre class="screen">
-/etc/ctdb/public_addresses:
+/usr/local/etc/ctdb/public_addresses:
 
   192.168.1.98	eth2,eth3
   192.168.1.99	eth2,eth3
 
-/etc/ctdb/policy_routing:
+/usr/local/etc/ctdb/policy_routing:
 
   192.168.1.98 192.168.1.0/24
   192.168.1.98 192.168.200.0/24	192.168.1.254
@@ -519,7 +528,7 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
 	The routes local packets as expected, the default route is as
 	previously discussed, but packets to 192.168.200.0/24 are
 	routed via the alternate gateway 192.168.1.254.
-      </p></div></div><div class="refsect1"><a name="idp55071696"></a><h2>NOTIFICATION SCRIPT</h2><p>
+      </p></div></div><div class="refsect1"><a name="idp55124176"></a><h2>NOTIFICATION SCRIPT</h2><p>
       When certain state changes occur in CTDB, it can be configured
       to perform arbitrary actions via a notification script.  For
       example, sending SNMP traps or emails when a node becomes
@@ -529,15 +538,15 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
       <code class="varname">CTDB_NOTIFY_SCRIPT</code> configuration variable.
       The specified script must be executable.  
     </p><p>
-      Use of the provided <code class="filename">/etc/ctdb/notify.sh</code>
+      Use of the provided <code class="filename">/usr/local/etc/ctdb/notify.sh</code>
       script is recommended.  It executes files in
-      <code class="filename">/etc/ctdb/notify.d/</code>.
+      <code class="filename">/usr/local/etc/ctdb/notify.d/</code>.
     </p><p>
       CTDB currently generates notifications after CTDB changes to
       these states:
-    </p><table border="0" summary="Simple list" class="simplelist"><tr><td>init</td></tr><tr><td>setup</td></tr><tr><td>startup</td></tr><tr><td>healthy</td></tr><tr><td>unhealthy</td></tr></table></div><div class="refsect1"><a name="idp55078640"></a><h2>DEBUG LEVELS</h2><p>
+    </p><table border="0" summary="Simple list" class="simplelist"><tr><td>init</td></tr><tr><td>setup</td></tr><tr><td>startup</td></tr><tr><td>healthy</td></tr><tr><td>unhealthy</td></tr></table></div><div class="refsect1"><a name="idp55131120"></a><h2>DEBUG LEVELS</h2><p>
       Valid values for DEBUGLEVEL are:
-    </p><table border="0" summary="Simple list" class="simplelist"><tr><td>ERR (0)</td></tr><tr><td>WARNING (1)</td></tr><tr><td>NOTICE (2)</td></tr><tr><td>INFO (3)</td></tr><tr><td>DEBUG (4)</td></tr></table></div><div class="refsect1"><a name="idp55082336"></a><h2>REMOTE CLUSTER NODES</h2><p>
+    </p><table border="0" summary="Simple list" class="simplelist"><tr><td>ERR (0)</td></tr><tr><td>WARNING (1)</td></tr><tr><td>NOTICE (2)</td></tr><tr><td>INFO (3)</td></tr><tr><td>DEBUG (4)</td></tr></table></div><div class="refsect1"><a name="idp55134816"></a><h2>REMOTE CLUSTER NODES</h2><p>
 It is possible to have a CTDB cluster that spans across a WAN link. 
 For example where you have a CTDB cluster in your datacentre but you also
 want to have one additional CTDB node located at a remote branch site.
@@ -566,7 +575,7 @@ CTDB_CAPABILITY_RECMASTER=no
     </p><p>
 	Verify with the command "ctdb getcapabilities" that that node no longer
 	has the recmaster or the lmaster capabilities.
-    </p></div><div class="refsect1"><a name="idp55087120"></a><h2>SEE ALSO</h2><p>
+    </p></div><div class="refsect1"><a name="idp55139520"></a><h2>SEE ALSO</h2><p>
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span>,
 
       <span class="citerefentry"><span class="refentrytitle">ctdbd</span>(1)</span>,
diff --git a/ctdb/doc/ctdb.7.xml b/ctdb/doc/ctdb.7.xml
index ad17df7..6fab41c 100644
--- a/ctdb/doc/ctdb.7.xml
+++ b/ctdb/doc/ctdb.7.xml
@@ -167,7 +167,7 @@
         <varname>CTDB_NODES</varname> configuration variable (see
         <citerefentry><refentrytitle>ctdbd.conf</refentrytitle>
         <manvolnum>5</manvolnum></citerefentry>, default
-        <filename>/etc/ctdb/nodes</filename>).  This file contains the
+        <filename>/usr/local/etc/ctdb/nodes</filename>).  This file contains the
         list of private addresses for all nodes in the cluster, one
         per line. This file must be the same on all nodes in the
         cluster.
@@ -183,7 +183,7 @@
       </para>
 
       <para>
-	Example <filename>/etc/ctdb/nodes</filename> for a four node
+	Example <filename>/usr/local/etc/ctdb/nodes</filename> for a four node
 	cluster:
       </para>
       <screen format="linespecific">
@@ -219,7 +219,7 @@
 	configuration variable (see
 	<citerefentry><refentrytitle>ctdbd.conf</refentrytitle>
 	<manvolnum>5</manvolnum></citerefentry>, recommended
-	<filename>/etc/ctdb/public_addresses</filename>).  This file
+	<filename>/usr/local/etc/ctdb/public_addresses</filename>).  This file
 	contains a list of the public addresses that the node is
 	capable of hosting, one per line.  Each entry also contains
 	the netmask and the interface to which the address should be
@@ -227,7 +227,7 @@
       </para>
 
       <para>
-	Example <filename>/etc/ctdb/public_addresses</filename> for a
+	Example <filename>/usr/local/etc/ctdb/public_addresses</filename> for a
 	node that can host 4 public addresses, on 2 different
 	interfaces:
       </para>
@@ -248,19 +248,19 @@
 	Example: 4 nodes partitioned into two subgroups:
       </para>
       <screen format="linespecific">
-Node 0:/etc/ctdb/public_addresses
+Node 0:/usr/local/etc/ctdb/public_addresses
 	10.1.1.1/24 eth1
 	10.1.1.2/24 eth1
 
-Node 1:/etc/ctdb/public_addresses
+Node 1:/usr/local/etc/ctdb/public_addresses
 	10.1.1.1/24 eth1
 	10.1.1.2/24 eth1
 
-Node 2:/etc/ctdb/public_addresses
+Node 2:/usr/local/etc/ctdb/public_addresses
 	10.1.2.1/24 eth2
 	10.1.2.2/24 eth2
 
-Node 3:/etc/ctdb/public_addresses
+Node 3:/usr/local/etc/ctdb/public_addresses
 	10.1.2.1/24 eth2
 	10.1.2.2/24 eth2
       </screen>
@@ -446,18 +446,6 @@ Node 3:/etc/ctdb/public_addresses
 	</listitem>
       </varlistentry>
 
-      <varlistentry>
-	<term>NATGW</term>
-	<listitem>
-	  <para>
-	    Indicates that this node is configured to become the NAT
-	    gateway master in a NAT gateway group.  See the
-	    <citetitle>NAT GATEWAY</citetitle> section for more
-	    details.
-	  </para>
-	</listitem>
-      </varlistentry>
-
     </variablelist>
 
     <para>
@@ -588,7 +576,29 @@ CTDB_LVS_PUBLIC_IP=10.1.1.237
 
     </refsect2>
   </refsect1>
-    
+
+  <refsect1>
+    <title>TRACKING AND RESETTING TCP CONNECTIONS</title>
+
+    <para>
+      CTDB tracks TCP connections from clients to public IP addresses,
+      on known ports.  When an IP address moves from one node to
+      another, all existing TCP connections to that IP address are
+      reset.  The node taking over this IP address will also send
+      gratuitous ARPs (for IPv4, or neighbour advertisement, for
+      IPv6).  This allows clients to reconnect quickly, rather than
+      waiting for TCP timeouts, which can be very long.
+    </para>
+
+    <para>
+      It is important that established TCP connections do not survive
+      a release and take of a public IP address on the same node.
+      Such connections can get out of sync with sequence and ACK
+      numbers, potentially causing a disruptive ACK storm.
+    </para>
+
+  </refsect1>
+
   <refsect1>
     <title>NAT GATEWAY</title>
 
@@ -649,7 +659,7 @@ CTDB_LVS_PUBLIC_IP=10.1.1.237
 	NATGW is usually configured similar to the following example configuration:
       </para>
       <screen format="linespecific">
-CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+CTDB_NATGW_NODES=/usr/local/etc/ctdb/natgw_nodes
 CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24
 CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
 CTDB_NATGW_PUBLIC_IFACE=eth0
@@ -659,14 +669,15 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
       <para>
 	Normally any node in a NATGW group can act as the NATGW
 	master.  Some configurations may have special nodes that lack
-	connectivity to a public network.  In such cases,
-	<varname>CTDB_NATGW_SLAVE_ONLY</varname> can be used to limit the
-	NATGW functionality of thos nodes.
+	connectivity to a public network.  In such cases, those nodes
+	can be flagged with the "slave-only" option in the
+	<varname>CTDB_NATGW_NODES</varname> file to limit the NATGW
+	functionality of those nodes.
       </para>
 
       <para>
 	See the <citetitle>NAT GATEWAY</citetitle> section in
-	<citerefentry><refentrytitle>ctdb.conf</refentrytitle>
+	<citerefentry><refentrytitle>ctdbd.conf</refentrytitle>
 	<manvolnum>5</manvolnum></citerefentry> for more details of
 	NATGW configuration.
       </para>
@@ -871,12 +882,12 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
       </para>
 
       <screen>
-/etc/ctdb/public_addresses:
+/usr/local/etc/ctdb/public_addresses:
 
   192.168.1.98	eth2,eth3
   192.168.1.99	eth2,eth3
 
-/etc/ctdb/policy_routing:
+/usr/local/etc/ctdb/policy_routing:
 
   192.168.1.98 192.168.1.0/24
   192.168.1.98 192.168.200.0/24	192.168.1.254
@@ -910,9 +921,9 @@ CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
       The specified script must be executable.  
     </para>
     <para>
-      Use of the provided <filename>/etc/ctdb/notify.sh</filename>
+      Use of the provided <filename>/usr/local/etc/ctdb/notify.sh</filename>
       script is recommended.  It executes files in
-      <filename>/etc/ctdb/notify.d/</filename>.
+      <filename>/usr/local/etc/ctdb/notify.d/</filename>.
     </para>
     <para>
       CTDB currently generates notifications after CTDB changes to
diff --git a/ctdb/doc/ctdbd.1 b/ctdb/doc/ctdbd.1
index f6928f4..4634b42 100644
--- a/ctdb/doc/ctdbd.1
+++ b/ctdb/doc/ctdbd.1
@@ -2,12 +2,12 @@
 .\"     Title: ctdbd
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDBD" "1" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDBD" "1" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -60,24 +60,24 @@ for more information\&.
 .RS 4
 DIRECTORY on local storage where ctdbd keeps a local copy of TDB databases\&. This directory is local for each node and should not be stored on the shared cluster filesystem\&.
 .sp
-This directory would usually be
-/var/lib/ctdb
+Defaults to
+/usr/local/var/lib/ctdb\&.
 .RE
 .PP
 \-\-dbdir\-persistent=\fIDIRECTORY\fR
 .RS 4
 DIRECTORY on local storage where ctdbd keeps a local copy of persistent TDB databases\&. This directory is local for each node and should not be stored on the shared cluster filesystem\&.
 .sp
-This directory would usually be
-/var/lib/ctdb/persistent
+Defaults to
+/usr/local/var/lib/ctdb/persistent\&.
 .RE
 .PP
 \-\-dbdir\-state=\fIDIRECTORY\fR
 .RS 4
 DIRECTORY on local storage where ctdbd keep internal state TDB files\&. This directory is local for each node and should not be stored on the shared cluster filesystem\&.
 .sp
-This directory would usually be
-/var/lib/ctdb/state
+Defaults to
+/usr/local/var/lib/ctdb/state\&.
 .RE
 .PP
 \-\-event\-script\-dir=\fIDIRECTORY\fR
@@ -90,7 +90,7 @@ for more information\&.
 .sp
 Default is
 \fBCTDB_BASE\fR/events\&.d, so usually
-/etc/ctdb/events\&.d, which is part of the CTDB installation\&.
+/usr/local/etc/ctdb/events\&.d, which is part of the CTDB installation\&.
 .RE
 .PP
 \-\-listen=\fIIPADDR\fR
@@ -105,15 +105,14 @@ This option is only required when automatic address detection can not be used\&.
 .PP
 \-\-logging=\fISTRING\fR
 .RS 4
-STRING specifies where ctdbd will write its log\&. The default is file:/var/log/log\&.ctdb
-or similar \- the prefix may differ depending on how CTDB was built\&.
+STRING specifies where ctdbd will write its log\&. The default is file:/usr/local/var/log/log\&.ctdb\&.
 .sp
 Valid values are:
 .PP
 file:\fIFILENAME\fR
 .RS 4
 FILENAME where ctdbd will write its log\&. This is usually
-/var/log/log\&.ctdb\&.
+/usr/local/var/log/log\&.ctdb\&.
 .RE
 .PP
 syslog[:\fIMETHOD\fR]
@@ -168,7 +167,7 @@ in the cluster\&.
 .sp
 Default is
 \fBCTDB_BASE\fR/nodes, so usually
-/etc/ctdb/nodes\&.
+/usr/local/etc/ctdb/nodes\&.
 .RE
 .PP
 \-\-no\-lmaster
@@ -198,7 +197,7 @@ for more information\&.
 FILENAME specifying a script to be invoked by ctdbd when certain state changes occur\&.
 .sp
 This file is usually
-/etc/ctdb/notify\&.sh\&.
+/usr/local/etc/ctdb/notify\&.sh\&.
 .sp
 Please see the
 NOTIFICATION SCRIPT
@@ -221,7 +220,7 @@ FILENAME specifying a file containing the public IP addresses to use on the clus
 The IP addresses specified in this file can differ across nodes\&.
 .sp
 This is usually the file
-/etc/ctdb/public_addresses
+/usr/local/etc/ctdb/public_addresses
 .RE
 .PP
 \-\-public\-interface=\fIINTERFACE\fR
@@ -244,7 +243,7 @@ section in
 .PP
 \-\-single\-public\-ip=\fIIPADDR\fR
 .RS 4
-IPADDR specifies the single IP that CTDB will use in conjuction with LVS\&.
+IPADDR specifies the single IP that CTDB will use in conjunction with LVS\&.
 .sp
 Please see the
 LVS
@@ -283,11 +282,6 @@ section in
 for more information about the STOPPED state\&.
 .RE
 .PP
-\-\-syslog
-.RS 4
-Send log messages to syslog instead of the CTDB logfile\&. This option overrides \-\-logfile\&. The default is to log to a file\&.
-.RE
-.PP
 \-\-transport=tcp|infiniband
 .RS 4
 This option specifies which transport to use for ctdbd internode communications\&. The default is "tcp"\&.
@@ -327,8 +321,7 @@ run as a real\-time process and instead run ctdbd as a normal userspace process\
 FILENAME specifies the name of the Unix domain socket that ctdbd will create\&. This socket is used by local clients to communicate with ctdbd\&.
 .sp
 The default is
-/tmp/ctdb\&.socket
-\&. You only need to use this option if you plan to run multiple ctdbd daemons on the same physical host, usually for testing\&.
+/usr/local/var/run/ctdb/ctdbd\&.socket\&. You only need to use this option if you plan to run multiple ctdbd daemons on the same physical host, usually for testing\&.
 .RE
 .PP
 \-\-script\-log\-level=\fIDEBUGLEVEL\fR
diff --git a/ctdb/doc/ctdbd.1.html b/ctdb/doc/ctdbd.1.html
index 87b6712..4c0ae52 100644
--- a/ctdb/doc/ctdbd.1.html
+++ b/ctdb/doc/ctdbd.1.html
@@ -1,11 +1,11 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdbd.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd — The CTDB cluster daemon</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p>< [...]
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdbd.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd — The CTDB cluster daemon</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p>< [...]
       ctdbd is the main CTDB daemon.
     </p><p>
       Note that ctdbd is not usually invoked directly.  It is invoked
       via <span class="citerefentry"><span class="refentrytitle">ctdbd_wrapper</span>(1)</span> or via the initscript.
     </p><p>
       See <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for an overview of CTDB.
-    </p></div><div class="refsect1"><a name="idp52972944"></a><h2>GENERAL OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-d, --debug=<em class="parameter"><code>DEBUGLEVEL</code></em></span></dt><dd><p>
+    </p></div><div class="refsect1"><a name="idp49554896"></a><h2>GENERAL OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-d, --debug=<em class="parameter"><code>DEBUGLEVEL</code></em></span></dt><dd><p>
 	    This option sets the debug level to DEBUGLEVEL, which
 	    controls what will be written by the logging
 	    subsystem.  The default is 2.
@@ -18,29 +18,27 @@
 	    TDB databases.  This directory is local for each node and
 	    should not be stored on the shared cluster filesystem.
 	  </p><p>
-	    This directory would usually be <code class="filename">/var/lib/ctdb</code>
+	    Defaults to <code class="filename">/usr/local/var/lib/ctdb</code>.
 	  </p></dd><dt><span class="term">--dbdir-persistent=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
 	    DIRECTORY on local storage where ctdbd keeps a local copy of
 	    persistent TDB databases.  This directory is local for each
 	    node and should not be stored on the shared cluster
 	    filesystem.
 	  </p><p>
-	    This directory would usually be
-	    <code class="filename">/var/lib/ctdb/persistent</code>
+	    Defaults to <code class="filename">/usr/local/var/lib/ctdb/persistent</code>.
 	  </p></dd><dt><span class="term">--dbdir-state=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
 	    DIRECTORY on local storage where ctdbd keep internal state
 	    TDB files.  This directory is local for each node and
 	    should not be stored on the shared cluster filesystem.
 	  </p><p>
-	    This directory would usually be
-	    <code class="filename">/var/lib/ctdb/state</code>
+	    Defaults to <code class="filename">/usr/local/var/lib/ctdb/state</code>.
 	  </p></dd><dt><span class="term">--event-script-dir=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
 	    DIRECTORY where the CTDB event scripts are stored.  See the
 	    <em class="citetitle">EVENT SCRIPTS</em> section in
 	    <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for more information.
 	  </p><p>
 	    Default is <code class="envar">CTDB_BASE</code>/events.d, so usually
-	    <code class="filename">/etc/ctdb/events.d</code>, which is part of
+	    <code class="filename">/usr/local/etc/ctdb/events.d</code>, which is part of
 	    the CTDB installation.
 	  </p></dd><dt><span class="term">--listen=<em class="parameter"><code>IPADDR</code></em></span></dt><dd><p>
 	    IPADDR is the private IP address that ctdbd will bind to.
@@ -57,14 +55,13 @@
 	    net.ipv4.ip_nonlocal_bind=1.
 	  </p></dd><dt><span class="term">--logging=<em class="parameter"><code>STRING</code></em></span></dt><dd><p>
 	    STRING specifies where ctdbd will write its log. The
-	    default is file:<code class="filename">/var/log/log.ctdb</code> or
-	    similar - the prefix may differ depending on how CTDB was
-	    built.
+	    default is
+	    file:<code class="filename">/usr/local/var/log/log.ctdb</code>.
 	  </p><p>
 	    Valid values are:
 	  </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">file:<em class="parameter"><code>FILENAME</code></em></span></dt><dd><p>
 		  FILENAME where ctdbd will write its log. This is usually
-		  <code class="filename">/var/log/log.ctdb</code>.
+		  <code class="filename">/usr/local/var/log/log.ctdb</code>.
 		</p></dd><dt><span class="term">syslog[<span class="optional">:<em class="parameter"><code>METHOD</code></em></span>]</span></dt><dd><p>
 		  CTDB will log to syslog.  By default this will use
 		  the syslog(3) API.
@@ -115,7 +112,7 @@
 	    cluster.
 	  </p><p>
 	    Default is <code class="envar">CTDB_BASE</code>/nodes, so usually
-	    <code class="filename">/etc/ctdb/nodes</code>.
+	    <code class="filename">/usr/local/etc/ctdb/nodes</code>.
 	  </p></dd><dt><span class="term">--no-lmaster</span></dt><dd><p>
 	    This argument specifies that this node can NOT become an lmaster
 	    for records in the database. This means that it will never show up
@@ -138,7 +135,7 @@
 	    certain state changes occur.
 	  </p><p>
 	    This file is usually
-	    <code class="filename">/etc/ctdb/notify.sh</code>.
+	    <code class="filename">/usr/local/etc/ctdb/notify.sh</code>.
 	  </p><p>
 	    Please see the <em class="citetitle">NOTIFICATION SCRIPT</em>
 	    section in <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for more
@@ -160,7 +157,7 @@
 	    nodes.
 	  </p><p>
 	    This is usually the file
-	    <code class="filename">/etc/ctdb/public_addresses</code>
+	    <code class="filename">/usr/local/etc/ctdb/public_addresses</code>
 	  </p></dd><dt><span class="term">--public-interface=<em class="parameter"><code>INTERFACE</code></em></span></dt><dd><p>
 	    INTERFACE on which to attach public IP addresses or on which
 	    to attach the single-public-ip when used.
@@ -178,7 +175,7 @@
 	    <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span>.
 	  </p></dd><dt><span class="term">--single-public-ip=<em class="parameter"><code>IPADDR</code></em></span></dt><dd><p>
 	    IPADDR specifies the single IP that CTDB will use in
-	    conjuction with LVS.
+	    conjunction with LVS.
 	  </p><p>
 	    Please see the <em class="citetitle">LVS</em> section in
 	    <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for more
@@ -203,10 +200,6 @@
 	    Please see the <em class="citetitle">NODE STATES</em> section
 	    in <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for more
 	    information about the STOPPED state.
-	  </p></dd><dt><span class="term">--syslog</span></dt><dd><p>
-	    Send log messages to syslog instead of the CTDB logfile.
-	    This option overrides --logfile.  The default is to log to
-	    a file.
 	  </p></dd><dt><span class="term">--transport=tcp|infiniband</span></dt><dd><p>
 	    This option specifies which transport to use for ctdbd
 	    internode communications. The default is "tcp".
@@ -214,7 +207,7 @@
 	    The "infiniband" support is not regularly tested.
 	  </p></dd><dt><span class="term">-?, --help</span></dt><dd><p>
 	    Display a summary of options.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp54745248"></a><h2>DEBUGGING OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-i, --interactive</span></dt><dd><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp55026688"></a><h2>DEBUGGING OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-i, --interactive</span></dt><dd><p>
 	    Enable interactive mode.  This will make ctdbd run in the
 	    foreground and not detach from the terminal.  By default
 	    ctdbd will detach itself and run in the background as a
@@ -243,10 +236,10 @@
 	    ctdbd will create. This socket is used by local clients to
 	    communicate with ctdbd.
 	  </p><p>
-	    The default is <code class="filename">/tmp/ctdb.socket</code> . You
-	    only need to use this option if you plan to run multiple
-	    ctdbd daemons on the same physical host, usually for
-	    testing.
+	    The default is <code class="filename">/usr/local/var/run/ctdb/ctdbd.socket</code>.
+	    You only need to use this option if you plan to run
+	    multiple ctdbd daemons on the same physical host, usually
+	    for testing.
 	  </p></dd><dt><span class="term">--script-log-level=<em class="parameter"><code>DEBUGLEVEL</code></em></span></dt><dd><p>
 	    This option sets the debug level of event script output to
 	    DEBUGLEVEL.  The default is ERR (0).
@@ -271,7 +264,7 @@
 	    This is a debugging option. This option is only used when
 	    debugging ctdbd.  This enables additional debugging
 	    capabilities and implies --nosetsched.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp54766736"></a><h2>SEE ALSO</h2><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp55048176"></a><h2>SEE ALSO</h2><p>
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span>,
 
       <span class="citerefentry"><span class="refentrytitle">ctdbd_wrapper</span>(1)</span>,
diff --git a/ctdb/doc/ctdbd.1.xml b/ctdb/doc/ctdbd.1.xml
index 558e534..ae61792 100644
--- a/ctdb/doc/ctdbd.1.xml
+++ b/ctdb/doc/ctdbd.1.xml
@@ -72,7 +72,7 @@
 	    should not be stored on the shared cluster filesystem.
 	  </para>
 	  <para>
-	    This directory would usually be <filename>/var/lib/ctdb</filename>
+	    Defaults to <filename>/usr/local/var/lib/ctdb</filename>.
 	  </para>
 	</listitem>
       </varlistentry>
@@ -87,8 +87,7 @@
 	    filesystem.
 	  </para>
 	  <para>
-	    This directory would usually be
-	    <filename>/var/lib/ctdb/persistent</filename>
+	    Defaults to <filename>/usr/local/var/lib/ctdb/persistent</filename>.
 	  </para>
 	</listitem>
       </varlistentry>
@@ -102,8 +101,7 @@
 	    should not be stored on the shared cluster filesystem.
 	  </para>
 	  <para>
-	    This directory would usually be
-	    <filename>/var/lib/ctdb/state</filename>
+	    Defaults to <filename>/usr/local/var/lib/ctdb/state</filename>.
 	  </para>
 	</listitem>
       </varlistentry>
@@ -119,7 +117,7 @@
 	  </para>
 	  <para>
 	    Default is <envar>CTDB_BASE</envar>/events.d, so usually
-	    <filename>/etc/ctdb/events.d</filename>, which is part of
+	    <filename>/usr/local/etc/ctdb/events.d</filename>, which is part of
 	    the CTDB installation.
 	  </para>
 	</listitem>
@@ -152,9 +150,8 @@
 	<listitem>
 	  <para>
 	    STRING specifies where ctdbd will write its log. The
-	    default is file:<filename>/var/log/log.ctdb</filename> or
-	    similar - the prefix may differ depending on how CTDB was
-	    built.
+	    default is
+	    file:<filename>/usr/local/var/log/log.ctdb</filename>.
 	  </para>
 	  <para>
 	    Valid values are:
@@ -165,7 +162,7 @@
 	      <listitem>
 		<para>
 		  FILENAME where ctdbd will write its log. This is usually
-		  <filename>/var/log/log.ctdb</filename>.
+		  <filename>/usr/local/var/log/log.ctdb</filename>.
 		</para>
 	      </listitem>
 	    </varlistentry>
@@ -271,7 +268,7 @@
 	  </para>
 	  <para>
 	    Default is <envar>CTDB_BASE</envar>/nodes, so usually
-	    <filename>/etc/ctdb/nodes</filename>.
+	    <filename>/usr/local/etc/ctdb/nodes</filename>.
 	  </para>
 	</listitem>
       </varlistentry>
@@ -320,7 +317,7 @@
 	  </para>
 	  <para>
 	    This file is usually
-	    <filename>/etc/ctdb/notify.sh</filename>.
+	    <filename>/usr/local/etc/ctdb/notify.sh</filename>.
 	  </para>
 	  <para>
 	    Please see the <citetitle>NOTIFICATION SCRIPT</citetitle>
@@ -361,7 +358,7 @@
 	  </para>
 	  <para>
 	    This is usually the file
-	    <filename>/etc/ctdb/public_addresses</filename>
+	    <filename>/usr/local/etc/ctdb/public_addresses</filename>
 	  </para>
 	</listitem>
       </varlistentry>
@@ -403,7 +400,7 @@
 	<listitem>
 	  <para>
 	    IPADDR specifies the single IP that CTDB will use in
-	    conjuction with LVS.
+	    conjunction with LVS.
 	  </para>
 	  <para>
 	    Please see the <citetitle>LVS</citetitle> section in
@@ -455,17 +452,6 @@
       </varlistentry>
 
       <varlistentry>
-	<term>--syslog</term>
-	<listitem>
-	  <para>
-	    Send log messages to syslog instead of the CTDB logfile.
-	    This option overrides --logfile.  The default is to log to
-	    a file.
-	  </para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
 	<term>--transport=tcp|infiniband</term>
 	<listitem>
 	  <para>
@@ -551,10 +537,10 @@
 	    communicate with ctdbd.
 	  </para>
 	  <para>
-	    The default is <filename>/tmp/ctdb.socket</filename> . You
-	    only need to use this option if you plan to run multiple
-	    ctdbd daemons on the same physical host, usually for
-	    testing.
+	    The default is <filename>/usr/local/var/run/ctdb/ctdbd.socket</filename>.
+	    You only need to use this option if you plan to run
+	    multiple ctdbd daemons on the same physical host, usually
+	    for testing.
 	  </para>
 	</listitem>
       </varlistentry>
diff --git a/ctdb/doc/ctdbd.conf.5 b/ctdb/doc/ctdbd.conf.5
index e62e3a6..9073eec 100644
--- a/ctdb/doc/ctdbd.conf.5
+++ b/ctdb/doc/ctdbd.conf.5
@@ -2,12 +2,12 @@
 .\"     Title: ctdbd.conf
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDBD\&.CONF" "5" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDBD\&.CONF" "5" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -32,7 +32,7 @@ ctdbd.conf \- CTDB daemon configuration file
 .SH "DESCRIPTION"
 .PP
 This file contains CTDB configuration variables that are affect the operation of CTDB\&. The default location of this file is
-/etc/ctdb/ctdbd\&.conf\&.
+/usr/local/etc/ctdb/ctdbd\&.conf\&.
 .PP
 This file is a shell script (see
 \fBsh\fR(1)) but is usually limited to simple variable assignments and shell\-style comments\&.
@@ -44,7 +44,7 @@ Variables defined in this document can also be set in a distribution\-specific c
 (Red Hat) or
 /etc/default/ctdb
 (Debian)\&. However, these files should be reserved for variables used by the initscript\&. A historical alternative is
-/etc/ctdb/sysconfig/ctdb
+/usr/local/etc/ctdb/sysconfig/ctdb
 \- this is deprecated\&.
 .SH "INITSCRIPT CONFIGURATION"
 .PP
@@ -59,7 +59,7 @@ FILENAME is the name of the file used to contain the process ID (PID) of the mai
 \fBctdbd_wrapper\fR(1)\&.
 .sp
 Default is
-/var/run/ctdb/ctdbd\&.pid\&. Corresponds to
+/usr/local/var/run/ctdb/ctdbd\&.pid\&. Corresponds to
 \fB\-\-pidfile\fR\&.
 .RE
 .SH "GLOBAL CONFIGURATION"
@@ -70,16 +70,6 @@ CTDB_BASE=\fIDIRECTORY\fR
 .RS 4
 DIRECTORY containing CTDB scripts and configuration files\&.
 .RE
-.PP
-CTDB_VARDIR=\fIDIRECTORY\fR
-.RS 4
-DIRECTORY containing CTDB files that are modified at runtime\&.
-.sp
-Defaults to
-/var/ctdb, unless
-/var/lib/ctdb
-already exists in which case it is used\&.
-.RE
 .SH "DAEMON CONFIGURATION"
 .PP
 Variables in this section are processed by
@@ -106,21 +96,34 @@ Defaults to yes\&. Corresponds to
 CTDB_DBDIR=\fIDIRECTORY\fR
 .RS 4
 Defaults to
-\fICTDB_VARDIR\fR\&. Corresponds to
+/usr/local/var/lib/ctdb\&.
+.sp
+Apart from a DIRECTORY, this can take a special value of the form
+\fBtmpfs\fR[:\fIOPTIONS\fR]\&. OPTIONS is a comma\-separated list of any permissible options to the tmpfs filesystem\&. The only pre\-specified default is
+\fBmode=700\fR, which can overriden by specifying
+\fBmode\fR
+in OPTIONS\&. It probably makes sense to specify a maximum
+\fBsize\fR\&.
+.sp
+Corresponds to
 \fB\-\-dbdir\fR\&.
 .RE
 .PP
 CTDB_DBDIR_PERSISTENT=\fIDIRECTORY\fR
 .RS 4
 Defaults to
-\fICTDB_VARDIR\fR/persistent\&. Corresponds to
+/usr/local/var/lib/ctdb/persistent\&.
+.sp
+Corresponds to
 \fB\-\-dbdir\-persistent\fR\&.
 .RE
 .PP
 CTDB_DBDIR_STATE=\fIDIRECTORY\fR
 .RS 4
 Defaults to
-\fICTDB_VARDIR\fR/state\&. Corresponds to
+/usr/local/var/lib/ctdb/state\&.
+.sp
+Corresponds to
 \fB\-\-dbdir\-state\fR\&.
 .RE
 .PP
@@ -136,14 +139,13 @@ CTDB_EVENT_SCRIPT_DIR=\fIDIRECTORY\fR
 .RS 4
 Default is
 \fICTDB_BASE\fR/events\&.d, so usually
-/etc/ctdb/events\&.d\&. Corresponds to
+/usr/local/etc/ctdb/events\&.d\&. Corresponds to
 \fB\-\-event\-script\-dir\fR\&.
 .RE
 .PP
 CTDB_LOGGING=\fISTRING\fR
 .RS 4
-STRING specifies where ctdbd will write its log\&. The default is file:/var/log/log\&.ctdb
-or similar \- the prefix may differ depending on how CTDB was built\&. Corresponds to
+STRING specifies where ctdbd will write its log\&. The default is file:/usr/local/var/log/log\&.ctdb\&. Corresponds to
 \fB\-\-logging\fR\&.
 .sp
 Valid values are:
@@ -151,7 +153,7 @@ Valid values are:
 file:\fIFILENAME\fR
 .RS 4
 FILENAME where ctdbd will write its log\&. This is usually
-/var/log/log\&.ctdb\&.
+/usr/local/var/log/log\&.ctdb\&.
 .RE
 .PP
 syslog[:\fIMETHOD\fR]
@@ -188,14 +190,14 @@ CTDB_NODES=\fIFILENAME\fR
 .RS 4
 Default is
 \fICTDB_BASE\fR/nodes, so usually
-/etc/ctdb/nodes\&. Corresponds to
+/usr/local/etc/ctdb/nodes\&. Corresponds to
 \fB\-\-nlist\fR\&.
 .RE
 .PP
 CTDB_NOTIFY_SCRIPT=\fIFILENAME\fR
 .RS 4
 No default, usually
-/etc/ctdb/notify\&.sh\&. Corresponds to
+/usr/local/etc/ctdb/notify\&.sh\&. Corresponds to
 \fB\-\-notification\-script\fR\&.
 .RE
 .PP
@@ -205,7 +207,7 @@ Default 0\&. Corresponds to
 \fB\-\-max\-persistent\-check\-errors\fR\&.
 .RE
 .PP
-CTDB_NODE_ADDRESS=\fIFILENAME\fR
+CTDB_NODE_ADDRESS=\fIIPADDR\fR
 .RS 4
 IPADDR is the private IP address that ctdbd will bind to\&. Corresponds to
 \fB\-\-listen\fR\&.
@@ -219,7 +221,7 @@ This option is only required when automatic address detection can not be used\&.
 CTDB_PUBLIC_ADDRESSES=\fIFILENAME\fR
 .RS 4
 No default, usually
-/etc/ctdb/public_addresses\&. Corresponds to
+/usr/local/etc/ctdb/public_addresses\&. Corresponds to
 \fB\-\-public\-addresses\fR\&.
 .RE
 .PP
@@ -250,10 +252,10 @@ Defaults to ERR (0)\&. Corresponds to
 CTDB_SOCKET=\fIFILENAME\fR
 .RS 4
 Defaults to
-/tmp/ctdb\&.socket\&. Corresponds to
+/usr/local/var/run/ctdb/ctdbd\&.socket\&. Corresponds to
 \fB\-\-socket\fR\&.
 .sp
-If you change this then you probably want to set this in root\*(Aqs enviroment (perhaps in a file in
+If you change this then you probably want to set this in root\*(Aqs environment (perhaps in a file in
 /etc/profile\&.d) so that you can use the
 \fBctdb\fR(1)
 command in a straightforward manner\&.
@@ -326,15 +328,23 @@ File format:
 .RS 4
 .\}
 .nf
-\fIIPADDR\fR
+\fIIPADDR\fR [slave\-only]
 	      
 .fi
 .if n \{\
 .RE
 .\}
 .sp
+IPADDR is the private IP address of each node in the NAT gateway group\&.
+.sp
+If "slave\-only" is specified then the corresponding node can not be the NAT gateway master node\&. In this case
+\fICTDB_NATGW_PUBLIC_IFACE\fR
+and
+\fICTDB_NATGW_PUBLIC_IP\fR
+are optional and unused\&.
+.sp
 No default, usually
-/etc/ctdb/natgw_nodes
+/usr/local/etc/ctdb/natgw_nodes
 when enabled\&.
 .RE
 .PP
@@ -361,17 +371,6 @@ be a configured public IP address\&.
 No default\&.
 .RE
 .PP
-CTDB_NATGW_SLAVE_ONLY=yes|no
-.RS 4
-When set to "yes" a node can not be a NAT gateway master node\&. In this case
-\fICTDB_NATGW_PUBLIC_IFACE\fR
-and
-\fICTDB_NATGW_PUBLIC_IP\fR
-are optional and unused\&.
-.sp
-Default is no\&.
-.RE
-.PP
 CTDB_NATGW_STATIC_ROUTES=\fIIPADDR/MASK[@GATEWAY]\fR \&.\&.\&.
 .RS 4
 Each IPADDR/MASK identifies a network or host to which NATGW should create a fallback route, instead of creating a single default route\&. This can be used when there is already a default route, via an interface that can not reach required infrastructure, that overrides the NAT gateway default route\&.
@@ -399,7 +398,7 @@ No default\&.
 .RS 4
 .\}
 .nf
-CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+CTDB_NATGW_NODES=/usr/local/etc/ctdb/natgw_nodes
 CTDB_NATGW_PRIVATE_NETWORK=192\&.168\&.1\&.0/24
 CTDB_NATGW_DEFAULT_GATEWAY=10\&.0\&.0\&.1
 CTDB_NATGW_PUBLIC_IP=10\&.0\&.0\&.227/24
@@ -416,7 +415,7 @@ A variation that ensures that infrastructure (ADS, DNS, \&.\&.\&.) directly atta
 .RS 4
 .\}
 .nf
-CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+CTDB_NATGW_NODES=/usr/local/etc/ctdb/natgw_nodes
 CTDB_NATGW_PRIVATE_NETWORK=192\&.168\&.1\&.0/24
 CTDB_NATGW_PUBLIC_IP=10\&.0\&.0\&.227/24
 CTDB_NATGW_PUBLIC_IFACE=eth0
@@ -464,7 +463,7 @@ File format:
 .\}
 .sp
 No default, usually
-/etc/ctdb/policy_routing
+/usr/local/etc/ctdb/policy_routing
 when enabled\&.
 .RE
 .PP
@@ -504,7 +503,7 @@ No default, usually 1000 and 9000\&.
 .RS 4
 .\}
 .nf
-CTDB_PER_IP_ROUTING_CONF=/etc/ctdb/policy_routing
+CTDB_PER_IP_ROUTING_CONF=/usr/local/etc/ctdb/policy_routing
 CTDB_PER_IP_ROUTING_RULE_PREF=100
 CTDB_PER_IP_ROUTING_TABLE_ID_LOW=1000
 CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
@@ -522,6 +521,8 @@ Whether one or more offline interfaces should cause a monitor event to fail if t
 \fBctdb status\fR
 will display the node as "PARTIALLYONLINE"\&.
 .sp
+Note that CTDB_PARTIALLY_ONLINE_INTERFACES=yes is incompatible with NAT gateway, since NAT gateway relies on the interface configured by CTDB_NATGW_PUBLIC_IFACE to be up\&.
+.sp
 Default is "no"\&.
 .RE
 .SH "SERVICE CONFIGURATION"
@@ -796,7 +797,9 @@ Default is no\&.
 .RE
 .SS "SYSTEM RESOURCE MONITORING CONFIGURATION"
 .PP
-CTDB can experience seemingly random (performance and other) issues if system resources become too contrained\&. Options in this section can be enabled to allow certain system resources to be checked\&.
+CTDB can experience seemingly random (performance and other) issues if system resources become too constrained\&. Options in this section can be enabled to allow certain system resources to be checked\&. They allows warnings to be logged and nodes to be marked unhealthy when system resource usage reaches the configured thresholds\&.
+.PP
+Some checks are enabled by default\&. It is recommended that these checks remain enabled or are augmented by extra checks\&. There is no supported way of completely disabling the checks\&.
 .sp
 .it 1 an-trap
 .nr an-no-space-flag 1
@@ -806,52 +809,40 @@ CTDB can experience seemingly random (performance and other) issues if system re
 \fBEventscripts\fR
 .RS 4
 .RS 4
-00\&.ctdb
-.RE
-.RS 4
-40\&.fs_use
+05\&.system
 .RE
 .PP
-Filesystem usage monitoring is in
-40\&.fs_use\&. This eventscript is not enabled by default\&. Use
-\fBctdb enablescript\fR
-to enable it\&.
+Filesystem and memory usage monitoring is in
+05\&.system\&.
 .RE
 .PP
-CTDB_CHECK_FS_USE=\fIFS\-LIMIT\-LIST\fR
+CTDB_MONITOR_FILESYSTEM_USAGE=\fIFS\-LIMIT\-LIST\fR
 .RS 4
 FS\-LIMIT\-LIST is a space\-separated list of
-\fIFILESYSTEM\fR:\fILIMIT\fR
-pairs indicating that a node should be flagged unhealthy if the space used on FILESYSTEM reaches LIMIT%\&.
+\fIFILESYSTEM\fR:\fIWARN_LIMIT\fR[:\fIUNHEALTHY_LIMIT\fR]
+triples indicating that warnings should be logged if the space used on FILESYSTEM reaches WARN_LIMIT%\&. If usage reaches UNHEALTHY_LIMIT then the node should be flagged unhealthy\&. Either WARN_LIMIT or UNHEALTHY_LIMIT may be left blank, meaning that check will be omitted\&.
 .sp
-No default\&.
-.sp
-Note that this feature uses the
-40\&.fs_use
-eventscript, which is not enabled by default\&. Use
-\fBctdb enablescript\fR
-to enable it\&.
+Default is to warn for each filesystem containing a database directory (\fBCTDB_DBDIR\fR,
+\fBCTDB_DBDIR_PERSISTENT\fR,
+\fBCTDB_DBDIR_STATE\fR) with a threshold of 90%\&.
 .RE
 .PP
-CTDB_CHECK_SWAP_IS_NOT_USED=yes|no
+CTDB_MONITOR_MEMORY_USAGE=\fIMEM\-LIMITS\fR
 .RS 4
-Should a warning be logged if swap space is in use\&.
+MEM\-LIMITS takes the form
+\fIWARN_LIMIT\fR[:\fIUNHEALTHY_LIMIT\fR]
+indicating that warnings should be logged if memory usage reaches WARN_LIMIT%\&. If usage reaches UNHEALTHY_LIMIT then the node should be flagged unhealthy\&. Either WARN_LIMIT or UNHEALTHY_LIMIT may be left blank, meaning that check will be omitted\&.
 .sp
-Default is no\&.
+Default is 80, so warnings will be logged when memory usage reaches 80%\&.
 .RE
 .PP
-CTDB_MONITOR_FREE_MEMORY=\fINUM\fR
+CTDB_MONITOR_SWAP_USAGE=\fISWAP\-LIMITS\fR
 .RS 4
-NUM is a lower limit on available system memory, expressed in megabytes\&. If this is set and the amount of available memory falls below this limit then some debug information will be logged, the node will be disabled and then CTDB will be shut down\&.
+SWAP\-LIMITS takes the form
+\fIWARN_LIMIT\fR[:\fIUNHEALTHY_LIMIT\fR]
+indicating that warnings should be logged if swap usage reaches WARN_LIMIT%\&. If usage reaches UNHEALTHY_LIMIT then the node should be flagged unhealthy\&. Either WARN_LIMIT or UNHEALTHY_LIMIT may be left blank, meaning that check will be omitted\&.
 .sp
-No default\&.
-.RE
-.PP
-CTDB_MONITOR_FREE_MEMORY_WARN=\fINUM\fR
-.RS 4
-NUM is a lower limit on available system memory, expressed in megabytes\&. If this is set and the amount of available memory falls below this limit then a warning will be logged\&.
-.sp
-No default\&.
+Default is 25, so warnings will be logged when swap usage reaches 25%\&.
 .RE
 .SS "MISCELLANEOUS SERVICE\-RELATED CONFIGURATION"
 .PP
@@ -935,7 +926,7 @@ No default, usually
 \fICTDB_BASE\fR/debug_locks\&.sh\&.
 .RE
 .PP
-CTDB_ETCDIR=\fIDIRECTORY\fR
+CTDB_SYS_ETCDIR=\fIDIRECTORY\fR
 .RS 4
 DIRECTORY containing system configuration files\&. This is used to provide alternate configuration when testing and should not need to be changed from the default\&.
 .sp
@@ -1006,7 +997,7 @@ If "yes", this causes
 to be run under
 \fBvalgrind\fR(1)
 with logs going to
-/var/log/ctdb_valgrind\&. If neither "yes" nor "no" then the value is assumed to be a COMMAND (e\&.g\&. a
+/usr/local/var/log/ctdb_valgrind\&. If neither "yes" nor "no" then the value is assumed to be a COMMAND (e\&.g\&. a
 \fBvalgrind\fR
 variation, a
 \fBgdb\fR(1)
@@ -1019,9 +1010,17 @@ option is passed to
 .sp
 Default is no\&.
 .RE
+.PP
+CTDB_VARDIR=\fIDIRECTORY\fR
+.RS 4
+DIRECTORY containing CTDB files that are modified at runtime\&.
+.sp
+Defaults to
+/usr/local/var/lib/ctdb\&.
+.RE
 .SH "FILES"
 .RS 4
-/etc/ctdb/ctdbd\&.conf
+/usr/local/etc/ctdb/ctdbd\&.conf
 .RE
 .RS 4
 /etc/sysconfig/ctdb
@@ -1030,7 +1029,7 @@ Default is no\&.
 /etc/default/ctdb
 .RE
 .RS 4
-/etc/ctdb/sysconfig/ctdb
+/usr/local/etc/ctdb/sysconfig/ctdb
 .RE
 .SH "SEE ALSO"
 .PP
diff --git a/ctdb/doc/ctdbd.conf.5.html b/ctdb/doc/ctdbd.conf.5.html
index 7fe0a75..82e89da 100644
--- a/ctdb/doc/ctdbd.conf.5.html
+++ b/ctdb/doc/ctdbd.conf.5.html
@@ -1,7 +1,7 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd.conf</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdbd.conf.5"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd.conf — CTDB daemon configuration file</p></div><div class="refsect1"><a name="idp51979744"></a><h2> [...]
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd.conf</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdbd.conf.5"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd.conf — CTDB daemon configuration file</p></div><div class="refsect1"><a name="idp53709056"></a><h2> [...]
       This file contains CTDB configuration variables that are affect
       the operation of CTDB.  The default location of this file is
-      <code class="filename">/etc/ctdb/ctdbd.conf</code>.
+      <code class="filename">/usr/local/etc/ctdb/ctdbd.conf</code>.
     </p><p>
       This file is a shell script (see
       <span class="citerefentry"><span class="refentrytitle">sh</span>(1)</span>) but is usually limited
@@ -15,9 +15,9 @@
       <code class="filename">/etc/default/ctdb</code> (Debian).  However, these
       files should be reserved for variables used by the initscript.
       A historical alternative is
-      <code class="filename">/etc/ctdb/sysconfig/ctdb</code> - this is
+      <code class="filename">/usr/local/etc/ctdb/sysconfig/ctdb</code> - this is
       deprecated.
-    </p></div><div class="refsect1"><a name="idp51478896"></a><h2>
+    </p></div><div class="refsect1"><a name="idp52187248"></a><h2>
       INITSCRIPT CONFIGURATION
     </h2><p>
       Some options must be available to the initscript so they need to
@@ -30,23 +30,16 @@
 	    running.  This is passed from the initscript to
 	    <span class="citerefentry"><span class="refentrytitle">ctdbd_wrapper</span>(1)</span>.
 	  </p><p>
-	    Default is <code class="filename">/var/run/ctdb/ctdbd.pid</code>.
+	    Default is <code class="filename">/usr/local/var/run/ctdb/ctdbd.pid</code>.
 	    Corresponds to <code class="option">--pidfile</code>.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp49232048"></a><h2>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp52645200"></a><h2>
       GLOBAL CONFIGURATION
     </h2><p>
       These options may be used in the initscripts, daemon and
       scripts.
     </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_BASE=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
 	    DIRECTORY containing CTDB scripts and configuration files.
-	  </p></dd><dt><span class="term">CTDB_VARDIR=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
-	    DIRECTORY containing CTDB files that are modified at
-	    runtime.
-	  </p><p>
-	    Defaults to <code class="filename">/var/ctdb</code>, unless
-	    <code class="filename">/var/lib/ctdb</code> already exists in which
-	    case it is used.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp53889648"></a><h2>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp49236080"></a><h2>
       DAEMON CONFIGURATION
     </h2><p>
       Variables in this section are processed by
@@ -64,31 +57,44 @@
 	    Defaults to yes.  Corresponds to
 	    <code class="option">--no-recmaster</code>.
 	  </p></dd><dt><span class="term">CTDB_DBDIR=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
-	    Defaults to <code class="varname">CTDB_VARDIR</code>.  Corresponds to
-	    <code class="option">--dbdir</code>.
+	    Defaults to <code class="filename">/usr/local/var/lib/ctdb</code>.
+	  </p><p>
+	    Apart from a DIRECTORY, this can take a special value of
+	    the form
+	    <code class="option">tmpfs</code>[<span class="optional">:<em class="parameter"><code>OPTIONS</code></em></span>].
+	    OPTIONS is a comma-separated list of any permissible
+	    options to the tmpfs filesystem.  The only pre-specified
+	    default is <code class="option">mode=700</code>, which can
+	    overriden by specifying <code class="option">mode</code> in
+	    OPTIONS.  It probably makes sense to specify a maximum
+	    <code class="option">size</code>.
+	  </p><p>
+	    Corresponds to <code class="option">--dbdir</code>.
 	  </p></dd><dt><span class="term">CTDB_DBDIR_PERSISTENT=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
-	    Defaults to <code class="varname">CTDB_VARDIR</code>/persistent.
+	    Defaults to <code class="filename">/usr/local/var/lib/ctdb/persistent</code>.
+	  </p><p>
 	    Corresponds to <code class="option">--dbdir-persistent</code>.
 	  </p></dd><dt><span class="term">CTDB_DBDIR_STATE=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
-	    Defaults to <code class="varname">CTDB_VARDIR</code>/state.
+	    Defaults to <code class="filename">/usr/local/var/lib/ctdb/state</code>.
+	  </p><p>
 	    Corresponds to <code class="option">--dbdir-state</code>.
 	  </p></dd><dt><span class="term">CTDB_DEBUGLEVEL=<em class="parameter"><code>DEBUGLEVEL</code></em></span></dt><dd><p>
 	    Default is NOTICE (2).  Corresponds to <code class="option">-d</code> or
 	    <code class="option">--debug</code>.
 	  </p></dd><dt><span class="term">CTDB_EVENT_SCRIPT_DIR=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
 	    Default is <code class="varname">CTDB_BASE</code>/events.d, so usually
-	    <code class="filename">/etc/ctdb/events.d</code>.  Corresponds to
+	    <code class="filename">/usr/local/etc/ctdb/events.d</code>.  Corresponds to
 	    <code class="option">--event-script-dir</code>.
 	  </p></dd><dt><span class="term">CTDB_LOGGING=<em class="parameter"><code>STRING</code></em></span></dt><dd><p>
 	    STRING specifies where ctdbd will write its log. The
-	    default is file:<code class="filename">/var/log/log.ctdb</code> or
-	    similar - the prefix may differ depending on how CTDB was
-	    built.  Corresponds to <code class="option">--logging</code>.
+	    default is
+	    file:<code class="filename">/usr/local/var/log/log.ctdb</code>.
+	    Corresponds to <code class="option">--logging</code>.
 	  </p><p>
 	    Valid values are:
 	  </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">file:<em class="parameter"><code>FILENAME</code></em></span></dt><dd><p>
 		  FILENAME where ctdbd will write its log. This is usually
-		  <code class="filename">/var/log/log.ctdb</code>.
+		  <code class="filename">/usr/local/var/log/log.ctdb</code>.
 		</p></dd><dt><span class="term">syslog[<span class="optional">:<em class="parameter"><code>METHOD</code></em></span>]</span></dt><dd><p>
 		  CTDB will log to syslog.  By default this will use
 		  the syslog(3) API.
@@ -123,16 +129,16 @@
 	    <code class="option">--single-public-ip IPADDR"</code>.
 	  </p></dd><dt><span class="term">CTDB_NODES=<em class="parameter"><code>FILENAME</code></em></span></dt><dd><p>
 	    Default is <code class="varname">CTDB_BASE</code>/nodes, so usually
-	    <code class="filename">/etc/ctdb/nodes</code>.  Corresponds to
+	    <code class="filename">/usr/local/etc/ctdb/nodes</code>.  Corresponds to
 	    <code class="option">--nlist</code>.
 	  </p></dd><dt><span class="term">CTDB_NOTIFY_SCRIPT=<em class="parameter"><code>FILENAME</code></em></span></dt><dd><p>
 	    No default, usually
-	    <code class="filename">/etc/ctdb/notify.sh</code>.  Corresponds to
+	    <code class="filename">/usr/local/etc/ctdb/notify.sh</code>.  Corresponds to
 	    <code class="option">--notification-script</code>.
 	  </p></dd><dt><span class="term">CTDB_MAX_PERSISTENT_CHECK_ERRORS=<em class="parameter"><code>NUM</code></em></span></dt><dd><p>
 	    Default 0.  Corresponds to
 	    <code class="option">--max-persistent-check-errors</code>.
-	  </p></dd><dt><span class="term">CTDB_NODE_ADDRESS=<em class="parameter"><code>FILENAME</code></em></span></dt><dd><p>
+	  </p></dd><dt><span class="term">CTDB_NODE_ADDRESS=<em class="parameter"><code>IPADDR</code></em></span></dt><dd><p>
 	    IPADDR is the private IP address that ctdbd will bind to.
 	    Corresponds to <code class="option">--listen</code>.
 	  </p><p>
@@ -148,7 +154,7 @@
 	    net.ipv4.ip_nonlocal_bind=1.
 	  </p></dd><dt><span class="term">CTDB_PUBLIC_ADDRESSES=<em class="parameter"><code>FILENAME</code></em></span></dt><dd><p>
 	    No default, usually
-	    <code class="filename">/etc/ctdb/public_addresses</code>.
+	    <code class="filename">/usr/local/etc/ctdb/public_addresses</code>.
 	    Corresponds to <code class="option">--public-addresses</code>.
 	  </p></dd><dt><span class="term">CTDB_PUBLIC_INTERFACE=<em class="parameter"><code>INTERFACE</code></em></span></dt><dd><p>
 	    No default.  Corresponds to
@@ -166,11 +172,11 @@
 	    Defaults to ERR (0).  Corresponds to
 	    <code class="option">--script-log-level</code>.
 	  </p></dd><dt><span class="term">CTDB_SOCKET=<em class="parameter"><code>FILENAME</code></em></span></dt><dd><p>
-	    Defaults to <code class="filename">/tmp/ctdb.socket</code>.
+	    Defaults to <code class="filename">/usr/local/var/run/ctdb/ctdbd.socket</code>.
 	    Corresponds to <code class="option">--socket</code>.
 	  </p><p>
 	    If you change this then you probably want to set this in
-	    root's enviroment (perhaps in a file in
+	    root's environment (perhaps in a file in
 	    <code class="filename">/etc/profile.d</code>) so that you can use
 	    the <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span> command in a
 	    straightforward manner.
@@ -202,7 +208,7 @@
 	    "setup" event before this timeout then it is killed.
 	  </p><p>
 	    Defaults is 10.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp55060688"></a><h2>NETWORK CONFIGURATION</h2><div class="refsect2"><a name="idp55061328"></a><h3>NAT GATEWAY</h3><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp55114240"></a><h2>NETWORK CONFIGURATION</h2><div class="refsect2"><a name="idp55114880"></a><h3>NAT GATEWAY</h3><p>
 	NAT gateway is used to configure fallback routing for nodes
 	when they do not host any public IP addresses.  For example,
 	it allows unhealthy nodes to reliably communicate with
@@ -226,11 +232,20 @@
 	    </p><p>
 	      File format:
 	      </p><pre class="screen">
-<em class="parameter"><code>IPADDR</code></em>
+<em class="parameter"><code>IPADDR</code></em> [<span class="optional">slave-only</span>]
 	      </pre><p>
 	    </p><p>
+	      IPADDR is the private IP address of each node in the NAT
+	      gateway group.
+	    </p><p>
+	      If "slave-only" is specified then the corresponding node
+	      can not be the NAT gateway master node.  In this case
+	      <code class="varname">CTDB_NATGW_PUBLIC_IFACE</code> and
+	      <code class="varname">CTDB_NATGW_PUBLIC_IP</code> are optional and
+	      unused.
+	    </p><p>
 	      No default, usually
-	      <code class="filename">/etc/ctdb/natgw_nodes</code> when enabled.
+	      <code class="filename">/usr/local/etc/ctdb/natgw_nodes</code> when enabled.
 	    </p></dd><dt><span class="term">CTDB_NATGW_PRIVATE_NETWORK=<em class="parameter"><code>IPADDR/MASK</code></em></span></dt><dd><p>
 	      IPADDR/MASK is the private sub-network that is
 	      internally routed via the NAT gateway master node.  This
@@ -251,14 +266,6 @@
 	      configured public IP address.
 	    </p><p>
 	      No default.
-	    </p></dd><dt><span class="term">CTDB_NATGW_SLAVE_ONLY=yes|no</span></dt><dd><p>
-	      When set to "yes" a node can not be a NAT gateway master
-	      node.  In this case
-	      <code class="varname">CTDB_NATGW_PUBLIC_IFACE</code> and
-	      <code class="varname">CTDB_NATGW_PUBLIC_IP</code> are optional
-	      and unused.
-	    </p><p>
-	      Default is no.
 	    </p></dd><dt><span class="term">CTDB_NATGW_STATIC_ROUTES=<em class="parameter"><code>IPADDR/MASK[@GATEWAY]</code></em> ...</span></dt><dd><p>
 	      Each IPADDR/MASK identifies a network or host to which
 	      NATGW should create a fallback route, instead of
@@ -285,8 +292,8 @@
 	      route to avoid this.
 	    </p><p>
 	      No default.
-	    </p></dd></dl></div><div class="refsect3"><a name="idp55088176"></a><h4>Example</h4><pre class="screen">
-CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+	    </p></dd></dl></div><div class="refsect3"><a name="idp55141104"></a><h4>Example</h4><pre class="screen">
+CTDB_NATGW_NODES=/usr/local/etc/ctdb/natgw_nodes
 CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24
 CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
 CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
@@ -296,7 +303,7 @@ CTDB_NATGW_PUBLIC_IFACE=eth0
 	  directly attached to the public network (10.0.0.0/24) is
 	  always reachable would look like this:
 	</p><pre class="screen">
-CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+CTDB_NATGW_NODES=/usr/local/etc/ctdb/natgw_nodes
 CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24
 CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
 CTDB_NATGW_PUBLIC_IFACE=eth0
@@ -304,7 +311,7 @@ CTDB_NATGW_STATIC_ROUTES=10.0.0.0/24
 	</pre><p>
 	  Note that <code class="varname">CTDB_NATGW_DEFAULT_GATEWAY</code> is
 	  not specified.
-	</p></div></div><div class="refsect2"><a name="idp55092064"></a><h3>POLICY ROUTING</h3><p>
+	</p></div></div><div class="refsect2"><a name="idp55145008"></a><h3>POLICY ROUTING</h3><p>
 	A node running CTDB may be a component of a complex network
 	topology.  In particular, public addresses may be spread
 	across several different networks (or VLANs) and it may not be
@@ -334,7 +341,7 @@ CTDB_NATGW_STATIC_ROUTES=10.0.0.0/24
 	      </pre><p>
 	    </p><p>
 	      No default, usually
-	      <code class="filename">/etc/ctdb/policy_routing</code> when enabled.
+	      <code class="filename">/usr/local/etc/ctdb/policy_routing</code> when enabled.
 	    </p></dd><dt><span class="term">CTDB_PER_IP_ROUTING_RULE_PREF=<em class="parameter"><code>NUM</code></em></span></dt><dd><p>
 	    NUM sets the priority (or preference) for the routing
 	    rules that are added by CTDB.
@@ -368,20 +375,25 @@ CTDB_NATGW_STATIC_ROUTES=10.0.0.0/24
 	      manipulate).
 	    </p><p>
 	      No default, usually 1000 and 9000.
-	    </p></dd></dl></div><div class="refsect3"><a name="idp55114000"></a><h4>Example</h4><pre class="screen">
-CTDB_PER_IP_ROUTING_CONF=/etc/ctdb/policy_routing
+	    </p></dd></dl></div><div class="refsect3"><a name="idp55166944"></a><h4>Example</h4><pre class="screen">
+CTDB_PER_IP_ROUTING_CONF=/usr/local/etc/ctdb/policy_routing
 CTDB_PER_IP_ROUTING_RULE_PREF=100
 CTDB_PER_IP_ROUTING_TABLE_ID_LOW=1000
 CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
-	</pre></div></div><div class="refsect2"><a name="idp55115696"></a><h3>MISCELLANEOUS NETWORK CONFIGURATION</h3><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_PARTIALLY_ONLINE_INTERFACES=yes|no</span></dt><dd><p>
+	</pre></div></div><div class="refsect2"><a name="idp55168656"></a><h3>MISCELLANEOUS NETWORK CONFIGURATION</h3><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_PARTIALLY_ONLINE_INTERFACES=yes|no</span></dt><dd><p>
 	      Whether one or more offline interfaces should cause a
 	      monitor event to fail if there are other interfaces that
 	      are up.  If this is "yes" and a node has some interfaces
 	      that are down then <span class="command"><strong>ctdb status</strong></span> will
 	      display the node as "PARTIALLYONLINE".
 	    </p><p>
+	      Note that CTDB_PARTIALLY_ONLINE_INTERFACES=yes is
+	      incompatible with NAT gateway, since NAT gateway relies
+	      on the interface configured by CTDB_NATGW_PUBLIC_IFACE
+	      to be up.
+	    </p><p>
 	      Default is "no".
-	    </p></dd></dl></div></div></div><div class="refsect1"><a name="idp55119760"></a><h2>SERVICE CONFIGURATION</h2><p>
+	    </p></dd></dl></div></div></div><div class="refsect1"><a name="idp55173328"></a><h2>SERVICE CONFIGURATION</h2><p>
       CTDB can be configured to manage and/or monitor various NAS (and
       other) services via its eventscripts.
     </p><p>
@@ -390,7 +402,7 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
       monitor the service and CTDB will do any required
       reconfiguration of the service when public IP addresses are
       failed over.
-    </p><div class="refsect2"><a name="idp55121616"></a><h3>SAMBA</h3><div class="refsect3"><a name="idp55122256"></a><h4>Eventscripts</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">49.winbind</code></td></tr><tr><td><code class="filename">50.samba</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGES_SAMBA=yes|no</span></dt><dd><p>
+    </p><div class="refsect2"><a name="idp55175184"></a><h3>SAMBA</h3><div class="refsect3"><a name="idp55175824"></a><h4>Eventscripts</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">49.winbind</code></td></tr><tr><td><code class="filename">50.samba</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGES_SAMBA=yes|no</span></dt><dd><p>
 	      Should CTDB manage Samba?
 	    </p><p>
 	      Default is no.
@@ -422,11 +434,11 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
 	      Distribution specific SERVICE for managing winbindd.
 	    </p><p>
 	      Default is "winbind".
-	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55141680"></a><h3>NFS</h3><p>
+	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55195152"></a><h3>NFS</h3><p>
 	This includes parameters for the kernel NFS server.
 	Alternative NFS subsystems (such as <a class="ulink" href="https://github.com/nfs-ganesha/nfs-ganesha/wiki" target="_top">NFS-Ganesha</a>)
 	can be integrated using <code class="varname">CTDB_NFS_CALLOUT</code>.
-      </p><div class="refsect3"><a name="idp55143824"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">60.nfs</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_CLUSTER_FILESYSTEM_TYPE=gpfs</span></dt><dd><p>
+      </p><div class="refsect3"><a name="idp55197296"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">60.nfs</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_CLUSTER_FILESYSTEM_TYPE=gpfs</span></dt><dd><p>
 	      The type of cluster filesystem to use with NFS-ganesha.
 	      Currently only "gpfs" is supported.
 	    </p><p>
@@ -465,16 +477,16 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
 	      overheads.
 	    </p><p>
 	      Default is "::1".
-	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55164896"></a><h3>APACHE HTTPD</h3><p>
+	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55218368"></a><h3>APACHE HTTPD</h3><p>
 	CTDB can manage the Apache web server.
-      </p><div class="refsect3"><a name="idp55165920"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">41.httpd</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGES_HTTPD=yes|no</span></dt><dd><p>
+      </p><div class="refsect3"><a name="idp55219392"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">41.httpd</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGES_HTTPD=yes|no</span></dt><dd><p>
 	      Should CTDB manage the Apache web server?
 	    </p><p>
 	      Default is no.
-	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55170496"></a><h3>CLAMAV</h3><p>
+	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55223968"></a><h3>CLAMAV</h3><p>
 	CTDB has support to manage the popular anti-virus daemon
 	ClamAV.
-      </p><div class="refsect3"><a name="idp55171616"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">31.clamd</code></td></tr></table><p>
+      </p><div class="refsect3"><a name="idp55225088"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">31.clamd</code></td></tr></table><p>
 	  This eventscript is not enabled by default.  Use
 	  <span class="command"><strong>ctdb enablescript</strong></span> to enable it.
 	</p></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGES_CLAMD=yes|no</span></dt><dd><p>
@@ -485,9 +497,9 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
 	      FILENAME is the socket to monitor ClamAV.
 	    </p><p>
 	      No default.
-	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55179696"></a><h3>ISCSI</h3><p>
+	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55233168"></a><h3>ISCSI</h3><p>
 	CTDB has support for managing the Linux iSCSI tgtd service.
-      </p><div class="refsect3"><a name="idp55180800"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">70.iscsi</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGES_ISCSI=yes|no</span></dt><dd><p>
+      </p><div class="refsect3"><a name="idp55234272"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">70.iscsi</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGES_ISCSI=yes|no</span></dt><dd><p>
 	      Should CTDB manage iSCSI tgtd?
 	    </p><p>
 	      Default is no.
@@ -496,66 +508,75 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
 	      tgtd for each public IP address.
 	    </p><p>
 	      No default.
-	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55187920"></a><h3>MULTIPATHD</h3><p>
+	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55241392"></a><h3>MULTIPATHD</h3><p>
 	CTDB can monitor multipath devices to ensure that active paths
 	are available.
-      </p><div class="refsect3"><a name="idp55189040"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">20.multipathd</code></td></tr></table><p>
+      </p><div class="refsect3"><a name="idp55242512"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">20.multipathd</code></td></tr></table><p>
 	  This eventscript is not enabled by default.  Use
 	  <span class="command"><strong>ctdb enablescript</strong></span> to enable it.
 	</p></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MONITOR_MPDEVICES=<em class="parameter"><code>MP-DEVICE-LIST</code></em></span></dt><dd><p>
 	      MP-DEVICE-LIST is a list of multipath devices for CTDB to monitor?
 	    </p><p>
 	      No default.
-	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55195296"></a><h3>VSFTPD</h3><p>
+	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55248768"></a><h3>VSFTPD</h3><p>
 	CTDB can manage the vsftpd FTP server.
-      </p><div class="refsect3"><a name="idp55196320"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">40.vsftpd</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGES_VSFTPD=yes|no</span></dt><dd><p>
+      </p><div class="refsect3"><a name="idp55249792"></a><h4>Eventscript</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">40.vsftpd</code></td></tr></table></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGES_VSFTPD=yes|no</span></dt><dd><p>
 	      Should CTDB manage the vsftpd FTP server?
 	    </p><p>
 	      Default is no.
-	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55200896"></a><h3>
+	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55254368"></a><h3>
 	SYSTEM RESOURCE MONITORING CONFIGURATION
       </h3><p>
 	CTDB can experience seemingly random (performance and other)
-	issues if system resources become too contrained.  Options in
-	this section can be enabled to allow certain system resources to
-	be checked.
-      </p><div class="refsect3"><a name="idp55202144"></a><h4>Eventscripts</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">00.ctdb</code></td></tr><tr><td><code class="filename">40.fs_use</code></td></tr></table><p>
-	  Filesystem usage monitoring is in
-	  <code class="filename">40.fs_use</code>.  This eventscript is not
-	  enabled by default.  Use <span class="command"><strong>ctdb
-	  enablescript</strong></span> to enable it.
-	</p></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_CHECK_FS_USE=<em class="parameter"><code>FS-LIMIT-LIST</code></em></span></dt><dd><p>
+	issues if system resources become too constrained.  Options in
+	this section can be enabled to allow certain system resources
+	to be checked.  They allows warnings to be logged and nodes to
+	be marked unhealthy when system resource usage reaches the
+	configured thresholds.
+      </p><p>
+	Some checks are enabled by default.  It is recommended that
+	these checks remain enabled or are augmented by extra checks.
+	There is no supported way of completely disabling the checks.
+      </p><div class="refsect3"><a name="idp55256352"></a><h4>Eventscripts</h4><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">05.system</code></td></tr></table><p>
+	  Filesystem and memory usage monitoring is in
+	  <code class="filename">05.system</code>.
+	</p></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MONITOR_FILESYSTEM_USAGE=<em class="parameter"><code>FS-LIMIT-LIST</code></em></span></dt><dd><p>
 	      FS-LIMIT-LIST is a space-separated list of
-	      <em class="parameter"><code>FILESYSTEM</code></em>:<em class="parameter"><code>LIMIT</code></em>
-	      pairs indicating that a node should be flagged unhealthy
-	      if the space used on FILESYSTEM reaches LIMIT%.
-	    </p><p>
-	      No default.
-	    </p><p>
-	      Note that this feature uses the
-	      <code class="filename">40.fs_use</code> eventscript, which is not
-	      enabled by default.  Use <span class="command"><strong>ctdb
-	      enablescript</strong></span> to enable it.
-	    </p></dd><dt><span class="term">CTDB_CHECK_SWAP_IS_NOT_USED=yes|no</span></dt><dd><p>
-	      Should a warning be logged if swap space is in use.
-	    </p><p>
-	      Default is no.
-	    </p></dd><dt><span class="term">CTDB_MONITOR_FREE_MEMORY=<em class="parameter"><code>NUM</code></em></span></dt><dd><p>
-	      NUM is a lower limit on available system memory, expressed
-	      in megabytes.  If this is set and the amount of available
-	      memory falls below this limit then some debug information
-	      will be logged, the node will be disabled and then CTDB
-	      will be shut down.
-	    </p><p>
-	      No default.
-	    </p></dd><dt><span class="term">CTDB_MONITOR_FREE_MEMORY_WARN=<em class="parameter"><code>NUM</code></em></span></dt><dd><p>
-	      NUM is a lower limit on available system memory, expressed
-	      in megabytes.  If this is set and the amount of available
-	      memory falls below this limit then a warning will be
-	      logged.
-	    </p><p>
-	      No default.
-	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55220144"></a><h3>MISCELLANEOUS SERVICE-RELATED CONFIGURATION</h3><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGED_SERVICES=<em class="parameter"><code>SERVICE-LIST</code></em></span></dt><dd><p>
+	      <em class="parameter"><code>FILESYSTEM</code></em>:<em class="parameter"><code>WARN_LIMIT</code></em>[<span class="optional">:<em class="parameter"><code>UNHEALTHY_LIMIT</code></em></span>]
+	      triples indicating that warnings should be logged if the
+	      space used on FILESYSTEM reaches WARN_LIMIT%.  If usage
+	      reaches UNHEALTHY_LIMIT then the node should be flagged
+	      unhealthy.  Either WARN_LIMIT or UNHEALTHY_LIMIT may be
+	      left blank, meaning that check will be omitted.
+	    </p><p>
+	      Default is to warn for each filesystem containing a
+	      database directory (<code class="envar">CTDB_DBDIR</code>,
+	      <code class="envar">CTDB_DBDIR_PERSISTENT</code>,
+	      <code class="envar">CTDB_DBDIR_STATE</code>) with a threshold of
+	      90%.
+	    </p></dd><dt><span class="term">CTDB_MONITOR_MEMORY_USAGE=<em class="parameter"><code>MEM-LIMITS</code></em></span></dt><dd><p>
+	      MEM-LIMITS takes the form
+	      <em class="parameter"><code>WARN_LIMIT</code></em>[<span class="optional">:<em class="parameter"><code>UNHEALTHY_LIMIT</code></em></span>]
+	      indicating that warnings should be logged if memory
+	      usage reaches WARN_LIMIT%.  If usage reaches
+	      UNHEALTHY_LIMIT then the node should be flagged
+	      unhealthy.  Either WARN_LIMIT or UNHEALTHY_LIMIT may be
+	      left blank, meaning that check will be omitted.
+	    </p><p>
+	      Default is 80, so warnings will be logged when memory
+	      usage reaches 80%.
+	    </p></dd><dt><span class="term">CTDB_MONITOR_SWAP_USAGE=<em class="parameter"><code>SWAP-LIMITS</code></em></span></dt><dd><p>
+	      SWAP-LIMITS takes the form
+	      <em class="parameter"><code>WARN_LIMIT</code></em>[<span class="optional">:<em class="parameter"><code>UNHEALTHY_LIMIT</code></em></span>]
+	       indicating that warnings should be logged if
+	      swap usage reaches WARN_LIMIT%.  If usage reaches
+	      UNHEALTHY_LIMIT then the node should be flagged
+	      unhealthy.  Either WARN_LIMIT or UNHEALTHY_LIMIT may be
+	      left blank, meaning that check will be omitted.
+	    </p><p>
+	      Default is 25, so warnings will be logged when swap
+	      usage reaches 25%.
+	    </p></dd></dl></div></div><div class="refsect2"><a name="idp55274512"></a><h3>MISCELLANEOUS SERVICE-RELATED CONFIGURATION</h3><div class="variablelist"><dl class="variablelist"><dt><span class="term">CTDB_MANAGED_SERVICES=<em class="parameter"><code>SERVICE-LIST</code></em></span></dt><dd><p>
 	      SERVICE-LIST is a space-separated list of SERVICEs that
 	      CTDB should manage.  This can be used as an alternative
 	      to the
@@ -568,7 +589,7 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
 	      managed or unmanaged.
 	    </p><p>
 	      Default is no.
-	    </p></dd></dl></div></div></div><div class="refsect1"><a name="idp55226672"></a><h2>
+	    </p></dd></dl></div></div></div><div class="refsect1"><a name="idp55281040"></a><h2>
       TUNABLES CONFIGURATION
     </h2><p>
       CTDB tunables (see
@@ -584,7 +605,7 @@ CTDB_SET_<em class="replaceable"><code>TUNABLE</code></em>=<em class="replaceabl
       </p><pre class="screen">
 CTDB_SET_MonitorInterval=20
       </pre><p>
-    </p></div><div class="refsect1"><a name="idp55231456"></a><h2>
+    </p></div><div class="refsect1"><a name="idp55285824"></a><h2>
       DEBUG AND TEST
     </h2><p>
       Variable in this section are for debugging and testing CTDB.
@@ -616,7 +637,7 @@ CTDB_SET_MonitorInterval=20
 	  </p><p>
 	    No default, usually
 	    <code class="filename"><code class="varname">CTDB_BASE</code>/debug_locks.sh</code>.
-	  </p></dd><dt><span class="term">CTDB_ETCDIR=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
+	  </p></dd><dt><span class="term">CTDB_SYS_ETCDIR=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
 	    DIRECTORY containing system configuration files.  This is
 	    used to provide alternate configuration when testing and
 	    should not need to be changed from the default.
@@ -677,7 +698,7 @@ CTDB_SET_MonitorInterval=20
 	    If "yes", this causes
 	    <span class="citerefentry"><span class="refentrytitle">ctdbd</span>(1)</span> to be run under
 	    <span class="citerefentry"><span class="refentrytitle">valgrind</span>(1)</span> with logs going to
-	    <code class="filename">/var/log/ctdb_valgrind</code>.  If neither
+	    <code class="filename">/usr/local/var/log/ctdb_valgrind</code>.  If neither
 	    "yes" nor "no" then the value is assumed to be a COMMAND
 	    (e.g. a <span class="command"><strong>valgrind</strong></span> variation, a
 	    <span class="citerefentry"><span class="refentrytitle">gdb</span>(1)</span> command) that is
@@ -686,7 +707,12 @@ CTDB_SET_MonitorInterval=20
 	    option is passed to <span class="command"><strong>ctdbd</strong></span>.
 	  </p><p>
 	    Default is no.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp55276736"></a><h2>FILES</h2><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">/etc/ctdb/ctdbd.conf</code></td></tr><tr><td><code class="filename">/etc/sysconfig/ctdb</code></td></tr><tr><td><code class="filename">/etc/default/ctdb</code></td></tr><tr><td><code class="filename">/etc/ctdb/sysconfig/ctdb</code></td></tr></table></div><div class="refsect1"><a name="idp55281136"></a><h2>SEE  [...]
+	  </p></dd><dt><span class="term">CTDB_VARDIR=<em class="parameter"><code>DIRECTORY</code></em></span></dt><dd><p>
+	    DIRECTORY containing CTDB files that are modified at
+	    runtime.
+	  </p><p>
+	    Defaults to <code class="filename">/usr/local/var/lib/ctdb</code>.
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp55334560"></a><h2>FILES</h2><table border="0" summary="Simple list" class="simplelist"><tr><td><code class="filename">/usr/local/etc/ctdb/ctdbd.conf</code></td></tr><tr><td><code class="filename">/etc/sysconfig/ctdb</code></td></tr><tr><td><code class="filename">/etc/default/ctdb</code></td></tr><tr><td><code class="filename">/usr/local/etc/ctdb/sysconfig/ctdb</code></td></tr></table></div><div class="refsect1"><a name="idp55 [...]
       <span class="citerefentry"><span class="refentrytitle">ctdbd</span>(1)</span>,
 
       <span class="citerefentry"><span class="refentrytitle">ctdbd_wrapper</span>(1)</span>,
diff --git a/ctdb/doc/ctdbd.conf.5.xml b/ctdb/doc/ctdbd.conf.5.xml
index da53e51..5494b51 100644
--- a/ctdb/doc/ctdbd.conf.5.xml
+++ b/ctdb/doc/ctdbd.conf.5.xml
@@ -23,7 +23,7 @@
     <para>
       This file contains CTDB configuration variables that are affect
       the operation of CTDB.  The default location of this file is
-      <filename>/etc/ctdb/ctdbd.conf</filename>.
+      <filename>/usr/local/etc/ctdb/ctdbd.conf</filename>.
     </para>
 
     <para>
@@ -44,7 +44,7 @@
       <filename>/etc/default/ctdb</filename> (Debian).  However, these
       files should be reserved for variables used by the initscript.
       A historical alternative is
-      <filename>/etc/ctdb/sysconfig/ctdb</filename> - this is
+      <filename>/usr/local/etc/ctdb/sysconfig/ctdb</filename> - this is
       deprecated.
     </para>
 
@@ -76,7 +76,7 @@
 	  </para>
 
 	  <para>
-	    Default is <filename>/var/run/ctdb/ctdbd.pid</filename>.
+	    Default is <filename>/usr/local/var/run/ctdb/ctdbd.pid</filename>.
 	    Corresponds to <option>--pidfile</option>.
 	  </para>
 	</listitem>
@@ -106,22 +106,6 @@
 	</listitem>
       </varlistentry>
 
-      <varlistentry>
-	<term>CTDB_VARDIR=<parameter>DIRECTORY</parameter></term>
-	<listitem>
-	  <para>
-	    DIRECTORY containing CTDB files that are modified at
-	    runtime.
-	  </para>
-	  <para>
-	    Defaults to <filename>/var/ctdb</filename>, unless
-	    <filename>/var/lib/ctdb</filename> already exists in which
-	    case it is used.
-	  </para>
-	</listitem>
-      </varlistentry>
-
-
     </variablelist>
   </refsect1>
 
@@ -172,8 +156,21 @@
 	<term>CTDB_DBDIR=<parameter>DIRECTORY</parameter></term>
 	<listitem>
 	  <para>
-	    Defaults to <varname>CTDB_VARDIR</varname>.  Corresponds to
-	    <option>--dbdir</option>.
+	    Defaults to <filename>/usr/local/var/lib/ctdb</filename>.
+	  </para>
+	  <para>
+	    Apart from a DIRECTORY, this can take a special value of
+	    the form
+	    <option>tmpfs</option><optional>:<parameter>OPTIONS</parameter></optional>.
+	    OPTIONS is a comma-separated list of any permissible
+	    options to the tmpfs filesystem.  The only pre-specified
+	    default is <option>mode=700</option>, which can
+	    overriden by specifying <option>mode</option> in
+	    OPTIONS.  It probably makes sense to specify a maximum
+	    <option>size</option>.
+	  </para>
+	  <para>
+	    Corresponds to <option>--dbdir</option>.
 	  </para>
 	</listitem>
       </varlistentry>
@@ -182,7 +179,9 @@
 	<term>CTDB_DBDIR_PERSISTENT=<parameter>DIRECTORY</parameter></term>
 	<listitem>
 	  <para>
-	    Defaults to <varname>CTDB_VARDIR</varname>/persistent.
+	    Defaults to <filename>/usr/local/var/lib/ctdb/persistent</filename>.
+	  </para>
+	  <para>
 	    Corresponds to <option>--dbdir-persistent</option>.
 	  </para>
 	</listitem>
@@ -192,7 +191,9 @@
 	<term>CTDB_DBDIR_STATE=<parameter>DIRECTORY</parameter></term>
 	<listitem>
 	  <para>
-	    Defaults to <varname>CTDB_VARDIR</varname>/state.
+	    Defaults to <filename>/usr/local/var/lib/ctdb/state</filename>.
+	  </para>
+	  <para>
 	    Corresponds to <option>--dbdir-state</option>.
 	  </para>
 	</listitem>
@@ -213,7 +214,7 @@
 	<listitem>
 	  <para>
 	    Default is <varname>CTDB_BASE</varname>/events.d, so usually
-	    <filename>/etc/ctdb/events.d</filename>.  Corresponds to
+	    <filename>/usr/local/etc/ctdb/events.d</filename>.  Corresponds to
 	    <option>--event-script-dir</option>.
 	  </para>
 	</listitem>
@@ -224,9 +225,9 @@
 	<listitem>
 	  <para>
 	    STRING specifies where ctdbd will write its log. The
-	    default is file:<filename>/var/log/log.ctdb</filename> or
-	    similar - the prefix may differ depending on how CTDB was
-	    built.  Corresponds to <option>--logging</option>.
+	    default is
+	    file:<filename>/usr/local/var/log/log.ctdb</filename>.
+	    Corresponds to <option>--logging</option>.
 	  </para>
 	  <para>
 	    Valid values are:
@@ -237,7 +238,7 @@
 	      <listitem>
 		<para>
 		  FILENAME where ctdbd will write its log. This is usually
-		  <filename>/var/log/log.ctdb</filename>.
+		  <filename>/usr/local/var/log/log.ctdb</filename>.
 		</para>
 	      </listitem>
 	    </varlistentry>
@@ -316,7 +317,7 @@
 	<listitem>
 	  <para>
 	    Default is <varname>CTDB_BASE</varname>/nodes, so usually
-	    <filename>/etc/ctdb/nodes</filename>.  Corresponds to
+	    <filename>/usr/local/etc/ctdb/nodes</filename>.  Corresponds to
 	    <option>--nlist</option>.
 	  </para>
 	</listitem>
@@ -327,7 +328,7 @@
 	<listitem>
 	  <para>
 	    No default, usually
-	    <filename>/etc/ctdb/notify.sh</filename>.  Corresponds to
+	    <filename>/usr/local/etc/ctdb/notify.sh</filename>.  Corresponds to
 	    <option>--notification-script</option>.
 	  </para>
 	</listitem>
@@ -344,7 +345,7 @@
       </varlistentry>
 
       <varlistentry>
-	<term>CTDB_NODE_ADDRESS=<parameter>FILENAME</parameter></term>
+	<term>CTDB_NODE_ADDRESS=<parameter>IPADDR</parameter></term>
 	<listitem>
 	  <para>
 	    IPADDR is the private IP address that ctdbd will bind to.
@@ -371,7 +372,7 @@
 	<listitem>
 	  <para>
 	    No default, usually
-	    <filename>/etc/ctdb/public_addresses</filename>.
+	    <filename>/usr/local/etc/ctdb/public_addresses</filename>.
 	    Corresponds to <option>--public-addresses</option>.
 	  </para>
 	</listitem>
@@ -419,12 +420,12 @@
 	<term>CTDB_SOCKET=<parameter>FILENAME</parameter></term>
 	<listitem>
 	  <para>
-	    Defaults to <filename>/tmp/ctdb.socket</filename>.
+	    Defaults to <filename>/usr/local/var/run/ctdb/ctdbd.socket</filename>.
 	    Corresponds to <option>--socket</option>.
 	  </para>
 	  <para>
 	    If you change this then you probably want to set this in
-	    root's enviroment (perhaps in a file in
+	    root's environment (perhaps in a file in
 	    <filename>/etc/profile.d</filename>) so that you can use
 	    the <citerefentry><refentrytitle>ctdb</refentrytitle>
 	    <manvolnum>1</manvolnum></citerefentry> command in a
@@ -560,12 +561,23 @@
 	    <para>
 	      File format:
 	      <screen>
-<parameter>IPADDR</parameter>
+<parameter>IPADDR</parameter> <optional>slave-only</optional>
 	      </screen>
 	    </para>
 	    <para>
+	      IPADDR is the private IP address of each node in the NAT
+	      gateway group.
+	    </para>
+	    <para>
+	      If "slave-only" is specified then the corresponding node
+	      can not be the NAT gateway master node.  In this case
+	      <varname>CTDB_NATGW_PUBLIC_IFACE</varname> and
+	      <varname>CTDB_NATGW_PUBLIC_IP</varname> are optional and
+	      unused.
+	    </para>
+	    <para>
 	      No default, usually
-	      <filename>/etc/ctdb/natgw_nodes</filename> when enabled.
+	      <filename>/usr/local/etc/ctdb/natgw_nodes</filename> when enabled.
 	    </para>
 	  </listitem>
 	</varlistentry>
@@ -615,22 +627,6 @@
 	</varlistentry>
 
 	<varlistentry>
-	  <term>CTDB_NATGW_SLAVE_ONLY=yes|no</term>
-	  <listitem>
-	    <para>
-	      When set to "yes" a node can not be a NAT gateway master
-	      node.  In this case
-	      <varname>CTDB_NATGW_PUBLIC_IFACE</varname> and
-	      <varname>CTDB_NATGW_PUBLIC_IP</varname> are optional
-	      and unused.
-	    </para>
-	    <para>
-	      Default is no.
-	    </para>
-	  </listitem>
-	</varlistentry>
-
-	<varlistentry>
 	  <term>CTDB_NATGW_STATIC_ROUTES=<parameter>IPADDR/MASK[@GATEWAY]</parameter> ...</term>
 	  <listitem>
 	    <para>
@@ -671,7 +667,7 @@
       <refsect3>
 	<title>Example</title>
 	<screen>
-CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+CTDB_NATGW_NODES=/usr/local/etc/ctdb/natgw_nodes
 CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24
 CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
 CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
@@ -684,7 +680,7 @@ CTDB_NATGW_PUBLIC_IFACE=eth0
 	  always reachable would look like this:
 	</para>
 	<screen>
-CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+CTDB_NATGW_NODES=/usr/local/etc/ctdb/natgw_nodes
 CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24
 CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
 CTDB_NATGW_PUBLIC_IFACE=eth0
@@ -746,7 +742,7 @@ CTDB_NATGW_STATIC_ROUTES=10.0.0.0/24
 
 	    <para>
 	      No default, usually
-	      <filename>/etc/ctdb/policy_routing</filename> when enabled.
+	      <filename>/usr/local/etc/ctdb/policy_routing</filename> when enabled.
 	    </para>
 	  </listitem>
 	</varlistentry>
@@ -812,7 +808,7 @@ CTDB_NATGW_STATIC_ROUTES=10.0.0.0/24
       <refsect3>
 	<title>Example</title>
 	<screen>
-CTDB_PER_IP_ROUTING_CONF=/etc/ctdb/policy_routing
+CTDB_PER_IP_ROUTING_CONF=/usr/local/etc/ctdb/policy_routing
 CTDB_PER_IP_ROUTING_RULE_PREF=100
 CTDB_PER_IP_ROUTING_TABLE_ID_LOW=1000
 CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
@@ -838,6 +834,13 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
 	    </para>
 
 	    <para>
+	      Note that CTDB_PARTIALLY_ONLINE_INTERFACES=yes is
+	      incompatible with NAT gateway, since NAT gateway relies
+	      on the interface configured by CTDB_NATGW_PUBLIC_IFACE
+	      to be up.
+	    </para>
+
+	    <para>
 	      Default is "no".
 	    </para>
 	  </listitem>
@@ -1279,91 +1282,91 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
 
       <para>
 	CTDB can experience seemingly random (performance and other)
-	issues if system resources become too contrained.  Options in
-	this section can be enabled to allow certain system resources to
-	be checked.
+	issues if system resources become too constrained.  Options in
+	this section can be enabled to allow certain system resources
+	to be checked.  They allows warnings to be logged and nodes to
+	be marked unhealthy when system resource usage reaches the
+	configured thresholds.
+      </para>
+
+      <para>
+	Some checks are enabled by default.  It is recommended that
+	these checks remain enabled or are augmented by extra checks.
+	There is no supported way of completely disabling the checks.
       </para>
 
       <refsect3>
 	<title>Eventscripts</title>
 
 	<simplelist>
-	  <member><filename>00.ctdb</filename></member>
-	  <member><filename>40.fs_use</filename></member>
+	  <member><filename>05.system</filename></member>
 	</simplelist>
 
 	<para>
-	  Filesystem usage monitoring is in
-	  <filename>40.fs_use</filename>.  This eventscript is not
-	  enabled by default.  Use <command>ctdb
-	  enablescript</command> to enable it.
+	  Filesystem and memory usage monitoring is in
+	  <filename>05.system</filename>.
 	</para>
       </refsect3>
 
       <variablelist>
 
 	<varlistentry>
-	  <term>CTDB_CHECK_FS_USE=<parameter>FS-LIMIT-LIST</parameter></term>
+	  <term>CTDB_MONITOR_FILESYSTEM_USAGE=<parameter>FS-LIMIT-LIST</parameter></term>
 	  <listitem>
 	    <para>
 	      FS-LIMIT-LIST is a space-separated list of
-	      <parameter>FILESYSTEM</parameter>:<parameter>LIMIT</parameter>
-	      pairs indicating that a node should be flagged unhealthy
-	      if the space used on FILESYSTEM reaches LIMIT%.
-	    </para>
-
-	    <para>
-	      No default.
+	      <parameter>FILESYSTEM</parameter>:<parameter>WARN_LIMIT</parameter><optional>:<parameter>UNHEALTHY_LIMIT</parameter></optional>
+	      triples indicating that warnings should be logged if the
+	      space used on FILESYSTEM reaches WARN_LIMIT%.  If usage
+	      reaches UNHEALTHY_LIMIT then the node should be flagged
+	      unhealthy.  Either WARN_LIMIT or UNHEALTHY_LIMIT may be
+	      left blank, meaning that check will be omitted.
 	    </para>
 
 	    <para>
-	      Note that this feature uses the
-	      <filename>40.fs_use</filename> eventscript, which is not
-	      enabled by default.  Use <command>ctdb
-	      enablescript</command> to enable it.
+	      Default is to warn for each filesystem containing a
+	      database directory (<envar>CTDB_DBDIR</envar>,
+	      <envar>CTDB_DBDIR_PERSISTENT</envar>,
+	      <envar>CTDB_DBDIR_STATE</envar>) with a threshold of
+	      90%.
 	    </para>
 	  </listitem>
 	</varlistentry>
 
 	<varlistentry>
-	  <term>CTDB_CHECK_SWAP_IS_NOT_USED=yes|no</term>
+	  <term>CTDB_MONITOR_MEMORY_USAGE=<parameter>MEM-LIMITS</parameter></term>
 	  <listitem>
 	    <para>
-	      Should a warning be logged if swap space is in use.
+	      MEM-LIMITS takes the form
+	      <parameter>WARN_LIMIT</parameter><optional>:<parameter>UNHEALTHY_LIMIT</parameter></optional>
+	      indicating that warnings should be logged if memory
+	      usage reaches WARN_LIMIT%.  If usage reaches
+	      UNHEALTHY_LIMIT then the node should be flagged
+	      unhealthy.  Either WARN_LIMIT or UNHEALTHY_LIMIT may be
+	      left blank, meaning that check will be omitted.
 	    </para>
 	    <para>
-	      Default is no.
+	      Default is 80, so warnings will be logged when memory
+	      usage reaches 80%.
 	    </para>
 	  </listitem>
 	</varlistentry>
 
 	<varlistentry>
-	  <term>CTDB_MONITOR_FREE_MEMORY=<parameter>NUM</parameter></term>
+	  <term>CTDB_MONITOR_SWAP_USAGE=<parameter>SWAP-LIMITS</parameter></term>
 	  <listitem>
 	    <para>
-	      NUM is a lower limit on available system memory, expressed
-	      in megabytes.  If this is set and the amount of available
-	      memory falls below this limit then some debug information
-	      will be logged, the node will be disabled and then CTDB
-	      will be shut down.
+	      SWAP-LIMITS takes the form
+	      <parameter>WARN_LIMIT</parameter><optional>:<parameter>UNHEALTHY_LIMIT</parameter></optional>
+	       indicating that warnings should be logged if
+	      swap usage reaches WARN_LIMIT%.  If usage reaches
+	      UNHEALTHY_LIMIT then the node should be flagged
+	      unhealthy.  Either WARN_LIMIT or UNHEALTHY_LIMIT may be
+	      left blank, meaning that check will be omitted.
 	    </para>
 	    <para>
-	      No default.
-	    </para>
-	  </listitem>
-	</varlistentry>
-
-	<varlistentry>
-	  <term>CTDB_MONITOR_FREE_MEMORY_WARN=<parameter>NUM</parameter></term>
-	  <listitem>
-	    <para>
-	      NUM is a lower limit on available system memory, expressed
-	      in megabytes.  If this is set and the amount of available
-	      memory falls below this limit then a warning will be
-	      logged.
-	    </para>
-	    <para>
-	      No default.
+	      Default is 25, so warnings will be logged when swap
+	      usage reaches 25%.
 	    </para>
 	  </listitem>
 	</varlistentry>
@@ -1508,7 +1511,7 @@ CTDB_SET_MonitorInterval=20
       </varlistentry>
 
       <varlistentry>
-	<term>CTDB_ETCDIR=<parameter>DIRECTORY</parameter></term>
+	<term>CTDB_SYS_ETCDIR=<parameter>DIRECTORY</parameter></term>
 	<listitem>
 	  <para>
 	    DIRECTORY containing system configuration files.  This is
@@ -1638,7 +1641,7 @@ CTDB_SET_MonitorInterval=20
 	    <manvolnum>1</manvolnum></citerefentry> to be run under
 	    <citerefentry><refentrytitle>valgrind</refentrytitle>
 	    <manvolnum>1</manvolnum></citerefentry> with logs going to
-	    <filename>/var/log/ctdb_valgrind</filename>.  If neither
+	    <filename>/usr/local/var/log/ctdb_valgrind</filename>.  If neither
 	    "yes" nor "no" then the value is assumed to be a COMMAND
 	    (e.g. a <command>valgrind</command> variation, a
 	    <citerefentry><refentrytitle>gdb</refentrytitle>
@@ -1653,6 +1656,19 @@ CTDB_SET_MonitorInterval=20
 	</listitem>
       </varlistentry>
 
+      <varlistentry>
+	<term>CTDB_VARDIR=<parameter>DIRECTORY</parameter></term>
+	<listitem>
+	  <para>
+	    DIRECTORY containing CTDB files that are modified at
+	    runtime.
+	  </para>
+	  <para>
+	    Defaults to <filename>/usr/local/var/lib/ctdb</filename>.
+	  </para>
+	</listitem>
+      </varlistentry>
+
     </variablelist>
 
   </refsect1>
@@ -1662,10 +1678,10 @@ CTDB_SET_MonitorInterval=20
     <title>FILES</title>
 
     <simplelist>
-      <member><filename>/etc/ctdb/ctdbd.conf</filename></member>
+      <member><filename>/usr/local/etc/ctdb/ctdbd.conf</filename></member>
       <member><filename>/etc/sysconfig/ctdb</filename></member>
       <member><filename>/etc/default/ctdb</filename></member>
-      <member><filename>/etc/ctdb/sysconfig/ctdb</filename></member>
+      <member><filename>/usr/local/etc/ctdb/sysconfig/ctdb</filename></member>
     </simplelist>
   </refsect1>
 
diff --git a/ctdb/doc/ctdbd_wrapper.1 b/ctdb/doc/ctdbd_wrapper.1
index f3670c3..a6a8989 100644
--- a/ctdb/doc/ctdbd_wrapper.1
+++ b/ctdb/doc/ctdbd_wrapper.1
@@ -2,12 +2,12 @@
 .\"     Title: ctdbd_wrapper
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDBD_WRAPPER" "1" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDBD_WRAPPER" "1" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/ctdb/doc/ctdbd_wrapper.1.html b/ctdb/doc/ctdbd_wrapper.1.html
index a1b6613..7f5ed21 100644
--- a/ctdb/doc/ctdbd_wrapper.1.html
+++ b/ctdb/doc/ctdbd_wrapper.1.html
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd_wrapper</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdbd_wrapper.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd_wrapper — Wrapper for ctdbd</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class= [...]
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd_wrapper</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdbd_wrapper.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd_wrapper — Wrapper for ctdbd</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class= [...]
       ctdbd_wrapper is used to start or stop the main CTDB daemon.
     </p><p>
       <em class="replaceable"><code>PIDFILE</code></em> specifies the location of the
@@ -9,7 +9,7 @@
       <span class="citerefentry"><span class="refentrytitle">ctdbd.conf</span>(5)</span>.
     </p><p>
       See <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for an overview of CTDB.
-    </p></div><div class="refsect1"><a name="idp53317216"></a><h2>SEE ALSO</h2><p>
+    </p></div><div class="refsect1"><a name="idp49551120"></a><h2>SEE ALSO</h2><p>
       <span class="citerefentry"><span class="refentrytitle">ctdbd</span>(1)</span>,
 
       <span class="citerefentry"><span class="refentrytitle">ctdbd.conf</span>(5)</span>,
diff --git a/ctdb/doc/ltdbtool.1 b/ctdb/doc/ltdbtool.1
index c408672..c16fa66 100644
--- a/ctdb/doc/ltdbtool.1
+++ b/ctdb/doc/ltdbtool.1
@@ -2,12 +2,12 @@
 .\"     Title: ltdbtool
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "LTDBTOOL" "1" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "LTDBTOOL" "1" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/ctdb/doc/ltdbtool.1.html b/ctdb/doc/ltdbtool.1.html
index 391df38..9b3ee59 100644
--- a/ctdb/doc/ltdbtool.1.html
+++ b/ctdb/doc/ltdbtool.1.html
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ltdbtool</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ltdbtool.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ltdbtool — manipulate CTDB's local TDB files</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class [...]
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ltdbtool</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ltdbtool.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ltdbtool — manipulate CTDB's local TDB files</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class [...]
       ltdbtool is a utility to manipulate CTDB's local TDB databases
       (LTDBs) without connecting to a CTDB daemon.
     </p><p>
@@ -11,7 +11,7 @@
 	  by adding or removing CTDB headers and
 	</p></li><li class="listitem"><p>convert between 64 and 32 bit LTDBs where the CTDB record
 	  headers differ by 4 bytes of padding.
-	  </p></li></ul></div></div><div class="refsect1"><a name="idp52723440"></a><h2>OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-e</span></dt><dd><p>
+	  </p></li></ul></div></div><div class="refsect1"><a name="idp52740656"></a><h2>OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-e</span></dt><dd><p>
 	    Dump empty records.  These are normally excluded.
 	  </p></dd><dt><span class="term">-p</span></dt><dd><p>
 	    Dump with header information, similar to "ctdb catdb".
@@ -37,7 +37,7 @@
 	    output database in bytes.
 	  </p></dd><dt><span class="term">-h</span></dt><dd><p>
             Print help text.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp52226512"></a><h2>COMMANDS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">help</span></dt><dd><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp53957568"></a><h2>COMMANDS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">help</span></dt><dd><p>
 	    Print help text.
 	  </p></dd><dt><span class="term">dump <em class="parameter"><code>IDB</code></em></span></dt><dd><p>
 	    Dump the contents of an LTDB input file IDB to standard
@@ -47,7 +47,7 @@
 	</span></dt><dd><p>
 	    Copy an LTDB input file IDB to output file ODB, optionally
 	    adding or removing CTDB headers.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp52657920"></a><h2>EXAMPLES</h2><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp49118400"></a><h2>EXAMPLES</h2><p>
       Print a local tdb in "tdbdump" style:
     </p><pre class="screen">
       ltdbtool dump idmap2.tdb.0
@@ -75,7 +75,7 @@
       Add a default header:
     </p><pre class="screen">
       ltdbtool convert -s0 idmap.tdb idmap2.tdb.0
-    </pre></div><div class="refsect1"><a name="idp54544544"></a><h2>SEE ALSO</h2><p>
+    </pre></div><div class="refsect1"><a name="idp49126576"></a><h2>SEE ALSO</h2><p>
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span>,
 
       <span class="citerefentry"><span class="refentrytitle">tdbdump</span>(1)</span>,
diff --git a/ctdb/doc/onnode.1 b/ctdb/doc/onnode.1
index 5076710..026cf75 100644
--- a/ctdb/doc/onnode.1
+++ b/ctdb/doc/onnode.1
@@ -2,12 +2,12 @@
 .\"     Title: onnode
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "ONNODE" "1" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "ONNODE" "1" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -52,8 +52,8 @@ Execute COMMAND in the current working directory on the specified nodes\&.
 .PP
 \-f \fIFILENAME\fR
 .RS 4
-Specify an alternative nodes FILENAME to use instead of the default\&. This option overrides the CTDB_NODES_FILE environment variable\&. See the discussion of
-/etc/ctdb/nodes
+Specify an alternative nodes FILENAME to use instead of the default\&. This option overrides the CTDB_NODES_FILE and CTDB_NODES variables\&. See the discussion of
+/usr/local/etc/ctdb/nodes
 in the FILES section for more details\&.
 .RE
 .PP
@@ -162,7 +162,7 @@ The following command would show the last 5 lines of log on each node, preceded
 .RS 4
 .\}
 .nf
-      onnode all "hostname; tail \-5 /var/log/log\&.ctdb"
+      onnode all "hostname; tail \-5 /usr/local/var/log/log\&.ctdb"
     
 .fi
 .if n \{\
@@ -199,7 +199,7 @@ The following command would run \&./foo in the current working directory, in par
 \fBCTDB_BASE\fR
 .RS 4
 Directory containing CTDB configuration files\&. The default is
-/etc/ctdb\&.
+/usr/local/etc/ctdb\&.
 .RE
 .PP
 \fBCTDB_NODES_FILE\fR
@@ -210,21 +210,34 @@ section for more details\&.
 .RE
 .SH "FILES"
 .PP
-/etc/ctdb/nodes
+/usr/local/etc/ctdb/nodes
 .RS 4
 Default file containing a list of each node\*(Aqs IP address or hostname\&.
 .sp
-Actually, the default is
+As above, a file specified via the
+\fB\-f\fR
+or
+\fBCTDB_NODES_FILE\fR
+is given precedence\&. If a relative path is specified and no corresponding file exists relative to the current directory then the file is also searched for in the
+$CTDB_BASE
+directory\&.
+.sp
+If
+\fBCTDB_NODES_FILE\fR
+is not set and
+\fBCTDB_NODES\fR
+is set in configuration then the file pointed to by
+\fBCTDB_NODES\fR
+is used\&.
+.sp
+Otherwise the default is
 $CTDB_BASE/nodes, where
 \fBCTDB_BASE\fR
 defaults to
-/etc/ctdb\&. If a relative path is given (via the \-f option or
-\fBCTDB_BASE\fR) and no corresponding file exists relative to the current directory then the file is also searched for in the
-$CTDB_BASE
-directory\&.
+/usr/local/etc/ctdb\&.
 .RE
 .PP
-/etc/ctdb/onnode\&.conf
+/usr/local/etc/ctdb/onnode\&.conf
 .RS 4
 If this file exists it is sourced by onnode\&. The main purpose is to allow the administrator to set
 \fBSSH\fR
diff --git a/ctdb/doc/onnode.1.html b/ctdb/doc/onnode.1.html
index e3c7461..d91bed2 100644
--- a/ctdb/doc/onnode.1.html
+++ b/ctdb/doc/onnode.1.html
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>onnode</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="onnode.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>onnode — run commands on CTDB cluster nodes</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmd [...]
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>onnode</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="onnode.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>onnode — run commands on CTDB cluster nodes</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmd [...]
       onnode is a utility to run commands on a specific node of a CTDB
       cluster, or on all nodes.
     </p><p>
@@ -9,14 +9,14 @@
       <em class="replaceable"><code>COMMAND</code></em> can be any shell command. The
       onnode utility uses ssh or rsh to connect to the remote nodes
       and run the command.
-    </p></div><div class="refsect1"><a name="idp54651424"></a><h2>OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-c</span></dt><dd><p>
+    </p></div><div class="refsect1"><a name="idp52824016"></a><h2>OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-c</span></dt><dd><p>
             Execute COMMAND in the current working directory on the
             specified nodes.
 	  </p></dd><dt><span class="term">-f <em class="parameter"><code>FILENAME</code></em></span></dt><dd><p>
             Specify an alternative nodes FILENAME to use instead of
             the default.  This option overrides the CTDB_NODES_FILE
-            environment variable.  See the discussion of
-            <code class="filename">/etc/ctdb/nodes</code> in the FILES section
+            and CTDB_NODES variables.  See the discussion of
+            <code class="filename">/usr/local/etc/ctdb/nodes</code> in the FILES section
             for more details.
 	  </p></dd><dt><span class="term">-i</span></dt><dd><p>
 	    Keep standard input open, allowing data to be piped to
@@ -49,7 +49,7 @@
             more than one node is specified.
 	  </p></dd><dt><span class="term">-h, --help</span></dt><dd><p>
             Show a short usage guide.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp53082368"></a><h2>NODES SPECIFICATION</h2><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp53951872"></a><h2>NODES SPECIFICATION</h2><p>
       Nodes can be specified via numeric node numbers (from 0 to N-1)
       or mnemonics.  Multiple nodes are specified using lists of
       nodes, separated by commas, and ranges of numeric node numbers,
@@ -74,7 +74,7 @@
             The current NAT gateway.
 	  </p></dd><dt><span class="term">rm | recmaster</span></dt><dd><p>
             The current recovery master.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp51121440"></a><h2>EXAMPLES</h2><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp49117664"></a><h2>EXAMPLES</h2><p>
       The following command would show the process ID of ctdbd on all nodes
     </p><pre class="screen">
       onnode all ctdb getpid
@@ -82,7 +82,7 @@
       The following command would show the last 5 lines of log on each
       node, preceded by the node's hostname
     </p><pre class="screen">
-      onnode all "hostname; tail -5 /var/log/log.ctdb"
+      onnode all "hostname; tail -5 /usr/local/var/log/log.ctdb"
     </pre><p>
       The following command would restart the ctdb service on all
       nodes, in parallel.
@@ -93,32 +93,39 @@
       directory, in parallel, on nodes 0, 2, 3 and 4.
     </p><pre class="screen">
       onnode -c -p 0,2-4 ./foo
-    </pre></div><div class="refsect1"><a name="idp52830032"></a><h2>ENVIRONMENT</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="envar">CTDB_BASE</code></span></dt><dd><p>
+    </pre></div><div class="refsect1"><a name="idp49123120"></a><h2>ENVIRONMENT</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="envar">CTDB_BASE</code></span></dt><dd><p>
 	    Directory containing CTDB configuration files.  The
-	    default is <code class="filename">/etc/ctdb</code>.
+	    default is <code class="filename">/usr/local/etc/ctdb</code>.
 	  </p></dd><dt><span class="term"><code class="envar">CTDB_NODES_FILE</code></span></dt><dd><p>
 	    Name of alternative nodes file to use instead of the
 	    default.  See the <em class="citetitle">FILES</em> section for
 	    more details.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp51106640"></a><h2>FILES</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="filename">/etc/ctdb/nodes</code></span></dt><dd><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp49128624"></a><h2>FILES</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="filename">/usr/local/etc/ctdb/nodes</code></span></dt><dd><p>
             Default file containing a list of each node's IP address
             or hostname.
 	  </p><p>
-	    Actually, the default is
+	    As above, a file specified via the <code class="option">-f</code> or
+	    <code class="envar">CTDB_NODES_FILE</code> is given precedence.  If a
+	    relative path is specified and no corresponding file
+	    exists relative to the current directory then the file is
+	    also searched for in the <code class="filename">$CTDB_BASE</code>
+	    directory.
+	  </p><p>
+	    If <code class="envar">CTDB_NODES_FILE</code> is not set and
+	    <code class="envar">CTDB_NODES</code> is set in configuration then the
+	    file pointed to by <code class="envar">CTDB_NODES</code> is used.
+	  </p><p>
+	    Otherwise the default is
 	    <code class="filename">$CTDB_BASE/nodes</code>, where
 	    <code class="envar">CTDB_BASE</code> defaults to
-	    <code class="filename">/etc/ctdb</code>.  If a relative path is
-	    given (via the -f option or <code class="envar">CTDB_BASE</code>) and
-	    no corresponding file exists relative to the current
-	    directory then the file is also searched for in the
-	    <code class="filename">$CTDB_BASE</code> directory.
-	  </p></dd><dt><span class="term"><code class="filename">/etc/ctdb/onnode.conf</code></span></dt><dd><p>
+	    <code class="filename">/usr/local/etc/ctdb</code>.
+          </p></dd><dt><span class="term"><code class="filename">/usr/local/etc/ctdb/onnode.conf</code></span></dt><dd><p>
             If this file exists it is sourced by onnode.  The main
             purpose is to allow the administrator to set
             <code class="envar">SSH</code> to something other than "ssh".  In this
             case the -t option is ignored.  For example, the
             administrator may choose to use use rsh instead of ssh.
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp54619408"></a><h2>SEE ALSO</h2><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp49145264"></a><h2>SEE ALSO</h2><p>
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span>,
 
       <a class="ulink" href="http://ctdb.samba.org/" target="_top">http://ctdb.samba.org/</a>
diff --git a/ctdb/doc/onnode.1.xml b/ctdb/doc/onnode.1.xml
index ec87803..02898d2 100644
--- a/ctdb/doc/onnode.1.xml
+++ b/ctdb/doc/onnode.1.xml
@@ -61,8 +61,8 @@
           <para>
             Specify an alternative nodes FILENAME to use instead of
             the default.  This option overrides the CTDB_NODES_FILE
-            environment variable.  See the discussion of
-            <filename>/etc/ctdb/nodes</filename> in the FILES section
+            and CTDB_NODES variables.  See the discussion of
+            <filename>/usr/local/etc/ctdb/nodes</filename> in the FILES section
             for more details.
 	  </para>
         </listitem>
@@ -235,7 +235,7 @@
       node, preceded by the node's hostname
     </para>
     <screen format="linespecific">
-      onnode all "hostname; tail -5 /var/log/log.ctdb"
+      onnode all "hostname; tail -5 /usr/local/var/log/log.ctdb"
     </screen>
 
     <para>
@@ -263,7 +263,7 @@
         <listitem>
           <para>
 	    Directory containing CTDB configuration files.  The
-	    default is <filename>/etc/ctdb</filename>.
+	    default is <filename>/usr/local/etc/ctdb</filename>.
 	  </para>
         </listitem>
       </varlistentry>
@@ -285,26 +285,35 @@
     <title>FILES</title>
 
     <variablelist>
-      <varlistentry><term><filename>/etc/ctdb/nodes</filename></term>
+      <varlistentry><term><filename>/usr/local/etc/ctdb/nodes</filename></term>
         <listitem>
           <para>
             Default file containing a list of each node's IP address
             or hostname.
 	  </para>
 	  <para>
-	    Actually, the default is
+	    As above, a file specified via the <option>-f</option> or
+	    <envar>CTDB_NODES_FILE</envar> is given precedence.  If a
+	    relative path is specified and no corresponding file
+	    exists relative to the current directory then the file is
+	    also searched for in the <filename>$CTDB_BASE</filename>
+	    directory.
+	  </para>
+	  <para>
+	    If <envar>CTDB_NODES_FILE</envar> is not set and
+	    <envar>CTDB_NODES</envar> is set in configuration then the
+	    file pointed to by <envar>CTDB_NODES</envar> is used.
+	  </para>
+	  <para>
+	    Otherwise the default is
 	    <filename>$CTDB_BASE/nodes</filename>, where
 	    <envar>CTDB_BASE</envar> defaults to
-	    <filename>/etc/ctdb</filename>.  If a relative path is
-	    given (via the -f option or <envar>CTDB_BASE</envar>) and
-	    no corresponding file exists relative to the current
-	    directory then the file is also searched for in the
-	    <filename>$CTDB_BASE</filename> directory.
-	  </para>
-        </listitem>
+	    <filename>/usr/local/etc/ctdb</filename>.
+          </para>
+	</listitem>
       </varlistentry>
 
-      <varlistentry><term><filename>/etc/ctdb/onnode.conf</filename></term>
+      <varlistentry><term><filename>/usr/local/etc/ctdb/onnode.conf</filename></term>
         <listitem>
           <para>
             If this file exists it is sourced by onnode.  The main
diff --git a/ctdb/doc/ping_pong.1 b/ctdb/doc/ping_pong.1
index 69da9aa..db3b197 100644
--- a/ctdb/doc/ping_pong.1
+++ b/ctdb/doc/ping_pong.1
@@ -2,12 +2,12 @@
 .\"     Title: ping_pong
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2015
+.\"      Date: 01/27/2016
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "PING_PONG" "1" "12/10/2015" "ctdb" "CTDB \- clustered TDB database"
+.TH "PING_PONG" "1" "01/27/2016" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/ctdb/doc/ping_pong.1.html b/ctdb/doc/ping_pong.1.html
index 16a2863..9562c67 100644
--- a/ctdb/doc/ping_pong.1.html
+++ b/ctdb/doc/ping_pong.1.html
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ping_pong</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ping_pong.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ping_pong — measures the ping-pong byte range lock latency</p></div><div class="refsynopsisdiv"><h2>Synopsi [...]
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ping_pong</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ping_pong.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ping_pong — measures the ping-pong byte range lock latency</p></div><div class="refsynopsisdiv"><h2>Synopsi [...]
       ping_pong measures the byte range lock latency. It is especially
       useful on a cluster of nodes sharing a common lock manager as it
       will give some indication of the lock manager's performance
@@ -9,7 +9,7 @@
     </p><p>
       NUM-LOCKS is the number of byte range locks, so needs to be
       (strictly) greater than the number of nodes in the cluster.
-    </p></div><div class="refsect1"><a name="idp50142544"></a><h2>OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-r</span></dt><dd><p>
+    </p></div><div class="refsect1"><a name="idp51929904"></a><h2>OPTIONS</h2><div class="variablelist"><dl class="variablelist"><dt><span class="term">-r</span></dt><dd><p>
 	    test read performance
 	  </p></dd><dt><span class="term">-w</span></dt><dd><p>
 	    test write performance
@@ -17,7 +17,7 @@
 	    use mmap
 	  </p></dd><dt><span class="term">-c</span></dt><dd><p>
 	    validate the locks
-	  </p></dd></dl></div></div><div class="refsect1"><a name="idp53880944"></a><h2>EXAMPLES</h2><p>
+	  </p></dd></dl></div></div><div class="refsect1"><a name="idp49227968"></a><h2>EXAMPLES</h2><p>
       Testing lock coherence
     </p><pre class="screen">
       ping_pong test.dat N
@@ -29,7 +29,7 @@
       Testing IO coherence
     </p><pre class="screen">
       ping_pong -rw test.dat N
-    </pre></div><div class="refsect1"><a name="idp53885104"></a><h2>SEE ALSO</h2><p>
+    </pre></div><div class="refsect1"><a name="idp53939216"></a><h2>SEE ALSO</h2><p>
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span>,
 
       <a class="ulink" href="https://wiki.samba.org/index.php/Ping_pong" target="_top">https://wiki.samba.org/index.php/Ping_pong</a>
diff --git a/ctdb/ib/ibw_ctdb.c b/ctdb/ib/ibw_ctdb.c
index 2e70d1d..458646f 100644
--- a/ctdb/ib/ibw_ctdb.c
+++ b/ctdb/ib/ibw_ctdb.c
@@ -20,10 +20,21 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "includes.h"
-#include <system/network.h>
+#include "replace.h"
+#include "system/network.h"
+
 #include <assert.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/time.h"
+#include "lib/util/debug.h"
+
 #include "ctdb_private.h"
+
+#include "common/common.h"
+#include "common/logging.h"
+
 #include "ibwrapper.h"
 #include "ibw_ctdb.h"
 
@@ -49,30 +60,23 @@ int ctdb_ibw_node_connect(struct ctdb_node *node)
 
 	assert(cn!=NULL);
 	assert(cn->conn!=NULL);
-	struct sockaddr_in sock_out;
-
-	memset(&sock_out, 0, sizeof(struct sockaddr_in));
-	sock_out.sin_port = htons(node->address.port);
-	sock_out.sin_family = PF_INET;
-	if (ctdb_ibw_get_address(node->ctdb, node->address.address, &sock_out.sin_addr)) {
-		DEBUG(DEBUG_ERR, ("ctdb_ibw_node_connect failed\n"));
-		return -1;
-	}
 
-	rc = ibw_connect(cn->conn, &sock_out, node);
+	rc = ibw_connect(cn->conn, &node->address.ip, node);
 	if (rc) {
 		DEBUG(DEBUG_ERR, ("ctdb_ibw_node_connect/ibw_connect failed - retrying...\n"));
 		/* try again once a second */
-		event_add_timed(node->ctdb->ev, node, timeval_current_ofs(1, 0), 
-			ctdb_ibw_node_connect_event, node);
+		tevent_add_timer(node->ctdb->ev, node,
+				 timeval_current_ofs(1, 0),
+				 ctdb_ibw_node_connect_event, node);
 	}
 
 	/* continues at ibw_ctdb.c/IBWC_CONNECTED in good case */
 	return 0;
 }
 
-void ctdb_ibw_node_connect_event(struct event_context *ev, struct timed_event *te, 
-	struct timeval t, void *private_data)
+void ctdb_ibw_node_connect_event(struct tevent_context *ev,
+				 struct tevent_timer *te,
+				 struct timeval t, void *private_data)
 {
 	struct ctdb_node *node = talloc_get_type(private_data, struct ctdb_node);
 
@@ -138,8 +142,9 @@ int ctdb_ibw_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn)
 				DEBUG(DEBUG_DEBUG, ("IBWC_ERROR, reconnecting...\n"));
 				talloc_free(cn->conn); /* internal queue content is destroyed */
 				cn->conn = (void *)ibw_conn_new(ictx, node);
-				event_add_timed(node->ctdb->ev, node, timeval_current_ofs(1, 0),
-					ctdb_ibw_node_connect_event, node);
+				tevent_add_timer(node->ctdb->ev, node,
+						 timeval_current_ofs(1, 0),
+						 ctdb_ibw_node_connect_event, node);
 			}
 		} break;
 		default:
diff --git a/ctdb/ib/ibw_ctdb.h b/ctdb/ib/ibw_ctdb.h
index 98ea102..57f659b 100644
--- a/ctdb/ib/ibw_ctdb.h
+++ b/ctdb/ib/ibw_ctdb.h
@@ -42,8 +42,9 @@ int ctdb_ibw_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn);
 int ctdb_ibw_receive_handler(struct ibw_conn *conn, void *buf, int n);
 
 int ctdb_ibw_node_connect(struct ctdb_node *node);
-void ctdb_ibw_node_connect_event(struct event_context *ev, struct timed_event *te, 
-	struct timeval t, void *private_data);
+void ctdb_ibw_node_connect_event(struct tevent_context *ev,
+				 struct tevent_timer *te,
+				 struct timeval t, void *private_data);
 
 int ctdb_flush_cn_queue(struct ctdb_ibw_node *cn);
 
diff --git a/ctdb/ib/ibw_ctdb_init.c b/ctdb/ib/ibw_ctdb_init.c
index 63deff2..7e77ec0 100644
--- a/ctdb/ib/ibw_ctdb_init.c
+++ b/ctdb/ib/ibw_ctdb_init.c
@@ -20,27 +20,31 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "includes.h"
-#include <system/network.h>
+#include "replace.h"
+#include "system/network.h"
+
 #include <assert.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+
 #include "ctdb_private.h"
+
+#include "common/common.h"
+#include "common/logging.h"
+
 #include "ibwrapper.h"
 #include "ibw_ctdb.h"
-#include "lib/util/dlinklist.h"
 
 static int ctdb_ibw_listen(struct ctdb_context *ctdb, int backlog)
 {
 	struct ibw_ctx *ictx = talloc_get_type(ctdb->private_data, struct ibw_ctx);
-	struct sockaddr_in my_addr;
 
 	assert(ictx!=NULL);
-	memset(&my_addr, 0, sizeof(struct sockaddr_in));
-	my_addr.sin_port = htons(ctdb->address.port);
-	my_addr.sin_family = PF_INET;
-	if (ctdb_ibw_get_address(ctdb, ctdb->address.address, &my_addr.sin_addr))
-		return -1;
 
-	if (ibw_bind(ictx, &my_addr)) {
+	if (ibw_bind(ictx, &ctdb->address->ip)) {
 		DEBUG(DEBUG_CRIT, ("ctdb_ibw_listen: ibw_bind failed\n"));
 		return -1;
 	}
@@ -105,7 +109,7 @@ static int ctdb_ibw_start(struct ctdb_context *ctdb)
 	/* everything async here */
 	for (i=0;i<ctdb->num_nodes;i++) {
 		struct ctdb_node *node = ctdb->nodes[i];
-		if (!ctdb_same_address(&ctdb->address, &node->address)) {
+		if (!ctdb_same_address(ctdb->address, &node->address)) {
 			ctdb_ibw_node_connect(node);
 		}
 	}
diff --git a/ctdb/ib/ibwrapper.c b/ctdb/ib/ibwrapper.c
index 51d39da..b10aaf5 100644
--- a/ctdb/ib/ibwrapper.c
+++ b/ctdb/ib/ibwrapper.c
@@ -20,28 +20,24 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <malloc.h>
+#include "replace.h"
+#include "system/network.h"
+
 #include <assert.h>
-#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
 
-#include "includes.h"
-#include "ibwrapper.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+
+#include "common/logging.h"
 
 #include <infiniband/kern-abi.h>
 #include <rdma/rdma_cma_abi.h>
 #include <rdma/rdma_cma.h>
 
+#include "ibwrapper.h"
 #include "ibwrapper_internal.h"
-#include "lib/util/dlinklist.h"
 
 #define IBW_LASTERR_BUFSIZE 512
 static char ibw_lasterr[IBW_LASTERR_BUFSIZE];
@@ -51,8 +47,8 @@ static char ibw_lasterr[IBW_LASTERR_BUFSIZE];
 #define IBW_RECV_BUFSIZE 256
 #define IBW_RECV_THRESHOLD (1 * 1024 * 1024)
 
-static void ibw_event_handler_verbs(struct event_context *ev,
-	struct fd_event *fde, uint16_t flags, void *private_data);
+static void ibw_event_handler_verbs(struct tevent_context *ev,
+	struct tevent_fd *fde, uint16_t flags, void *private_data);
 static int ibw_fill_cq(struct ibw_conn *conn);
 static int ibw_wc_recv(struct ibw_conn *conn, struct ibv_wc *wc);
 static int ibw_wc_send(struct ibw_conn *conn, struct ibv_wc *wc);
@@ -263,8 +259,8 @@ static int ibw_setup_cq_qp(struct ibw_conn *conn)
 	}
 	DEBUG(DEBUG_DEBUG, ("created channel %p\n", pconn->verbs_channel));
 
-	pconn->verbs_channel_event = event_add_fd(pctx->ectx, NULL, /* not pconn or conn */
-		pconn->verbs_channel->fd, EVENT_FD_READ, ibw_event_handler_verbs, conn);
+	pconn->verbs_channel_event = tevent_add_fd(pctx->ectx, NULL, /* not pconn or conn */
+		pconn->verbs_channel->fd, TEVENT_FD_READ, ibw_event_handler_verbs, conn);
 
 	pconn->pd = ibv_alloc_pd(pconn->cm_id->verbs);
 	if (!pconn->pd) {
@@ -410,8 +406,8 @@ static int ibw_manage_connect(struct ibw_conn *conn)
 	return rc;
 }
 
-static void ibw_event_handler_cm(struct event_context *ev,
-	struct fd_event *fde, uint16_t flags, void *private_data)
+static void ibw_event_handler_cm(struct tevent_context *ev,
+	struct tevent_fd *fde, uint16_t flags, void *private_data)
 {
 	int	rc;
 	struct ibw_ctx	*ctx = talloc_get_type(private_data, struct ibw_ctx);
@@ -581,8 +577,8 @@ error:
 	return;
 }
 
-static void ibw_event_handler_verbs(struct event_context *ev,
-	struct fd_event *fde, uint16_t flags, void *private_data)
+static void ibw_event_handler_verbs(struct tevent_context *ev,
+	struct tevent_fd *fde, uint16_t flags, void *private_data)
 {
 	struct ibw_conn	*conn = talloc_get_type(private_data, struct ibw_conn);
 	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
@@ -938,7 +934,7 @@ struct ibw_ctx *ibw_init(struct ibw_initattr *attr, int nattr,
 	void *ctx_userdata,
 	ibw_connstate_fn_t ibw_connstate,
 	ibw_receive_fn_t ibw_receive,
-	struct event_context *ectx)
+	struct tevent_context *ectx)
 {
 	struct ibw_ctx *ctx = talloc_zero(NULL, struct ibw_ctx);
 	struct ibw_ctx_priv *pctx;
@@ -975,8 +971,8 @@ struct ibw_ctx *ibw_init(struct ibw_initattr *attr, int nattr,
 		goto cleanup;
 	}
 
-	pctx->cm_channel_event = event_add_fd(pctx->ectx, pctx,
-		pctx->cm_channel->fd, EVENT_FD_READ, ibw_event_handler_cm, ctx);
+	pctx->cm_channel_event = tevent_add_fd(pctx->ectx, pctx,
+		pctx->cm_channel->fd, TEVENT_FD_READ, ibw_event_handler_cm, ctx);
 
 #if RDMA_USER_CM_MAX_ABI_VERSION >= 2
 	rc = rdma_create_id(pctx->cm_channel, &pctx->cm_id, ctx, RDMA_PS_TCP);
diff --git a/ctdb/ib/ibwrapper.h b/ctdb/ib/ibwrapper.h
index 0b880b3..d5cdc60 100644
--- a/ctdb/ib/ibwrapper.h
+++ b/ctdb/ib/ibwrapper.h
@@ -106,7 +106,7 @@ struct ibw_ctx *ibw_init(struct ibw_initattr *attr, int nattr,
 	void *ctx_userdata,
 	ibw_connstate_fn_t ibw_connstate,
 	ibw_receive_fn_t ibw_receive,
-	struct event_context *ectx);
+	struct tevent_context *ectx);
 
 /*
  * Must be called in states of (IBWS_ERROR, IBWS_READY, IBWS_CONNECT_REQUEST)
diff --git a/ctdb/ib/ibwrapper_internal.h b/ctdb/ib/ibwrapper_internal.h
index 20aef7f..b8100a8 100644
--- a/ctdb/ib/ibwrapper_internal.h
+++ b/ctdb/ib/ibwrapper_internal.h
@@ -45,14 +45,14 @@ struct ibw_wr {
 };
 
 struct ibw_ctx_priv {
-	struct event_context *ectx;
+	struct tevent_context *ectx;
 
 	struct ibw_opts opts;
 
 	struct rdma_cm_id	*cm_id; /* server cm id */
 
 	struct rdma_event_channel *cm_channel;
-	struct fd_event *cm_channel_event;
+	struct tevent_fd *cm_channel_event;
 
 	ibw_connstate_fn_t connstate_func; /* see ibw_init */
 	ibw_receive_fn_t receive_func; /* see ibw_init */
@@ -69,7 +69,7 @@ struct ibw_part {
 
 struct ibw_conn_priv {
 	struct ibv_comp_channel *verbs_channel;
-	struct fd_event *verbs_channel_event;
+	struct tevent_fd *verbs_channel_event;
 
 	struct rdma_cm_id *cm_id; /* client's cm id */
 	struct ibv_pd	*pd;
diff --git a/ctdb/ib/ibwrapper_test.c b/ctdb/ib/ibwrapper_test.c
index 397fdf1..eaa14fb 100644
--- a/ctdb/ib/ibwrapper_test.c
+++ b/ctdb/ib/ibwrapper_test.c
@@ -20,23 +20,19 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <malloc.h>
+#include "replace.h"
+#include "system/network.h"
+#include "system/time.h"
+
 #include <assert.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <time.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/time.h"
+#include "lib/util/debug.h"
+
+#include "common/logging.h"
 
-#include "includes.h"
 #include "ib/ibwrapper.h"
 
 struct ibwtest_ctx {
@@ -77,7 +73,7 @@ enum testopcode {
 	TESTOP_SEND_RND = 3
 };
 
-int ibwtest_connect_everybody(struct ibwtest_ctx *tcx)
+static int ibwtest_connect_everybody(struct ibwtest_ctx *tcx)
 {
 	struct ibw_conn		*conn;
 	struct ibwtest_conn	*tconn = talloc_zero(tcx, struct ibwtest_conn);
@@ -95,7 +91,7 @@ int ibwtest_connect_everybody(struct ibwtest_ctx *tcx)
 	return 0;
 }
 
-int ibwtest_send_id(struct ibw_conn *conn)
+static int ibwtest_send_id(struct ibw_conn *conn)
 {
 	struct ibwtest_ctx *tcx = talloc_get_type(conn->ctx->ctx_userdata, struct ibwtest_ctx);
 	char *buf;
@@ -123,7 +119,7 @@ int ibwtest_send_id(struct ibw_conn *conn)
 	return 0;
 }
 
-int ibwtest_send_test_msg(struct ibwtest_ctx *tcx, struct ibw_conn *conn, const char *msg)
+static int ibwtest_send_test_msg(struct ibwtest_ctx *tcx, struct ibw_conn *conn, const char *msg)
 {
 	char *buf, *p;
 	void *key;
@@ -154,7 +150,7 @@ int ibwtest_send_test_msg(struct ibwtest_ctx *tcx, struct ibw_conn *conn, const
 	return 0;
 }
 
-unsigned char ibwtest_fill_random(unsigned char *buf, uint32_t size)
+static unsigned char ibwtest_fill_random(unsigned char *buf, uint32_t size)
 {
 	uint32_t	i = size;
 	unsigned char	sum = 0;
@@ -168,7 +164,7 @@ unsigned char ibwtest_fill_random(unsigned char *buf, uint32_t size)
 	return sum;
 }
 
-unsigned char ibwtest_get_sum(unsigned char *buf, uint32_t size)
+static unsigned char ibwtest_get_sum(unsigned char *buf, uint32_t size)
 {
 	uint32_t	i = size;
 	unsigned char	sum = 0;
@@ -180,7 +176,7 @@ unsigned char ibwtest_get_sum(unsigned char *buf, uint32_t size)
 	return sum;
 }
 
-int ibwtest_do_varsize_scenario_conn_size(struct ibwtest_ctx *tcx, struct ibw_conn *conn, uint32_t size)
+static int ibwtest_do_varsize_scenario_conn_size(struct ibwtest_ctx *tcx, struct ibw_conn *conn, uint32_t size)
 {
 	unsigned char *buf;
 	void	*key;
@@ -205,7 +201,7 @@ int ibwtest_do_varsize_scenario_conn_size(struct ibwtest_ctx *tcx, struct ibw_co
 	return 0;
 }
 
-int ibwtest_do_varsize_scenario_conn(struct ibwtest_ctx *tcx, struct ibw_conn *conn)
+static int ibwtest_do_varsize_scenario_conn(struct ibwtest_ctx *tcx, struct ibw_conn *conn)
 {
 	uint32_t	size;
 	int	i;
@@ -234,7 +230,7 @@ int ibwtest_do_varsize_scenario_conn(struct ibwtest_ctx *tcx, struct ibw_conn *c
 	}
 }*/
 
-int ibwtest_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn)
+static int ibwtest_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn)
 {
 	struct ibwtest_ctx	*tcx = NULL; /* userdata */
 	struct ibwtest_conn	*tconn = NULL; /* userdata */
@@ -298,7 +294,7 @@ int ibwtest_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn)
 	return 0;
 }
 
-int ibwtest_receive_handler(struct ibw_conn *conn, void *buf, int n)
+static int ibwtest_receive_handler(struct ibw_conn *conn, void *buf, int n)
 {
 	struct ibwtest_conn *tconn;
 	enum testopcode op;
@@ -375,8 +371,9 @@ error:
 	return -1;
 }
 
-void ibwtest_timeout_handler(struct event_context *ev, struct timed_event *te, 
-	struct timeval t, void *private_data)
+static void ibwtest_timeout_handler(struct tevent_context *ev,
+				    struct tevent_timer *te,
+				    struct timeval t, void *private_data)
 {
 	struct ibwtest_ctx *tcx = talloc_get_type(private_data, struct ibwtest_ctx);
 	int	rc;
@@ -401,7 +398,7 @@ void ibwtest_timeout_handler(struct event_context *ev, struct timed_event *te,
 
 static struct ibwtest_ctx *testctx = NULL;
 
-void ibwtest_sigint_handler(int sig)
+static void ibwtest_sigint_handler(int sig)
 {
 	DEBUG(DEBUG_ERR, ("got SIGINT\n"));
 	if (testctx) {
@@ -422,7 +419,7 @@ void ibwtest_sigint_handler(int sig)
 	}
 }
 
-int ibwtest_parse_attrs(struct ibwtest_ctx *tcx, char *optext,
+static int ibwtest_parse_attrs(struct ibwtest_ctx *tcx, char *optext,
 	struct ibw_initattr **pattrs, int *nattrs, char op)
 {
 	int	i = 0, n = 1;
@@ -477,7 +474,7 @@ static int ibwtest_get_address(const char *address, struct in_addr *addr)
 	return 0;
 }
 
-int ibwtest_getdests(struct ibwtest_ctx *tcx, char op)
+static int ibwtest_getdests(struct ibwtest_ctx *tcx, char op)
 {
 	int	i;
 	struct ibw_initattr	*attrs = NULL;
@@ -503,7 +500,7 @@ int ibwtest_getdests(struct ibwtest_ctx *tcx, char op)
 	return 0;
 }
 
-int ibwtest_init_server(struct ibwtest_ctx *tcx)
+static int ibwtest_init_server(struct ibwtest_ctx *tcx)
 {
 	if (tcx->naddrs!=1) {
 		fprintf(stderr, "incorrect number of addrs(%d!=1)\n", tcx->naddrs);
@@ -524,7 +521,7 @@ int ibwtest_init_server(struct ibwtest_ctx *tcx)
 	return 0;
 }
 
-void ibwtest_usage(struct ibwtest_ctx *tcx, char *name)
+static void ibwtest_usage(struct ibwtest_ctx *tcx, char *name)
 {
 	printf("Usage:\n");
 	printf("\t%s -i <id> -o {name:value} -d {addr:port} -t nsec -s\n", name);
@@ -605,7 +602,7 @@ int main(int argc, char *argv[])
 		goto cleanup;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 	assert(ev);
 
 	tcx->ibwctx = ibw_init(tcx->attrs, tcx->nattrs,
@@ -626,11 +623,12 @@ int main(int argc, char *argv[])
 
 	while(!tcx->kill_me && !tcx->error) {
 		if (tcx->nsec) {
-			event_add_timed(ev, tcx, timeval_current_ofs(0, tcx->nsec),
-				ibwtest_timeout_handler, tcx);
+			tevent_add_timer(ev, tcx,
+					 timeval_current_ofs(0, tcx->nsec),
+					 ibwtest_timeout_handler, tcx);
 		}
 
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 
 		if (tcx->sleep_usec)
 			usleep(tcx->sleep_usec);
diff --git a/ctdb/include/common/srvid.h b/ctdb/include/common/srvid.h
new file mode 120000
index 0000000..5a36c27
--- /dev/null
+++ b/ctdb/include/common/srvid.h
@@ -0,0 +1 @@
+../../common/srvid.h
\ No newline at end of file
diff --git a/ctdb/include/ctdb.h b/ctdb/include/ctdb.h
deleted file mode 100644
index c3da068..0000000
--- a/ctdb/include/ctdb.h
+++ /dev/null
@@ -1,1236 +0,0 @@
-/*
-   ctdb database library
-
-   Copyright (C) Ronnie sahlberg 2010
-   Copyright (C) Rusty Russell 2010
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _CTDB_H
-#define _CTDB_H
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <tdb.h>
-#include <netinet/in.h>
-#include <ctdb_protocol.h>
-
-/**
- * ctdb - a library for accessing tdbs controlled by ctdbd
- *
- * ctdbd (clustered tdb daemon) is a daemon designed to syncronize TDB
- * databases across a cluster.  Using this library, you can communicate with
- * the daemon to access the databases, pass messages across the cluster, and
- * control the daemon itself.
- *
- * The general API is event-driven and asynchronous: you call the
- * *_send functions, supplying callbacks, then when the ctdbd file
- * descriptor is usable, call ctdb_service() to perform read from it
- * and call your callbacks, which use the *_recv functions to unpack
- * the replies from ctdbd.
- *
- * There is also a synchronous wrapper for each function for trivial
- * programs; these can be found in the section marked "Synchronous API".
- */
-
-/**
- * ctdb_log_fn_t - logging function for ctdbd
- * @log_priv: private (typesafe) arg via ctdb_connect
- * @severity: syslog-style severity
- * @format: printf-style format string.
- * @ap: arguments for formatting.
- *
- * The severity passed to log() are as per syslog(3).  In particular,
- * LOG_DEBUG is used for tracing, LOG_WARNING is used for unusual
- * conditions which don't necessarily return an error through the API,
- * LOG_ERR is used for errors such as lost communication with ctdbd or
- * out-of-memory, LOG_ALERT is used for library usage bugs, LOG_CRIT is
- * used for libctdb internal consistency checks.
- *
- * The log() function can be typesafe: the @log_priv arg to
- * ctdb_donnect and signature of log() should match.
- */
-typedef void (*ctdb_log_fn_t)(void *log_priv,
-			      int severity, const char *format, va_list ap);
-
-/**
- * ctdb_connect - connect to ctdb using the specified domain socket.
- * @addr: the socket address, or NULL for default
- * @log: the logging function
- * @log_priv: the private argument to the logging function.
- *
- * Returns a ctdb context if successful or NULL.  Use ctdb_disconnect() to
- * release the returned ctdb_connection when finished.
- *
- * See Also:
- *	ctdb_log_fn_t, ctdb_log_file()
- */
-struct ctdb_connection *ctdb_connect(const char *addr,
-				     ctdb_log_fn_t log_fn, void *log_priv);
-
-/**
- * ctdb_log_file - example logging function
- *
- * Logs everything at priority LOG_WARNING or above to the file given (via
- * the log_priv argument, usually stderr).
- */
-void ctdb_log_file(FILE *, int, const char *, va_list);
-
-/**
- * ctdb_log_level - level at which to call logging function
- *
- * This variable globally controls filtering on the logging function.
- * It is initialized to LOG_WARNING, meaning that strange but nonfatal
- * events, as well as errors and API misuses are reported.
- *
- * Set it to LOG_DEBUG to receive all messages.
- */
-extern int ctdb_log_level;
-
-/**
- * ctdb_disconnect - close down a connection to ctdbd.
- * @ctdb: the ctdb connectio returned from ctdb_connect.
- *
- * The @ctdb arg will be freed by this call, and must not be used again.
- */
-void ctdb_disconnect(struct ctdb_connection *ctdb);
-
-/***
- *
- *  Asynchronous API
- *
- ***/
-
-/**
- * ctdb_num_active - get the number of active commands
- * @ctdb: the ctdb_connection from ctdb_connect.
- *
- * This command can be used to find the number of active commands we have
- * issued. An active command is a command we have queued, or sent
- * to the ctdb daemon but which we have not yet received a reply to.
- *
- * See Also:
- *	ctdb_num_in_flight(), ctdb_num_out_queue()
- */
-int ctdb_num_active(struct ctdb_connection *ctdb);
-
-/**
- * ctdb_num_in_flight - get the number of commands in flight.
- * @ctdb: the ctdb_connection from ctdb_connect.
- *
- * This command can be used to find the number of commands we have
- * sent to the ctdb daemon to which we have not yet received/processed
- * the reply.
- *
- * See Also:
- *	ctdb_num_out_queue(), ctdb_num_active()
- */
-int ctdb_num_in_flight(struct ctdb_connection *ctdb);
-
-/**
- * ctdb_num_out_queue - get the number of commands in the out queue
- * @ctdb: the ctdb_connection from ctdb_connect.
- *
- * This command can be used to find the number of commands we have
- * queued for delivery to the ctdb daemon but have not yet been
- * written to the domain socket.
- *
- * See Also:
- *	ctdb_num_in_flight(), ctdb_num_active()
- */
-int ctdb_num_out_queue(struct ctdb_connection *ctdb);
-
-/**
- * ctdb_get_fd - get the filedescriptor to select/poll on
- * @ctdb: the ctdb_connection from ctdb_connect.
- *
- * By using poll or select on this file descriptor, you will know when to call
- * ctdb_service().
- *
- * See Also:
- *	ctdb_which_events(), ctdb_service()
- */
-int ctdb_get_fd(struct ctdb_connection *ctdb);
-
-/**
- * ctdb_which_events - determine which events ctdb_service wants to see
- * @ctdb: the ctdb_connection from ctdb_connect.
- *
- * This returns POLLIN, possibly or'd with POLLOUT if there are writes
- * pending.  You can set this straight into poll.events.
- *
- * See Also:
- *	ctdb_service()
- */
-int ctdb_which_events(struct ctdb_connection *ctdb);
-
-/**
- * ctdb_service - service any I/O and callbacks from ctdbd communication
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @revents: which events are available.
- *
- * This is the core of the library: it read and writes to the ctdbd
- * socket.  It may call callbacks registered with the various _send
- * functions.
- *
- * revents is a bitset: POLLIN and/or POLLOUT may be set to indicate
- * it is worth attempting to read/write the (nonblocking)
- * filedescriptor respectively.
- *
- * Note that the synchronous functions call this internally.
- * Returns false on catastrophic failure.
- */
-bool ctdb_service(struct ctdb_connection *ctdb, int revents);
-
-/**
- * struct ctdb_request - handle for an outstanding request
- *
- * This opaque structure returned from various *_send functions gives
- * you a handle by which you can cancel a request.  You can't do
- * anything else with it until the request is completed and it is
- * handed to your callback function.
- */
-struct ctdb_request;
-
-/**
- * ctdb_request_free - free a completed request
- *
- * This frees a request: you should only call it once it has been
- * handed to your callback.  For incomplete requests, see ctdb_cancel().
- */
-void ctdb_request_free(struct ctdb_request *req);
-
-/**
- * ctdb_callback_t - callback for completed requests.
- *
- * This would normally unpack the request using ctdb_*_recv().  You
- * must free the request using ctdb_request_free().
- *
- * Note that due to macro magic, actual your callback can be typesafe:
- * instead of taking a void *, it can take a type which matches the
- * actual private parameter.
- */
-typedef void (*ctdb_callback_t)(struct ctdb_connection *ctdb,
-				struct ctdb_request *req, void *private_data);
-
-/**
- * struct ctdb_db - connection to a particular open TDB
- *
- * This represents a particular open database: you receive it from
- * ctdb_attachdb or ctdb_attachdb_recv to manipulate a database.
- *
- * You have to free the handle with ctdb_detachdb() when finished with it.
- */
-struct ctdb_db;
-
-/**
- * ctdb_attachdb_send - open a clustered TDB
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @name: the filename of the database (no /).
- * @persistent: whether the database is persistent across ctdbd's life
- * @tdb_flags: the flags to pass to tdb_open.
- * @callback: the callback when we're attached or failed (typesafe)
- * @cbdata: the argument to callback()
- *
- * This function connects to a TDB controlled by ctdbd.  It can create
- * a new TDB if it does not exist, depending on tdb_flags.  Returns
- * the pending request, or NULL on error.
- */
-struct ctdb_request *
-ctdb_attachdb_send(struct ctdb_connection *ctdb,
-		   const char *name, bool persistent, uint32_t tdb_flags,
-		   ctdb_callback_t callback, void *cbdata);
-
-/**
- * ctdb_attachdb_recv - read an ctdb_attach reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- *
- * This returns NULL if something went wrong, or otherwise the open database.
- */
-struct ctdb_db *ctdb_attachdb_recv(struct ctdb_connection *ctdb,
-				   struct ctdb_request *req);
-
-
-/**
- * struct ctdb_lock - a record lock on a clustered TDB database
- *
- * This locks a subset of the database across the entire cluster; it
- * is the fundamental sychronization element for ctdb.  You cannot have
- * more than one lock at once.
- *
- * You MUST NOT block during holding this lock and MUST release it
- * quickly by performing ctdb_release_lock(lock).
- * Do NOT make any system calls that may block while holding the lock.
- *
- * Try to release the lock as quickly as possible.
- */
-struct ctdb_lock;
-
-/**
- * ctdb_rrl_callback_t - callback for ctdb_readrecordlock_async
- *
- * This is not the standard ctdb_callback_t, because there is often no
- * request required to access a database record (ie. if it is local already).
- * So the callback is handed the lock directly: it might be NULL if there
- * was an error obtaining the lock.
- *
- * See Also:
- *	ctdb_readrecordlock_async(), ctdb_readrecordlock()
- */
-typedef void (*ctdb_rrl_callback_t)(struct ctdb_db *ctdb_db,
-				    struct ctdb_lock *lock,
-				    TDB_DATA data,
-				    void *private_data);
-
-/**
- * ctdb_readrecordlock_async - read and lock a record
- * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
- * @key: the key of the record to lock.
- * @callback: the callback once the record is locked (typesafe).
- * @cbdata: the argument to callback()
- *
- * This returns true on success.  Commonly, we can obtain the record
- * immediately and so the callback will be invoked.  Otherwise a request
- * will be queued to ctdbd for the record.
- *
- * If failure is immediate, false is returned.  Otherwise, the callback
- * may receive a NULL lock arg to indicate asynchronous failure.
- */
-bool ctdb_readrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key,
-			       ctdb_rrl_callback_t callback, void *cbdata);
-
-/**
- * ctdb_readonlyrecordlock_async - read and lock a record for read-only access
- * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
- * @key: the key of the record to lock.
- * @callback: the callback once the record is locked (typesafe).
- * @cbdata: the argument to callback()
- *
- * This returns true on success.  Commonly, we can obtain the record
- * immediately and so the callback will be invoked.  Otherwise a request
- * will be queued to ctdbd for the record.
- *
- * If failure is immediate, false is returned.  Otherwise, the callback
- * may receive a NULL lock arg to indicate asynchronous failure.
- */
-bool ctdb_readonlyrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key,
-			       ctdb_rrl_callback_t callback, void *cbdata);
-
-
-/**
- * ctdb_writerecord - write a locked record in a TDB
- * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
- * @lock: the lock from ctdb_readrecordlock/ctdb_readrecordlock_recv
- * @data: the new data to place in the record.
- */
-bool ctdb_writerecord(struct ctdb_db *ctdb_db,
-		      struct ctdb_lock *lock, TDB_DATA data);
-
-/**
- * ctdb_release_lock - release a record lock on a TDB
- * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
- * @lock: the lock from ctdb_readrecordlock/ctdb_readrecordlock_async
- */
-void ctdb_release_lock(struct ctdb_db *ctdb_db, struct ctdb_lock *lock);
-
-
-
-/**
- * ctdb_traverse_callback_t - callback for ctdb_traverse_async.
- * return 0 - to continue traverse
- * return 1 - to abort the traverse
- *
- * See Also:
- *	ctdb_traverse_async()
- */
-#define TRAVERSE_STATUS_RECORD		0
-#define TRAVERSE_STATUS_FINISHED	1
-#define TRAVERSE_STATUS_ERROR		2
-typedef int (*ctdb_traverse_callback_t)(struct ctdb_connection *ctdb,
-				    struct ctdb_db *ctdb_db,
-				    int status,
-				    TDB_DATA key,
-				    TDB_DATA data,
-				    void *private_data);
-
-/**
- * ctdb_traverse_async - traverse a database.
- * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
- * @callback: the callback once the record is locked (typesafe).
- * @cbdata: the argument to callback()
- *
- * This returns true on success.
- * when successfull, the callback will be invoked for each record
- * until the traversal is finished.
- *
- * status == 
- * TRAVERSE_STATUS_RECORD         key/data contains a record.
- * TRAVERSE_STATUS_FINISHED       traverse is finished. key/data is undefined.
- * TRAVERSE_STATUS_ERROR          an error occured during traverse.
- *                                key/data is undefined.
- *
- * If failure is immediate, false is returned.
- */
-bool ctdb_traverse_async(struct ctdb_db *ctdb_db,
-			 ctdb_traverse_callback_t callback, void *cbdata);
-
-/**
- * ctdb_message_fn_t - messaging callback for ctdb messages
- *
- * ctdbd provides a simple messaging API; you can register for a particular
- * 64-bit id on which you want to send messages, and send to other ids.
- *
- * See Also:
- *	ctdb_set_message_handler_send()
- */
-typedef void (*ctdb_message_fn_t)(struct ctdb_connection *,
-				  uint64_t srvid, TDB_DATA data, void *);
-
-/**
- * ctdb_set_message_handler_send - register for messages to a srvid
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @srvid: the 64 bit identifier for our messages.
- * @handler: the callback when we receive such a message (typesafe)
- * @handler_data: the argument to handler()
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * Note: our callback will always be called before handler.
- *
- * See Also:
- *	ctdb_set_message_handler_recv(), ctdb_remove_message_handler_send()
- */
-struct ctdb_request *
-ctdb_set_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
-			      ctdb_message_fn_t handler,
-			      void *handler_data,
-			      ctdb_callback_t callback,
-			      void *cbdata);
-
-/**
- * ctdb_set_message_handler_recv - read a set_message_handler result
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request
- *
- * If this returns true, the registered handler may be called from the next
- * ctdb_service().  If this returns false, the registration failed.
- */
-bool ctdb_set_message_handler_recv(struct ctdb_connection *ctdb,
-				   struct ctdb_request *handle);
-
-/**
- * ctdb_remove_message_handler_send - unregister for messages to a srvid
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @srvid: the 64 bit identifier for our messages.
- * @handler: the callback when we receive such a message (typesafe)
- * @handler_data: the argument to handler()
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * This undoes a successful ctdb_set_message_handler or
- * ctdb_set_message_handler_recv.
- */
-struct ctdb_request *
-ctdb_remove_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
-				 ctdb_message_fn_t handler, void *handler_data,
-				 ctdb_callback_t callback, void *cbdata);
-
-/**
- * ctdb_remove_message_handler_recv - read a remove_message_handler result
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request
- *
- * After this returns true, the registered handler will no longer be called.
- * If this returns false, the de-registration failed.
- */
-bool ctdb_remove_message_handler_recv(struct ctdb_connection *ctdb,
-				      struct ctdb_request *req);
-
-
-/**
- * ctdb_send_message - send a message via ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @pnn: the physical node number to send to
- * @srvid: the 64 bit identifier for this message type.
- * @data: the data to send
- *
- * This allows arbitrary messages to be sent across the cluster to those
- * listening (via ctdb_set_message_handler et al).
- *
- * This queues a message to be sent: you will need to call
- * ctdb_service() to actually send the message.  There is no callback
- * because there is no acknowledgement.
- *
- * See Also:
- *	ctdb_getpnn_send(), ctdb_getpnn()
- */
-bool ctdb_send_message(struct ctdb_connection *ctdb, uint32_t pnn, uint64_t srvid, TDB_DATA data);
-
-/**
- * ctdb_getpnn_send - read the pnn number of a node.
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getpnn_send(struct ctdb_connection *ctdb,
-		 uint32_t destnode,
-		 ctdb_callback_t callback,
-		 void *cbdata);
-/**
- * ctdb_getpnn_recv - read an ctdb_getpnn reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @pnn: a pointer to the pnn to fill in
- *
- * This returns false if something went wrong, or otherwise fills in pnn.
- */
-bool ctdb_getpnn_recv(struct ctdb_connection *ctdb,
-		      struct ctdb_request *req, uint32_t *pnn);
-
-
-/**
- * ctdb_getdbstat_send - read statistics for a db
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @db_id:    the database to collect the statistics from
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getdbstat_send(struct ctdb_connection *ctdb,
-		     uint32_t destnode,
-		     uint32_t db_id,
-		     ctdb_callback_t callback,
-		     void *cbdata);
-/**
- * ctdb_getdbstat_recv - read an ctdb_getdbstat reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @stat: a pointer to the *stat to fill in
- *
- * This returns false if something went wrong, or otherwise fills in **stats
- * stats must be freed later by calling ctdb_free_dbstat();
- */
-bool ctdb_getdbstat_recv(struct ctdb_connection *ctdb,
-			 struct ctdb_request *req,
-			 struct ctdb_db_statistics **stat);
-
-void ctdb_free_dbstat(struct ctdb_db_statistics *stat);
-
-/**
- * ctdb_check_message_handlers_send - check a list of message_handlers
- * if they are registered
- * message_handlers are registered on the daemon using the
- *   ctdb_set_message_handler_send() call
- *
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @num: number of srvids to check
- * @mhs: @num message_handlers values to check
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_check_message_handlers_send(struct ctdb_connection *ctdb,
-		 uint32_t destnode,
-		 uint32_t num,
-		 uint64_t *mhs,
-		 ctdb_callback_t callback,
-		 void *cbdata);
-/**
- * ctdb_check_message_handlers_recv - read a ctdb_check_message_handlers
- * reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @num: number of message_handlers to check
- * @result: an array of @num uint8_t fields containing the result of the check
- *     0: message_handler does not exist
- *     1: message_handler exists
- *
- * This returns false if something went wrong, or otherwise fills in result.
- */
-bool
-ctdb_check_message_handlers_recv(struct ctdb_connection *ctdb,
-				  struct ctdb_request *req, uint32_t num,
-				  uint8_t *result);
-
-
-/**
- * ctdb_getcapabilities_send - read the capabilities of a node
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getcapabilities_send(struct ctdb_connection *ctdb,
-			  uint32_t destnode,
-			  ctdb_callback_t callback, void *cbdata);
-
-/**
- * ctdb_getcapabilities_recv - read an ctdb_getcapabilities reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @capabilities: a pointer to the capabilities to fill in
- *
- * This returns false if something went wrong, or otherwise fills in
- * capabilities.
- */
-bool ctdb_getcapabilities_recv(struct ctdb_connection *ctdb,
-			       struct ctdb_request *handle,
-			       uint32_t *capabilities);
-
-/**
- * ctdb_getdbseqnum_send - read the sequence number off a db
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @dbid: database id
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getdbseqnum_send(struct ctdb_connection *ctdb,
-		 uint32_t destnode,
-		 uint32_t dbid,
-		 ctdb_callback_t callback,
-		 void *cbdata);
-/**
- * ctdb_getdbseqnum_recv - read the sequence number off a database
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @seqnum: a pointer to the seqnum to fill in
- *
- * This returns false if something went wrong, or otherwise fills in pnn.
- */
-bool ctdb_getdbseqnum_recv(struct ctdb_connection *ctdb,
-		      struct ctdb_request *req, uint64_t *seqnum);
-
-/**
- * ctdb_getnodemap_send - read the nodemap number from a node.
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getnodemap_send(struct ctdb_connection *ctdb,
-		 uint32_t destnode,
-		 ctdb_callback_t callback,
-		 void *cbdata);
-/**
- * ctdb_getnodemap_recv - read an ctdb_getnodemap reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @nodemap: a pointer to the returned nodemap structure
- *
- * This returns false if something went wrong.
- * If the command failed, it guarantees to set nodemap to NULL.
- * A non-NULL value for nodemap means the command was successful.
- *
- * A non-NULL value of the nodemap must be release released/freed
- * by ctdb_free_nodemap().
- */
-bool ctdb_getnodemap_recv(struct ctdb_connection *ctdb,
-		      struct ctdb_request *req, struct ctdb_node_map **nodemap);
-
-/**
- * ctdb_getifaces_send - read the list of interfaces from a node.
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getifaces_send(struct ctdb_connection *ctdb,
-		 uint32_t destnode,
-		 ctdb_callback_t callback,
-		 void *cbdata);
-/**
- * ctdb_getifaces_recv - read an ctdb_getifaces reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @ifaces: the list of interfaces 
- *
- * This returns false if something went wrong.
- * If the command failed, it guarantees to set ifaces to NULL.
- * A non-NULL value for ifaces means the command was successful.
- *
- * A non-NULL value of the ifaces must be release released/freed
- * by ctdb_free_ifaces().
- */
-bool ctdb_getifaces_recv(struct ctdb_connection *ctdb,
-		      struct ctdb_request *req, struct ctdb_ifaces_list **ifaces);
-
-/* Free a datastructure returned by ctdb_getifaces[_recv] */
-void ctdb_free_ifaces(struct ctdb_ifaces_list *ifaces);
-
-/**
- * ctdb_getpublicips_send - read the public ip list from a node.
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * This control returns the list of public ips known to the local node.
- * Deamons only know about those ips that are listed in the local
- * public addresses file, which means the returned list of ips may
- * be only a subset of all ips across the entire cluster.
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getpublicips_send(struct ctdb_connection *ctdb,
-		 uint32_t destnode,
-		 ctdb_callback_t callback,
-		 void *cbdata);
-/**
- * ctdb_getpublicips_recv - read the public ip list from a node
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @ips: a pointer to the returned public ip list
- *
- * This returns false if something went wrong.
- * If the command failed, it guarantees to set ips to NULL.
- * A non-NULL value for nodemap means the command was successful.
- *
- * A non-NULL value of the nodemap must be release released/freed
- * by ctdb_free_publicips().
- */
-bool ctdb_getpublicips_recv(struct ctdb_connection *ctdb,
-		      struct ctdb_request *req, struct ctdb_all_public_ips **ips);
-
-
-/**
- * ctdb_getrecmaster_send - read the recovery master of a node
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getrecmaster_send(struct ctdb_connection *ctdb,
-			uint32_t destnode,
-			ctdb_callback_t callback, void *cbdata);
-
-/**
- * ctdb_getrecmaster_recv - read an ctdb_getrecmaster reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @recmaster: a pointer to the recmaster to fill in
- *
- * This returns false if something went wrong, or otherwise fills in
- * recmaster.
- */
-bool ctdb_getrecmaster_recv(struct ctdb_connection *ctdb,
-			    struct ctdb_request *handle,
-			    uint32_t *recmaster);
-
-/**
- * ctdb_getrecmode_send - read the recovery mode of a node
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getrecmode_send(struct ctdb_connection *ctdb,
-		     uint32_t destnode,
-		     ctdb_callback_t callback, void *cbdata);
-
-/**
- * ctdb_getrecmode_recv - read an ctdb_getrecmode reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @recmode: a pointer to the recmode to fill in
- *
- * This returns false if something went wrong, or otherwise fills in
- * recmode.
- */
-bool ctdb_getrecmode_recv(struct ctdb_connection *ctdb,
-			  struct ctdb_request *handle,
-			  uint32_t *recmode);
-
-/**
- * ctdb_getvnnmap_send - read the vnn map from a node.
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @callback: the callback when ctdb replies to our message (typesafe)
- * @cbdata: the argument to callback()
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-struct ctdb_request *
-ctdb_getvnnmap_send(struct ctdb_connection *ctdb,
-		    uint32_t destnode,
-		    ctdb_callback_t callback,
-		    void *cbdata);
-/**
- * ctdb_getvnnmap_recv - read an ctdb_getvnnmap reply from ctdbd
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the completed request.
- * @vnnmap: the list of interfaces 
- *
- * This returns false if something went wrong.
- * If the command failed, it guarantees to set vnnmap to NULL.
- * A non-NULL value for vnnmap means the command was successful.
- *
- * A non-NULL value of the vnnmap must be released/freed
- * by ctdb_free_vnnmap().
- */
-bool ctdb_getvnnmap_recv(struct ctdb_connection *ctdb,
-			 struct ctdb_request *req, struct ctdb_vnn_map **vnnmap);
-
-/**
- * ctdb_cancel - cancel an uncompleted request
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @req: the uncompleted request.
- *
- * This cancels a request, returning true.  You may not cancel a
- * request which has already been completed (ie. once its callback has
- * been called); you should simply use ctdb_request_free() in that case.
- */
-void ctdb_cancel(struct ctdb_connection *ctdb, struct ctdb_request *req);
-
-/***
- *
- *  Synchronous API
- *
- ***/
-
-/**
- * ctdb_attachdb - open a clustered TDB (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @name: the filename of the database (no /).
- * @persistent: whether the database is persistent across ctdbd's life
- * @tdb_flags: the flags to pass to tdb_open.
- *
- * Do a ctdb_attachdb_send and wait for it to complete.
- * Returns NULL on failure.
- */
-struct ctdb_db *ctdb_attachdb(struct ctdb_connection *ctdb,
-			      const char *name, bool persistent,
-			      uint32_t tdb_flags);
-
-/**
- * ctdb_detachdb - close a clustered TDB.
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @db: the database from ctdb_attachdb/ctdb_attachdb_send
- *
- * Closes a clustered tdb.
- */
-void ctdb_detachdb(struct ctdb_connection *ctdb, struct ctdb_db *db);
-
-/**
- * ctdb_readrecordlock - read and lock a record (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
- * @key: the key of the record to lock.
- * @req: a pointer to the request, if one is needed.
- *
- * Do a ctdb_readrecordlock_send and wait for it to complete.
- * Returns NULL on failure.
- */
-struct ctdb_lock *ctdb_readrecordlock(struct ctdb_connection *ctdb,
-				      struct ctdb_db *ctdb_db, TDB_DATA key,
-				      TDB_DATA *data);
-
-
-/**
- * ctdb_set_message_handler - register for messages to a srvid (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @srvid: the 64 bit identifier for our messages.
- * @handler: the callback when we receive such a message (typesafe)
- * @cbdata: the argument to handler()
- *
- * If this returns true, the message handler can be called from any
- * ctdb_service() (which is also called indirectly by other
- * synchronous functions).  If this returns false, the registration
- * failed.
- */
-bool ctdb_set_message_handler(struct ctdb_connection *ctdb, uint64_t srvid,
-			      ctdb_message_fn_t handler, void *cbdata);
-
-
-/**
- * ctdb_remove_message_handler - deregister for messages (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @srvid: the 64 bit identifier for our messages.
- * @handler: the callback when we receive such a message (typesafe)
- * @handler_data: the argument to handler()
- *
- * If this returns true, the message handler will no longer be called.
- * If this returns false, the deregistration failed.
- */
-bool ctdb_remove_message_handler(struct ctdb_connection *ctdb, uint64_t srvid,
-				 ctdb_message_fn_t handler, void *handler_data);
-
-/**
- * ctdb_getpnn - read the pnn number of a node (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @pnn: a pointer to the pnn to fill in
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * Returns true and fills in *pnn on success.
- */
-bool ctdb_getpnn(struct ctdb_connection *ctdb,
-		 uint32_t destnode,
-		 uint32_t *pnn);
-
-/**
- * ctdb_getdbstat - read the db stat of a node (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @db_id:    the database to collect the statistics from
- * @stat: a pointer to the *stat to fill in
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * This returns false if something went wrong, or otherwise fills in **stat
- * stat must be freed later by calling ctdb_free_dbstat();
- */
-bool ctdb_getdbstat(struct ctdb_connection *ctdb,
-		    uint32_t destnode,
-		    uint32_t db_id,
-		    struct ctdb_db_statistics **stat);
-
-
-/**
- * ctdb_check_message_handlers - check a list of message_handlers (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @num: number of srvids to check
- * @mhs: @num message_handlers to check
- * @result: an array of @num uint8_t fields containing the result of the check
- *     0: message_handler does not exist
- *     1: message_handler exists
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- */
-bool
-ctdb_check_message_handlers(struct ctdb_connection *ctdb,
-			   uint32_t destnode,
-			   uint32_t num,
-			   uint64_t *mhs,
-			   uint8_t *result);
-
-/**
- * ctdb_getcapabilities - read the capabilities of a node (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @capabilities: a pointer to the capabilities to fill in
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * Returns true and fills in *capabilities on success.
- */
-bool ctdb_getcapabilities(struct ctdb_connection *ctdb,
-			  uint32_t destnode,
-			  uint32_t *capabilities);
-
-
-/**
- * ctdb_getdbseqnum - read the seqnum of a database
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @dbid: database id
- * @seqnum: sequence number for the database
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * Returns true and fills in *pnn on success.
- */
-bool
-ctdb_getdbseqnum(struct ctdb_connection *ctdb,
-		 uint32_t destnode,
-		 uint32_t dbid,
-		 uint64_t *seqnum);
-
-/**
- * ctdb_getrecmaster - read the recovery master of a node (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @recmaster: a pointer to the recmaster to fill in
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * Returns true and fills in *recmaster on success.
- */
-bool ctdb_getrecmaster(struct ctdb_connection *ctdb,
-		       uint32_t destnode,
-		       uint32_t *recmaster);
-
-
-/**
- * ctdb_getrecmode - read the recovery mode of a node (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @recmode: a pointer to the recmode to fill in
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * Returns true and fills in *recmode on success.
- */
-bool ctdb_getrecmode(struct ctdb_connection *ctdb,
-		     uint32_t destnode,
-		     uint32_t *recmode);
-
-
-/**
- * ctdb_getnodemap - read the nodemap from a node (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @nodemap: a pointer to the nodemap to fill in
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * Returns true and fills in *nodemap on success.
- * A non-NULL nodemap must be freed by calling ctdb_free_nodemap.
- */
-bool ctdb_getnodemap(struct ctdb_connection *ctdb,
-		     uint32_t destnode, struct ctdb_node_map **nodemap);
-
-/**
- * ctdb_getifaces - read the list of interfaces from a node (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @ifaces: a pointer to the ifaces to fill in
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * Returns true and fills in *ifaces on success.
- * A non-NULL value of the ifaces must be release released/freed
- * by ctdb_free_ifaces().
- */
-bool ctdb_getifaces(struct ctdb_connection *ctdb,
-		    uint32_t destnode, struct ctdb_ifaces_list **ifaces);
-
-/*
- * This function is used to release/free the nodemap structure returned
- * by ctdb_getnodemap() and ctdb_getnodemap_recv()
- */
-void ctdb_free_nodemap(struct ctdb_node_map *nodemap);
-
-
-/**
- * ctdb_getpublicips - read the public ip list from a node.
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @ips: a pointer to the returned public ip list
- *
- * This control returns the list of public ips known to the local node.
- * Deamons only know about those ips that are listed in the local
- * public addresses file, which means the returned list of ips may
- * be only a subset of all ips across the entire cluster.
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * This returns false if something went wrong.
- * If the command failed, it guarantees to set ips to NULL.
- * A non-NULL value for nodemap means the command was successful.
- *
- * A non-NULL value of the nodemap must be release released/freed
- * by ctdb_free_publicips().
- */
-bool ctdb_getpublicips(struct ctdb_connection *ctdb,
-		     uint32_t destnode, struct ctdb_all_public_ips **ips);
-
-/*
- * This function is used to release/free the public ip structure returned
- * by ctdb_getpublicips() and ctdb_getpublicips_recv()
- */
-void ctdb_free_publicips(struct ctdb_all_public_ips *ips);
-
-
-/**
- * ctdb_getvnnmap - read the vnn map from a node (synchronous)
- * @ctdb: the ctdb_connection from ctdb_connect.
- * @destnode: the destination node (see below)
- * @vnnmap: a pointer to the vnnmap to fill in
- *
- * There are several special values for destnode, detailed in
- * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
- * local ctdbd.
- *
- * Returns true and fills in *vnnmap on success.
- * A non-NULL value of the vnnmap must be  released/freed
- * by ctdb_free_vnnmap().
- */
-bool ctdb_getvnnmap(struct ctdb_connection *ctdb,
-		    uint32_t destnode, struct ctdb_vnn_map **vnnmap);
-
-/*
- * This function is used to release/free the vnnmap structure returned
- * by ctdb_getvnnmap() and ctdb_getvnnmap_recv()
- */
-void ctdb_free_vnnmap(struct ctdb_vnn_map *vnnmap);
-
-/* These ugly macro wrappers make the callbacks typesafe. */
-#include <ctdb_typesafe_cb.h>
-#define ctdb_sendcb(cb, cbdata)						\
-	 typesafe_cb_preargs(void, (cb), (cbdata),			\
-			     struct ctdb_connection *, struct ctdb_request *)
-
-#define ctdb_msgcb(cb, cbdata)						\
-	typesafe_cb_preargs(void, (cb), (cbdata),			\
-			    struct ctdb_connection *, uint64_t, TDB_DATA)
-
-#define ctdb_connect(addr, log, logpriv)				\
-	ctdb_connect((addr),						\
-		     typesafe_cb_postargs(void, (log), (logpriv),	\
-					  int, const char *, va_list),	\
-		     (logpriv))
-
-#define ctdb_set_message_handler(ctdb, srvid, handler, hdata)		\
-	ctdb_set_message_handler((ctdb), (srvid),			\
-				 ctdb_msgcb((handler), (hdata)), (hdata))
-
-#define ctdb_remove_message_handler(ctdb, srvid, handler, hdata)	\
-	ctdb_remove_message_handler((ctdb), (srvid),			\
-				    ctdb_msgcb((handler), (hdata)), (hdata))
-
-#define ctdb_attachdb_send(ctdb, name, persistent, tdb_flags, cb, cbdata) \
-	ctdb_attachdb_send((ctdb), (name), (persistent), (tdb_flags),	\
-			   ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_readrecordlock_async(_ctdb_db, key, cb, cbdata)		\
-	ctdb_readrecordlock_async((_ctdb_db), (key),			\
-		typesafe_cb_preargs(void, (cb), (cbdata),		\
-				    struct ctdb_db *, struct ctdb_lock *, \
-				    TDB_DATA), (cbdata))
-
-#define ctdb_set_message_handler_send(ctdb, srvid, handler, hdata, cb, cbdata) \
-	ctdb_set_message_handler_send((ctdb), (srvid),			\
-				      ctdb_msgcb((handler), (hdata)), (hdata), \
-				      ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_remove_message_handler_send(ctdb, srvid, handler, hdata, cb, cbdata) \
-	ctdb_remove_message_handler_send((ctdb), (srvid),		\
-	      ctdb_msgcb((handler), (hdata)), (hdata),			\
-	      ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getpnn_send(ctdb, destnode, cb, cbdata)			\
-	ctdb_getpnn_send((ctdb), (destnode),				\
-			 ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getcapabilities_send(ctdb, destnode, cb, cbdata)		\
-	ctdb_getcapabilities_send((ctdb), (destnode),			\
-				  ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getdbstat_send(ctdb, destnode, db_id, cb, cbdata)		\
-	ctdb_getdbstat_send((ctdb), (destnode), (db_id),		\
-			    ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_check_message_handlers_send(ctdb, destnode, num, mhs,	\
-			 cb, cbdata)					\
-	ctdb_check_message_handlers_send((ctdb), (destnode), (num), 	\
-			 (mhs),						\
-			 ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getrecmaster_send(ctdb, destnode, cb, cbdata)		\
-	ctdb_getrecmaster_send((ctdb), (destnode),			\
-			       ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getrecmode_send(ctdb, destnode, cb, cbdata)		\
-	ctdb_getrecmode_send((ctdb), (destnode),			\
-			       ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getnodemap_send(ctdb, destnode, cb, cbdata)		\
-	ctdb_getnodemap_send((ctdb), (destnode),			\
-			 ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getpublicips_send(ctdb, destnode, cb, cbdata)		\
-	ctdb_getpublicips_send((ctdb), (destnode),			\
-			 ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getdbseqnum_send(ctdb, destnode, dbid, cb, cbdata)		\
-	ctdb_getdbseqnum_send((ctdb), (destnode), (dbid),		\
-			 ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getifaces_send(ctdb, destnode, cb, cbdata)			\
-	ctdb_getifaces_send((ctdb), (destnode),				\
-			 ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#define ctdb_getvnnmap_send(ctdb, destnode, cb, cbdata)			\
-	ctdb_getvnnmap_send((ctdb), (destnode),				\
-			 ctdb_sendcb((cb), (cbdata)), (cbdata))
-
-#endif
diff --git a/ctdb/include/ctdb_client.h b/ctdb/include/ctdb_client.h
index 74887a7..e81d7bb 100644
--- a/ctdb/include/ctdb_client.h
+++ b/ctdb/include/ctdb_client.h
@@ -19,9 +19,16 @@
 
 #ifndef _CTDB_CLIENT_H
 #define _CTDB_CLIENT_H
+
+#include "common/srvid.h"
 #include "ctdb_protocol.h"
 
-enum control_state {CTDB_CONTROL_WAIT, CTDB_CONTROL_DONE, CTDB_CONTROL_ERROR, CTDB_CONTROL_TIMEOUT};
+enum control_state {
+	CTDB_CONTROL_WAIT,
+	CTDB_CONTROL_DONE,
+	CTDB_CONTROL_ERROR,
+	CTDB_CONTROL_TIMEOUT
+};
 
 struct ctdb_client_control_state {
 	struct ctdb_context *ctdb;
@@ -30,7 +37,7 @@ struct ctdb_client_control_state {
 	TDB_DATA outdata;
 	enum control_state state;
 	char *errormsg;
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 
 	/* if we have a callback registered for the completion (or failure) of
 	   this control
@@ -42,292 +49,251 @@ struct ctdb_client_control_state {
 	} async;
 };
 
-struct ctdb_client_notify_register {
-	uint64_t srvid;
-	uint32_t len;
-	uint8_t notify_data[1];
-};
-
-struct ctdb_client_notify_deregister {
-	uint64_t srvid;
-};
-
 struct tevent_context;
+struct ctdb_db_context;
 
 /*
-  initialise ctdb subsystem
-*/
-struct ctdb_context *ctdb_init(struct tevent_context *ev);
-
-/*
-  choose the transport
-*/
-int ctdb_set_transport(struct ctdb_context *ctdb, const char *transport);
-
-/*
-  set some flags
-*/
-void ctdb_set_flags(struct ctdb_context *ctdb, unsigned flags);
-
-/*
-  tell ctdb what address to listen on, in transport specific format
-*/
-int ctdb_set_address(struct ctdb_context *ctdb, const char *address);
-
-int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname);
-const char *ctdb_get_socketname(struct ctdb_context *ctdb);
-
-/*
-  Check that a specific ip address exists in the node list and returns
-  the id for the node or -1
-*/
-int ctdb_ip_to_nodeid(struct ctdb_context *ctdb, const ctdb_sock_addr *nodeip);
-
-/*
-  attach to a ctdb database
-*/
-struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb,
-				    struct timeval timeout,
-				    const char *name,
-				    bool persistent,
-				    uint32_t tdb_flags);
-
-int ctdb_detach(struct ctdb_context *ctdb, uint32_t db_id);
-
-/*
-  find an attached ctdb_db handle given a name
+  allocate a packet for use in client<->daemon communication
  */
-struct ctdb_db_context *ctdb_db_handle(struct ctdb_context *ctdb, const char *name);
+struct ctdb_req_header *_ctdbd_allocate_pkt(struct ctdb_context *ctdb,
+					    TALLOC_CTX *mem_ctx,
+					    enum ctdb_operation operation,
+					    size_t length, size_t slength,
+					    const char *type);
 
-/*
-  error string for last ctdb error
-*/
-const char *ctdb_errstr(struct ctdb_context *);
+#define ctdbd_allocate_pkt(ctdb, mem_ctx, operation, length, type) \
+	(type *)_ctdbd_allocate_pkt(ctdb, mem_ctx, operation, length, \
+				    sizeof(type), #type)
 
-/* a ctdb call function */
-typedef int (*ctdb_fn_t)(struct ctdb_call_info *);
+int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call,
+		    struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx,
+		    TDB_DATA *data, bool updatetdb);
 
-/*
-  setup a ctdb call function
-*/
-int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id);
+void ctdb_request_message(struct ctdb_context *ctdb,
+			  struct ctdb_req_header *hdr);
 
+void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args);
 
+int ctdb_socket_connect(struct ctdb_context *ctdb);
 
 /*
   make a ctdb call. The associated ctdb call function will be called on the DMASTER
   for the given record
 */
+struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db,
+					      struct ctdb_call *call);
+int ctdb_call_recv(struct ctdb_client_call_state *state,
+		   struct ctdb_call *call);
 int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call);
 
-/* return pnn of this node */
-uint32_t ctdb_get_pnn(struct ctdb_context *ctdb);
-
 /* setup a handler for ctdb messages */
 typedef void (*ctdb_msg_fn_t)(struct ctdb_context *, uint64_t srvid,
-				  TDB_DATA data, void *);
+			      TDB_DATA data, void *);
+
 int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
-			     ctdb_msg_fn_t handler,
-			     void *private_data);
+				    srvid_handler_fn handler,
+				    void *private_data);
 int ctdb_client_remove_message_handler(struct ctdb_context *ctdb,
 				       uint64_t srvid, void *private_data);
 int ctdb_client_check_message_handlers(struct ctdb_context *ctdb,
 				       uint64_t *ids, uint32_t num,
 				       uint8_t *result);
 
-int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call);
-struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call);
-int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call);
-
 /* send a ctdb message */
 int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t pnn,
-		      uint64_t srvid, TDB_DATA data);
-
+			     uint64_t srvid, TDB_DATA data);
 
 /*
-   Fetch a ctdb record from a remote node
- . Underneath this will force the
+   Fetch a ctdb record from a remote node. Underneath this will force the
    dmaster for the record to be moved to the local node.
 */
-struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx,
+struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db,
+					   TALLOC_CTX *mem_ctx,
 					   TDB_DATA key, TDB_DATA *data);
 
-struct ctdb_record_handle *ctdb_fetch_readonly_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data, int read_only);
+struct ctdb_record_handle *ctdb_fetch_readonly_lock(
+					struct ctdb_db_context *ctdb_db,
+					TALLOC_CTX *mem_ctx, TDB_DATA key,
+					TDB_DATA *data, int read_only);
 
 int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data);
 
 int ctdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx,
 	       TDB_DATA key, TDB_DATA *data);
 
-int ctdb_register_message_handler(struct ctdb_context *ctdb,
-				  TALLOC_CTX *mem_ctx,
-				  uint64_t srvid,
-				  ctdb_msg_fn_t handler,
-				  void *private_data);
-
-struct ctdb_db_context *find_ctdb_db(struct ctdb_context *ctdb, uint32_t id);
-
+struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb,
+						    uint32_t destnode,
+						    uint64_t srvid,
+						    uint32_t opcode,
+						    uint32_t flags,
+						    TDB_DATA data,
+						    TALLOC_CTX *mem_ctx,
+						    struct timeval *timeout,
+						    char **errormsg);
+int ctdb_control_recv(struct ctdb_context *ctdb,
+		      struct ctdb_client_control_state *state,
+		      TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
+		      int32_t *status, char **errormsg);
+int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
+		 uint32_t opcode, uint32_t flags, TDB_DATA data,
+		 TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
+		 struct timeval *timeout, char **errormsg);
+
+int ctdb_ctrl_process_exists(struct ctdb_context *ctdb, uint32_t destnode,
+			     pid_t pid);
+
+int ctdb_ctrl_statistics(struct ctdb_context *ctdb, uint32_t destnode,
+			 struct ctdb_statistics *status);
+int ctdb_ctrl_dbstatistics(struct ctdb_context *ctdb, uint32_t destnode,
+			   uint32_t dbid, TALLOC_CTX *mem_ctx,
+			   struct ctdb_db_statistics_old **dbstat);
+
+int ctdb_ctrl_shutdown(struct ctdb_context *ctdb, struct timeval timeout,
+		       uint32_t destnode);
+
+int ctdb_ctrl_getvnnmap(struct ctdb_context *ctdb, struct timeval timeout,
+			uint32_t destnode, TALLOC_CTX *mem_ctx,
+			struct ctdb_vnn_map **vnnmap);
+int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, struct timeval timeout,
+			uint32_t destnode, TALLOC_CTX *mem_ctx,
+			struct ctdb_vnn_map *vnnmap);
 
-struct ctdb_context *ctdb_cmdline_client(struct tevent_context *ev,
-					 struct timeval req_timeout);
-
-struct ctdb_statistics;
-int ctdb_ctrl_statistics(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_statistics *status);
-int ctdb_ctrl_dbstatistics(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
-			   TALLOC_CTX *mem_ctx, struct ctdb_db_statistics **dbstat);
-
-int ctdb_ctrl_shutdown(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+/*
+  get the recovery mode of a remote node
+ */
+struct ctdb_client_control_state *ctdb_ctrl_getrecmode_send(
+					struct ctdb_context *ctdb,
+					TALLOC_CTX *mem_ctx,
+					struct timeval timeout,
+					uint32_t destnode);
+int ctdb_ctrl_getrecmode_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+			      struct ctdb_client_control_state *state,
+			      uint32_t *recmode);
+int ctdb_ctrl_getrecmode(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+			 struct timeval timeout, uint32_t destnode,
+			 uint32_t *recmode);
 
-struct ctdb_vnn_map;
-int ctdb_ctrl_getvnnmap(struct ctdb_context *ctdb,
-		struct timeval timeout, uint32_t destnode,
-		TALLOC_CTX *mem_ctx, struct ctdb_vnn_map **vnnmap);
-int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb,
-		struct timeval timeout, uint32_t destnode,
-		TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *vnnmap);
+/*
+  set the recovery mode of a remote node
+ */
+int ctdb_ctrl_setrecmode(struct ctdb_context *ctdb, struct timeval timeout,
+			 uint32_t destnode, uint32_t recmode);
 
-/* table that contains a list of all dbids on a node
+/*
+  get the recovery master of a remote node
  */
-struct ctdb_dbid_map {
-	uint32_t num;
-	struct ctdb_dbid {
-		uint32_t dbid;
-#define CTDB_DB_FLAGS_PERSISTENT	0x01
-#define CTDB_DB_FLAGS_READONLY		0x02
-#define CTDB_DB_FLAGS_STICKY		0x04
-		uint8_t flags;
-	} dbs[1];
-};
-int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb,
-	struct timeval timeout, uint32_t destnode,
-	TALLOC_CTX *mem_ctx, struct ctdb_dbid_map **dbmap);
+struct ctdb_client_control_state *ctdb_ctrl_getrecmaster_send(
+					struct ctdb_context *ctdb,
+					TALLOC_CTX *mem_ctx,
+					struct timeval timeout,
+					uint32_t destnode);
+int ctdb_ctrl_getrecmaster_recv(struct ctdb_context *ctdb,
+				TALLOC_CTX *mem_ctx,
+				struct ctdb_client_control_state *state,
+				uint32_t *recmaster);
+int ctdb_ctrl_getrecmaster(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+			   struct timeval timeout, uint32_t destnode,
+			   uint32_t *recmaster);
 
+/*
+  set the recovery master of a remote node
+ */
+int ctdb_ctrl_setrecmaster(struct ctdb_context *ctdb, struct timeval timeout,
+			   uint32_t destnode, uint32_t recmaster);
 
-struct ctdb_node_map;
+int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, struct timeval timeout,
+		       uint32_t destnode, TALLOC_CTX *mem_ctx,
+		       struct ctdb_dbid_map_old **dbmap);
 
-int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb,
-		    struct timeval timeout, uint32_t destnode,
-		    TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap);
+int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb, struct timeval timeout,
+			 uint32_t destnode, TALLOC_CTX *mem_ctx,
+			 struct ctdb_node_map_old **nodemap);
 
-int ctdb_ctrl_getnodesfile(struct ctdb_context *ctdb,
-			   struct timeval timeout, uint32_t destnode,
-			   TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap);
+int ctdb_ctrl_getnodesfile(struct ctdb_context *ctdb, struct timeval timeout,
+			   uint32_t destnode, TALLOC_CTX *mem_ctx,
+			   struct ctdb_node_map_old **nodemap);
 
 int ctdb_ctrl_reload_nodes_file(struct ctdb_context *ctdb,
-		    struct timeval timeout, uint32_t destnode);
-
-struct ctdb_key_list {
-	uint32_t dbid;
-	uint32_t num;
-	TDB_DATA *keys;
-	struct ctdb_ltdb_header *headers;
-	TDB_DATA *data;
-};
-
-int ctdb_ctrl_pulldb(
-       struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
-       uint32_t lmaster, TALLOC_CTX *mem_ctx,
-       struct timeval timeout, TDB_DATA *outdata);
+				struct timeval timeout, uint32_t destnode);
 
 struct ctdb_client_control_state *ctdb_ctrl_pulldb_send(
-       struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
-       uint32_t lmaster, TALLOC_CTX *mem_ctx, struct timeval timeout);
-
-int ctdb_ctrl_pulldb_recv(
-       struct ctdb_context *ctdb,
-       TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state,
-       TDB_DATA *outdata);
-
-int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **path);
-int ctdb_ctrl_getdbname(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **name);
-int ctdb_ctrl_getdbhealth(struct ctdb_context *ctdb,
-			  struct timeval timeout,
-			  uint32_t destnode,
-			  uint32_t dbid, TALLOC_CTX *mem_ctx,
-			  const char **reason);
-int ctdb_ctrl_getdbseqnum(struct ctdb_context *ctdb, struct timeval timeout,
-			  uint32_t destnode, uint32_t dbid, uint64_t *seqnum);
-int ctdb_ctrl_createdb(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const char *name, bool persistent);
-
-int ctdb_ctrl_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t pid);
-
-int ctdb_ctrl_ping(struct ctdb_context *ctdb, uint32_t destnode);
-
-int ctdb_ctrl_get_runstate(struct ctdb_context *ctdb, 
-			   struct timeval timeout, 
-			   uint32_t destnode,
-			   uint32_t *runstate);
-
-int ctdb_ctrl_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t *level);
-int ctdb_ctrl_set_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t level);
+					struct ctdb_context *ctdb,
+					uint32_t destnode, uint32_t dbid,
+					uint32_t lmaster, TALLOC_CTX *mem_ctx,
+					struct timeval timeout);
+int ctdb_ctrl_pulldb_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+			  struct ctdb_client_control_state *state,
+			  TDB_DATA *outdata);
+int ctdb_ctrl_pulldb(struct ctdb_context *ctdb, uint32_t destnode,
+		     uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx,
+		     struct timeval timeout, TDB_DATA *outdata);
 
 /*
   change dmaster for all keys in the database to the new value
  */
-int ctdb_ctrl_setdmaster(struct ctdb_context *ctdb,
-	struct timeval timeout, uint32_t destnode,
-	TALLOC_CTX *mem_ctx, uint32_t dbid, uint32_t dmaster);
-
-#define CTDB_RECOVERY_NORMAL		0
-#define CTDB_RECOVERY_ACTIVE		1
-
-/*
-  get the recovery mode of a remote node
- */
-int ctdb_ctrl_getrecmode(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmode);
-
-struct ctdb_client_control_state *ctdb_ctrl_getrecmode_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode);
+int ctdb_ctrl_setdmaster(struct ctdb_context *ctdb, struct timeval timeout,
+			 uint32_t destnode, TALLOC_CTX *mem_ctx,
+			 uint32_t dbid, uint32_t dmaster);
 
-int ctdb_ctrl_getrecmode_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmode);
+int ctdb_ctrl_ping(struct ctdb_context *ctdb, uint32_t destnode);
 
+int ctdb_ctrl_get_runstate(struct ctdb_context *ctdb, struct timeval timeout,
+			   uint32_t destnode, uint32_t *runstate);
+
+int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, struct timeval timeout,
+			uint32_t destnode, uint32_t dbid,
+			TALLOC_CTX *mem_ctx, const char **path);
+int ctdb_ctrl_getdbname(struct ctdb_context *ctdb, struct timeval timeout,
+			uint32_t destnode, uint32_t dbid,
+			TALLOC_CTX *mem_ctx, const char **name);
+int ctdb_ctrl_getdbhealth(struct ctdb_context *ctdb, struct timeval timeout,
+			  uint32_t destnode, uint32_t dbid,
+			  TALLOC_CTX *mem_ctx, const char **reason);
+int ctdb_ctrl_getdbseqnum(struct ctdb_context *ctdb, struct timeval timeout,
+			  uint32_t destnode, uint32_t dbid, uint64_t *seqnum);
 
-/*
-  set the recovery mode of a remote node
- */
-int ctdb_ctrl_setrecmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmode);
-/*
-  get the monitoring mode of a remote node
- */
-int ctdb_ctrl_getmonmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *monmode);
+int ctdb_ctrl_createdb(struct ctdb_context *ctdb, struct timeval timeout,
+		       uint32_t destnode, TALLOC_CTX *mem_ctx,
+		       const char *name, bool persistent);
 
-/*
-  set the monitoring mode of a remote node to active
- */
-int ctdb_ctrl_enable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+int ctdb_ctrl_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode,
+			     int32_t *level);
+int ctdb_ctrl_set_debuglevel(struct ctdb_context *ctdb, uint32_t destnode,
+			     int32_t level);
 
-/*
-  set the monitoring mode of a remote node to disabled
- */
-int ctdb_ctrl_disable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+uint32_t *ctdb_get_connected_nodes(struct ctdb_context *ctdb,
+				   struct timeval timeout,
+				   TALLOC_CTX *mem_ctx, uint32_t *num_nodes);
 
+int ctdb_statistics_reset(struct ctdb_context *ctdb, uint32_t destnode);
 
 /*
-  get the recovery master of a remote node
- */
-int ctdb_ctrl_getrecmaster(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmaster);
-
-struct ctdb_client_control_state *ctdb_ctrl_getrecmaster_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode);
-
-int ctdb_ctrl_getrecmaster_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmaster);
+  attach to a ctdb database
+*/
+struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb,
+				    struct timeval timeout,
+				    const char *name,
+				    bool persistent,
+				    uint32_t tdb_flags);
 
+int ctdb_detach(struct ctdb_context *ctdb, uint32_t db_id);
 
+/* a ctdb call function */
+typedef int (*ctdb_fn_t)(struct ctdb_call_info *);
 
 /*
-  set the recovery master of a remote node
- */
-int ctdb_ctrl_setrecmaster(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmaster);
+  setup a ctdb call function
+*/
+int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id);
 
-uint32_t *ctdb_get_connected_nodes(struct ctdb_context *ctdb,
-				   struct timeval timeout,
-				   TALLOC_CTX *mem_ctx,
-				   uint32_t *num_nodes);
 
-int ctdb_statistics_reset(struct ctdb_context *ctdb, uint32_t destnode);
+typedef int (*ctdb_traverse_func)(TDB_DATA, TDB_DATA, void *);
 
-typedef int (*ctdb_traverse_func)(struct ctdb_context *, TDB_DATA, TDB_DATA, void *);
-int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *private_data);
+int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn,
+		  void *private_data);
 
 struct ctdb_dump_db_context {
+	struct ctdb_context *ctdb;
 	FILE *f;
 	bool printemptyrecords;
 	bool printdatasize;
@@ -336,117 +302,229 @@ struct ctdb_dump_db_context {
 	bool printrecordflags;
 };
 
-int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p);
+int ctdb_dumpdb_record(TDB_DATA key, TDB_DATA data, void *p);
 int ctdb_dump_db(struct ctdb_db_context *ctdb_db,
 		 struct ctdb_dump_db_context *ctx);
 
 /*
   get the pid of a ctdb daemon
  */
-int ctdb_ctrl_getpid(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *pid);
+int ctdb_ctrl_getpid(struct ctdb_context *ctdb, struct timeval timeout,
+		     uint32_t destnode, uint32_t *pid);
+
+struct ctdb_client_control_state *ctdb_ctrl_freeze_send(
+					struct ctdb_context *ctdb,
+					TALLOC_CTX *mem_ctx,
+					struct timeval timeout,
+					uint32_t destnode, uint32_t priority);
+int ctdb_ctrl_freeze_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+			  struct ctdb_client_control_state *state);
 
-int ctdb_ctrl_freeze(struct ctdb_context *ctdb, struct timeval timeout,
-			uint32_t destnode);
 int ctdb_ctrl_freeze_priority(struct ctdb_context *ctdb, struct timeval timeout,
 			      uint32_t destnode, uint32_t priority);
+int ctdb_ctrl_freeze(struct ctdb_context *ctdb, struct timeval timeout,
+		     uint32_t destnode);
 
-struct ctdb_client_control_state *
-ctdb_ctrl_freeze_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
-		      struct timeval timeout, uint32_t destnode,
-		      uint32_t priority);
+int ctdb_ctrl_thaw_priority(struct ctdb_context *ctdb, struct timeval timeout,
+			    uint32_t destnode, uint32_t priority);
+int ctdb_ctrl_thaw(struct ctdb_context *ctdb, struct timeval timeout,
+		   uint32_t destnode);
 
-int ctdb_ctrl_freeze_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
-			struct ctdb_client_control_state *state);
+int ctdb_ctrl_getpnn(struct ctdb_context *ctdb, struct timeval timeout,
+		     uint32_t destnode);
 
-int ctdb_ctrl_thaw_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t priority);
-int ctdb_ctrl_thaw(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+/*
+  get the monitoring mode of a remote node
+ */
+int ctdb_ctrl_getmonmode(struct ctdb_context *ctdb, struct timeval timeout,
+			 uint32_t destnode, uint32_t *monmode);
 
-int ctdb_ctrl_getpnn(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+/*
+  set the monitoring mode of a remote node to active
+ */
+int ctdb_ctrl_enable_monmode(struct ctdb_context *ctdb,
+			     struct timeval timeout, uint32_t destnode);
+
+/*
+  set the monitoring mode of a remote node to disabled
+ */
+int ctdb_ctrl_disable_monmode(struct ctdb_context *ctdb,
+			      struct timeval timeout, uint32_t destnode);
+
+int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout,
+			  uint32_t destnode, struct ctdb_public_ip *ip);
+int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout,
+			 uint32_t destnode, struct ctdb_public_ip *ip);
 
 int ctdb_ctrl_get_tunable(struct ctdb_context *ctdb,
-			  struct timeval timeout,
-			  uint32_t destnode,
+			  struct timeval timeout, uint32_t destnode,
 			  const char *name, uint32_t *value);
-
 int ctdb_ctrl_set_tunable(struct ctdb_context *ctdb,
-			  struct timeval timeout,
-			  uint32_t destnode,
+			  struct timeval timeout, uint32_t destnode,
 			  const char *name, uint32_t value);
-
 int ctdb_ctrl_list_tunables(struct ctdb_context *ctdb,
-			    struct timeval timeout,
-			    uint32_t destnode,
+			    struct timeval timeout, uint32_t destnode,
 			    TALLOC_CTX *mem_ctx,
 			    const char ***list, uint32_t *count);
 
+int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
+				   struct timeval timeout, uint32_t destnode,
+				   TALLOC_CTX *mem_ctx, uint32_t flags,
+				   struct ctdb_public_ip_list_old **ips);
+int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
+			     struct timeval timeout, uint32_t destnode,
+			     TALLOC_CTX *mem_ctx,
+			     struct ctdb_public_ip_list_old **ips);
+int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
+				 struct timeval timeout, uint32_t destnode,
+				 TALLOC_CTX *mem_ctx,
+				 const ctdb_sock_addr *addr,
+				 struct ctdb_public_ip_info_old **info);
+
+int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
+			 struct timeval timeout, uint32_t destnode,
+			 TALLOC_CTX *mem_ctx,
+			 struct ctdb_iface_list_old **ifaces);
+int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb,
+			     struct timeval timeout, uint32_t destnode,
+			     TALLOC_CTX *mem_ctx,
+			     const struct ctdb_iface *info);
+
 int ctdb_ctrl_modflags(struct ctdb_context *ctdb,
 		       struct timeval timeout,
 		       uint32_t destnode,
 		       uint32_t set, uint32_t clear);
 
-enum ctdb_server_id_type {
-	SERVER_TYPE_SAMBA=1,
-	SERVER_TYPE_NFSD=2,
-	SERVER_TYPE_ISCSID=3
-};
+int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb,
+			       struct timeval timeout, uint32_t destnode,
+			       struct ctdb_tunable_list *tunables);
 
-struct ctdb_server_id {
-	enum ctdb_server_id_type type;
-	uint32_t pnn;
-	uint32_t server_id;
-};
+int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb,
+			    struct timeval timeout, uint32_t destnode,
+			    struct ctdb_addr_info_old *pub);
+int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb,
+			    struct timeval timeout, uint32_t destnode,
+			    struct ctdb_addr_info_old *pub);
 
-struct ctdb_server_id_list {
-	uint32_t num;
-	struct ctdb_server_id server_ids[1];
-};
+int ctdb_ctrl_killtcp(struct ctdb_context *ctdb,
+		      struct timeval timeout, uint32_t destnode,
+		      struct ctdb_connection *killtcp);
+
+int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb,
+			   struct timeval timeout, uint32_t destnode,
+			   ctdb_sock_addr *addr, const char *ifname);
 
+int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb,
+			      struct timeval timeout, uint32_t destnode,
+			      TALLOC_CTX *mem_ctx, ctdb_sock_addr *addr,
+			      struct ctdb_tickle_list_old **list);
 
 int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb,
-		struct timeval timeout,
-		struct ctdb_server_id *id);
+				 struct timeval timeout,
+				 struct ctdb_client_id *id);
 int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb,
-		struct timeval timeout,
-		struct ctdb_server_id *id);
+				   struct timeval timeout,
+				   struct ctdb_client_id *id);
 int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb,
-		struct timeval timeout, uint32_t destnode,
-		struct ctdb_server_id *id, uint32_t *status);
+			      struct timeval timeout, uint32_t destnode,
+			      struct ctdb_client_id *id, uint32_t *status);
 int ctdb_ctrl_get_server_id_list(struct ctdb_context *ctdb,
-		TALLOC_CTX *mem_ctx,
-		struct timeval timeout, uint32_t destnode,
-		struct ctdb_server_id_list **svid_list);
-
-struct ctdb_uptime {
-	struct timeval current_time;
-	struct timeval ctdbd_start_time;
-	struct timeval last_recovery_started;
-	struct timeval last_recovery_finished;
-};
+				 TALLOC_CTX *mem_ctx,
+				 struct timeval timeout, uint32_t destnode,
+				 struct ctdb_client_id_list_old **svid_list);
 
-struct ctdb_control_tcp_addr {
-	ctdb_sock_addr src;
-	ctdb_sock_addr dest;
-};
+/*
+  initialise ctdb subsystem
+*/
+struct ctdb_context *ctdb_init(struct tevent_context *ev);
 
-int ctdb_socket_connect(struct ctdb_context *ctdb);
+/*
+  set some flags
+*/
+void ctdb_set_flags(struct ctdb_context *ctdb, unsigned flags);
+
+int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname);
+const char *ctdb_get_socketname(struct ctdb_context *ctdb);
+
+/* return pnn of this node */
+uint32_t ctdb_get_pnn(struct ctdb_context *ctdb);
 
 /*
   get the uptime of a remote node
  */
-int ctdb_ctrl_uptime(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_uptime **uptime);
+struct ctdb_client_control_state *ctdb_ctrl_uptime_send(
+					struct ctdb_context *ctdb,
+					TALLOC_CTX *mem_ctx,
+					struct timeval timeout,
+					uint32_t destnode);
+int ctdb_ctrl_uptime_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+			  struct ctdb_client_control_state *state,
+			  struct ctdb_uptime **uptime);
+int ctdb_ctrl_uptime(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+		     struct timeval timeout, uint32_t destnode,
+		     struct ctdb_uptime **uptime);
+
+int ctdb_ctrl_end_recovery(struct ctdb_context *ctdb, struct timeval timeout,
+			   uint32_t destnode);
+
+typedef void (*client_async_callback)(struct ctdb_context *ctdb,
+				      uint32_t node_pnn, int32_t res,
+				      TDB_DATA outdata, void *callback_data);
+
+struct client_async_data {
+	enum ctdb_controls opcode;
+	bool dont_log_errors;
+	uint32_t count;
+	uint32_t fail_count;
+	client_async_callback callback;
+	client_async_callback fail_callback;
+	void *callback_data;
+};
+
+void ctdb_client_async_add(struct client_async_data *data,
+			   struct ctdb_client_control_state *state);
+int ctdb_client_async_wait(struct ctdb_context *ctdb,
+			   struct client_async_data *data);
+int ctdb_client_async_control(struct ctdb_context *ctdb,
+			      enum ctdb_controls opcode, uint32_t *nodes,
+			      uint64_t srvid, struct timeval timeout,
+			      bool dont_log_errors, TDB_DATA data,
+			      client_async_callback client_callback,
+			      client_async_callback fail_callback,
+			      void *callback_data);
 
-struct ctdb_client_control_state *ctdb_ctrl_uptime_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode);
+uint32_t *list_of_vnnmap_nodes(struct ctdb_context *ctdb,
+			       struct ctdb_vnn_map *vnn_map,
+			       TALLOC_CTX *mem_ctx, bool include_self);
 
-int ctdb_ctrl_uptime_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, struct ctdb_uptime **uptime);
+uint32_t *list_of_nodes(struct ctdb_context *ctdb,
+			struct ctdb_node_map_old *node_map,
+			TALLOC_CTX *mem_ctx, uint32_t mask, int exclude_pnn);
+uint32_t *list_of_active_nodes(struct ctdb_context *ctdb,
+			       struct ctdb_node_map_old *node_map,
+			       TALLOC_CTX *mem_ctx, bool include_self);
+uint32_t *list_of_connected_nodes(struct ctdb_context *ctdb,
+				  struct ctdb_node_map_old *node_map,
+				  TALLOC_CTX *mem_ctx, bool include_self);
 
-int ctdb_ctrl_end_recovery(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+int ctdb_read_pnn_lock(int fd, int32_t pnn);
 
-int ctdb_ctrl_getreclock(struct ctdb_context *ctdb,
-	struct timeval timeout, uint32_t destnode,
-	TALLOC_CTX *mem_ctx, const char **reclock);
-int ctdb_ctrl_setreclock(struct ctdb_context *ctdb,
-	struct timeval timeout, uint32_t destnode,
-	const char *reclock);
+/*
+  get capabilities of a remote node
+ */
+
+struct ctdb_client_control_state *ctdb_ctrl_getcapabilities_send(
+					struct ctdb_context *ctdb,
+					TALLOC_CTX *mem_ctx,
+					struct timeval timeout,
+					uint32_t destnode);
+int ctdb_ctrl_getcapabilities_recv(struct ctdb_context *ctdb,
+				   TALLOC_CTX *mem_ctx,
+				   struct ctdb_client_control_state *state,
+				   uint32_t *capabilities);
+int ctdb_ctrl_getcapabilities(struct ctdb_context *ctdb,
+			      struct timeval timeout, uint32_t destnode,
+			      uint32_t *capabilities);
 
 struct ctdb_node_capabilities {
 	bool retrieved;
@@ -455,62 +533,24 @@ struct ctdb_node_capabilities {
 
 /* Retrieve capabilities for all connected nodes.  The length of the
  * returned array can be calculated using talloc_array_length(). */
-struct ctdb_node_capabilities *
-ctdb_get_capabilities(struct ctdb_context *ctdb,
-		      TALLOC_CTX *mem_ctx,
-		      struct timeval timeout,
-		      struct ctdb_node_map *nodemap);
+struct ctdb_node_capabilities *ctdb_get_capabilities(
+					struct ctdb_context *ctdb,
+					TALLOC_CTX *mem_ctx,
+					struct timeval timeout,
+					struct ctdb_node_map_old *nodemap);
 
 /* Get capabilities for specified node, NULL if not found */
-uint32_t *
-ctdb_get_node_capabilities(struct ctdb_node_capabilities *caps,
-			   uint32_t pnn);
+uint32_t *ctdb_get_node_capabilities(struct ctdb_node_capabilities *caps,
+				     uint32_t pnn);
 
 /* True if the given node has all of the required capabilities */
 bool ctdb_node_has_capabilities(struct ctdb_node_capabilities *caps,
-				uint32_t pnn,
-				uint32_t capabilities_required);
-
-uint32_t *list_of_nodes(struct ctdb_context *ctdb,
-			struct ctdb_node_map *node_map,
-			TALLOC_CTX *mem_ctx,
-			uint32_t mask,
-			int exclude_pnn);
-uint32_t *list_of_connected_nodes(struct ctdb_context *ctdb,
-				struct ctdb_node_map *node_map,
-				TALLOC_CTX *mem_ctx,
-				bool include_self);
-uint32_t *list_of_active_nodes(struct ctdb_context *ctdb,
-				struct ctdb_node_map *node_map,
-				TALLOC_CTX *mem_ctx,
-				bool include_self);
-uint32_t *list_of_vnnmap_nodes(struct ctdb_context *ctdb,
-				struct ctdb_vnn_map *vnn_map,
-				TALLOC_CTX *mem_ctx,
-				bool include_self);
-
-int ctdb_read_pnn_lock(int fd, int32_t pnn);
-
-/*
-  get capabilities of a remote node
- */
-int ctdb_ctrl_getcapabilities(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *capabilities);
-
-struct ctdb_client_control_state *ctdb_ctrl_getcapabilities_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode);
-
-int ctdb_ctrl_getcapabilities_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *capabilities);
+				uint32_t pnn, uint32_t capabilities_required);
 
-struct ctdb_marshall_buffer *ctdb_marshall_add(TALLOC_CTX *mem_ctx,
-					       struct ctdb_marshall_buffer *m,
-					       uint64_t db_id,
-					       uint32_t reqid,
-					       TDB_DATA key,
-					       struct ctdb_ltdb_header *header,
-					       TDB_DATA data);
-TDB_DATA ctdb_marshall_finish(struct ctdb_marshall_buffer *m);
 
-struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *ctdb_db,
-						       TALLOC_CTX *mem_ctx);
+struct ctdb_transaction_handle *ctdb_transaction_start(
+					struct ctdb_db_context *ctdb_db,
+					TALLOC_CTX *mem_ctx);
 int ctdb_transaction_fetch(struct ctdb_transaction_handle *h,
 			   TALLOC_CTX *mem_ctx,
 			   TDB_DATA key, TDB_DATA *data);
@@ -521,62 +561,93 @@ int ctdb_transaction_cancel(struct ctdb_transaction_handle *h);
 
 int ctdb_ctrl_recd_ping(struct ctdb_context *ctdb);
 
-int switch_from_server_to_client(struct ctdb_context *ctdb, const char *fmt,
-				 ...);
-
 int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb,
-		    struct timeval timeout, uint32_t destnode,
-		    TALLOC_CTX *mem_ctx, enum ctdb_eventscript_call type,
-		    struct ctdb_scripts_wire **script_status);
-
-
-int ctdb_ctrl_stop_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
-int ctdb_ctrl_continue_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
-
-int ctdb_ctrl_setnatgwstate(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t natgwstate);
-int ctdb_ctrl_setlmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t lmasterrole);
-int ctdb_ctrl_setrecmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmasterrole);
-
-int ctdb_ctrl_enablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script);
-int ctdb_ctrl_disablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script);
-
-struct ctdb_ban_time {
-	uint32_t pnn;
-	uint32_t time;
-};
+			      struct timeval timeout, uint32_t destnode,
+			      TALLOC_CTX *mem_ctx,
+			      enum ctdb_event type,
+			      struct ctdb_script_list_old **script_status);
 
-int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_ban_time *bantime);
-int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_ban_time **bantime);
+int ctdb_ctrl_report_recd_lock_latency(struct ctdb_context *ctdb,
+				       struct timeval timeout, double latency);
 
-struct ctdb_db_priority {
-	uint32_t db_id;
-	uint32_t priority;
-};
-
-int ctdb_ctrl_set_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_db_priority *db_prio);
-int ctdb_ctrl_get_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t db_id, uint32_t *priority);
-
-int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_statistics_wire **stats);
-
-
-
-struct ctdb_client_control_state *
-ctdb_ctrl_updaterecord_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data);
-
-int ctdb_ctrl_updaterecord_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state);
-
-int
-ctdb_ctrl_updaterecord(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data);
-
-
-struct ctdb_client_control_state *
-ctdb_ctrl_set_db_readonly_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid);
-int ctdb_ctrl_set_db_readonly_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state);
-int ctdb_ctrl_set_db_readonly(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid);
+int ctdb_ctrl_getreclock(struct ctdb_context *ctdb,
+			 struct timeval timeout, uint32_t destnode,
+			 TALLOC_CTX *mem_ctx, const char **reclock);
+int ctdb_ctrl_setreclock(struct ctdb_context *ctdb,
+			 struct timeval timeout, uint32_t destnode,
+			 const char *reclock);
 
-struct ctdb_client_control_state *
-ctdb_ctrl_set_db_sticky_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid);
-int ctdb_ctrl_set_db_sticky_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state);
-int ctdb_ctrl_set_db_sticky(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid);
+int ctdb_ctrl_stop_node(struct ctdb_context *ctdb, struct timeval timeout,
+			uint32_t destnode);
+int ctdb_ctrl_continue_node(struct ctdb_context *ctdb, struct timeval timeout,
+			    uint32_t destnode);
+
+int ctdb_ctrl_setnatgwstate(struct ctdb_context *ctdb,
+			    struct timeval timeout, uint32_t destnode,
+			    uint32_t natgwstate);
+int ctdb_ctrl_setlmasterrole(struct ctdb_context *ctdb,
+			     struct timeval timeout, uint32_t destnode,
+			     uint32_t lmasterrole);
+int ctdb_ctrl_setrecmasterrole(struct ctdb_context *ctdb,
+			       struct timeval timeout, uint32_t destnode,
+			       uint32_t recmasterrole);
+
+int ctdb_ctrl_enablescript(struct ctdb_context *ctdb, struct timeval timeout,
+			   uint32_t destnode, const char *script);
+int ctdb_ctrl_disablescript(struct ctdb_context *ctdb, struct timeval timeout,
+			    uint32_t destnode, const char *script);
+
+int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout,
+		      uint32_t destnode, struct ctdb_ban_state *bantime);
+int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout,
+		      uint32_t destnode, TALLOC_CTX *mem_ctx,
+		      struct ctdb_ban_state **bantime);
+
+int ctdb_ctrl_set_db_priority(struct ctdb_context *ctdb,
+			      struct timeval timeout, uint32_t destnode,
+			      struct ctdb_db_priority *db_prio);
+int ctdb_ctrl_get_db_priority(struct ctdb_context *ctdb,
+			      struct timeval timeout, uint32_t destnode,
+			      uint32_t db_id, uint32_t *priority);
+
+int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb,
+			     struct timeval timeout, uint32_t destnode,
+			     TALLOC_CTX *mem_ctx,
+			     struct ctdb_statistics_list_old **stats);
+
+struct ctdb_ltdb_header *ctdb_header_from_record_handle(
+					struct ctdb_record_handle *h);
+
+struct ctdb_client_control_state *ctdb_ctrl_updaterecord_send(
+					struct ctdb_context *ctdb,
+					TALLOC_CTX *mem_ctx,
+					struct timeval timeout,
+					uint32_t destnode,
+					struct ctdb_db_context *ctdb_db,
+					TDB_DATA key,
+					struct ctdb_ltdb_header *header,
+					TDB_DATA data);
+int ctdb_ctrl_updaterecord_recv(struct ctdb_context *ctdb,
+				struct ctdb_client_control_state *state);
+int ctdb_ctrl_updaterecord(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+			   struct timeval timeout, uint32_t destnode,
+			   struct ctdb_db_context *ctdb_db, TDB_DATA key,
+			   struct ctdb_ltdb_header *header, TDB_DATA data);
+
+struct ctdb_client_control_state *ctdb_ctrl_set_db_readonly_send(
+					struct ctdb_context *ctdb,
+					uint32_t destnode, uint32_t dbid);
+int ctdb_ctrl_set_db_readonly_recv(struct ctdb_context *ctdb,
+				   struct ctdb_client_control_state *state);
+int ctdb_ctrl_set_db_readonly(struct ctdb_context *ctdb, uint32_t destnode,
+			      uint32_t dbid);
+
+struct ctdb_client_control_state *ctdb_ctrl_set_db_sticky_send(
+					struct ctdb_context *ctdb,
+					uint32_t destnode, uint32_t dbid);
+int ctdb_ctrl_set_db_sticky_recv(struct ctdb_context *ctdb,
+				 struct ctdb_client_control_state *state);
+int ctdb_ctrl_set_db_sticky(struct ctdb_context *ctdb, uint32_t destnode,
+			    uint32_t dbid);
 
 #endif /* _CTDB_CLIENT_H */
diff --git a/ctdb/include/ctdb_logging.h b/ctdb/include/ctdb_logging.h
deleted file mode 100644
index c419e85..0000000
--- a/ctdb/include/ctdb_logging.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-   ctdb logging code
-
-   Copyright (C) Andrew Tridgell  2008
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _CTDB_LOGGING_H_
-#define _CTDB_LOGGING_H_
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <talloc.h>
-
-extern const char *debug_extra;
-
-enum debug_level {
-	DEBUG_ERR     =  0,
-	DEBUG_WARNING =  1,
-	DEBUG_NOTICE  =  2,
-	DEBUG_INFO    =  3,
-	DEBUG_DEBUG   =  4,
-};
-
-/* These are used in many places, so define them here to avoid churn */
-#define DEBUG_ALERT DEBUG_ERR
-#define	DEBUG_CRIT  DEBUG_ERR
-
-const char *get_debug_by_level(int32_t level);
-bool parse_debug(const char *str, int32_t *level);
-void print_debug_levels(FILE *stream);
-
-bool ctdb_logging_init(TALLOC_CTX *mem_ctx, const char *logging);
-typedef int (*ctdb_log_setup_fn_t)(TALLOC_CTX *mem_ctx,
-				   const char *logging,
-				   const char *app_name);
-void ctdb_log_register_backend(const char *prefix, ctdb_log_setup_fn_t init);
-void ctdb_log_init_file(void);
-void ctdb_log_init_syslog(void);
-
-#endif /* _CTDB_LOGGING_H_ */
diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h
index 4cb0fe6..b7c3e5d 100644
--- a/ctdb/include/ctdb_private.h
+++ b/ctdb/include/ctdb_private.h
@@ -24,109 +24,11 @@
 #include <sys/socket.h>
 
 /*
- * Structures to support SRVID requests and replies
- */
-struct srvid_request {
-	uint32_t pnn;
-	uint64_t srvid;
-};
-
-struct srvid_request_data {
-	uint32_t pnn;
-	uint64_t srvid;
-	uint32_t data;
-};
-
-/*
-  a tcp connection description
-  also used by tcp_add and tcp_remove controls
- */
-struct ctdb_tcp_connection {
-	ctdb_sock_addr src_addr;
-	ctdb_sock_addr dst_addr;
-};
-
-/* the wire representation for a tcp tickle array */
-struct ctdb_tcp_wire_array {
-	uint32_t num;
-	struct ctdb_tcp_connection connections[1];
-};	
-
-/* the list of tcp tickles used by get/set tcp tickle list */
-struct ctdb_control_tcp_tickle_list {
-	ctdb_sock_addr addr;
-	struct ctdb_tcp_wire_array tickles;
-};
-
-/*
   array of tcp connections
  */
 struct ctdb_tcp_array {
 	uint32_t num;
-	struct ctdb_tcp_connection *connections;
-};	
-
-
-/* all tunable variables go in here */
-struct ctdb_tunable {
-	uint32_t max_redirect_count;
-	uint32_t seqnum_interval; /* unit is ms */
-	uint32_t control_timeout;
-	uint32_t traverse_timeout;
-	uint32_t keepalive_interval;
-	uint32_t keepalive_limit;
-	uint32_t recover_timeout;
-	uint32_t recover_interval;
-	uint32_t election_timeout;
-	uint32_t takeover_timeout;
-	uint32_t monitor_interval;
-	uint32_t tickle_update_interval;
-	uint32_t script_timeout;
-	uint32_t script_timeout_count; /* allow dodgy scripts to hang this many times in a row before we mark the node unhealthy */
-	uint32_t script_unhealthy_on_timeout; /* obsolete */
-	uint32_t recovery_grace_period;
-	uint32_t recovery_ban_period;
-	uint32_t database_hash_size;
-	uint32_t database_max_dead;
-	uint32_t rerecovery_timeout;
-	uint32_t enable_bans;
-	uint32_t deterministic_public_ips;
-	uint32_t reclock_ping_period;
-	uint32_t no_ip_failback;
-	uint32_t disable_ip_failover;
-	uint32_t verbose_memory_names;
-	uint32_t recd_ping_timeout;
-	uint32_t recd_ping_failcount;
-	uint32_t log_latency_ms;
-	uint32_t reclock_latency_ms;
-	uint32_t recovery_drop_all_ips;
-	uint32_t verify_recovery_lock;
-	uint32_t vacuum_interval;
-	uint32_t vacuum_max_run_time;
-	uint32_t repack_limit;
-	uint32_t vacuum_limit;
-	uint32_t max_queue_depth_drop_msg;
-	uint32_t allow_unhealthy_db_read;
-	uint32_t stat_history_interval;
-	uint32_t deferred_attach_timeout;
-	uint32_t vacuum_fast_path_count;
-	uint32_t lcp2_public_ip_assignment;
-	uint32_t allow_client_db_attach;
-	uint32_t recover_pdb_by_seqnum;
-	uint32_t deferred_rebalance_on_node_add;
-	uint32_t fetch_collapse;
-	uint32_t hopcount_make_sticky;
-	uint32_t sticky_duration;
-	uint32_t sticky_pindown;
-	uint32_t no_ip_takeover;
-	uint32_t db_record_count_warn;
-	uint32_t db_record_size_warn;
-	uint32_t db_size_warn;
-	uint32_t pulldb_preallocation_size;
-	uint32_t no_ip_host_on_all_disabled;
-	uint32_t samba3_hack;
-	uint32_t mutex_enabled;
-	uint32_t lock_processes_per_db;
+	struct ctdb_connection *connections;
 };
 
 /*
@@ -169,13 +71,11 @@ struct ctdb_client {
 	struct ctdb_client_notify_list *notify;
 };
 
-struct ctdb_iface;
-
 /* state associated with a public ip address */
 struct ctdb_vnn {
 	struct ctdb_vnn *prev, *next;
 
-	struct ctdb_iface *iface;
+	struct ctdb_interface *iface;
 	const char **ifaces;
 	ctdb_sock_addr public_address;
 	uint8_t public_netmask_bits;
@@ -226,12 +126,6 @@ struct ctdb_node {
 	   if the node becomes disconnected */
 	struct daemon_control_state *pending_controls;
 
-	/* used by the recovery daemon when distributing ip addresses 
-	   across the nodes.  it needs to know which public ip's can be handled
-	   by each node.
-	*/
-	struct ctdb_all_public_ips *known_public_ips;
-	struct ctdb_all_public_ips *available_public_ips;
 	/* used by the recovery dameon to track when a node should be banned */
 	struct ctdb_banning_state *ban_state; 
 };
@@ -264,21 +158,6 @@ struct ctdb_upcalls {
 	void (*node_connected)(struct ctdb_node *);
 };
 
-/* list of message handlers - needs to be changed to a more efficient data
-   structure so we can find a message handler given a srvid quickly */
-struct ctdb_message_list_header {
-	struct ctdb_message_list_header *next, *prev;
-	struct ctdb_context *ctdb;
-	uint64_t srvid;
-	struct ctdb_message_list *m;
-};
-struct ctdb_message_list {
-	struct ctdb_message_list *next, *prev;
-	struct ctdb_message_list_header *h;
-	ctdb_msg_fn_t message_handler;
-	void *message_private;
-};
-
 /* additional data required for the daemon mode */
 struct ctdb_daemon_data {
 	int sd;
@@ -403,38 +282,8 @@ struct ctdb_daemon_data {
 	}
 
 
-
-/* a structure that contains the elements required for the write record
-   control
-*/
-struct ctdb_write_record {
-	uint32_t dbid;
-	uint32_t keylen;
-	uint32_t datalen;
-	unsigned char blob[1];
-};
-
 enum ctdb_freeze_mode {CTDB_FREEZE_NONE, CTDB_FREEZE_PENDING, CTDB_FREEZE_FROZEN};
 
-enum ctdb_runstate {
-	CTDB_RUNSTATE_UNKNOWN,
-	CTDB_RUNSTATE_INIT,
-	CTDB_RUNSTATE_SETUP,
-	CTDB_RUNSTATE_FIRST_RECOVERY,
-	CTDB_RUNSTATE_STARTUP,
-	CTDB_RUNSTATE_RUNNING,
-	CTDB_RUNSTATE_SHUTDOWN,
-};
-
-const char *runstate_to_string(enum ctdb_runstate runstate);
-enum ctdb_runstate runstate_from_string(const char *label);
-void ctdb_set_runstate(struct ctdb_context *ctdb, enum ctdb_runstate runstate);
-
-void ctdb_shutdown_sequence(struct ctdb_context *ctdb, int exit_code);
-
-#define CTDB_MONITORING_ACTIVE		0
-#define CTDB_MONITORING_DISABLED	1
-
 #define NUM_DB_PRIORITIES 3
 /* main state of the ctdb daemon */
 struct ctdb_context {
@@ -446,7 +295,7 @@ struct ctdb_context {
 	TALLOC_CTX *tickle_update_context;
 	TALLOC_CTX *keepalive_ctx;
 	TALLOC_CTX *check_public_ifaces_ctx;
-	struct ctdb_tunable tunable;
+	struct ctdb_tunable_list tunable;
 	enum ctdb_freeze_mode freeze_mode[NUM_DB_PRIORITIES+1];
 	struct ctdb_freeze_handle *freeze_handles[NUM_DB_PRIORITIES+1];
 	bool freeze_transaction_started;
@@ -468,19 +317,17 @@ struct ctdb_context {
 	uint32_t num_connected;
 	unsigned flags;
 	uint32_t capabilities;
-	struct idr_context *idr;
-	int lastid;
+	struct reqid_context *idr;
 	struct ctdb_node **nodes; /* array of nodes in the cluster - indexed by vnn */
 	struct ctdb_vnn *vnn; /* list of public ip addresses and interfaces */
 	struct ctdb_vnn *single_ip_vnn; /* a structure for the single ip */
-	struct ctdb_iface *ifaces; /* list of local interfaces */
+	struct ctdb_interface *ifaces; /* list of local interfaces */
 	char *err_msg;
 	const struct ctdb_methods *methods; /* transport methods */
 	const struct ctdb_upcalls *upcalls; /* transport upcalls */
 	void *private_data; /* private to transport */
 	struct ctdb_db_context *db_list;
-	struct ctdb_message_list_header *message_list_header;
-	struct tdb_context *message_list_indexdb;
+	struct srvid_context *srv;
 	struct ctdb_daemon_data daemon;
 	struct ctdb_statistics statistics;
 	struct ctdb_statistics statistics_current;
@@ -489,7 +336,6 @@ struct ctdb_context {
 	struct ctdb_vnn_map *vnn_map;
 	uint32_t num_clients;
 	uint32_t recovery_master;
-	struct ctdb_call_state *pending_calls;
 	struct ctdb_client_ip *client_ip_list;
 	bool do_checkpublicip;
 	struct trbt_tree *server_ids; 
@@ -504,7 +350,6 @@ struct ctdb_context {
 	int start_as_disabled;
 	int start_as_stopped;
 	bool valgrinding;
-	uint32_t event_script_timeouts; /* counting how many consecutive times an eventscript has timedout */
 	uint32_t *recd_ping_count;
 	TALLOC_CTX *recd_ctx; /* a context used to track recoverd monitoring events */
 	TALLOC_CTX *release_ips_ctx; /* a context used to automatically drop all IPs if we fail to recover the node */
@@ -513,7 +358,7 @@ struct ctdb_context {
 	int active_events;
 
 	struct ctdb_event_script_state *current_monitor;
-	struct ctdb_scripts_wire *last_status[CTDB_EVENT_MAX];
+	struct ctdb_script_list_old *last_status[CTDB_EVENT_MAX];
 
 	TALLOC_CTX *banning_ctx;
 
@@ -559,7 +404,7 @@ struct ctdb_db_context {
 	struct tdb_context *rottdb; /* ReadOnly tracking TDB */
 	struct ctdb_registered_call *calls; /* list of registered calls */
 	uint32_t seqnum;
-	struct timed_event *seqnum_update;
+	struct tevent_timer *seqnum_update;
 	struct ctdb_traverse_local_handle *traverse;
 	struct ctdb_vacuum_handle *vacuum_handle;
 	char *unhealthy_reason;
@@ -579,11 +424,19 @@ struct ctdb_db_context {
 	struct trbt_tree *deferred_fetch;
 	struct trbt_tree *defer_dmaster;
 
-	struct ctdb_db_statistics statistics;
+	struct ctdb_db_statistics_old statistics;
 
 	struct lock_context *lock_current;
 	struct lock_context *lock_pending;
 	int lock_num_current;
+
+	struct ctdb_call_state *pending_calls;
+
+	enum ctdb_freeze_mode freeze_mode;
+	struct ctdb_db_freeze_handle *freeze_handle;
+	bool freeze_transaction_started;
+	uint32_t freeze_transaction_id;
+	uint32_t generation;
 };
 
 
@@ -607,66 +460,9 @@ struct ctdb_db_context {
           ctdb_fatal(ctdb, "Out of memory in " __location__ ); \
 	  }} while (0)
 
-/*
-  struct for kill_tcp control
- */
-struct ctdb_control_killtcp {
-	ctdb_sock_addr src_addr;
-	ctdb_sock_addr dst_addr;
-};
-
-/*
-  struct holding a ctdb_sock_addr and an interface name,
-  used to add/remove public addresses
- */
-struct ctdb_control_ip_iface {
-	ctdb_sock_addr addr;
-	uint32_t mask;
-	uint32_t len;
-	char iface[1];
-};
-
-/*
-  struct holding a ctdb_sock_addr and an interface name,
-  used for send_gratious_arp
- */
-struct ctdb_control_gratious_arp {
-	ctdb_sock_addr addr;
-	uint32_t mask;
-	uint32_t len;
-	char iface[1];
-};
-
-/*
-  persistent store control - update this record on all other nodes
- */
-struct ctdb_control_persistent_store {
-	uint32_t db_id;
-	uint32_t len;
-	uint8_t  data[1];
-};
-
-/*
-  structure used for CTDB_SRVID_NODE_FLAGS_CHANGED
- */
-struct ctdb_node_flag_change {
-	uint32_t pnn;
-	uint32_t new_flags;
-	uint32_t old_flags;
-};
-
-/*
-  struct for admin setting a ban
- */
-struct ctdb_ban_info {
-	uint32_t pnn;
-	uint32_t ban_time;
-};
 
 enum call_state {CTDB_CALL_WAIT, CTDB_CALL_DONE, CTDB_CALL_ERROR};
 
-#define CTDB_LMASTER_ANY	0xffffffff
-
 /*
   state of a in-progress ctdb call
 */
@@ -674,7 +470,7 @@ struct ctdb_call_state {
 	struct ctdb_call_state *next, *prev;
 	enum call_state state;
 	uint32_t reqid;
-	struct ctdb_req_call *c;
+	struct ctdb_req_call_old *c;
 	struct ctdb_db_context *ctdb_db;
 	const char *errmsg;
 	struct ctdb_call *call;
@@ -685,822 +481,629 @@ struct ctdb_call_state {
 	} async;
 };
 
-
-/* used for fetch_lock */
-struct ctdb_fetch_handle {
-	struct ctdb_db_context *ctdb_db;
-	TDB_DATA key;
-	TDB_DATA *data;
-	struct ctdb_ltdb_header header;
-};
-
 /* internal prototypes */
-void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-void ctdb_fatal(struct ctdb_context *ctdb, const char *msg);
-void ctdb_die(struct ctdb_context *ctdb, const char *msg);
-bool ctdb_set_helper(const char *type, char *helper, size_t size,
-		     const char *envvar, const char *dir, const char *file);
-void ctdb_external_trace(void);
-bool ctdb_same_address(ctdb_sock_addr *a1, ctdb_sock_addr *a2);
-int ctdb_parse_address(TALLOC_CTX *mem_ctx, const char *str,
-		       ctdb_sock_addr *address);
-bool ctdb_same_ip(const ctdb_sock_addr *ip1, const ctdb_sock_addr *ip2);
-bool ctdb_same_sockaddr(const ctdb_sock_addr *ip1, const ctdb_sock_addr *ip2);
-uint32_t ctdb_hash(const TDB_DATA *key);
-uint32_t *ctdb_key_to_idkey(TALLOC_CTX *mem_ctx, TDB_DATA key);
-
-void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
-void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
-void ctdb_request_message(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
-void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
-void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
-void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
-
-uint32_t ctdb_lmaster(struct ctdb_context *ctdb, const TDB_DATA *key);
-int ctdb_ltdb_fetch(struct ctdb_db_context *ctdb_db, 
-		    TDB_DATA key, struct ctdb_ltdb_header *header, 
-		    TALLOC_CTX *mem_ctx, TDB_DATA *data);
-int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, 
-		    struct ctdb_ltdb_header *header, TDB_DATA data);
-int ctdb_ltdb_delete(struct ctdb_db_context *ctdb_db, TDB_DATA key);
-int ctdb_ltdb_fetch_with_header(struct ctdb_db_context *ctdb_db, 
-		    TDB_DATA key, struct ctdb_ltdb_header *header, 
-		    TALLOC_CTX *mem_ctx, TDB_DATA *data);
-int32_t ctdb_control_start_persistent_update(struct ctdb_context *ctdb, 
-			struct ctdb_req_control *c,
-			TDB_DATA recdata);
-int32_t ctdb_control_cancel_persistent_update(struct ctdb_context *ctdb, 
-			struct ctdb_req_control *c,
-			TDB_DATA recdata);
-void ctdb_queue_packet(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
-void ctdb_queue_packet_opcode(struct ctdb_context *ctdb, struct ctdb_req_header *hdr, unsigned opcode);
-int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db, 
-			   TDB_DATA key, struct ctdb_req_header *hdr,
-			   void (*recv_pkt)(void *, struct ctdb_req_header *),
-			   void *recv_context, bool ignore_generation);
-int ctdb_ltdb_lock_fetch_requeue(struct ctdb_db_context *ctdb_db, 
-				 TDB_DATA key, struct ctdb_ltdb_header *header, 
-				 struct ctdb_req_header *hdr, TDB_DATA *data,
-				 void (*recv_pkt)(void *, struct ctdb_req_header *),
-				 void *recv_context, bool ignore_generation);
-void ctdb_input_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *);
-
-struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db, 
-					     struct ctdb_call *call,
-					     struct ctdb_ltdb_header *header,
-					     TDB_DATA *data);
 
+#define CHECK_CONTROL_DATA_SIZE(size) do { \
+ if (indata.dsize != size) { \
+	 DEBUG(0,(__location__ " Invalid data size in opcode %u. Got %u expected %u\n", \
+		  opcode, (unsigned)indata.dsize, (unsigned)size));	\
+	 return -1; \
+ } \
+ } while (0)
 
-int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork);
+#define CHECK_CONTROL_MIN_DATA_SIZE(size) do { \
+ if (indata.dsize < size) { \
+	 DEBUG(0,(__location__ " Invalid data size in opcode %u. Got %u expected >= %u\n", \
+		  opcode, (unsigned)indata.dsize, (unsigned)size));	\
+	 return -1; \
+ } \
+ } while (0)
 
 /*
-  queue a packet for sending
+  state of a in-progress ctdb call in client
 */
-int ctdb_queue_send(struct ctdb_queue *queue, uint8_t *data, uint32_t length);
+struct ctdb_client_call_state {
+	enum call_state state;
+	uint32_t reqid;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_call *call;
+	struct {
+		void (*fn)(struct ctdb_client_call_state *);
+		void *private_data;
+	} async;
+};
 
-/*
-  setup the fd used by the queue
- */
-int ctdb_queue_set_fd(struct ctdb_queue *queue, int fd);
+extern int script_log_level;
+extern bool fast_start;
+extern const char *ctdbd_pidfile;
 
-/*
-  setup a packet queue on a socket
- */
-struct ctdb_queue *ctdb_queue_setup(struct ctdb_context *ctdb,
-				    TALLOC_CTX *mem_ctx, int fd, int alignment,
-				    
-				    ctdb_queue_cb_fn_t callback,
-				    void *private_data, const char *fmt, ...)
-	PRINTF_ATTRIBUTE(7,8);
+typedef void (*deferred_requeue_fn)(void *call_context, struct ctdb_req_header *hdr);
 
-/*
-  allocate a packet for use in client<->daemon communication
- */
-struct ctdb_req_header *_ctdbd_allocate_pkt(struct ctdb_context *ctdb,
-					    TALLOC_CTX *mem_ctx, 
-					    enum ctdb_operation operation, 
-					    size_t length, size_t slength,
-					    const char *type);
-#define ctdbd_allocate_pkt(ctdb, mem_ctx, operation, length, type) \
-	(type *)_ctdbd_allocate_pkt(ctdb, mem_ctx, operation, length, sizeof(type), #type)
 
-struct ctdb_req_header *_ctdb_transport_allocate(struct ctdb_context *ctdb,
-						 TALLOC_CTX *mem_ctx, 
-						 enum ctdb_operation operation, 
-						 size_t length, size_t slength,
-						 const char *type);
-#define ctdb_transport_allocate(ctdb, mem_ctx, operation, length, type) \
-	(type *)_ctdb_transport_allocate(ctdb, mem_ctx, operation, length, sizeof(type), #type)
+/* from tcp/ and ib/ */
+
+int ctdb_tcp_init(struct ctdb_context *ctdb);
+int ctdb_ibw_init(struct ctdb_context *ctdb);
 
-int ctdb_queue_length(struct ctdb_queue *queue);
+/* from ctdb_banning.c */
 
-/*
-  lock a record in the ltdb, given a key
- */
-int ctdb_ltdb_lock(struct ctdb_db_context *ctdb_db, TDB_DATA key);
+void ctdb_local_node_got_banned(struct ctdb_context *ctdb);
+int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_get_ban_state(struct ctdb_context *ctdb, TDB_DATA *outdata);
+void ctdb_ban_self(struct ctdb_context *ctdb);
 
-/*
-  unlock a record in the ltdb, given a key
- */
-int ctdb_ltdb_unlock(struct ctdb_db_context *ctdb_db, TDB_DATA key);
+/* from ctdb_call.c */
 
+struct ctdb_db_context *find_ctdb_db(struct ctdb_context *ctdb, uint32_t id);
 
-int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t vnn,
-			     uint64_t srvid, TDB_DATA data);
+void ctdb_request_dmaster(struct ctdb_context *ctdb,
+			  struct ctdb_req_header *hdr);
+void ctdb_reply_dmaster(struct ctdb_context *ctdb,
+			struct ctdb_req_header *hdr);
+void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
 
-/*
-  send a ctdb message
-*/
-int ctdb_daemon_send_message(struct ctdb_context *ctdb, uint32_t pnn,
-			     uint64_t srvid, TDB_DATA data);
+void ctdb_call_resend_db(struct ctdb_db_context *ctdb);
+void ctdb_call_resend_all(struct ctdb_context *ctdb);
+
+struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db,
+					     struct ctdb_call *call,
+					     struct ctdb_ltdb_header *header,
+					     TDB_DATA *data);
 
+struct ctdb_call_state *ctdb_daemon_call_send_remote(
+					struct ctdb_db_context *ctdb_db,
+					struct ctdb_call *call,
+					struct ctdb_ltdb_header *header);
+int ctdb_daemon_call_recv(struct ctdb_call_state *state,
+			  struct ctdb_call *call);
 
-int ctdb_daemon_call_recv(struct ctdb_call_state *state, struct ctdb_call *call);
+void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode);
 
-struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctdb_db, 
-						     struct ctdb_call *call, 
-						     struct ctdb_ltdb_header *header);
+int ctdb_start_revoke_ro_record(struct ctdb_context *ctdb,
+				struct ctdb_db_context *ctdb_db,
+				TDB_DATA key, struct ctdb_ltdb_header *header,
+				TDB_DATA data);
 
-int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call,
-		    struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx,
-		    TDB_DATA *data, bool updatetdb);
+int ctdb_add_revoke_deferred_call(struct ctdb_context *ctdb,
+				  struct ctdb_db_context *ctdb_db,
+				  TDB_DATA key, struct ctdb_req_header *hdr,
+				  deferred_requeue_fn fn, void *call_context);
 
-#define ctdb_reqid_find(ctdb, reqid, type)	(type *)_ctdb_reqid_find(ctdb, reqid, #type, __location__)
+/* from server/ctdb_control.c */
 
-int ctdb_socket_connect(struct ctdb_context *ctdb);
-void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args);
+int32_t ctdb_dump_memory(struct ctdb_context *ctdb, TDB_DATA *outdata);
 
-#define CTDB_BAD_REQID ((uint32_t)-1)
-uint32_t ctdb_reqid_new(struct ctdb_context *ctdb, void *state);
-void *_ctdb_reqid_find(struct ctdb_context *ctdb, uint32_t reqid, const char *type, const char *location);
-void ctdb_reqid_remove(struct ctdb_context *ctdb, uint32_t reqid);
+void ctdb_request_control_reply(struct ctdb_context *ctdb,
+				struct ctdb_req_control_old *c,
+				TDB_DATA *outdata, int32_t status,
+				const char *errormsg);
 
-void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
-void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_request_control(struct ctdb_context *ctdb,
+			  struct ctdb_req_header *hdr);
+void ctdb_reply_control(struct ctdb_context *ctdb,
+			struct ctdb_req_header *hdr);
 
 int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
-			     uint64_t srvid, uint32_t opcode, uint32_t client_id, uint32_t flags,
+			     uint64_t srvid, uint32_t opcode,
+			     uint32_t client_id, uint32_t flags,
 			     TDB_DATA data,
 			     ctdb_control_callback_fn_t callback,
 			     void *private_data);
 
-int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata, 
-			       TDB_DATA *outdata, uint64_t tdb_flags,
-			       bool persistent, uint32_t client_id,
-			       struct ctdb_req_control *c,
-			       bool *async_reply);
-int32_t ctdb_control_db_detach(struct ctdb_context *ctdb, TDB_DATA indata,
-			       uint32_t client_id);
-
-int ctdb_daemon_set_call(struct ctdb_context *ctdb, uint32_t db_id,
-			 ctdb_fn_t fn, int id);
+/* from server/ctdb_daemon.c */
 
-int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, 
-		 uint32_t opcode, uint32_t flags, TDB_DATA data, 
-		 TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
-		 struct timeval *timeout, char **errormsg);
-int ctdb_control_recv(struct ctdb_context *ctdb, 
-		struct ctdb_client_control_state *state, 
-		TALLOC_CTX *mem_ctx,
-		TDB_DATA *outdata, int32_t *status, char **errormsg);
-
-struct ctdb_client_control_state *
-ctdb_control_send(struct ctdb_context *ctdb, 
-		uint32_t destnode, uint64_t srvid, 
-		uint32_t opcode, uint32_t flags, TDB_DATA data, 
-		TALLOC_CTX *mem_ctx,
-		struct timeval *timeout,
-		char **errormsg);
+int daemon_register_message_handler(struct ctdb_context *ctdb,
+				    uint32_t client_id, uint64_t srvid);
+int daemon_deregister_message_handler(struct ctdb_context *ctdb,
+				      uint32_t client_id, uint64_t srvid);
+int daemon_check_srvids(struct ctdb_context *ctdb, TDB_DATA indata,
+			TDB_DATA *outdata);
 
+int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork);
 
+struct ctdb_req_header *_ctdb_transport_allocate(struct ctdb_context *ctdb,
+						 TALLOC_CTX *mem_ctx,
+						 enum ctdb_operation operation,
+						 size_t length, size_t slength,
+						 const char *type);
 
+#define ctdb_transport_allocate(ctdb, mem_ctx, operation, length, type) \
+	(type *)_ctdb_transport_allocate(ctdb, mem_ctx, operation, length, \
+					 sizeof(type), #type)
 
-#define CHECK_CONTROL_DATA_SIZE(size) do { \
- if (indata.dsize != size) { \
-	 DEBUG(0,(__location__ " Invalid data size in opcode %u. Got %u expected %u\n", \
-		  opcode, (unsigned)indata.dsize, (unsigned)size));	\
-	 return -1; \
- } \
- } while (0)
+void ctdb_daemon_cancel_controls(struct ctdb_context *ctdb,
+				 struct ctdb_node *node);
 
-#define CHECK_CONTROL_MIN_DATA_SIZE(size) do { \
- if (indata.dsize < size) { \
-	 DEBUG(0,(__location__ " Invalid data size in opcode %u. Got %u expected >= %u\n", \
-		  opcode, (unsigned)indata.dsize, (unsigned)size));	\
-	 return -1; \
- } \
- } while (0)
+int ctdb_daemon_set_call(struct ctdb_context *ctdb, uint32_t db_id,
+			 ctdb_fn_t fn, int id);
 
-int ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
-int ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
-int ctdb_control_getdbmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
-int ctdb_control_getnodemap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
-int ctdb_control_getnodesfile(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
+int ctdb_daemon_send_message(struct ctdb_context *ctdb, uint32_t pnn,
+			     uint64_t srvid, TDB_DATA data);
 
+int32_t ctdb_control_register_notify(struct ctdb_context *ctdb,
+				     uint32_t client_id, TDB_DATA indata);
+int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb,
+				       uint32_t client_id, TDB_DATA indata);
 
-/* structure used for pulldb control */
-struct ctdb_control_pulldb {
-	uint32_t db_id;
-	uint32_t lmaster;
-};
+struct ctdb_client *ctdb_find_client_by_pid(struct ctdb_context *ctdb,
+					    pid_t pid);
 
-/* structure used for sending lists of records */
-struct ctdb_marshall_buffer {
-	uint32_t db_id;
-	uint32_t count;
-	uint8_t data[1];
-};
+int32_t ctdb_control_process_exists(struct ctdb_context *ctdb, pid_t pid);
 
-/*
-  structure for setting a tunable
- */
-struct ctdb_control_set_tunable {
-	uint32_t value;
-	uint32_t length;
-	uint8_t  name[1];
-};
+int ctdb_control_getnodesfile(struct ctdb_context *ctdb, uint32_t opcode,
+			      TDB_DATA indata, TDB_DATA *outdata);
 
-/*
-  structure for getting a tunable
- */
-struct ctdb_control_get_tunable {
-	uint32_t length;
-	uint8_t  name[1];
-};
+void ctdb_shutdown_sequence(struct ctdb_context *ctdb, int exit_code);
 
-/*
-  structure for listing tunables
- */
-struct ctdb_control_list_tunable {
-	uint32_t length;
-	/* returns a : separated list of tunable names */
-	uint8_t  data[1];
-};
+int switch_from_server_to_client(struct ctdb_context *ctdb,
+				 const char *fmt, ...);
 
+/* From server/ctdb_fork.c */
 
-struct ctdb_control_wipe_database {
-	uint32_t db_id;
-	uint32_t transaction_id;
-};
+void ctdb_set_child_info(TALLOC_CTX *mem_ctx, const char *child_name_fmt, ...);
 
-/*
-  state of a in-progress ctdb call in client
-*/
-struct ctdb_client_call_state {
-	enum call_state state;
-	uint32_t reqid;
-	struct ctdb_db_context *ctdb_db;
-	struct ctdb_call *call;
-	struct {
-		void (*fn)(struct ctdb_client_call_state *);
-		void *private_data;
-	} async;
-};
+void ctdb_track_child(struct ctdb_context *ctdb, pid_t pid);
 
+pid_t ctdb_fork(struct ctdb_context *ctdb);
 
-int32_t ctdb_control_traverse_start_ext(struct ctdb_context *ctdb,
-					TDB_DATA indata,
-					TDB_DATA *outdata,
-					uint32_t srcnode,
-					uint32_t client_id);
-int32_t ctdb_control_traverse_start(struct ctdb_context *ctdb, TDB_DATA indata, 
-				    TDB_DATA *outdata, uint32_t srcnode, uint32_t client_id);
-int32_t ctdb_control_traverse_all(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata);
-int32_t ctdb_control_traverse_all_ext(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata);
-int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata);
-int32_t ctdb_control_traverse_kill(struct ctdb_context *ctdb, TDB_DATA indata, 
-				    TDB_DATA *outdata, uint32_t srcnode);
+struct tevent_signal *ctdb_init_sigchld(struct ctdb_context *ctdb);
 
-int ctdb_dispatch_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data);
-bool ctdb_check_message_handler(struct ctdb_context *ctdb, uint64_t srvid);
+int ctdb_kill(struct ctdb_context *ctdb, pid_t pid, int signum);
 
-int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid);
-int ctdb_deregister_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data);
-int daemon_deregister_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid);
-int daemon_check_srvids(struct ctdb_context *ctdb, TDB_DATA indata,
-			TDB_DATA *outdata);
+/* from server/ctdb_freeze.c */
 
-int32_t ctdb_ltdb_enable_seqnum(struct ctdb_context *ctdb, uint32_t db_id);
-int32_t ctdb_ltdb_update_seqnum(struct ctdb_context *ctdb, uint32_t db_id, uint32_t srcnode);
+int32_t ctdb_control_db_freeze(struct ctdb_context *ctdb,
+			       struct ctdb_req_control_old *c,
+			       uint32_t db_id, bool *async_reply);
+int32_t ctdb_control_db_thaw(struct ctdb_context *ctdb, uint32_t db_id);
 
-struct ctdb_rec_data *ctdb_marshall_record(TALLOC_CTX *mem_ctx, uint32_t reqid,	
-					   TDB_DATA key, struct ctdb_ltdb_header *, TDB_DATA data);
+int32_t ctdb_control_freeze(struct ctdb_context *ctdb,
+			    struct ctdb_req_control_old *c, bool *async_reply);
+int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority,
+			  bool check_recmode);
 
-struct ctdb_rec_data *ctdb_marshall_loop_next(struct ctdb_marshall_buffer *m, struct ctdb_rec_data *r,
-					      uint32_t *reqid,
-					      struct ctdb_ltdb_header *header,
-					      TDB_DATA *key, TDB_DATA *data);
+bool ctdb_blocking_freeze(struct ctdb_context *ctdb);
 
-int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
-int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_db_transaction_start(struct ctdb_context *ctdb,
+					  TDB_DATA indata);
+int32_t ctdb_control_db_transaction_cancel(struct ctdb_context *ctdb,
+					   TDB_DATA indata);
+int32_t ctdb_control_db_transaction_commit(struct ctdb_context *ctdb,
+					   TDB_DATA indata);
 
-int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, 
-				 struct ctdb_req_control *c,
-				 TDB_DATA indata, bool *async_reply,
-				 const char **errormsg);
-void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c,
-				TDB_DATA *outdata, int32_t status, const char *errormsg);
+int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id);
+int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb);
+int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id);
 
-int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply);
-int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority,
-			  bool check_recmode);
+int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata);
 
-int ctdb_start_recoverd(struct ctdb_context *ctdb);
-void ctdb_stop_recoverd(struct ctdb_context *ctdb);
+bool ctdb_db_frozen(struct ctdb_db_context *ctdb_db);
+bool ctdb_db_prio_frozen(struct ctdb_context *ctdb, uint32_t priority);
+bool ctdb_db_all_frozen(struct ctdb_context *ctdb);
 
-uint32_t ctdb_get_num_active_nodes(struct ctdb_context *ctdb);
+/* from server/ctdb_keepalive.c */
 
-void ctdb_disable_monitoring(struct ctdb_context *ctdb);
-void ctdb_enable_monitoring(struct ctdb_context *ctdb);
-void ctdb_stop_monitoring(struct ctdb_context *ctdb);
-void ctdb_wait_for_first_recovery(struct ctdb_context *ctdb);
-int ctdb_tcp_init(struct ctdb_context *ctdb);
-int ctdb_ibw_init(struct ctdb_context *ctdb);
-void ctdb_start_tcp_tickle_update(struct ctdb_context *ctdb);
-void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode);
 void ctdb_start_keepalive(struct ctdb_context *ctdb);
 void ctdb_stop_keepalive(struct ctdb_context *ctdb);
-int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA data, bool *async_reply);
 
+/* from server/ctdb_lock.c */
 
-void ctdb_daemon_cancel_controls(struct ctdb_context *ctdb, struct ctdb_node *node);
-void ctdb_call_resend_all(struct ctdb_context *ctdb);
-void ctdb_node_dead(struct ctdb_node *node);
-void ctdb_node_connected(struct ctdb_node *node);
-bool ctdb_blocking_freeze(struct ctdb_context *ctdb);
-bool set_scheduler(void);
-void reset_scheduler(void);
+struct lock_request;
 
-struct tevent_signal *ctdb_init_sigchld(struct ctdb_context *ctdb);
-void ctdb_track_child(struct ctdb_context *ctdb, pid_t pid);
-pid_t ctdb_fork(struct ctdb_context *ctdb);
-void ctdb_set_child_info(TALLOC_CTX *mem_ctx, const char *child_name_fmt, ...);
-int ctdb_kill(struct ctdb_context *ctdb, pid_t pid, int signum);
+typedef int (*ctdb_db_handler_t)(struct ctdb_db_context *ctdb_db,
+				 void *private_data);
 
-int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb, 
-				 struct ctdb_req_control *c,
-				 TDB_DATA indata, 
-				 bool *async_reply);
-int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, 
-				 struct ctdb_req_control *c,
-				 TDB_DATA indata, 
-				 bool *async_reply);
-int32_t ctdb_control_ipreallocated(struct ctdb_context *ctdb, 
-				 struct ctdb_req_control *c,
-				 bool *async_reply);
-int32_t ctdb_control_start_recovery(struct ctdb_context *ctdb, 
-				 struct ctdb_req_control *c,
-				 bool *async_reply);
-int32_t ctdb_control_end_recovery(struct ctdb_context *ctdb, 
-				 struct ctdb_req_control *c,
-				 bool *async_reply);
+int ctdb_db_prio_iterator(struct ctdb_context *ctdb, uint32_t priority,
+			  ctdb_db_handler_t handler, void *private_data);
+int ctdb_db_iterator(struct ctdb_context *ctdb, ctdb_db_handler_t handler,
+		     void *private_data);
 
-int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout, 
-			  uint32_t destnode, struct ctdb_public_ip *ip);
-int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout, 
-			 uint32_t destnode, struct ctdb_public_ip *ip);
+int ctdb_lockdb_mark(struct ctdb_db_context *ctdb_db);
+int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority);
 
-int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb,
-				    struct ctdb_req_control *c,
-				    TDB_DATA *outdata);
-int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
-			     struct timeval timeout,
-			     uint32_t destnode,
-			     TALLOC_CTX *mem_ctx,
-			     struct ctdb_all_public_ips **ips);
-#define CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE 0x00010000
-int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
-				   struct timeval timeout, uint32_t destnode,
-				   TALLOC_CTX *mem_ctx,
-				   uint32_t flags,
-				   struct ctdb_all_public_ips **ips);
-
-struct ctdb_control_iface_info {
-	char name[CTDB_IFACE_SIZE+2];
-	uint16_t link_state;
-	uint32_t references;
-};
+int ctdb_lockdb_unmark(struct ctdb_db_context *ctdb_db);
+int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority);
 
-struct ctdb_control_public_ip_info {
-	struct ctdb_public_ip ip;
-	uint32_t active_idx;
-	uint32_t num;
-	struct ctdb_control_iface_info ifaces[1];
-};
+struct lock_request *ctdb_lock_record(TALLOC_CTX *mem_ctx,
+				      struct ctdb_db_context *ctdb_db,
+				      TDB_DATA key,
+				      bool auto_mark,
+				      void (*callback)(void *, bool),
+				      void *private_data);
 
-struct ctdb_control_get_ifaces {
-	uint32_t num;
-	struct ctdb_control_iface_info ifaces[1];
-};
+struct lock_request *ctdb_lock_db(TALLOC_CTX *mem_ctx,
+				  struct ctdb_db_context *ctdb_db,
+				  bool auto_mark,
+				  void (*callback)(void *, bool),
+				  void *private_data);
 
-int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
-					struct ctdb_req_control *c,
-					TDB_DATA indata,
-					TDB_DATA *outdata);
-int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
-				struct ctdb_req_control *c,
-				TDB_DATA *outdata);
-int32_t ctdb_control_set_iface_link(struct ctdb_context *ctdb,
-				    struct ctdb_req_control *c,
+struct lock_request *ctdb_lock_alldb_prio(TALLOC_CTX *mem_ctx,
+					  struct ctdb_context *ctdb,
+					  uint32_t priority,
+					  bool auto_mark,
+					  void (*callback)(void *, bool),
+					  void *private_data);
+
+struct lock_request *ctdb_lock_alldb(TALLOC_CTX *mem_ctx,
+				     struct ctdb_context *ctdb,
+				     bool auto_mark,
+				     void (*callback)(void *, bool),
+				     void *private_data);
+
+/* from ctdb_logging.c */
+
+extern const char *debug_extra;
+
+typedef int (*ctdb_log_setup_fn_t)(TALLOC_CTX *mem_ctx,
+				   const char *logging,
+				   const char *app_name);
+
+void ctdb_log_register_backend(const char *prefix, ctdb_log_setup_fn_t init);
+
+bool ctdb_logging_init(TALLOC_CTX *mem_ctx, const char *logging);
+
+struct ctdb_log_state *ctdb_vfork_with_logging(TALLOC_CTX *mem_ctx,
+					       struct ctdb_context *ctdb,
+					       const char *log_prefix,
+					       const char *helper,
+					       int helper_argc,
+					       const char **helper_argv,
+					       void (*logfn)(const char *,
+							     uint16_t, void *),
+					       void *logfn_private, pid_t *pid);
+
+int ctdb_set_child_logging(struct ctdb_context *ctdb);
+int ctdb_init_tevent_logging(struct ctdb_context *ctdb);
+
+/* from ctdb_logging_file.c */
+
+void ctdb_log_init_file(void);
+
+/* from ctdb_logging_syslog.c */
+
+void ctdb_log_init_syslog(void);
+
+/* from ctdb_ltdb_server.c */
+
+int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db,
+			   TDB_DATA key, struct ctdb_req_header *hdr,
+			   void (*recv_pkt)(void *, struct ctdb_req_header *),
+			   void *recv_context, bool ignore_generation);
+
+int ctdb_ltdb_lock_fetch_requeue(struct ctdb_db_context *ctdb_db,
+				 TDB_DATA key, struct ctdb_ltdb_header *header,
+				 struct ctdb_req_header *hdr, TDB_DATA *data,
+				 void (*recv_pkt)(void *, struct ctdb_req_header *),
+				 void *recv_context, bool ignore_generation);
+
+int ctdb_load_persistent_health(struct ctdb_context *ctdb,
+				struct ctdb_db_context *ctdb_db);
+int ctdb_update_persistent_health(struct ctdb_context *ctdb,
+				  struct ctdb_db_context *ctdb_db,
+				  const char *reason,/* NULL means healthy */
+				  int num_healthy_nodes);
+int ctdb_recheck_persistent_health(struct ctdb_context *ctdb);
+
+int32_t ctdb_control_db_set_healthy(struct ctdb_context *ctdb,
 				    TDB_DATA indata);
-int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
-				 struct timeval timeout, uint32_t destnode,
-				 TALLOC_CTX *mem_ctx,
-				 const ctdb_sock_addr *addr,
-				 struct ctdb_control_public_ip_info **info);
-int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
-			 struct timeval timeout, uint32_t destnode,
-			 TALLOC_CTX *mem_ctx,
-			 struct ctdb_control_get_ifaces **ifaces);
-int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb,
-			     struct timeval timeout, uint32_t destnode,
-			     TALLOC_CTX *mem_ctx,
-			     const struct ctdb_control_iface_info *info);
-
-/* from takeover/system.c */
-uint32_t uint16_checksum(uint16_t *data, size_t n);
-int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface);
-bool ctdb_sys_have_ip(ctdb_sock_addr *addr);
-char *ctdb_sys_find_ifname(ctdb_sock_addr *addr);
-bool ctdb_sys_check_iface_exists(const char *iface);
-int ctdb_get_peer_pid(const int fd, pid_t *peer_pid);
-int ctdb_sys_send_tcp(const ctdb_sock_addr *dest, 
-		      const ctdb_sock_addr *src,
-		      uint32_t seq, uint32_t ack, int rst);
-
-/* Details of a byte range lock */
-struct ctdb_lock_info {
-	ino_t inode;
-	off_t start, end;
-	bool waiting;
-	bool read_only;
-};
+int32_t ctdb_control_db_get_health(struct ctdb_context *ctdb,
+				   TDB_DATA indata, TDB_DATA *outdata);
 
-char *ctdb_get_process_name(pid_t pid);
-int ctdb_set_process_name(const char *name);
-bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info);
-bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid);
+int ctdb_set_db_readonly(struct ctdb_context *ctdb,
+			 struct ctdb_db_context *ctdb_db);
 
-typedef void (*client_async_callback)(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data);
+int ctdb_process_deferred_attach(struct ctdb_context *ctdb);
 
-int ctdb_set_public_addresses(struct ctdb_context *ctdb, bool check_addresses);
-int ctdb_set_single_public_ip(struct ctdb_context *ctdb,
-			      const char *iface,
-			      const char *ip);
-int ctdb_set_notification_script(struct ctdb_context *ctdb, const char *script);
-int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap,
-		      uint32_t *force_rebalance_nodes,
-		      client_async_callback fail_callback, void *callback_data);
+int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata,
+			       TDB_DATA *outdata, uint64_t tdb_flags,
+			       bool persistent, uint32_t client_id,
+			       struct ctdb_req_control_old *c,
+			       bool *async_reply);
+int32_t ctdb_control_db_detach(struct ctdb_context *ctdb, TDB_DATA indata,
+			       uint32_t client_id);
 
-int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, 
-				TDB_DATA indata);
-int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tcp_update_needed);
-int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata);
-int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn);
-int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata);
-int32_t ctdb_control_send_gratious_arp(struct ctdb_context *ctdb, TDB_DATA indata);
-int32_t ctdb_control_get_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
-int32_t ctdb_control_set_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata);
+int ctdb_attach_databases(struct ctdb_context *ctdb);
 
-void ctdb_takeover_client_destructor_hook(struct ctdb_client *client);
-int ctdb_event_script(struct ctdb_context *ctdb, enum ctdb_eventscript_call call);
-int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_eventscript_call call,
-			   const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
-int ctdb_event_script_callback(struct ctdb_context *ctdb, 
-			       TALLOC_CTX *mem_ctx,
-			       void (*callback)(struct ctdb_context *, int, void *),
-			       void *private_data,
-			       enum ctdb_eventscript_call call,
-			       const char *fmt, ...) PRINTF_ATTRIBUTE(6,7);
-void ctdb_release_all_ips(struct ctdb_context *ctdb);
+int32_t ctdb_ltdb_update_seqnum(struct ctdb_context *ctdb, uint32_t db_id,
+				uint32_t srcnode);
+int32_t ctdb_ltdb_enable_seqnum(struct ctdb_context *ctdb, uint32_t db_id);
 
-void set_nonblocking(int fd);
-void set_close_on_exec(int fd);
+int32_t ctdb_control_set_db_priority(struct ctdb_context *ctdb, TDB_DATA indata,
+				     uint32_t client_id);
 
-bool ctdb_recovery_have_lock(struct ctdb_context *ctdb);
-bool ctdb_recovery_lock(struct ctdb_context *ctdb);
-void ctdb_recovery_unlock(struct ctdb_context *ctdb);
+int ctdb_set_db_sticky(struct ctdb_context *ctdb,
+		       struct ctdb_db_context *ctdb_db);
 
-int ctdb_set_recovery_lock_file(struct ctdb_context *ctdb, const char *file);
+void ctdb_db_statistics_reset(struct ctdb_db_context *ctdb_db);
 
-int32_t ctdb_control_get_tunable(struct ctdb_context *ctdb, TDB_DATA indata, 
-				 TDB_DATA *outdata);
-int32_t ctdb_control_set_tunable(struct ctdb_context *ctdb, TDB_DATA indata);
-int32_t ctdb_control_list_tunables(struct ctdb_context *ctdb, TDB_DATA *outdata);
-int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
-int32_t ctdb_control_receive_records(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
-int32_t ctdb_control_add_public_address(struct ctdb_context *ctdb, TDB_DATA indata);
-int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb,
-					struct ctdb_req_control *c,
-					TDB_DATA recdata, bool *async_reply);
+int32_t ctdb_control_get_db_statistics(struct ctdb_context *ctdb,
+				       uint32_t db_id, TDB_DATA *outdata);
 
-void ctdb_tunables_set_defaults(struct ctdb_context *ctdb);
+/* from ctdb_monitor.c */
+
+int ctdb_set_notification_script(struct ctdb_context *ctdb, const char *script);
+void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event);
+
+void ctdb_disable_monitoring(struct ctdb_context *ctdb);
+void ctdb_enable_monitoring(struct ctdb_context *ctdb);
+void ctdb_stop_monitoring(struct ctdb_context *ctdb);
+
+void ctdb_wait_for_first_recovery(struct ctdb_context *ctdb);
 
 int32_t ctdb_control_modflags(struct ctdb_context *ctdb, TDB_DATA indata);
 
-int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb, 
-			       struct timeval timeout, 
-			       uint32_t destnode,
-			       struct ctdb_tunable *tunables);
-
-void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority);
-
-bool parse_ip_mask(const char *s, const char *iface, ctdb_sock_addr *addr, unsigned *mask);
-bool parse_ip_port(const char *s, ctdb_sock_addr *addr);
-bool parse_ip(const char *s, const char *iface, unsigned port, ctdb_sock_addr *addr);
-bool parse_ipv4(const char *s, unsigned port, struct sockaddr_in *sin);
- 
-
-int ctdb_sys_open_capture_socket(const char *iface, void **private_data);
-int ctdb_sys_close_capture_socket(void *private_data);
-int ctdb_sys_read_tcp_packet(int s, void *private_data, ctdb_sock_addr *src, ctdb_sock_addr *dst, uint32_t *ack_seq, uint32_t *seq);
-
-int ctdb_ctrl_killtcp(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      uint32_t destnode,
-		      struct ctdb_control_killtcp *killtcp);
-
-int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      uint32_t destnode,
-		      struct ctdb_control_ip_iface *pub);
-
-int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      uint32_t destnode,
-		      struct ctdb_control_ip_iface *pub);
-
-int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      uint32_t destnode,
-		      ctdb_sock_addr *addr,
-		      const char *ifname);
-
-int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb, 
-		      struct timeval timeout, 
-		      uint32_t destnode,
-		      TALLOC_CTX *mem_ctx,
-		      ctdb_sock_addr *addr,
-		      struct ctdb_control_tcp_tickle_list **list);
-
-
-int32_t ctdb_control_register_server_id(struct ctdb_context *ctdb, 
-		      uint32_t client_id,
-		      TDB_DATA indata);
-int32_t ctdb_control_check_server_id(struct ctdb_context *ctdb, 
-		      TDB_DATA indata);
-int32_t ctdb_control_unregister_server_id(struct ctdb_context *ctdb, 
-		      TDB_DATA indata);
-int32_t ctdb_control_get_server_id_list(struct ctdb_context *ctdb, 
-		      TDB_DATA *outdata);
-int32_t ctdb_control_uptime(struct ctdb_context *ctdb, 
-		      TDB_DATA *outdata);
+int32_t ctdb_monitoring_mode(struct ctdb_context *ctdb);
+bool ctdb_stopped_monitoring(struct ctdb_context *ctdb);
 
-int ctdb_attach_databases(struct ctdb_context *ctdb);
+/* from ctdb_persistent.c */
 
-int32_t ctdb_control_persistent_store(struct ctdb_context *ctdb, 
-				      struct ctdb_req_control *c, 
-				      TDB_DATA recdata, bool *async_reply);
-int32_t ctdb_control_update_record(struct ctdb_context *ctdb, 
-				   struct ctdb_req_control *c, TDB_DATA recdata, 
-				   bool *async_reply);
+void ctdb_persistent_finish_trans3_commits(struct ctdb_context *ctdb);
 
 int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb,
-				   struct ctdb_req_control *c,
+				   struct ctdb_req_control_old *c,
 				   TDB_DATA recdata, bool *async_reply);
 
-void ctdb_persistent_finish_trans3_commits(struct ctdb_context *ctdb);
+int32_t ctdb_control_start_persistent_update(struct ctdb_context *ctdb,
+					     struct ctdb_req_control_old *c,
+					     TDB_DATA recdata);
+int32_t ctdb_control_cancel_persistent_update(struct ctdb_context *ctdb,
+					      struct ctdb_req_control_old *c,
+					      TDB_DATA recdata);
 
-int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id);
-int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id);
-int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb);
-int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata);
-int32_t ctdb_control_db_set_healthy(struct ctdb_context *ctdb, TDB_DATA indata);
-int32_t ctdb_control_db_get_health(struct ctdb_context *ctdb,
-				   TDB_DATA indata,
-				   TDB_DATA *outdata);
+int32_t ctdb_control_get_db_seqnum(struct ctdb_context *ctdb,
+				   TDB_DATA indata, TDB_DATA *outdata);
 
+/* from ctdb_recover.c */
 
-int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv);
+int ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode,
+			   TDB_DATA indata, TDB_DATA *outdata);
+int ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode,
+			   TDB_DATA indata, TDB_DATA *outdata);
 
-int32_t ctdb_monitoring_mode(struct ctdb_context *ctdb);
-bool ctdb_stopped_monitoring(struct ctdb_context *ctdb);
-int ctdb_set_child_logging(struct ctdb_context *ctdb);
-void lockdown_memory(bool valgrinding);
-
-struct client_async_data {
-	enum ctdb_controls opcode;
-	bool dont_log_errors;
-	uint32_t count;
-	uint32_t fail_count;
-	client_async_callback callback;
-	client_async_callback fail_callback;
-	void *callback_data;
-};
-void ctdb_client_async_add(struct client_async_data *data, struct ctdb_client_control_state *state);
-int ctdb_client_async_wait(struct ctdb_context *ctdb, struct client_async_data *data);
-int ctdb_client_async_control(struct ctdb_context *ctdb,
-				enum ctdb_controls opcode,
-				uint32_t *nodes,
-			      	uint64_t srvid,
-				struct timeval timeout,
-				bool dont_log_errors,
-				TDB_DATA data,
-			      	client_async_callback client_callback,
-			        client_async_callback fail_callback,
-				void *callback_data);
-
-struct ctdb_node_map *
-ctdb_node_list_to_map(struct ctdb_node **nodes, uint32_t num_nodes,
-		      TALLOC_CTX *mem_ctx);
-struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
-					   const char *nlist);
-void ctdb_load_nodes_file(struct ctdb_context *ctdb);
+int ctdb_control_getdbmap(struct ctdb_context *ctdb, uint32_t opcode,
+			  TDB_DATA indata, TDB_DATA *outdata);
+int ctdb_control_getnodemap(struct ctdb_context *ctdb, uint32_t opcode,
+			    TDB_DATA indata, TDB_DATA *outdata);
 
 int ctdb_control_reload_nodes_file(struct ctdb_context *ctdb, uint32_t opcode);
 
-int32_t ctdb_dump_memory(struct ctdb_context *ctdb, TDB_DATA *outdata);
-int32_t ctdb_control_get_capabilities(struct ctdb_context *ctdb, TDB_DATA *outdata);
+int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata,
+			     TDB_DATA *outdata);
+int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata);
 
-char *ctdb_addr_to_str(ctdb_sock_addr *addr);
-unsigned ctdb_addr_to_port(ctdb_sock_addr *addr);
-void ctdb_canonicalize_ip(const ctdb_sock_addr *ip, ctdb_sock_addr *cip);
+int ctdb_deferred_drop_all_ips(struct ctdb_context *ctdb);
 
-int32_t ctdb_control_recd_ping(struct ctdb_context *ctdb);
-int32_t ctdb_control_set_recmaster(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata);
+int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb,
+				 struct ctdb_req_control_old *c,
+				 TDB_DATA indata, bool *async_reply,
+				 const char **errormsg);
 
-extern int script_log_level;
-extern bool fast_start;
-extern const char *ctdbd_pidfile;
+bool ctdb_recovery_have_lock(struct ctdb_context *ctdb);
+bool ctdb_recovery_lock(struct ctdb_context *ctdb);
+void ctdb_recovery_unlock(struct ctdb_context *ctdb);
 
-int32_t ctdb_control_get_event_script_status(struct ctdb_context *ctdb,
-					     uint32_t call_type,
-					     TDB_DATA *outdata);
+int32_t ctdb_control_end_recovery(struct ctdb_context *ctdb,
+				 struct ctdb_req_control_old *c,
+				 bool *async_reply);
+int32_t ctdb_control_start_recovery(struct ctdb_context *ctdb,
+				 struct ctdb_req_control_old *c,
+				 bool *async_reply);
+
+int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb,
+					TDB_DATA indata, TDB_DATA *outdata);
+int32_t ctdb_control_receive_records(struct ctdb_context *ctdb,
+				     TDB_DATA indata, TDB_DATA *outdata);
 
-int ctdb_ctrl_report_recd_lock_latency(struct ctdb_context *ctdb, struct timeval timeout, double latency);
+int32_t ctdb_control_get_capabilities(struct ctdb_context *ctdb,
+				      TDB_DATA *outdata);
+
+int32_t ctdb_control_recd_ping(struct ctdb_context *ctdb);
+int32_t ctdb_control_set_recmaster(struct ctdb_context *ctdb,
+				   uint32_t opcode, TDB_DATA indata);
 
 int32_t ctdb_control_stop_node(struct ctdb_context *ctdb);
 int32_t ctdb_control_continue_node(struct ctdb_context *ctdb);
 
-void ctdb_stop_vacuuming(struct ctdb_context *ctdb);
-int ctdb_vacuum_init(struct ctdb_db_context *ctdb_db);
+/* from ctdb_recoverd.c */
 
-int32_t ctdb_control_enable_script(struct ctdb_context *ctdb, TDB_DATA indata);
-int32_t ctdb_control_disable_script(struct ctdb_context *ctdb, TDB_DATA indata);
+int ctdb_start_recoverd(struct ctdb_context *ctdb);
+void ctdb_stop_recoverd(struct ctdb_context *ctdb);
 
-void ctdb_local_node_got_banned(struct ctdb_context *ctdb);
-int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata);
-int32_t ctdb_control_get_ban_state(struct ctdb_context *ctdb, TDB_DATA *outdata);
-int32_t ctdb_control_set_db_priority(struct ctdb_context *ctdb, TDB_DATA indata,
-				     uint32_t client_id);
-void ctdb_ban_self(struct ctdb_context *ctdb);
+/* from ctdb_server.c */
 
-int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata);
+int ctdb_set_transport(struct ctdb_context *ctdb, const char *transport);
 
-int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata);
+int ctdb_ip_to_nodeid(struct ctdb_context *ctdb, const ctdb_sock_addr *nodeip);
 
-struct ctdb_log_state *ctdb_vfork_with_logging(TALLOC_CTX *mem_ctx,
-					       struct ctdb_context *ctdb,
-					       const char *log_prefix,
-					       const char *helper,
-					       int helper_argc,
-					       const char **helper_argv,
-					       void (*logfn)(const char *, uint16_t, void *),
-					       void *logfn_private, pid_t *pid);
+int ctdb_set_recovery_lock_file(struct ctdb_context *ctdb, const char *file);
 
+void ctdb_load_nodes_file(struct ctdb_context *ctdb);
 
-int32_t ctdb_control_process_exists(struct ctdb_context *ctdb, pid_t pid);
-struct ctdb_client *ctdb_find_client_by_pid(struct ctdb_context *ctdb, pid_t pid);
+int ctdb_set_address(struct ctdb_context *ctdb, const char *address);
 
-int32_t ctdb_control_get_db_seqnum(struct ctdb_context *ctdb,
-				   TDB_DATA indata,
-				   TDB_DATA *outdata);
+uint32_t ctdb_get_num_active_nodes(struct ctdb_context *ctdb);
 
-int ctdb_load_persistent_health(struct ctdb_context *ctdb,
-				struct ctdb_db_context *ctdb_db);
-int ctdb_update_persistent_health(struct ctdb_context *ctdb,
-				  struct ctdb_db_context *ctdb_db,
-				  const char *reason,/* NULL means healthy */
-				  int num_healthy_nodes);
-int ctdb_recheck_persistent_health(struct ctdb_context *ctdb);
+void ctdb_input_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *);
 
-void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event);
+void ctdb_node_dead(struct ctdb_node *node);
+void ctdb_node_connected(struct ctdb_node *node);
 
-int verify_remote_ip_allocation(struct ctdb_context *ctdb,
-				struct ctdb_all_public_ips *ips,
-				uint32_t pnn);
-int update_ip_assignment_tree(struct ctdb_context *ctdb,
-				struct ctdb_public_ip *ip);
-void clear_ip_assignment_tree(struct ctdb_context *ctdb);
+void ctdb_queue_packet(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_queue_packet_opcode(struct ctdb_context *ctdb,
+			      struct ctdb_req_header *hdr, unsigned opcode);
+
+/* from ctdb_serverids.c */
+
+int32_t ctdb_control_register_server_id(struct ctdb_context *ctdb,
+					uint32_t client_id, TDB_DATA indata);
+int32_t ctdb_control_check_server_id(struct ctdb_context *ctdb,
+				     TDB_DATA indata);
+int32_t ctdb_control_unregister_server_id(struct ctdb_context *ctdb,
+					  TDB_DATA indata);
+int32_t ctdb_control_get_server_id_list(struct ctdb_context *ctdb,
+					TDB_DATA *outdata);
 
-int ctdb_init_tevent_logging(struct ctdb_context *ctdb);
+/* from ctdb_statistics.c */
 
 int ctdb_statistics_init(struct ctdb_context *ctdb);
 
 int32_t ctdb_control_get_stat_history(struct ctdb_context *ctdb,
-				      struct ctdb_req_control *c,
+				      struct ctdb_req_control_old *c,
 				      TDB_DATA *outdata);
 
-int ctdb_deferred_drop_all_ips(struct ctdb_context *ctdb);
+/* from ctdb_takeover.c */
 
-int ctdb_process_deferred_attach(struct ctdb_context *ctdb);
+int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb,
+				 struct ctdb_req_control_old *c,
+				 TDB_DATA indata,
+				 bool *async_reply);
+int32_t ctdb_control_release_ip(struct ctdb_context *ctdb,
+				 struct ctdb_req_control_old *c,
+				 TDB_DATA indata,
+				 bool *async_reply);
+int32_t ctdb_control_ipreallocated(struct ctdb_context *ctdb,
+				 struct ctdb_req_control_old *c,
+				 bool *async_reply);
 
-/**
- * structure to pass to a schedule_for_deletion_control
- */
-struct ctdb_control_schedule_for_deletion {
-	uint32_t db_id;
-	struct ctdb_ltdb_header hdr;
-	uint32_t keylen;
-	uint8_t key[1]; /* key[] */
-};
+int ctdb_set_public_addresses(struct ctdb_context *ctdb, bool check_addresses);
+int ctdb_set_single_public_ip(struct ctdb_context *ctdb, const char *iface,
+			      const char *ip);
 
-int32_t ctdb_control_schedule_for_deletion(struct ctdb_context *ctdb,
-					   TDB_DATA indata);
+int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map_old *nodemap,
+		      uint32_t *force_rebalance_nodes,
+		      client_async_callback fail_callback, void *callback_data);
 
+int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
+				TDB_DATA indata);
+int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata,
+			     bool tcp_update_needed);
+int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn);
 
-int32_t ctdb_local_schedule_for_deletion(struct ctdb_db_context *ctdb_db,
-					 const struct ctdb_ltdb_header *hdr,
-					 TDB_DATA key);
+void ctdb_takeover_client_destructor_hook(struct ctdb_client *client);
 
-void ctdb_local_remove_from_delete_queue(struct ctdb_db_context *ctdb_db,
-					 const struct ctdb_ltdb_header *hdr,
-					 const TDB_DATA key);
+void ctdb_release_all_ips(struct ctdb_context *ctdb);
 
-struct ctdb_ltdb_header *ctdb_header_from_record_handle(struct ctdb_record_handle *h);
+int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb,
+				    struct ctdb_req_control_old *c,
+				    TDB_DATA *outdata);
+int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
+					struct ctdb_req_control_old *c,
+					TDB_DATA indata, TDB_DATA *outdata);
 
-int ctdb_trackingdb_add_pnn(struct ctdb_context *ctdb, TDB_DATA *data, uint32_t pnn);
+int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
+				struct ctdb_req_control_old *c,
+				TDB_DATA *outdata);
+int32_t ctdb_control_set_iface_link(struct ctdb_context *ctdb,
+				    struct ctdb_req_control_old *c,
+				    TDB_DATA indata);
 
-typedef void (*ctdb_trackingdb_cb)(struct ctdb_context *ctdb, uint32_t pnn, void *private_data);
+int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_set_tcp_tickle_list(struct ctdb_context *ctdb,
+					 TDB_DATA indata);
+int32_t ctdb_control_get_tcp_tickle_list(struct ctdb_context *ctdb,
+					 TDB_DATA indata, TDB_DATA *outdata);
 
-void ctdb_trackingdb_traverse(struct ctdb_context *ctdb, TDB_DATA data, ctdb_trackingdb_cb cb, void *private_data);
+void ctdb_start_tcp_tickle_update(struct ctdb_context *ctdb);
 
-int ctdb_start_revoke_ro_record(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data);
+int32_t ctdb_control_send_gratious_arp(struct ctdb_context *ctdb,
+				       TDB_DATA indata);
 
-typedef void (*deferred_requeue_fn)(void *call_context, struct ctdb_req_header *hdr);
+int32_t ctdb_control_add_public_address(struct ctdb_context *ctdb,
+					TDB_DATA indata);
+int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb,
+					struct ctdb_req_control_old *c,
+					TDB_DATA recdata, bool *async_reply);
 
-int ctdb_add_revoke_deferred_call(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_req_header *hdr, deferred_requeue_fn fn, void *call_context);
+int update_ip_assignment_tree(struct ctdb_context *ctdb,
+				struct ctdb_public_ip *ip);
+void clear_ip_assignment_tree(struct ctdb_context *ctdb);
 
-int ctdb_set_db_readonly(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db);
+int32_t ctdb_control_reload_public_ips(struct ctdb_context *ctdb,
+				       struct ctdb_req_control_old *c,
+				       bool *async_reply);
 
-int ctdb_null_func(struct ctdb_call_info *call);
+/* from ctdb_traverse.c */
 
-int ctdb_fetch_func(struct ctdb_call_info *call);
+int32_t ctdb_control_traverse_all_ext(struct ctdb_context *ctdb,
+				      TDB_DATA data, TDB_DATA *outdata);
+int32_t ctdb_control_traverse_all(struct ctdb_context *ctdb,
+				  TDB_DATA data, TDB_DATA *outdata);
+int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb,
+				   TDB_DATA data, TDB_DATA *outdata);
+int32_t ctdb_control_traverse_kill(struct ctdb_context *ctdb, TDB_DATA indata,
+				    TDB_DATA *outdata, uint32_t srcnode);
 
-int ctdb_fetch_with_header_func(struct ctdb_call_info *call);
+int32_t ctdb_control_traverse_start_ext(struct ctdb_context *ctdb,
+					TDB_DATA indata, TDB_DATA *outdata,
+					uint32_t srcnode, uint32_t client_id);
+int32_t ctdb_control_traverse_start(struct ctdb_context *ctdb,
+				    TDB_DATA indata, TDB_DATA *outdata,
+				    uint32_t srcnode, uint32_t client_id);
 
-int32_t ctdb_control_get_db_statistics(struct ctdb_context *ctdb,
-				uint32_t db_id,
-				TDB_DATA *outdata);
+/* from ctdb_tunables.c */
 
-int ctdb_set_db_sticky(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db);
+void ctdb_tunables_set_defaults(struct ctdb_context *ctdb);
 
-/*
-  description for a message to reload all ips via recovery master/daemon
- */
-struct reloadips_all_reply {
-	uint32_t pnn;
-	uint64_t srvid;
-};
+int32_t ctdb_control_get_tunable(struct ctdb_context *ctdb, TDB_DATA indata,
+				 TDB_DATA *outdata);
+int32_t ctdb_control_set_tunable(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_list_tunables(struct ctdb_context *ctdb,
+				   TDB_DATA *outdata);
 
-int32_t ctdb_control_reload_public_ips(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply);
+/* from ctdb_update_record.c */
 
-/* from server/ctdb_lock.c */
-struct lock_request;
+int32_t ctdb_control_update_record(struct ctdb_context *ctdb,
+				   struct ctdb_req_control_old *c,
+				   TDB_DATA recdata, bool *async_reply);
 
-int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority);
-int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority);
+/* from ctdb_uptime.c */
 
-struct lock_request *ctdb_lock_record(TALLOC_CTX *mem_ctx,
-				      struct ctdb_db_context *ctdb_db,
-				      TDB_DATA key,
-				      bool auto_mark,
-				      void (*callback)(void *, bool),
-				      void *private_data);
+int32_t ctdb_control_uptime(struct ctdb_context *ctdb, TDB_DATA *outdata);
 
-struct lock_request *ctdb_lock_db(TALLOC_CTX *mem_ctx,
-				  struct ctdb_db_context *ctdb_db,
-				  bool auto_mark,
-				  void (*callback)(void *, bool),
-				  void *private_data);
+/* from ctdb_vacuum.c */
 
-struct lock_request *ctdb_lock_alldb_prio(TALLOC_CTX *mem_ctx,
-					  struct ctdb_context *ctdb,
-					  uint32_t priority,
-					  bool auto_mark,
-					  void (*callback)(void *, bool),
-					  void *private_data);
+void ctdb_stop_vacuuming(struct ctdb_context *ctdb);
+int ctdb_vacuum_init(struct ctdb_db_context *ctdb_db);
 
-struct lock_request *ctdb_lock_alldb(TALLOC_CTX *mem_ctx,
-				     struct ctdb_context *ctdb,
-				     bool auto_mark,
-				     void (*callback)(void *, bool),
-				     void *private_data);
+int32_t ctdb_control_schedule_for_deletion(struct ctdb_context *ctdb,
+					   TDB_DATA indata);
+int32_t ctdb_local_schedule_for_deletion(struct ctdb_db_context *ctdb_db,
+					 const struct ctdb_ltdb_header *hdr,
+					 TDB_DATA key);
+
+void ctdb_local_remove_from_delete_queue(struct ctdb_db_context *ctdb_db,
+					 const struct ctdb_ltdb_header *hdr,
+					 const TDB_DATA key);
 
-int mkdir_p(const char *dir, int mode);
-void mkdir_p_or_die(const char *dir, int mode);
+/* from eventscript.c */
 
-ssize_t sys_read(int fd, void *buf, size_t count);
-ssize_t sys_write(int fd, const void *buf, size_t count);
+int32_t ctdb_control_get_event_script_status(struct ctdb_context *ctdb,
+					     uint32_t call_type,
+					     TDB_DATA *outdata);
+
+int ctdb_event_script_callback(struct ctdb_context *ctdb,
+			       TALLOC_CTX *mem_ctx,
+			       void (*callback)(struct ctdb_context *,
+						int, void *),
+			       void *private_data,
+			       enum ctdb_event call,
+			       const char *fmt, ...) PRINTF_ATTRIBUTE(6,7);
+
+int ctdb_event_script_args(struct ctdb_context *ctdb,
+			   enum ctdb_event call,
+			   const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+int ctdb_event_script(struct ctdb_context *ctdb,
+		      enum ctdb_event call);
+
+int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb,
+			      struct ctdb_req_control_old *c,
+			      TDB_DATA data, bool *async_reply);
+
+int32_t ctdb_control_enable_script(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_disable_script(struct ctdb_context *ctdb, TDB_DATA indata);
 
 #endif
diff --git a/ctdb/include/ctdb_protocol.h b/ctdb/include/ctdb_protocol.h
index d9cad7c..feea114 100644
--- a/ctdb/include/ctdb_protocol.h
+++ b/ctdb/include/ctdb_protocol.h
@@ -21,38 +21,14 @@
 #define _CTDB_PROTOCOL_H
 
 #include <sys/socket.h>
+#include "protocol/protocol.h"
 
-/* location of daemon socket, set at configure time */
-#ifdef SOCKPATH
-#define CTDB_SOCKET 	SOCKPATH
-#else
-#define CTDB_SOCKET 	"/var/run/ctdb/ctdbd.socket"
-#endif
-
-/* default ctdb port number */
+/* define ctdb port number */
 #define CTDB_PORT 4379
 
 /* we must align packets to ensure ctdb works on all architectures (eg. sparc) */
 #define CTDB_DS_ALIGNMENT 8
 
-
-#define CTDB_NULL_FUNC                  0xFF000001
-#define CTDB_FETCH_FUNC                 0xFF000002
-#define CTDB_FETCH_WITH_HEADER_FUNC     0xFF000003
-
-
-struct ctdb_call {
-	int call_id;
-	TDB_DATA key;
-	TDB_DATA call_data;
-	TDB_DATA reply_data;
-	uint32_t status;
-#define CTDB_IMMEDIATE_MIGRATION		0x00000001
-#define CTDB_CALL_FLAG_VACUUM_MIGRATION		0x00000002
-#define CTDB_WANT_READONLY			0x00000004
-	uint32_t flags;
-};
-
 /*
   structure passed to a ctdb call backend function
 */
@@ -66,372 +42,23 @@ struct ctdb_call_info {
 	uint32_t status;       /* optional reply status - defaults to zero */
 };
 
-#define CTDB_ERR_INVALID 1
-#define CTDB_ERR_NOMEM 2
-
 /*
   ctdb flags
 */
 #define CTDB_FLAG_TORTURE      (1<<1)
 
-/*
-   a message handler ID meaning "give me all messages"
- */
-#define CTDB_SRVID_ALL (~(uint64_t)0)
-
-/*
-  srvid type : RECOVERY
-*/
-#define CTDB_SRVID_RECOVERY	0xF100000000000000LL
-
-/*
-   a message handler ID meaning that the cluster has been reconfigured
- */
-#define CTDB_SRVID_RECONFIGURE 0xF200000000000000LL
-
-/*
-   a message handler ID meaning that an IP address has been released
- */
-#define CTDB_SRVID_RELEASE_IP 0xF300000000000000LL
-
-/*
-   a message handler ID meaning that an IP address has been taken
- */
-#define CTDB_SRVID_TAKE_IP 0xF301000000000000LL
-
-/*
-   a message ID to set the node flags in the recovery daemon
- */
-#define CTDB_SRVID_SET_NODE_FLAGS 0xF400000000000000LL
-
-/*
-   a message ID to ask the recovery daemon to update the expected node
-   assignment for a public ip
- */
-#define CTDB_SRVID_RECD_UPDATE_IP 0xF500000000000000LL
-
-/*
-  a message to tell the recovery daemon to fetch a set of records
- */
-#define CTDB_SRVID_VACUUM_FETCH 0xF700000000000000LL
-
-/*
- * a message to tell recovery daemon to detach a database
- */
-#define CTDB_SRVID_DETACH_DATABASE 0xF701000000000000LL
-/*
-  a message to tell the recovery daemon to write a talloc memdump
-  to the log
- */
-#define CTDB_SRVID_MEM_DUMP 0xF800000000000000LL
-
-/* A message id used to ask the recover daemon to send logs
-*/
-#define CTDB_SRVID_GETLOG  0xF801000000000000LL
-
-/* A message id used to ask the recover daemon to send logs
-*/
-#define CTDB_SRVID_CLEARLOG  0xF802000000000000LL
-
-/*
-   a message ID to get the recovery daemon to push the node flags out
- */
-#define CTDB_SRVID_PUSH_NODE_FLAGS 0xF900000000000000LL
-
-/*
-   a message ID to get the recovery daemon to reload the nodes file
- */
-#define CTDB_SRVID_RELOAD_NODES 0xFA00000000000000LL
-
-/*
-   a message ID to get the recovery daemon to perform a takeover run
- */
-#define CTDB_SRVID_TAKEOVER_RUN 0xFB00000000000000LL
-
-/* request recovery daemon to rebalance ips for a node.
-   input is uint32_t for the node id.
-*/
-#define CTDB_SRVID_REBALANCE_NODE 0xFB01000000000000LL
-
-/* A message handler ID to stop takeover runs from occurring */
-#define CTDB_SRVID_DISABLE_TAKEOVER_RUNS 0xFB03000000000000LL
-
-/* A message handler ID to stop recoveries from occurring */
-#define CTDB_SRVID_DISABLE_RECOVERIES 0xFB04000000000000LL
-
-/* A message id to ask the recovery daemon to temporarily disable the
-   public ip checks
-*/
-#define CTDB_SRVID_DISABLE_IP_CHECK  0xFC00000000000000LL
-
-/* A dummy port used for sending back ipreallocate resposnes to the main
-   daemon
-*/
-#define CTDB_SRVID_TAKEOVER_RUN_RESPONSE  0xFD00000000000000LL
-
-/* A range of ports reserved for registering a PID (top 8 bits)
- * All ports matching the 8 top bits are reserved for exclusive use by
- * registering a SRVID that matches the process-id of the requesting process
- */
-#define CTDB_SRVID_PID_RANGE   0x0000000000000000LL
-
-/* A range of ports reserved for samba (top 8 bits)
- * All ports matching the 8 top bits are reserved for exclusive use by
- * CIFS server
- */
-#define CTDB_SRVID_SAMBA_NOTIFY  0xFE00000000000000LL
-#define CTDB_SRVID_SAMBA_RANGE   0xFE00000000000000LL
-
-/* A range of ports reserved for a CTDB NFS server (top 8 bits)
- * All ports matching the 8 top bits are reserved for exclusive use by
- * NFS server
- */
-#define CTDB_SRVID_NFSD_RANGE  0xEE00000000000000LL
-
-/* A range of ports reserved for a CTDB ISCSI server (top 8 bits)
- * All ports matching the 8 top bits are reserved for exclusive use by
- * ISCSI server
- */
-#define CTDB_SRVID_ISCSID_RANGE  0xDE00000000000000LL
-
-/* A range of ports reserved for testing (top 8 bits)
- * All ports matching the 8 top bits are reserved for exclusive use by
- * test applications
- */
-#define CTDB_SRVID_TEST_RANGE  0xCE00000000000000LL
-
-/* Range of ports reserved for traversals */
-#define CTDB_SRVID_TRAVERSE_RANGE  0xBE00000000000000LL
-
-/* used on the domain socket, send a pdu to the local daemon */
-#define CTDB_CURRENT_NODE     0xF0000001
-/* send a broadcast to all nodes in the cluster, active or not */
-#define CTDB_BROADCAST_ALL    0xF0000002
-/* send a broadcast to all nodes in the current vnn map */
-#define CTDB_BROADCAST_VNNMAP 0xF0000003
-/* send a broadcast to all connected nodes */
-#define CTDB_BROADCAST_CONNECTED 0xF0000004
-/* send a broadcast to selected connected nodes */
-#define CTDB_MULTICAST 0xF0000005
-
-/* the key used for transaction locking on persistent databases */
-#define CTDB_TRANSACTION_LOCK_KEY "__transaction_lock__"
-
-/* the key used to store persistent db sequence number */
-#define CTDB_DB_SEQNUM_KEY "__db_sequence_number__"
-
-#define MONITOR_SCRIPT_OK      0
-#define MONITOR_SCRIPT_TIMEOUT 1
-
-#define MAX_SCRIPT_NAME 31
-#define MAX_SCRIPT_OUTPUT 511
-struct ctdb_script_wire {
-	char name[MAX_SCRIPT_NAME+1];
-	struct timeval start;
-	struct timeval finished;
-	int32_t status;
-	char output[MAX_SCRIPT_OUTPUT+1];
-};
-
-struct ctdb_scripts_wire {
+struct ctdb_script_list_old {
 	uint32_t num_scripts;
-	struct ctdb_script_wire scripts[1];
-};
-
-/* different calls to event scripts. */
-enum ctdb_eventscript_call {
-	CTDB_EVENT_INIT,		/* CTDB starting up: no args */
-	CTDB_EVENT_SETUP,		/* CTDB starting up after transport is readdy: no args. */
-	CTDB_EVENT_STARTUP,		/* CTDB starting up after initial recovery: no args. */
-	CTDB_EVENT_START_RECOVERY,	/* CTDB recovery starting: no args. */
-	CTDB_EVENT_RECOVERED,		/* CTDB recovery finished: no args. */
-	CTDB_EVENT_TAKE_IP,		/* IP taken: interface, IP address, netmask bits. */
-	CTDB_EVENT_RELEASE_IP,		/* IP released: interface, IP address, netmask bits. */
-	CTDB_EVENT_STOPPED,		/* Deprecated, do not use. */
-	CTDB_EVENT_MONITOR,		/* Please check if service is healthy: no args. */
-	CTDB_EVENT_STATUS,		/* Deprecated, do not use. */
-	CTDB_EVENT_SHUTDOWN,		/* CTDB shutting down: no args. */
-	CTDB_EVENT_RELOAD,		/* Deprecated, do not use */
-	CTDB_EVENT_UPDATE_IP,		/* IP updating: old interface, new interface, IP address, netmask bits. */
-	CTDB_EVENT_IPREALLOCATED,	/* when a takeover_run() completes */
-	CTDB_EVENT_MAX
+	struct ctdb_script scripts[1];
 };
 
 /* Mapping from enum to names. */
 extern const char *ctdb_eventscript_call_names[];
 
 /*
-  operation IDs
-*/
-enum ctdb_operation {
-	CTDB_REQ_CALL           = 0,
-	CTDB_REPLY_CALL         = 1,
-	CTDB_REQ_DMASTER        = 2,
-	CTDB_REPLY_DMASTER      = 3,
-	CTDB_REPLY_ERROR        = 4,
-	CTDB_REQ_MESSAGE        = 5,
-	/* #6 removed */
-	CTDB_REQ_CONTROL        = 7,
-	CTDB_REPLY_CONTROL      = 8,
-	CTDB_REQ_KEEPALIVE      = 9,
-};
-
-#define CTDB_MAGIC 0x43544442 /* CTDB */
-#define CTDB_PROTOCOL 1
-
-enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS          = 0,
-		    CTDB_CONTROL_STATISTICS              = 1,
-		    /* #2 removed */
-		    CTDB_CONTROL_PING                    = 3,
-		    CTDB_CONTROL_GETDBPATH               = 4,
-		    CTDB_CONTROL_GETVNNMAP               = 5,
-		    CTDB_CONTROL_SETVNNMAP               = 6,
-		    CTDB_CONTROL_GET_DEBUG               = 7,
-		    CTDB_CONTROL_SET_DEBUG               = 8,
-		    CTDB_CONTROL_GET_DBMAP               = 9,
-		    CTDB_CONTROL_GET_NODEMAPv4           = 10, /* obsolete */
-		    CTDB_CONTROL_SET_DMASTER             = 11, /* obsolete */
-		    /* #12 removed */
-		    CTDB_CONTROL_PULL_DB                 = 13,
-		    CTDB_CONTROL_PUSH_DB                 = 14,
-		    CTDB_CONTROL_GET_RECMODE             = 15,
-		    CTDB_CONTROL_SET_RECMODE             = 16,
-		    CTDB_CONTROL_STATISTICS_RESET        = 17,
-		    CTDB_CONTROL_DB_ATTACH               = 18,
-		    CTDB_CONTROL_SET_CALL                = 19, /* obsolete */
-		    CTDB_CONTROL_TRAVERSE_START          = 20,
-		    CTDB_CONTROL_TRAVERSE_ALL            = 21,
-		    CTDB_CONTROL_TRAVERSE_DATA           = 22,
-		    CTDB_CONTROL_REGISTER_SRVID          = 23,
-		    CTDB_CONTROL_DEREGISTER_SRVID        = 24,
-		    CTDB_CONTROL_GET_DBNAME              = 25,
-		    CTDB_CONTROL_ENABLE_SEQNUM           = 26,
-		    CTDB_CONTROL_UPDATE_SEQNUM           = 27,
-		    /* #28 removed */
-		    CTDB_CONTROL_DUMP_MEMORY             = 29,
-		    CTDB_CONTROL_GET_PID                 = 30,
-		    CTDB_CONTROL_GET_RECMASTER           = 31,
-		    CTDB_CONTROL_SET_RECMASTER           = 32,
-		    CTDB_CONTROL_FREEZE                  = 33,
-		    CTDB_CONTROL_THAW                    = 34,
-		    CTDB_CONTROL_GET_PNN                 = 35,
-		    CTDB_CONTROL_SHUTDOWN                = 36,
-		    CTDB_CONTROL_GET_MONMODE             = 37,
-		    /* #38 removed */
-		    /* #39 removed */
-		    /* #40 removed */
-		    /* #41 removed */
-		    CTDB_CONTROL_TAKEOVER_IPv4           = 42, /* obsolete */
-		    CTDB_CONTROL_RELEASE_IPv4            = 43, /* obsolete */
-		    CTDB_CONTROL_TCP_CLIENT              = 44,
-		    CTDB_CONTROL_TCP_ADD                 = 45,
-		    CTDB_CONTROL_TCP_REMOVE              = 46,
-		    CTDB_CONTROL_STARTUP                 = 47,
-		    CTDB_CONTROL_SET_TUNABLE             = 48,
-		    CTDB_CONTROL_GET_TUNABLE             = 49,
-		    CTDB_CONTROL_LIST_TUNABLES           = 50,
-		    CTDB_CONTROL_GET_PUBLIC_IPSv4        = 51, /* obsolete */
-		    CTDB_CONTROL_MODIFY_FLAGS            = 52,
-		    CTDB_CONTROL_GET_ALL_TUNABLES        = 53,
-		    CTDB_CONTROL_KILL_TCP                = 54,
-		    CTDB_CONTROL_GET_TCP_TICKLE_LIST     = 55,
-		    CTDB_CONTROL_SET_TCP_TICKLE_LIST     = 56,
-		    CTDB_CONTROL_REGISTER_SERVER_ID	 = 57,
-		    CTDB_CONTROL_UNREGISTER_SERVER_ID	 = 58,
-		    CTDB_CONTROL_CHECK_SERVER_ID	 = 59,
-		    CTDB_CONTROL_GET_SERVER_ID_LIST	 = 60,
-		    CTDB_CONTROL_DB_ATTACH_PERSISTENT    = 61,
-		    CTDB_CONTROL_PERSISTENT_STORE        = 62, /* obsolete */
-		    CTDB_CONTROL_UPDATE_RECORD           = 63,
-		    CTDB_CONTROL_SEND_GRATIOUS_ARP       = 64,
-		    CTDB_CONTROL_TRANSACTION_START       = 65,
-		    CTDB_CONTROL_TRANSACTION_COMMIT      = 66,
-		    CTDB_CONTROL_WIPE_DATABASE           = 67,
-		    /* #68 removed */
-		    CTDB_CONTROL_UPTIME                  = 69,
-		    CTDB_CONTROL_START_RECOVERY          = 70,
-		    CTDB_CONTROL_END_RECOVERY            = 71,
-		    CTDB_CONTROL_RELOAD_NODES_FILE       = 72,
-		    /* #73 removed */
-		    CTDB_CONTROL_TRY_DELETE_RECORDS      = 74,
-		    CTDB_CONTROL_ENABLE_MONITOR          = 75,
-		    CTDB_CONTROL_DISABLE_MONITOR         = 76,
-		    CTDB_CONTROL_ADD_PUBLIC_IP           = 77,
-		    CTDB_CONTROL_DEL_PUBLIC_IP           = 78,
-		    CTDB_CONTROL_RUN_EVENTSCRIPTS        = 79,
-		    CTDB_CONTROL_GET_CAPABILITIES	 = 80,
-		    CTDB_CONTROL_START_PERSISTENT_UPDATE = 81,
-		    CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE= 82,
-		    CTDB_CONTROL_TRANS2_COMMIT           = 83, /* obsolete */
-		    CTDB_CONTROL_TRANS2_FINISHED         = 84, /* obsolete */
-		    CTDB_CONTROL_TRANS2_ERROR            = 85, /* obsolete */
-		    CTDB_CONTROL_TRANS2_COMMIT_RETRY     = 86, /* obsolete */
-		    CTDB_CONTROL_RECD_PING		 = 87,
-		    CTDB_CONTROL_RELEASE_IP              = 88,
-		    CTDB_CONTROL_TAKEOVER_IP             = 89,
-		    CTDB_CONTROL_GET_PUBLIC_IPS          = 90,
-		    CTDB_CONTROL_GET_NODEMAP             = 91,
-		    CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS = 96,
-		    CTDB_CONTROL_TRAVERSE_KILL		 = 97,
-		    CTDB_CONTROL_RECD_RECLOCK_LATENCY    = 98,
-		    CTDB_CONTROL_GET_RECLOCK_FILE        = 99,
-		    CTDB_CONTROL_SET_RECLOCK_FILE        = 100,
-		    CTDB_CONTROL_STOP_NODE               = 101,
-		    CTDB_CONTROL_CONTINUE_NODE           = 102,
-		    CTDB_CONTROL_SET_NATGWSTATE          = 103,
-		    CTDB_CONTROL_SET_LMASTERROLE         = 104,
-		    CTDB_CONTROL_SET_RECMASTERROLE       = 105,
-		    CTDB_CONTROL_ENABLE_SCRIPT           = 107,
-		    CTDB_CONTROL_DISABLE_SCRIPT          = 108,
-		    CTDB_CONTROL_SET_BAN_STATE           = 109,
-		    CTDB_CONTROL_GET_BAN_STATE           = 110,
-		    CTDB_CONTROL_SET_DB_PRIORITY         = 111,
-		    CTDB_CONTROL_GET_DB_PRIORITY         = 112,
-		    CTDB_CONTROL_TRANSACTION_CANCEL      = 113,
-		    CTDB_CONTROL_REGISTER_NOTIFY         = 114,
-		    CTDB_CONTROL_DEREGISTER_NOTIFY       = 115,
-		    CTDB_CONTROL_TRANS2_ACTIVE           = 116, /* obsolete */
-		    CTDB_CONTROL_GET_LOG		 = 117, /* obsolete */
-		    CTDB_CONTROL_CLEAR_LOG		 = 118, /* obsolete */
-		    CTDB_CONTROL_TRANS3_COMMIT           = 119,
-		    CTDB_CONTROL_GET_DB_SEQNUM           = 120,
-		    CTDB_CONTROL_DB_SET_HEALTHY		 = 121,
-		    CTDB_CONTROL_DB_GET_HEALTH		 = 122,
-		    CTDB_CONTROL_GET_PUBLIC_IP_INFO	 = 123,
-		    CTDB_CONTROL_GET_IFACES		 = 124,
-		    CTDB_CONTROL_SET_IFACE_LINK_STATE	 = 125,
-		    CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE  = 126,
-		    CTDB_CONTROL_GET_STAT_HISTORY	 = 127,
-		    CTDB_CONTROL_SCHEDULE_FOR_DELETION   = 128,
-		    CTDB_CONTROL_SET_DB_READONLY	 = 129,
-		    CTDB_CONTROL_CHECK_SRVIDS		 = 130,
-		    CTDB_CONTROL_TRAVERSE_START_EXT	 = 131,
-		    CTDB_CONTROL_GET_DB_STATISTICS	 = 132,
-		    CTDB_CONTROL_SET_DB_STICKY		 = 133,
-		    CTDB_CONTROL_RELOAD_PUBLIC_IPS	 = 134,
-		    CTDB_CONTROL_TRAVERSE_ALL_EXT	 = 135,
-		    CTDB_CONTROL_RECEIVE_RECORDS	 = 136,
-		    CTDB_CONTROL_IPREALLOCATED		 = 137,
-		    CTDB_CONTROL_GET_RUNSTATE		 = 138,
-		    CTDB_CONTROL_DB_DETACH		 = 139,
-		    CTDB_CONTROL_GET_NODES_FILE		 = 140,
-};
-
-/*
   packet structures
 */
-struct ctdb_req_header {
-	uint32_t length;
-	uint32_t ctdb_magic;
-	uint32_t ctdb_version;
-	uint32_t generation;
-	uint32_t operation;
-	uint32_t destnode;
-	uint32_t srcnode;
-	uint32_t reqid;
-};
-
-struct ctdb_req_call {
+struct ctdb_req_call_old {
 	struct ctdb_req_header hdr;
 	uint32_t flags;
 	uint32_t db_id;
@@ -442,21 +69,21 @@ struct ctdb_req_call {
 	uint8_t data[1]; /* key[] followed by calldata[] */
 };
 
-struct ctdb_reply_call {
+struct ctdb_reply_call_old {
 	struct ctdb_req_header hdr;
 	uint32_t status;
 	uint32_t datalen;
 	uint8_t  data[1];
 };
 
-struct ctdb_reply_error {
+struct ctdb_reply_error_old {
 	struct ctdb_req_header hdr;
 	uint32_t status;
 	uint32_t msglen;
 	uint8_t  msg[1];
 };
 
-struct ctdb_req_dmaster {
+struct ctdb_req_dmaster_old {
 	struct ctdb_req_header hdr;
 	uint32_t db_id;
 	uint64_t rsn;
@@ -466,7 +93,7 @@ struct ctdb_req_dmaster {
 	uint8_t  data[1];
 };
 
-struct ctdb_reply_dmaster {
+struct ctdb_reply_dmaster_old {
 	struct ctdb_req_header hdr;
 	uint32_t db_id;
 	uint64_t rsn;
@@ -475,38 +102,25 @@ struct ctdb_reply_dmaster {
 	uint8_t  data[1];
 };
 
-struct ctdb_req_message {
+struct ctdb_req_message_old {
 	struct ctdb_req_header hdr;
 	uint64_t srvid;
 	uint32_t datalen;
 	uint8_t data[1];
 };
 
-struct ctdb_req_getdbpath {
-	struct ctdb_req_header hdr;
-	uint32_t db_id;
-};
-
-struct ctdb_reply_getdbpath {
-	struct ctdb_req_header hdr;
-	uint32_t datalen;
-	uint8_t data[1];
-};
-
-struct ctdb_req_control {
+struct ctdb_req_control_old {
 	struct ctdb_req_header hdr;
 	uint32_t opcode;
 	uint32_t pad;
 	uint64_t srvid;
 	uint32_t client_id;
-#define CTDB_CTRL_FLAG_NOREPLY   1
-#define CTDB_CTRL_FLAG_OPCODE_SPECIFIC   0xFFFF0000
 	uint32_t flags;
 	uint32_t datalen;
 	uint8_t data[1];
 };
 
-struct ctdb_reply_control {
+struct ctdb_reply_control_old {
 	struct ctdb_req_header hdr;
 	int32_t  status;
 	uint32_t datalen;
@@ -514,110 +128,29 @@ struct ctdb_reply_control {
 	uint8_t data[1];
 };
 
-struct ctdb_req_keepalive {
+struct ctdb_req_keepalive_old {
 	struct ctdb_req_header hdr;
 };
 
-
-/*
-  the extended header for records in the ltdb
-*/
-struct ctdb_ltdb_header {
-	uint64_t rsn;
-	uint32_t dmaster;
-	uint32_t reserved1;
-#define CTDB_REC_FLAG_DEFAULT			0x00000000
-#define CTDB_REC_FLAG_MIGRATED_WITH_DATA	0x00010000
-#define CTDB_REC_FLAG_VACUUM_MIGRATED		0x00020000
-#define CTDB_REC_FLAG_AUTOMATIC			0x00040000
-#define CTDB_REC_RO_HAVE_DELEGATIONS		0x01000000
-#define CTDB_REC_RO_HAVE_READONLY		0x02000000
-#define CTDB_REC_RO_REVOKING_READONLY		0x04000000
-#define CTDB_REC_RO_REVOKE_COMPLETE		0x08000000
-#define CTDB_REC_RO_FLAGS			(CTDB_REC_RO_HAVE_DELEGATIONS|\
-						 CTDB_REC_RO_HAVE_READONLY|\
-						 CTDB_REC_RO_REVOKING_READONLY|\
-						 CTDB_REC_RO_REVOKE_COMPLETE)
-	uint32_t flags;
-};
-
-
-/*
-  definitions for different socket structures
- */
-typedef struct sockaddr_in ctdb_addr_in;
-typedef struct sockaddr_in6 ctdb_addr_in6;
-typedef union {
-	struct sockaddr sa;
-	ctdb_addr_in	ip;
-	ctdb_addr_in6	ip6;
-} ctdb_sock_addr;
-
-/*
-   A structure describing a single node, its flags and its address
-*/
-struct ctdb_node_and_flags {
-	uint32_t pnn;
-	uint32_t flags;
-	ctdb_sock_addr addr;
-};
-
-
 /*
    Structure used for a nodemap. 
    The nodemap is the structure containing a list of all nodes
    known to the cluster and their associated flags.
 */
-struct ctdb_node_map {
+struct ctdb_node_map_old {
 	uint32_t num;
 	struct ctdb_node_and_flags nodes[1];
 };
 
-/*
- * Node flags
- */
-#define NODE_FLAGS_DISCONNECTED		0x00000001 /* node isn't connected */
-#define NODE_FLAGS_UNHEALTHY  		0x00000002 /* monitoring says node is unhealthy */
-#define NODE_FLAGS_PERMANENTLY_DISABLED	0x00000004 /* administrator has disabled node */
-#define NODE_FLAGS_BANNED		0x00000008 /* recovery daemon has banned the node */
-#define NODE_FLAGS_DELETED		0x00000010 /* this node has been deleted */
-#define NODE_FLAGS_STOPPED		0x00000020 /* this node has been stopped */
-#define NODE_FLAGS_DISABLED		(NODE_FLAGS_UNHEALTHY|NODE_FLAGS_PERMANENTLY_DISABLED)
-#define NODE_FLAGS_INACTIVE		(NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)
-
-/*
- * Node capabilities
- */
-#define CTDB_CAP_RECMASTER		0x00000001
-#define CTDB_CAP_LMASTER		0x00000002
-/* This capability is set if CTDB_LVS_PUBLIC_IP is set */
-#define CTDB_CAP_LVS			0x00000004
-/* This capability is set if NATGW is enabled */
-#define CTDB_CAP_NATGW			0x00000008
-
-
-struct ctdb_public_ip {
-	uint32_t pnn;
-	ctdb_sock_addr addr;
-};
-
-struct ctdb_all_public_ips {
+struct ctdb_public_ip_list_old {
 	uint32_t num;
 	struct ctdb_public_ip ips[1];
 };
 
-
-struct latency_counter {
-	int num;
-	double min;
-	double max;
-	double total;
-};
-
 /*
   structure used to pass record data between the child and parent
  */
-struct ctdb_rec_data {
+struct ctdb_rec_data_old {
 	uint32_t length;
 	uint32_t reqid;
 	uint32_t keylen;
@@ -625,88 +158,10 @@ struct ctdb_rec_data {
 	uint8_t  data[1];
 };
 
-struct ctdb_traverse_start {
-	uint32_t db_id;
-	uint32_t reqid;
-	uint64_t srvid;
-};
-
-struct ctdb_traverse_start_ext {
-	uint32_t db_id;
-	uint32_t reqid;
-	uint64_t srvid;
-	bool withemptyrecords;
-};
-
-/*
-  ctdb statistics information
- */
-#define MAX_COUNT_BUCKETS 16
-#define MAX_HOT_KEYS      10
-
-struct ctdb_statistics {
-	uint32_t num_clients;
-	uint32_t frozen;
-	uint32_t recovering;
-	uint32_t client_packets_sent;
-	uint32_t client_packets_recv;
-	uint32_t node_packets_sent;
-	uint32_t node_packets_recv;
-	uint32_t keepalive_packets_sent;
-	uint32_t keepalive_packets_recv;
-	struct {
-		uint32_t req_call;
-		uint32_t reply_call;
-		uint32_t req_dmaster;
-		uint32_t reply_dmaster;
-		uint32_t reply_error;
-		uint32_t req_message;
-		uint32_t req_control;
-		uint32_t reply_control;
-	} node;
-	struct {
-		uint32_t req_call;
-		uint32_t req_message;
-		uint32_t req_control;
-	} client;
-	struct {
-		uint32_t call;
-		uint32_t control;
-		uint32_t traverse;
-	} timeouts;
-	struct {
-		struct latency_counter ctdbd;
-		struct latency_counter recd;
-	} reclock;
-	struct {
-		uint32_t num_calls;
-		uint32_t num_current;
-		uint32_t num_pending;
-		uint32_t num_failed;
-		struct latency_counter latency;
-		uint32_t buckets[MAX_COUNT_BUCKETS];
-	} locks;
-	uint32_t total_calls;
-	uint32_t pending_calls;
-	uint32_t childwrite_calls;
-	uint32_t pending_childwrite_calls;
-	uint32_t memory_used;
-	uint32_t __last_counter; /* hack for control_statistics_all */
-	uint32_t max_hop_count;
-	uint32_t hop_count_bucket[MAX_COUNT_BUCKETS];
-	struct latency_counter call_latency;
-	struct latency_counter childwrite_latency;
-	uint32_t num_recoveries;
-	struct timeval statistics_start_time;
-	struct timeval statistics_current_time;
-	uint32_t total_ro_delegations;
-	uint32_t total_ro_revokes;
-};
-
 /*
  * wire format for statistics history
  */
-struct ctdb_statistics_wire {
+struct ctdb_statistics_list_old {
 	uint32_t num;
 	struct ctdb_statistics stats[1];
 };
@@ -714,17 +169,17 @@ struct ctdb_statistics_wire {
 /*
  * db statistics
  */
-struct ctdb_db_statistics {
+struct ctdb_db_statistics_old {
 	struct {
 		uint32_t num_calls;
 		uint32_t num_current;
 		uint32_t num_pending;
 		uint32_t num_failed;
-		struct latency_counter latency;
+		struct ctdb_latency_counter latency;
 		uint32_t buckets[MAX_COUNT_BUCKETS];
 	} locks;
 	struct {
-		struct latency_counter latency;
+		struct ctdb_latency_counter latency;
 	} vacuum;
 	uint32_t db_ro_delegations;
 	uint32_t db_ro_revokes;
@@ -737,42 +192,107 @@ struct ctdb_db_statistics {
 	char hot_keys_wire[1];
 };
 
-/*
- * wire format for interface list
+/* 
+   a wire representation of the vnn map
  */
-#ifdef IFNAMSIZ
-#define CTDB_IFACE_SIZE IFNAMSIZ
-#else
-#define CTDB_IFACE_SIZE 16
-#endif
+struct ctdb_vnn_map_wire {
+	uint32_t generation;
+	uint32_t size;
+	uint32_t map[1];
+};
 
-struct ctdb_iface_info {
-	char name[CTDB_IFACE_SIZE+2];
-	uint16_t link_state;
-	uint32_t references;
+struct ctdb_notify_data_old {
+	uint64_t srvid;
+	uint32_t len;
+	uint8_t notify_data[1];
 };
 
-struct ctdb_ifaces_list {
+/* table that contains a list of all dbids on a node
+ */
+struct ctdb_dbid_map_old {
 	uint32_t num;
-	struct ctdb_iface_info ifaces[1];
+	struct ctdb_dbid dbs[1];
 };
 
-#define INVALID_GENERATION 1
-/* table that contains the mapping between a hash value and lmaster
+struct ctdb_client_id_list_old {
+	uint32_t num;
+	struct ctdb_client_id server_ids[1];
+};
+
+/* the list of tcp tickles used by get/set tcp tickle list */
+struct ctdb_tickle_list_old {
+	ctdb_sock_addr addr;
+	uint32_t num;
+	struct ctdb_connection connections[1];
+};
+
+/*
+  struct holding a ctdb_sock_addr and an interface name,
+  used to add/remove public addresses and grat arp
  */
-struct ctdb_vnn_map {
-	uint32_t generation;
-	uint32_t size;
-	uint32_t *map;
+struct ctdb_addr_info_old {
+	ctdb_sock_addr addr;
+	uint32_t mask;
+	uint32_t len;
+	char iface[1];
 };
 
-/* 
-   a wire representation of the vnn map
+/* structure used for sending lists of records */
+struct ctdb_marshall_buffer {
+	uint32_t db_id;
+	uint32_t count;
+	uint8_t data[1];
+};
+
+/*
+  structure for setting a tunable
  */
-struct ctdb_vnn_map_wire {
-	uint32_t generation;
-	uint32_t size;
-	uint32_t map[1];
+struct ctdb_tunable_old {
+	uint32_t value;
+	uint32_t length;
+	uint8_t  name[1];
+};
+
+/*
+  structure for getting a tunable
+ */
+struct ctdb_control_get_tunable {
+	uint32_t length;
+	uint8_t  name[1];
+};
+
+/*
+  structure for listing tunables
+ */
+struct ctdb_control_list_tunable {
+	uint32_t length;
+	/* returns a : separated list of tunable names */
+	uint8_t  data[1];
+};
+
+
+#define CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE 0x00010000
+
+struct ctdb_public_ip_info_old {
+	struct ctdb_public_ip ip;
+	uint32_t active_idx;
+	uint32_t num;
+	struct ctdb_iface ifaces[1];
+};
+
+struct ctdb_iface_list_old {
+	uint32_t num;
+	struct ctdb_iface ifaces[1];
+};
+
+/**
+ * structure to pass to a schedule_for_deletion_control
+ */
+struct ctdb_control_schedule_for_deletion {
+	uint32_t db_id;
+	struct ctdb_ltdb_header hdr;
+	uint32_t keylen;
+	uint8_t key[1]; /* key[] */
 };
 
 #endif
diff --git a/ctdb/include/ctdb_typesafe_cb.h b/ctdb/include/ctdb_typesafe_cb.h
deleted file mode 100644
index b1f2c5f..0000000
--- a/ctdb/include/ctdb_typesafe_cb.h
+++ /dev/null
@@ -1,177 +0,0 @@
-#ifndef CCAN_CAST_IF_TYPE_H
-#define CCAN_CAST_IF_TYPE_H
-
-#if (__GNUC__ >= 3)
-#define HAVE_TYPEOF 1
-#define HAVE_BUILTIN_CHOOSE_EXPR 1
-#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1
-#endif
-
-#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
-/**
- * cast_if_type - only cast an expression if test matches a given type
- * @desttype: the type to cast to
- * @expr: the expression to cast
- * @test: the expression to test
- * @oktype: the type we allow
- *
- * This macro is used to create functions which allow multiple types.
- * The result of this macro is used somewhere that a @desttype type is
- * expected: if @expr was of type @oktype, it will be cast to
- * @desttype type.  As a result, if @expr is any type other than
- * @oktype or @desttype, a compiler warning will be issued.
- *
- * This macro can be used in static initializers.
- *
- * This is merely useful for warnings: if the compiler does not
- * support the primitives required for cast_if_type(), it becomes an
- * unconditional cast, and the @test and @oktype argument is not used.  In
- * particular, this means that @oktype can be a type which uses
- * the "typeof": it will not be evaluated if typeof is not supported.
- *
- * Example:
- *	// We can take either an unsigned long or a void *.
- *	void _set_some_value(void *val);
- *	#define set_some_value(e)			\
- *		_set_some_value(cast_if_type(void *, (e), (e), unsigned long))
- */
-#define cast_if_type(desttype, expr, test, oktype)			\
-__builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(test):0), oktype), \
-			(desttype)(expr), (expr))
-#else
-#define cast_if_type(desttype, expr, test, oktype) ((desttype)(expr))
-#endif
-
-/**
- * cast_if_any - only cast an expression if it is one of the three given types
- * @desttype: the type to cast to
- * @expr: the expression to cast
- * @test: the expression to test
- * @ok1: the first type we allow
- * @ok2: the second type we allow
- * @ok3: the third type we allow
- *
- * This is a convenient wrapper for multiple cast_if_type() calls.  You can
- * chain them inside each other (ie. use cast_if_any() for expr) if you need
- * more than 3 arguments.
- *
- * Example:
- *	// We can take either a long, unsigned long, void * or a const void *.
- *	void _set_some_value(void *val);
- *	#define set_some_value(expr)					\
- *		_set_some_value(cast_if_any(void *, (expr), (expr),	\
- *					    long, unsigned long, const void *))
- */
-#define cast_if_any(desttype, expr, test, ok1, ok2, ok3)		\
-	cast_if_type(desttype,						\
-		     cast_if_type(desttype,				\
-				  cast_if_type(desttype, (expr), (test), ok1), \
-				  ok2),					\
-		     ok3)
-
-/**
- * typesafe_cb - cast a callback function if it matches the arg
- * @rtype: the return type of the callback function
- * @fn: the callback function to cast
- * @arg: the (pointer) argument to hand to the callback function.
- *
- * If a callback function takes a single argument, this macro does
- * appropriate casts to a function which takes a single void * argument if the
- * callback provided matches the @arg (or a const or volatile version).
- *
- * It is assumed that @arg is of pointer type: usually @arg is passed
- * or assigned to a void * elsewhere anyway.
- *
- * Example:
- *	void _register_callback(void (*fn)(void *arg), void *arg);
- *	#define register_callback(fn, arg) \
- *		_register_callback(typesafe_cb(void, (fn), (arg)), (arg))
- */
-#define typesafe_cb(rtype, fn, arg)			\
-	cast_if_type(rtype (*)(void *), (fn), (fn)(arg), rtype)
-
-/**
- * typesafe_cb_const - cast a const callback function if it matches the arg
- * @rtype: the return type of the callback function
- * @fn: the callback function to cast
- * @arg: the (pointer) argument to hand to the callback function.
- *
- * If a callback function takes a single argument, this macro does appropriate
- * casts to a function which takes a single const void * argument if the
- * callback provided matches the @arg.
- *
- * It is assumed that @arg is of pointer type: usually @arg is passed
- * or assigned to a void * elsewhere anyway.
- *
- * Example:
- *	void _register_callback(void (*fn)(const void *arg), const void *arg);
- *	#define register_callback(fn, arg) \
- *		_register_callback(typesafe_cb_const(void, (fn), (arg)), (arg))
- */
-#define typesafe_cb_const(rtype, fn, arg)				\
-	sizeof((fn)((const void *)0)),					\
-		cast_if_type(rtype (*)(const void *),			\
-			     (fn), (fn)(arg), rtype (*)(typeof(arg)))
-
-/**
- * typesafe_cb_preargs - cast a callback function if it matches the arg
- * @rtype: the return type of the callback function
- * @fn: the callback function to cast
- * @arg: the (pointer) argument to hand to the callback function.
- *
- * This is a version of typesafe_cb() for callbacks that take other arguments
- * before the @arg.
- *
- * Example:
- *	void _register_callback(void (*fn)(int, void *arg), void *arg);
- *	#define register_callback(fn, arg) \
- *		_register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\
- *				   (arg))
- */
-#define typesafe_cb_preargs(rtype, fn, arg, ...)			\
-	cast_if_type(rtype (*)(__VA_ARGS__, void *), (fn), (fn),	\
-		     rtype (*)(__VA_ARGS__, typeof(arg)))
-/**
- * typesafe_cb_postargs - cast a callback function if it matches the arg
- * @rtype: the return type of the callback function
- * @fn: the callback function to cast
- * @arg: the (pointer) argument to hand to the callback function.
- *
- * This is a version of typesafe_cb() for callbacks that take other arguments
- * after the @arg.
- *
- * Example:
- *	void _register_callback(void (*fn)(void *arg, int), void *arg);
- *	#define register_callback(fn, arg) \
- *		_register_callback(typesafe_cb_postargs(void, (fn), (arg), int),\
- *				   (arg))
- */
-#define typesafe_cb_postargs(rtype, fn, arg, ...)			\
-	cast_if_type(rtype (*)(void *, __VA_ARGS__), (fn), (fn),	\
-		     rtype (*)(typeof(arg), __VA_ARGS__))
-/**
- * typesafe_cb_cmp - cast a compare function if it matches the arg
- * @rtype: the return type of the callback function
- * @fn: the callback function to cast
- * @arg: the (pointer) argument(s) to hand to the compare function.
- *
- * If a callback function takes two matching-type arguments, this macro does
- * appropriate casts to a function which takes two const void * arguments if
- * the callback provided takes two a const pointers to @arg.
- *
- * It is assumed that @arg is of pointer type: usually @arg is passed
- * or assigned to a void * elsewhere anyway.  Note also that the type
- * arg points to must be defined.
- *
- * Example:
- *	void _my_qsort(void *base, size_t nmemb, size_t size,
- *		       int (*cmp)(const void *, const void *));
- *	#define my_qsort(base, nmemb, cmpfn) \
- *		_my_qsort((base), (nmemb), sizeof(*(base)), \
- *			  typesafe_cb_cmp(int, (cmpfn), (base)), (arg))
- */
-#define typesafe_cb_cmp(rtype, cmpfn, arg)				\
-	cast_if_type(rtype (*)(const void *, const void *), (cmpfn),	\
-		     rtype (*)(const typeof(*arg)*, const typeof(*arg)*))
-		     
-#endif /* CCAN_CAST_IF_TYPE_H */
diff --git a/ctdb/include/internal/cmdline.h b/ctdb/include/internal/cmdline.h
deleted file mode 100644
index 67704c6..0000000
--- a/ctdb/include/internal/cmdline.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef CTDB_CMDLINE_H
-#define CTDB_CMDLINE_H
-
-extern struct poptOption popt_ctdb_cmdline[];
-
-#define POPT_CTDB_CMDLINE { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_ctdb_cmdline, 0, "Common ctdb test options:", NULL },
-
-struct ctdb_context *ctdb_cmdline_init(struct event_context *ev);
-
-#endif /* CTDB_CMDLINE_H */
diff --git a/ctdb/include/internal/includes.h b/ctdb/include/internal/includes.h
deleted file mode 100644
index 6c00c03..0000000
--- a/ctdb/include/internal/includes.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _CTDB_INCLUDES_H
-#define _CTDB_INCLUDES_H
-
-/* Replace must be before broken tdb.h to define bool */
-#include "replace.h"
-#include "system/wait.h"
-#include "system/network.h"
-
-#include <talloc.h>
-#include <tdb.h>
-
-/* Allow use of deprecated function tevent_loop_allow_nesting() */
-#define TEVENT_DEPRECATED
-/* Saves ctdb from massive churn. */
-#define TEVENT_COMPAT_DEFINES 1
-#include <tevent.h>
-
-#include "lib/util/debug.h"
-#include "lib/util/samba_util.h"
-
-#include "ctdb_client.h"
-#include "ctdb_logging.h"
-
-#endif /* _CTDB_INCLUDES_H */
diff --git a/ctdb/include/public/util/README.txt b/ctdb/include/public/util/README.txt
new file mode 100644
index 0000000..534e9b7
--- /dev/null
+++ b/ctdb/include/public/util/README.txt
@@ -0,0 +1,6 @@
+DO NOT REMOVE
+
+This is a placeholder to allow for build rules putting public headers
+in this directory. Using this directory allows us to ensure that our
+public headers will work with external applications that make use of
+Samba libraries
diff --git a/ctdb/packaging/RPM/ctdb.spec.in b/ctdb/packaging/RPM/ctdb.spec.in
index 00f0be5..1547dfb 100644
--- a/ctdb/packaging/RPM/ctdb.spec.in
+++ b/ctdb/packaging/RPM/ctdb.spec.in
@@ -95,6 +95,7 @@ CFLAGS="$RPM_OPT_FLAGS $EXTRA -D_GNU_SOURCE" ./buildtools/bin/waf configure \
 	--enable-pmda \
 %endif
 	--prefix=%{_prefix} \
+	--includedir=%{_includedir}/ctdb \
 	--libdir=%{_libdir} \
 	--sysconfdir=%{_sysconfdir} \
 	--mandir=%{_mandir} \
@@ -167,6 +168,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_sysconfdir}/ctdb/functions
 %{_sysconfdir}/ctdb/events.d/00.ctdb
 %{_sysconfdir}/ctdb/events.d/01.reclock
+%{_sysconfdir}/ctdb/events.d/05.system
 %{_sysconfdir}/ctdb/events.d/10.interface
 %{_sysconfdir}/ctdb/events.d/10.external
 %{_sysconfdir}/ctdb/events.d/13.per_ip_routing
@@ -174,13 +176,11 @@ rm -rf $RPM_BUILD_ROOT
 %{_sysconfdir}/ctdb/events.d/11.routing
 %{_sysconfdir}/ctdb/events.d/20.multipathd
 %{_sysconfdir}/ctdb/events.d/31.clamd
-%{_sysconfdir}/ctdb/events.d/40.fs_use
 %{_sysconfdir}/ctdb/events.d/40.vsftpd
 %{_sysconfdir}/ctdb/events.d/41.httpd
 %{_sysconfdir}/ctdb/events.d/49.winbind
 %{_sysconfdir}/ctdb/events.d/50.samba
 %{_sysconfdir}/ctdb/events.d/60.nfs
-%{_sysconfdir}/ctdb/events.d/62.cnfs
 %{_sysconfdir}/ctdb/events.d/70.iscsi
 %{_sysconfdir}/ctdb/events.d/91.lvs
 %{_sysconfdir}/ctdb/events.d/99.timeout
@@ -195,15 +195,19 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/ctdbd
 %{_sbindir}/ctdbd_wrapper
 %{_bindir}/ctdb
-%{_bindir}/ctdb_lock_helper
-%{_bindir}/ctdb_event_helper
-%{_bindir}/smnotify
 %{_bindir}/ping_pong
 %{_bindir}/ltdbtool
 %{_bindir}/ctdb_diagnostics
 %{_bindir}/onnode
+%dir %{_libexecdir}/ctdb
+%{_libexecdir}/ctdb/ctdb_lock_helper
+%{_libexecdir}/ctdb/ctdb_event_helper
+%{_libexecdir}/ctdb/ctdb_recovery_helper
+%{_libexecdir}/ctdb/ctdb_natgw
+%{_libexecdir}/ctdb/smnotify
 %dir %{_libdir}
 %{_libdir}/ctdb/lib*
+%{_libdir}/libtevent-unix-util.so.0*
 %{_mandir}/man1/ctdb.1.gz
 %{_mandir}/man1/ctdbd.1.gz
 %{_mandir}/man1/ctdbd_wrapper.1.gz
@@ -214,7 +218,6 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man7/ctdb.7.gz
 %{_mandir}/man7/ctdb-statistics.7.gz
 %{_mandir}/man7/ctdb-tunables.7.gz
-%{_libdir}/pkgconfig/ctdb.pc
 
 
 %package devel
@@ -226,12 +229,8 @@ development libraries for ctdb
 
 %files devel
 %defattr(-,root,root)
-%{_includedir}/ctdb.h
-%{_includedir}/ctdb_client.h
-%{_includedir}/ctdb_protocol.h
-%{_includedir}/ctdb_private.h
-%{_includedir}/ctdb_typesafe_cb.h
-%{_includedir}/ctdb_version.h
+%{_includedir}/ctdb/util/*.h
+%{_libdir}/libtevent-unix-util.so
 
 %package tests
 Summary: CTDB test suite
@@ -279,7 +278,7 @@ Performance Co-Pilot (PCP) support for CTDB
 * Tue Nov 8 2011 : Version 1.12
  - Add new tunable : AllowClientDBAttach that can be used to stop
    client db access during maintenance operations
- - Updated logging for interfaces that are missing or dont exist but are
+ - Updated logging for interfaces that are missing or don't exist but are
    configured to be used.
  - Add timeout argument to ctdb_cmdline_client
  - PDMA support
@@ -345,7 +344,7 @@ Performance Co-Pilot (PCP) support for CTDB
    just do a less disruptive ip-reallocation
  - When starting ctdbd, wait until all initial recoveries have finished 
    before we issue the "startup" event.
-   So dont start services or monitoring until the cluster has
+   So don't start services or monitoring until the cluster has
    stabilized.
  - Major eventscript overhaul by Ronnie, Rusty and Martins and fixes of a few
    bugs found.
@@ -394,14 +393,14 @@ Performance Co-Pilot (PCP) support for CTDB
    "time since last ..." if from either the last recovery OR the last failover
  - Michael A: transaction updates
 * Wed Oct 28 2009 : Version 1.0.101
- - create a separate context for non-monitoring events so they dont interfere with the monitor event
+ - create a separate context for non-monitoring events so they don't interfere with the monitor event
  - make sure to return status 0 in teh callback when we abort an event
 * Wed Oct 28 2009 : Version 1.0.100
  - Change eventscript handling to allow EventScriptTimeout for each individual script instead of for all scripts as a whole.
  - Enhanced logging from the eventscripts, log the name and the duration for each script as it finishes.
  - Add a check to use wbinfo -t for the startup event of samba
  - TEMP: allow clients to attach to databases even when teh node is in recovery mode
- - dont run the monitor event as frequently after an event has failed
+ - don't run the monitor event as frequently after an event has failed
  - DEBUG: in the eventloops, check the local time and warn if the time changes backward or rapidly forward
  - From Metze, fix a bug where recovery master becoming unhealthy did not trigger an ip failover.
  - Disable the multipath script by default
@@ -413,7 +412,7 @@ Performance Co-Pilot (PCP) support for CTDB
  - Fix a SEGV in the new db priority code.
  - From Wolfgang : eliminate a ctdb_fatal() if there is a dmaster violation detected.
  - During testing we often add/delete eventscripts at runtime. This could cause an eventscript to fail and mark the node unhealthy if an eventscript was deleted while we were listing the names. Handle the errorcode and make sure the node does not becomne unhealthy in this case.
- - Lower the debuglevel for the messages when ctdb creates a filedescruiptor so we dont spam the logs with these messages.
+ - Lower the debuglevel for the messages when ctdb creates a filedescruiptor so we don't spam the logs with these messages.
  - Dont have the RPM automatically restart ctdb
  - Volker : add a missing transaction_cancel() in the handling of persistent databases
  - Treat interfaces with the anme ethX* as bond devices in 10.interfaces so we do the correct test for if they are up or not.
@@ -436,7 +435,7 @@ Performance Co-Pilot (PCP) support for CTDB
  - Add more debugging output when eventscripts have trouble. Print a 
    "pstree -p" to the log when scripts have hung.
  - Update the initscript,  only print the "No reclock file used" warning
-   when we do "service ctdb start", dont also print them for all other
+   when we do "service ctdb start", don't also print them for all other
    actions.
  - When changing between unhealthy/healthy state, push a request to the
    recovery master to perform an ip reallocation   instead of waiting for the
@@ -479,7 +478,7 @@ Performance Co-Pilot (PCP) support for CTDB
  - Add machinereadable output to the ctdb getreclock command
  - merge transaction updates from Michael Adam
  - In the new banning code, reset the culprit count to 0 for all nodes that could successfully compelte a full recovery.
- - dont mark the recovery master as a ban culprit because a node in the cluster needs a recovery. this happens naturally when using ctdb recover command so dont make this cause a node to be banned.
+ - don't mark the recovery master as a ban culprit because a node in the cluster needs a recovery. this happens naturally when using ctdb recover command so dont make this cause a node to be banned.
 * Sat Sep 12 2009 : Version 1.0.90
  - Be more forgiving for eventscripts that hang during startup
  - Fix for a banning bug in the new banning logic
@@ -567,7 +566,7 @@ Performance Co-Pilot (PCP) support for CTDB
  - When building initial vnnmap, ignode any nonexisting nodes
  - Add a new nodestate : DELETED that is used when deleting a node from an
    existing cluster.
- - dont remove the ctdb socket when shutting down. This prevents a race in the
+ - don't remove the ctdb socket when shutting down. This prevents a race in the
    initscripts when restarting ctdb quickly after stopping it.
  - TDB nesting reworked.
  - Remove obsolete ipmux
@@ -614,7 +613,7 @@ Performance Co-Pilot (PCP) support for CTDB
  - if we can not pull a database from a remote node during recovery, mark that node as a culprit so it becomes banned
  - increase the loglevel when we volunteer to drop all ip addresses after beeing in recovery mode for too long. Make this timeout tuneable with "RecoveryDropAllIPs" and have it default to 60 seconds
  - Add a new flag TDB_NO_NESTING to the tdb layer to prevent nested transactions which ctdb does not use and does not expect. Have ctdb set this flag to prevent nested transactions from occuring.
- - dont unconditionally kill off ctdb and restrat it on "service ctdb start". Fail "service ctdb start" with an error if ctdb is already running.
+ - don't unconditionally kill off ctdb and restrat it on "service ctdb start". Fail "service ctdb start" with an error if ctdb is already running.
  - Add a new tunable "VerifyRecoveryLock" that can be set to 0 to prevent the main ctdb daemon to verify that the recovery master has locked the reclock file correctly before allowing it to set the recovery mode to active.
  - fix a cosmetic bug with ctdb statistics where certain counters could become negative.
 * Wed Apr 8 2009 : Version 1.0.79
@@ -623,7 +622,7 @@ Performance Co-Pilot (PCP) support for CTDB
  - add a funciton remove_ip to safely remove an ip from an interface, taking care to workaround an issue with linux alias interfaces.
  - Update the natgw eventscript to use the safe remove_ip() function
  - fix a bug in the eventscript child process that would cause the socket to be removed.
- - dont verify nodemap on banned nodes during cluster monitoring
+ - don't verify nodemap on banned nodes during cluster monitoring
  - Update the dodgy SeqnumInterval to have ms resolution
 * Tue Mar 31 2009 : Version 1.0.78
  - Add a notify mechanism so we can send snmptraps/email to external management systems when the node becomes unhealthy
@@ -801,7 +800,7 @@ Performance Co-Pilot (PCP) support for CTDB
 * Fri Jul 18 2008 : Version 1.0.50
  - Dont assume that just because we can establish a TCP connection
    that we are actually talking to a functioning ctdb daemon.
-   So dont mark the node as CONNECTED just because the tcp handshake
+   So don't mark the node as CONNECTED just because the tcp handshake
    was successful.
  - Dont try to set the recmaster to ourself during elections for those
    cases we know this will fail. To remove some annoying benign but scary
@@ -869,7 +868,7 @@ Performance Co-Pilot (PCP) support for CTDB
  - zero out ctdb->freeze_handle when we free/destroy a freeze-child.
    This prevent a heap corruption/ctdb crash bug that could trigger
    if the freeze child times out.
- - we dont need to explicitely thaw the databases from the recovery daemon
+ - we don't need to explicitely thaw the databases from the recovery daemon
    since this is done implicitely when we restore the recovery mode back to normal.
  - track when we start and stop a recovery. Add the 'time it took to complete the
    recovery' to the 'ctdb uptime' output.
diff --git a/ctdb/packaging/mkversion.sh b/ctdb/packaging/mkversion.sh
index e4a37ad..54dc2cd 100755
--- a/ctdb/packaging/mkversion.sh
+++ b/ctdb/packaging/mkversion.sh
@@ -61,10 +61,21 @@ case "$TAG" in
 	;;
 esac
 
+else
+
+    # If building from tarball, Samba version creation will create
+    # VERSION with UNKNOWN git hash.
+    case "$VERSION" in
+        *UNKNOWN)
+	    if [ -f ../include/ctdb_version.h ] ; then
+		VERSION=$(awk -F \" '/CTDB_VERSION_STRING/ {print $2}' ../include/ctdb_version.h)
+	    fi
+	    ;;
+    esac
 fi
 
 cat > "$OUTPUT" <<EOF
-/* This file is auto-genrated by packaging/mkversion.sh */
+/* This file is auto-generated by packaging/mkversion.sh */
 
 #define CTDB_VERSION_STRING "$VERSION"
 
diff --git a/ctdb/protocol/protocol.h b/ctdb/protocol/protocol.h
new file mode 100644
index 0000000..a2a0c45
--- /dev/null
+++ b/ctdb/protocol/protocol.h
@@ -0,0 +1,1022 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_PROTOCOL_H__
+#define __CTDB_PROTOCOL_H__
+
+#include <tdb.h>
+
+#define CTDB_MAGIC	0x43544442 /* CTDB */
+#define CTDB_PROTOCOL	1
+
+enum ctdb_operation {
+	CTDB_REQ_CALL           = 0,
+	CTDB_REPLY_CALL         = 1,
+	CTDB_REQ_DMASTER        = 2,
+	CTDB_REPLY_DMASTER      = 3,
+	CTDB_REPLY_ERROR        = 4,
+	CTDB_REQ_MESSAGE        = 5,
+	/* #6 removed */
+	CTDB_REQ_CONTROL        = 7,
+	CTDB_REPLY_CONTROL      = 8,
+	CTDB_REQ_KEEPALIVE      = 9,
+};
+
+/* used on the domain socket, send a pdu to the local daemon */
+#define CTDB_CURRENT_NODE     0xF0000001
+/* send a broadcast to all nodes in the cluster, active or not */
+#define CTDB_BROADCAST_ALL    0xF0000002
+/* send a broadcast to all nodes in the current vnn map */
+#define CTDB_BROADCAST_VNNMAP 0xF0000003
+/* send a broadcast to all connected nodes */
+#define CTDB_BROADCAST_CONNECTED 0xF0000004
+/* send a broadcast to selected connected nodes */
+#define CTDB_MULTICAST 0xF0000005
+
+#define CTDB_UNKNOWN_PNN	0xFFFFFFFF
+
+/* the key used to store persistent db sequence number */
+#define CTDB_DB_SEQNUM_KEY "__db_sequence_number__"
+
+struct ctdb_req_header {
+	uint32_t length;
+	uint32_t ctdb_magic;
+	uint32_t ctdb_version;
+	uint32_t generation;
+	uint32_t operation;
+	uint32_t destnode;
+	uint32_t srcnode;
+	uint32_t reqid;
+};
+
+struct ctdb_req_call {
+	uint32_t flags;
+	uint32_t db_id;
+	uint32_t callid;
+	uint32_t hopcount;
+	TDB_DATA key;
+	TDB_DATA calldata;
+};
+
+struct ctdb_reply_call {
+	int32_t status;
+	TDB_DATA data;
+};
+
+struct ctdb_reply_error {
+	int32_t status;
+	TDB_DATA msg;
+};
+
+struct ctdb_req_dmaster {
+	uint32_t db_id;
+	uint64_t rsn;
+	uint32_t dmaster;
+	TDB_DATA key;
+	TDB_DATA data;
+};
+
+struct ctdb_reply_dmaster {
+	uint32_t db_id;
+	uint64_t rsn;
+	TDB_DATA key;
+	TDB_DATA data;
+};
+
+#define CTDB_NULL_FUNC                  0xFF000001
+#define CTDB_FETCH_FUNC                 0xFF000002
+#define CTDB_FETCH_WITH_HEADER_FUNC     0xFF000003
+
+struct ctdb_call {
+	int call_id;
+	TDB_DATA key;
+	TDB_DATA call_data;
+	TDB_DATA reply_data;
+	uint32_t status;
+#define CTDB_IMMEDIATE_MIGRATION		0x00000001
+#define CTDB_CALL_FLAG_VACUUM_MIGRATION		0x00000002
+#define CTDB_WANT_READONLY			0x00000004
+	uint32_t flags;
+};
+
+/* SRVID to catch all messages */
+#define CTDB_SRVID_ALL (~(uint64_t)0)
+
+/* SRVID prefix used by CTDB */
+#define CTDB_SRVID_PREFIX	0xF000000000000000LL
+
+/* SRVID to inform of election data */
+#define CTDB_SRVID_ELECTION	0xF100000000000000LL
+
+/* SRVID to inform clients that the cluster has been reconfigured */
+#define CTDB_SRVID_RECONFIGURE 0xF200000000000000LL
+
+/* SRVID to inform clients an IP address has been released */
+#define CTDB_SRVID_RELEASE_IP 0xF300000000000000LL
+
+/* SRVID to inform clients that an IP address has been taken over */
+#define CTDB_SRVID_TAKE_IP 0xF301000000000000LL
+
+/* SRVID to inform recovery daemon of the node flags */
+#define CTDB_SRVID_SET_NODE_FLAGS 0xF400000000000000LL
+
+/* SRVID to inform recovery daemon to update public ip assignment */
+#define CTDB_SRVID_RECD_UPDATE_IP 0xF500000000000000LL
+
+/* SRVID to inform recovery daemon to migrate a set of records */
+#define CTDB_SRVID_VACUUM_FETCH 0xF700000000000000LL
+
+/* SRVID to inform recovery daemon to detach a database */
+#define CTDB_SRVID_DETACH_DATABASE 0xF701000000000000LL
+
+/* SRVID to inform recovery daemon to dump talloc memdump to the log */
+#define CTDB_SRVID_MEM_DUMP 0xF800000000000000LL
+
+/* SRVID to inform recovery daemon to send logs */
+#define CTDB_SRVID_GETLOG  0xF801000000000000LL
+
+/* SRVID to inform recovery daemon to clear logs */
+#define CTDB_SRVID_CLEARLOG  0xF802000000000000LL
+
+/* SRVID to inform recovery daemon to push the node flags to other nodes */
+#define CTDB_SRVID_PUSH_NODE_FLAGS 0xF900000000000000LL
+
+/* SRVID to inform recovery daemon to reload the nodes file */
+#define CTDB_SRVID_RELOAD_NODES 0xFA00000000000000LL
+
+/* SRVID to inform recovery daemon to perform a takeover run */
+#define CTDB_SRVID_TAKEOVER_RUN 0xFB00000000000000LL
+
+/* SRVID to inform recovery daemon to rebalance ips for a node.  */
+#define CTDB_SRVID_REBALANCE_NODE 0xFB01000000000000LL
+
+/* SRVID to inform recovery daemon to stop takeover runs from occurring */
+#define CTDB_SRVID_DISABLE_TAKEOVER_RUNS 0xFB03000000000000LL
+
+/* SRVID to inform recovery daemon to stop recoveries from occurring */
+#define CTDB_SRVID_DISABLE_RECOVERIES 0xFB04000000000000LL
+
+/* SRVID to inform recovery daemon to disable the public ip checks */
+#define CTDB_SRVID_DISABLE_IP_CHECK  0xFC00000000000000LL
+
+/* SRVID to inform recovery daemon of ipreallocate resposnes from ctdbd */
+#define CTDB_SRVID_TAKEOVER_RUN_RESPONSE  0xFD00000000000000LL
+
+/* A range of ports reserved for registering a PID (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * registering a SRVID that matches the process-id of the requesting process
+ */
+#define CTDB_SRVID_PID_RANGE   0x0000000000000000LL
+
+/* A range of ports reserved for samba (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * CIFS server
+ */
+#define CTDB_SRVID_SAMBA_NOTIFY  0xFE00000000000000LL
+#define CTDB_SRVID_SAMBA_RANGE   0xFE00000000000000LL
+
+/* A range of ports reserved for a CTDB NFS server (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * NFS server
+ */
+#define CTDB_SRVID_NFSD_RANGE  0xEE00000000000000LL
+
+/* A range of ports reserved for a CTDB ISCSI server (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * ISCSI server
+ */
+#define CTDB_SRVID_ISCSID_RANGE  0xDE00000000000000LL
+
+/* A range of ports reserved for testing (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * test applications
+ */
+#define CTDB_SRVID_TEST_RANGE  0xCE00000000000000LL
+
+/* Range of ports reserved for traversals */
+#define CTDB_SRVID_TRAVERSE_RANGE  0xBE00000000000000LL
+
+
+enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS          = 0,
+		    CTDB_CONTROL_STATISTICS              = 1,
+		    /* #2 removed */
+		    CTDB_CONTROL_PING                    = 3,
+		    CTDB_CONTROL_GETDBPATH               = 4,
+		    CTDB_CONTROL_GETVNNMAP               = 5,
+		    CTDB_CONTROL_SETVNNMAP               = 6,
+		    CTDB_CONTROL_GET_DEBUG               = 7,
+		    CTDB_CONTROL_SET_DEBUG               = 8,
+		    CTDB_CONTROL_GET_DBMAP               = 9,
+		    CTDB_CONTROL_GET_NODEMAPv4           = 10, /* obsolete */
+		    CTDB_CONTROL_SET_DMASTER             = 11, /* obsolete */
+		    /* #12 removed */
+		    CTDB_CONTROL_PULL_DB                 = 13,
+		    CTDB_CONTROL_PUSH_DB                 = 14,
+		    CTDB_CONTROL_GET_RECMODE             = 15,
+		    CTDB_CONTROL_SET_RECMODE             = 16,
+		    CTDB_CONTROL_STATISTICS_RESET        = 17,
+		    CTDB_CONTROL_DB_ATTACH               = 18,
+		    CTDB_CONTROL_SET_CALL                = 19, /* obsolete */
+		    CTDB_CONTROL_TRAVERSE_START          = 20,
+		    CTDB_CONTROL_TRAVERSE_ALL            = 21,
+		    CTDB_CONTROL_TRAVERSE_DATA           = 22,
+		    CTDB_CONTROL_REGISTER_SRVID          = 23,
+		    CTDB_CONTROL_DEREGISTER_SRVID        = 24,
+		    CTDB_CONTROL_GET_DBNAME              = 25,
+		    CTDB_CONTROL_ENABLE_SEQNUM           = 26,
+		    CTDB_CONTROL_UPDATE_SEQNUM           = 27,
+		    /* #28 removed */
+		    CTDB_CONTROL_DUMP_MEMORY             = 29,
+		    CTDB_CONTROL_GET_PID                 = 30,
+		    CTDB_CONTROL_GET_RECMASTER           = 31,
+		    CTDB_CONTROL_SET_RECMASTER           = 32,
+		    CTDB_CONTROL_FREEZE                  = 33,
+		    CTDB_CONTROL_THAW                    = 34,
+		    CTDB_CONTROL_GET_PNN                 = 35,
+		    CTDB_CONTROL_SHUTDOWN                = 36,
+		    CTDB_CONTROL_GET_MONMODE             = 37,
+		    /* #38 removed */
+		    /* #39 removed */
+		    /* #40 removed */
+		    /* #41 removed */
+		    CTDB_CONTROL_TAKEOVER_IPv4           = 42, /* obsolete */
+		    CTDB_CONTROL_RELEASE_IPv4            = 43, /* obsolete */
+		    CTDB_CONTROL_TCP_CLIENT              = 44,
+		    CTDB_CONTROL_TCP_ADD                 = 45,
+		    CTDB_CONTROL_TCP_REMOVE              = 46,
+		    CTDB_CONTROL_STARTUP                 = 47,
+		    CTDB_CONTROL_SET_TUNABLE             = 48,
+		    CTDB_CONTROL_GET_TUNABLE             = 49,
+		    CTDB_CONTROL_LIST_TUNABLES           = 50,
+		    CTDB_CONTROL_GET_PUBLIC_IPSv4        = 51, /* obsolete */
+		    CTDB_CONTROL_MODIFY_FLAGS            = 52,
+		    CTDB_CONTROL_GET_ALL_TUNABLES        = 53,
+		    CTDB_CONTROL_KILL_TCP                = 54,
+		    CTDB_CONTROL_GET_TCP_TICKLE_LIST     = 55,
+		    CTDB_CONTROL_SET_TCP_TICKLE_LIST     = 56,
+		    CTDB_CONTROL_REGISTER_SERVER_ID      = 57,
+		    CTDB_CONTROL_UNREGISTER_SERVER_ID    = 58,
+		    CTDB_CONTROL_CHECK_SERVER_ID         = 59,
+		    CTDB_CONTROL_GET_SERVER_ID_LIST      = 60,
+		    CTDB_CONTROL_DB_ATTACH_PERSISTENT    = 61,
+		    CTDB_CONTROL_PERSISTENT_STORE        = 62, /* obsolete */
+		    CTDB_CONTROL_UPDATE_RECORD           = 63,
+		    CTDB_CONTROL_SEND_GRATUITOUS_ARP     = 64,
+		    CTDB_CONTROL_TRANSACTION_START       = 65,
+		    CTDB_CONTROL_TRANSACTION_COMMIT      = 66,
+		    CTDB_CONTROL_WIPE_DATABASE           = 67,
+		    /* #68 removed */
+		    CTDB_CONTROL_UPTIME                  = 69,
+		    CTDB_CONTROL_START_RECOVERY          = 70,
+		    CTDB_CONTROL_END_RECOVERY            = 71,
+		    CTDB_CONTROL_RELOAD_NODES_FILE       = 72,
+		    /* #73 removed */
+		    CTDB_CONTROL_TRY_DELETE_RECORDS      = 74,
+		    CTDB_CONTROL_ENABLE_MONITOR          = 75,
+		    CTDB_CONTROL_DISABLE_MONITOR         = 76,
+		    CTDB_CONTROL_ADD_PUBLIC_IP           = 77,
+		    CTDB_CONTROL_DEL_PUBLIC_IP           = 78,
+		    CTDB_CONTROL_RUN_EVENTSCRIPTS        = 79,
+		    CTDB_CONTROL_GET_CAPABILITIES        = 80,
+		    CTDB_CONTROL_START_PERSISTENT_UPDATE = 81, /* obsolete */
+		    CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE= 82, /* obsolete */
+		    CTDB_CONTROL_TRANS2_COMMIT           = 83, /* obsolete */
+		    CTDB_CONTROL_TRANS2_FINISHED         = 84, /* obsolete */
+		    CTDB_CONTROL_TRANS2_ERROR            = 85, /* obsolete */
+		    CTDB_CONTROL_TRANS2_COMMIT_RETRY     = 86, /* obsolete */
+		    CTDB_CONTROL_RECD_PING               = 87,
+		    CTDB_CONTROL_RELEASE_IP              = 88,
+		    CTDB_CONTROL_TAKEOVER_IP             = 89,
+		    CTDB_CONTROL_GET_PUBLIC_IPS          = 90,
+		    CTDB_CONTROL_GET_NODEMAP             = 91,
+		    /* missing */
+		    CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS = 96,
+		    CTDB_CONTROL_TRAVERSE_KILL           = 97,
+		    CTDB_CONTROL_RECD_RECLOCK_LATENCY    = 98,
+		    CTDB_CONTROL_GET_RECLOCK_FILE        = 99,
+		    CTDB_CONTROL_SET_RECLOCK_FILE        = 100,
+		    CTDB_CONTROL_STOP_NODE               = 101,
+		    CTDB_CONTROL_CONTINUE_NODE           = 102,
+		    CTDB_CONTROL_SET_NATGWSTATE          = 103,
+		    CTDB_CONTROL_SET_LMASTERROLE         = 104,
+		    CTDB_CONTROL_SET_RECMASTERROLE       = 105,
+		    CTDB_CONTROL_ENABLE_SCRIPT           = 107,
+		    CTDB_CONTROL_DISABLE_SCRIPT          = 108,
+		    CTDB_CONTROL_SET_BAN_STATE           = 109,
+		    CTDB_CONTROL_GET_BAN_STATE           = 110,
+		    CTDB_CONTROL_SET_DB_PRIORITY         = 111,
+		    CTDB_CONTROL_GET_DB_PRIORITY         = 112,
+		    CTDB_CONTROL_TRANSACTION_CANCEL      = 113,
+		    CTDB_CONTROL_REGISTER_NOTIFY         = 114,
+		    CTDB_CONTROL_DEREGISTER_NOTIFY       = 115,
+		    CTDB_CONTROL_TRANS2_ACTIVE           = 116, /* obsolete */
+		    CTDB_CONTROL_GET_LOG                 = 117, /* obsolete */
+		    CTDB_CONTROL_CLEAR_LOG               = 118, /* obsolete */
+		    CTDB_CONTROL_TRANS3_COMMIT           = 119,
+		    CTDB_CONTROL_GET_DB_SEQNUM           = 120,
+		    CTDB_CONTROL_DB_SET_HEALTHY          = 121,
+		    CTDB_CONTROL_DB_GET_HEALTH           = 122,
+		    CTDB_CONTROL_GET_PUBLIC_IP_INFO      = 123,
+		    CTDB_CONTROL_GET_IFACES              = 124,
+		    CTDB_CONTROL_SET_IFACE_LINK_STATE    = 125,
+		    CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE  = 126,
+		    CTDB_CONTROL_GET_STAT_HISTORY        = 127,
+		    CTDB_CONTROL_SCHEDULE_FOR_DELETION   = 128,
+		    CTDB_CONTROL_SET_DB_READONLY         = 129,
+		    CTDB_CONTROL_CHECK_SRVIDS            = 130,
+		    CTDB_CONTROL_TRAVERSE_START_EXT      = 131,
+		    CTDB_CONTROL_GET_DB_STATISTICS       = 132,
+		    CTDB_CONTROL_SET_DB_STICKY           = 133,
+		    CTDB_CONTROL_RELOAD_PUBLIC_IPS       = 134,
+		    CTDB_CONTROL_TRAVERSE_ALL_EXT        = 135,
+		    CTDB_CONTROL_RECEIVE_RECORDS         = 136,
+		    CTDB_CONTROL_IPREALLOCATED           = 137,
+		    CTDB_CONTROL_GET_RUNSTATE            = 138,
+		    CTDB_CONTROL_DB_DETACH               = 139,
+		    CTDB_CONTROL_GET_NODES_FILE          = 140,
+		    CTDB_CONTROL_DB_FREEZE               = 141,
+		    CTDB_CONTROL_DB_THAW                 = 142,
+		    CTDB_CONTROL_DB_TRANSACTION_START    = 143,
+		    CTDB_CONTROL_DB_TRANSACTION_COMMIT   = 144,
+		    CTDB_CONTROL_DB_TRANSACTION_CANCEL	 = 145,
+};
+
+#define CTDB_MONITORING_ACTIVE		0
+#define CTDB_MONITORING_DISABLED	1
+
+#define MAX_COUNT_BUCKETS 16
+#define MAX_HOT_KEYS      10
+
+struct ctdb_latency_counter {
+	int num;
+	double min;
+	double max;
+	double total;
+};
+
+struct ctdb_statistics {
+	uint32_t num_clients;
+	uint32_t frozen;
+	uint32_t recovering;
+	uint32_t client_packets_sent;
+	uint32_t client_packets_recv;
+	uint32_t node_packets_sent;
+	uint32_t node_packets_recv;
+	uint32_t keepalive_packets_sent;
+	uint32_t keepalive_packets_recv;
+	struct {
+		uint32_t req_call;
+		uint32_t reply_call;
+		uint32_t req_dmaster;
+		uint32_t reply_dmaster;
+		uint32_t reply_error;
+		uint32_t req_message;
+		uint32_t req_control;
+		uint32_t reply_control;
+	} node;
+	struct {
+		uint32_t req_call;
+		uint32_t req_message;
+		uint32_t req_control;
+	} client;
+	struct {
+		uint32_t call;
+		uint32_t control;
+		uint32_t traverse;
+	} timeouts;
+	struct {
+		struct ctdb_latency_counter ctdbd;
+		struct ctdb_latency_counter recd;
+	} reclock;
+	struct {
+		uint32_t num_calls;
+		uint32_t num_current;
+		uint32_t num_pending;
+		uint32_t num_failed;
+		struct ctdb_latency_counter latency;
+		uint32_t buckets[MAX_COUNT_BUCKETS];
+	} locks;
+	uint32_t total_calls;
+	uint32_t pending_calls;
+	uint32_t childwrite_calls;
+	uint32_t pending_childwrite_calls;
+	uint32_t memory_used;
+	uint32_t __last_counter; /* hack */
+	uint32_t max_hop_count;
+	uint32_t hop_count_bucket[MAX_COUNT_BUCKETS];
+	struct ctdb_latency_counter call_latency;
+	struct ctdb_latency_counter childwrite_latency;
+	uint32_t num_recoveries;
+	struct timeval statistics_start_time;
+	struct timeval statistics_current_time;
+	uint32_t total_ro_delegations;
+	uint32_t total_ro_revokes;
+};
+
+#define INVALID_GENERATION 1
+/* table that contains the mapping between a hash value and lmaster
+ */
+struct ctdb_vnn_map {
+	uint32_t generation;
+	uint32_t size;
+	uint32_t *map;
+};
+
+struct ctdb_dbid {
+	uint32_t db_id;
+#define CTDB_DB_FLAGS_PERSISTENT	0x01
+#define CTDB_DB_FLAGS_READONLY		0x02
+#define CTDB_DB_FLAGS_STICKY		0x04
+	uint8_t flags;
+};
+
+struct ctdb_dbid_map {
+	uint32_t num;
+	struct ctdb_dbid *dbs;
+};
+
+struct ctdb_pulldb {
+	uint32_t db_id;
+#define CTDB_LMASTER_ANY	0xffffffff
+	uint32_t lmaster;
+};
+
+#define CTDB_RECOVERY_NORMAL		0
+#define CTDB_RECOVERY_ACTIVE		1
+
+#define CTDB_NUM_DB_PRIORITIES		3
+
+/*
+  the extended header for records in the ltdb
+*/
+struct ctdb_ltdb_header {
+	uint64_t rsn;
+	uint32_t dmaster;
+	uint32_t reserved1;
+#define CTDB_REC_FLAG_DEFAULT			0x00000000
+#define CTDB_REC_FLAG_MIGRATED_WITH_DATA	0x00010000
+#define CTDB_REC_FLAG_VACUUM_MIGRATED		0x00020000
+#define CTDB_REC_FLAG_AUTOMATIC			0x00040000
+#define CTDB_REC_RO_HAVE_DELEGATIONS		0x01000000
+#define CTDB_REC_RO_HAVE_READONLY		0x02000000
+#define CTDB_REC_RO_REVOKING_READONLY		0x04000000
+#define CTDB_REC_RO_REVOKE_COMPLETE		0x08000000
+#define CTDB_REC_RO_FLAGS			(CTDB_REC_RO_HAVE_DELEGATIONS|\
+						 CTDB_REC_RO_HAVE_READONLY|\
+						 CTDB_REC_RO_REVOKING_READONLY|\
+						 CTDB_REC_RO_REVOKE_COMPLETE)
+	uint32_t flags;
+};
+
+struct ctdb_rec_data {
+	uint32_t reqid;
+	struct ctdb_ltdb_header *header;
+	TDB_DATA key, data;
+};
+
+struct ctdb_rec_buffer {
+	uint32_t db_id;
+	uint32_t count;
+	uint8_t *buf;
+	size_t buflen;
+};
+
+typedef int (*ctdb_rec_parser_func_t)(uint32_t reqid,
+				      struct ctdb_ltdb_header *header,
+				      TDB_DATA key, TDB_DATA data,
+				      void *private_data);
+
+struct ctdb_traverse_start {
+	uint32_t db_id;
+	uint32_t reqid;
+	uint64_t srvid;
+};
+
+struct ctdb_traverse_all {
+	uint32_t db_id;
+	uint32_t reqid;
+	uint32_t pnn;
+	uint32_t client_reqid;
+	uint64_t srvid;
+};
+
+struct ctdb_traverse_start_ext {
+	uint32_t db_id;
+	uint32_t reqid;
+	uint64_t srvid;
+	bool withemptyrecords;
+};
+
+struct ctdb_traverse_all_ext {
+	uint32_t db_id;
+	uint32_t reqid;
+	uint32_t pnn;
+	uint32_t client_reqid;
+	uint64_t srvid;
+	bool withemptyrecords;
+};
+
+typedef union {
+	struct sockaddr sa;
+	struct sockaddr_in ip;
+	struct sockaddr_in6 ip6;
+} ctdb_sock_addr;
+
+struct ctdb_connection {
+	ctdb_sock_addr src;
+	ctdb_sock_addr dst;
+};
+
+struct ctdb_tunable {
+	const char *name;
+	uint32_t value;
+};
+
+struct ctdb_var_list {
+	int count;
+	const char **var;
+};
+
+struct ctdb_node_flag_change {
+	uint32_t pnn;
+	uint32_t new_flags;
+	uint32_t old_flags;
+};
+
+/* all tunable variables go in here */
+struct ctdb_tunable_list {
+	uint32_t max_redirect_count;
+	uint32_t seqnum_interval; /* unit is ms */
+	uint32_t control_timeout;
+	uint32_t traverse_timeout;
+	uint32_t keepalive_interval;
+	uint32_t keepalive_limit;
+	uint32_t recover_timeout;
+	uint32_t recover_interval;
+	uint32_t election_timeout;
+	uint32_t takeover_timeout;
+	uint32_t monitor_interval;
+	uint32_t tickle_update_interval;
+	uint32_t script_timeout;
+	uint32_t monitor_timeout_count; /* allow dodgy scripts to hang this many times in a row before we mark the node unhealthy */
+	uint32_t script_unhealthy_on_timeout; /* obsolete */
+	uint32_t recovery_grace_period;
+	uint32_t recovery_ban_period;
+	uint32_t database_hash_size;
+	uint32_t database_max_dead;
+	uint32_t rerecovery_timeout;
+	uint32_t enable_bans;
+	uint32_t deterministic_public_ips;
+	uint32_t reclock_ping_period;
+	uint32_t no_ip_failback;
+	uint32_t disable_ip_failover;
+	uint32_t verbose_memory_names;
+	uint32_t recd_ping_timeout;
+	uint32_t recd_ping_failcount;
+	uint32_t log_latency_ms;
+	uint32_t reclock_latency_ms;
+	uint32_t recovery_drop_all_ips;
+	uint32_t verify_recovery_lock;
+	uint32_t vacuum_interval;
+	uint32_t vacuum_max_run_time;
+	uint32_t repack_limit;
+	uint32_t vacuum_limit;
+	uint32_t max_queue_depth_drop_msg;
+	uint32_t allow_unhealthy_db_read;
+	uint32_t stat_history_interval;
+	uint32_t deferred_attach_timeout;
+	uint32_t vacuum_fast_path_count;
+	uint32_t lcp2_public_ip_assignment;
+	uint32_t allow_client_db_attach;
+	uint32_t recover_pdb_by_seqnum;
+	uint32_t deferred_rebalance_on_node_add;
+	uint32_t fetch_collapse;
+	uint32_t hopcount_make_sticky;
+	uint32_t sticky_duration;
+	uint32_t sticky_pindown;
+	uint32_t no_ip_takeover;
+	uint32_t db_record_count_warn;
+	uint32_t db_record_size_warn;
+	uint32_t db_size_warn;
+	uint32_t pulldb_preallocation_size;
+	uint32_t no_ip_host_on_all_disabled;
+	uint32_t samba3_hack;
+	uint32_t mutex_enabled;
+	uint32_t lock_processes_per_db;
+};
+
+struct ctdb_tickle_list {
+	ctdb_sock_addr addr;
+	uint32_t num;
+	struct ctdb_connection *conn;
+};
+
+enum ctdb_client_type {
+	SERVER_TYPE_CTDB = 0,
+	SERVER_TYPE_SAMBA = 1,
+	SERVER_TYPE_NFSD = 2,
+	SERVER_TYPE_ISCSID = 3
+};
+
+struct ctdb_client_id {
+	enum ctdb_client_type type;
+	uint32_t pnn;
+	uint32_t server_id;
+};
+
+struct ctdb_client_id_list {
+	uint32_t num;
+	struct ctdb_client_id *cid;
+};
+
+struct ctdb_client_id_map {
+	int count;
+	struct ctdb_client_id_list *list;
+};
+
+struct ctdb_addr_info {
+	ctdb_sock_addr addr;
+	uint32_t mask;
+	const char *iface;
+};
+
+struct ctdb_transdb {
+	uint32_t db_id;
+	uint32_t tid;
+};
+
+struct ctdb_uptime {
+	struct timeval current_time;
+	struct timeval ctdbd_start_time;
+	struct timeval last_recovery_started;
+	struct timeval last_recovery_finished;
+};
+
+struct ctdb_public_ip {
+	uint32_t pnn;
+	ctdb_sock_addr addr;
+};
+
+struct ctdb_public_ip_list {
+	uint32_t num;
+	struct ctdb_public_ip *ip;
+};
+
+/*
+ * Node flags
+ */
+#define NODE_FLAGS_DISCONNECTED		0x00000001 /* node isn't connected */
+#define NODE_FLAGS_UNHEALTHY  		0x00000002 /* monitoring says node is unhealthy */
+#define NODE_FLAGS_PERMANENTLY_DISABLED	0x00000004 /* administrator has disabled node */
+#define NODE_FLAGS_BANNED		0x00000008 /* recovery daemon has banned the node */
+#define NODE_FLAGS_DELETED		0x00000010 /* this node has been deleted */
+#define NODE_FLAGS_STOPPED		0x00000020 /* this node has been stopped */
+#define NODE_FLAGS_DISABLED		(NODE_FLAGS_UNHEALTHY|NODE_FLAGS_PERMANENTLY_DISABLED)
+#define NODE_FLAGS_INACTIVE		(NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)
+
+/*
+ * Node capabilities
+ */
+#define CTDB_CAP_RECMASTER		0x00000001
+#define CTDB_CAP_LMASTER		0x00000002
+/* This capability is set if CTDB_LVS_PUBLIC_IP is set */
+#define CTDB_CAP_LVS			0x00000004
+/* This capability is set if NATGW is enabled */
+#define CTDB_CAP_NATGW			0x00000008
+
+/*
+ * Node features
+ */
+#define CTDB_CAP_PARALLEL_RECOVERY	0x00010000
+
+#define CTDB_CAP_FEATURES		(CTDB_CAP_PARALLEL_RECOVERY)
+
+#define CTDB_CAP_DEFAULT		(CTDB_CAP_RECMASTER | \
+					 CTDB_CAP_LMASTER   | \
+					 CTDB_CAP_FEATURES)
+
+struct ctdb_node_and_flags {
+	uint32_t pnn;
+	uint32_t flags;
+	ctdb_sock_addr addr;
+};
+
+struct ctdb_node_map {
+	uint32_t num;
+	struct ctdb_node_and_flags *node;
+};
+
+enum ctdb_event {
+	CTDB_EVENT_INIT,		/* CTDB starting up: no args */
+	CTDB_EVENT_SETUP,		/* CTDB starting up after transport is readdy: no args. */
+	CTDB_EVENT_STARTUP,		/* CTDB starting up after initial recovery: no args. */
+	CTDB_EVENT_START_RECOVERY,	/* CTDB recovery starting: no args. */
+	CTDB_EVENT_RECOVERED,		/* CTDB recovery finished: no args. */
+	CTDB_EVENT_TAKE_IP,		/* IP taken: interface, IP address, netmask bits. */
+	CTDB_EVENT_RELEASE_IP,		/* IP released: interface, IP address, netmask bits. */
+	CTDB_EVENT_STOPPED,		/* Deprecated, do not use. */
+	CTDB_EVENT_MONITOR,		/* Please check if service is healthy: no args. */
+	CTDB_EVENT_STATUS,		/* Deprecated, do not use. */
+	CTDB_EVENT_SHUTDOWN,		/* CTDB shutting down: no args. */
+	CTDB_EVENT_RELOAD,		/* Deprecated, do not use */
+	CTDB_EVENT_UPDATE_IP,		/* IP updating: old interface, new interface, IP address, netmask bits. */
+	CTDB_EVENT_IPREALLOCATED,	/* when a takeover_run() completes */
+	CTDB_EVENT_MAX
+};
+
+#define MAX_SCRIPT_NAME 31
+#define MAX_SCRIPT_OUTPUT 511
+
+struct ctdb_script {
+	char name[MAX_SCRIPT_NAME+1];
+	struct timeval start;
+	struct timeval finished;
+	int32_t status;
+	char output[MAX_SCRIPT_OUTPUT+1];
+};
+
+struct ctdb_script_list {
+	uint32_t num_scripts;
+	struct ctdb_script *script;
+};
+
+struct ctdb_ban_state {
+	uint32_t pnn;
+	uint32_t time;
+};
+
+struct ctdb_db_priority {
+	uint32_t db_id;
+	uint32_t priority;
+};
+
+struct ctdb_notify_data {
+	uint64_t srvid;
+	TDB_DATA data;
+};
+
+#ifdef IFNAMSIZ
+#define CTDB_IFACE_SIZE IFNAMSIZ
+#else
+#define CTDB_IFACE_SIZE 16
+#endif
+
+struct ctdb_iface {
+	char name[CTDB_IFACE_SIZE+2];
+	uint16_t link_state;
+	uint32_t references;
+};
+
+struct ctdb_iface_list {
+	uint32_t num;
+	struct ctdb_iface *iface;
+};
+
+struct ctdb_public_ip_info {
+	struct ctdb_public_ip ip;
+	uint32_t active_idx;
+	struct ctdb_iface_list *ifaces;
+};
+
+struct ctdb_statistics_list {
+	int num;
+	struct ctdb_statistics *stats;
+};
+
+struct ctdb_key_data {
+	uint32_t db_id;
+	struct ctdb_ltdb_header header;
+	TDB_DATA key;
+};
+
+struct ctdb_uint8_array {
+	int num;
+	uint8_t *val;
+};
+
+struct ctdb_uint64_array {
+	int num;
+	uint64_t *val;
+};
+
+struct ctdb_db_statistics {
+	struct {
+		uint32_t num_calls;
+		uint32_t num_current;
+		uint32_t num_pending;
+		uint32_t num_failed;
+		struct ctdb_latency_counter latency;
+		uint32_t buckets[MAX_COUNT_BUCKETS];
+	} locks;
+	struct {
+		struct ctdb_latency_counter latency;
+	} vacuum;
+	uint32_t db_ro_delegations;
+	uint32_t db_ro_revokes;
+	uint32_t hop_count_bucket[MAX_COUNT_BUCKETS];
+	uint32_t num_hot_keys;
+	struct {
+		uint32_t count;
+		TDB_DATA key;
+	} hot_keys[MAX_HOT_KEYS];
+};
+
+enum ctdb_runstate {
+	CTDB_RUNSTATE_UNKNOWN,
+	CTDB_RUNSTATE_INIT,
+	CTDB_RUNSTATE_SETUP,
+	CTDB_RUNSTATE_FIRST_RECOVERY,
+	CTDB_RUNSTATE_STARTUP,
+	CTDB_RUNSTATE_RUNNING,
+	CTDB_RUNSTATE_SHUTDOWN,
+};
+
+struct ctdb_req_control_data {
+	uint32_t opcode;
+	union {
+		pid_t pid;
+		uint32_t db_id;
+		struct ctdb_vnn_map *vnnmap;
+		uint32_t loglevel;
+		struct ctdb_pulldb *pulldb;
+		struct ctdb_rec_buffer *recbuf;
+		uint32_t recmode;
+		const char *db_name;
+		struct ctdb_traverse_start *traverse_start;
+		struct ctdb_traverse_all *traverse_all;
+		struct ctdb_rec_data *rec_data;
+		uint32_t recmaster;
+		struct ctdb_connection *conn;
+		struct ctdb_tunable *tunable;
+		const char *tun_var;
+		struct ctdb_node_flag_change *flag_change;
+		ctdb_sock_addr *addr;
+		struct ctdb_tickle_list *tickles;
+		struct ctdb_client_id *cid;
+		struct ctdb_addr_info *addr_info;
+		uint32_t tid;
+		struct ctdb_transdb *transdb;
+		const char *event_str;
+		struct ctdb_public_ip *pubip;
+		enum ctdb_event event;
+		double reclock_latency;
+		const char *reclock_file;
+		uint32_t role;
+		const char *script;
+		struct ctdb_ban_state *ban_state;
+		struct ctdb_db_priority *db_prio;
+		struct ctdb_notify_data *notify;
+		uint64_t srvid;
+		struct ctdb_iface *iface;
+		struct ctdb_key_data *key;
+		struct ctdb_uint64_array *u64_array;
+		struct ctdb_traverse_start_ext *traverse_start_ext;
+		struct ctdb_traverse_all_ext *traverse_all_ext;
+	} data;
+};
+
+struct ctdb_reply_control_data {
+	uint32_t opcode;
+	union {
+		struct ctdb_statistics *stats;
+		const char *db_path;
+		struct ctdb_vnn_map *vnnmap;
+		uint32_t loglevel;
+		struct ctdb_dbid_map *dbmap;
+		struct ctdb_rec_buffer *recbuf;
+		uint32_t db_id;
+		const char *db_name;
+		const char *mem_str;
+		uint32_t tun_value;
+		struct ctdb_var_list *tun_var_list;
+		struct ctdb_tunable_list *tun_list;
+		struct ctdb_tickle_list *tickles;
+		struct ctdb_client_id_map *cid_map;
+		struct ctdb_uptime *uptime;
+		uint32_t caps;
+		struct ctdb_public_ip_list *pubip_list;
+		struct ctdb_node_map *nodemap;
+		struct ctdb_script_list *script_list;
+		const char *reclock_file;
+		struct ctdb_ban_state *ban_state;
+		uint64_t seqnum;
+		const char *reason;
+		struct ctdb_public_ip_info *ipinfo;
+		struct ctdb_iface_list *iface_list;
+		struct ctdb_statistics_list *stats_list;
+		struct ctdb_uint8_array *u8_array;
+		struct ctdb_db_statistics *dbstats;
+		enum ctdb_runstate runstate;
+	} data;
+};
+
+struct ctdb_req_control {
+	uint32_t opcode;
+	uint32_t pad;
+	uint64_t srvid;
+	uint32_t client_id;
+#define CTDB_CTRL_FLAG_NOREPLY   1
+#define CTDB_CTRL_FLAG_OPCODE_SPECIFIC   0xFFFF0000
+	uint32_t flags;
+	struct ctdb_req_control_data rdata;
+};
+
+struct ctdb_reply_control {
+	int32_t status;
+	const char *errmsg;
+	struct ctdb_reply_control_data rdata;
+};
+
+struct ctdb_election_message {
+	uint32_t num_connected;
+	struct timeval priority_time;
+	uint32_t pnn;
+	uint32_t node_flags;
+};
+
+struct ctdb_srvid_message {
+	uint32_t pnn;
+	uint64_t srvid;
+};
+
+struct ctdb_disable_message {
+	uint32_t pnn;
+	uint64_t srvid;
+	uint32_t timeout;
+};
+
+union ctdb_message_data {
+	/* SRVID_ELECTION */
+	struct ctdb_election_message *election;
+	/* SRVID_RELEASE_IP, SRVID_TAKE_IP */
+	const char *ipaddr;
+	/* SRVID_SET_NODE_FLAGS, SERVID_PUSH_NODE_FLAGS */
+	struct ctdb_node_flag_change *flag_change;
+	/* SRVID_RECD_UPDATE_IP */
+	struct ctdb_public_ip *pubip;
+	/* SRVID_VACUUM_FETCH */
+	struct ctdb_rec_buffer *recbuf;
+	/* SRVID_DETACH_DATABASE */
+	uint32_t db_id;
+	/* SRVID_MEM_DUMP, SRVID_TAKEOVER_RUN */
+	struct ctdb_srvid_message *msg;
+	/* SRVID_REBALANCE_NODE */
+	uint32_t pnn;
+	/* SRVID_DISABLE_TAKEOVER_RUNS, SRVID_DISABLE_RECOVERIES */
+	struct ctdb_disable_message *disable;
+	/* SRVID_DISABLE_IP_CHECK */
+	uint32_t timeout;
+	/* Other */
+	TDB_DATA data;
+};
+
+struct ctdb_req_message {
+	uint64_t srvid;
+	union ctdb_message_data data;
+};
+
+struct ctdb_req_message_data {
+	uint64_t srvid;
+	TDB_DATA data;
+};
+
+/* This is equivalent to server_id */
+struct ctdb_server_id {
+	uint64_t pid;
+	uint32_t task_id;
+	uint32_t vnn;
+	uint64_t unique_id;
+};
+
+enum ctdb_g_lock_type {
+	CTDB_G_LOCK_READ = 0,
+	CTDB_G_LOCK_WRITE = 1,
+};
+
+struct ctdb_g_lock {
+	enum ctdb_g_lock_type type;
+	struct ctdb_server_id sid;
+};
+
+struct ctdb_g_lock_list {
+	unsigned int num;
+	struct ctdb_g_lock *lock;
+};
+
+#endif /* __CTDB_PROTOCOL_H__ */
diff --git a/ctdb/protocol/protocol_api.h b/ctdb/protocol/protocol_api.h
new file mode 100644
index 0000000..6fb9cec
--- /dev/null
+++ b/ctdb/protocol/protocol_api.h
@@ -0,0 +1,669 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_PROTOCOL_API_H__
+#define __CTDB_PROTOCOL_API_H__
+
+#include <talloc.h>
+
+#include "protocol/protocol.h"
+
+/* From protocol/protocol_types.c */
+
+size_t ctdb_ltdb_header_len(struct ctdb_ltdb_header *header);
+void ctdb_ltdb_header_push(struct ctdb_ltdb_header *header, uint8_t *buf);
+int ctdb_ltdb_header_pull(uint8_t *buf, size_t buflen,
+			  struct ctdb_ltdb_header *header);
+
+int ctdb_ltdb_header_extract(TDB_DATA *data, struct ctdb_ltdb_header *header);
+
+size_t ctdb_rec_data_len(struct ctdb_rec_data *rec);
+void ctdb_rec_data_push(struct ctdb_rec_data *rec, uint8_t *buf);
+int ctdb_rec_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_rec_data **out);
+
+size_t ctdb_rec_buffer_len(struct ctdb_rec_buffer *recbuf);
+void ctdb_rec_buffer_push(struct ctdb_rec_buffer *recbuf, uint8_t *buf);
+int ctdb_rec_buffer_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		      struct ctdb_rec_buffer **out);
+
+struct ctdb_rec_buffer *ctdb_rec_buffer_init(TALLOC_CTX *mem_ctx,
+					     uint32_t db_id);
+int ctdb_rec_buffer_add(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *recbuf,
+			uint32_t reqid, struct ctdb_ltdb_header *header,
+			TDB_DATA key, TDB_DATA data);
+int ctdb_rec_buffer_traverse(struct ctdb_rec_buffer *recbuf,
+			     ctdb_rec_parser_func_t func,
+			     void *private_data);
+
+size_t ctdb_server_id_len(struct ctdb_server_id *sid);
+void ctdb_server_id_push(struct ctdb_server_id *sid, uint8_t *buf);
+int ctdb_server_id_pull(uint8_t *buf, size_t buflen,
+			 struct ctdb_server_id *sid);
+
+size_t ctdb_g_lock_len(struct ctdb_g_lock *lock);
+void ctdb_g_lock_push(struct ctdb_g_lock *lock, uint8_t *buf);
+int ctdb_g_lock_pull(uint8_t *buf, size_t buflen, struct ctdb_g_lock *lock);
+
+size_t ctdb_g_lock_list_len(struct ctdb_g_lock_list *lock_list);
+void ctdb_g_lock_list_push(struct ctdb_g_lock_list *lock_list, uint8_t *buf);
+int ctdb_g_lock_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_g_lock_list **out);
+
+/* From protocol/protocol_header.c */
+
+void ctdb_req_header_fill(struct ctdb_req_header *h, uint32_t generation,
+			  uint32_t operation, uint32_t destnode,
+			  uint32_t srcnode, uint32_t reqid);
+
+int ctdb_req_header_pull(uint8_t *pkt, size_t pkt_len,
+			 struct ctdb_req_header *h);
+
+int ctdb_req_header_verify(struct ctdb_req_header *h, uint32_t operation);
+
+/* From protocol/protocol_call.c */
+
+int ctdb_req_call_push(struct ctdb_req_header *h,
+		       struct ctdb_req_call *c,
+		       TALLOC_CTX *mem_ctx,
+		       uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_call_pull(uint8_t *pkt, size_t pkt_len,
+		       struct ctdb_req_header *h,
+		       TALLOC_CTX *mem_ctx,
+		       struct ctdb_req_call *c);
+
+int ctdb_reply_call_push(struct ctdb_req_header *h,
+			 struct ctdb_reply_call *c,
+			 TALLOC_CTX *mem_ctx,
+			 uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_reply_call_pull(uint8_t *pkt, size_t pkt_len,
+			 struct ctdb_req_header *h,
+			 TALLOC_CTX *mem_ctx,
+			 struct ctdb_reply_call *c);
+
+int ctdb_reply_error_push(struct ctdb_req_header *h,
+			  struct ctdb_reply_error *c,
+			  TALLOC_CTX *mem_ctx,
+			  uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_reply_error_pull(uint8_t *pkt, size_t pkt_len,
+			  struct ctdb_req_header *h,
+			  TALLOC_CTX *mem_ctx,
+			  struct ctdb_reply_error *c);
+
+int ctdb_req_dmaster_push(struct ctdb_req_header *h,
+			  struct ctdb_req_dmaster *c,
+			  TALLOC_CTX *mem_ctx,
+			  uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_dmaster_pull(uint8_t *pkt, size_t pkt_len,
+			  struct ctdb_req_header *h,
+			  TALLOC_CTX *mem_ctx,
+			  struct ctdb_req_dmaster *c);
+
+int ctdb_reply_dmaster_push(struct ctdb_req_header *h,
+			    struct ctdb_reply_dmaster *c,
+			    TALLOC_CTX *mem_ctx,
+			    uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_reply_dmaster_pull(uint8_t *pkt, size_t pkt_len,
+			    struct ctdb_req_header *h,
+			    TALLOC_CTX *mem_ctx,
+			    struct ctdb_reply_dmaster *c);
+
+/* From protocol/protocol_control.c */
+
+int ctdb_req_control_push(struct ctdb_req_header *h,
+			  struct ctdb_req_control *c,
+			  TALLOC_CTX *mem_ctx,
+			  uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_control_pull(uint8_t *pkt, size_t pkt_len,
+			  struct ctdb_req_header *h,
+			  TALLOC_CTX *mem_ctx,
+			  struct ctdb_req_control *c);
+
+int ctdb_reply_control_push(struct ctdb_req_header *h,
+			    struct ctdb_reply_control *c,
+			    TALLOC_CTX *mem_ctx,
+			    uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_reply_control_pull(uint8_t *pkt, size_t pkt_len, uint32_t opcode,
+			    struct ctdb_req_header *h,
+			    TALLOC_CTX *mem_ctx,
+			    struct ctdb_reply_control *c);
+
+/* From protocol/protocol_client.c */
+
+void ctdb_req_control_process_exists(struct ctdb_req_control *request,
+				     pid_t pid);
+int ctdb_reply_control_process_exists(struct ctdb_reply_control *reply,
+				      int *status);
+
+void ctdb_req_control_statistics(struct ctdb_req_control *request);
+
+int ctdb_reply_control_statistics(struct ctdb_reply_control *reply,
+				  TALLOC_CTX *mem_ctx,
+				  struct ctdb_statistics **stats);
+
+void ctdb_req_control_ping(struct ctdb_req_control *request);
+int ctdb_reply_control_ping(struct ctdb_reply_control *reply,
+			    int *num_clients);
+
+void ctdb_req_control_getdbpath(struct ctdb_req_control *request,
+				uint32_t db_id);
+int ctdb_reply_control_getdbpath(struct ctdb_reply_control *reply,
+				 TALLOC_CTX *mem_ctx, const char **db_path);
+
+void ctdb_req_control_getvnnmap(struct ctdb_req_control *request);
+int ctdb_reply_control_getvnnmap(struct ctdb_reply_control *reply,
+				 TALLOC_CTX *mem_ctx,
+				 struct ctdb_vnn_map **vnnmap);
+
+void ctdb_req_control_setvnnmap(struct ctdb_req_control *request,
+				struct ctdb_vnn_map *vnnmap);
+int ctdb_reply_control_setvnnmap(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_debug(struct ctdb_req_control *request);
+int ctdb_reply_control_get_debug(struct ctdb_reply_control *reply,
+				 uint32_t *debug_level);
+
+void ctdb_req_control_set_debug(struct ctdb_req_control *request,
+				uint32_t debug_level);
+int ctdb_reply_control_set_debug(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_dbmap(struct ctdb_req_control *request);
+int ctdb_reply_control_get_dbmap(struct ctdb_reply_control *reply,
+				 TALLOC_CTX *mem_ctx,
+				 struct ctdb_dbid_map **dbmap);
+
+void ctdb_req_control_pull_db(struct ctdb_req_control *request,
+			      struct ctdb_pulldb *pulldb);
+int ctdb_reply_control_pull_db(struct ctdb_reply_control *reply,
+			       TALLOC_CTX *mem_ctx,
+			       struct ctdb_rec_buffer **recbuf);
+
+void ctdb_req_control_push_db(struct ctdb_req_control *request,
+			      struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_push_db(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_recmode(struct ctdb_req_control *request);
+int ctdb_reply_control_get_recmode(struct ctdb_reply_control *reply,
+				   int *recmode);
+
+void ctdb_req_control_set_recmode(struct ctdb_req_control *request,
+				  int recmode);
+int ctdb_reply_control_set_recmode(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_statistics_reset(struct ctdb_req_control *request);
+int ctdb_reply_control_statistics_reset(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_db_attach(struct ctdb_req_control *request,
+				const char *db_name, uint32_t tdb_flags);
+int ctdb_reply_control_db_attach(struct ctdb_reply_control *reply,
+				 uint32_t *db_id);
+
+void ctdb_req_control_traverse_start(struct ctdb_req_control *request,
+				     struct ctdb_traverse_start *traverse);
+int ctdb_reply_control_traverse_start(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_register_srvid(struct ctdb_req_control *request,
+				     uint64_t srvid);
+int ctdb_reply_control_register_srvid(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_deregister_srvid(struct ctdb_req_control *request,
+				       uint64_t srvid);
+int ctdb_reply_control_deregister_srvid(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_dbname(struct ctdb_req_control *request,
+				 uint32_t db_id);
+int ctdb_reply_control_get_dbname(struct ctdb_reply_control *reply,
+				  TALLOC_CTX *mem_ctx, const char **db_name);
+
+void ctdb_req_control_enable_seqnum(struct ctdb_req_control *request,
+				    uint32_t db_id);
+int ctdb_reply_control_enable_seqnum(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_update_seqnum(struct ctdb_req_control *request,
+				    uint32_t db_id);
+int ctdb_reply_control_update_seqnum(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_dump_memory(struct ctdb_req_control *request);
+int ctdb_reply_control_dump_memory(struct ctdb_reply_control *reply,
+				   TALLOC_CTX *mem_ctx, const char **mem_str);
+
+void ctdb_req_control_get_pid(struct ctdb_req_control *request);
+int ctdb_reply_control_get_pid(struct ctdb_reply_control *reply,
+			       pid_t *pid);
+
+void ctdb_req_control_get_recmaster(struct ctdb_req_control *request);
+int ctdb_reply_control_get_recmaster(struct ctdb_reply_control *reply,
+				     uint32_t *recmaster);
+
+void ctdb_req_control_set_recmaster(struct ctdb_req_control *request,
+				    int recmaster);
+int ctdb_reply_control_set_recmaster(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_freeze(struct ctdb_req_control *request,
+			     uint32_t priority);
+int ctdb_reply_control_freeze(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_thaw(struct ctdb_req_control *request,
+			   uint32_t priority);
+int ctdb_reply_control_thaw(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_pnn(struct ctdb_req_control *request);
+int ctdb_reply_control_get_pnn(struct ctdb_reply_control *reply,
+			       uint32_t *pnn);
+
+void ctdb_req_control_shutdown(struct ctdb_req_control *request);
+int ctdb_reply_control_shutdown(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_monmode(struct ctdb_req_control *request);
+int ctdb_reply_control_get_monmode(struct ctdb_reply_control *reply,
+				   int *mon_mode);
+
+void ctdb_req_control_tcp_client(struct ctdb_req_control *request,
+				 struct ctdb_connection *conn);
+int ctdb_reply_control_tcp_client(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_tcp_add(struct ctdb_req_control *request,
+			      struct ctdb_connection *conn);
+int ctdb_reply_control_tcp_add(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_tcp_remove(struct ctdb_req_control *request,
+				 struct ctdb_connection *conn);
+int ctdb_reply_control_tcp_remove(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_startup(struct ctdb_req_control *request);
+int ctdb_reply_control_startup(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_tunable(struct ctdb_req_control *request,
+				  struct ctdb_tunable *tunable);
+int ctdb_reply_control_set_tunable(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_tunable(struct ctdb_req_control *request,
+				  const char *name);
+int ctdb_reply_control_get_tunable(struct ctdb_reply_control *reply,
+				   uint32_t *value);
+
+void ctdb_req_control_list_tunables(struct ctdb_req_control *request);
+int ctdb_reply_control_list_tunables(struct ctdb_reply_control *reply,
+				     TALLOC_CTX *mem_ctx,
+				     struct ctdb_var_list **tun_var_list);
+
+void ctdb_req_control_modify_flags(struct ctdb_req_control *request,
+				   struct ctdb_node_flag_change *flag_change);
+int ctdb_reply_control_modify_flags(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_all_tunables(struct ctdb_req_control *request);
+int ctdb_reply_control_get_all_tunables(struct ctdb_reply_control *reply,
+					TALLOC_CTX *mem_ctx,
+					struct ctdb_tunable_list **tun_list);
+
+void ctdb_req_control_kill_tcp(struct ctdb_req_control *request,
+			       struct ctdb_connection *conn);
+int ctdb_reply_control_kill_tcp(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_tcp_tickle_list(struct ctdb_req_control *request,
+					  ctdb_sock_addr *addr);
+int ctdb_reply_control_get_tcp_tickle_list(struct ctdb_reply_control *reply,
+					   TALLOC_CTX *mem_ctx,
+					   struct ctdb_tickle_list **tickles);
+
+void ctdb_req_control_set_tcp_tickle_list(struct ctdb_req_control *request,
+					  struct ctdb_tickle_list *tickles);
+int ctdb_reply_control_set_tcp_tickle_list(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_register_server_id(struct ctdb_req_control *request,
+					 struct ctdb_client_id *sid);
+int ctdb_reply_control_register_server_id(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_unregister_server_id(struct ctdb_req_control *request,
+					   struct ctdb_client_id *sid);
+int ctdb_reply_control_unregister_server_id(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_check_server_id(struct ctdb_req_control *request,
+				      struct ctdb_client_id *sid);
+int ctdb_reply_control_check_server_id(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_server_id_list(struct ctdb_req_control *request);
+int ctdb_reply_control_get_server_id_list(struct ctdb_reply_control *reply,
+					  TALLOC_CTX *mem_ctx,
+					  struct ctdb_client_id_map **cid_map);
+
+void ctdb_req_control_db_attach_persistent(struct ctdb_req_control *request,
+					   const char *name,
+					   uint32_t tdb_flags);
+int ctdb_reply_control_db_attach_persistent(struct ctdb_reply_control *reply,
+					    uint32_t *db_id);
+
+void ctdb_req_control_update_record(struct ctdb_req_control *request,
+				    struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_update_record(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_send_gratuitous_arp(struct ctdb_req_control *request,
+					  struct ctdb_addr_info *addr_info);
+int ctdb_reply_control_send_gratuitous_arp(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_transaction_start(struct ctdb_req_control *request,
+					uint32_t tid);
+int ctdb_reply_control_transaction_start(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_transaction_commit(struct ctdb_req_control *request,
+					 uint32_t tid);
+int ctdb_reply_control_transaction_commit(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_wipe_database(struct ctdb_req_control *request,
+				    struct ctdb_transdb *transdb);
+int ctdb_reply_control_wipe_database(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_uptime(struct ctdb_req_control *request);
+int ctdb_reply_control_uptime(struct ctdb_reply_control *reply,
+			      TALLOC_CTX *mem_ctx,
+			      struct ctdb_uptime **uptime);
+
+void ctdb_req_control_start_recovery(struct ctdb_req_control *request);
+int ctdb_reply_control_start_recovery(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_end_recovery(struct ctdb_req_control *request);
+int ctdb_reply_control_end_recovery(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_reload_nodes_file(struct ctdb_req_control *request);
+int ctdb_reply_control_reload_nodes_file(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_try_delete_records(struct ctdb_req_control *request,
+					 struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_try_delete_records(struct ctdb_reply_control *reply,
+					  TALLOC_CTX *mem_ctx,
+					  struct ctdb_rec_buffer **recbuf);
+
+void ctdb_req_control_enable_monitor(struct ctdb_req_control *request);
+int ctdb_reply_control_enable_monitor(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_disable_monitor(struct ctdb_req_control *request);
+int ctdb_reply_control_disable_monitor(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_add_public_ip(struct ctdb_req_control *request,
+				    struct ctdb_addr_info *addr_info);
+int ctdb_reply_control_add_public_ip(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_del_public_ip(struct ctdb_req_control *request,
+				    struct ctdb_addr_info *addr_info);
+int ctdb_reply_control_del_public_ip(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_run_eventscripts(struct ctdb_req_control *request,
+				       const char *event_str);
+int ctdb_reply_control_run_eventscripts(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_capabilities(struct ctdb_req_control *request);
+int ctdb_reply_control_get_capabilities(struct ctdb_reply_control *reply,
+					uint32_t *caps);
+
+void ctdb_req_control_recd_ping(struct ctdb_req_control *request);
+int ctdb_reply_control_recd_ping(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_release_ip(struct ctdb_req_control *request,
+				 struct ctdb_public_ip *pubip);
+int ctdb_reply_control_release_ip(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_takeover_ip(struct ctdb_req_control *request,
+				  struct ctdb_public_ip *pubip);
+int ctdb_reply_control_takeover_ip(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_public_ips(struct ctdb_req_control *request);
+int ctdb_reply_control_get_public_ips(struct ctdb_reply_control *reply,
+				      TALLOC_CTX *mem_ctx,
+				      struct ctdb_public_ip_list **pubip_list);
+
+void ctdb_req_control_get_nodemap(struct ctdb_req_control *request);
+int ctdb_reply_control_get_nodemap(struct ctdb_reply_control *reply,
+				   TALLOC_CTX *mem_ctx,
+				   struct ctdb_node_map **nodemap);
+
+void ctdb_req_control_get_event_script_status(struct ctdb_req_control *request,
+					      uint32_t event);
+int ctdb_reply_control_get_event_script_status(struct ctdb_reply_control *reply,
+					       TALLOC_CTX *mem_ctx,
+					       struct ctdb_script_list **script_list);
+
+void ctdb_req_control_traverse_kill(struct ctdb_req_control *request,
+				    struct ctdb_traverse_start *traverse);
+int ctdb_reply_control_traverse_kill(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_recd_reclock_latency(struct ctdb_req_control *request,
+					   double reclock_latency);
+int ctdb_reply_control_recd_reclock_latency(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_reclock_file(struct ctdb_req_control *request);
+int ctdb_reply_control_get_reclock_file(struct ctdb_reply_control *reply,
+					TALLOC_CTX *mem_ctx,
+					const char **reclock_file);
+
+void ctdb_req_control_set_reclock_file(struct ctdb_req_control *request,
+				       const char *reclock_file);
+int ctdb_reply_control_set_reclock_file(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_stop_node(struct ctdb_req_control *request);
+int ctdb_reply_control_stop_node(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_continue_node(struct ctdb_req_control *request);
+int ctdb_reply_control_continue_node(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_natgwstate(struct ctdb_req_control *request,
+				     uint32_t natgw_role);
+int ctdb_reply_control_set_natgwstate(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_lmasterrole(struct ctdb_req_control *request,
+				      uint32_t lmaster_role);
+int ctdb_reply_control_set_lmasterrole(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_recmasterrole(struct ctdb_req_control *request,
+					uint32_t recmaster_role);
+int ctdb_reply_control_set_recmasterrole(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_enable_script(struct ctdb_req_control *request,
+				    const char *script);
+int ctdb_reply_control_enable_script(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_disable_script(struct ctdb_req_control *request,
+				     const char *script);
+int ctdb_reply_control_disable_script(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_ban_state(struct ctdb_req_control *request,
+				    struct ctdb_ban_state *ban_state);
+int ctdb_reply_control_set_ban_state(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_ban_state(struct ctdb_req_control *request);
+int ctdb_reply_control_get_ban_state(struct ctdb_reply_control *reply,
+				     TALLOC_CTX *mem_ctx,
+				     struct ctdb_ban_state **ban_state);
+
+void ctdb_req_control_set_db_priority(struct ctdb_req_control *request,
+				      struct ctdb_db_priority *db_prio);
+int ctdb_reply_control_set_db_priority(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_db_priority(struct ctdb_req_control *request,
+				      uint32_t db_id);
+int ctdb_reply_control_get_db_priority(struct ctdb_reply_control *reply,
+				       uint32_t *priority);
+
+void ctdb_req_control_transaction_cancel(struct ctdb_req_control *request,
+					 uint32_t tid);
+int ctdb_reply_control_transaction_cancel(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_register_notify(struct ctdb_req_control *request,
+				      struct ctdb_notify_data *notify);
+int ctdb_reply_control_register_notify(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_deregister_notify(struct ctdb_req_control *request,
+					uint64_t srvid);
+int ctdb_reply_control_deregister_notify(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_trans3_commit(struct ctdb_req_control *request,
+				    struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_trans3_commit(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_db_seqnum(struct ctdb_req_control *request,
+				    uint32_t db_id);
+int ctdb_reply_control_get_db_seqnum(struct ctdb_reply_control *reply,
+				     uint64_t *seqnum);
+
+void ctdb_req_control_db_set_healthy(struct ctdb_req_control *request,
+				     uint32_t db_id);
+int ctdb_reply_control_db_set_healthy(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_db_get_health(struct ctdb_req_control *request,
+				    uint32_t db_id);
+int ctdb_reply_control_db_get_health(struct ctdb_reply_control *reply,
+				     TALLOC_CTX *mem_ctx,
+				     const char **reason);
+
+void ctdb_req_control_get_public_ip_info(struct ctdb_req_control *request,
+					 ctdb_sock_addr *addr);
+int ctdb_reply_control_get_public_ip_info(struct ctdb_reply_control *reply,
+					  TALLOC_CTX *mem_ctx,
+					  struct ctdb_public_ip_info **ipinfo);
+
+void ctdb_req_control_get_ifaces(struct ctdb_req_control *request);
+int ctdb_reply_control_get_ifaces(struct ctdb_reply_control *reply,
+				  TALLOC_CTX *mem_ctx,
+				  struct ctdb_iface_list **iface_list);
+
+void ctdb_req_control_set_iface_link_state(struct ctdb_req_control *request,
+					   struct ctdb_iface *iface);
+int ctdb_reply_control_set_iface_link_state(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_tcp_add_delayed_update(struct ctdb_req_control *request,
+					     struct ctdb_connection *conn);
+int ctdb_reply_control_tcp_add_delayed_update(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_stat_history(struct ctdb_req_control *request);
+int ctdb_reply_control_get_stat_history(struct ctdb_reply_control *reply,
+					TALLOC_CTX *mem_ctx,
+					struct ctdb_statistics_list **stats_list);
+
+void ctdb_req_control_schedule_for_deletion(struct ctdb_req_control *request,
+					    struct ctdb_key_data *key);
+int ctdb_reply_control_schedule_for_deletion(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_db_readonly(struct ctdb_req_control *request,
+				      uint32_t db_id);
+int ctdb_reply_control_set_db_readonly(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_check_srvids(struct ctdb_req_control *request,
+				   struct ctdb_uint64_array *u64_array);
+int ctdb_reply_control_check_srvids(struct ctdb_reply_control *reply,
+				    TALLOC_CTX *mem_ctx,
+				    struct ctdb_uint8_array **u8_array);
+
+void ctdb_req_control_traverse_start_ext(struct ctdb_req_control *request,
+					 struct ctdb_traverse_start_ext *traverse);
+int ctdb_reply_control_traverse_start_ext(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_db_statistics(struct ctdb_req_control *request,
+					uint32_t db_id);
+int ctdb_reply_control_get_db_statistics(struct ctdb_reply_control *reply,
+					 TALLOC_CTX *mem_ctx,
+					 struct ctdb_db_statistics **dbstats);
+
+void ctdb_req_control_set_db_sticky(struct ctdb_req_control *request,
+				    uint32_t db_id);
+int ctdb_reply_control_set_db_sticky(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_reload_public_ips(struct ctdb_req_control *request);
+int ctdb_reply_control_reload_public_ips(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_receive_records(struct ctdb_req_control *request,
+				      struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_receive_records(struct ctdb_reply_control *reply,
+				       TALLOC_CTX *mem_ctx,
+				       struct ctdb_rec_buffer **recbuf);
+
+void ctdb_req_control_ipreallocated(struct ctdb_req_control *request);
+int ctdb_reply_control_ipreallocated(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_runstate(struct ctdb_req_control *request);
+int ctdb_reply_control_get_runstate(struct ctdb_reply_control *reply,
+				    enum ctdb_runstate *runstate);
+
+void ctdb_req_control_db_detach(struct ctdb_req_control *request,
+				uint32_t db_id);
+int ctdb_reply_control_db_detach(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_nodes_file(struct ctdb_req_control *request);
+int ctdb_reply_control_get_nodes_file(struct ctdb_reply_control *reply,
+				      TALLOC_CTX *mem_ctx,
+				      struct ctdb_node_map **nodemap);
+
+void ctdb_req_control_db_freeze(struct ctdb_req_control *request,
+				uint32_t db_id);
+int ctdb_reply_control_db_freeze(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_db_thaw(struct ctdb_req_control *request,
+			      uint32_t db_id);
+int ctdb_reply_control_db_thaw(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_db_transaction_start(struct ctdb_req_control *request,
+					   struct ctdb_transdb *transdb);
+int ctdb_reply_control_db_transaction_start(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_db_transaction_commit(struct ctdb_req_control *request,
+					    struct ctdb_transdb *transdb);
+int ctdb_reply_control_db_transaction_commit(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_db_transaction_cancel(struct ctdb_req_control *request,
+					    uint32_t db_id);
+int ctdb_reply_control_db_transaction_cancel(struct ctdb_reply_control *reply);
+
+/* From protocol/protocol_message.c */
+
+int ctdb_req_message_push(struct ctdb_req_header *h,
+			  struct ctdb_req_message *c,
+			  TALLOC_CTX *mem_ctx,
+			  uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_message_pull(uint8_t *pkt, size_t pkt_len,
+			  struct ctdb_req_header *h,
+			  TALLOC_CTX *mem_ctx,
+			  struct ctdb_req_message *c);
+
+int ctdb_req_message_data_push(struct ctdb_req_header *h,
+			       struct ctdb_req_message_data *message,
+			       TALLOC_CTX *mem_ctx,
+			       uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_message_data_pull(uint8_t *pkt, size_t pkt_len,
+			       struct ctdb_req_header *h,
+			       TALLOC_CTX *mem_ctx,
+			       struct ctdb_req_message_data *message);
+
+/* From protocol/protocol_util.c */
+
+const char *ctdb_runstate_to_string(enum ctdb_runstate runstate);
+enum ctdb_runstate ctdb_runstate_from_string(const char *runstate_str);
+
+const char *ctdb_event_to_string(enum ctdb_event event);
+enum ctdb_event ctdb_event_from_string(const char *event_str);
+
+const char *ctdb_sock_addr_to_string(TALLOC_CTX *mem_ctx, ctdb_sock_addr *addr);
+
+#endif /* __CTDB_PROTOCOL_API_H__ */
diff --git a/ctdb/protocol/protocol_call.c b/ctdb/protocol/protocol_call.c
new file mode 100644
index 0000000..e0f38d9
--- /dev/null
+++ b/ctdb/protocol/protocol_call.c
@@ -0,0 +1,446 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+#include "protocol_private.h"
+
+struct ctdb_req_call_wire {
+	struct ctdb_req_header hdr;
+	uint32_t flags;
+	uint32_t db_id;
+	uint32_t callid;
+	uint32_t hopcount;
+	uint32_t keylen;
+	uint32_t calldatalen;
+	uint8_t data[1]; /* key[] followed by calldata[] */
+};
+
+struct ctdb_reply_call_wire {
+	struct ctdb_req_header hdr;
+	uint32_t status;
+	uint32_t datalen;
+	uint8_t  data[1];
+};
+
+struct ctdb_reply_error_wire {
+	struct ctdb_req_header hdr;
+	uint32_t status;
+	uint32_t msglen;
+	uint8_t  msg[1];
+};
+
+struct ctdb_req_dmaster_wire {
+	struct ctdb_req_header hdr;
+	uint32_t db_id;
+	uint64_t rsn;
+	uint32_t dmaster;
+	uint32_t keylen;
+	uint32_t datalen;
+	uint8_t  data[1];
+};
+
+struct ctdb_reply_dmaster_wire {
+	struct ctdb_req_header hdr;
+	uint32_t db_id;
+	uint64_t rsn;
+	uint32_t keylen;
+	uint32_t datalen;
+	uint8_t  data[1];
+};
+
+int ctdb_req_call_push(struct ctdb_req_header *h, struct ctdb_req_call *c,
+		       TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+	struct ctdb_req_call_wire *wire;
+	uint8_t *buf;
+	size_t length, buflen;
+	int ret;
+
+	if (c->key.dsize == 0) {
+		return EINVAL;
+	}
+
+	length = offsetof(struct ctdb_req_call_wire, data) +
+		 c->key.dsize + c->calldata.dsize;
+
+	ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	wire = (struct ctdb_req_call_wire *)buf;
+
+	h->length = buflen;
+	memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+	wire->flags = c->flags;
+	wire->db_id = c->db_id;
+	wire->callid = c->callid;
+	wire->hopcount = c->hopcount;
+	wire->keylen = c->key.dsize;
+	wire->calldatalen = c->calldata.dsize;
+	memcpy(wire->data, c->key.dptr, c->key.dsize);
+	if (c->calldata.dsize > 0) {
+		memcpy(wire->data + c->key.dsize, c->calldata.dptr,
+		       c->calldata.dsize);
+	}
+
+	*pkt = buf;
+	*pkt_len = buflen;
+	return 0;
+}
+
+int ctdb_req_call_pull(uint8_t *pkt, size_t pkt_len,
+		       struct ctdb_req_header *h,
+		       TALLOC_CTX *mem_ctx,
+		       struct ctdb_req_call *c)
+{
+	struct ctdb_req_call_wire *wire;
+	size_t length;
+
+	length = offsetof(struct ctdb_req_call_wire, data);
+	if (pkt_len < length) {
+		return EMSGSIZE;
+	}
+
+	wire = (struct ctdb_req_call_wire *)pkt;
+
+	if (pkt_len < length + wire->keylen + wire->calldatalen) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+	c->flags = wire->flags;
+	c->db_id = wire->db_id;
+	c->callid = wire->callid;
+	c->hopcount = wire->hopcount;
+	c->key.dsize = wire->keylen;
+	c->key.dptr = talloc_memdup(mem_ctx, wire->data, wire->keylen);
+	if (c->key.dptr == NULL) {
+		return ENOMEM;
+	}
+	c->calldata.dsize = wire->calldatalen;
+	if (wire->calldatalen > 0) {
+		c->calldata.dptr = talloc_memdup(mem_ctx,
+						 wire->data + wire->keylen,
+						 wire->calldatalen);
+		if (c->calldata.dptr == NULL) {
+			talloc_free(c->key.dptr);
+			return ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int ctdb_reply_call_push(struct ctdb_req_header *h, struct ctdb_reply_call *c,
+			 TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+	struct ctdb_reply_call_wire *wire;
+	uint8_t *buf;
+	size_t length, buflen;
+	int ret;
+
+	length = offsetof(struct ctdb_reply_call_wire, data) + c->data.dsize;
+
+	ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	wire = (struct ctdb_reply_call_wire *)buf;
+
+	h->length = buflen;
+	memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+	wire->status = c->status;
+	wire->datalen = c->data.dsize;
+	if (c->data.dsize > 0) {
+		memcpy(wire->data, c->data.dptr, c->data.dsize);
+	}
+
+	*pkt = buf;
+	*pkt_len = buflen;
+	return 0;
+}
+
+int ctdb_reply_call_pull(uint8_t *pkt, size_t pkt_len,
+			 struct ctdb_req_header *h,
+			 TALLOC_CTX *mem_ctx,
+			 struct ctdb_reply_call *c)
+{
+	struct ctdb_reply_call_wire *wire;
+	size_t length;
+
+	length = offsetof(struct ctdb_reply_call_wire, data);
+	if (pkt_len < length) {
+		return EMSGSIZE;
+	}
+
+	wire = (struct ctdb_reply_call_wire *)pkt;
+
+	if (pkt_len < length + wire->datalen) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+	c->status = wire->status;
+	c->data.dsize = wire->datalen;
+	if (wire->datalen > 0) {
+		c->data.dptr = talloc_memdup(mem_ctx, wire->data,
+					     wire->datalen);
+		if (c->data.dptr == NULL) {
+			return ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int ctdb_reply_error_push(struct ctdb_req_header *h, struct ctdb_reply_error *c,
+			  TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+	struct ctdb_reply_error_wire *wire;
+	uint8_t *buf;
+	size_t length, buflen;
+	int ret;
+
+	length = offsetof(struct ctdb_reply_error_wire, msg) + c->msg.dsize;
+
+	ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	wire = (struct ctdb_reply_error_wire *)buf;
+
+	h->length = buflen;
+	memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+	wire->status = c->status;
+	wire->msglen = c->msg.dsize;
+	if (c->msg.dsize > 0) {
+		memcpy(wire->msg, c->msg.dptr, c->msg.dsize);
+	}
+
+	*pkt = buf;
+	*pkt_len = buflen;
+	return 0;
+}
+
+int ctdb_reply_error_pull(uint8_t *pkt, size_t pkt_len,
+			  struct ctdb_req_header *h,
+			  TALLOC_CTX *mem_ctx,
+			  struct ctdb_reply_error *c)
+{
+	struct ctdb_reply_error_wire *wire;
+	size_t length;
+
+	length = offsetof(struct ctdb_reply_error_wire, msg);
+	if (pkt_len < length) {
+		return EMSGSIZE;
+	}
+
+	wire = (struct ctdb_reply_error_wire *)pkt;
+
+	if (pkt_len < length + wire->msglen) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+	c->status = wire->status;
+	c->msg.dsize = wire->msglen;
+	if (wire->msglen > 0) {
+		c->msg.dptr = talloc_memdup(mem_ctx, wire->msg, wire->msglen);
+		if (c->msg.dptr == NULL) {
+			return ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int ctdb_req_dmaster_push(struct ctdb_req_header *h, struct ctdb_req_dmaster *c,
+			  TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+	struct ctdb_req_dmaster_wire *wire;
+	uint8_t *buf;
+	size_t length, buflen;
+	int ret;
+
+	length = offsetof(struct ctdb_req_dmaster_wire, data) +
+		 c->key.dsize + c->data.dsize;
+
+	ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	wire = (struct ctdb_req_dmaster_wire *)buf;
+
+	h->length = buflen;
+	memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+	wire->db_id = c->db_id;
+	wire->rsn = c->rsn;
+	wire->dmaster = c->dmaster;
+	wire->keylen = c->key.dsize;
+	if (c->key.dsize > 0) {
+		memcpy(wire->data, c->key.dptr, c->key.dsize);
+	}
+	wire->datalen = c->data.dsize;
+	if (c->data.dsize > 0) {
+		memcpy(wire->data + c->key.dsize, c->data.dptr, c->data.dsize);
+	}
+
+	*pkt = buf;
+	*pkt_len = buflen;
+	return 0;
+}
+
+int ctdb_req_dmaster_pull(uint8_t *pkt, size_t pkt_len,
+			  struct ctdb_req_header *h,
+			  TALLOC_CTX *mem_ctx,
+			  struct ctdb_req_dmaster *c)
+{
+	struct ctdb_req_dmaster_wire *wire;
+	size_t length;
+
+	length = offsetof(struct ctdb_req_dmaster_wire, data);
+	if (pkt_len < length) {
+		return EMSGSIZE;
+	}
+
+	wire = (struct ctdb_req_dmaster_wire *)pkt;
+
+	if (pkt_len < length + wire->keylen + wire->datalen) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+	c->db_id = wire->db_id;
+	c->rsn = wire->rsn;
+	c->dmaster = wire->dmaster;
+	c->key.dsize = wire->keylen;
+	c->key.dptr = talloc_memdup(mem_ctx, wire->data, wire->keylen);
+	if (c->key.dptr == NULL) {
+		return ENOMEM;
+	}
+	c->data.dsize = wire->datalen;
+	if (wire->datalen > 0) {
+		c->data.dptr = talloc_memdup(mem_ctx, wire->data + wire->keylen,
+					     wire->datalen);
+		if (c->data.dptr == NULL) {
+			talloc_free(c->key.dptr);
+			return ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int ctdb_reply_dmaster_push(struct ctdb_req_header *h,
+			    struct ctdb_reply_dmaster *c,
+			    TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+	struct ctdb_reply_dmaster_wire *wire;
+	uint8_t *buf;
+	size_t length, buflen;
+	int ret;
+
+	length = offsetof(struct ctdb_reply_dmaster_wire, data) +
+		 c->key.dsize + c->data.dsize;
+
+	ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	wire = (struct ctdb_reply_dmaster_wire *)buf;
+
+	h->length = buflen;
+	memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+	wire->db_id = c->db_id;
+	wire->rsn = c->rsn;
+	wire->keylen = c->key.dsize;
+	if (c->key.dsize > 0) {
+		memcpy(wire->data, c->key.dptr, c->key.dsize);
+	}
+	wire->datalen = c->data.dsize;
+	if (c->data.dsize > 0) {
+		memcpy(wire->data + c->key.dsize, c->data.dptr, c->data.dsize);
+	}
+
+	*pkt = buf;
+	*pkt_len = buflen;
+	return 0;
+}
+
+int ctdb_reply_dmaster_pull(uint8_t *pkt, size_t pkt_len,
+			    struct ctdb_req_header *h,
+			    TALLOC_CTX *mem_ctx,
+			    struct ctdb_reply_dmaster *c)
+{
+	struct ctdb_reply_dmaster_wire *wire;
+	size_t length;
+
+	length = offsetof(struct ctdb_reply_dmaster_wire, data);
+	if (pkt_len < length) {
+		return EMSGSIZE;
+	}
+
+	wire = (struct ctdb_reply_dmaster_wire *)pkt;
+
+	if (pkt_len < length + wire->keylen + wire->datalen) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+	c->db_id = wire->db_id;
+	c->rsn = wire->rsn;
+	c->key.dsize = wire->keylen;
+	c->key.dptr = talloc_memdup(mem_ctx, wire->data, wire->keylen);
+	if (c->key.dptr == NULL) {
+		return ENOMEM;
+	}
+	c->data.dsize = wire->datalen;
+	if (wire->datalen > 0) {
+		c->data.dptr = talloc_memdup(mem_ctx, wire->data + wire->keylen,
+					     wire->datalen);
+		if (c->data.dptr == NULL) {
+			talloc_free(c->key.dptr);
+			return ENOMEM;
+		}
+	}
+
+	return 0;
+}
diff --git a/ctdb/protocol/protocol_client.c b/ctdb/protocol/protocol_client.c
new file mode 100644
index 0000000..a4c19d9
--- /dev/null
+++ b/ctdb/protocol/protocol_client.c
@@ -0,0 +1,2470 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+#include "protocol_private.h"
+
+/*
+void ctdb_req_call_fill(struct ctdb_req_call *c,
+			uint32_t db_id, uint32_t flags,
+			uint32_t call_id, TDB_DATA key)
+{
+	request->flags = flags;
+	c->db_id = db_id;
+	c->call_id = call_id;
+	c->key = key;
+	c->calldata = tdb_null;
+}
+*/
+
+static int ctdb_reply_control_generic(struct ctdb_reply_control *reply)
+{
+	return reply->status;
+}
+
+/* CTDB_CONTROL_PROCESS_EXISTS */
+
+void ctdb_req_control_process_exists(struct ctdb_req_control *request,
+				     pid_t pid)
+{
+	request->opcode = CTDB_CONTROL_PROCESS_EXISTS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_PROCESS_EXISTS;
+	request->rdata.data.pid = pid;
+
+}
+
+int ctdb_reply_control_process_exists(struct ctdb_reply_control *reply,
+				      int *status)
+{
+	if (reply->rdata.opcode == CTDB_CONTROL_PROCESS_EXISTS) {
+		*status = reply->status;
+		reply->status = 0;
+
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_STATISTICS */
+
+void ctdb_req_control_statistics(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_STATISTICS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_STATISTICS;
+}
+
+int ctdb_reply_control_statistics(struct ctdb_reply_control *reply,
+				  TALLOC_CTX *mem_ctx,
+				  struct ctdb_statistics **stats)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_STATISTICS) {
+		*stats = talloc_steal(mem_ctx, reply->rdata.data.stats);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_PING */
+
+void ctdb_req_control_ping(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_PING;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_PING;
+}
+
+int ctdb_reply_control_ping(struct ctdb_reply_control *reply,
+			    int *num_clients)
+{
+	if (reply->status >= 0) {
+		*num_clients = reply->status;
+		reply->status = 0;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_GETDBPATH */
+
+void ctdb_req_control_getdbpath(struct ctdb_req_control *request,
+				uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_GETDBPATH;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GETDBPATH;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_getdbpath(struct ctdb_reply_control *reply,
+				 TALLOC_CTX *mem_ctx, const char **db_path)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GETDBPATH) {
+		*db_path = talloc_steal(mem_ctx, reply->rdata.data.db_path);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_GETVNNMAP */
+
+void ctdb_req_control_getvnnmap(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GETVNNMAP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GETVNNMAP;
+}
+
+int ctdb_reply_control_getvnnmap(struct ctdb_reply_control *reply,
+				 TALLOC_CTX *mem_ctx,
+				 struct ctdb_vnn_map **vnnmap)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GETVNNMAP) {
+		*vnnmap = talloc_steal(mem_ctx, reply->rdata.data.vnnmap);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SETVNNMAP */
+
+void ctdb_req_control_setvnnmap(struct ctdb_req_control *request,
+				struct ctdb_vnn_map *vnnmap)
+{
+	request->opcode = CTDB_CONTROL_SETVNNMAP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SETVNNMAP;
+	request->rdata.data.vnnmap = vnnmap;
+}
+
+int ctdb_reply_control_setvnnmap(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DEBUG */
+
+void ctdb_req_control_get_debug(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_DEBUG;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_DEBUG;
+}
+
+int ctdb_reply_control_get_debug(struct ctdb_reply_control *reply,
+				 uint32_t *loglevel)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_DEBUG) {
+		*loglevel = reply->rdata.data.loglevel;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SET_DEBUG */
+
+void ctdb_req_control_set_debug(struct ctdb_req_control *request,
+				uint32_t loglevel)
+{
+	request->opcode = CTDB_CONTROL_SET_DEBUG;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_DEBUG;
+	request->rdata.data.loglevel = loglevel;
+}
+
+int ctdb_reply_control_set_debug(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DBMAP */
+
+void ctdb_req_control_get_dbmap(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_DBMAP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_DBMAP;
+}
+
+int ctdb_reply_control_get_dbmap(struct ctdb_reply_control *reply,
+				 TALLOC_CTX *mem_ctx,
+				 struct ctdb_dbid_map **dbmap)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_DBMAP) {
+		*dbmap = talloc_steal(mem_ctx, reply->rdata.data.dbmap);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_PULL_DB */
+
+void ctdb_req_control_pull_db(struct ctdb_req_control *request,
+			      struct ctdb_pulldb *pulldb)
+{
+	request->opcode = CTDB_CONTROL_PULL_DB;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_PULL_DB;
+	request->rdata.data.pulldb = pulldb;
+}
+
+int ctdb_reply_control_pull_db(struct ctdb_reply_control *reply,
+			       TALLOC_CTX *mem_ctx,
+			       struct ctdb_rec_buffer **recbuf)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_PULL_DB) {
+		*recbuf = talloc_steal(mem_ctx, reply->rdata.data.recbuf);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_PUSH_DB */
+
+void ctdb_req_control_push_db(struct ctdb_req_control *request,
+			      struct ctdb_rec_buffer *recbuf)
+{
+	request->opcode = CTDB_CONTROL_PUSH_DB;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_PUSH_DB;
+	request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_push_db(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_RECMODE */
+
+void ctdb_req_control_get_recmode(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_RECMODE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_RECMODE;
+}
+
+int ctdb_reply_control_get_recmode(struct ctdb_reply_control *reply,
+				   int *recmode)
+{
+	if (reply->status >= 0) {
+		*recmode = reply->status;
+		reply->status = 0;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SET_RECMODE */
+
+void ctdb_req_control_set_recmode(struct ctdb_req_control *request,
+				  int recmode)
+{
+	request->opcode = CTDB_CONTROL_SET_RECMODE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_RECMODE;
+	request->rdata.data.recmode = recmode;
+}
+
+int ctdb_reply_control_set_recmode(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_STATISTICS_RESET */
+
+void ctdb_req_control_statistics_reset(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_STATISTICS_RESET;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_STATISTICS_RESET;
+}
+
+int ctdb_reply_control_statistics_reset(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DB_ATTACH */
+
+void ctdb_req_control_db_attach(struct ctdb_req_control *request,
+				const char *db_name, uint32_t tdb_flags)
+{
+	request->opcode = CTDB_CONTROL_DB_ATTACH;
+	request->pad = 0;
+	request->srvid = tdb_flags;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_ATTACH;
+	request->rdata.data.db_name = db_name;
+}
+
+int ctdb_reply_control_db_attach(struct ctdb_reply_control *reply,
+				 uint32_t *db_id)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_DB_ATTACH) {
+		*db_id = reply->rdata.data.db_id;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SET_CALL */
+
+/* CTDB_CONTROL_TRAVERSE_START */
+
+void ctdb_req_control_traverse_start(struct ctdb_req_control *request,
+				     struct ctdb_traverse_start *traverse)
+{
+	request->opcode = CTDB_CONTROL_TRAVERSE_START;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TRAVERSE_START;
+	request->rdata.data.traverse_start = traverse;
+}
+
+int ctdb_reply_control_traverse_start(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRAVERSE_ALL */
+/* CTDB_CONTROL_TRAVERSE_DATA */
+
+/* CTDB_CONTROL_REGISTER_SRVID */
+
+void ctdb_req_control_register_srvid(struct ctdb_req_control *request,
+				     uint64_t srvid)
+{
+	request->opcode = CTDB_CONTROL_REGISTER_SRVID;
+	request->pad = 0;
+	request->srvid = srvid;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_REGISTER_SRVID;
+}
+
+int ctdb_reply_control_register_srvid(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DEREGISTER_SRVID */
+
+void ctdb_req_control_deregister_srvid(struct ctdb_req_control *request,
+				       uint64_t srvid)
+{
+	request->opcode = CTDB_CONTROL_DEREGISTER_SRVID;
+	request->pad = 0;
+	request->srvid = srvid;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DEREGISTER_SRVID;
+}
+
+int ctdb_reply_control_deregister_srvid(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DBNAME */
+
+void ctdb_req_control_get_dbname(struct ctdb_req_control *request,
+				 uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_GET_DBNAME;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_DBNAME;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_get_dbname(struct ctdb_reply_control *reply,
+				  TALLOC_CTX *mem_ctx, const char **db_name)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_DBNAME) {
+		*db_name = talloc_steal(mem_ctx, reply->rdata.data.db_name);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_ENABLE_SEQNUM */
+
+void ctdb_req_control_enable_seqnum(struct ctdb_req_control *request,
+				    uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_ENABLE_SEQNUM;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_ENABLE_SEQNUM;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_enable_seqnum(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_UPDATE_SEQNUM */
+
+void ctdb_req_control_update_seqnum(struct ctdb_req_control *request,
+				    uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_UPDATE_SEQNUM;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_UPDATE_SEQNUM;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_update_seqnum(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DUMP_MEMORY */
+
+void ctdb_req_control_dump_memory(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_DUMP_MEMORY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DUMP_MEMORY;
+}
+
+int ctdb_reply_control_dump_memory(struct ctdb_reply_control *reply,
+				   TALLOC_CTX *mem_ctx, const char **mem_str)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_DUMP_MEMORY) {
+		*mem_str = talloc_steal(mem_ctx, reply->rdata.data.mem_str);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_GET_PID */
+
+void ctdb_req_control_get_pid(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_PID;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_PID;
+}
+
+int ctdb_reply_control_get_pid(struct ctdb_reply_control *reply,
+			       pid_t *pid)
+{
+	if (reply->rdata.opcode == CTDB_CONTROL_GET_PID) {
+		*pid = reply->status;
+		reply->status = 0;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_GET_RECMASTER */
+
+void ctdb_req_control_get_recmaster(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_RECMASTER;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_RECMASTER;
+}
+
+int ctdb_reply_control_get_recmaster(struct ctdb_reply_control *reply,
+				     uint32_t *recmaster)
+{
+	if (reply->rdata.opcode == CTDB_CONTROL_GET_RECMASTER) {
+		*recmaster = reply->status;
+		reply->status = 0;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SET_RECMASTER */
+
+void ctdb_req_control_set_recmaster(struct ctdb_req_control *request,
+				    int recmaster)
+{
+	request->opcode = CTDB_CONTROL_SET_RECMASTER;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_RECMASTER;
+	request->rdata.data.recmaster = recmaster;
+}
+
+int ctdb_reply_control_set_recmaster(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_FREEZE */
+
+void ctdb_req_control_freeze(struct ctdb_req_control *request,
+			     uint32_t priority)
+{
+	request->opcode = CTDB_CONTROL_FREEZE;
+	request->pad = 0;
+	request->srvid = priority;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_FREEZE;
+}
+
+int ctdb_reply_control_freeze(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_THAW */
+
+void ctdb_req_control_thaw(struct ctdb_req_control *request,
+			   uint32_t priority)
+{
+	request->opcode = CTDB_CONTROL_THAW;
+	request->pad = 0;
+	request->srvid = priority;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_THAW;
+}
+
+int ctdb_reply_control_thaw(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_PNN */
+
+void ctdb_req_control_get_pnn(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_PNN;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_PNN;
+}
+
+int ctdb_reply_control_get_pnn(struct ctdb_reply_control *reply,
+			       uint32_t *pnn)
+{
+	if (reply->status >= 0) {
+		*pnn = reply->status;
+		reply->status = 0;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SHUTDOWN */
+
+void ctdb_req_control_shutdown(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_SHUTDOWN;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = CTDB_CTRL_FLAG_NOREPLY;
+
+	request->rdata.opcode = CTDB_CONTROL_SHUTDOWN;
+}
+
+int ctdb_reply_control_shutdown(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_MONMODE */
+
+void ctdb_req_control_get_monmode(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_MONMODE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_MONMODE;
+}
+
+int ctdb_reply_control_get_monmode(struct ctdb_reply_control *reply,
+				   int *mon_mode)
+{
+	if (reply->status >= 0) {
+		*mon_mode = reply->status;
+		reply->status = 0;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_TCP_CLIENT */
+
+void ctdb_req_control_tcp_client(struct ctdb_req_control *request,
+				 struct ctdb_connection *conn)
+{
+	request->opcode = CTDB_CONTROL_TCP_CLIENT;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TCP_CLIENT;
+	request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_tcp_client(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TCP_ADD */
+
+void ctdb_req_control_tcp_add(struct ctdb_req_control *request,
+			      struct ctdb_connection *conn)
+{
+	request->opcode = CTDB_CONTROL_TCP_ADD;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TCP_ADD;
+	request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_tcp_add(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TCP_REMOVE */
+
+void ctdb_req_control_tcp_remove(struct ctdb_req_control *request,
+				 struct ctdb_connection *conn)
+{
+	request->opcode = CTDB_CONTROL_TCP_REMOVE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TCP_REMOVE;
+	request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_tcp_remove(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_STARTUP */
+
+void ctdb_req_control_startup(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_STARTUP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_STARTUP;
+}
+
+int ctdb_reply_control_startup(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_TUNABLE */
+
+void ctdb_req_control_set_tunable(struct ctdb_req_control *request,
+				  struct ctdb_tunable *tunable)
+{
+	request->opcode = CTDB_CONTROL_SET_TUNABLE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_TUNABLE;
+	request->rdata.data.tunable = tunable;
+}
+
+int ctdb_reply_control_set_tunable(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_TUNABLE */
+
+void ctdb_req_control_get_tunable(struct ctdb_req_control *request,
+				  const char *name)
+{
+	request->opcode = CTDB_CONTROL_GET_TUNABLE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_TUNABLE;
+	request->rdata.data.tun_var = discard_const(name);
+}
+
+int ctdb_reply_control_get_tunable(struct ctdb_reply_control *reply,
+				   uint32_t *value)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_TUNABLE) {
+		*value = reply->rdata.data.tun_value;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_LIST_TUNABLES */
+
+void ctdb_req_control_list_tunables(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_LIST_TUNABLES;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_LIST_TUNABLES;
+}
+
+int ctdb_reply_control_list_tunables(struct ctdb_reply_control *reply,
+				     TALLOC_CTX *mem_ctx,
+				     struct ctdb_var_list **tun_var_list)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_LIST_TUNABLES) {
+		*tun_var_list = talloc_steal(mem_ctx,
+					     reply->rdata.data.tun_var_list);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_MODIFY_FLAGS */
+
+void ctdb_req_control_modify_flags(struct ctdb_req_control *request,
+				   struct ctdb_node_flag_change *flag_change)
+{
+	request->opcode = CTDB_CONTROL_MODIFY_FLAGS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_MODIFY_FLAGS;
+	request->rdata.data.flag_change = flag_change;
+}
+
+int ctdb_reply_control_modify_flags(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_ALL_TUNABLES */
+
+void ctdb_req_control_get_all_tunables(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_ALL_TUNABLES;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_ALL_TUNABLES;
+}
+
+int ctdb_reply_control_get_all_tunables(struct ctdb_reply_control *reply,
+					TALLOC_CTX *mem_ctx,
+					struct ctdb_tunable_list **tun_list)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_ALL_TUNABLES) {
+		*tun_list = talloc_steal(mem_ctx, reply->rdata.data.tun_list);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_KILL_TCP */
+
+void ctdb_req_control_kill_tcp(struct ctdb_req_control *request,
+			       struct ctdb_connection *conn)
+{
+	request->opcode = CTDB_CONTROL_KILL_TCP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_KILL_TCP;
+	request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_kill_tcp(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_TCP_TICKLE_LIST */
+
+void ctdb_req_control_get_tcp_tickle_list(struct ctdb_req_control *request,
+					  ctdb_sock_addr *addr)
+{
+	request->opcode = CTDB_CONTROL_GET_TCP_TICKLE_LIST;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_TCP_TICKLE_LIST;
+	request->rdata.data.addr = addr;
+}
+
+int ctdb_reply_control_get_tcp_tickle_list(struct ctdb_reply_control *reply,
+					   TALLOC_CTX *mem_ctx,
+					   struct ctdb_tickle_list **tickles)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_TCP_TICKLE_LIST) {
+		*tickles = talloc_steal(mem_ctx, reply->rdata.data.tickles);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SET_TCP_TICKLE_LIST */
+
+void ctdb_req_control_set_tcp_tickle_list(struct ctdb_req_control *request,
+					  struct ctdb_tickle_list *tickles)
+{
+	request->opcode = CTDB_CONTROL_SET_TCP_TICKLE_LIST;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_TCP_TICKLE_LIST;
+	request->rdata.data.tickles = tickles;
+}
+
+int ctdb_reply_control_set_tcp_tickle_list(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_REGISTER_SERVER_ID */
+
+void ctdb_req_control_register_server_id(struct ctdb_req_control *request,
+					 struct ctdb_client_id *cid)
+{
+	request->opcode = CTDB_CONTROL_REGISTER_SERVER_ID;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_REGISTER_SERVER_ID;
+	request->rdata.data.cid = cid;
+}
+
+int ctdb_reply_control_register_server_id(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_UNREGISTER_SERVER_ID */
+
+void ctdb_req_control_unregister_server_id(struct ctdb_req_control *request,
+					   struct ctdb_client_id *cid)
+{
+	request->opcode = CTDB_CONTROL_UNREGISTER_SERVER_ID;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_UNREGISTER_SERVER_ID;
+	request->rdata.data.cid = cid;
+}
+
+int ctdb_reply_control_unregister_server_id(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_CHECK_SERVER_ID */
+
+void ctdb_req_control_check_server_id(struct ctdb_req_control *request,
+				      struct ctdb_client_id *cid)
+{
+	request->opcode = CTDB_CONTROL_CHECK_SERVER_ID;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_CHECK_SERVER_ID;
+	request->rdata.data.cid = cid;
+}
+
+int ctdb_reply_control_check_server_id(struct ctdb_reply_control *reply)
+{
+	return reply->status;
+}
+
+/* CTDB_CONTROL_GET_SERVER_ID_LIST */
+
+void ctdb_req_control_get_server_id_list(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_SERVER_ID_LIST;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_SERVER_ID_LIST;
+}
+
+int ctdb_reply_control_get_server_id_list(struct ctdb_reply_control *reply,
+					  TALLOC_CTX *mem_ctx,
+					  struct ctdb_client_id_map **cid_map)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_SERVER_ID_LIST) {
+		*cid_map = talloc_steal(mem_ctx, reply->rdata.data.cid_map);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_DB_ATTACH_PERSISTENT */
+
+void ctdb_req_control_db_attach_persistent(struct ctdb_req_control *request,
+					   const char *db_name,
+					   uint32_t tdb_flags)
+{
+	request->opcode = CTDB_CONTROL_DB_ATTACH_PERSISTENT;
+	request->pad = 0;
+	request->srvid = tdb_flags;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_ATTACH_PERSISTENT;
+	request->rdata.data.db_name = db_name;
+}
+
+int ctdb_reply_control_db_attach_persistent(struct ctdb_reply_control *reply,
+					    uint32_t *db_id)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_DB_ATTACH_PERSISTENT) {
+		*db_id = reply->rdata.data.db_id;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_UPDATE_RECORD */
+
+void ctdb_req_control_update_record(struct ctdb_req_control *request,
+				    struct ctdb_rec_buffer *recbuf)
+{
+	request->opcode = CTDB_CONTROL_UPDATE_RECORD;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_UPDATE_RECORD;
+	request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_update_record(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SEND_GRATUITOUS_ARP */
+
+void ctdb_req_control_send_gratuitous_arp(struct ctdb_req_control *request,
+					  struct ctdb_addr_info *addr_info)
+{
+	request->opcode = CTDB_CONTROL_SEND_GRATUITOUS_ARP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SEND_GRATUITOUS_ARP;
+	request->rdata.data.addr_info = addr_info;
+}
+
+int ctdb_reply_control_send_gratuitous_arp(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRANSACTION_START */
+
+void ctdb_req_control_transaction_start(struct ctdb_req_control *request,
+					uint32_t tid)
+{
+	request->opcode = CTDB_CONTROL_TRANSACTION_START;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TRANSACTION_START;
+	request->rdata.data.tid = tid;
+}
+
+int ctdb_reply_control_transaction_start(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRANSACTION_COMMIT */
+
+void ctdb_req_control_transaction_commit(struct ctdb_req_control *request,
+					 uint32_t tid)
+{
+	request->opcode = CTDB_CONTROL_TRANSACTION_COMMIT;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TRANSACTION_COMMIT;
+	request->rdata.data.tid = tid;
+}
+
+int ctdb_reply_control_transaction_commit(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_WIPE_DATABASE */
+
+void ctdb_req_control_wipe_database(struct ctdb_req_control *request,
+				    struct ctdb_transdb *transdb)
+{
+	request->opcode = CTDB_CONTROL_WIPE_DATABASE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_WIPE_DATABASE;
+	request->rdata.data.transdb = transdb;
+}
+
+int ctdb_reply_control_wipe_database(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_UPTIME */
+
+void ctdb_req_control_uptime(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_UPTIME;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_UPTIME;
+}
+
+int ctdb_reply_control_uptime(struct ctdb_reply_control *reply,
+			      TALLOC_CTX *mem_ctx, struct ctdb_uptime **uptime)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_UPTIME) {
+		*uptime = talloc_steal(mem_ctx, reply->rdata.data.uptime);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_START_RECOVERY */
+
+void ctdb_req_control_start_recovery(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_START_RECOVERY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_START_RECOVERY;
+}
+
+int ctdb_reply_control_start_recovery(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_END_RECOVERY */
+
+void ctdb_req_control_end_recovery(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_END_RECOVERY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_END_RECOVERY;
+}
+
+int ctdb_reply_control_end_recovery(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RELOAD_NODES_FILE */
+
+void ctdb_req_control_reload_nodes_file(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_RELOAD_NODES_FILE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_RELOAD_NODES_FILE;
+}
+
+int ctdb_reply_control_reload_nodes_file(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRY_DELETE_RECORDS */
+
+void ctdb_req_control_try_delete_records(struct ctdb_req_control *request,
+					 struct ctdb_rec_buffer *recbuf)
+{
+	request->opcode = CTDB_CONTROL_TRY_DELETE_RECORDS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TRY_DELETE_RECORDS;
+	request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_try_delete_records(struct ctdb_reply_control *reply,
+					  TALLOC_CTX *mem_ctx,
+					  struct ctdb_rec_buffer **recbuf)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_TRY_DELETE_RECORDS) {
+		*recbuf = talloc_steal(mem_ctx, reply->rdata.data.recbuf);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_ENABLE_MONITOR */
+
+void ctdb_req_control_enable_monitor(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_ENABLE_MONITOR;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_ENABLE_MONITOR;
+}
+
+int ctdb_reply_control_enable_monitor(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DISABLE_MONITOR */
+
+void ctdb_req_control_disable_monitor(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_DISABLE_MONITOR;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DISABLE_MONITOR;
+}
+
+int ctdb_reply_control_disable_monitor(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_ADD_PUBLIC_IP */
+
+void ctdb_req_control_add_public_ip(struct ctdb_req_control *request,
+				    struct ctdb_addr_info *addr_info)
+{
+	request->opcode = CTDB_CONTROL_ADD_PUBLIC_IP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_ADD_PUBLIC_IP;
+	request->rdata.data.addr_info = addr_info;
+}
+
+int ctdb_reply_control_add_public_ip(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DEL_PUBLIC_IP */
+
+void ctdb_req_control_del_public_ip(struct ctdb_req_control *request,
+				    struct ctdb_addr_info *addr_info)
+{
+	request->opcode = CTDB_CONTROL_DEL_PUBLIC_IP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DEL_PUBLIC_IP;
+	request->rdata.data.addr_info = addr_info;
+}
+
+int ctdb_reply_control_del_public_ip(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RUN_EVENTSCRIPTS */
+
+void ctdb_req_control_run_eventscripts(struct ctdb_req_control *request,
+				       const char *event_str)
+{
+	request->opcode = CTDB_CONTROL_RUN_EVENTSCRIPTS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_RUN_EVENTSCRIPTS;
+	request->rdata.data.event_str = event_str;
+}
+
+int ctdb_reply_control_run_eventscripts(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_CAPABILITIES */
+
+void ctdb_req_control_get_capabilities(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_CAPABILITIES;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_CAPABILITIES;
+}
+
+int ctdb_reply_control_get_capabilities(struct ctdb_reply_control *reply,
+					uint32_t *caps)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_CAPABILITIES) {
+		*caps = reply->rdata.data.caps;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_RECD_PING */
+
+void ctdb_req_control_recd_ping(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_RECD_PING;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_RECD_PING;
+}
+
+int ctdb_reply_control_recd_ping(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RELEASE_IP */
+
+void ctdb_req_control_release_ip(struct ctdb_req_control *request,
+				 struct ctdb_public_ip *pubip)
+{
+	request->opcode = CTDB_CONTROL_RELEASE_IP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_RELEASE_IP;
+	request->rdata.data.pubip = pubip;
+}
+
+int ctdb_reply_control_release_ip(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TAKEOVER_IP */
+
+void ctdb_req_control_takeover_ip(struct ctdb_req_control *request,
+				  struct ctdb_public_ip *pubip)
+{
+	request->opcode = CTDB_CONTROL_TAKEOVER_IP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TAKEOVER_IP;
+	request->rdata.data.pubip = pubip;
+}
+
+int ctdb_reply_control_takeover_ip(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_PUBLIC_IPS */
+
+void ctdb_req_control_get_public_ips(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_PUBLIC_IPS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_PUBLIC_IPS;
+}
+
+int ctdb_reply_control_get_public_ips(struct ctdb_reply_control *reply,
+				      TALLOC_CTX *mem_ctx,
+				      struct ctdb_public_ip_list **pubip_list)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_PUBLIC_IPS) {
+		*pubip_list = talloc_steal(mem_ctx, reply->rdata.data.pubip_list);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_GET_NODEMAP */
+
+void ctdb_req_control_get_nodemap(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_NODEMAP;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_NODEMAP;
+}
+
+int ctdb_reply_control_get_nodemap(struct ctdb_reply_control *reply,
+				   TALLOC_CTX *mem_ctx,
+				   struct ctdb_node_map **nodemap)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_NODEMAP) {
+		*nodemap = talloc_steal(mem_ctx, reply->rdata.data.nodemap);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS */
+
+void ctdb_req_control_get_event_script_status(struct ctdb_req_control *request,
+					      uint32_t event)
+{
+	request->opcode = CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS;
+	request->rdata.data.event = event;
+}
+
+int ctdb_reply_control_get_event_script_status(struct ctdb_reply_control *reply,
+					       TALLOC_CTX *mem_ctx,
+					       struct ctdb_script_list **slist)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS) {
+		*slist = talloc_steal(mem_ctx, reply->rdata.data.script_list);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_TRAVERSE_KILL */
+
+void ctdb_req_control_traverse_kill(struct ctdb_req_control *request,
+				    struct ctdb_traverse_start *traverse)
+{
+	request->opcode = CTDB_CONTROL_TRAVERSE_KILL;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TRAVERSE_KILL;
+	request->rdata.data.traverse_start = traverse;
+}
+
+int ctdb_reply_control_traverse_kill(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RECD_RECLOCK_LATENCY */
+
+void ctdb_req_control_recd_reclock_latency(struct ctdb_req_control *request,
+					   double reclock_latency)
+{
+	request->opcode = CTDB_CONTROL_RECD_RECLOCK_LATENCY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_RECD_RECLOCK_LATENCY;
+	request->rdata.data.reclock_latency = reclock_latency;
+}
+
+int ctdb_reply_control_recd_reclock_latency(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_RECLOCK_FILE */
+
+void ctdb_req_control_get_reclock_file(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_RECLOCK_FILE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_RECLOCK_FILE;
+}
+
+int ctdb_reply_control_get_reclock_file(struct ctdb_reply_control *reply,
+					TALLOC_CTX *mem_ctx,
+					const char **reclock_file)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_RECLOCK_FILE) {
+		*reclock_file = talloc_steal(mem_ctx,
+					     reply->rdata.data.reclock_file);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SET_RECLOCK_FILE */
+
+void ctdb_req_control_set_reclock_file(struct ctdb_req_control *request,
+				       const char *reclock_file)
+{
+	request->opcode = CTDB_CONTROL_SET_RECLOCK_FILE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_RECLOCK_FILE;
+	request->rdata.data.reclock_file = reclock_file;
+}
+
+int ctdb_reply_control_set_reclock_file(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+
+/* CTDB_CONTROL_STOP_NODE */
+
+void ctdb_req_control_stop_node(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_STOP_NODE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_STOP_NODE;
+}
+
+int ctdb_reply_control_stop_node(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_CONTINUE_NODE */
+
+void ctdb_req_control_continue_node(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_CONTINUE_NODE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_CONTINUE_NODE;
+}
+
+int ctdb_reply_control_continue_node(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_NATGWSTATE */
+
+void ctdb_req_control_set_natgwstate(struct ctdb_req_control *request,
+				     uint32_t natgw_role)
+{
+	request->opcode = CTDB_CONTROL_SET_NATGWSTATE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_NATGWSTATE;
+	request->rdata.data.role = natgw_role;
+}
+
+int ctdb_reply_control_set_natgwstate(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_LMASTERROLE */
+
+void ctdb_req_control_set_lmasterrole(struct ctdb_req_control *request,
+				      uint32_t lmaster_role)
+{
+	request->opcode = CTDB_CONTROL_SET_LMASTERROLE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_LMASTERROLE;
+	request->rdata.data.role = lmaster_role;
+}
+
+int ctdb_reply_control_set_lmasterrole(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_RECMASTERROLE */
+
+void ctdb_req_control_set_recmasterrole(struct ctdb_req_control *request,
+					uint32_t recmaster_role)
+{
+	request->opcode = CTDB_CONTROL_SET_RECMASTERROLE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_RECMASTERROLE;
+	request->rdata.data.role = recmaster_role;
+}
+
+int ctdb_reply_control_set_recmasterrole(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_ENABLE_SCRIPT */
+
+void ctdb_req_control_enable_script(struct ctdb_req_control *request,
+				    const char *script)
+{
+	request->opcode = CTDB_CONTROL_ENABLE_SCRIPT;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_ENABLE_SCRIPT;
+	request->rdata.data.script = script;
+}
+
+int ctdb_reply_control_enable_script(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DISABLE_SCRIPT */
+
+void ctdb_req_control_disable_script(struct ctdb_req_control *request,
+				     const char *script)
+{
+	request->opcode = CTDB_CONTROL_DISABLE_SCRIPT;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DISABLE_SCRIPT;
+	request->rdata.data.script = script;
+}
+
+int ctdb_reply_control_disable_script(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_BAN_STATE */
+
+void ctdb_req_control_set_ban_state(struct ctdb_req_control *request,
+				    struct ctdb_ban_state *ban_state)
+{
+	request->opcode = CTDB_CONTROL_SET_BAN_STATE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_BAN_STATE;
+	request->rdata.data.ban_state = ban_state;
+}
+
+int ctdb_reply_control_set_ban_state(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_BAN_STATE */
+
+void ctdb_req_control_get_ban_state(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_BAN_STATE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_BAN_STATE;
+}
+
+int ctdb_reply_control_get_ban_state(struct ctdb_reply_control *reply,
+				     TALLOC_CTX *mem_ctx,
+				     struct ctdb_ban_state **ban_state)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_BAN_STATE) {
+		*ban_state = talloc_steal(mem_ctx,
+					  reply->rdata.data.ban_state);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SET_DB_PRIORITY */
+
+void ctdb_req_control_set_db_priority(struct ctdb_req_control *request,
+				      struct ctdb_db_priority *db_prio)
+{
+	request->opcode = CTDB_CONTROL_SET_DB_PRIORITY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_DB_PRIORITY;
+	request->rdata.data.db_prio = db_prio;
+}
+
+int ctdb_reply_control_set_db_priority(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DB_PRIORITY */
+
+void ctdb_req_control_get_db_priority(struct ctdb_req_control *request,
+				      uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_GET_DB_PRIORITY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_DB_PRIORITY;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_get_db_priority(struct ctdb_reply_control *reply,
+				       uint32_t *priority)
+{
+	if (reply->rdata.opcode == CTDB_CONTROL_GET_DB_PRIORITY) {
+		*priority = reply->status;
+		reply->status = 0;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_TRANSACTION_CANCEL */
+
+void ctdb_req_control_transaction_cancel(struct ctdb_req_control *request,
+					 uint32_t tid)
+{
+	request->opcode = CTDB_CONTROL_TRANSACTION_CANCEL;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TRANSACTION_CANCEL;
+	request->rdata.data.tid = tid;
+}
+
+int ctdb_reply_control_transaction_cancel(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_REGISTER_NOTIFY */
+
+void ctdb_req_control_register_notify(struct ctdb_req_control *request,
+				      struct ctdb_notify_data *notify)
+{
+	request->opcode = CTDB_CONTROL_REGISTER_NOTIFY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_REGISTER_NOTIFY;
+	request->rdata.data.notify = notify;
+}
+
+int ctdb_reply_control_register_notify(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DEREGISTER_NOTIFY */
+
+void ctdb_req_control_deregister_notify(struct ctdb_req_control *request,
+					uint64_t srvid)
+{
+	request->opcode = CTDB_CONTROL_DEREGISTER_NOTIFY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DEREGISTER_NOTIFY;
+	request->rdata.data.srvid = srvid;
+}
+
+int ctdb_reply_control_deregister_notify(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRANS3_COMMIT */
+
+void ctdb_req_control_trans3_commit(struct ctdb_req_control *request,
+				    struct ctdb_rec_buffer *recbuf)
+{
+	request->opcode = CTDB_CONTROL_TRANS3_COMMIT;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TRANS3_COMMIT;
+	request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_trans3_commit(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DB_SEQNUM */
+
+void ctdb_req_control_get_db_seqnum(struct ctdb_req_control *request,
+				    uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_GET_DB_SEQNUM;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_DB_SEQNUM;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_get_db_seqnum(struct ctdb_reply_control *reply,
+				     uint64_t *seqnum)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_DB_SEQNUM) {
+		*seqnum = reply->rdata.data.seqnum;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_DB_SET_HEALTHY */
+
+void ctdb_req_control_db_set_healthy(struct ctdb_req_control *request,
+				     uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_DB_SET_HEALTHY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_SET_HEALTHY;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_db_set_healthy(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DB_GET_HEALTH */
+
+void ctdb_req_control_db_get_health(struct ctdb_req_control *request,
+				    uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_DB_GET_HEALTH;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_GET_HEALTH;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_db_get_health(struct ctdb_reply_control *reply,
+				     TALLOC_CTX *mem_ctx, const char **reason)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_DB_GET_HEALTH) {
+		*reason = talloc_steal(mem_ctx, reply->rdata.data.reason);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_GET_PUBLIC_IP_INFO */
+
+void ctdb_req_control_get_public_ip_info(struct ctdb_req_control *request,
+					 ctdb_sock_addr *addr)
+{
+	request->opcode = CTDB_CONTROL_GET_PUBLIC_IP_INFO;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_PUBLIC_IP_INFO;
+	request->rdata.data.addr = addr;
+}
+
+int ctdb_reply_control_get_public_ip_info(struct ctdb_reply_control *reply,
+					  TALLOC_CTX *mem_ctx,
+					  struct ctdb_public_ip_info **ipinfo)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_PUBLIC_IP_INFO) {
+		*ipinfo = talloc_steal(mem_ctx, reply->rdata.data.ipinfo);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_GET_IFACES */
+
+void ctdb_req_control_get_ifaces(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_IFACES;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_IFACES;
+}
+
+int ctdb_reply_control_get_ifaces(struct ctdb_reply_control *reply,
+				  TALLOC_CTX *mem_ctx,
+				  struct ctdb_iface_list **iface_list)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_IFACES) {
+		*iface_list = talloc_steal(mem_ctx,
+					   reply->rdata.data.iface_list);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SET_IFACE_LINK_STATE */
+
+void ctdb_req_control_set_iface_link_state(struct ctdb_req_control *request,
+					   struct ctdb_iface *iface)
+{
+	request->opcode = CTDB_CONTROL_SET_IFACE_LINK_STATE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_IFACE_LINK_STATE;
+	request->rdata.data.iface = iface;
+}
+
+int ctdb_reply_control_set_iface_link_state(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE */
+
+void ctdb_req_control_tcp_add_delayed_update(struct ctdb_req_control *request,
+					     struct ctdb_connection *conn)
+{
+	request->opcode = CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE;
+	request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_tcp_add_delayed_update(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_STAT_HISTORY */
+
+void ctdb_req_control_get_stat_history(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_STAT_HISTORY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_STAT_HISTORY;
+}
+
+int ctdb_reply_control_get_stat_history(struct ctdb_reply_control *reply,
+					TALLOC_CTX *mem_ctx,
+					struct ctdb_statistics_list **stats_list)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_STAT_HISTORY) {
+		*stats_list = talloc_steal(mem_ctx,
+					   reply->rdata.data.stats_list);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SCHEDULE_FOR_DELETION */
+
+void ctdb_req_control_schedule_for_deletion(struct ctdb_req_control *request,
+					    struct ctdb_key_data *key)
+{
+	request->opcode = CTDB_CONTROL_SCHEDULE_FOR_DELETION;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SCHEDULE_FOR_DELETION;
+	request->rdata.data.key = key;
+}
+
+int ctdb_reply_control_schedule_for_deletion(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_DB_READONLY */
+
+void ctdb_req_control_set_db_readonly(struct ctdb_req_control *request,
+				      uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_SET_DB_READONLY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_DB_READONLY;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_set_db_readonly(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_CHECK_SRVIDS */
+
+void ctdb_req_control_check_srvids(struct ctdb_req_control *request,
+				   struct ctdb_uint64_array *u64_array)
+{
+	request->opcode = CTDB_CONTROL_CHECK_SRVIDS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_CHECK_SRVIDS;
+	request->rdata.data.u64_array = u64_array;
+}
+
+int ctdb_reply_control_check_srvids(struct ctdb_reply_control *reply,
+				    TALLOC_CTX *mem_ctx,
+				    struct ctdb_uint8_array **u8_array)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_CHECK_SRVIDS) {
+		*u8_array = talloc_steal(mem_ctx, reply->rdata.data.u8_array);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_TRAVERSE_START_EXT */
+
+void ctdb_req_control_traverse_start_ext(struct ctdb_req_control *request,
+					 struct ctdb_traverse_start_ext *traverse)
+{
+	request->opcode = CTDB_CONTROL_TRAVERSE_START_EXT;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_TRAVERSE_START_EXT;
+	request->rdata.data.traverse_start_ext = traverse;
+}
+
+int ctdb_reply_control_traverse_start_ext(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DB_STATISTICS */
+
+void ctdb_req_control_get_db_statistics(struct ctdb_req_control *request,
+					uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_GET_DB_STATISTICS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_DB_STATISTICS;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_get_db_statistics(struct ctdb_reply_control *reply,
+					 TALLOC_CTX *mem_ctx,
+					 struct ctdb_db_statistics **dbstats)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_DB_STATISTICS) {
+		*dbstats = talloc_steal(mem_ctx, reply->rdata.data.dbstats);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_SET_DB_STICKY */
+
+void ctdb_req_control_set_db_sticky(struct ctdb_req_control *request,
+				    uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_SET_DB_STICKY;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_SET_DB_STICKY;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_set_db_sticky(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RELOAD_PUBLIC_IPS */
+
+void ctdb_req_control_reload_public_ips(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_RELOAD_PUBLIC_IPS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_RELOAD_PUBLIC_IPS;
+}
+
+int ctdb_reply_control_reload_public_ips(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRAVERSE_ALL_EXT */
+
+/* CTDB_CONTROL_RECEIVE_RECORDS */
+
+void ctdb_req_control_receive_records(struct ctdb_req_control *request,
+				      struct ctdb_rec_buffer *recbuf)
+{
+	request->opcode = CTDB_CONTROL_RECEIVE_RECORDS;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_RECEIVE_RECORDS;
+	request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_receive_records(struct ctdb_reply_control *reply,
+				       TALLOC_CTX *mem_ctx,
+				       struct ctdb_rec_buffer **recbuf)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_RECEIVE_RECORDS) {
+		*recbuf = talloc_steal(mem_ctx, reply->rdata.data.recbuf);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_IPREALLOCATED */
+
+void ctdb_req_control_ipreallocated(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_IPREALLOCATED;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_IPREALLOCATED;
+}
+
+int ctdb_reply_control_ipreallocated(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_RUNSTATE */
+
+void ctdb_req_control_get_runstate(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_RUNSTATE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_RUNSTATE;
+}
+
+int ctdb_reply_control_get_runstate(struct ctdb_reply_control *reply,
+				    enum ctdb_runstate *runstate)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_RUNSTATE) {
+		*runstate = reply->rdata.data.runstate;
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_DB_DETACH */
+
+void ctdb_req_control_db_detach(struct ctdb_req_control *request,
+				uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_DB_DETACH;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_DETACH;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_db_detach(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_NODES_FILE */
+
+void ctdb_req_control_get_nodes_file(struct ctdb_req_control *request)
+{
+	request->opcode = CTDB_CONTROL_GET_NODES_FILE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_GET_NODES_FILE;
+}
+
+int ctdb_reply_control_get_nodes_file(struct ctdb_reply_control *reply,
+				      TALLOC_CTX *mem_ctx,
+				      struct ctdb_node_map **nodemap)
+{
+	if (reply->status == 0 &&
+	    reply->rdata.opcode == CTDB_CONTROL_GET_NODES_FILE) {
+		*nodemap = talloc_steal(mem_ctx, reply->rdata.data.nodemap);
+	}
+	return reply->status;
+}
+
+/* CTDB_CONTROL_DB_FREEZE */
+
+void ctdb_req_control_db_freeze(struct ctdb_req_control *request,
+				uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_DB_FREEZE;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_FREEZE;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_db_freeze(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DB_THAW */
+
+void ctdb_req_control_db_thaw(struct ctdb_req_control *request,
+			      uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_DB_THAW;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_THAW;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_db_thaw(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DB_TRANSACTION_START */
+
+void ctdb_req_control_db_transaction_start(struct ctdb_req_control *request,
+					   struct ctdb_transdb *transdb)
+{
+	request->opcode = CTDB_CONTROL_DB_TRANSACTION_START;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_TRANSACTION_START;
+	request->rdata.data.transdb = transdb;
+}
+
+int ctdb_reply_control_db_transaction_start(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DB_TRANSACTION_COMMIT */
+
+void ctdb_req_control_db_transaction_commit(struct ctdb_req_control *request,
+					    struct ctdb_transdb *transdb)
+{
+	request->opcode = CTDB_CONTROL_DB_TRANSACTION_COMMIT;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_TRANSACTION_COMMIT;
+	request->rdata.data.transdb = transdb;
+}
+
+int ctdb_reply_control_db_transaction_commit(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DB_TRANSACTION_CANCEL */
+
+void ctdb_req_control_db_transaction_cancel(struct ctdb_req_control *request,
+					    uint32_t db_id)
+{
+	request->opcode = CTDB_CONTROL_DB_TRANSACTION_CANCEL;
+	request->pad = 0;
+	request->srvid = 0;
+	request->client_id = 0;
+	request->flags = 0;
+
+	request->rdata.opcode = CTDB_CONTROL_DB_TRANSACTION_CANCEL;
+	request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_db_transaction_cancel(struct ctdb_reply_control *reply)
+{
+	return ctdb_reply_control_generic(reply);
+}
diff --git a/ctdb/protocol/protocol_control.c b/ctdb/protocol/protocol_control.c
new file mode 100644
index 0000000..1c8364e
--- /dev/null
+++ b/ctdb/protocol/protocol_control.c
@@ -0,0 +1,2087 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+#include "protocol_private.h"
+
+struct ctdb_req_control_wire {
+	struct ctdb_req_header hdr;
+	uint32_t opcode;
+	uint32_t pad;
+	uint64_t srvid;
+	uint32_t client_id;
+	uint32_t flags;
+	uint32_t datalen;
+	uint8_t data[1];
+};
+
+struct ctdb_reply_control_wire {
+	struct ctdb_req_header hdr;
+	int32_t status;
+	uint32_t datalen;
+	uint32_t errorlen;
+	uint8_t data[1];
+};
+
+static size_t ctdb_req_control_data_len(struct ctdb_req_control_data *cd)
+{
+	size_t len = 0;
+	uint64_t u64;
+
+	if (cd == NULL) {
+		return 0;
+	}
+
+	switch (cd->opcode) {
+	case CTDB_CONTROL_PROCESS_EXISTS:
+		len = ctdb_pid_len(cd->data.pid);
+		break;
+
+	case CTDB_CONTROL_STATISTICS:
+		break;
+
+	case CTDB_CONTROL_PING:
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_GETVNNMAP:
+		break;
+
+	case CTDB_CONTROL_SETVNNMAP:
+		len = ctdb_vnn_map_len(cd->data.vnnmap);
+		break;
+
+	case CTDB_CONTROL_GET_DEBUG:
+		break;
+
+	case CTDB_CONTROL_SET_DEBUG:
+		len = ctdb_uint32_len(cd->data.loglevel);
+		break;
+
+	case CTDB_CONTROL_GET_DBMAP:
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		len = ctdb_pulldb_len(cd->data.pulldb);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		len = ctdb_rec_buffer_len(cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_GET_RECMODE:
+		break;
+
+	case CTDB_CONTROL_SET_RECMODE:
+		len = ctdb_uint32_len(cd->data.recmode);
+		break;
+
+	case CTDB_CONTROL_STATISTICS_RESET:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		len = ctdb_string_len(cd->data.db_name);
+		break;
+
+	case CTDB_CONTROL_SET_CALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START:
+		len = ctdb_traverse_start_len(cd->data.traverse_start);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL:
+		len = ctdb_traverse_all_len(cd->data.traverse_all);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_DATA:
+		len = ctdb_rec_data_len(cd->data.rec_data);
+		break;
+
+	case CTDB_CONTROL_REGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SEQNUM:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_UPDATE_SEQNUM:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DUMP_MEMORY:
+		break;
+
+	case CTDB_CONTROL_GET_PID:
+		break;
+
+	case CTDB_CONTROL_GET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTER:
+		len = ctdb_uint32_len(cd->data.recmaster);
+		break;
+
+	case CTDB_CONTROL_FREEZE:
+		break;
+
+	case CTDB_CONTROL_THAW:
+		break;
+
+	case CTDB_CONTROL_GET_PNN:
+		break;
+
+	case CTDB_CONTROL_SHUTDOWN:
+		break;
+
+	case CTDB_CONTROL_GET_MONMODE:
+		break;
+
+	case CTDB_CONTROL_TCP_CLIENT:
+		len = ctdb_connection_len(cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD:
+		len = ctdb_connection_len(cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_TCP_REMOVE:
+		len = ctdb_connection_len(cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_STARTUP:
+		break;
+
+	case CTDB_CONTROL_SET_TUNABLE:
+		len = ctdb_tunable_len(cd->data.tunable);
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		len = ctdb_stringn_len(cd->data.tun_var);
+		break;
+
+	case CTDB_CONTROL_LIST_TUNABLES:
+		break;
+
+	case CTDB_CONTROL_MODIFY_FLAGS:
+		len = ctdb_node_flag_change_len(cd->data.flag_change);
+		break;
+
+	case CTDB_CONTROL_GET_ALL_TUNABLES:
+		break;
+
+	case CTDB_CONTROL_KILL_TCP:
+		len = ctdb_connection_len(cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		len = ctdb_sock_addr_len(cd->data.addr);
+		break;
+
+	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+		len = ctdb_tickle_list_len(cd->data.tickles);
+		break;
+
+	case CTDB_CONTROL_REGISTER_SERVER_ID:
+		len = ctdb_client_id_len(cd->data.cid);
+		break;
+
+	case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+		len = ctdb_client_id_len(cd->data.cid);
+		break;
+
+	case CTDB_CONTROL_CHECK_SERVER_ID:
+		len = ctdb_client_id_len(cd->data.cid);
+		break;
+
+	case CTDB_CONTROL_GET_SERVER_ID_LIST:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		len = ctdb_string_len(cd->data.db_name);
+		break;
+
+	case CTDB_CONTROL_UPDATE_RECORD:
+		len = ctdb_rec_buffer_len(cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+		len = ctdb_addr_info_len(cd->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_START:
+		len = ctdb_uint32_len(cd->data.tid);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_COMMIT:
+		len = ctdb_uint32_len(cd->data.tid);
+		break;
+
+	case CTDB_CONTROL_WIPE_DATABASE:
+		len = ctdb_transdb_len(cd->data.transdb);
+		break;
+
+	case CTDB_CONTROL_UPTIME:
+		break;
+
+	case CTDB_CONTROL_START_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_END_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_RELOAD_NODES_FILE:
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		len = ctdb_rec_buffer_len(cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_ENABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_DISABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_ADD_PUBLIC_IP:
+		len = ctdb_addr_info_len(cd->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_DEL_PUBLIC_IP:
+		len = ctdb_addr_info_len(cd->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+		len = ctdb_string_len(cd->data.event_str);
+		break;
+
+	case CTDB_CONTROL_GET_CAPABILITIES:
+		break;
+
+	case CTDB_CONTROL_RECD_PING:
+		break;
+
+	case CTDB_CONTROL_RELEASE_IP:
+		len = ctdb_public_ip_len(cd->data.pubip);
+		break;
+
+	case CTDB_CONTROL_TAKEOVER_IP:
+		len = ctdb_public_ip_len(cd->data.pubip);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IPS:
+		break;
+
+	case CTDB_CONTROL_GET_NODEMAP:
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		len = ctdb_uint32_len(cd->data.event);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_KILL:
+		len = ctdb_traverse_start_len(cd->data.traverse_start);
+		break;
+
+	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+		len = ctdb_double_len(cd->data.reclock_latency);
+		break;
+
+	case CTDB_CONTROL_GET_RECLOCK_FILE:
+		break;
+
+	case CTDB_CONTROL_SET_RECLOCK_FILE:
+		len = ctdb_string_len(cd->data.reclock_file);
+		break;
+
+	case CTDB_CONTROL_STOP_NODE:
+		break;
+
+	case CTDB_CONTROL_CONTINUE_NODE:
+		break;
+
+	case CTDB_CONTROL_SET_NATGWSTATE:
+		len = ctdb_uint32_len(cd->data.role);
+		break;
+
+	case CTDB_CONTROL_SET_LMASTERROLE:
+		len = ctdb_uint32_len(cd->data.role);
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTERROLE:
+		len = ctdb_uint32_len(cd->data.role);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SCRIPT:
+		len = ctdb_string_len(cd->data.script);
+		break;
+
+	case CTDB_CONTROL_DISABLE_SCRIPT:
+		len = ctdb_string_len(cd->data.script);
+		break;
+
+	case CTDB_CONTROL_SET_BAN_STATE:
+		len = ctdb_ban_state_len(cd->data.ban_state);
+		break;
+
+	case CTDB_CONTROL_GET_BAN_STATE:
+		break;
+
+	case CTDB_CONTROL_SET_DB_PRIORITY:
+		len = ctdb_db_priority_len(cd->data.db_prio);
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_CANCEL:
+		break;
+
+	case CTDB_CONTROL_REGISTER_NOTIFY:
+		len = ctdb_notify_data_len(cd->data.notify);
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_NOTIFY:
+		len = ctdb_uint64_len(cd->data.srvid);
+		break;
+
+	case CTDB_CONTROL_TRANS3_COMMIT:
+		len = ctdb_rec_buffer_len(cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		u64 = cd->data.db_id;
+		len = ctdb_uint64_len(u64);
+		break;
+
+	case CTDB_CONTROL_DB_SET_HEALTHY:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		len = ctdb_sock_addr_len(cd->data.addr);
+		break;
+
+	case CTDB_CONTROL_GET_IFACES:
+		break;
+
+	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+		len = ctdb_iface_len(cd->data.iface);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+		len = ctdb_connection_len(cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_GET_STAT_HISTORY:
+		break;
+
+	case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+		len = ctdb_key_data_len(cd->data.key);
+		break;
+
+	case CTDB_CONTROL_SET_DB_READONLY:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		len = ctdb_uint64_array_len(cd->data.u64_array);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START_EXT:
+		len = ctdb_traverse_start_ext_len(cd->data.traverse_start_ext);
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_SET_DB_STICKY:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+		len = ctdb_traverse_all_ext_len(cd->data.traverse_all_ext);
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		len = ctdb_rec_buffer_len(cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_IPREALLOCATED:
+		break;
+
+	case CTDB_CONTROL_GET_RUNSTATE:
+		break;
+
+	case CTDB_CONTROL_DB_DETACH:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_GET_NODES_FILE:
+		break;
+
+	case CTDB_CONTROL_DB_FREEZE:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_THAW:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_START:
+		len = ctdb_transdb_len(cd->data.transdb);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_COMMIT:
+		len = ctdb_transdb_len(cd->data.transdb);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_CANCEL:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+	}
+
+	return len;
+}
+
+static void ctdb_req_control_data_push(struct ctdb_req_control_data *cd,
+				       uint8_t *buf)
+{
+	uint64_t u64;
+
+	switch (cd->opcode) {
+	case CTDB_CONTROL_PROCESS_EXISTS:
+		ctdb_pid_push(cd->data.pid, buf);
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_SETVNNMAP:
+		ctdb_vnn_map_push(cd->data.vnnmap, buf);
+		break;
+
+	case CTDB_CONTROL_SET_DEBUG:
+		ctdb_uint32_push(cd->data.loglevel, buf);
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		ctdb_pulldb_push(cd->data.pulldb, buf);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		ctdb_rec_buffer_push(cd->data.recbuf, buf);
+		break;
+
+	case CTDB_CONTROL_SET_RECMODE:
+		ctdb_uint32_push(cd->data.recmode, buf);
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		ctdb_string_push(cd->data.db_name, buf);
+		break;
+
+	case CTDB_CONTROL_SET_CALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START:
+		ctdb_traverse_start_push(cd->data.traverse_start, buf);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL:
+		ctdb_traverse_all_push(cd->data.traverse_all, buf);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_DATA:
+		ctdb_rec_data_push(cd->data.rec_data, buf);
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SEQNUM:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_UPDATE_SEQNUM:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTER:
+		ctdb_uint32_push(cd->data.recmaster, buf);
+		break;
+
+	case CTDB_CONTROL_TCP_CLIENT:
+		ctdb_connection_push(cd->data.conn, buf);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD:
+		ctdb_connection_push(cd->data.conn, buf);
+		break;
+
+	case CTDB_CONTROL_TCP_REMOVE:
+		ctdb_connection_push(cd->data.conn, buf);
+		break;
+
+	case CTDB_CONTROL_SET_TUNABLE:
+		ctdb_tunable_push(cd->data.tunable, buf);
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		ctdb_stringn_push(cd->data.tun_var, buf);
+		break;
+
+	case CTDB_CONTROL_MODIFY_FLAGS:
+		ctdb_node_flag_change_push(cd->data.flag_change, buf);
+		break;
+
+	case CTDB_CONTROL_KILL_TCP:
+		ctdb_connection_push(cd->data.conn, buf);
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		ctdb_sock_addr_push(cd->data.addr, buf);
+		break;
+
+	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+		ctdb_tickle_list_push(cd->data.tickles, buf);
+		break;
+
+	case CTDB_CONTROL_REGISTER_SERVER_ID:
+		ctdb_client_id_push(cd->data.cid, buf);
+		break;
+
+	case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+		ctdb_client_id_push(cd->data.cid, buf);
+		break;
+
+	case CTDB_CONTROL_CHECK_SERVER_ID:
+		ctdb_client_id_push(cd->data.cid, buf);
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		ctdb_string_push(cd->data.db_name, buf);
+		break;
+
+	case CTDB_CONTROL_UPDATE_RECORD:
+		ctdb_rec_buffer_push(cd->data.recbuf, buf);
+		break;
+
+	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+		ctdb_addr_info_push(cd->data.addr_info, buf);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_START:
+		ctdb_uint32_push(cd->data.tid, buf);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_COMMIT:
+		ctdb_uint32_push(cd->data.tid, buf);
+		break;
+
+	case CTDB_CONTROL_WIPE_DATABASE:
+		ctdb_transdb_push(cd->data.transdb, buf);
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		ctdb_rec_buffer_push(cd->data.recbuf, buf);
+		break;
+
+	case CTDB_CONTROL_ADD_PUBLIC_IP:
+		ctdb_addr_info_push(cd->data.addr_info, buf);
+		break;
+
+	case CTDB_CONTROL_DEL_PUBLIC_IP:
+		ctdb_addr_info_push(cd->data.addr_info, buf);
+		break;
+
+	case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+		ctdb_string_push(cd->data.event_str, buf);
+		break;
+
+	case CTDB_CONTROL_RELEASE_IP:
+		ctdb_public_ip_push(cd->data.pubip, buf);
+		break;
+
+	case CTDB_CONTROL_TAKEOVER_IP:
+		ctdb_public_ip_push(cd->data.pubip, buf);
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		ctdb_uint32_push(cd->data.event, buf);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_KILL:
+		ctdb_traverse_start_push(cd->data.traverse_start, buf);
+		break;
+
+	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+		ctdb_double_push(cd->data.reclock_latency, buf);
+		break;
+
+	case CTDB_CONTROL_SET_RECLOCK_FILE:
+		ctdb_string_push(cd->data.reclock_file, buf);
+		break;
+
+	case CTDB_CONTROL_SET_NATGWSTATE:
+		ctdb_uint32_push(cd->data.role, buf);
+		break;
+
+	case CTDB_CONTROL_SET_LMASTERROLE:
+		ctdb_uint32_push(cd->data.role, buf);
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTERROLE:
+		ctdb_uint32_push(cd->data.role, buf);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SCRIPT:
+		ctdb_string_push(cd->data.script, buf);
+		break;
+
+	case CTDB_CONTROL_DISABLE_SCRIPT:
+		ctdb_string_push(cd->data.script, buf);
+		break;
+
+	case CTDB_CONTROL_SET_BAN_STATE:
+		ctdb_ban_state_push(cd->data.ban_state, buf);
+		break;
+
+	case CTDB_CONTROL_SET_DB_PRIORITY:
+		ctdb_db_priority_push(cd->data.db_prio, buf);
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_REGISTER_NOTIFY:
+		ctdb_notify_data_push(cd->data.notify, buf);
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_NOTIFY:
+		ctdb_uint64_push(cd->data.srvid, buf);
+		break;
+
+	case CTDB_CONTROL_TRANS3_COMMIT:
+		ctdb_rec_buffer_push(cd->data.recbuf, buf);
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		u64 = cd->data.db_id;
+		ctdb_uint64_push(u64, buf);
+		break;
+
+	case CTDB_CONTROL_DB_SET_HEALTHY:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		ctdb_sock_addr_push(cd->data.addr, buf);
+		break;
+
+	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+		ctdb_iface_push(cd->data.iface, buf);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+		ctdb_connection_push(cd->data.conn, buf);
+		break;
+
+	case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+		ctdb_key_data_push(cd->data.key, buf);
+		break;
+
+	case CTDB_CONTROL_SET_DB_READONLY:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		ctdb_uint64_array_push(cd->data.u64_array, buf);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START_EXT:
+		ctdb_traverse_start_ext_push(cd->data.traverse_start_ext, buf);
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_SET_DB_STICKY:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+		ctdb_traverse_all_ext_push(cd->data.traverse_all_ext, buf);
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		ctdb_rec_buffer_push(cd->data.recbuf, buf);
+		break;
+
+	case CTDB_CONTROL_DB_DETACH:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_DB_FREEZE:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_DB_THAW:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_START:
+		ctdb_transdb_push(cd->data.transdb, buf);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_COMMIT:
+		ctdb_transdb_push(cd->data.transdb, buf);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_CANCEL:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+	}
+}
+
+static int ctdb_req_control_data_pull(uint8_t *buf, size_t buflen,
+				      uint32_t opcode,
+				      TALLOC_CTX *mem_ctx,
+				      struct ctdb_req_control_data *cd)
+{
+	int ret = 0;
+	uint64_t u64 = 0;
+
+	cd->opcode = opcode;
+
+	switch (opcode) {
+	case CTDB_CONTROL_PROCESS_EXISTS:
+		ret = ctdb_pid_pull(buf, buflen, mem_ctx,
+				    &cd->data.pid);
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_SETVNNMAP:
+		ret = ctdb_vnn_map_pull(buf, buflen, mem_ctx,
+					&cd->data.vnnmap);
+		break;
+
+	case CTDB_CONTROL_SET_DEBUG:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.loglevel);
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		ret = ctdb_pulldb_pull(buf, buflen, mem_ctx,
+				       &cd->data.pulldb);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+					   &cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_SET_RECMODE:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.recmode);
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_name);
+		break;
+
+	case CTDB_CONTROL_SET_CALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START:
+		ret = ctdb_traverse_start_pull(buf, buflen, mem_ctx,
+					       &cd->data.traverse_start);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL:
+		ret = ctdb_traverse_all_pull(buf, buflen, mem_ctx,
+					     &cd->data.traverse_all);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_DATA:
+		ret = ctdb_rec_data_pull(buf, buflen, mem_ctx,
+					 &cd->data.rec_data);
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SEQNUM:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_UPDATE_SEQNUM:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTER:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.recmaster);
+		break;
+
+	case CTDB_CONTROL_TCP_CLIENT:
+		ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+					   &cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD:
+		ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+					   &cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_TCP_REMOVE:
+		ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+					   &cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_SET_TUNABLE:
+		ret = ctdb_tunable_pull(buf, buflen, mem_ctx,
+					&cd->data.tunable);
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		ret = ctdb_stringn_pull(buf, buflen, mem_ctx,
+					&cd->data.tun_var);
+		break;
+
+	case CTDB_CONTROL_MODIFY_FLAGS:
+		ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
+						 &cd->data.flag_change);
+		break;
+
+	case CTDB_CONTROL_KILL_TCP:
+		ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+					   &cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		ret = ctdb_sock_addr_pull(buf, buflen, mem_ctx,
+					  &cd->data.addr);
+		break;
+
+	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+		ret = ctdb_tickle_list_pull(buf, buflen, mem_ctx,
+					    &cd->data.tickles);
+		break;
+
+	case CTDB_CONTROL_REGISTER_SERVER_ID:
+		ret = ctdb_client_id_pull(buf, buflen, mem_ctx,
+					  &cd->data.cid);
+		break;
+
+	case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+		ret = ctdb_client_id_pull(buf, buflen, mem_ctx,
+					  &cd->data.cid);
+		break;
+
+	case CTDB_CONTROL_CHECK_SERVER_ID:
+		ret = ctdb_client_id_pull(buf, buflen, mem_ctx,
+					  &cd->data.cid);
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_name);
+		break;
+
+	case CTDB_CONTROL_UPDATE_RECORD:
+		ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+					   &cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+		ret = ctdb_addr_info_pull(buf, buflen, mem_ctx,
+					  &cd->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_START:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.tid);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_COMMIT:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.tid);
+		break;
+
+	case CTDB_CONTROL_WIPE_DATABASE:
+		ret = ctdb_transdb_pull(buf, buflen, mem_ctx,
+				       &cd->data.transdb);
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+					   &cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_ADD_PUBLIC_IP:
+		ret = ctdb_addr_info_pull(buf, buflen, mem_ctx,
+					  &cd->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_DEL_PUBLIC_IP:
+		ret = ctdb_addr_info_pull(buf, buflen, mem_ctx,
+					  &cd->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.event_str);
+		break;
+
+	case CTDB_CONTROL_RELEASE_IP:
+		ret = ctdb_public_ip_pull(buf, buflen, mem_ctx,
+					  &cd->data.pubip);
+		break;
+
+	case CTDB_CONTROL_TAKEOVER_IP:
+		ret = ctdb_public_ip_pull(buf, buflen, mem_ctx,
+					  &cd->data.pubip);
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				       &cd->data.event);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_KILL:
+		ret = ctdb_traverse_start_pull(buf, buflen, mem_ctx,
+					       &cd->data.traverse_start);
+		break;
+
+	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+		ret = ctdb_double_pull(buf, buflen, mem_ctx,
+				       &cd->data.reclock_latency);
+		break;
+
+	case CTDB_CONTROL_SET_RECLOCK_FILE:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.reclock_file);
+		break;
+
+	case CTDB_CONTROL_SET_NATGWSTATE:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.role);
+		break;
+
+	case CTDB_CONTROL_SET_LMASTERROLE:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.role);
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTERROLE:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.role);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SCRIPT:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.script);
+		break;
+
+	case CTDB_CONTROL_DISABLE_SCRIPT:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.script);
+		break;
+
+	case CTDB_CONTROL_SET_BAN_STATE:
+		ret = ctdb_ban_state_pull(buf, buflen, mem_ctx,
+					  &cd->data.ban_state);
+		break;
+
+	case CTDB_CONTROL_SET_DB_PRIORITY:
+		ret = ctdb_db_priority_pull(buf, buflen, mem_ctx,
+					    &cd->data.db_prio);
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_REGISTER_NOTIFY:
+		ret = ctdb_notify_data_pull(buf, buflen, mem_ctx,
+					    &cd->data.notify);
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_NOTIFY:
+		ctdb_uint64_pull(buf, buflen, mem_ctx,
+				 &cd->data.srvid);
+		break;
+
+	case CTDB_CONTROL_TRANS3_COMMIT:
+		ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+					   &cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		ret = ctdb_uint64_pull(buf, buflen, mem_ctx, &u64);
+		cd->data.db_id = (uint32_t)u64;
+		break;
+
+	case CTDB_CONTROL_DB_SET_HEALTHY:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		ret = ctdb_sock_addr_pull(buf, buflen, mem_ctx,
+					  &cd->data.addr);
+		break;
+
+	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+		ret = ctdb_iface_pull(buf, buflen, mem_ctx,
+				      &cd->data.iface);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+		ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+					   &cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+		ret = ctdb_key_data_pull(buf, buflen, mem_ctx,
+					 &cd->data.key);
+		break;
+
+	case CTDB_CONTROL_SET_DB_READONLY:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		ret = ctdb_uint64_array_pull(buf, buflen, mem_ctx,
+					     &cd->data.u64_array);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START_EXT:
+		ret = ctdb_traverse_start_ext_pull(buf, buflen, mem_ctx,
+						   &cd->data.traverse_start_ext);
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_SET_DB_STICKY:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+		ret = ctdb_traverse_all_ext_pull(buf, buflen, mem_ctx,
+						 &cd->data.traverse_all_ext);
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+					   &cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_DB_DETACH:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_FREEZE:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_THAW:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_START:
+		ret = ctdb_transdb_pull(buf, buflen, mem_ctx,
+					&cd->data.transdb);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_COMMIT:
+		ret = ctdb_transdb_pull(buf, buflen, mem_ctx,
+					&cd->data.transdb);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_CANCEL:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+					&cd->data.db_id);
+		break;
+	}
+
+	return ret;
+}
+
+static size_t ctdb_reply_control_data_len(struct ctdb_reply_control_data *cd)
+{
+	size_t len = 0;
+
+	if (cd == NULL) {
+		return 0;
+	}
+
+	switch (cd->opcode) {
+	case CTDB_CONTROL_PROCESS_EXISTS:
+		break;
+
+	case CTDB_CONTROL_STATISTICS:
+		len = ctdb_statistics_len(cd->data.stats);
+		break;
+
+	case CTDB_CONTROL_PING:
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		len = ctdb_string_len(cd->data.db_path);
+		break;
+
+	case CTDB_CONTROL_GETVNNMAP:
+		len = ctdb_vnn_map_len(cd->data.vnnmap);
+		break;
+
+	case CTDB_CONTROL_SETVNNMAP:
+		break;
+
+	case CTDB_CONTROL_GET_DEBUG:
+		len = ctdb_uint32_len(cd->data.loglevel);
+		break;
+
+	case CTDB_CONTROL_SET_DEBUG:
+		break;
+
+	case CTDB_CONTROL_GET_DBMAP:
+		len = ctdb_dbid_map_len(cd->data.dbmap);
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		len = ctdb_rec_buffer_len(cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		break;
+
+	case CTDB_CONTROL_GET_RECMODE:
+		break;
+
+	case CTDB_CONTROL_SET_RECMODE:
+		break;
+
+	case CTDB_CONTROL_STATISTICS_RESET:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_SET_CALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_DATA:
+		break;
+
+	case CTDB_CONTROL_REGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		len = ctdb_string_len(cd->data.db_name);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SEQNUM:
+		break;
+
+	case CTDB_CONTROL_UPDATE_SEQNUM:
+		break;
+
+	case CTDB_CONTROL_DUMP_MEMORY:
+		len = ctdb_string_len(cd->data.mem_str);
+		break;
+
+	case CTDB_CONTROL_GET_PID:
+		break;
+
+	case CTDB_CONTROL_GET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_FREEZE:
+		break;
+
+	case CTDB_CONTROL_THAW:
+		break;
+
+	case CTDB_CONTROL_GET_PNN:
+		break;
+
+	case CTDB_CONTROL_SHUTDOWN:
+		break;
+
+	case CTDB_CONTROL_GET_MONMODE:
+		break;
+
+	case CTDB_CONTROL_TCP_CLIENT:
+		break;
+
+	case CTDB_CONTROL_TCP_ADD:
+		break;
+
+	case CTDB_CONTROL_TCP_REMOVE:
+		break;
+
+	case CTDB_CONTROL_STARTUP:
+		break;
+
+	case CTDB_CONTROL_SET_TUNABLE:
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		len = ctdb_uint32_len(cd->data.tun_value);
+		break;
+
+	case CTDB_CONTROL_LIST_TUNABLES:
+		len = ctdb_var_list_len(cd->data.tun_var_list);
+		break;
+
+	case CTDB_CONTROL_MODIFY_FLAGS:
+		break;
+
+	case CTDB_CONTROL_GET_ALL_TUNABLES:
+		len = ctdb_tunable_list_len(cd->data.tun_list);
+		break;
+
+	case CTDB_CONTROL_KILL_TCP:
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		len = ctdb_tickle_list_len(cd->data.tickles);
+		break;
+
+	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+		break;
+
+	case CTDB_CONTROL_REGISTER_SERVER_ID:
+		break;
+
+	case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+		break;
+
+	case CTDB_CONTROL_CHECK_SERVER_ID:
+		break;
+
+	case CTDB_CONTROL_GET_SERVER_ID_LIST:
+		len = ctdb_client_id_map_len(cd->data.cid_map);
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		len = ctdb_uint32_len(cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_UPDATE_RECORD:
+		break;
+
+	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_START:
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_COMMIT:
+		break;
+
+	case CTDB_CONTROL_WIPE_DATABASE:
+		break;
+
+	case CTDB_CONTROL_UPTIME:
+		len = ctdb_uptime_len(cd->data.uptime);
+		break;
+
+	case CTDB_CONTROL_START_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_END_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_RELOAD_NODES_FILE:
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		len = ctdb_rec_buffer_len(cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_ENABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_DISABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_ADD_PUBLIC_IP:
+		break;
+
+	case CTDB_CONTROL_DEL_PUBLIC_IP:
+		break;
+
+	case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+		break;
+
+	case CTDB_CONTROL_GET_CAPABILITIES:
+		len = ctdb_uint32_len(cd->data.caps);
+		break;
+
+	case CTDB_CONTROL_RECD_PING:
+		break;
+
+	case CTDB_CONTROL_RELEASE_IP:
+		break;
+
+	case CTDB_CONTROL_TAKEOVER_IP:
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IPS:
+		len = ctdb_public_ip_list_len(cd->data.pubip_list);
+		break;
+
+	case CTDB_CONTROL_GET_NODEMAP:
+		len = ctdb_node_map_len(cd->data.nodemap);
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		len = ctdb_script_list_len(cd->data.script_list);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_KILL:
+		break;
+
+	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+		break;
+
+	case CTDB_CONTROL_GET_RECLOCK_FILE:
+		len = ctdb_string_len(cd->data.reclock_file);
+		break;
+
+	case CTDB_CONTROL_SET_RECLOCK_FILE:
+		break;
+
+	case CTDB_CONTROL_STOP_NODE:
+		break;
+
+	case CTDB_CONTROL_CONTINUE_NODE:
+		break;
+
+	case CTDB_CONTROL_SET_NATGWSTATE:
+		break;
+
+	case CTDB_CONTROL_SET_LMASTERROLE:
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTERROLE:
+		break;
+
+	case CTDB_CONTROL_ENABLE_SCRIPT:
+		break;
+
+	case CTDB_CONTROL_DISABLE_SCRIPT:
+		break;
+
+	case CTDB_CONTROL_SET_BAN_STATE:
+		break;
+
+	case CTDB_CONTROL_GET_BAN_STATE:
+		len = ctdb_ban_state_len(cd->data.ban_state);
+		break;
+
+	case CTDB_CONTROL_SET_DB_PRIORITY:
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_CANCEL:
+		break;
+
+	case CTDB_CONTROL_REGISTER_NOTIFY:
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_NOTIFY:
+		break;
+
+	case CTDB_CONTROL_TRANS3_COMMIT:
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		len = ctdb_uint64_len(cd->data.seqnum);
+		break;
+
+	case CTDB_CONTROL_DB_SET_HEALTHY:
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		len = ctdb_string_len(cd->data.reason);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		len = ctdb_public_ip_info_len(cd->data.ipinfo);
+		break;
+
+	case CTDB_CONTROL_GET_IFACES:
+		len = ctdb_iface_list_len(cd->data.iface_list);
+		break;
+
+	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+		break;
+
+	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+		break;
+
+	case CTDB_CONTROL_GET_STAT_HISTORY:
+		len = ctdb_statistics_list_len(cd->data.stats_list);
+		break;
+
+	case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+		break;
+
+	case CTDB_CONTROL_SET_DB_READONLY:
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		len = ctdb_uint8_array_len(cd->data.u8_array);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START_EXT:
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		len = ctdb_db_statistics_len(cd->data.dbstats);
+		break;
+
+	case CTDB_CONTROL_SET_DB_STICKY:
+		break;
+
+	case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		len = ctdb_rec_buffer_len(cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_IPREALLOCATED:
+		break;
+
+	case CTDB_CONTROL_GET_RUNSTATE:
+		len = ctdb_uint32_len(cd->data.runstate);
+		break;
+
+	case CTDB_CONTROL_DB_DETACH:
+		break;
+
+	case CTDB_CONTROL_GET_NODES_FILE:
+		len = ctdb_node_map_len(cd->data.nodemap);
+		break;
+
+	case CTDB_CONTROL_DB_FREEZE:
+		break;
+
+	case CTDB_CONTROL_DB_THAW:
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_START:
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_COMMIT:
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_CANCEL:
+		break;
+	}
+
+	return len;
+}
+
+static void ctdb_reply_control_data_push(struct ctdb_reply_control_data *cd,
+					 uint8_t *buf)
+{
+	switch (cd->opcode) {
+	case CTDB_CONTROL_STATISTICS:
+		ctdb_statistics_push(cd->data.stats, buf);
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		ctdb_string_push(cd->data.db_path, buf);
+		break;
+
+	case CTDB_CONTROL_GETVNNMAP:
+		ctdb_vnn_map_push(cd->data.vnnmap, buf);
+		break;
+
+	case CTDB_CONTROL_GET_DEBUG:
+		ctdb_uint32_push(cd->data.loglevel, buf);
+		break;
+
+	case CTDB_CONTROL_GET_DBMAP:
+		ctdb_dbid_map_push(cd->data.dbmap, buf);
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		ctdb_rec_buffer_push(cd->data.recbuf, buf);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		ctdb_string_push(cd->data.db_name, buf);
+		break;
+
+	case CTDB_CONTROL_DUMP_MEMORY:
+		ctdb_string_push(cd->data.mem_str, buf);
+		break;
+
+	case CTDB_CONTROL_GET_PID:
+		break;
+
+	case CTDB_CONTROL_GET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		ctdb_uint32_push(cd->data.tun_value, buf);
+		break;
+
+	case CTDB_CONTROL_LIST_TUNABLES:
+		ctdb_var_list_push(cd->data.tun_var_list, buf);
+		break;
+
+	case CTDB_CONTROL_GET_ALL_TUNABLES:
+		ctdb_tunable_list_push(cd->data.tun_list, buf);
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		ctdb_tickle_list_push(cd->data.tickles, buf);
+		break;
+
+	case CTDB_CONTROL_GET_SERVER_ID_LIST:
+		ctdb_client_id_map_push(cd->data.cid_map, buf);
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		ctdb_uint32_push(cd->data.db_id, buf);
+		break;
+
+	case CTDB_CONTROL_UPTIME:
+		ctdb_uptime_push(cd->data.uptime, buf);
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		ctdb_rec_buffer_push(cd->data.recbuf, buf);
+		break;
+
+	case CTDB_CONTROL_GET_CAPABILITIES:
+		ctdb_uint32_push(cd->data.caps, buf);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IPS:
+		ctdb_public_ip_list_push(cd->data.pubip_list, buf);
+		break;
+
+	case CTDB_CONTROL_GET_NODEMAP:
+		ctdb_node_map_push(cd->data.nodemap, buf);
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		ctdb_script_list_push(cd->data.script_list, buf);
+		break;
+
+	case CTDB_CONTROL_GET_RECLOCK_FILE:
+		ctdb_string_push(cd->data.reclock_file, buf);
+		break;
+
+	case CTDB_CONTROL_GET_BAN_STATE:
+		ctdb_ban_state_push(cd->data.ban_state, buf);
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		ctdb_uint64_push(cd->data.seqnum, buf);
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		ctdb_string_push(cd->data.reason, buf);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		ctdb_public_ip_info_push(cd->data.ipinfo, buf);
+		break;
+
+	case CTDB_CONTROL_GET_IFACES:
+		ctdb_iface_list_push(cd->data.iface_list, buf);
+		break;
+
+	case CTDB_CONTROL_GET_STAT_HISTORY:
+		ctdb_statistics_list_push(cd->data.stats_list, buf);
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		ctdb_uint8_array_push(cd->data.u8_array, buf);
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		ctdb_db_statistics_push(cd->data.dbstats, buf);
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		ctdb_rec_buffer_push(cd->data.recbuf, buf);
+		break;
+
+	case CTDB_CONTROL_GET_RUNSTATE:
+		ctdb_uint32_push(cd->data.runstate, buf);
+		break;
+
+	case CTDB_CONTROL_GET_NODES_FILE:
+		ctdb_node_map_push(cd->data.nodemap, buf);
+		break;
+	}
+}
+
+static int ctdb_reply_control_data_pull(uint8_t *buf, size_t buflen,
+					uint32_t opcode, TALLOC_CTX *mem_ctx,
+					struct ctdb_reply_control_data *cd)
+{
+	int ret = 0;
+	cd->opcode = opcode;
+
+	switch (opcode) {
+	case CTDB_CONTROL_STATISTICS:
+		ret = ctdb_statistics_pull(buf, buflen, mem_ctx,
+					   &cd->data.stats);
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_path);
+		break;
+
+	case CTDB_CONTROL_GETVNNMAP:
+		ret = ctdb_vnn_map_pull(buf, buflen, mem_ctx,
+					&cd->data.vnnmap);
+		break;
+
+	case CTDB_CONTROL_GET_DEBUG:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.loglevel);
+		break;
+
+	case CTDB_CONTROL_GET_DBMAP:
+		ret = ctdb_dbid_map_pull(buf, buflen, mem_ctx,
+					 &cd->data.dbmap);
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+					   &cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_name);
+		break;
+
+	case CTDB_CONTROL_DUMP_MEMORY:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.mem_str);
+		break;
+
+	case CTDB_CONTROL_GET_PID:
+		break;
+
+	case CTDB_CONTROL_GET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.tun_value);
+		break;
+
+	case CTDB_CONTROL_LIST_TUNABLES:
+		ret = ctdb_var_list_pull(buf, buflen, mem_ctx,
+					 &cd->data.tun_var_list);
+		break;
+
+	case CTDB_CONTROL_GET_ALL_TUNABLES:
+		ret = ctdb_tunable_list_pull(buf, buflen, mem_ctx,
+					     &cd->data.tun_list);
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		ret = ctdb_tickle_list_pull(buf, buflen, mem_ctx,
+					    &cd->data.tickles);
+		break;
+
+	case CTDB_CONTROL_GET_SERVER_ID_LIST:
+		ret = ctdb_client_id_map_pull(buf, buflen, mem_ctx,
+					      &cd->data.cid_map);
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				       &cd->data.db_id);
+		break;
+
+	case CTDB_CONTROL_UPTIME:
+		ret = ctdb_uptime_pull(buf, buflen, mem_ctx,
+				       &cd->data.uptime);
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+				     &cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_GET_CAPABILITIES:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				     &cd->data.caps);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IPS:
+		ret = ctdb_public_ip_list_pull(buf, buflen, mem_ctx,
+					       &cd->data.pubip_list);
+		break;
+
+	case CTDB_CONTROL_GET_NODEMAP:
+		ret = ctdb_node_map_pull(buf, buflen, mem_ctx,
+					 &cd->data.nodemap);
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		ret = ctdb_script_list_pull(buf, buflen, mem_ctx,
+					    &cd->data.script_list);
+		break;
+
+	case CTDB_CONTROL_GET_RECLOCK_FILE:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.reclock_file);
+		break;
+
+	case CTDB_CONTROL_GET_BAN_STATE:
+		ret = ctdb_ban_state_pull(buf, buflen, mem_ctx,
+					  &cd->data.ban_state);
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		ret = ctdb_uint64_pull(buf, buflen, mem_ctx,
+				       &cd->data.seqnum);
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx,
+				       &cd->data.reason);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		ret = ctdb_public_ip_info_pull(buf, buflen, mem_ctx,
+					       &cd->data.ipinfo);
+		break;
+
+	case CTDB_CONTROL_GET_IFACES:
+		ret = ctdb_iface_list_pull(buf, buflen, mem_ctx,
+					   &cd->data.iface_list);
+		break;
+
+	case CTDB_CONTROL_GET_STAT_HISTORY:
+		ret = ctdb_statistics_list_pull(buf, buflen, mem_ctx,
+						&cd->data.stats_list);
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		ret = ctdb_uint8_array_pull(buf, buflen, mem_ctx,
+					    &cd->data.u8_array);
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		ret = ctdb_db_statistics_pull(buf, buflen, mem_ctx,
+					      &cd->data.dbstats);
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+					   &cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_GET_RUNSTATE:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+				       &cd->data.runstate);
+		break;
+
+	case CTDB_CONTROL_GET_NODES_FILE:
+		ret = ctdb_node_map_pull(buf, buflen, mem_ctx,
+					 &cd->data.nodemap);
+		break;
+	}
+
+	return ret;
+}
+
+int ctdb_req_control_push(struct ctdb_req_header *h,
+			  struct ctdb_req_control *request,
+			  TALLOC_CTX *mem_ctx,
+			  uint8_t **pkt, size_t *pkt_len)
+{
+	struct ctdb_req_control_wire *wire;
+	uint8_t *buf;
+	size_t length, buflen, datalen;
+	int ret;
+
+	datalen = ctdb_req_control_data_len(&request->rdata);
+	length = offsetof(struct ctdb_req_control_wire, data) + datalen;
+
+	ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	wire = (struct ctdb_req_control_wire *)buf;
+
+	h->length = buflen;
+	memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+	wire->opcode = request->opcode;
+	wire->pad = request->pad;
+	wire->srvid = request->srvid;
+	wire->client_id = request->client_id;
+	wire->flags = request->flags;
+
+	wire->datalen = datalen;
+	ctdb_req_control_data_push(&request->rdata, wire->data);
+
+	*pkt = buf;
+	*pkt_len = buflen;
+	return 0;
+}
+
+int ctdb_req_control_pull(uint8_t *pkt, size_t pkt_len,
+			  struct ctdb_req_header *h,
+			  TALLOC_CTX *mem_ctx,
+			  struct ctdb_req_control *request)
+{
+	struct ctdb_req_control_wire *wire =
+		(struct ctdb_req_control_wire *)pkt;
+	size_t length;
+	int ret;
+
+	length = offsetof(struct ctdb_req_control_wire, data);
+	if (pkt_len < length) {
+		return EMSGSIZE;
+	}
+	if (pkt_len < length + wire->datalen) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+	request->opcode = wire->opcode;
+	request->pad = wire->pad;
+	request->srvid = wire->srvid;
+	request->client_id = wire->client_id;
+	request->flags = wire->flags;
+
+	ret = ctdb_req_control_data_pull(wire->data, wire->datalen,
+					 request->opcode, mem_ctx,
+					 &request->rdata);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return 0;
+}
+
+int ctdb_reply_control_push(struct ctdb_req_header *h,
+			    struct ctdb_reply_control *reply,
+			    TALLOC_CTX *mem_ctx,
+			    uint8_t **pkt, size_t *pkt_len)
+{
+	struct ctdb_reply_control_wire *wire;
+	uint8_t *buf;
+	size_t length, buflen, datalen, errlen;
+	int ret;
+
+	if (reply->status == 0) {
+		datalen = ctdb_reply_control_data_len(&reply->rdata);
+	} else {
+		datalen = 0;
+	}
+
+	if (reply->errmsg == NULL) {
+		errlen = 0;
+	} else {
+		errlen = strlen(reply->errmsg) + 1;
+	}
+
+	length = offsetof(struct ctdb_reply_control_wire, data) +
+		 datalen + errlen;
+
+	ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	wire = (struct ctdb_reply_control_wire *)buf;
+
+	h->length = buflen;
+	memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+	wire->status = reply->status;
+
+	wire->datalen = datalen;
+	if (reply->status == 0) {
+		ctdb_reply_control_data_push(&reply->rdata, wire->data);
+	}
+
+	wire->errorlen = errlen;
+	if (errlen > 0) {
+		memcpy(wire->data + datalen, reply->errmsg, wire->errorlen);
+	}
+
+	*pkt = buf;
+	*pkt_len = buflen;
+	return 0;
+}
+
+int ctdb_reply_control_pull(uint8_t *pkt, size_t pkt_len, uint32_t opcode,
+			    struct ctdb_req_header *h,
+			    TALLOC_CTX *mem_ctx,
+			    struct ctdb_reply_control *reply)
+{
+	struct ctdb_reply_control_wire *wire =
+		(struct ctdb_reply_control_wire *)pkt;
+	size_t length;
+	int ret;
+
+	length = offsetof(struct ctdb_reply_control_wire, data);
+
+	if (pkt_len < length) {
+		return EMSGSIZE;
+	}
+	if (pkt_len < length + wire->datalen + wire->errorlen) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+	reply->status = wire->status;
+
+	if (reply->status != -1) {
+		ret = ctdb_reply_control_data_pull(wire->data, wire->datalen,
+						   opcode, mem_ctx,
+						   &reply->rdata);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	if (wire->errorlen > 0) {
+		reply->errmsg = talloc_memdup(mem_ctx,
+					      wire->data + wire->datalen,
+					      wire->errorlen);
+	} else {
+		reply->errmsg = NULL;
+	}
+
+	return 0;
+}
diff --git a/ctdb/protocol/protocol_header.c b/ctdb/protocol/protocol_header.c
new file mode 100644
index 0000000..b802d08
--- /dev/null
+++ b/ctdb/protocol/protocol_header.c
@@ -0,0 +1,73 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+
+int ctdb_req_header_verify(struct ctdb_req_header *h, uint32_t operation)
+{
+	if (h->length < sizeof(struct ctdb_req_header)) {
+		return EMSGSIZE;
+	}
+
+	if (h->ctdb_magic != CTDB_MAGIC) {
+		return EPROTO;
+	}
+
+	if (h->ctdb_version != CTDB_PROTOCOL) {
+		return EPROTO;
+	}
+
+	if (operation != 0 && h->operation != operation) {
+		return EPROTO;
+	}
+
+	return 0;
+}
+
+void ctdb_req_header_fill(struct ctdb_req_header *h, uint32_t generation,
+			  uint32_t operation, uint32_t destnode,
+			  uint32_t srcnode, uint32_t reqid)
+{
+	h->length = sizeof(struct ctdb_req_header);
+	h->ctdb_magic = CTDB_MAGIC;
+	h->ctdb_version = CTDB_PROTOCOL;
+	h->generation = generation;
+	h->operation = operation;
+	h->destnode = destnode;
+	h->srcnode = srcnode;
+	h->reqid = reqid;
+}
+
+int ctdb_req_header_pull(uint8_t *pkt, size_t pkt_len,
+			 struct ctdb_req_header *h)
+{
+	if (pkt_len < sizeof(struct ctdb_req_header)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, pkt, sizeof(struct ctdb_req_header));
+	return 0;
+}
diff --git a/ctdb/protocol/protocol_message.c b/ctdb/protocol/protocol_message.c
new file mode 100644
index 0000000..696367e
--- /dev/null
+++ b/ctdb/protocol/protocol_message.c
@@ -0,0 +1,395 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+#include "protocol_private.h"
+
+struct ctdb_req_message_wire {
+	struct ctdb_req_header hdr;
+	uint64_t srvid;
+	uint32_t datalen;
+	uint8_t data[1];
+};
+
+static size_t ctdb_message_data_len(union ctdb_message_data *mdata,
+				    uint64_t srvid)
+{
+	size_t len = 0;
+
+	switch (srvid) {
+	case CTDB_SRVID_ELECTION:
+		len = ctdb_election_message_len(mdata->election);
+		break;
+
+	case CTDB_SRVID_RECONFIGURE:
+		break;
+
+	case CTDB_SRVID_RELEASE_IP:
+		len = ctdb_string_len(mdata->ipaddr);
+		break;
+
+	case CTDB_SRVID_TAKE_IP:
+		len = ctdb_string_len(mdata->ipaddr);
+		break;
+
+	case CTDB_SRVID_SET_NODE_FLAGS:
+		len = ctdb_node_flag_change_len(mdata->flag_change);
+		break;
+
+	case CTDB_SRVID_RECD_UPDATE_IP:
+		len = ctdb_public_ip_len(mdata->pubip);
+		break;
+
+	case CTDB_SRVID_VACUUM_FETCH:
+		len = ctdb_rec_buffer_len(mdata->recbuf);
+		break;
+
+	case CTDB_SRVID_DETACH_DATABASE:
+		len = ctdb_uint32_len(mdata->db_id);
+		break;
+
+	case CTDB_SRVID_MEM_DUMP:
+		len = ctdb_srvid_message_len(mdata->msg);
+		break;
+
+	case CTDB_SRVID_PUSH_NODE_FLAGS:
+		len = ctdb_node_flag_change_len(mdata->flag_change);
+		break;
+
+	case CTDB_SRVID_RELOAD_NODES:
+		break;
+
+	case CTDB_SRVID_TAKEOVER_RUN:
+		len = ctdb_srvid_message_len(mdata->msg);
+		break;
+
+	case CTDB_SRVID_REBALANCE_NODE:
+		len = ctdb_uint32_len(mdata->pnn);
+		break;
+
+	case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
+		len = ctdb_disable_message_len(mdata->disable);
+		break;
+
+	case CTDB_SRVID_DISABLE_RECOVERIES:
+		len = ctdb_disable_message_len(mdata->disable);
+		break;
+
+	case CTDB_SRVID_DISABLE_IP_CHECK:
+		len = ctdb_uint32_len(mdata->timeout);
+		break;
+
+	default:
+		len = ctdb_tdb_data_len(mdata->data);
+		break;
+	}
+
+	return len;
+}
+
+static void ctdb_message_data_push(union ctdb_message_data *mdata,
+				   uint64_t srvid, uint8_t *buf)
+{
+	switch (srvid) {
+	case CTDB_SRVID_ELECTION:
+		ctdb_election_message_push(mdata->election, buf);
+		break;
+
+	case CTDB_SRVID_RECONFIGURE:
+		break;
+
+	case CTDB_SRVID_RELEASE_IP:
+		ctdb_string_push(mdata->ipaddr, buf);
+		break;
+
+	case CTDB_SRVID_TAKE_IP:
+		ctdb_string_push(mdata->ipaddr, buf);
+		break;
+
+	case CTDB_SRVID_SET_NODE_FLAGS:
+		ctdb_node_flag_change_push(mdata->flag_change, buf);
+		break;
+
+	case CTDB_SRVID_RECD_UPDATE_IP:
+		ctdb_public_ip_push(mdata->pubip, buf);
+		break;
+
+	case CTDB_SRVID_VACUUM_FETCH:
+		ctdb_rec_buffer_push(mdata->recbuf, buf);
+		break;
+
+	case CTDB_SRVID_DETACH_DATABASE:
+		ctdb_uint32_push(mdata->db_id, buf);
+		break;
+
+	case CTDB_SRVID_MEM_DUMP:
+		ctdb_srvid_message_push(mdata->msg, buf);
+		break;
+
+	case CTDB_SRVID_PUSH_NODE_FLAGS:
+		ctdb_node_flag_change_push(mdata->flag_change, buf);
+		break;
+
+	case CTDB_SRVID_RELOAD_NODES:
+		break;
+
+	case CTDB_SRVID_TAKEOVER_RUN:
+		ctdb_srvid_message_push(mdata->msg, buf);
+		break;
+
+	case CTDB_SRVID_REBALANCE_NODE:
+		ctdb_uint32_push(mdata->pnn, buf);
+		break;
+
+	case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
+		ctdb_disable_message_push(mdata->disable, buf);
+		break;
+
+	case CTDB_SRVID_DISABLE_RECOVERIES:
+		ctdb_disable_message_push(mdata->disable, buf);
+		break;
+
+	case CTDB_SRVID_DISABLE_IP_CHECK:
+		ctdb_uint32_push(mdata->timeout, buf);
+		break;
+
+	default:
+		ctdb_tdb_data_push(mdata->data, buf);
+		break;
+	}
+}
+
+static int ctdb_message_data_pull(uint8_t *buf, size_t buflen,
+				  uint64_t srvid, TALLOC_CTX *mem_ctx,
+				  union ctdb_message_data *mdata)
+{
+	int ret = 0;
+
+	switch (srvid) {
+	case CTDB_SRVID_ELECTION:
+		ret = ctdb_election_message_pull(buf, buflen, mem_ctx,
+						 &mdata->election);
+		break;
+
+	case CTDB_SRVID_RECONFIGURE:
+		break;
+
+	case CTDB_SRVID_RELEASE_IP:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr);
+		break;
+
+	case CTDB_SRVID_TAKE_IP:
+		ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr);
+		break;
+
+	case CTDB_SRVID_SET_NODE_FLAGS:
+		ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
+						 &mdata->flag_change);
+		break;
+
+	case CTDB_SRVID_RECD_UPDATE_IP:
+		ret = ctdb_public_ip_pull(buf, buflen, mem_ctx,
+					  &mdata->pubip);
+		break;
+
+	case CTDB_SRVID_VACUUM_FETCH:
+		ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+					   &mdata->recbuf);
+		break;
+
+	case CTDB_SRVID_DETACH_DATABASE:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &mdata->db_id);
+		break;
+
+	case CTDB_SRVID_MEM_DUMP:
+		ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx,
+					      &mdata->msg);
+		break;
+
+	case CTDB_SRVID_PUSH_NODE_FLAGS:
+		ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
+						 &mdata->flag_change);
+		break;
+
+	case CTDB_SRVID_RELOAD_NODES:
+		break;
+
+	case CTDB_SRVID_TAKEOVER_RUN:
+		ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx,
+					      &mdata->msg);
+		break;
+
+	case CTDB_SRVID_REBALANCE_NODE:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &mdata->pnn);
+		break;
+
+	case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
+		ret = ctdb_disable_message_pull(buf, buflen, mem_ctx,
+						&mdata->disable);
+		break;
+
+	case CTDB_SRVID_DISABLE_RECOVERIES:
+		ret = ctdb_disable_message_pull(buf, buflen, mem_ctx,
+						&mdata->disable);
+		break;
+
+	case CTDB_SRVID_DISABLE_IP_CHECK:
+		ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &mdata->timeout);
+		break;
+
+	default:
+		ret = ctdb_tdb_data_pull(buf, buflen, mem_ctx, &mdata->data);
+		break;
+	}
+
+	return ret;
+}
+
+int ctdb_req_message_push(struct ctdb_req_header *h,
+			  struct ctdb_req_message *message,
+			  TALLOC_CTX *mem_ctx,
+			  uint8_t **pkt, size_t *pkt_len)
+{
+	struct ctdb_req_message_wire *wire;
+	uint8_t *buf;
+	size_t length, buflen, datalen;
+	int ret;
+
+	datalen = ctdb_message_data_len(&message->data, message->srvid);
+	length = offsetof(struct ctdb_req_message_wire, data) + datalen;
+
+	ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	wire = (struct ctdb_req_message_wire *)buf;
+
+	h->length = buflen;
+	memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+	wire->srvid = message->srvid;
+	wire->datalen = datalen;
+	ctdb_message_data_push(&message->data, message->srvid, wire->data);
+
+	*pkt = buf;
+	*pkt_len = buflen;
+	return 0;
+}
+
+int ctdb_req_message_pull(uint8_t *pkt, size_t pkt_len,
+			  struct ctdb_req_header *h,
+			  TALLOC_CTX *mem_ctx,
+			  struct ctdb_req_message *message)
+{
+	struct ctdb_req_message_wire *wire =
+		(struct ctdb_req_message_wire *)pkt;
+	size_t length;
+	int ret;
+
+	length = offsetof(struct ctdb_req_message_wire, data);
+
+	if (pkt_len < length) {
+		return EMSGSIZE;
+	}
+	if (pkt_len < length + wire->datalen) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+	message->srvid = wire->srvid;
+	ret = ctdb_message_data_pull(wire->data, wire->datalen, wire->srvid,
+				     mem_ctx, &message->data);
+	return ret;
+}
+
+int ctdb_req_message_data_push(struct ctdb_req_header *h,
+			       struct ctdb_req_message_data *message,
+			       TALLOC_CTX *mem_ctx,
+			       uint8_t **pkt, size_t *pkt_len)
+{
+	struct ctdb_req_message_wire *wire;
+	uint8_t *buf;
+	size_t length, buflen;
+	int ret;
+
+	length = offsetof(struct ctdb_req_message_wire, data) +
+		 message->data.dsize;
+
+	ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	wire = (struct ctdb_req_message_wire *)buf;
+
+	h->length = buflen;
+	memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+	wire->srvid = message->srvid;
+	wire->datalen = message->data.dsize;
+	if (message->data.dsize > 0) {
+		memcpy(wire->data, message->data.dptr, message->data.dsize);
+	}
+
+	*pkt = buf;
+	*pkt_len = buflen;
+	return 0;
+}
+
+int ctdb_req_message_data_pull(uint8_t *pkt, size_t pkt_len,
+			       struct ctdb_req_header *h,
+			       TALLOC_CTX *mem_ctx,
+			       struct ctdb_req_message_data *message)
+{
+	struct ctdb_req_message_wire *wire =
+		(struct ctdb_req_message_wire *)pkt;
+	size_t length;
+
+	length = offsetof(struct ctdb_req_message_wire, data);
+
+	if (pkt_len < length) {
+		return EMSGSIZE;
+	}
+	if (pkt_len < length + wire->datalen) {
+		return EMSGSIZE;
+	}
+
+	memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+	message->srvid = wire->srvid;
+	message->data.dsize = wire->datalen;
+	if (wire->datalen > 0) {
+		message->data.dptr = talloc_memdup(mem_ctx, wire->data,
+						   wire->datalen);
+		if (message->data.dptr == NULL) {
+			return ENOMEM;
+		}
+	}
+
+	return 0;
+}
diff --git a/ctdb/protocol/protocol_packet.c b/ctdb/protocol/protocol_packet.c
new file mode 100644
index 0000000..0e1a61c
--- /dev/null
+++ b/ctdb/protocol/protocol_packet.c
@@ -0,0 +1,44 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol_private.h"
+
+#define CTDB_DS_ALIGNMENT 8
+
+int allocate_pkt(TALLOC_CTX *mem_ctx, size_t length,
+		 uint8_t **buf, size_t *buflen)
+{
+	size_t new_length;
+
+	new_length = (length + CTDB_DS_ALIGNMENT-1) & ~(CTDB_DS_ALIGNMENT-1);
+
+	*buflen = new_length;
+	*buf = talloc_zero_size(mem_ctx, new_length);
+	if (*buf == NULL) {
+		return ENOMEM;
+	}
+
+	return 0;
+}
diff --git a/ctdb/protocol/protocol_private.h b/ctdb/protocol/protocol_private.h
new file mode 100644
index 0000000..65193d9
--- /dev/null
+++ b/ctdb/protocol/protocol_private.h
@@ -0,0 +1,279 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __PROTOCOL_PRIVATE_H__
+#define __PROTOCOL_PRIVATE_H__
+
+#include "protocol.h"
+
+int allocate_pkt(TALLOC_CTX *mem_ctx, size_t length,
+		 uint8_t **buf, size_t *buflen);
+
+size_t ctdb_uint32_len(uint32_t val);
+void ctdb_uint32_push(uint32_t val, uint8_t *buf);
+int ctdb_uint32_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     uint32_t *out);
+
+size_t ctdb_uint64_len(uint64_t val);
+void ctdb_uint64_push(uint64_t val, uint8_t *buf);
+int ctdb_uint64_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     uint64_t *out);
+
+size_t ctdb_double_len(double val);
+void ctdb_double_push(double val, uint8_t *buf);
+int ctdb_double_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     double *out);
+
+size_t ctdb_uint8_array_len(struct ctdb_uint8_array *array);
+void ctdb_uint8_array_push(struct ctdb_uint8_array *array, uint8_t *buf);
+int ctdb_uint8_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_uint8_array **out);
+
+size_t ctdb_uint64_array_len(struct ctdb_uint64_array *array);
+void ctdb_uint64_array_push(struct ctdb_uint64_array *array, uint8_t *buf);
+int ctdb_uint64_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			   struct ctdb_uint64_array **out);
+
+size_t ctdb_pid_len(pid_t pid);
+void ctdb_pid_push(pid_t pid, uint8_t *buf);
+int ctdb_pid_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		  pid_t *out);
+
+size_t ctdb_string_len(const char *str);
+void ctdb_string_push(const char *str, uint8_t *buf);
+int ctdb_string_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     const char **out);
+
+size_t ctdb_stringn_len(const char *str);
+void ctdb_stringn_push(const char *str, uint8_t *buf);
+int ctdb_stringn_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		      const char **out);
+
+size_t ctdb_statistics_len(struct ctdb_statistics *stats);
+void ctdb_statistics_push(struct ctdb_statistics *stats, uint8_t *buf);
+int ctdb_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			 struct ctdb_statistics **out);
+
+size_t ctdb_statistics_list_len(struct ctdb_statistics_list *stats_list);
+void ctdb_statistics_list_push(struct ctdb_statistics_list *stats_list,
+			       uint8_t *buf);
+int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			      struct ctdb_statistics_list **out);
+
+size_t ctdb_vnn_map_len(struct ctdb_vnn_map *vnnmap);
+void ctdb_vnn_map_push(struct ctdb_vnn_map *vnnmap, uint8_t *buf);
+int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		      struct ctdb_vnn_map **out);
+
+size_t ctdb_dbid_map_len(struct ctdb_dbid_map *dbmap);
+void ctdb_dbid_map_push(struct ctdb_dbid_map *dbmap, uint8_t *buf);
+int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_dbid_map **out);
+
+size_t ctdb_pulldb_len(struct ctdb_pulldb *pulldb);
+void ctdb_pulldb_push(struct ctdb_pulldb *pulldb, uint8_t *buf);
+int ctdb_pulldb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     struct ctdb_pulldb **out);
+
+size_t ctdb_traverse_start_len(struct ctdb_traverse_start *traverse);
+void ctdb_traverse_start_push(struct ctdb_traverse_start *traverse,
+			      uint8_t *buf);
+int ctdb_traverse_start_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			     struct ctdb_traverse_start **out);
+
+size_t ctdb_traverse_all_len(struct ctdb_traverse_all *traverse);
+void ctdb_traverse_all_push(struct ctdb_traverse_all *traverse, uint8_t *buf);
+int ctdb_traverse_all_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			   struct ctdb_traverse_all **out);
+
+size_t ctdb_traverse_start_ext_len(struct ctdb_traverse_start_ext *traverse);
+void ctdb_traverse_start_ext_push(struct ctdb_traverse_start_ext *traverse,
+				  uint8_t *buf);
+int ctdb_traverse_start_ext_pull(uint8_t *buf, size_t buflen,
+				 TALLOC_CTX *mem_ctx,
+				 struct ctdb_traverse_start_ext **out);
+
+size_t ctdb_traverse_all_ext_len(struct ctdb_traverse_all_ext *traverse);
+void ctdb_traverse_all_ext_push(struct ctdb_traverse_all_ext *traverse,
+				uint8_t *buf);
+int ctdb_traverse_all_ext_pull(uint8_t *buf, size_t buflen,
+			       TALLOC_CTX *mem_ctx,
+			       struct ctdb_traverse_all_ext **out);
+
+size_t ctdb_sock_addr_len(ctdb_sock_addr *addr);
+void ctdb_sock_addr_push(ctdb_sock_addr *addr, uint8_t *buf);
+int ctdb_sock_addr_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			ctdb_sock_addr **out);
+
+size_t ctdb_connection_len(struct ctdb_connection *conn);
+void ctdb_connection_push(struct ctdb_connection *conn, uint8_t *buf);
+int ctdb_connection_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			 struct ctdb_connection **out);
+
+size_t ctdb_tunable_len(struct ctdb_tunable *tunable);
+void ctdb_tunable_push(struct ctdb_tunable *tunable, uint8_t *buf);
+int ctdb_tunable_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		      struct ctdb_tunable **out);
+
+size_t ctdb_node_flag_change_len(struct ctdb_node_flag_change *flag_change);
+void ctdb_node_flag_change_push(struct ctdb_node_flag_change *flag_change,
+				uint8_t *buf);
+int ctdb_node_flag_change_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			       struct ctdb_node_flag_change **out);
+
+size_t ctdb_var_list_len(struct ctdb_var_list *var_list);
+void ctdb_var_list_push(struct ctdb_var_list *var_list, uint8_t *buf);
+int ctdb_var_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_var_list **out);
+
+size_t ctdb_tunable_list_len(struct ctdb_tunable_list *tun_list);
+void ctdb_tunable_list_push(struct ctdb_tunable_list *tun_list, uint8_t *buf);
+int ctdb_tunable_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			   struct ctdb_tunable_list **out);
+
+size_t ctdb_tickle_list_len(struct ctdb_tickle_list *tickles);
+void ctdb_tickle_list_push(struct ctdb_tickle_list *tickles, uint8_t *buf);
+int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_tickle_list **out);
+
+size_t ctdb_client_id_len(struct ctdb_client_id *cid);
+void ctdb_client_id_push(struct ctdb_client_id *cid, uint8_t *buf);
+int ctdb_client_id_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			struct ctdb_client_id **out);
+
+size_t ctdb_client_id_list_len(struct ctdb_client_id_list *cid_list);
+void ctdb_client_id_list_push(struct ctdb_client_id_list *cid_list,
+			      uint8_t *buf);
+int ctdb_client_id_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			     struct ctdb_client_id_list **out);
+
+size_t ctdb_client_id_map_len(struct ctdb_client_id_map *cid_map);
+void ctdb_client_id_map_push(struct ctdb_client_id_map *cid_map, uint8_t *buf);
+int ctdb_client_id_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			    struct ctdb_client_id_map **out);
+
+size_t ctdb_addr_info_len(struct ctdb_addr_info *addr_info);
+void ctdb_addr_info_push(struct ctdb_addr_info *addr_info, uint8_t *buf);
+int ctdb_addr_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			struct ctdb_addr_info **out);
+
+size_t ctdb_transdb_len(struct ctdb_transdb *transdb);
+void ctdb_transdb_push(struct ctdb_transdb *transdb, uint8_t *buf);
+int ctdb_transdb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     struct ctdb_transdb **out);
+
+size_t ctdb_uptime_len(struct ctdb_uptime *uptime);
+void ctdb_uptime_push(struct ctdb_uptime *uptime, uint8_t *buf);
+int ctdb_uptime_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     struct ctdb_uptime **out);
+
+size_t ctdb_public_ip_len(struct ctdb_public_ip *public_ip);
+void ctdb_public_ip_push(struct ctdb_public_ip *public_ip, uint8_t *buf);
+int ctdb_public_ip_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			struct ctdb_public_ip **out);
+
+size_t ctdb_public_ip_list_len(struct ctdb_public_ip_list *pubip_list);
+void ctdb_public_ip_list_push(struct ctdb_public_ip_list *pubip_list,
+			      uint8_t *buf);
+int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			     struct ctdb_public_ip_list **out);
+
+size_t ctdb_node_and_flags_len(struct ctdb_node_and_flags *node);
+void ctdb_node_and_flags_push(struct ctdb_node_and_flags *node, uint8_t *buf);
+int ctdb_node_and_flags_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			     struct ctdb_node_and_flags **out);
+
+size_t ctdb_node_map_len(struct ctdb_node_map *nodemap);
+void ctdb_node_map_push(struct ctdb_node_map *nodemap, uint8_t *buf);
+int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_node_map **out);
+
+size_t ctdb_script_len(struct ctdb_script *script);
+void ctdb_script_push(struct ctdb_script *script, uint8_t *buf);
+int ctdb_script_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     struct ctdb_script **out);
+
+size_t ctdb_script_list_len(struct ctdb_script_list *script_list);
+void ctdb_script_list_push(struct ctdb_script_list *script_list, uint8_t *buf);
+int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_script_list **out);
+
+size_t ctdb_ban_state_len(struct ctdb_ban_state *ban_state);
+void ctdb_ban_state_push(struct ctdb_ban_state *ban_state, uint8_t *buf);
+int ctdb_ban_state_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			struct ctdb_ban_state **out);
+
+size_t ctdb_db_priority_len(struct ctdb_db_priority *db_prio);
+void ctdb_db_priority_push(struct ctdb_db_priority *db_prio, uint8_t *buf);
+int ctdb_db_priority_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_db_priority **out);
+
+size_t ctdb_notify_data_len(struct ctdb_notify_data *notify);
+void ctdb_notify_data_push(struct ctdb_notify_data *notify, uint8_t *buf);
+int ctdb_notify_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_notify_data **out);
+
+size_t ctdb_iface_len(struct ctdb_iface *iface);
+void ctdb_iface_push(struct ctdb_iface *iface, uint8_t *buf);
+int ctdb_iface_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		    struct ctdb_iface **out);
+
+size_t ctdb_iface_list_len(struct ctdb_iface_list *iface_list);
+void ctdb_iface_list_push(struct ctdb_iface_list *iface_list, uint8_t *buf);
+int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			 struct ctdb_iface_list **out);
+
+size_t ctdb_public_ip_info_len(struct ctdb_public_ip_info *ipinfo);
+void ctdb_public_ip_info_push(struct ctdb_public_ip_info *ipinfo, uint8_t *buf);
+int ctdb_public_ip_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			     struct ctdb_public_ip_info **out);
+
+size_t ctdb_key_data_len(struct ctdb_key_data *key);
+void ctdb_key_data_push(struct ctdb_key_data *key, uint8_t *buf);
+int ctdb_key_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_key_data **out);
+
+size_t ctdb_db_statistics_len(struct ctdb_db_statistics *dbstats);
+void ctdb_db_statistics_push(struct ctdb_db_statistics *dbstats, void *buf);
+int ctdb_db_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			    struct ctdb_db_statistics **out);
+
+size_t ctdb_election_message_len(struct ctdb_election_message *election);
+void ctdb_election_message_push(struct ctdb_election_message *election,
+				uint8_t *buf);
+int ctdb_election_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			       struct ctdb_election_message **out);
+
+size_t ctdb_srvid_message_len(struct ctdb_srvid_message *msg);
+void ctdb_srvid_message_push(struct ctdb_srvid_message *msg, uint8_t *buf);
+int ctdb_srvid_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			    struct ctdb_srvid_message **out);
+
+size_t ctdb_tdb_data_len(TDB_DATA data);
+void ctdb_tdb_data_push(TDB_DATA data, uint8_t *buf);
+int ctdb_tdb_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       TDB_DATA *out);
+
+size_t ctdb_disable_message_len(struct ctdb_disable_message *disable);
+void ctdb_disable_message_push(struct ctdb_disable_message *disable,
+			       uint8_t *buf);
+int ctdb_disable_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			      struct ctdb_disable_message **out);
+
+#endif /* __PROTOCOL_PRIVATE_H__ */
diff --git a/ctdb/protocol/protocol_types.c b/ctdb/protocol/protocol_types.c
new file mode 100644
index 0000000..e36d2e8
--- /dev/null
+++ b/ctdb/protocol/protocol_types.c
@@ -0,0 +1,2575 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_private.h"
+#include "protocol_api.h"
+
+size_t ctdb_uint32_len(uint32_t val)
+{
+	return sizeof(uint32_t);
+}
+
+void ctdb_uint32_push(uint32_t val, uint8_t *buf)
+{
+	memcpy(buf, &val, sizeof(uint32_t));
+}
+
+int ctdb_uint32_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     uint32_t *out)
+{
+	if (buflen < sizeof(uint32_t)) {
+		return EMSGSIZE;
+	}
+
+	*out = *(uint32_t *)buf;
+	return 0;
+}
+
+size_t ctdb_uint64_len(uint64_t val)
+{
+	return sizeof(uint64_t);
+}
+
+void ctdb_uint64_push(uint64_t val, uint8_t *buf)
+{
+	memcpy(buf, &val, sizeof(uint64_t));
+}
+
+int ctdb_uint64_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     uint64_t *out)
+{
+	if (buflen < sizeof(uint64_t)) {
+		return EMSGSIZE;
+	}
+
+	*out = *(uint64_t *)buf;
+	return 0;
+}
+
+size_t ctdb_double_len(double val)
+{
+	return sizeof(double);
+}
+
+void ctdb_double_push(double val, uint8_t *buf)
+{
+	memcpy(buf, &val, sizeof(double));
+}
+
+int ctdb_double_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     double *out)
+{
+	if (buflen < sizeof(double)) {
+		return EMSGSIZE;
+	}
+
+	*out = *(double *)buf;
+	return 0;
+}
+
+size_t ctdb_uint8_array_len(struct ctdb_uint8_array *array)
+{
+	return array->num * sizeof(uint8_t);
+}
+
+void ctdb_uint8_array_push(struct ctdb_uint8_array *array, uint8_t *buf)
+{
+	memcpy(buf, array->val, array->num * sizeof(uint8_t));
+}
+
+int ctdb_uint8_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_uint8_array **out)
+{
+	struct ctdb_uint8_array *array;
+
+	array = talloc(mem_ctx, struct ctdb_uint8_array);
+	if (array == NULL) {
+		return ENOMEM;
+	}
+
+	array->num = buflen / sizeof(uint8_t);
+
+	array->val = talloc_array(array, uint8_t, array->num);
+	if (array->val == NULL) {
+		talloc_free(array);
+		return ENOMEM;
+	}
+	memcpy(array->val, buf, buflen);
+
+	*out = array;
+	return 0;
+}
+
+size_t ctdb_uint64_array_len(struct ctdb_uint64_array *array)
+{
+	return array->num * sizeof(uint64_t);
+}
+
+void ctdb_uint64_array_push(struct ctdb_uint64_array *array, uint8_t *buf)
+{
+	memcpy(buf, array->val, array->num * sizeof(uint64_t));
+}
+
+int ctdb_uint64_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			   struct ctdb_uint64_array **out)
+{
+	struct ctdb_uint64_array *array;
+
+	array = talloc(mem_ctx, struct ctdb_uint64_array);
+	if (array == NULL) {
+		return ENOMEM;
+	}
+
+	array->num = buflen / sizeof(uint64_t);
+
+	array->val = talloc_array(array, uint64_t, array->num);
+	if (array->val == NULL) {
+		talloc_free(array);
+		return ENOMEM;
+	}
+	memcpy(array->val, buf, buflen);
+
+	*out = array;
+	return 0;
+}
+
+size_t ctdb_pid_len(pid_t pid)
+{
+	return sizeof(pid_t);
+}
+
+void ctdb_pid_push(pid_t pid, uint8_t *buf)
+{
+	memcpy(buf, &pid, sizeof(pid_t));
+}
+
+int ctdb_pid_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		  pid_t *out)
+{
+	if (buflen < sizeof(pid_t)) {
+		return EMSGSIZE;
+	}
+
+	*out = *(pid_t *)buf;
+	return 0;
+}
+
+size_t ctdb_string_len(const char *str)
+{
+	if (str == NULL) {
+		return 0;
+	}
+	return strlen(str) + 1;
+}
+
+void ctdb_string_push(const char *str, uint8_t *buf)
+{
+	if (str == NULL) {
+		return;
+	}
+	memcpy(buf, str, strlen(str)+1);
+}
+
+int ctdb_string_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     const char **out)
+{
+	char *str;
+
+	if (buflen == 0) {
+		return 0;
+	}
+
+	str = talloc_strndup(mem_ctx, (char *)buf, buflen);
+	if (str == NULL) {
+		return ENOMEM;
+	}
+
+	*out = str;
+	return 0;
+}
+
+struct stringn_wire {
+	uint32_t length;
+	uint8_t str[1];
+};
+
+size_t ctdb_stringn_len(const char *str)
+{
+	return sizeof(uint32_t) + strlen(str) + 1;
+}
+
+void ctdb_stringn_push(const char *str, uint8_t *buf)
+{
+	struct stringn_wire *wire = (struct stringn_wire *)buf;
+
+	if (str == NULL) {
+		wire->length = 0;
+	} else {
+		wire->length = strlen(str) + 1;
+		memcpy(wire->str, str, wire->length);
+	}
+}
+
+int ctdb_stringn_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		      const char **out)
+{
+	char *str;
+	struct stringn_wire *wire = (struct stringn_wire *)buf;
+
+	if (buflen < sizeof(uint32_t)) {
+		return EMSGSIZE;
+	}
+
+	if (buflen < sizeof(uint32_t) + wire->length) {
+		return EMSGSIZE;
+	}
+
+	str = talloc_strndup(mem_ctx, (char *)wire->str, wire->length);
+	if (str == NULL) {
+		return ENOMEM;
+	}
+
+	*out = str;
+	return 0;
+}
+
+size_t ctdb_statistics_len(struct ctdb_statistics *stats)
+{
+	return sizeof(struct ctdb_statistics);
+}
+
+void ctdb_statistics_push(struct ctdb_statistics *stats, uint8_t *buf)
+{
+	memcpy(buf, stats, sizeof(struct ctdb_statistics));
+}
+
+int ctdb_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			 struct ctdb_statistics **out)
+{
+	struct ctdb_statistics *stats;
+	struct ctdb_statistics *wire = (struct ctdb_statistics *)buf;
+
+	if (buflen < sizeof(struct ctdb_statistics)) {
+		return EMSGSIZE;
+	}
+
+	stats = talloc(mem_ctx, struct ctdb_statistics);
+	if (stats == NULL) {
+		return ENOMEM;
+	}
+	memcpy(stats, wire, sizeof(struct ctdb_statistics));
+
+	*out = stats;
+	return 0;
+}
+
+struct ctdb_statistics_list_wire {
+	uint32_t num;
+	struct ctdb_statistics stats[1];
+};
+
+size_t ctdb_statistics_list_len(struct ctdb_statistics_list *stats_list)
+{
+	return offsetof(struct ctdb_statistics_list_wire, stats) +
+	       stats_list->num * sizeof(struct ctdb_statistics);
+}
+
+void ctdb_statistics_list_push(struct ctdb_statistics_list *stats_list,
+			       uint8_t *buf)
+{
+	struct ctdb_statistics_list_wire *wire =
+		(struct ctdb_statistics_list_wire *)buf;
+
+	wire->num = stats_list->num;
+	memcpy(wire->stats, stats_list->stats,
+	       stats_list->num * sizeof(struct ctdb_statistics));
+}
+
+int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			      struct ctdb_statistics_list **out)
+{
+	struct ctdb_statistics_list *stats_list;
+	struct ctdb_statistics_list_wire *wire =
+		(struct ctdb_statistics_list_wire *)buf;
+
+	if (buflen < offsetof(struct ctdb_statistics_list_wire, stats)) {
+		return EMSGSIZE;
+	}
+	if (buflen < offsetof(struct ctdb_statistics_list_wire, stats) +
+		     wire->num * sizeof(struct ctdb_statistics)) {
+		return EMSGSIZE;
+	}
+
+	stats_list = talloc(mem_ctx, struct ctdb_statistics_list);
+	if (stats_list == NULL) {
+		return ENOMEM;
+	}
+
+	stats_list->num = wire->num;
+
+	stats_list->stats = talloc_array(stats_list, struct ctdb_statistics,
+					 wire->num);
+	if (stats_list->stats == NULL) {
+		talloc_free(stats_list);
+		return ENOMEM;
+	}
+
+	memcpy(stats_list->stats, wire->stats,
+	       wire->num * sizeof(struct ctdb_statistics));
+
+	*out = stats_list;
+	return 0;
+}
+
+struct ctdb_vnn_map_wire {
+	uint32_t generation;
+	uint32_t size;
+	uint32_t map[1];
+};
+
+size_t ctdb_vnn_map_len(struct ctdb_vnn_map *vnnmap)
+{
+	return offsetof(struct ctdb_vnn_map, map) +
+	       vnnmap->size * sizeof(uint32_t);
+}
+
+void ctdb_vnn_map_push(struct ctdb_vnn_map *vnnmap, uint8_t *buf)
+{
+	struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf;
+
+	memcpy(wire, vnnmap, offsetof(struct ctdb_vnn_map, map));
+	memcpy(wire->map, vnnmap->map, vnnmap->size * sizeof(uint32_t));
+}
+
+int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		      struct ctdb_vnn_map **out)
+{
+	struct ctdb_vnn_map *vnnmap;
+	struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf;
+
+	if (buflen < offsetof(struct ctdb_vnn_map_wire, map)) {
+		return EMSGSIZE;
+	}
+	if (buflen < offsetof(struct ctdb_vnn_map_wire, map) +
+		     wire->size * sizeof(uint32_t)) {
+		return EMSGSIZE;
+	}
+
+	vnnmap = talloc(mem_ctx, struct ctdb_vnn_map);
+	if (vnnmap == NULL) {
+		return ENOMEM;
+	}
+
+	memcpy(vnnmap, wire, offsetof(struct ctdb_vnn_map, map));
+
+	vnnmap->map = talloc_memdup(vnnmap, wire->map,
+				    wire->size * sizeof(uint32_t));
+	if (vnnmap->map == NULL) {
+		talloc_free(vnnmap);
+		return ENOMEM;
+	}
+
+	*out = vnnmap;
+	return 0;
+}
+
+struct ctdb_dbid_map_wire {
+	uint32_t num;
+	struct ctdb_dbid dbs[1];
+};
+
+size_t ctdb_dbid_map_len(struct ctdb_dbid_map *dbmap)
+{
+	return sizeof(uint32_t) + dbmap->num * sizeof(struct ctdb_dbid);
+}
+
+void ctdb_dbid_map_push(struct ctdb_dbid_map *dbmap, uint8_t *buf)
+{
+	struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf;
+
+	wire->num = dbmap->num;
+	memcpy(wire->dbs, dbmap->dbs, dbmap->num * sizeof(struct ctdb_dbid));
+}
+
+int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_dbid_map **out)
+{
+	struct ctdb_dbid_map *dbmap;
+	struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf;
+
+	if (buflen < sizeof(uint32_t)) {
+		return EMSGSIZE;
+	}
+	if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_dbid)) {
+		return EMSGSIZE;
+	}
+
+	dbmap = talloc(mem_ctx, struct ctdb_dbid_map);
+	if (dbmap == NULL) {
+		return ENOMEM;
+	}
+
+	dbmap->num = wire->num;
+
+	dbmap->dbs = talloc_memdup(dbmap, wire->dbs,
+				   wire->num * sizeof(struct ctdb_dbid));
+	if (dbmap->dbs == NULL) {
+		talloc_free(dbmap);
+		return ENOMEM;
+	}
+
+	*out = dbmap;
+	return 0;
+}
+
+size_t ctdb_pulldb_len(struct ctdb_pulldb *pulldb)
+{
+	return sizeof(struct ctdb_pulldb);
+}
+
+void ctdb_pulldb_push(struct ctdb_pulldb *pulldb, uint8_t *buf)
+{
+	memcpy(buf, pulldb, sizeof(struct ctdb_pulldb));
+}
+
+int ctdb_pulldb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     struct ctdb_pulldb **out)
+{
+	struct ctdb_pulldb *pulldb;
+
+	if (buflen < sizeof(struct ctdb_pulldb)) {
+		return EMSGSIZE;
+	}
+
+	pulldb = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_pulldb));
+	if (pulldb == NULL) {
+		return ENOMEM;
+	}
+
+	*out = pulldb;
+	return 0;
+}
+
+size_t ctdb_ltdb_header_len(struct ctdb_ltdb_header *header)
+{
+	return sizeof(struct ctdb_ltdb_header);
+}
+
+void ctdb_ltdb_header_push(struct ctdb_ltdb_header *header, uint8_t *buf)
+{
+	memcpy(buf, header, sizeof(struct ctdb_ltdb_header));
+}
+
+int ctdb_ltdb_header_pull(uint8_t *buf, size_t buflen,
+			  struct ctdb_ltdb_header *header)
+{
+	if (buflen < sizeof(struct ctdb_ltdb_header)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(header, buf, sizeof(struct ctdb_ltdb_header));
+	return 0;
+}
+
+int ctdb_ltdb_header_extract(TDB_DATA *data, struct ctdb_ltdb_header *header)
+{
+	int ret;
+
+	ret = ctdb_ltdb_header_pull(data->dptr, data->dsize, header);
+	if (ret != 0) {
+		return ret;
+	}
+
+	data->dptr += sizeof(struct ctdb_ltdb_header);
+	data->dsize -= sizeof(struct ctdb_ltdb_header);
+
+	return 0;
+}
+
+struct ctdb_rec_data_wire {
+	uint32_t length;
+	uint32_t reqid;
+	uint32_t keylen;
+	uint32_t datalen;
+	uint8_t data[1];
+};
+
+size_t ctdb_rec_data_len(struct ctdb_rec_data *rec)
+{
+	return offsetof(struct ctdb_rec_data_wire, data) +
+	       rec->key.dsize + rec->data.dsize +
+	       (rec->header == NULL ? 0 : sizeof(struct ctdb_ltdb_header));
+}
+
+void ctdb_rec_data_push(struct ctdb_rec_data *rec, uint8_t *buf)
+{
+	struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf;
+	size_t offset;
+
+	wire->length = ctdb_rec_data_len(rec);
+	wire->reqid = rec->reqid;
+	wire->keylen = rec->key.dsize;
+	wire->datalen = rec->data.dsize;
+	if (rec->header != NULL) {
+		wire->datalen += sizeof(struct ctdb_ltdb_header);
+	}
+
+	memcpy(wire->data, rec->key.dptr, rec->key.dsize);
+	offset = rec->key.dsize;
+	if (rec->header != NULL) {
+		memcpy(&wire->data[offset], rec->header,
+		       sizeof(struct ctdb_ltdb_header));
+		offset += sizeof(struct ctdb_ltdb_header);
+	}
+	if (rec->data.dsize > 0) {
+		memcpy(&wire->data[offset], rec->data.dptr, rec->data.dsize);
+	}
+}
+
+static int ctdb_rec_data_pull_data(uint8_t *buf, size_t buflen,
+				   uint32_t *reqid,
+				   struct ctdb_ltdb_header **header,
+				   TDB_DATA *key, TDB_DATA *data,
+				   size_t *reclen)
+{
+	struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf;
+	size_t offset, n;
+
+	if (buflen < offsetof(struct ctdb_rec_data_wire, data)) {
+		return EMSGSIZE;
+	}
+	n = offsetof(struct ctdb_rec_data_wire, data) +
+		wire->keylen + wire->datalen;
+	if (buflen < n) {
+		return EMSGSIZE;
+	}
+
+	*reqid = wire->reqid;
+
+	key->dsize = wire->keylen;
+	key->dptr = wire->data;
+	offset = wire->keylen;
+
+	/* Always set header to NULL.  If it is required, exact it using
+	 * ctdb_rec_data_extract_header()
+	 */
+	*header = NULL;
+
+	data->dsize = wire->datalen;
+	data->dptr = &wire->data[offset];
+
+	*reclen = n;
+
+	return 0;
+}
+
+static int ctdb_rec_data_pull_elems(uint8_t *buf, size_t buflen,
+				    TALLOC_CTX *mem_ctx,
+				    struct ctdb_rec_data *out)
+{
+	uint32_t reqid;
+	struct ctdb_ltdb_header *header;
+	TDB_DATA key, data;
+	size_t reclen;
+	int ret;
+
+	ret = ctdb_rec_data_pull_data(buf, buflen, &reqid, &header,
+				      &key, &data, &reclen);
+	if (ret != 0) {
+		return ret;
+	}
+
+	out->reqid = reqid;
+	out->header = NULL;
+
+	out->key.dsize = key.dsize;
+	if (key.dsize > 0) {
+		out->key.dptr = talloc_memdup(mem_ctx, key.dptr, key.dsize);
+		if (out->key.dptr == NULL) {
+			return ENOMEM;
+		}
+	}
+
+	out->data.dsize = data.dsize;
+	if (data.dsize > 0) {
+		out->data.dptr = talloc_memdup(mem_ctx, data.dptr, data.dsize);
+		if (out->data.dptr == NULL) {
+			return ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int ctdb_rec_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_rec_data **out)
+{
+	struct ctdb_rec_data *rec;
+	int ret;
+
+	rec = talloc(mem_ctx, struct ctdb_rec_data);
+	if (rec == NULL) {
+		return ENOMEM;
+	}
+
+	ret = ctdb_rec_data_pull_elems(buf, buflen, rec, rec);
+	if (ret != 0) {
+		TALLOC_FREE(rec);
+	}
+
+	*out = rec;
+	return ret;
+}
+
+struct ctdb_rec_buffer_wire {
+	uint32_t db_id;
+	uint32_t count;
+	uint8_t data[1];
+};
+
+size_t ctdb_rec_buffer_len(struct ctdb_rec_buffer *recbuf)
+{
+	return offsetof(struct ctdb_rec_buffer_wire, data) + recbuf->buflen;
+}
+
+void ctdb_rec_buffer_push(struct ctdb_rec_buffer *recbuf, uint8_t *buf)
+{
+	struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf;
+
+	wire->db_id = recbuf->db_id;
+	wire->count = recbuf->count;
+	if (recbuf->buflen > 0) {
+		memcpy(wire->data, recbuf->buf, recbuf->buflen);
+	}
+}
+
+int ctdb_rec_buffer_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			 struct ctdb_rec_buffer **out)
+{
+	struct ctdb_rec_buffer *recbuf;
+	struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf;
+	size_t offset;
+
+	if (buflen < offsetof(struct ctdb_rec_buffer_wire, data)) {
+		return EMSGSIZE;
+	}
+
+	recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+	if (recbuf == NULL) {
+		return ENOMEM;
+	}
+
+	recbuf->db_id = wire->db_id;
+	recbuf->count = wire->count;
+
+	offset = offsetof(struct ctdb_rec_buffer_wire, data);
+	recbuf->buflen = buflen - offset;
+	recbuf->buf = talloc_memdup(recbuf, wire->data, recbuf->buflen);
+	if (recbuf->buf == NULL) {
+		talloc_free(recbuf);
+		return ENOMEM;
+	}
+
+	*out = recbuf;
+	return 0;
+}
+
+struct ctdb_rec_buffer *ctdb_rec_buffer_init(TALLOC_CTX *mem_ctx,
+					     uint32_t db_id)
+{
+	struct ctdb_rec_buffer *recbuf;
+
+	recbuf = talloc_zero(mem_ctx, struct ctdb_rec_buffer);
+	if (recbuf == NULL) {
+		return recbuf;
+	}
+
+	recbuf->db_id = db_id;
+
+	return recbuf;
+}
+
+int ctdb_rec_buffer_add(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *recbuf,
+			uint32_t reqid, struct ctdb_ltdb_header *header,
+			TDB_DATA key, TDB_DATA data)
+{
+	struct ctdb_rec_data recdata;
+	size_t len;
+	uint8_t *ptr;
+
+	recdata.reqid = reqid;
+	recdata.header = header;
+	recdata.key = key;
+	recdata.data = data;
+
+	len = ctdb_rec_data_len(&recdata);
+
+	ptr = talloc_realloc(mem_ctx, recbuf->buf, uint8_t,
+			     recbuf->buflen + len);
+	if (ptr == NULL) {
+		return ENOMEM;
+	}
+
+	ctdb_rec_data_push(&recdata, &ptr[recbuf->buflen]);
+
+	recbuf->count++;
+	recbuf->buf = ptr;
+	recbuf->buflen += len;
+	return 0;
+}
+
+int ctdb_rec_buffer_traverse(struct ctdb_rec_buffer *recbuf,
+			     ctdb_rec_parser_func_t func,
+			     void *private_data)
+{
+	struct ctdb_ltdb_header *header;
+	TDB_DATA key, data;
+	uint32_t reqid;
+	size_t offset, reclen;
+	int ret = 0, i;
+
+	offset = 0;
+	for (i=0; i<recbuf->count; i++) {
+		ret = ctdb_rec_data_pull_data(&recbuf->buf[offset],
+					      recbuf->buflen - offset,
+					      &reqid, &header,
+					      &key, &data, &reclen);
+		if (ret != 0) {
+			return ret;
+		}
+
+		ret = func(reqid, header, key, data, private_data);
+		if (ret != 0) {
+			break;
+		}
+
+		offset += reclen;
+	}
+
+	return ret;
+}
+
+size_t ctdb_traverse_start_len(struct ctdb_traverse_start *traverse)
+{
+	return sizeof(struct ctdb_traverse_start);
+}
+
+void ctdb_traverse_start_push(struct ctdb_traverse_start *traverse,
+			      uint8_t *buf)
+{
+	memcpy(buf, traverse, sizeof(struct ctdb_traverse_start));
+}
+
+int ctdb_traverse_start_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			     struct ctdb_traverse_start **out)
+{
+	struct ctdb_traverse_start *traverse;
+
+	if (buflen < sizeof(struct ctdb_traverse_start)) {
+		return EMSGSIZE;
+	}
+
+	traverse = talloc_memdup(mem_ctx, buf,
+				 sizeof(struct ctdb_traverse_start));
+	if (traverse == NULL) {
+		return ENOMEM;
+	}
+
+	*out = traverse;
+	return 0;
+}
+
+size_t ctdb_traverse_all_len(struct ctdb_traverse_all *traverse)
+{
+	return sizeof(struct ctdb_traverse_all);
+}
+
+void ctdb_traverse_all_push(struct ctdb_traverse_all *traverse, uint8_t *buf)
+{
+	memcpy(buf, traverse, sizeof(struct ctdb_traverse_all));
+}
+
+int ctdb_traverse_all_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			   struct ctdb_traverse_all **out)
+{
+	struct ctdb_traverse_all *traverse;
+
+	if (buflen < sizeof(struct ctdb_traverse_all)) {
+		return EMSGSIZE;
+	}
+
+	traverse = talloc_memdup(mem_ctx, buf,
+				 sizeof(struct ctdb_traverse_all));
+	if (traverse == NULL) {
+		return ENOMEM;
+	}
+
+	*out = traverse;
+	return 0;
+}
+
+size_t ctdb_traverse_start_ext_len(struct ctdb_traverse_start_ext *traverse)
+{
+	return sizeof(struct ctdb_traverse_start_ext);
+}
+
+void ctdb_traverse_start_ext_push(struct ctdb_traverse_start_ext *traverse,
+				  uint8_t *buf)
+{
+	memcpy(buf, traverse, sizeof(struct ctdb_traverse_start_ext));
+}
+
+int ctdb_traverse_start_ext_pull(uint8_t *buf, size_t buflen,
+				 TALLOC_CTX *mem_ctx,
+				 struct ctdb_traverse_start_ext **out)
+{
+	struct ctdb_traverse_start_ext *traverse;
+
+	if (buflen < sizeof(struct ctdb_traverse_start_ext)) {
+		return EMSGSIZE;
+	}
+
+	traverse = talloc_memdup(mem_ctx, buf,
+				 sizeof(struct ctdb_traverse_start_ext));
+	if (traverse == NULL) {
+		return ENOMEM;
+	}
+
+	*out = traverse;
+	return 0;
+}
+
+size_t ctdb_traverse_all_ext_len(struct ctdb_traverse_all_ext *traverse)
+{
+	return sizeof(struct ctdb_traverse_all_ext);
+}
+
+void ctdb_traverse_all_ext_push(struct ctdb_traverse_all_ext *traverse,
+				uint8_t *buf)
+{
+	memcpy(buf, traverse, sizeof(struct ctdb_traverse_all_ext));
+}
+
+int ctdb_traverse_all_ext_pull(uint8_t *buf, size_t buflen,
+			       TALLOC_CTX *mem_ctx,
+			       struct ctdb_traverse_all_ext **out)
+{
+	struct ctdb_traverse_all_ext *traverse;
+
+	if (buflen < sizeof(struct ctdb_traverse_all_ext)) {
+		return EMSGSIZE;
+	}
+
+	traverse = talloc_memdup(mem_ctx, buf,
+				 sizeof(struct ctdb_traverse_all_ext));
+	if (traverse == NULL) {
+		return ENOMEM;
+	}
+
+	*out = traverse;
+	return 0;
+}
+
+size_t ctdb_sock_addr_len(ctdb_sock_addr *addr)
+{
+	return sizeof(ctdb_sock_addr);
+}
+
+void ctdb_sock_addr_push(ctdb_sock_addr *addr, uint8_t *buf)
+{
+	memcpy(buf, addr, sizeof(ctdb_sock_addr));
+}
+
+static int ctdb_sock_addr_pull_elems(uint8_t *buf, size_t buflen,
+				     TALLOC_CTX *mem_ctx, ctdb_sock_addr *out)
+{
+	if (buflen < sizeof(ctdb_sock_addr)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(out, buf, sizeof(ctdb_sock_addr));
+
+	return 0;
+}
+
+int ctdb_sock_addr_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			ctdb_sock_addr **out)
+{
+	ctdb_sock_addr *addr;
+	int ret;
+
+	addr = talloc(mem_ctx, ctdb_sock_addr);
+	if (addr == NULL) {
+		return false;
+	}
+
+	ret = ctdb_sock_addr_pull_elems(buf, buflen, addr, addr);
+	if (ret != 0) {
+		TALLOC_FREE(addr);
+	}
+
+	*out = addr;
+	return ret;
+}
+
+size_t ctdb_connection_len(struct ctdb_connection *conn)
+{
+	return sizeof(struct ctdb_connection);
+}
+
+void ctdb_connection_push(struct ctdb_connection *conn, uint8_t *buf)
+{
+	memcpy(buf, conn, sizeof(struct ctdb_connection));
+}
+
+static int ctdb_connection_pull_elems(uint8_t *buf, size_t buflen,
+				      TALLOC_CTX *mem_ctx,
+				      struct ctdb_connection *out)
+{
+	if (buflen < sizeof(struct ctdb_connection)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(out, buf, sizeof(struct ctdb_connection));
+
+	return 0;
+}
+
+int ctdb_connection_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			 struct ctdb_connection **out)
+{
+	struct ctdb_connection *conn;
+	int ret;
+
+	conn = talloc(mem_ctx, struct ctdb_connection);
+	if (conn == NULL) {
+		return ENOMEM;
+	}
+
+	ret = ctdb_connection_pull_elems(buf, buflen, conn, conn);
+	if (ret != 0) {
+		TALLOC_FREE(conn);
+	}
+
+	*out = conn;
+	return ret;
+}
+
+struct ctdb_tunable_wire {
+	uint32_t value;
+	uint32_t length;
+	uint8_t name[1];
+};
+
+size_t ctdb_tunable_len(struct ctdb_tunable *tunable)
+{
+	return offsetof(struct ctdb_tunable_wire, name) +
+	       strlen(tunable->name) + 1;
+}
+
+void ctdb_tunable_push(struct ctdb_tunable *tunable, uint8_t *buf)
+{
+	struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf;
+
+	wire->value = tunable->value;
+	wire->length = strlen(tunable->name) + 1;
+	memcpy(wire->name, tunable->name, wire->length);
+}
+
+int ctdb_tunable_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		      struct ctdb_tunable **out)
+{
+	struct ctdb_tunable *tunable;
+	struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf;
+
+	if (buflen < offsetof(struct ctdb_tunable_wire, name)) {
+		return EMSGSIZE;
+	}
+	if (buflen < offsetof(struct ctdb_tunable_wire, name) + wire->length) {
+		return EMSGSIZE;
+	}
+
+	tunable = talloc(mem_ctx, struct ctdb_tunable);
+	if (tunable == NULL) {
+		return ENOMEM;
+	}
+
+	tunable->value = wire->value;
+	tunable->name = talloc_memdup(tunable, wire->name, wire->length);
+	if (tunable->name == NULL) {
+		talloc_free(tunable);
+		return ENOMEM;
+	}
+
+	*out = tunable;
+	return 0;
+}
+
+size_t ctdb_node_flag_change_len(struct ctdb_node_flag_change *flag_change)
+{
+	return sizeof(struct ctdb_node_flag_change);
+}
+
+void ctdb_node_flag_change_push(struct ctdb_node_flag_change *flag_change,
+				uint8_t *buf)
+{
+	memcpy(buf, flag_change, sizeof(struct ctdb_node_flag_change));
+}
+
+int ctdb_node_flag_change_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			       struct ctdb_node_flag_change **out)
+{
+	struct ctdb_node_flag_change *flag_change;
+
+	if (buflen < sizeof(struct ctdb_node_flag_change)) {
+		return EMSGSIZE;
+	}
+
+	flag_change = talloc_memdup(mem_ctx, buf,
+				    sizeof(struct ctdb_node_flag_change));
+	if (flag_change == NULL) {
+		return ENOMEM;
+	}
+
+	*out = flag_change;
+	return 0;
+}
+
+struct ctdb_var_list_wire {
+	uint32_t length;
+	char list_str[1];
+};
+
+size_t ctdb_var_list_len(struct ctdb_var_list *var_list)
+{
+	int i;
+	size_t len = sizeof(uint32_t);
+
+	for (i=0; i<var_list->count; i++) {
+		len += strlen(var_list->var[i]) + 1;
+	}
+	return len;
+}
+
+void ctdb_var_list_push(struct ctdb_var_list *var_list, uint8_t *buf)
+{
+	struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf;
+	int i, n;
+	size_t offset = 0;
+
+	if (var_list->count > 0) {
+		n = sprintf(wire->list_str, "%s", var_list->var[0]);
+		offset += n;
+	}
+	for (i=1; i<var_list->count; i++) {
+		n = sprintf(&wire->list_str[offset], ":%s", var_list->var[i]);
+		offset += n;
+	}
+	wire->length = offset + 1;
+}
+
+int ctdb_var_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_var_list **out)
+{
+	struct ctdb_var_list *var_list = NULL;
+	struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf;
+	char *str, *s, *tok, *ptr;
+	const char **list;
+
+	if (buflen < sizeof(uint32_t)) {
+		return EMSGSIZE;
+	}
+	if (buflen < sizeof(uint32_t) + wire->length) {
+		return EMSGSIZE;
+	}
+
+	str = talloc_strndup(mem_ctx, (char *)wire->list_str, wire->length);
+	if (str == NULL) {
+		return ENOMEM;
+	}
+
+	var_list = talloc_zero(mem_ctx, struct ctdb_var_list);
+	if (var_list == NULL) {
+		goto fail;
+	}
+
+	s = str;
+	while ((tok = strtok_r(s, ":", &ptr)) != NULL) {
+		s = NULL;
+		list = talloc_realloc(var_list, var_list->var, const char *,
+				      var_list->count+1);
+		if (list == NULL) {
+			goto fail;
+		}
+
+		var_list->var = list;
+		var_list->var[var_list->count] = talloc_strdup(var_list, tok);
+		if (var_list->var[var_list->count] == NULL) {
+			goto fail;
+		}
+		var_list->count++;
+	}
+
+	talloc_free(str);
+	*out = var_list;
+	return 0;
+
+fail:
+	talloc_free(str);
+	talloc_free(var_list);
+	return ENOMEM;
+}
+
+size_t ctdb_tunable_list_len(struct ctdb_tunable_list *tun_list)
+{
+	return sizeof(struct ctdb_tunable_list);
+}
+
+void ctdb_tunable_list_push(struct ctdb_tunable_list *tun_list, uint8_t *buf)
+{
+	memcpy(buf, tun_list, sizeof(struct ctdb_tunable_list));
+}
+
+int ctdb_tunable_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			   struct ctdb_tunable_list **out)
+{
+	struct ctdb_tunable_list *tun_list;
+
+	if (buflen < sizeof(struct ctdb_tunable_list)) {
+		return EMSGSIZE;
+	}
+
+	tun_list = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_tunable_list));
+	if (tun_list == NULL) {
+		return ENOMEM;
+	}
+
+	*out = tun_list;
+	return 0;
+}
+
+struct ctdb_tickle_list_wire {
+	ctdb_sock_addr addr;
+	uint32_t num;
+	struct ctdb_connection conn[1];
+};
+
+size_t ctdb_tickle_list_len(struct ctdb_tickle_list *tickles)
+{
+	return offsetof(struct ctdb_tickle_list, conn) +
+	       tickles->num * sizeof(struct ctdb_connection);
+}
+
+void ctdb_tickle_list_push(struct ctdb_tickle_list *tickles, uint8_t *buf)
+{
+	struct ctdb_tickle_list_wire *wire =
+		(struct ctdb_tickle_list_wire *)buf;
+	size_t offset;
+	int i;
+
+	memcpy(&wire->addr, &tickles->addr, sizeof(ctdb_sock_addr));
+	wire->num = tickles->num;
+
+	offset = offsetof(struct ctdb_tickle_list_wire, conn);
+	for (i=0; i<tickles->num; i++) {
+		ctdb_connection_push(&tickles->conn[i], &buf[offset]);
+		offset += ctdb_connection_len(&tickles->conn[i]);
+	}
+}
+
+int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			   struct ctdb_tickle_list **out)
+{
+	struct ctdb_tickle_list *tickles;
+	struct ctdb_tickle_list_wire *wire =
+		(struct ctdb_tickle_list_wire *)buf;
+	size_t offset;
+	int i, ret;
+
+	if (buflen < offsetof(struct ctdb_tickle_list_wire, conn)) {
+		return EMSGSIZE;
+	}
+	if (buflen < offsetof(struct ctdb_tickle_list_wire, conn) +
+		     wire->num * sizeof(struct ctdb_connection)) {
+		return EMSGSIZE;
+	}
+
+	tickles = talloc(mem_ctx, struct ctdb_tickle_list);
+	if (tickles == NULL) {
+		return ENOMEM;
+	}
+
+	offset = offsetof(struct ctdb_tickle_list, conn);
+	memcpy(tickles, wire, offset);
+
+	tickles->conn = talloc_array(tickles, struct ctdb_connection,
+				     wire->num);
+	if (tickles->conn == NULL) {
+		talloc_free(tickles);
+		return ENOMEM;
+	}
+
+	for (i=0; i<wire->num; i++) {
+		ret = ctdb_connection_pull_elems(&buf[offset], buflen-offset,
+						 tickles->conn,
+						 &tickles->conn[i]);
+		if (ret != 0) {
+			talloc_free(tickles);
+			return ret;
+		}
+		offset += ctdb_connection_len(&tickles->conn[i]);
+	}
+
+	*out = tickles;
+	return 0;
+}
+
+size_t ctdb_client_id_len(struct ctdb_client_id *cid)
+{
+	return sizeof(struct ctdb_client_id);
+}
+
+void ctdb_client_id_push(struct ctdb_client_id *cid, uint8_t *buf)
+{
+	memcpy(buf, cid, sizeof(struct ctdb_client_id));
+}
+
+static int ctdb_client_id_pull_elems(uint8_t *buf, size_t buflen,
+				     TALLOC_CTX *mem_ctx,
+				     struct ctdb_client_id *out)
+{
+	if (buflen < sizeof(struct ctdb_client_id)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(out, buf, sizeof(struct ctdb_client_id));
+
+	return 0;
+}
+
+int ctdb_client_id_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			struct ctdb_client_id **out)
+{
+	struct ctdb_client_id *cid;
+	int ret;
+
+	cid = talloc(mem_ctx, struct ctdb_client_id);
+	if (cid == NULL) {
+		return ENOMEM;
+	}
+
+	ret = ctdb_client_id_pull_elems(buf, buflen, cid, cid);
+	if (ret != 0) {
+		TALLOC_FREE(cid);
+	}
+
+	*out = cid;
+	return ret;
+}
+
+struct ctdb_client_id_list_wire {
+	uint32_t num;
+	struct ctdb_client_id cid[1];
+};
+
+size_t ctdb_client_id_list_len(struct ctdb_client_id_list *cid_list)
+{
+	return sizeof(uint32_t) +
+	       cid_list->num * sizeof(struct ctdb_client_id);
+}
+
+void ctdb_client_id_list_push(struct ctdb_client_id_list *cid_list,
+			      uint8_t *buf)
+{
+	struct ctdb_client_id_list_wire *wire =
+		(struct ctdb_client_id_list_wire *)buf;
+	size_t offset;
+	int i;
+
+	wire->num = cid_list->num;
+
+	offset = offsetof(struct ctdb_client_id_list_wire, cid);
+	for (i=0; i<cid_list->num; i++) {
+		ctdb_client_id_push(&cid_list->cid[i], &buf[offset]);
+		offset += ctdb_client_id_len(&cid_list->cid[i]);
+	}
+}
+
+static int ctdb_client_id_list_pull_elems(uint8_t *buf, size_t buflen,
+					  TALLOC_CTX *mem_ctx,
+					  struct ctdb_client_id_list *out)
+{
+	struct ctdb_client_id_list_wire *wire =
+		(struct ctdb_client_id_list_wire *)buf;
+	size_t offset;
+	int i;
+
+	if (buflen < sizeof(uint32_t)) {
+		return EMSGSIZE;
+	}
+	if (buflen < sizeof(uint32_t) +
+		     wire->num * sizeof(struct ctdb_client_id)) {
+		return EMSGSIZE;
+	}
+
+	out->num = wire->num;
+	out->cid = talloc_array(mem_ctx, struct ctdb_client_id,
+				wire->num);
+	if (out->cid == NULL) {
+		return ENOMEM;
+	}
+
+	offset = offsetof(struct ctdb_client_id_list_wire, cid);
+	for (i=0; i<wire->num; i++) {
+		bool ret;
+		ret = ctdb_client_id_pull_elems(&buf[offset], buflen-offset,
+						out->cid, &out->cid[i]);
+		if (ret != 0) {
+			return ret;
+		}
+		offset += ctdb_client_id_len(&out->cid[i]);
+	}
+
+	return 0;
+}
+
+int ctdb_client_id_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			     struct ctdb_client_id_list **out)
+{
+	struct ctdb_client_id_list *cid_list;
+	int ret;
+
+	cid_list = talloc(mem_ctx, struct ctdb_client_id_list);
+	if (cid_list == NULL) {
+		return ENOMEM;
+	}
+
+	ret = ctdb_client_id_list_pull_elems(buf, buflen, cid_list, cid_list);
+	if (ret != 0) {
+		TALLOC_FREE(cid_list);
+	}
+
+	*out = cid_list;
+	return ret;
+}
+
+struct ctdb_client_id_map_wire {
+	int count;
+	struct ctdb_client_id_list list[1];
+};
+
+size_t ctdb_client_id_map_len(struct ctdb_client_id_map *cid_map)
+{
+	int i;
+	size_t len;
+
+	len = sizeof(int);
+	for (i=0; i<cid_map->count; i++) {
+		len += ctdb_client_id_list_len(&cid_map->list[i]);
+	}
+	return len;
+}
+
+void ctdb_client_id_map_push(struct ctdb_client_id_map *cid_map, uint8_t *buf)
+{
+	struct ctdb_client_id_map_wire *wire =
+		(struct ctdb_client_id_map_wire *)buf;
+	size_t offset;
+	int i;
+
+	wire->count = cid_map->count;
+
+	offset = sizeof(int);
+	for (i=0; i<cid_map->count; i++) {
+		ctdb_client_id_list_push(&cid_map->list[i], &buf[offset]);
+		offset += ctdb_client_id_list_len(&cid_map->list[i]);
+	}
+}
+
+int ctdb_client_id_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			    struct ctdb_client_id_map **out)
+{
+	struct ctdb_client_id_map *cid_map;
+	struct ctdb_client_id_map_wire *wire =
+		(struct ctdb_client_id_map_wire *)buf;
+	size_t offset;
+	int i;
+	bool ret;
+
+	if (buflen < sizeof(int)) {
+		return EMSGSIZE;
+	}
+	if (buflen < sizeof(int) +
+		     wire->count * sizeof(struct ctdb_client_id_list)) {
+		return EMSGSIZE;
+	}
+
+	cid_map = talloc(mem_ctx, struct ctdb_client_id_map);
+	if (cid_map == NULL) {
+		return ENOMEM;
+	}
+
+	cid_map->count = wire->count;
+	cid_map->list = talloc_array(cid_map, struct ctdb_client_id_list,
+				     wire->count);
+	if (cid_map->list == NULL) {
+		return ENOMEM;
+	}
+
+	offset = sizeof(int);
+	for (i=0; i<wire->count; i++) {
+		ret = ctdb_client_id_list_pull_elems(&buf[offset],
+						     buflen-offset,
+						     cid_map->list,
+						     &cid_map->list[i]);
+		if (ret != 0) {
+			talloc_free(cid_map);
+			return ret;
+		}
+		offset += ctdb_client_id_list_len(&cid_map->list[i]);
+	}
+
+	*out = cid_map;
+	return 0;
+}
+
+struct ctdb_addr_info_wire {
+	ctdb_sock_addr addr;
+	uint32_t mask;
+	uint32_t len;
+	char iface[1];
+};
+
+size_t ctdb_addr_info_len(struct ctdb_addr_info *arp)
+{
+	uint32_t len;
+
+	len = offsetof(struct ctdb_addr_info_wire, iface);
+	if (arp->iface != NULL) {
+	       len += strlen(arp->iface)+1;
+	}
+
+	return len;
+}
+
+void ctdb_addr_info_push(struct ctdb_addr_info *addr_info, uint8_t *buf)
+{
+	struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf;
+
+	wire->addr = addr_info->addr;
+	wire->mask = addr_info->mask;
+	if (addr_info->iface == NULL) {
+		wire->len = 0;
+	} else {
+		wire->len = strlen(addr_info->iface)+1;
+		memcpy(wire->iface, addr_info->iface, wire->len);
+	}
+}
+
+int ctdb_addr_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			struct ctdb_addr_info **out)
+{
+	struct ctdb_addr_info *addr_info;
+	struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf;
+
+	if (buflen < offsetof(struct ctdb_addr_info_wire, iface)) {
+		return EMSGSIZE;
+	}
+	if (buflen < offsetof(struct ctdb_addr_info_wire, iface) + wire->len) {
+		return EMSGSIZE;
+	}
+
+	addr_info = talloc(mem_ctx, struct ctdb_addr_info);
+	if (addr_info == NULL) {
+		return ENOMEM;
+	}
+
+	addr_info->addr = wire->addr;
+	addr_info->mask = wire->mask;
+
+	if (wire->len == 0) {
+		addr_info->iface = NULL;
+	} else {
+		addr_info->iface = talloc_strndup(addr_info, wire->iface,
+						  wire->len);
+		if (addr_info->iface == NULL) {
+			talloc_free(addr_info);
+			return ENOMEM;
+		}
+	}
+
+	*out = addr_info;
+	return 0;
+}
+
+size_t ctdb_transdb_len(struct ctdb_transdb *transdb)
+{
+	return sizeof(struct ctdb_transdb);
+}
+
+void ctdb_transdb_push(struct ctdb_transdb *transdb, uint8_t *buf)
+{
+	memcpy(buf, transdb, sizeof(struct ctdb_transdb));
+}
+
+int ctdb_transdb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     struct ctdb_transdb **out)
+{
+	struct ctdb_transdb *transdb;
+
+	if (buflen < sizeof(struct ctdb_transdb)) {
+		return EMSGSIZE;
+	}
+
+	transdb = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_transdb));
+	if (transdb == NULL) {
+		return ENOMEM;
+	}
+
+	*out = transdb;
+	return 0;
+}
+
+size_t ctdb_uptime_len(struct ctdb_uptime *uptime)
+{
+	return sizeof(struct ctdb_uptime);
+}
+
+void ctdb_uptime_push(struct ctdb_uptime *uptime, uint8_t *buf)
+{
+	memcpy(buf, uptime, sizeof(struct ctdb_uptime));
+}
+
+int ctdb_uptime_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     struct ctdb_uptime **out)
+{
+	struct ctdb_uptime *uptime;
+
+	if (buflen < sizeof(struct ctdb_uptime)) {
+		return EMSGSIZE;
+	}
+
+	uptime = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_uptime));
+	if (uptime == NULL) {
+		return ENOMEM;
+	}
+
+	*out = uptime;
+	return 0;
+}
+
+size_t ctdb_public_ip_len(struct ctdb_public_ip *pubip)
+{
+	return sizeof(struct ctdb_public_ip);
+}
+
+void ctdb_public_ip_push(struct ctdb_public_ip *pubip, uint8_t *buf)
+{
+	memcpy(buf, pubip, sizeof(struct ctdb_public_ip));
+}
+
+static int ctdb_public_ip_pull_elems(uint8_t *buf, size_t buflen,
+				     TALLOC_CTX *mem_ctx,
+				     struct ctdb_public_ip *out)
+{
+	if (buflen < sizeof(struct ctdb_public_ip)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(out, buf, sizeof(struct ctdb_public_ip));
+
+	return 0;
+}
+
+int ctdb_public_ip_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			struct ctdb_public_ip **out)
+{
+	struct ctdb_public_ip *pubip;
+	int ret;
+
+	pubip = talloc(mem_ctx, struct ctdb_public_ip);
+	if (pubip == NULL) {
+		return ENOMEM;
+	}
+
+	ret = ctdb_public_ip_pull_elems(buf, buflen, pubip, pubip);
+	if (ret != 0) {
+		TALLOC_FREE(pubip);
+	}
+
+	*out = pubip;
+	return ret;
+}
+
+struct ctdb_public_ip_list_wire {
+	uint32_t num;
+	struct ctdb_public_ip ip[1];
+};
+
+size_t ctdb_public_ip_list_len(struct ctdb_public_ip_list *pubip_list)
+{
+	int i;
+	size_t len;
+
+	len = sizeof(uint32_t);
+	for (i=0; i<pubip_list->num; i++) {
+		len += ctdb_public_ip_len(&pubip_list->ip[i]);
+	}
+	return len;
+}
+
+void ctdb_public_ip_list_push(struct ctdb_public_ip_list *pubip_list,
+			      uint8_t *buf)
+{
+	struct ctdb_public_ip_list_wire *wire =
+		(struct ctdb_public_ip_list_wire *)buf;
+	size_t offset;
+	int i;
+
+	wire->num = pubip_list->num;
+
+	offset = offsetof(struct ctdb_public_ip_list_wire, ip);
+	for (i=0; i<pubip_list->num; i++) {
+		ctdb_public_ip_push(&pubip_list->ip[i], &buf[offset]);
+		offset += ctdb_public_ip_len(&pubip_list->ip[i]);
+	}
+}
+
+int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			     struct ctdb_public_ip_list **out)
+{
+	struct ctdb_public_ip_list *pubip_list;
+	struct ctdb_public_ip_list_wire *wire =
+		(struct ctdb_public_ip_list_wire *)buf;
+	size_t offset;
+	int i;
+	bool ret;
+
+	if (buflen < sizeof(uint32_t)) {
+		return EMSGSIZE;
+	}
+	if (buflen < sizeof(uint32_t) +
+		     wire->num * sizeof(struct ctdb_public_ip)) {
+		return EMSGSIZE;
+	}
+
+	pubip_list = talloc(mem_ctx, struct ctdb_public_ip_list);
+	if (pubip_list == NULL) {
+		return ENOMEM;
+	}
+
+	pubip_list->num = wire->num;
+	if (wire->num == 0) {
+		pubip_list->ip = NULL;
+		*out = pubip_list;
+		return 0;
+	}
+	pubip_list->ip = talloc_array(pubip_list, struct ctdb_public_ip,
+				      wire->num);
+	if (pubip_list->ip == NULL) {
+		talloc_free(pubip_list);
+		return ENOMEM;
+	}
+
+	offset = offsetof(struct ctdb_public_ip_list_wire, ip);
+	for (i=0; i<wire->num; i++) {
+		ret = ctdb_public_ip_pull_elems(&buf[offset], buflen-offset,
+						pubip_list->ip,
+						&pubip_list->ip[i]);
+		if (ret != 0) {
+			talloc_free(pubip_list);
+			return ret;
+		}
+		offset += ctdb_public_ip_len(&pubip_list->ip[i]);
+	}
+
+	*out = pubip_list;
+	return 0;
+}
+
+size_t ctdb_node_and_flags_len(struct ctdb_node_and_flags *node)
+{
+	return sizeof(struct ctdb_node_and_flags);
+}
+
+void ctdb_node_and_flags_push(struct ctdb_node_and_flags *node, uint8_t *buf)
+{
+	memcpy(buf, node, sizeof(struct ctdb_node_and_flags));
+}
+
+static int ctdb_node_and_flags_pull_elems(TALLOC_CTX *mem_ctx,
+					  uint8_t *buf, size_t buflen,
+					  struct ctdb_node_and_flags *out)
+{
+	if (buflen < sizeof(struct ctdb_node_and_flags)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(out, buf, sizeof(struct ctdb_node_and_flags));
+
+	return 0;
+}
+
+int ctdb_node_and_flags_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			      struct ctdb_node_and_flags **out)
+{
+	struct ctdb_node_and_flags *node;
+	int ret;
+
+	node = talloc(mem_ctx, struct ctdb_node_and_flags);
+	if (node == NULL) {
+		return ENOMEM;
+	}
+
+	ret = ctdb_node_and_flags_pull_elems(node, buf, buflen, node);
+	if (ret != 0) {
+		TALLOC_FREE(node);
+	}
+
+	*out = node;
+	return ret;
+}
+
+struct ctdb_node_map_wire {
+	uint32_t num;
+	struct ctdb_node_and_flags node[1];
+};
+
+size_t ctdb_node_map_len(struct ctdb_node_map *nodemap)
+{
+	return sizeof(uint32_t) +
+	       nodemap->num * sizeof(struct ctdb_node_and_flags);
+}
+
+void ctdb_node_map_push(struct ctdb_node_map *nodemap, uint8_t *buf)
+{
+	struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf;
+	size_t offset;
+	int i;
+
+	wire->num = nodemap->num;
+
+	offset = offsetof(struct ctdb_node_map_wire, node);
+	for (i=0; i<nodemap->num; i++) {
+		ctdb_node_and_flags_push(&nodemap->node[i], &buf[offset]);
+		offset += ctdb_node_and_flags_len(&nodemap->node[i]);
+	}
+}
+
+int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_node_map **out)
+{
+	struct ctdb_node_map *nodemap;
+	struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf;
+	size_t offset;
+	int i;
+	bool ret;
+
+	nodemap = talloc(mem_ctx, struct ctdb_node_map);
+	if (nodemap == NULL) {
+		return ENOMEM;
+	}
+
+	nodemap->num = wire->num;
+	nodemap->node = talloc_array(nodemap, struct ctdb_node_and_flags,
+				     wire->num);
+	if (nodemap->node == NULL) {
+		talloc_free(nodemap);
+		return ENOMEM;
+	}
+
+	offset = offsetof(struct ctdb_node_map_wire, node);
+	for (i=0; i<wire->num; i++) {
+		ret = ctdb_node_and_flags_pull_elems(nodemap->node,
+						     &buf[offset],
+						     buflen-offset,
+						     &nodemap->node[i]);
+		if (ret != 0) {
+			talloc_free(nodemap);
+			return ret;
+		}
+		offset += ctdb_node_and_flags_len(&nodemap->node[i]);
+	}
+
+	*out = nodemap;
+	return 0;
+}
+
+size_t ctdb_script_len(struct ctdb_script *script)
+{
+	return sizeof(struct ctdb_script);
+}
+
+void ctdb_script_push(struct ctdb_script *script, uint8_t *buf)
+{
+	memcpy(buf, script, sizeof(struct ctdb_script));
+}
+
+static int ctdb_script_pull_elems(uint8_t *buf, size_t buflen,
+				  TALLOC_CTX *mem_ctx,
+				  struct ctdb_script *out)
+{
+	if (buflen < sizeof(struct ctdb_script)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(out, buf, sizeof(struct ctdb_script));
+
+	return 0;
+}
+
+int ctdb_script_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		     struct ctdb_script **out)
+{
+	struct ctdb_script *script;
+	int ret;
+
+	script = talloc(mem_ctx, struct ctdb_script);
+	if (script == NULL) {
+		return ENOMEM;
+	}
+
+	ret = ctdb_script_pull_elems(buf, buflen, script, script);
+	if (ret != 0) {
+		TALLOC_FREE(script);
+	}
+
+	*out = script;
+	return ret;
+}
+
+struct ctdb_script_list_wire {
+	uint32_t num_scripts;
+	struct ctdb_script script[1];
+};
+
+size_t ctdb_script_list_len(struct ctdb_script_list *script_list)
+{
+	int i;
+	size_t len;
+
+	if (script_list == NULL) {
+		return 0;
+	}
+
+	len = offsetof(struct ctdb_script_list_wire, script);
+	for (i=0; i<script_list->num_scripts; i++) {
+		len += ctdb_script_len(&script_list->script[i]);
+	}
+	return len;
+}
+
+void ctdb_script_list_push(struct ctdb_script_list *script_list, uint8_t *buf)
+{
+	struct ctdb_script_list_wire *wire =
+		(struct ctdb_script_list_wire *)buf;
+	size_t offset;
+	int i;
+
+	if (script_list == NULL) {
+		return;
+	}
+
+	wire->num_scripts = script_list->num_scripts;
+
+	offset = offsetof(struct ctdb_script_list_wire, script);
+	for (i=0; i<script_list->num_scripts; i++) {
+		ctdb_script_push(&script_list->script[i], &buf[offset]);
+		offset += ctdb_script_len(&script_list->script[i]);
+	}
+}
+
+int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_script_list **out)
+{
+	struct ctdb_script_list *script_list;
+	struct ctdb_script_list_wire *wire =
+		(struct ctdb_script_list_wire *)buf;
+	size_t offset;
+	int i;
+	bool ret;
+
+	/* If event scripts have never been run, the result will be NULL */
+	if (buflen == 0) {
+		*out = NULL;
+		return 0;
+	}
+
+	offset = offsetof(struct ctdb_script_list_wire, script);
+
+	if (buflen < offset) {
+		return EMSGSIZE;
+	}
+	if (buflen < offset + wire->num_scripts * sizeof(struct ctdb_script)) {
+		return EMSGSIZE;
+	}
+
+	script_list = talloc(mem_ctx, struct ctdb_script_list);
+	if (script_list == NULL) {
+		return ENOMEM;
+
+	}
+
+	script_list->num_scripts = wire->num_scripts;
+	script_list->script = talloc_array(script_list, struct ctdb_script,
+					   wire->num_scripts);
+	if (script_list->script == NULL) {
+		talloc_free(script_list);
+		return ENOMEM;
+	}
+
+	for (i=0; i<wire->num_scripts; i++) {
+		ret = ctdb_script_pull_elems(&buf[offset], buflen-offset,
+					     script_list->script,
+					     &script_list->script[i]);
+		if (ret != 0) {
+			talloc_free(script_list);
+			return ret;
+		}
+		offset += ctdb_script_len(&script_list->script[i]);
+	}
+
+	*out = script_list;
+	return 0;
+}
+
+size_t ctdb_ban_state_len(struct ctdb_ban_state *ban_state)
+{
+	return sizeof(struct ctdb_ban_state);
+}
+
+void ctdb_ban_state_push(struct ctdb_ban_state *ban_state, uint8_t *buf)
+{
+	memcpy(buf, ban_state, sizeof(struct ctdb_ban_state));
+}
+
+int ctdb_ban_state_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			struct ctdb_ban_state **out)
+{
+	struct ctdb_ban_state *ban_state;
+
+	if (buflen < sizeof(struct ctdb_ban_state)) {
+		return EMSGSIZE;
+	}
+
+	ban_state = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_ban_state));
+	if (ban_state == NULL) {
+		return ENOMEM;
+	}
+
+	*out = ban_state;
+	return 0;
+}
+
+size_t ctdb_db_priority_len(struct ctdb_db_priority *db_prio)
+{
+	return sizeof(struct ctdb_db_priority);
+}
+
+void ctdb_db_priority_push(struct ctdb_db_priority *db_prio, uint8_t *buf)
+{
+	memcpy(buf, db_prio, sizeof(struct ctdb_db_priority));
+}
+
+int ctdb_db_priority_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_db_priority **out)
+{
+	struct ctdb_db_priority *db_prio;
+
+	if (buflen < sizeof(struct ctdb_db_priority)) {
+		return EMSGSIZE;
+	}
+
+	db_prio = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_db_priority));
+	if (db_prio == NULL) {
+		return ENOMEM;
+	}
+
+	*out = db_prio;
+	return 0;
+}
+
+struct ctdb_notify_data_wire {
+	uint64_t srvid;
+	uint32_t len;
+	uint8_t data[1];
+};
+
+size_t ctdb_notify_data_len(struct ctdb_notify_data *notify)
+{
+	return offsetof(struct ctdb_notify_data_wire, data) +
+	       notify->data.dsize;
+}
+
+void ctdb_notify_data_push(struct ctdb_notify_data *notify, uint8_t *buf)
+{
+	struct ctdb_notify_data_wire *wire =
+		(struct ctdb_notify_data_wire *)buf;
+
+	wire->srvid = notify->srvid;
+	wire->len = notify->data.dsize;
+	memcpy(wire->data, notify->data.dptr, notify->data.dsize);
+}
+
+int ctdb_notify_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_notify_data **out)
+{
+	struct ctdb_notify_data *notify;
+	struct ctdb_notify_data_wire *wire =
+		(struct ctdb_notify_data_wire *)buf;
+
+	if (buflen < offsetof(struct ctdb_notify_data_wire, data)) {
+		return EMSGSIZE;
+	}
+	if (buflen < offsetof(struct ctdb_notify_data_wire, data) + wire->len) {
+		return EMSGSIZE;
+	}
+
+	notify = talloc(mem_ctx, struct ctdb_notify_data);
+	if (notify == NULL) {
+		return ENOMEM;
+	}
+
+	notify->srvid = wire->srvid;
+	notify->data.dsize = wire->len;
+	notify->data.dptr = talloc_memdup(notify, wire->data, wire->len);
+	if (notify->data.dptr == NULL) {
+		talloc_free(notify);
+		return ENOMEM;
+	}
+
+	*out = notify;
+	return 0;
+}
+
+size_t ctdb_iface_len(struct ctdb_iface *iface)
+{
+	return sizeof(struct ctdb_iface);
+}
+
+void ctdb_iface_push(struct ctdb_iface *iface, uint8_t *buf)
+{
+	memcpy(buf, iface, sizeof(struct ctdb_iface));
+}
+
+static int ctdb_iface_pull_elems(uint8_t *buf, size_t buflen,
+				 TALLOC_CTX *mem_ctx,
+				 struct ctdb_iface *out)
+{
+	if (buflen < sizeof(struct ctdb_iface)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(out, buf, sizeof(struct ctdb_iface));
+
+	return 0;
+}
+
+int ctdb_iface_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		    struct ctdb_iface **out)
+{
+	struct ctdb_iface *iface;
+	int ret;
+
+	iface = talloc(mem_ctx, struct ctdb_iface);
+	if (iface == NULL) {
+		return ENOMEM;
+	}
+
+	ret = ctdb_iface_pull_elems(buf, buflen, iface, iface);
+	if (ret != 0) {
+		TALLOC_FREE(iface);
+	}
+
+	*out = iface;
+	return ret;
+}
+
+struct ctdb_iface_list_wire {
+	uint32_t num;
+	struct ctdb_iface iface[1];
+};
+
+size_t ctdb_iface_list_len(struct ctdb_iface_list *iface_list)
+{
+	return sizeof(uint32_t) +
+	       iface_list->num * sizeof(struct ctdb_iface);
+}
+
+void ctdb_iface_list_push(struct ctdb_iface_list *iface_list, uint8_t *buf)
+{
+	struct ctdb_iface_list_wire *wire =
+		(struct ctdb_iface_list_wire *)buf;
+
+	wire->num = iface_list->num;
+	memcpy(wire->iface, iface_list->iface,
+	       iface_list->num * sizeof(struct ctdb_iface));
+}
+
+int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			 struct ctdb_iface_list **out)
+{
+	struct ctdb_iface_list *iface_list;
+	struct ctdb_iface_list_wire *wire =
+		(struct ctdb_iface_list_wire *)buf;
+
+	if (buflen < sizeof(uint32_t)) {
+		return EMSGSIZE;
+	}
+	if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_iface)) {
+		return EMSGSIZE;
+	}
+
+	iface_list = talloc(mem_ctx, struct ctdb_iface_list);
+	if (iface_list == NULL) {
+		return ENOMEM;
+	}
+
+	iface_list->num = wire->num;
+	iface_list->iface = talloc_array(iface_list, struct ctdb_iface,
+					 wire->num);
+	if (iface_list->iface == NULL) {
+		talloc_free(iface_list);
+		return ENOMEM;
+	}
+
+	memcpy(iface_list->iface, wire->iface,
+	       wire->num * sizeof(struct ctdb_iface));
+
+	*out = iface_list;
+	return 0;
+}
+
+struct ctdb_public_ip_info_wire {
+	struct ctdb_public_ip ip;
+	uint32_t active_idx;
+	uint32_t num;
+	struct ctdb_iface ifaces[1];
+};
+
+size_t ctdb_public_ip_info_len(struct ctdb_public_ip_info *ipinfo)
+{
+	return offsetof(struct ctdb_public_ip_info_wire, num) +
+	       ctdb_iface_list_len(ipinfo->ifaces);
+}
+
+void ctdb_public_ip_info_push(struct ctdb_public_ip_info *ipinfo, uint8_t *buf)
+{
+	struct ctdb_public_ip_info_wire *wire =
+		(struct ctdb_public_ip_info_wire *)buf;
+	size_t offset;
+
+	offset = offsetof(struct ctdb_public_ip_info_wire, num);
+	memcpy(wire, ipinfo, offset);
+	wire->num = ipinfo->ifaces->num;
+	memcpy(wire->ifaces, ipinfo->ifaces->iface,
+	       ipinfo->ifaces->num * sizeof(struct ctdb_iface));
+}
+
+int ctdb_public_ip_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			     struct ctdb_public_ip_info **out)
+{
+	struct ctdb_public_ip_info *ipinfo;
+	struct ctdb_public_ip_info_wire *wire =
+		(struct ctdb_public_ip_info_wire *)buf;
+
+	if (buflen < offsetof(struct ctdb_public_ip_info_wire, ifaces)) {
+		return EMSGSIZE;
+	}
+
+	ipinfo = talloc(mem_ctx, struct ctdb_public_ip_info);
+	if (ipinfo == NULL) {
+		return ENOMEM;
+	}
+
+	memcpy(ipinfo, wire, offsetof(struct ctdb_public_ip_info_wire, num));
+
+	ipinfo->ifaces = talloc(ipinfo, struct ctdb_iface_list);
+	if (ipinfo->ifaces == NULL) {
+		talloc_free(ipinfo);
+		return ENOMEM;
+	}
+
+	ipinfo->ifaces->num = wire->num;
+	ipinfo->ifaces->iface = talloc_array(ipinfo->ifaces, struct ctdb_iface,
+					     wire->num);
+	if (ipinfo->ifaces->iface == NULL) {
+		talloc_free(ipinfo);
+		return ENOMEM;
+	}
+
+	memcpy(ipinfo->ifaces->iface, wire->ifaces,
+	       wire->num * sizeof(struct ctdb_iface));
+
+	*out = ipinfo;
+	return 0;
+}
+
+struct ctdb_key_data_wire {
+	uint32_t db_id;
+	struct ctdb_ltdb_header header;
+	uint32_t keylen;
+	uint8_t key[1];
+};
+
+size_t ctdb_key_data_len(struct ctdb_key_data *key)
+{
+	return offsetof(struct ctdb_key_data_wire, key) + key->key.dsize;
+}
+
+void ctdb_key_data_push(struct ctdb_key_data *key, uint8_t *buf)
+{
+	struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf;
+
+	memcpy(wire, key, offsetof(struct ctdb_key_data, key));
+	wire->keylen = key->key.dsize;
+	memcpy(wire->key, key->key.dptr, key->key.dsize);
+}
+
+int ctdb_key_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_key_data **out)
+{
+	struct ctdb_key_data *key_data;
+	struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf;
+
+	if (buflen < offsetof(struct ctdb_key_data_wire, key)) {
+		return EMSGSIZE;
+	}
+	if (buflen < offsetof(struct ctdb_key_data_wire, key) + wire->keylen) {
+		return EMSGSIZE;
+	}
+
+	key_data = talloc(mem_ctx, struct ctdb_key_data);
+	if (key_data == NULL) {
+		return ENOMEM;
+	}
+
+	memcpy(key_data, wire, offsetof(struct ctdb_key_data, key));
+
+	key_data->key.dsize = wire->keylen;
+	key_data->key.dptr = talloc_memdup(key_data, wire->key, wire->keylen);
+	if (key_data->key.dptr == NULL) {
+		talloc_free(key_data);
+		return ENOMEM;
+	}
+
+	*out = key_data;
+	return 0;
+}
+
+struct ctdb_db_statistics_wire {
+	struct ctdb_db_statistics dbstats;
+	char hot_keys_wire[1];
+};
+
+size_t ctdb_db_statistics_len(struct ctdb_db_statistics *dbstats)
+{
+	size_t len;
+	int i;
+
+	len = sizeof(struct ctdb_db_statistics);
+	for (i=0; i<MAX_HOT_KEYS; i++) {
+		len += dbstats->hot_keys[i].key.dsize;
+	}
+	return len;
+}
+
+void ctdb_db_statistics_push(struct ctdb_db_statistics *dbstats, void *buf)
+{
+	struct ctdb_db_statistics_wire *wire =
+		(struct ctdb_db_statistics_wire *)buf;
+	size_t offset;
+	int i;
+
+	dbstats->num_hot_keys = MAX_HOT_KEYS;
+	memcpy(wire, dbstats, sizeof(struct ctdb_db_statistics));
+
+	offset = 0;
+	for (i=0; i<MAX_HOT_KEYS; i++) {
+		memcpy(&wire->hot_keys_wire[offset],
+		       dbstats->hot_keys[i].key.dptr,
+		       dbstats->hot_keys[i].key.dsize);
+		offset += dbstats->hot_keys[i].key.dsize;
+	}
+}
+
+int ctdb_db_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			    struct ctdb_db_statistics **out)
+{
+	struct ctdb_db_statistics *dbstats;
+	struct ctdb_db_statistics_wire *wire =
+		(struct ctdb_db_statistics_wire *)buf;
+	size_t offset;
+	int i;
+
+	if (buflen < sizeof(struct ctdb_db_statistics)) {
+		return EMSGSIZE;
+	}
+	offset = 0;
+	for (i=0; i<wire->dbstats.num_hot_keys; i++) {
+		offset += wire->dbstats.hot_keys[i].key.dsize;
+	}
+	if (buflen < sizeof(struct ctdb_db_statistics) + offset) {
+		return EMSGSIZE;
+	}
+
+	dbstats = talloc(mem_ctx, struct ctdb_db_statistics);
+	if (dbstats == NULL) {
+		return ENOMEM;
+	}
+
+	memcpy(dbstats, wire, sizeof(struct ctdb_db_statistics));
+
+	offset = 0;
+	for (i=0; i<wire->dbstats.num_hot_keys; i++) {
+		uint8_t *ptr;
+		size_t key_size;
+
+		key_size = dbstats->hot_keys[i].key.dsize;
+		ptr = talloc_memdup(mem_ctx, &wire->hot_keys_wire[offset],
+				    key_size);
+		if (ptr == NULL) {
+			talloc_free(dbstats);
+			return ENOMEM;
+		}
+		dbstats->hot_keys[i].key.dptr = ptr;
+		offset += key_size;
+	}
+
+	*out = dbstats;
+	return 0;
+}
+
+size_t ctdb_election_message_len(struct ctdb_election_message *election)
+{
+	return sizeof(struct ctdb_election_message);
+}
+
+void ctdb_election_message_push(struct ctdb_election_message *election,
+				uint8_t *buf)
+{
+	memcpy(buf, election, sizeof(struct ctdb_election_message));
+}
+
+int ctdb_election_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			       struct ctdb_election_message **out)
+{
+	struct ctdb_election_message *election;
+
+	if (buflen < sizeof(struct ctdb_election_message)) {
+		return EMSGSIZE;
+	}
+
+	election = talloc_memdup(mem_ctx, buf,
+				 sizeof(struct ctdb_election_message));
+	if (election == NULL) {
+		return ENOMEM;
+	}
+
+	*out = election;
+	return 0;
+}
+
+size_t ctdb_srvid_message_len(struct ctdb_srvid_message *msg)
+{
+	return sizeof(struct ctdb_srvid_message);
+}
+
+void ctdb_srvid_message_push(struct ctdb_srvid_message *msg, uint8_t *buf)
+{
+	memcpy(buf, msg, sizeof(struct ctdb_srvid_message));
+}
+
+int ctdb_srvid_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			    struct ctdb_srvid_message **out)
+{
+	struct ctdb_srvid_message *msg;
+
+	if (buflen < sizeof(struct ctdb_srvid_message)) {
+		return EMSGSIZE;
+	}
+
+	msg = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_srvid_message));
+	if (msg == NULL) {
+		return ENOMEM;
+	}
+
+	*out = msg;
+	return 0;
+}
+
+size_t ctdb_disable_message_len(struct ctdb_disable_message *disable)
+{
+	return sizeof(struct ctdb_disable_message);
+}
+
+void ctdb_disable_message_push(struct ctdb_disable_message *disable,
+			       uint8_t *buf)
+{
+	memcpy(buf, disable, sizeof(struct ctdb_disable_message));
+}
+
+int ctdb_disable_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			      struct ctdb_disable_message **out)
+{
+	struct ctdb_disable_message *disable;
+
+	if (buflen < sizeof(struct ctdb_disable_message)) {
+		return EMSGSIZE;
+	}
+
+	disable = talloc_memdup(mem_ctx, buf,
+				sizeof(struct ctdb_disable_message));
+	if (disable == NULL) {
+		return ENOMEM;
+	}
+
+	*out = disable;
+	return 0;
+}
+
+size_t ctdb_tdb_data_len(TDB_DATA data)
+{
+	return data.dsize;
+}
+
+void ctdb_tdb_data_push(TDB_DATA data, uint8_t *buf)
+{
+	memcpy(buf, data.dptr, data.dsize);
+}
+
+int ctdb_tdb_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       TDB_DATA *out)
+{
+	TDB_DATA data;
+
+	data.dsize = buflen;
+	if (data.dsize > 0) {
+		data.dptr = talloc_memdup(mem_ctx, buf, buflen);
+		if (data.dptr == NULL) {
+			return ENOMEM;
+		}
+	} else {
+		data.dptr = NULL;
+	}
+
+	*out = data;
+	return 0;
+}
+
+size_t ctdb_server_id_len(struct ctdb_server_id *sid)
+{
+	return sizeof(struct ctdb_server_id);
+}
+
+void ctdb_server_id_push(struct ctdb_server_id *sid, uint8_t *buf)
+{
+	memcpy(buf, sid, sizeof(struct ctdb_server_id));
+}
+
+int ctdb_server_id_pull(uint8_t *buf, size_t buflen,
+			struct ctdb_server_id *sid)
+{
+	if (buflen < sizeof(struct ctdb_server_id)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(sid, buf, sizeof(struct ctdb_server_id));
+	return 0;
+}
+
+size_t ctdb_g_lock_len(struct ctdb_g_lock *lock)
+{
+	return sizeof(struct ctdb_g_lock);
+}
+
+void ctdb_g_lock_push(struct ctdb_g_lock *lock, uint8_t *buf)
+{
+	memcpy(buf, lock, sizeof(struct ctdb_g_lock));
+}
+
+int ctdb_g_lock_pull(uint8_t *buf, size_t buflen, struct ctdb_g_lock *lock)
+{
+	if (buflen < sizeof(struct ctdb_g_lock)) {
+		return EMSGSIZE;
+	}
+
+	memcpy(lock, buf, sizeof(struct ctdb_g_lock));
+	return 0;
+}
+
+size_t ctdb_g_lock_list_len(struct ctdb_g_lock_list *lock_list)
+{
+	return lock_list->num * sizeof(struct ctdb_g_lock);
+}
+
+void ctdb_g_lock_list_push(struct ctdb_g_lock_list *lock_list, uint8_t *buf)
+{
+	size_t offset = 0;
+	int i;
+
+	for (i=0; i<lock_list->num; i++) {
+		ctdb_g_lock_push(&lock_list->lock[i], &buf[offset]);
+		offset += sizeof(struct ctdb_g_lock);
+	}
+}
+
+int ctdb_g_lock_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+			  struct ctdb_g_lock_list **out)
+{
+	struct ctdb_g_lock_list *lock_list;
+	unsigned count;
+	size_t offset;
+	int ret, i;
+
+	lock_list = talloc_zero(mem_ctx, struct ctdb_g_lock_list);
+	if (lock_list == NULL) {
+		return ENOMEM;
+	}
+
+	count = buflen / sizeof(struct ctdb_g_lock);
+	lock_list->lock = talloc_array(lock_list, struct ctdb_g_lock, count);
+	if (lock_list->lock == NULL) {
+		talloc_free(lock_list);
+		return ENOMEM;
+	}
+
+	offset = 0;
+	for (i=0; i<count; i++) {
+		ret = ctdb_g_lock_pull(&buf[offset], buflen-offset,
+				       &lock_list->lock[i]);
+		if (ret != 0) {
+			talloc_free(lock_list);
+			return ret;
+		}
+		offset += sizeof(struct ctdb_g_lock);
+	}
+
+	lock_list->num = count;
+
+	*out = lock_list;
+	return 0;
+}
diff --git a/ctdb/protocol/protocol_util.c b/ctdb/protocol/protocol_util.c
new file mode 100644
index 0000000..823849f
--- /dev/null
+++ b/ctdb/protocol/protocol_util.c
@@ -0,0 +1,142 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_private.h"
+#include "protocol_api.h"
+
+static struct {
+	enum ctdb_runstate runstate;
+	const char * label;
+} runstate_map[] = {
+	{ CTDB_RUNSTATE_UNKNOWN, "UNKNOWN" },
+	{ CTDB_RUNSTATE_INIT, "INIT" },
+	{ CTDB_RUNSTATE_SETUP, "SETUP" },
+	{ CTDB_RUNSTATE_FIRST_RECOVERY, "FIRST_RECOVERY" },
+	{ CTDB_RUNSTATE_STARTUP, "STARTUP" },
+	{ CTDB_RUNSTATE_RUNNING, "RUNNING" },
+	{ CTDB_RUNSTATE_SHUTDOWN, "SHUTDOWN" },
+	{ -1, NULL },
+};
+
+const char *ctdb_runstate_to_string(enum ctdb_runstate runstate)
+{
+	int i;
+
+	for (i=0; runstate_map[i].label != NULL; i++) {
+		if (runstate_map[i].runstate == runstate) {
+			return runstate_map[i].label;
+		}
+	}
+
+	return runstate_map[0].label;
+}
+
+enum ctdb_runstate ctdb_runstate_from_string(const char *runstate_str)
+{
+	int i;
+
+	for (i=0; runstate_map[i].label != NULL; i++) {
+		if (strcasecmp(runstate_map[i].label,
+			       runstate_str) == 0) {
+			return runstate_map[i].runstate;
+		}
+	}
+
+	return CTDB_RUNSTATE_UNKNOWN;
+}
+
+static struct {
+	enum ctdb_event event;
+	const char *label;
+} event_map[] = {
+	{ CTDB_EVENT_INIT, "init" },
+	{ CTDB_EVENT_SETUP, "setup" },
+	{ CTDB_EVENT_STARTUP, "startup" },
+	{ CTDB_EVENT_START_RECOVERY, "startrecovery" },
+	{ CTDB_EVENT_RECOVERED, "recovered" },
+	{ CTDB_EVENT_TAKE_IP, "takeip" },
+	{ CTDB_EVENT_RELEASE_IP, "releaseip" },
+	{ CTDB_EVENT_MONITOR, "monitor" },
+	{ CTDB_EVENT_SHUTDOWN, "shutdown" },
+	{ CTDB_EVENT_UPDATE_IP, "updateip" },
+	{ CTDB_EVENT_IPREALLOCATED, "ipreallocated" },
+	{ CTDB_EVENT_MAX, "all" },
+	{ -1, NULL },
+};
+
+const char *ctdb_event_to_string(enum ctdb_event event)
+{
+	int i;
+
+	for (i=0; event_map[i].label != NULL; i++) {
+		if (event_map[i].event == event) {
+			return event_map[i].label;
+		}
+	}
+
+	return "unknown";
+}
+
+enum ctdb_event ctdb_event_from_string(const char *event_str)
+{
+	int i;
+
+	for (i=0; event_map[i].label != NULL; i++) {
+		if (strcmp(event_map[i].label, event_str) == 0) {
+			return event_map[i].event;
+		}
+	}
+
+	return CTDB_EVENT_MAX;
+}
+
+const char *ctdb_sock_addr_to_string(TALLOC_CTX *mem_ctx, ctdb_sock_addr *addr)
+{
+	char *cip;
+
+	cip = talloc_size(mem_ctx, 128);
+	if (cip == NULL) {
+		return "Memory Error";
+	}
+
+	switch (addr->sa.sa_family) {
+	case AF_INET:
+		inet_ntop(addr->ip.sin_family, &addr->ip.sin_addr,
+			  cip, 128);
+		break;
+
+	case AF_INET6:
+		inet_ntop(addr->ip6.sin6_family, &addr->ip6.sin6_addr,
+			  cip, 128);
+		break;
+
+	default:
+		sprintf(cip, "Unknown family %u", addr->sa.sa_family);
+		break;
+	}
+
+	return cip;
+}
diff --git a/ctdb/server/ctdb_banning.c b/ctdb/server/ctdb_banning.c
index d8f7ab1..56d3b29 100644
--- a/ctdb/server/ctdb_banning.c
+++ b/ctdb/server/ctdb_banning.c
@@ -16,32 +16,32 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/time.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
 
+#include <talloc.h>
+#include <tevent.h>
 
-static void
-ctdb_ban_node_event(struct event_context *ev, struct timed_event *te, 
-			       struct timeval t, void *private_data)
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/common.h"
+#include "common/logging.h"
+
+static void ctdb_ban_node_event(struct tevent_context *ev,
+				struct tevent_timer *te,
+				struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
-	bool freeze_failed = false;
-	int i;
 
 	/* Make sure we were able to freeze databases during banning */
-	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
-		if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) {
-			freeze_failed = true;
-			break;
-		}
-	}
-	if (freeze_failed) {
+	if (!ctdb_db_all_frozen(ctdb)) {
 		DEBUG(DEBUG_ERR, ("Banning timedout, but still unable to freeze databases\n"));
 		ctdb_ban_self(ctdb);
 		return;
@@ -58,10 +58,9 @@ ctdb_ban_node_event(struct event_context *ev, struct timed_event *te,
 
 void ctdb_local_node_got_banned(struct ctdb_context *ctdb)
 {
-	uint32_t i;
+	struct ctdb_db_context *ctdb_db;
 
-	/* make sure we are frozen */
-	DEBUG(DEBUG_NOTICE,("This node has been banned - forcing freeze and recovery\n"));
+	DEBUG(DEBUG_NOTICE,("This node has been banned - forcing recovery\n"));
 
 	/* Reset the generation id to 1 to make us ignore any
 	   REQ/REPLY CALL/DMASTER someone sends to us.
@@ -69,43 +68,29 @@ void ctdb_local_node_got_banned(struct ctdb_context *ctdb)
 	   anymore.
 	*/
 	ctdb->vnn_map->generation = INVALID_GENERATION;
-
-	ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
-	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
-		ctdb_start_freeze(ctdb, i);
+	for (ctdb_db = ctdb->db_list; ctdb_db != NULL; ctdb_db = ctdb_db->next) {
+		ctdb_db->generation = INVALID_GENERATION;
 	}
+
+	/* Recovery daemon will set the recovery mode ACTIVE and freeze
+	 * databases.
+	 */
+
 	ctdb_release_all_ips(ctdb);
 }
 
 int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-	struct ctdb_ban_time *bantime = (struct ctdb_ban_time *)indata.dptr;
+	struct ctdb_ban_state *bantime = (struct ctdb_ban_state *)indata.dptr;
 	bool already_banned;
 
 	DEBUG(DEBUG_INFO,("SET BAN STATE\n"));
 
 	if (bantime->pnn != ctdb->pnn) {
-		if (bantime->pnn >= ctdb->num_nodes) {
-			DEBUG(DEBUG_ERR,(__location__ " ERROR: Invalid ban request. PNN:%d is invalid. Max nodes %d\n", bantime->pnn, ctdb->num_nodes));
-			return -1;
-		}
-		if (bantime->time == 0) {
-			DEBUG(DEBUG_NOTICE,("unbanning node %d\n", bantime->pnn));
-			ctdb->nodes[bantime->pnn]->flags &= ~NODE_FLAGS_BANNED;
-		} else {
-			DEBUG(DEBUG_NOTICE,("banning node %d\n", bantime->pnn));
-			if (ctdb->tunable.enable_bans == 0) {
-				/* FIXME: This is bogus. We really should be
-				 * taking decision based on the tunables on
-				 * the banned node and not local node.
-				 */
-				DEBUG(DEBUG_WARNING,("Bans are disabled - ignoring ban of node %u\n", bantime->pnn));
-				return 0;
-			}
-
-			ctdb->nodes[bantime->pnn]->flags |= NODE_FLAGS_BANNED;
-		}
-		return 0;
+		DEBUG(DEBUG_WARNING,
+		      ("SET_BAN_STATE control for PNN %d ignored\n",
+		       bantime->pnn));
+		return -1;
 	}
 
 	already_banned = false;
@@ -126,18 +111,20 @@ int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata)
 		return 0;
 	}
 
-	ctdb->banning_ctx = talloc(ctdb, struct ctdb_ban_time);
+	ctdb->banning_ctx = talloc(ctdb, struct ctdb_ban_state);
 	if (ctdb->banning_ctx == NULL) {
 		DEBUG(DEBUG_CRIT,(__location__ " ERROR Failed to allocate new banning state\n"));
 		return -1;
 	}
-	*((struct ctdb_ban_time *)(ctdb->banning_ctx)) = *bantime;
+	*((struct ctdb_ban_state *)(ctdb->banning_ctx)) = *bantime;
 
 
 	DEBUG(DEBUG_ERR,("Banning this node for %d seconds\n", bantime->time));
 	ctdb->nodes[bantime->pnn]->flags |= NODE_FLAGS_BANNED;
 
-	event_add_timed(ctdb->ev, ctdb->banning_ctx, timeval_current_ofs(bantime->time,0), ctdb_ban_node_event, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb->banning_ctx,
+			 timeval_current_ofs(bantime->time,0),
+			 ctdb_ban_node_event, ctdb);
 
 	if (!already_banned) {
 		ctdb_local_node_got_banned(ctdb);
@@ -147,20 +134,20 @@ int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata)
 
 int32_t ctdb_control_get_ban_state(struct ctdb_context *ctdb, TDB_DATA *outdata)
 {
-	struct ctdb_ban_time *bantime;
+	struct ctdb_ban_state *bantime;
 
-	bantime = talloc(outdata, struct ctdb_ban_time);
+	bantime = talloc(outdata, struct ctdb_ban_state);
 	CTDB_NO_MEMORY(ctdb, bantime);
 
 	if (ctdb->banning_ctx != NULL) {
-		*bantime = *(struct ctdb_ban_time *)(ctdb->banning_ctx);
+		*bantime = *(struct ctdb_ban_state *)(ctdb->banning_ctx);
 	} else {
 		bantime->pnn = ctdb->pnn;
 		bantime->time = 0;
 	}
 
 	outdata->dptr  = (uint8_t *)bantime;
-	outdata->dsize = sizeof(struct ctdb_ban_time);
+	outdata->dsize = sizeof(struct ctdb_ban_state);
 
 	return 0;
 }
@@ -169,7 +156,7 @@ int32_t ctdb_control_get_ban_state(struct ctdb_context *ctdb, TDB_DATA *outdata)
 void ctdb_ban_self(struct ctdb_context *ctdb)
 {
 	TDB_DATA data;
-	struct ctdb_ban_time bantime;
+	struct ctdb_ban_state bantime;
 
 	bantime.pnn  = ctdb->pnn;
 	bantime.time = ctdb->tunable.recovery_ban_period;
diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c
index 391dfb1..2461f95 100644
--- a/ctdb/server/ctdb_call.c
+++ b/ctdb/server/ctdb_call.c
@@ -20,13 +20,26 @@
   see http://wiki.samba.org/index.php/Samba_%26_Clustering for
   protocol design and packet details
 */
-#include "includes.h"
-#include "tdb.h"
-#include "lib/util/dlinklist.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/util_process.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/rb_tree.h"
+#include "common/reqid.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 struct ctdb_sticky_record {
 	struct ctdb_context *ctdb;
@@ -70,7 +83,7 @@ static void ctdb_send_error(struct ctdb_context *ctdb,
 			    const char *fmt, ...)
 {
 	va_list ap;
-	struct ctdb_reply_error *r;
+	struct ctdb_reply_error_old *r;
 	char *msg;
 	int msglen, len;
 
@@ -87,9 +100,9 @@ static void ctdb_send_error(struct ctdb_context *ctdb,
 	va_end(ap);
 
 	msglen = strlen(msg)+1;
-	len = offsetof(struct ctdb_reply_error, msg);
+	len = offsetof(struct ctdb_reply_error_old, msg);
 	r = ctdb_transport_allocate(ctdb, msg, CTDB_REPLY_ERROR, len + msglen, 
-				    struct ctdb_reply_error);
+				    struct ctdb_reply_error_old);
 	CTDB_NO_MEMORY_FATAL(ctdb, r);
 
 	r->hdr.destnode  = hdr->srcnode;
@@ -120,7 +133,7 @@ static void ctdb_send_error(struct ctdb_context *ctdb,
 static void ctdb_call_send_redirect(struct ctdb_context *ctdb,
 				    struct ctdb_db_context *ctdb_db,
 				    TDB_DATA key,
-				    struct ctdb_req_call *c, 
+				    struct ctdb_req_call_old *c, 
 				    struct ctdb_ltdb_header *header)
 {
 	uint32_t lmaster = ctdb_lmaster(ctdb, &key);
@@ -157,7 +170,7 @@ static void ctdb_send_dmaster_reply(struct ctdb_db_context *ctdb_db,
 				    uint32_t reqid)
 {
 	struct ctdb_context *ctdb = ctdb_db->ctdb;
-	struct ctdb_reply_dmaster *r;
+	struct ctdb_reply_dmaster_old *r;
 	int ret, len;
 	TALLOC_CTX *tmp_ctx;
 
@@ -183,13 +196,14 @@ static void ctdb_send_dmaster_reply(struct ctdb_db_context *ctdb_db,
 	tmp_ctx = talloc_new(ctdb);
 
 	/* send the CTDB_REPLY_DMASTER */
-	len = offsetof(struct ctdb_reply_dmaster, data) + key.dsize + data.dsize + sizeof(uint32_t);
+	len = offsetof(struct ctdb_reply_dmaster_old, data) + key.dsize + data.dsize + sizeof(uint32_t);
 	r = ctdb_transport_allocate(ctdb, tmp_ctx, CTDB_REPLY_DMASTER, len,
-				    struct ctdb_reply_dmaster);
+				    struct ctdb_reply_dmaster_old);
 	CTDB_NO_MEMORY_FATAL(ctdb, r);
 
 	r->hdr.destnode  = new_dmaster;
 	r->hdr.reqid     = reqid;
+	r->hdr.generation = ctdb_db->generation;
 	r->rsn           = header->rsn;
 	r->keylen        = key.dsize;
 	r->datalen       = data.dsize;
@@ -211,11 +225,11 @@ static void ctdb_send_dmaster_reply(struct ctdb_db_context *ctdb_db,
   CTDB_REPLY_DMASTER to the new dmaster
 */
 static void ctdb_call_send_dmaster(struct ctdb_db_context *ctdb_db, 
-				   struct ctdb_req_call *c, 
+				   struct ctdb_req_call_old *c, 
 				   struct ctdb_ltdb_header *header,
 				   TDB_DATA *key, TDB_DATA *data)
 {
-	struct ctdb_req_dmaster *r;
+	struct ctdb_req_dmaster_old *r;
 	struct ctdb_context *ctdb = ctdb_db->ctdb;
 	int len;
 	uint32_t lmaster = ctdb_lmaster(ctdb, key);
@@ -235,13 +249,14 @@ static void ctdb_call_send_dmaster(struct ctdb_db_context *ctdb_db,
 		return;
 	}
 	
-	len = offsetof(struct ctdb_req_dmaster, data) + key->dsize + data->dsize
+	len = offsetof(struct ctdb_req_dmaster_old, data) + key->dsize + data->dsize
 			+ sizeof(uint32_t);
 	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_DMASTER, len, 
-				    struct ctdb_req_dmaster);
+				    struct ctdb_req_dmaster_old);
 	CTDB_NO_MEMORY_FATAL(ctdb, r);
 	r->hdr.destnode  = lmaster;
 	r->hdr.reqid     = c->hdr.reqid;
+	r->hdr.generation = ctdb_db->generation;
 	r->db_id         = c->db_id;
 	r->rsn           = header->rsn;
 	r->dmaster       = c->hdr.srcnode;
@@ -261,8 +276,9 @@ static void ctdb_call_send_dmaster(struct ctdb_db_context *ctdb_db,
 	talloc_free(r);
 }
 
-static void ctdb_sticky_pindown_timeout(struct event_context *ev, struct timed_event *te, 
-				       struct timeval t, void *private_data)
+static void ctdb_sticky_pindown_timeout(struct tevent_context *ev,
+					struct tevent_timer *te,
+					struct timeval t, void *private_data)
 {
 	struct ctdb_sticky_record *sr = talloc_get_type(private_data, 
 						       struct ctdb_sticky_record);
@@ -303,7 +319,10 @@ ctdb_set_sticky_pindown(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_
 			DEBUG(DEBUG_ERR,("Failed to allocate pindown context for sticky record\n"));
 			return -1;
 		}
-		event_add_timed(ctdb->ev, sr->pindown, timeval_current_ofs(ctdb->tunable.sticky_pindown / 1000, (ctdb->tunable.sticky_pindown * 1000) % 1000000), ctdb_sticky_pindown_timeout, sr);
+		tevent_add_timer(ctdb->ev, sr->pindown,
+				 timeval_current_ofs(ctdb->tunable.sticky_pindown / 1000,
+						     (ctdb->tunable.sticky_pindown * 1000) % 1000000),
+				 ctdb_sticky_pindown_timeout, sr);
 	}
 
 	return 0;
@@ -332,7 +351,7 @@ static void ctdb_become_dmaster(struct ctdb_db_context *ctdb_db,
 	header.dmaster = ctdb->pnn;
 	header.flags = record_flags;
 
-	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
+	state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_call_state);
 
 	if (state) {
 		if (state->call->flags & CTDB_CALL_FLAG_VACUUM_MIGRATION) {
@@ -416,7 +435,7 @@ struct dmaster_defer_call {
 };
 
 struct dmaster_defer_queue {
-	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
 	uint32_t generation;
 	struct dmaster_defer_call *deferred_calls;
 };
@@ -436,7 +455,7 @@ static void dmaster_defer_reprocess(struct tevent_context *ev,
 static int dmaster_defer_queue_destructor(struct dmaster_defer_queue *ddq)
 {
 	/* Ignore requests, if database recovery happens in-between. */
-	if (ddq->generation != ddq->ctdb->vnn_map->generation) {
+	if (ddq->generation != ddq->ctdb_db->generation) {
 		return 0;
 	}
 
@@ -480,8 +499,15 @@ static int dmaster_defer_setup(struct ctdb_db_context *ctdb_db,
 	/* Already exists */
 	ddq = trbt_lookuparray32(ctdb_db->defer_dmaster, k[0], k);
 	if (ddq != NULL) {
-		talloc_free(k);
-		return 0;
+		if (ddq->generation == ctdb_db->generation) {
+			talloc_free(k);
+			return 0;
+		}
+
+		/* Recovery ocurred - get rid of old queue. All the deferred
+		 * requests will be resent anyway from ctdb_call_resend_db.
+		 */
+		talloc_free(ddq);
 	}
 
 	ddq = talloc(hdr, struct dmaster_defer_queue);
@@ -490,7 +516,7 @@ static int dmaster_defer_setup(struct ctdb_db_context *ctdb_db,
 		talloc_free(k);
 		return -1;
 	}
-	ddq->ctdb = ctdb_db->ctdb;
+	ddq->ctdb_db = ctdb_db;
 	ddq->generation = hdr->generation;
 	ddq->deferred_calls = NULL;
 
@@ -539,7 +565,7 @@ static int dmaster_defer_add(struct ctdb_db_context *ctdb_db,
 	call->ctdb = ctdb_db->ctdb;
 	call->hdr = talloc_steal(call, hdr);
 
-	DLIST_ADD_END(ddq->deferred_calls, call, NULL);
+	DLIST_ADD_END(ddq->deferred_calls, call);
 
 	return 0;
 }
@@ -552,7 +578,7 @@ static int dmaster_defer_add(struct ctdb_db_context *ctdb_db,
 */
 void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 {
-	struct ctdb_req_dmaster *c = (struct ctdb_req_dmaster *)hdr;
+	struct ctdb_req_dmaster_old *c = (struct ctdb_req_dmaster_old *)hdr;
 	TDB_DATA key, data, data2;
 	struct ctdb_ltdb_header header;
 	struct ctdb_db_context *ctdb_db;
@@ -564,7 +590,7 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
 	key.dsize = c->keylen;
 	data.dptr = c->data + c->keylen;
 	data.dsize = c->datalen;
-	len = offsetof(struct ctdb_req_dmaster, data) + key.dsize + data.dsize
+	len = offsetof(struct ctdb_req_dmaster_old, data) + key.dsize + data.dsize
 			+ sizeof(uint32_t);
 	if (len <= c->hdr.length) {
 		memcpy(&record_flags, &c->data[c->keylen + c->datalen],
@@ -646,7 +672,8 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
 	}
 }
 
-static void ctdb_sticky_record_timeout(struct event_context *ev, struct timed_event *te, 
+static void ctdb_sticky_record_timeout(struct tevent_context *ev,
+				       struct tevent_timer *te,
 				       struct timeval t, void *private_data)
 {
 	struct ctdb_sticky_record *sr = talloc_get_type(private_data, 
@@ -700,7 +727,9 @@ ctdb_make_record_sticky(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_
 
 	trbt_insertarray32_callback(ctdb_db->sticky_records, k[0], &k[0], ctdb_make_sticky_record_callback, sr);
 
-	event_add_timed(ctdb->ev, sr, timeval_current_ofs(ctdb->tunable.sticky_duration, 0), ctdb_sticky_record_timeout, sr);
+	tevent_add_timer(ctdb->ev, sr,
+			 timeval_current_ofs(ctdb->tunable.sticky_duration, 0),
+			 ctdb_sticky_record_timeout, sr);
 
 	talloc_free(tmp_ctx);
 	return 0;
@@ -716,8 +745,9 @@ struct pinned_down_deferred_call {
 	struct ctdb_req_header *hdr;
 };
 
-static void pinned_down_requeue(struct event_context *ev, struct timed_event *te, 
-		       struct timeval t, void *private_data)
+static void pinned_down_requeue(struct tevent_context *ev,
+				struct tevent_timer *te,
+				struct timeval t, void *private_data)
 {
 	struct pinned_down_requeue_handle *handle = talloc_get_type(private_data, struct pinned_down_requeue_handle);
 	struct ctdb_context *ctdb = handle->ctdb;
@@ -737,7 +767,8 @@ static int pinned_down_destructor(struct pinned_down_deferred_call *pinned_down)
 	handle->hdr  = pinned_down->hdr;
 	talloc_steal(handle, handle->hdr);
 
-	event_add_timed(ctdb->ev, handle, timeval_zero(), pinned_down_requeue, handle);
+	tevent_add_timer(ctdb->ev, handle, timeval_zero(),
+			 pinned_down_requeue, handle);
 
 	return 0;
 }
@@ -848,9 +879,9 @@ sort_keys:
 */
 void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 {
-	struct ctdb_req_call *c = (struct ctdb_req_call *)hdr;
+	struct ctdb_req_call_old *c = (struct ctdb_req_call_old *)hdr;
 	TDB_DATA data;
-	struct ctdb_reply_call *r;
+	struct ctdb_reply_call_old *r;
 	int ret, len;
 	struct ctdb_ltdb_header header;
 	struct ctdb_call *call;
@@ -917,7 +948,7 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 		return;
 	}
 
-	/* Dont do READONLY if we dont have a tracking database */
+	/* Dont do READONLY if we don't have a tracking database */
 	if ((c->flags & CTDB_WANT_READONLY) && !ctdb_db->readonly) {
 		c->flags &= ~CTDB_WANT_READONLY;
 	}
@@ -1018,12 +1049,13 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
 		}
 
-		len = offsetof(struct ctdb_reply_call, data) + data.dsize + sizeof(struct ctdb_ltdb_header);
+		len = offsetof(struct ctdb_reply_call_old, data) + data.dsize + sizeof(struct ctdb_ltdb_header);
 		r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CALL, len, 
-					    struct ctdb_reply_call);
+					    struct ctdb_reply_call_old);
 		CTDB_NO_MEMORY_FATAL(ctdb, r);
 		r->hdr.destnode  = c->hdr.srcnode;
 		r->hdr.reqid     = c->hdr.reqid;
+		r->hdr.generation = ctdb_db->generation;
 		r->status        = 0;
 		r->datalen       = data.dsize + sizeof(struct ctdb_ltdb_header);
 		header.rsn      -= 2;
@@ -1102,12 +1134,13 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 		DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
 	}
 
-	len = offsetof(struct ctdb_reply_call, data) + call->reply_data.dsize;
+	len = offsetof(struct ctdb_reply_call_old, data) + call->reply_data.dsize;
 	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CALL, len, 
-				    struct ctdb_reply_call);
+				    struct ctdb_reply_call_old);
 	CTDB_NO_MEMORY_FATAL(ctdb, r);
 	r->hdr.destnode  = hdr->srcnode;
 	r->hdr.reqid     = hdr->reqid;
+	r->hdr.generation = ctdb_db->generation;
 	r->status        = call->status;
 	r->datalen       = call->reply_data.dsize;
 	if (call->reply_data.dsize) {
@@ -1128,10 +1161,10 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
  */
 void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 {
-	struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr;
+	struct ctdb_reply_call_old *c = (struct ctdb_reply_call_old *)hdr;
 	struct ctdb_call_state *state;
 
-	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
+	state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_call_state);
 	if (state == NULL) {
 		DEBUG(DEBUG_ERR, (__location__ " reqid %u not found\n", hdr->reqid));
 		return;
@@ -1225,7 +1258,7 @@ finished_ro:
  */
 void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 {
-	struct ctdb_reply_dmaster *c = (struct ctdb_reply_dmaster *)hdr;
+	struct ctdb_reply_dmaster_old *c = (struct ctdb_reply_dmaster_old *)hdr;
 	struct ctdb_db_context *ctdb_db;
 	TDB_DATA key, data;
 	uint32_t record_flags = 0;
@@ -1242,7 +1275,7 @@ void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 	key.dsize = c->keylen;
 	data.dptr = &c->data[key.dsize];
 	data.dsize = c->datalen;
-	len = offsetof(struct ctdb_reply_dmaster, data) + key.dsize + data.dsize
+	len = offsetof(struct ctdb_reply_dmaster_old, data) + key.dsize + data.dsize
 		+ sizeof(uint32_t);
 	if (len <= c->hdr.length) {
 		memcpy(&record_flags, &c->data[c->keylen + c->datalen],
@@ -1270,10 +1303,10 @@ void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 */
 void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 {
-	struct ctdb_reply_error *c = (struct ctdb_reply_error *)hdr;
+	struct ctdb_reply_error_old *c = (struct ctdb_reply_error_old *)hdr;
 	struct ctdb_call_state *state;
 
-	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
+	state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_call_state);
 	if (state == NULL) {
 		DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_reply_error\n",
 			 ctdb->pnn, hdr->reqid));
@@ -1301,8 +1334,8 @@ void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 */
 static int ctdb_call_destructor(struct ctdb_call_state *state)
 {
-	DLIST_REMOVE(state->ctdb_db->ctdb->pending_calls, state);
-	ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid);
+	DLIST_REMOVE(state->ctdb_db->pending_calls, state);
+	reqid_remove(state->ctdb_db->ctdb->idr, state->reqid);
 	return 0;
 }
 
@@ -1314,11 +1347,11 @@ static void ctdb_call_resend(struct ctdb_call_state *state)
 {
 	struct ctdb_context *ctdb = state->ctdb_db->ctdb;
 
-	state->generation = ctdb->vnn_map->generation;
+	state->generation = state->ctdb_db->generation;
 
 	/* use a new reqid, in case the old reply does eventually come in */
-	ctdb_reqid_remove(ctdb, state->reqid);
-	state->reqid = ctdb_reqid_new(ctdb, state);
+	reqid_remove(ctdb->idr, state->reqid);
+	state->reqid = reqid_new(ctdb->idr, state);
 	state->c->hdr.reqid = state->reqid;
 
 	/* update the generation count for this request, so its valid with the new vnn_map */
@@ -1328,26 +1361,38 @@ static void ctdb_call_resend(struct ctdb_call_state *state)
 	state->c->hdr.destnode = ctdb->pnn;
 
 	ctdb_queue_packet(ctdb, &state->c->hdr);
-	DEBUG(DEBUG_NOTICE,("resent ctdb_call\n"));
+	DEBUG(DEBUG_NOTICE,("resent ctdb_call for db %s reqid %u generation %u\n",
+			    state->ctdb_db->db_name, state->reqid, state->generation));
 }
 
 /*
   resend all pending calls on recovery
  */
-void ctdb_call_resend_all(struct ctdb_context *ctdb)
+void ctdb_call_resend_db(struct ctdb_db_context *ctdb_db)
 {
 	struct ctdb_call_state *state, *next;
-	for (state=ctdb->pending_calls;state;state=next) {
+
+	for (state = ctdb_db->pending_calls; state; state = next) {
 		next = state->next;
 		ctdb_call_resend(state);
 	}
 }
 
+void ctdb_call_resend_all(struct ctdb_context *ctdb)
+{
+	struct ctdb_db_context *ctdb_db;
+
+	for (ctdb_db = ctdb->db_list; ctdb_db; ctdb_db = ctdb_db->next) {
+		ctdb_call_resend_db(ctdb_db);
+	}
+}
+
 /*
   this allows the caller to setup a async.fn 
 */
-static void call_local_trigger(struct event_context *ev, struct timed_event *te, 
-		       struct timeval t, void *private_data)
+static void call_local_trigger(struct tevent_context *ev,
+			       struct tevent_timer *te,
+			       struct timeval t, void *private_data)
 {
 	struct ctdb_call_state *state = talloc_get_type(private_data, struct ctdb_call_state);
 	if (state->async.fn) {
@@ -1387,7 +1432,8 @@ struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db,
 		DEBUG(DEBUG_DEBUG,("ctdb_call_local() failed, ignoring return code %d\n", ret));
 	}
 
-	event_add_timed(ctdb->ev, state, timeval_zero(), call_local_trigger, state);
+	tevent_add_timer(ctdb->ev, state, timeval_zero(),
+			 call_local_trigger, state);
 
 	return state;
 }
@@ -1417,18 +1463,19 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd
 	state->call = talloc(state, struct ctdb_call);
 	CTDB_NO_MEMORY_NULL(ctdb, state->call);
 
-	state->reqid = ctdb_reqid_new(ctdb, state);
+	state->reqid = reqid_new(ctdb->idr, state);
 	state->ctdb_db = ctdb_db;
 	talloc_set_destructor(state, ctdb_call_destructor);
 
-	len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize;
+	len = offsetof(struct ctdb_req_call_old, data) + call->key.dsize + call->call_data.dsize;
 	state->c = ctdb_transport_allocate(ctdb, state, CTDB_REQ_CALL, len, 
-					   struct ctdb_req_call);
+					   struct ctdb_req_call_old);
 	CTDB_NO_MEMORY_NULL(ctdb, state->c);
 	state->c->hdr.destnode  = header->dmaster;
 
 	/* this limits us to 16k outstanding messages - not unreasonable */
 	state->c->hdr.reqid     = state->reqid;
+	state->c->hdr.generation = ctdb_db->generation;
 	state->c->flags         = call->flags;
 	state->c->db_id         = ctdb_db->db_id;
 	state->c->callid        = call->call_id;
@@ -1443,9 +1490,9 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd
 	state->call->key.dptr       = &state->c->data[0];
 
 	state->state  = CTDB_CALL_WAIT;
-	state->generation = ctdb->vnn_map->generation;
+	state->generation = ctdb_db->generation;
 
-	DLIST_ADD(ctdb->pending_calls, state);
+	DLIST_ADD(ctdb_db->pending_calls, state);
 
 	ctdb_queue_packet(ctdb, &state->c->hdr);
 
@@ -1461,7 +1508,7 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd
 int ctdb_daemon_call_recv(struct ctdb_call_state *state, struct ctdb_call *call)
 {
 	while (state->state < CTDB_CALL_DONE) {
-		event_loop_once(state->ctdb_db->ctdb->ev);
+		tevent_loop_once(state->ctdb_db->ctdb->ev);
 	}
 	if (state->state != CTDB_CALL_DONE) {
 		ctdb_set_error(state->ctdb_db->ctdb, "%s", state->errmsg);
@@ -1489,7 +1536,7 @@ int ctdb_daemon_call_recv(struct ctdb_call_state *state, struct ctdb_call *call)
 */
 void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode)
 {
-	struct ctdb_req_keepalive *r;
+	struct ctdb_req_keepalive_old *r;
 	
 	if (ctdb->methods == NULL) {
 		DEBUG(DEBUG_INFO,(__location__ " Failed to send keepalive. Transport is DOWN\n"));
@@ -1497,8 +1544,8 @@ void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode)
 	}
 
 	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_KEEPALIVE,
-				    sizeof(struct ctdb_req_keepalive), 
-				    struct ctdb_req_keepalive);
+				    sizeof(struct ctdb_req_keepalive_old), 
+				    struct ctdb_req_keepalive_old);
 	CTDB_NO_MEMORY_FATAL(ctdb, r);
 	r->hdr.destnode  = destnode;
 	r->hdr.reqid     = 0;
@@ -1523,7 +1570,7 @@ struct revokechild_handle {
 	struct revokechild_handle *next, *prev;
 	struct ctdb_context *ctdb;
 	struct ctdb_db_context *ctdb_db;
-	struct fd_event *fde;
+	struct tevent_fd *fde;
 	int status;
 	int fd[2];
 	pid_t child;
@@ -1537,8 +1584,9 @@ struct revokechild_requeue_handle {
 	void *ctx;
 };
 
-static void deferred_call_requeue(struct event_context *ev, struct timed_event *te, 
-		       struct timeval t, void *private_data)
+static void deferred_call_requeue(struct tevent_context *ev,
+				  struct tevent_timer *te,
+				  struct timeval t, void *private_data)
 {
 	struct revokechild_requeue_handle *requeue_handle = talloc_get_type(private_data, struct revokechild_requeue_handle);
 
@@ -1550,7 +1598,7 @@ static int deferred_call_destructor(struct revokechild_deferred_call *deferred_c
 {
 	struct ctdb_context *ctdb = deferred_call->ctdb;
 	struct revokechild_requeue_handle *requeue_handle = talloc(ctdb, struct revokechild_requeue_handle);
-	struct ctdb_req_call *c = (struct ctdb_req_call *)deferred_call->hdr;
+	struct ctdb_req_call_old *c = (struct ctdb_req_call_old *)deferred_call->hdr;
 
 	requeue_handle->ctdb = ctdb;
 	requeue_handle->hdr  = deferred_call->hdr;
@@ -1559,7 +1607,9 @@ static int deferred_call_destructor(struct revokechild_deferred_call *deferred_c
 	talloc_steal(requeue_handle, requeue_handle->hdr);
 
 	/* when revoking, any READONLY requests have 1 second grace to let read/write finish first */
-	event_add_timed(ctdb->ev, requeue_handle, timeval_current_ofs(c->flags & CTDB_WANT_READONLY ? 1 : 0, 0), deferred_call_requeue, requeue_handle);
+	tevent_add_timer(ctdb->ev, requeue_handle,
+			 timeval_current_ofs(c->flags & CTDB_WANT_READONLY ? 1 : 0, 0),
+			 deferred_call_requeue, requeue_handle);
 
 	return 0;
 }
@@ -1583,8 +1633,9 @@ static int revokechild_destructor(struct revokechild_handle *rc)
 	return 0;
 }
 
-static void revokechild_handler(struct event_context *ev, struct fd_event *fde, 
-			     uint16_t flags, void *private_data)
+static void revokechild_handler(struct tevent_context *ev,
+				struct tevent_fd *fde,
+				uint16_t flags, void *private_data)
 {
 	struct revokechild_handle *rc = talloc_get_type(private_data, 
 						     struct revokechild_handle);
@@ -1660,8 +1711,9 @@ static void revoke_send_cb(struct ctdb_context *ctdb, uint32_t pnn, void *privat
 
 }
 
-static void ctdb_revoke_timeout_handler(struct event_context *ev, struct timed_event *te, 
-			      struct timeval yt, void *private_data)
+static void ctdb_revoke_timeout_handler(struct tevent_context *ev,
+					struct tevent_timer *te,
+					struct timeval yt, void *private_data)
 {
 	struct ctdb_revoke_state *state = private_data;
 
@@ -1683,10 +1735,12 @@ static int ctdb_revoke_all_delegations(struct ctdb_context *ctdb, struct ctdb_db
  
 	ctdb_trackingdb_traverse(ctdb, tdata, revoke_send_cb, state);
 
-	event_add_timed(ctdb->ev, state, timeval_current_ofs(ctdb->tunable.control_timeout, 0), ctdb_revoke_timeout_handler, state);
+	tevent_add_timer(ctdb->ev, state,
+			 timeval_current_ofs(ctdb->tunable.control_timeout, 0),
+			 ctdb_revoke_timeout_handler, state);
 
 	while (state->finished == 0) {
-		event_loop_once(ctdb->ev);
+		tevent_loop_once(ctdb->ev);
 	}
 
 	if (ctdb_ltdb_lock(ctdb_db, key) != 0) {
@@ -1799,7 +1853,7 @@ int ctdb_start_revoke_ro_record(struct ctdb_context *ctdb, struct ctdb_db_contex
 		close(rc->fd[0]);
 		debug_extra = talloc_asprintf(NULL, "revokechild-%s:", ctdb_db->db_name);
 
-		ctdb_set_process_name("ctdb_revokechild");
+		prctl_set_comment("ctdb_revokechild");
 		if (switch_from_server_to_client(ctdb, "revokechild-%s", ctdb_db->db_name) != 0) {
 			DEBUG(DEBUG_ERR,("Failed to switch from server to client for revokechild process\n"));
 			c = 1;
@@ -1822,11 +1876,10 @@ child_finished:
 	set_close_on_exec(rc->fd[0]);
 
 	/* This is an active revokechild child process */
-	DLIST_ADD_END(ctdb_db->revokechild_active, rc, NULL);
+	DLIST_ADD_END(ctdb_db->revokechild_active, rc);
 
-	rc->fde = event_add_fd(ctdb->ev, rc, rc->fd[0],
-				   EVENT_FD_READ, revokechild_handler,
-				   (void *)rc);
+	rc->fde = tevent_add_fd(ctdb->ev, rc, rc->fd[0], TEVENT_FD_READ,
+				revokechild_handler, (void *)rc);
 	if (rc->fde == NULL) {
 		DEBUG(DEBUG_ERR,("Failed to set up fd event for revokechild process\n"));
 		talloc_free(rc);
diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c
index fda4c29..e6f8a0d 100644
--- a/ctdb/server/ctdb_control.c
+++ b/ctdb/server/ctdb_control.c
@@ -16,14 +16,26 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
-#include "lib/util/dlinklist.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/talloc_report.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/reqid.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 
 struct ctdb_control_state {
@@ -40,34 +52,23 @@ struct ctdb_control_state {
  */
 int32_t ctdb_dump_memory(struct ctdb_context *ctdb, TDB_DATA *outdata)
 {
-	/* dump to a file, then send the file as a blob */
-	FILE *f;
-	long fsize;
-	f = tmpfile();
-	if (f == NULL) {
-		DEBUG(DEBUG_ERR,(__location__ " Unable to open tmpfile - %s\n", strerror(errno)));
-		return -1;
-	}
-	talloc_report_full(NULL, f);
-	fsize = ftell(f);
-	if (fsize == -1) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to get file size - %s\n",
-				  strerror(errno)));
-		fclose(f);
+	char *report;
+	size_t reportlen;
+
+	report = talloc_report_str(outdata, NULL);
+	if (report == NULL) {
+		DEBUG(DEBUG_ERR,
+		      (__location__ " talloc_report_str failed\n"));
 		return -1;
 	}
-	rewind(f);
-	outdata->dptr = talloc_size(outdata, fsize);
-	if (outdata->dptr == NULL) {
-		fclose(f);
-		CTDB_NO_MEMORY(ctdb, outdata->dptr);
-	}
-	outdata->dsize = fread(outdata->dptr, 1, fsize, f);
-	fclose(f);
-	if (outdata->dsize != fsize) {
-		DEBUG(DEBUG_ERR,(__location__ " Unable to read tmpfile\n"));
-		return -1;
+	reportlen = talloc_get_size(report);
+
+	if (reportlen > 0) {
+		reportlen -= 1;	/* strip trailing zero */
 	}
+
+	outdata->dptr = (uint8_t *)report;
+	outdata->dsize = reportlen;
 	return 0;
 }
 
@@ -90,7 +91,7 @@ static int32_t control_not_implemented(const char *unsupported,
   process a control request
  */
 static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, 
-				     struct ctdb_req_control *c,
+				     struct ctdb_req_control_old *c,
 				     TDB_DATA indata,
 				     TDB_DATA *outdata, uint32_t srcnode,
 				     const char **errormsg,
@@ -120,16 +121,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 	}
 
 	case CTDB_CONTROL_STATISTICS: {
-		int i;
 		CHECK_CONTROL_DATA_SIZE(0);
 		ctdb->statistics.memory_used = talloc_total_size(NULL);
 		ctdb->statistics.num_clients = ctdb->num_clients;
-		ctdb->statistics.frozen = 0;
-		for (i=1; i<= NUM_DB_PRIORITIES; i++) {
-			if (ctdb->freeze_mode[i] == CTDB_FREEZE_FROZEN) {
-				ctdb->statistics.frozen = 1;
-			}
-		}
+		ctdb->statistics.frozen = (ctdb_db_all_frozen(ctdb) ? 1 : 0);
 		ctdb->statistics.recovering = (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE);
 		ctdb->statistics.statistics_current_time = timeval_current();
 
@@ -151,8 +146,15 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 	}
 
 	case CTDB_CONTROL_STATISTICS_RESET: {
+		struct ctdb_db_context *ctdb_db;
+
 		CHECK_CONTROL_DATA_SIZE(0);
 		ZERO_STRUCT(ctdb->statistics);
+		for (ctdb_db = ctdb->db_list;
+		     ctdb_db != NULL;
+		     ctdb_db = ctdb_db->next) {
+			ctdb_db_statistics_reset(ctdb_db);
+		}
 		ctdb->statistics.statistics_start_time = timeval_current();
 		return 0;
 	}
@@ -191,7 +193,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 		return ctdb_control_setvnnmap(ctdb, opcode, indata, outdata);
 
 	case CTDB_CONTROL_PULL_DB: 
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_pulldb));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_pulldb));
 		return ctdb_control_pull_db(ctdb, indata, outdata);
 
 	case CTDB_CONTROL_SET_DMASTER: 
@@ -373,7 +375,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 		return ctdb_control_get_public_ips(ctdb, c, outdata);
 
 	case CTDB_CONTROL_TCP_CLIENT:
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp_addr));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
 		return ctdb_control_tcp_client(ctdb, client_id, indata);
 
 	case CTDB_CONTROL_STARTUP: 
@@ -381,15 +383,15 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 		return ctdb_control_startup(ctdb, srcnode);
 
 	case CTDB_CONTROL_TCP_ADD: 
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_tcp_connection));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
 		return ctdb_control_tcp_add(ctdb, indata, false);
 
 	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: 
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_tcp_connection));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
 		return ctdb_control_tcp_add(ctdb, indata, true);
 
 	case CTDB_CONTROL_TCP_REMOVE: 
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_tcp_connection));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
 		return ctdb_control_tcp_remove(ctdb, indata);
 
 	case CTDB_CONTROL_SET_TUNABLE:
@@ -406,7 +408,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 		return ctdb_control_modflags(ctdb, indata);
 
 	case CTDB_CONTROL_KILL_TCP: 
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_killtcp));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
 		return ctdb_control_kill_tcp(ctdb, indata);
 
 	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
@@ -418,15 +420,15 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 		return ctdb_control_set_tcp_tickle_list(ctdb, indata);
 
 	case CTDB_CONTROL_REGISTER_SERVER_ID: 
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_server_id));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id));
 		return ctdb_control_register_server_id(ctdb, client_id, indata);
 
 	case CTDB_CONTROL_UNREGISTER_SERVER_ID: 
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_server_id));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id));
 		return ctdb_control_unregister_server_id(ctdb, indata);
 
 	case CTDB_CONTROL_CHECK_SERVER_ID: 
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_server_id));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id));
 		return ctdb_control_check_server_id(ctdb, indata);
 
 	case CTDB_CONTROL_GET_SERVER_ID_LIST:
@@ -439,7 +441,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 	case CTDB_CONTROL_UPDATE_RECORD:
 		return ctdb_control_update_record(ctdb, c, indata, async_reply);
 
-	case CTDB_CONTROL_SEND_GRATIOUS_ARP:
+	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
 		return ctdb_control_send_gratious_arp(ctdb, indata);
 
 	case CTDB_CONTROL_TRANSACTION_START:
@@ -451,7 +453,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 		return ctdb_control_transaction_commit(ctdb, *(uint32_t *)indata.dptr);
 
 	case CTDB_CONTROL_WIPE_DATABASE:
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_wipe_database));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb));
 		return ctdb_control_wipe_database(ctdb, indata);
 
 	case CTDB_CONTROL_UPTIME:
@@ -602,7 +604,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 		return ctdb_control_disable_script(ctdb, indata);
 
 	case CTDB_CONTROL_SET_BAN_STATE:
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_ban_time));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_ban_state));
 		return ctdb_control_set_ban_state(ctdb, indata);
 
 	case CTDB_CONTROL_GET_BAN_STATE:
@@ -632,7 +634,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 		return ctdb_control_register_notify(ctdb, client_id, indata);
 
 	case CTDB_CONTROL_DEREGISTER_NOTIFY:
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_notify_deregister));
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint64_t));
 		return ctdb_control_deregister_notify(ctdb, client_id, indata);
 
 	case CTDB_CONTROL_GET_LOG:
@@ -662,7 +664,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 		return ctdb_control_get_ifaces(ctdb, c, outdata);
 
 	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
-		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_iface_info));
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_iface));
 		return ctdb_control_set_iface_link(ctdb, c, indata);
 
 	case CTDB_CONTROL_GET_STAT_HISTORY:
@@ -692,6 +694,27 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 	case CTDB_CONTROL_DB_DETACH:
 		return ctdb_control_db_detach(ctdb, indata, client_id);
 
+	case CTDB_CONTROL_DB_FREEZE:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_control_db_freeze(ctdb, c, *(uint32_t *)indata.dptr,
+					      async_reply);
+
+	case CTDB_CONTROL_DB_THAW:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_control_db_thaw(ctdb, *(uint32_t *)indata.dptr);
+
+	case CTDB_CONTROL_DB_TRANSACTION_START:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb));
+		return ctdb_control_db_transaction_start(ctdb, indata);
+
+	case CTDB_CONTROL_DB_TRANSACTION_COMMIT:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb));
+		return ctdb_control_db_transaction_commit(ctdb, indata);
+
+	case CTDB_CONTROL_DB_TRANSACTION_CANCEL:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_control_db_transaction_cancel(ctdb, indata);
+
 	default:
 		DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
 		return -1;
@@ -701,10 +724,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 /*
   send a reply for a ctdb control
  */
-void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c,
+void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control_old *c,
 				TDB_DATA *outdata, int32_t status, const char *errormsg)
 {
-	struct ctdb_reply_control *r;
+	struct ctdb_reply_control_old *r;
 	size_t len;
 	
 	/* some controls send no reply */
@@ -712,11 +735,11 @@ void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_contr
 		return;
 	}
 
-	len = offsetof(struct ctdb_reply_control, data) + (outdata?outdata->dsize:0);
+	len = offsetof(struct ctdb_reply_control_old, data) + (outdata?outdata->dsize:0);
 	if (errormsg) {
 		len += strlen(errormsg);
 	}
-	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CONTROL, len, struct ctdb_reply_control);
+	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CONTROL, len, struct ctdb_reply_control_old);
 	if (r == NULL) {
 		DEBUG(DEBUG_ERR,(__location__ "Unable to allocate transport - OOM or transport is down\n"));
 		return;
@@ -744,7 +767,7 @@ void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_contr
 */
 void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 {
-	struct ctdb_req_control *c = (struct ctdb_req_control *)hdr;
+	struct ctdb_req_control_old *c = (struct ctdb_req_control_old *)hdr;
 	TDB_DATA data, *outdata;
 	int32_t status;
 	bool async_reply = false;
@@ -768,12 +791,12 @@ void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
 */
 void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 {
-	struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
+	struct ctdb_reply_control_old *c = (struct ctdb_reply_control_old *)hdr;
 	TDB_DATA data;
 	struct ctdb_control_state *state;
 	const char *errormsg = NULL;
 
-	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_control_state);
+	state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_control_state);
 	if (state == NULL) {
 		DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_reply_control\n",
 			 ctdb->pnn, hdr->reqid));
@@ -802,15 +825,16 @@ void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 
 static int ctdb_control_destructor(struct ctdb_control_state *state)
 {
-	ctdb_reqid_remove(state->ctdb, state->reqid);
+	reqid_remove(state->ctdb->idr, state->reqid);
 	return 0;
 }
 
 /*
   handle a timeout of a control
  */
-static void ctdb_control_timeout(struct event_context *ev, struct timed_event *te, 
-		       struct timeval t, void *private_data)
+static void ctdb_control_timeout(struct tevent_context *ev,
+				 struct tevent_timer *te,
+				 struct timeval t, void *private_data)
 {
 	struct ctdb_control_state *state = talloc_get_type(private_data, struct ctdb_control_state);
 	TALLOC_CTX *tmp_ctx = talloc_new(ev);
@@ -836,7 +860,7 @@ int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
 			     ctdb_control_callback_fn_t callback,
 			     void *private_data)
 {
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	struct ctdb_control_state *state;
 	size_t len;
 
@@ -869,7 +893,7 @@ int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
 	state = talloc(private_data?private_data:ctdb, struct ctdb_control_state);
 	CTDB_NO_MEMORY(ctdb, state);
 
-	state->reqid = ctdb_reqid_new(ctdb, state);
+	state->reqid = reqid_new(ctdb->idr, state);
 	state->callback = callback;
 	state->private_data = private_data;
 	state->ctdb = ctdb;
@@ -877,9 +901,9 @@ int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
 
 	talloc_set_destructor(state, ctdb_control_destructor);
 
-	len = offsetof(struct ctdb_req_control, data) + data.dsize;
+	len = offsetof(struct ctdb_req_control_old, data) + data.dsize;
 	c = ctdb_transport_allocate(ctdb, state, CTDB_REQ_CONTROL, len, 
-				    struct ctdb_req_control);
+				    struct ctdb_req_control_old);
 	CTDB_NO_MEMORY(ctdb, c);
 	talloc_set_name_const(c, "ctdb_req_control packet");
 
@@ -902,9 +926,9 @@ int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
 	}
 
 	if (ctdb->tunable.control_timeout) {
-		event_add_timed(ctdb->ev, state, 
-				timeval_current_ofs(ctdb->tunable.control_timeout, 0), 
-				ctdb_control_timeout, state);
+		tevent_add_timer(ctdb->ev, state,
+				 timeval_current_ofs(ctdb->tunable.control_timeout, 0),
+				 ctdb_control_timeout, state);
 	}
 
 	talloc_free(c);
diff --git a/ctdb/server/ctdb_daemon.c b/ctdb/server/ctdb_daemon.c
index ac2db75..9a33691 100644
--- a/ctdb/server/ctdb_daemon.c
+++ b/ctdb/server/ctdb_daemon.c
@@ -17,18 +17,32 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "lib/tdb_wrap/tdb_wrap.h"
-#include "tdb.h"
-#include "lib/util/dlinklist.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_version.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
-#include <sys/socket.h>
+#include "system/time.h"
+
+#include <talloc.h>
+/* Allow use of deprecated function tevent_loop_allow_nesting() */
+#define TEVENT_DEPRECATED
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_version.h"
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/rb_tree.h"
+#include "common/reqid.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 struct ctdb_client_pid_list {
 	struct ctdb_client_pid_list *next, *prev;
@@ -55,7 +69,7 @@ static void print_exit_message(void)
 
 
 
-static void ctdb_time_tick(struct event_context *ev, struct timed_event *te, 
+static void ctdb_time_tick(struct tevent_context *ev, struct tevent_timer *te,
 				  struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
@@ -64,9 +78,9 @@ static void ctdb_time_tick(struct event_context *ev, struct timed_event *te,
 		return;
 	}
 
-	event_add_timed(ctdb->ev, ctdb, 
-			timeval_current_ofs(1, 0), 
-			ctdb_time_tick, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb,
+			 timeval_current_ofs(1, 0),
+			 ctdb_time_tick, ctdb);
 }
 
 /* Used to trigger a dummy event once per second, to make
@@ -74,9 +88,9 @@ static void ctdb_time_tick(struct event_context *ev, struct timed_event *te,
  */
 static void ctdb_start_time_tickd(struct ctdb_context *ctdb)
 {
-	event_add_timed(ctdb->ev, ctdb, 
-			timeval_current_ofs(1, 0), 
-			ctdb_time_tick, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb,
+			 timeval_current_ofs(1, 0),
+			 ctdb_time_tick, ctdb);
 }
 
 static void ctdb_start_periodic_events(struct ctdb_context *ctdb)
@@ -127,18 +141,18 @@ static int daemon_queue_send(struct ctdb_client *client, struct ctdb_req_header
   message handler for when we are in daemon mode. This redirects the message
   to the right client
  */
-static void daemon_message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-				    TDB_DATA data, void *private_data)
+static void daemon_message_handler(uint64_t srvid, TDB_DATA data,
+				   void *private_data)
 {
 	struct ctdb_client *client = talloc_get_type(private_data, struct ctdb_client);
-	struct ctdb_req_message *r;
+	struct ctdb_req_message_old *r;
 	int len;
 
 	/* construct a message to send to the client containing the data */
-	len = offsetof(struct ctdb_req_message, data) + data.dsize;
-	r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_MESSAGE, 
-			       len, struct ctdb_req_message);
-	CTDB_NO_MEMORY_VOID(ctdb, r);
+	len = offsetof(struct ctdb_req_message_old, data) + data.dsize;
+	r = ctdbd_allocate_pkt(client->ctdb, client->ctdb, CTDB_REQ_MESSAGE,
+			       len, struct ctdb_req_message_old);
+	CTDB_NO_MEMORY_VOID(client->ctdb, r);
 
 	talloc_set_name_const(r, "req_message packet");
 
@@ -157,13 +171,14 @@ static void daemon_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
  */
 int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid)
 {
-	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+	struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
 	int res;
 	if (client == NULL) {
 		DEBUG(DEBUG_ERR,("Bad client_id in daemon_request_register_message_handler\n"));
 		return -1;
 	}
-	res = ctdb_register_message_handler(ctdb, client, srvid, daemon_message_handler, client);
+	res = srvid_register(ctdb->srv, client, srvid, daemon_message_handler,
+			     client);
 	if (res != 0) {
 		DEBUG(DEBUG_ERR,(__location__ " Failed to register handler %llu in daemon\n", 
 			 (unsigned long long)srvid));
@@ -181,12 +196,12 @@ int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_i
  */
 int daemon_deregister_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid)
 {
-	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+	struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
 	if (client == NULL) {
 		DEBUG(DEBUG_ERR,("Bad client_id in daemon_request_deregister_message_handler\n"));
 		return -1;
 	}
-	return ctdb_deregister_message_handler(ctdb, srvid, client);
+	return srvid_deregister(ctdb->srv, srvid, client);
 }
 
 int daemon_check_srvids(struct ctdb_context *ctdb, TDB_DATA indata,
@@ -211,7 +226,7 @@ int daemon_check_srvids(struct ctdb_context *ctdb, TDB_DATA indata,
 		return -1;
 	}
 	for (i=0; i<num_ids; i++) {
-		if (ctdb_check_message_handler(ctdb, ids[i])) {
+		if (srvid_exists(ctdb->srv, ids[i]) == 0) {
 			results[i/8] |= (1 << (i%8));
 		}
 	}
@@ -228,7 +243,7 @@ static int ctdb_client_destructor(struct ctdb_client *client)
 	struct ctdb_db_context *ctdb_db;
 
 	ctdb_takeover_client_destructor_hook(client);
-	ctdb_reqid_remove(client->ctdb, client->client_id);
+	reqid_remove(client->ctdb->idr, client->client_id);
 	client->ctdb->num_clients--;
 
 	if (client->num_persistent_updates != 0) {
@@ -258,7 +273,7 @@ static int ctdb_client_destructor(struct ctdb_client *client)
   from a local client over the unix domain socket
  */
 static void daemon_request_message_from_client(struct ctdb_client *client, 
-					       struct ctdb_req_message *c)
+					       struct ctdb_req_message_old *c)
 {
 	TDB_DATA data;
 	int res;
@@ -303,7 +318,7 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state)
 {
 	struct daemon_call_state *dstate = talloc_get_type(state->async.private_data, 
 							   struct daemon_call_state);
-	struct ctdb_reply_call *r;
+	struct ctdb_reply_call_old *r;
 	int res;
 	uint32_t length;
 	struct ctdb_client *client = dstate->client;
@@ -321,7 +336,7 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state)
 		return;
 	}
 
-	length = offsetof(struct ctdb_reply_call, data) + dstate->call->reply_data.dsize;
+	length = offsetof(struct ctdb_reply_call_old, data) + dstate->call->reply_data.dsize;
 	/* If the client asked for readonly FETCH, we remapped this to 
 	   FETCH_WITH_HEADER when calling the daemon. So we must
 	   strip the extra header off the reply data before passing
@@ -333,7 +348,7 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state)
 	}
 
 	r = ctdbd_allocate_pkt(client->ctdb, dstate, CTDB_REPLY_CALL, 
-			       length, struct ctdb_reply_call);
+			       length, struct ctdb_reply_call_old);
 	if (r == NULL) {
 		DEBUG(DEBUG_ERR, (__location__ " Failed to allocate reply_call in ctdb daemon\n"));
 		CTDB_DECREMENT_STAT(client->ctdb, pending_calls);
@@ -386,7 +401,7 @@ static void daemon_incoming_packet_wrap(void *p, struct ctdb_req_header *hdr)
 		return;
 	}
 
-	client = ctdb_reqid_find(w->ctdb, w->client_id, struct ctdb_client);
+	client = reqid_find(w->ctdb->idr, w->client_id, struct ctdb_client);
 	if (client == NULL) {
 		DEBUG(DEBUG_ERR,(__location__ " Packet for disconnected client %u\n",
 			 w->client_id));
@@ -401,7 +416,7 @@ static void daemon_incoming_packet_wrap(void *p, struct ctdb_req_header *hdr)
 
 struct ctdb_deferred_fetch_call {
 	struct ctdb_deferred_fetch_call *next, *prev;
-	struct ctdb_req_call *c;
+	struct ctdb_req_call_old *c;
 	struct ctdb_daemon_packet_wrap *w;
 };
 
@@ -415,8 +430,9 @@ struct ctdb_deferred_requeue {
 };
 
 /* called from a timer event and starts reprocessing the deferred call.*/
-static void reprocess_deferred_call(struct event_context *ev, struct timed_event *te, 
-				       struct timeval t, void *private_data)
+static void reprocess_deferred_call(struct tevent_context *ev,
+				    struct tevent_timer *te,
+				    struct timeval t, void *private_data)
 {
 	struct ctdb_deferred_requeue *dfr = (struct ctdb_deferred_requeue *)private_data;
 	struct ctdb_client *client = dfr->client;
@@ -447,7 +463,7 @@ static int deferred_fetch_queue_destructor(struct ctdb_deferred_fetch_queue *dfq
 
 		DLIST_REMOVE(dfq->deferred_calls, dfc);
 
-		client = ctdb_reqid_find(dfc->w->ctdb, dfc->w->client_id, struct ctdb_client);
+		client = reqid_find(dfc->w->ctdb->idr, dfc->w->client_id, struct ctdb_client);
 		if (client == NULL) {
 			DEBUG(DEBUG_ERR,(__location__ " Packet for disconnected client %u\n",
 				 dfc->w->client_id));
@@ -464,7 +480,8 @@ static int deferred_fetch_queue_destructor(struct ctdb_deferred_fetch_queue *dfq
 		dfr->dfc    = talloc_steal(dfr, dfc);
 		dfr->client = client;
 
-		event_add_timed(dfc->w->ctdb->ev, client, timeval_zero(), reprocess_deferred_call, dfr);
+		tevent_add_timer(dfc->w->ctdb->ev, client, timeval_zero(),
+				 reprocess_deferred_call, dfr);
 	}
 
 	return 0;
@@ -488,8 +505,8 @@ static void *insert_dfq_callback(void *parm, void *data)
    free the context and context for all deferred requests to cause them to be
    re-inserted into the event system.
 */
-static void dfq_timeout(struct event_context *ev, struct timed_event *te, 
-				  struct timeval t, void *private_data)
+static void dfq_timeout(struct tevent_context *ev, struct tevent_timer *te,
+			struct timeval t, void *private_data)
 {
 	talloc_free(private_data);
 }
@@ -524,7 +541,8 @@ static int setup_deferred_fetch_locks(struct ctdb_db_context *ctdb_db, struct ct
 
 	/* if the fetch havent completed in 30 seconds, just tear it all down
 	   and let it try again as the events are reissued */
-	event_add_timed(ctdb_db->ctdb->ev, dfq, timeval_current_ofs(30, 0), dfq_timeout, dfq);
+	tevent_add_timer(ctdb_db->ctdb->ev, dfq, timeval_current_ofs(30, 0),
+			 dfq_timeout, dfq);
 
 	talloc_free(k);
 	return 0;
@@ -534,7 +552,7 @@ static int setup_deferred_fetch_locks(struct ctdb_db_context *ctdb_db, struct ct
    if it is, make this call deferred to be reprocessed later when
    the in-flight fetch completes.
 */
-static int requeue_duplicate_fetch(struct ctdb_db_context *ctdb_db, struct ctdb_client *client, TDB_DATA key, struct ctdb_req_call *c)
+static int requeue_duplicate_fetch(struct ctdb_db_context *ctdb_db, struct ctdb_client *client, TDB_DATA key, struct ctdb_req_call_old *c)
 {
 	uint32_t *k;
 	struct ctdb_deferred_fetch_queue *dfq;
@@ -572,7 +590,7 @@ static int requeue_duplicate_fetch(struct ctdb_db_context *ctdb_db, struct ctdb_
 	dfc->w->ctdb = ctdb_db->ctdb;
 	dfc->w->client_id = client->client_id;
 
-	DLIST_ADD_END(dfq->deferred_calls, dfc, NULL);
+	DLIST_ADD_END(dfq->deferred_calls, dfc);
 
 	return 0;
 }
@@ -583,7 +601,7 @@ static int requeue_duplicate_fetch(struct ctdb_db_context *ctdb_db, struct ctdb_
   from a local client over the unix domain socket
  */
 static void daemon_request_call_from_client(struct ctdb_client *client, 
-					    struct ctdb_req_call *c)
+					    struct ctdb_req_call_old *c)
 {
 	struct ctdb_call_state *state;
 	struct ctdb_db_context *ctdb_db;
@@ -658,7 +676,7 @@ static void daemon_request_call_from_client(struct ctdb_client *client,
 		}
 	}
 
-	/* Dont do READONLY if we dont have a tracking database */
+	/* Dont do READONLY if we don't have a tracking database */
 	if ((c->flags & CTDB_WANT_READONLY) && !ctdb_db->readonly) {
 		c->flags &= ~CTDB_WANT_READONLY;
 	}
@@ -793,7 +811,7 @@ static void daemon_request_call_from_client(struct ctdb_client *client,
 
 
 static void daemon_request_control_from_client(struct ctdb_client *client, 
-					       struct ctdb_req_control *c);
+					       struct ctdb_req_control_old *c);
 
 /* data contains a packet from the client */
 static void daemon_incoming_packet(void *p, struct ctdb_req_header *hdr)
@@ -822,17 +840,17 @@ static void daemon_incoming_packet(void *p, struct ctdb_req_header *hdr)
 	switch (hdr->operation) {
 	case CTDB_REQ_CALL:
 		CTDB_INCREMENT_STAT(ctdb, client.req_call);
-		daemon_request_call_from_client(client, (struct ctdb_req_call *)hdr);
+		daemon_request_call_from_client(client, (struct ctdb_req_call_old *)hdr);
 		break;
 
 	case CTDB_REQ_MESSAGE:
 		CTDB_INCREMENT_STAT(ctdb, client.req_message);
-		daemon_request_message_from_client(client, (struct ctdb_req_message *)hdr);
+		daemon_request_message_from_client(client, (struct ctdb_req_message_old *)hdr);
 		break;
 
 	case CTDB_REQ_CONTROL:
 		CTDB_INCREMENT_STAT(ctdb, client.req_control);
-		daemon_request_control_from_client(client, (struct ctdb_req_control *)hdr);
+		daemon_request_control_from_client(client, (struct ctdb_req_control_old *)hdr);
 		break;
 
 	default:
@@ -900,8 +918,9 @@ static int ctdb_clientpid_destructor(struct ctdb_client_pid_list *client_pid)
 }
 
 
-static void ctdb_accept_client(struct event_context *ev, struct fd_event *fde, 
-			 uint16_t flags, void *private_data)
+static void ctdb_accept_client(struct tevent_context *ev,
+			       struct tevent_fd *fde, uint16_t flags,
+			       void *private_data)
 {
 	struct sockaddr_un addr;
 	socklen_t len;
@@ -930,7 +949,7 @@ static void ctdb_accept_client(struct event_context *ev, struct fd_event *fde,
 
 	client->ctdb = ctdb;
 	client->fd = fd;
-	client->client_id = ctdb_reqid_new(ctdb, client);
+	client->client_id = reqid_new(ctdb->idr, client);
 	client->pid = peer_pid;
 
 	client_pid = talloc(client, struct ctdb_client_pid_list);
@@ -1083,7 +1102,7 @@ static void ctdb_tevent_trace(enum tevent_trace_point tp,
 			if (diff.tv_sec > 3) {
 				DEBUG(DEBUG_ERR,
 				      ("Handling event took %ld seconds!\n",
-				       diff.tv_sec));
+				       (long)diff.tv_sec));
 			}
 		}
 		tevent_before_wait_ts = now;
@@ -1095,7 +1114,7 @@ static void ctdb_tevent_trace(enum tevent_trace_point tp,
 			if (diff.tv_sec > 3) {
 				DEBUG(DEBUG_CRIT,
 				      ("No event for %ld seconds!\n",
-				       diff.tv_sec));
+				       (long)diff.tv_sec));
 			}
 		}
 		tevent_after_wait_ts = now;
@@ -1193,7 +1212,7 @@ static void ctdb_set_my_pnn(struct ctdb_context *ctdb)
 int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork)
 {
 	int res, ret = -1;
-	struct fd_event *fde;
+	struct tevent_fd *fde;
 
 	/* create a unix domain stream socket to listen to */
 	res = ux_socket_bind(ctdb);
@@ -1240,7 +1259,7 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork)
 		DEBUG(DEBUG_NOTICE, ("Set real-time scheduler priority\n"));
 	}
 
-	ctdb->ev = event_context_init(NULL);
+	ctdb->ev = tevent_context_init(NULL);
 	tevent_loop_allow_nesting(ctdb->ev);
 	tevent_set_trace_callback(ctdb->ev, ctdb_tevent_trace, ctdb);
 	ret = ctdb_init_tevent_logging(ctdb);
@@ -1257,6 +1276,11 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork)
 
 	ctdb_set_child_logging(ctdb);
 
+	if (srvid_init(ctdb, &ctdb->srv) != 0) {
+		DEBUG(DEBUG_CRIT,("Failed to setup message srvid context\n"));
+		exit(1);
+	}
+
 	/* initialize statistics collection */
 	ctdb_statistics_init(ctdb);
 
@@ -1319,9 +1343,8 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork)
 	}
 
 	/* now start accepting clients, only can do this once frozen */
-	fde = event_add_fd(ctdb->ev, ctdb, ctdb->daemon.sd, 
-			   EVENT_FD_READ,
-			   ctdb_accept_client, ctdb);
+	fde = tevent_add_fd(ctdb->ev, ctdb, ctdb->daemon.sd, TEVENT_FD_READ,
+			    ctdb_accept_client, ctdb);
 	if (fde == NULL) {
 		ctdb_fatal(ctdb, "Failed to add daemon socket to event loop");
 	}
@@ -1353,7 +1376,7 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork)
 	lockdown_memory(ctdb->valgrinding);
 
 	/* go into a wait loop to allow other nodes to complete */
-	event_loop_wait(ctdb->ev);
+	tevent_loop_wait(ctdb->ev);
 
 	DEBUG(DEBUG_CRIT,("event_loop_wait() returned. this should not happen\n"));
 	exit(1);
@@ -1401,7 +1424,7 @@ struct ctdb_req_header *_ctdb_transport_allocate(struct ctdb_context *ctdb,
 struct daemon_control_state {
 	struct daemon_control_state *next, *prev;
 	struct ctdb_client *client;
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	uint32_t reqid;
 	struct ctdb_node *node;
 };
@@ -1417,17 +1440,17 @@ static void daemon_control_callback(struct ctdb_context *ctdb,
 	struct daemon_control_state *state = talloc_get_type(private_data, 
 							     struct daemon_control_state);
 	struct ctdb_client *client = state->client;
-	struct ctdb_reply_control *r;
+	struct ctdb_reply_control_old *r;
 	size_t len;
 	int ret;
 
 	/* construct a message to send to the client containing the data */
-	len = offsetof(struct ctdb_reply_control, data) + data.dsize;
+	len = offsetof(struct ctdb_reply_control_old, data) + data.dsize;
 	if (errormsg) {
 		len += strlen(errormsg);
 	}
 	r = ctdbd_allocate_pkt(ctdb, state, CTDB_REPLY_CONTROL, len, 
-			       struct ctdb_reply_control);
+			       struct ctdb_reply_control_old);
 	CTDB_NO_MEMORY_VOID(ctdb, r);
 
 	r->hdr.reqid     = state->reqid;
@@ -1475,7 +1498,7 @@ static int daemon_control_destructor(struct daemon_control_state *state)
   from a local client over the unix domain socket
  */
 static void daemon_request_control_from_client(struct ctdb_client *client, 
-					       struct ctdb_req_control *c)
+					       struct ctdb_req_control_old *c)
 {
 	TDB_DATA data;
 	int res;
@@ -1555,18 +1578,14 @@ struct ctdb_local_message {
 	TDB_DATA data;
 };
 
-static void ctdb_local_message_trigger(struct event_context *ev, struct timed_event *te, 
+static void ctdb_local_message_trigger(struct tevent_context *ev,
+				       struct tevent_timer *te,
 				       struct timeval t, void *private_data)
 {
-	struct ctdb_local_message *m = talloc_get_type(private_data, 
-						       struct ctdb_local_message);
-	int res;
+	struct ctdb_local_message *m = talloc_get_type(
+		private_data, struct ctdb_local_message);
 
-	res = ctdb_dispatch_message(m->ctdb, m->srvid, m->data);
-	if (res != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Failed to dispatch message for srvid=%llu\n", 
-			  (unsigned long long)m->srvid));
-	}
+	srvid_dispatch(m->ctdb->srv, m->srvid, CTDB_SRVID_ALL, m->data);
 	talloc_free(m);
 }
 
@@ -1586,7 +1605,8 @@ static int ctdb_local_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DAT
 	}
 
 	/* this needs to be done as an event to prevent recursion */
-	event_add_timed(ctdb->ev, m, timeval_zero(), ctdb_local_message_trigger, m);
+	tevent_add_timer(ctdb->ev, m, timeval_zero(),
+			 ctdb_local_message_trigger, m);
 	return 0;
 }
 
@@ -1596,7 +1616,7 @@ static int ctdb_local_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DAT
 int ctdb_daemon_send_message(struct ctdb_context *ctdb, uint32_t pnn,
 			     uint64_t srvid, TDB_DATA data)
 {
-	struct ctdb_req_message *r;
+	struct ctdb_req_message_old *r;
 	int len;
 
 	if (ctdb->methods == NULL) {
@@ -1609,9 +1629,9 @@ int ctdb_daemon_send_message(struct ctdb_context *ctdb, uint32_t pnn,
 		return ctdb_local_message(ctdb, srvid, data);
 	}
 
-	len = offsetof(struct ctdb_req_message, data) + data.dsize;
+	len = offsetof(struct ctdb_req_message_old, data) + data.dsize;
 	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_MESSAGE, len,
-				    struct ctdb_req_message);
+				    struct ctdb_req_message_old);
 	CTDB_NO_MEMORY(ctdb, r);
 
 	r->hdr.destnode  = pnn;
@@ -1651,19 +1671,19 @@ static int ctdb_client_notify_destructor(struct ctdb_client_notify_list *nl)
 
 int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata)
 {
-	struct ctdb_client_notify_register *notify = (struct ctdb_client_notify_register *)indata.dptr;
-        struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); 
+	struct ctdb_notify_data_old *notify = (struct ctdb_notify_data_old *)indata.dptr;
+        struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
 	struct ctdb_client_notify_list *nl;
 
 	DEBUG(DEBUG_INFO,("Register srvid %llu for client %d\n", (unsigned long long)notify->srvid, client_id));
 
-	if (indata.dsize < offsetof(struct ctdb_client_notify_register, notify_data)) {
+	if (indata.dsize < offsetof(struct ctdb_notify_data_old, notify_data)) {
 		DEBUG(DEBUG_ERR,(__location__ " Too little data in control : %d\n", (int)indata.dsize));
 		return -1;
 	}
 
-	if (indata.dsize != (notify->len + offsetof(struct ctdb_client_notify_register, notify_data))) {
-		DEBUG(DEBUG_ERR,(__location__ " Wrong amount of data in control. Got %d, expected %d\n", (int)indata.dsize, (int)(notify->len + offsetof(struct ctdb_client_notify_register, notify_data))));
+	if (indata.dsize != (notify->len + offsetof(struct ctdb_notify_data_old, notify_data))) {
+		DEBUG(DEBUG_ERR,(__location__ " Wrong amount of data in control. Got %d, expected %d\n", (int)indata.dsize, (int)(notify->len + offsetof(struct ctdb_notify_data_old, notify_data))));
 		return -1;
 	}
 
@@ -1700,11 +1720,11 @@ int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_
 
 int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata)
 {
-	struct ctdb_client_notify_deregister *notify = (struct ctdb_client_notify_deregister *)indata.dptr;
-        struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); 
+	uint64_t srvid = *(uint64_t *)indata.dptr;
+        struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
 	struct ctdb_client_notify_list *nl;
 
-	DEBUG(DEBUG_INFO,("Deregister srvid %llu for client %d\n", (unsigned long long)notify->srvid, client_id));
+	DEBUG(DEBUG_INFO,("Deregister srvid %llu for client %d\n", (unsigned long long)srvid, client_id));
 
         if (client == NULL) {
                 DEBUG(DEBUG_ERR,(__location__ " Could not find client parent structure. You can not send this control to a remote node\n"));
@@ -1712,12 +1732,12 @@ int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb, uint32_t clien
         }
 
 	for(nl=client->notify; nl; nl=nl->next) {
-		if (nl->srvid == notify->srvid) {
+		if (nl->srvid == srvid) {
 			break;
 		}
 	}
 	if (nl == NULL) {
-                DEBUG(DEBUG_ERR,(__location__ " No notification for srvid:%llu found for this client\n", (unsigned long long)notify->srvid));
+                DEBUG(DEBUG_ERR,(__location__ " No notification for srvid:%llu found for this client\n", (unsigned long long)srvid));
                 return -1;
         }
 
@@ -1769,7 +1789,7 @@ int32_t ctdb_control_process_exists(struct ctdb_context *ctdb, pid_t pid)
 
 int ctdb_control_getnodesfile(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
 {
-	struct ctdb_node_map *node_map = NULL;
+	struct ctdb_node_map_old *node_map = NULL;
 
 	CHECK_CONTROL_DATA_SIZE(0);
 
@@ -1806,3 +1826,35 @@ void ctdb_shutdown_sequence(struct ctdb_context *ctdb, int exit_code)
 	DEBUG(DEBUG_NOTICE,("Shutdown sequence complete, exiting.\n"));
 	exit(exit_code);
 }
+
+/* When forking the main daemon and the child process needs to connect
+ * back to the daemon as a client process, this function can be used
+ * to change the ctdb context from daemon into client mode.  The child
+ * process must be created using ctdb_fork() and not fork() -
+ * ctdb_fork() does some necessary housekeeping.
+ */
+int switch_from_server_to_client(struct ctdb_context *ctdb, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	/* Add extra information so we can identify this in the logs */
+	va_start(ap, fmt);
+	debug_extra = talloc_strdup_append(talloc_vasprintf(NULL, fmt, ap), ":");
+	va_end(ap);
+
+	/* get a new event context */
+	ctdb->ev = tevent_context_init(ctdb);
+	tevent_loop_allow_nesting(ctdb->ev);
+
+	/* Connect to main CTDB daemon */
+	ret = ctdb_socket_connect(ctdb);
+	if (ret != 0) {
+		DEBUG(DEBUG_ALERT, (__location__ " Failed to init ctdb client\n"));
+		return -1;
+	}
+
+	ctdb->can_send_controls = true;
+
+	return 0;
+}
diff --git a/ctdb/server/ctdb_event_helper.c b/ctdb/server/ctdb_event_helper.c
index a1b5318..8db02b9 100644
--- a/ctdb/server/ctdb_event_helper.c
+++ b/ctdb/server/ctdb_event_helper.c
@@ -17,10 +17,17 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
+#include "system/wait.h"
+
+#include <talloc.h>
+
 #include "ctdb_private.h"
 
+#include "common/system.h"
+
 static char *progname = NULL;
 
 
diff --git a/ctdb/server/ctdb_fork.c b/ctdb/server/ctdb_fork.c
new file mode 100644
index 0000000..661e72c
--- /dev/null
+++ b/ctdb/server/ctdb_fork.c
@@ -0,0 +1,174 @@
+/* 
+   functions to track and manage processes
+
+   Copyright (C) Ronnie Sahlberg 2012
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/wait.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/rb_tree.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
+
+void ctdb_set_child_info(TALLOC_CTX *mem_ctx, const char *child_name_fmt, ...)
+{
+	if (child_name_fmt != NULL) {
+		va_list ap;
+		char *t;
+
+		va_start(ap, child_name_fmt);
+		t = talloc_vasprintf(mem_ctx, child_name_fmt, ap);
+		debug_extra = talloc_asprintf(mem_ctx, "%s:", t);
+		talloc_free(t);
+		va_end(ap);
+	}
+}
+
+void ctdb_track_child(struct ctdb_context *ctdb, pid_t pid)
+{
+	char *process;
+
+	/* Only CTDB main daemon should track child processes */
+	if (getpid() != ctdb->ctdbd_pid) {
+		return;
+	}
+
+	process = talloc_asprintf(ctdb->child_processes, "process:%d", (int)pid);
+	trbt_insert32(ctdb->child_processes, pid, process);
+}
+
+/*
+ * This function forks a child process and drops the realtime 
+ * scheduler for the child process.
+ */
+pid_t ctdb_fork(struct ctdb_context *ctdb)
+{
+	pid_t pid;
+
+	pid = fork();
+	if (pid == -1) {
+		return -1;
+	}
+	if (pid == 0) {
+		ctdb_set_child_info(ctdb, NULL);
+
+		/* Close the Unix Domain socket and the TCP socket.
+		 * This ensures that none of the child processes will
+		 * look like the main daemon when it is not running.
+		 * tevent needs to be stopped before closing sockets.
+		 */
+		if (ctdb->ev != NULL) {
+			talloc_free(ctdb->ev);
+			ctdb->ev = NULL;
+		}
+		if (ctdb->daemon.sd != -1) {
+			close(ctdb->daemon.sd);
+			ctdb->daemon.sd = -1;
+		}
+		if (ctdb->methods != NULL) {
+			ctdb->methods->shutdown(ctdb);
+		}
+
+		/* The child does not need to be realtime */
+		if (ctdb->do_setsched) {
+			reset_scheduler();
+		}
+		ctdb->can_send_controls = false;
+
+		return 0;
+	}
+
+	ctdb_track_child(ctdb, pid);
+	return pid;
+}
+
+static void ctdb_sigchld_handler(struct tevent_context *ev,
+	struct tevent_signal *te, int signum, int count,
+	void *dont_care, 
+	void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	int status;
+	pid_t pid = -1;
+
+	while (pid != 0) {
+		pid = waitpid(-1, &status, WNOHANG);
+		if (pid == -1) {
+			DEBUG(DEBUG_ERR, (__location__ " waitpid() returned error. errno:%d\n", errno));
+			return;
+		}
+		if (pid > 0) {
+			char *process;
+
+			if (getpid() != ctdb->ctdbd_pid) {
+				continue;
+			}
+
+			process = trbt_lookup32(ctdb->child_processes, pid);
+			if (process == NULL) {
+				DEBUG(DEBUG_ERR,("Got SIGCHLD from pid:%d we didn not spawn with ctdb_fork\n", pid));
+			}
+
+			DEBUG(DEBUG_DEBUG, ("SIGCHLD from %d %s\n", (int)pid, process));
+			talloc_free(process);
+		}
+	}
+}
+
+
+struct tevent_signal *
+ctdb_init_sigchld(struct ctdb_context *ctdb)
+{
+	struct tevent_signal *se;
+
+	ctdb->child_processes = trbt_create(ctdb, 0);
+
+	se = tevent_add_signal(ctdb->ev, ctdb, SIGCHLD, 0, ctdb_sigchld_handler, ctdb);
+	return se;
+}
+
+int
+ctdb_kill(struct ctdb_context *ctdb, pid_t pid, int signum)
+{
+	char *process;
+
+	if (signum == 0) {
+		return kill(pid, signum);
+	}
+
+	if (getpid() != ctdb->ctdbd_pid) {
+		return kill(pid, signum);
+	}
+
+	process = trbt_lookup32(ctdb->child_processes, pid);
+	if (process == NULL) {
+		DEBUG(DEBUG_ERR,("ctdb_kill: trying to kill(%d, %d) a process that does not exist\n", pid, signum));
+		return 0;
+	}
+
+	return kill(pid, signum);
+}
diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c
index ced2cca..1dd05e2 100644
--- a/ctdb/server/ctdb_freeze.c
+++ b/ctdb/server/ctdb_freeze.c
@@ -16,15 +16,270 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
-#include "lib/util/dlinklist.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
-#include "../common/rb_tree.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+
+#include "common/rb_tree.h"
+#include "common/common.h"
+#include "common/logging.h"
+
+/**
+ * Cancel a transaction on database
+ */
+static int db_transaction_cancel_handler(struct ctdb_db_context *ctdb_db,
+					 void *private_data)
+{
+	int ret;
+
+	tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	ret = tdb_transaction_cancel(ctdb_db->ltdb->tdb);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Failed to cancel transaction for db %s\n",
+				  ctdb_db->db_name));
+	}
+	tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	return 0;
+}
+
+/**
+ * Start a transaction on database
+ */
+static int db_transaction_start_handler(struct ctdb_db_context *ctdb_db,
+					void *private_data)
+{
+	bool freeze_transaction_started = *(bool *)private_data;
+	int ret;
+
+	tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	if (freeze_transaction_started) {
+		ret = tdb_transaction_cancel(ctdb_db->ltdb->tdb);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,
+			      ("Failed to cancel transaction for db %s\n",
+			       ctdb_db->db_name));
+		}
+	}
+	ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
+	tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Failed to start transaction for db %s\n",
+				  ctdb_db->db_name));
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Commit a transaction on database
+ */
+static int db_transaction_commit_handler(struct ctdb_db_context *ctdb_db,
+					 void *private_data)
+{
+	int healthy_nodes = *(int *)private_data;
+	int ret;
+
+	tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	ret = tdb_transaction_commit(ctdb_db->ltdb->tdb);
+	tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Failed to commit transaction for db %s\n",
+				  ctdb_db->db_name));
+		return -1;
+	}
+
+	ret = ctdb_update_persistent_health(ctdb_db->ctdb, ctdb_db, NULL,
+					    healthy_nodes);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Failed to update persistent health for db %s\n",
+				  ctdb_db->db_name));
+	}
+	return ret;
+}
+
+/* a list of control requests waiting for db freeze */
+struct ctdb_db_freeze_waiter {
+	struct ctdb_db_freeze_waiter *next, *prev;
+	struct ctdb_context *ctdb;
+	void *private_data;
+	int32_t status;
+};
+
+/* a handle to a db freeze lock child process */
+struct ctdb_db_freeze_handle {
+	struct ctdb_db_context *ctdb_db;
+	struct lock_request *lreq;
+	struct ctdb_db_freeze_waiter *waiters;
+};
+
+/**
+ * Called when freeing database freeze handle
+ */
+static int ctdb_db_freeze_handle_destructor(struct ctdb_db_freeze_handle *h)
+{
+	struct ctdb_db_context *ctdb_db = h->ctdb_db;
+
+	DEBUG(DEBUG_ERR, ("Release freeze handle for db %s\n",
+			  ctdb_db->db_name));
+
+	/* Cancel any pending transactions */
+	if (ctdb_db->freeze_transaction_started) {
+		db_transaction_cancel_handler(ctdb_db, NULL);
+		ctdb_db->freeze_transaction_started = false;
+	}
+	ctdb_db->freeze_mode = CTDB_FREEZE_NONE;
+	ctdb_db->freeze_handle = NULL;
+
+	talloc_free(h->lreq);
+	return 0;
+}
+
+/**
+ * Called when a database is frozen
+ */
+static void ctdb_db_freeze_handler(void *private_data, bool locked)
+{
+	struct ctdb_db_freeze_handle *h = talloc_get_type_abort(
+		private_data, struct ctdb_db_freeze_handle);
+	struct ctdb_db_freeze_waiter *w;
+
+	if (h->ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_ERR, ("Freeze db child died - unfreezing\n"));
+		h->ctdb_db->freeze_mode = CTDB_FREEZE_NONE;
+		talloc_free(h);
+		return;
+	}
+
+	if (!locked) {
+		DEBUG(DEBUG_ERR, ("Failed to get db lock for %s\n",
+				  h->ctdb_db->db_name));
+		h->ctdb_db->freeze_mode = CTDB_FREEZE_NONE;
+		talloc_free(h);
+		return;
+	}
+
+	h->ctdb_db->freeze_mode = CTDB_FREEZE_FROZEN;
+
+	/* notify the waiters */
+	while ((w = h->waiters) != NULL) {
+		w->status = 0;
+		DLIST_REMOVE(h->waiters, w);
+		talloc_free(w);
+	}
+}
+
+/**
+ * Start freeze process for a database
+ */
+static void ctdb_start_db_freeze(struct ctdb_db_context *ctdb_db)
+{
+	struct ctdb_db_freeze_handle *h;
+
+	if (ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) {
+		return;
+	}
+
+	if (ctdb_db->freeze_handle != NULL) {
+		return;
+	}
+
+	DEBUG(DEBUG_ERR, ("Freeze db: %s\n", ctdb_db->db_name));
+
+	ctdb_stop_vacuuming(ctdb_db->ctdb);
+
+	h = talloc_zero(ctdb_db, struct ctdb_db_freeze_handle);
+	CTDB_NO_MEMORY_FATAL(ctdb_db->ctdb, h);
+
+	h->ctdb_db = ctdb_db;
+	h->lreq = ctdb_lock_db(h, ctdb_db, false, ctdb_db_freeze_handler, h);
+	CTDB_NO_MEMORY_FATAL(ctdb_db->ctdb, h->lreq);
+	talloc_set_destructor(h, ctdb_db_freeze_handle_destructor);
+
+	ctdb_db->freeze_handle = h;
+	ctdb_db->freeze_mode = CTDB_FREEZE_PENDING;
+}
+
+/**
+ * Reply to a waiter for db freeze
+ */
+static int ctdb_db_freeze_waiter_destructor(struct ctdb_db_freeze_waiter *w)
+{
+	/* 'c' pointer is talloc_memdup(), so cannot use talloc_get_type */
+	struct ctdb_req_control_old *c =
+		(struct ctdb_req_control_old *)w->private_data;
+
+	ctdb_request_control_reply(w->ctdb, c, NULL, w->status, NULL);
+	return 0;
+}
+
+/**
+ * freeze a database
+ */
+int32_t ctdb_control_db_freeze(struct ctdb_context *ctdb,
+			       struct ctdb_req_control_old *c,
+			       uint32_t db_id,
+			       bool *async_reply)
+{
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_db_freeze_waiter *w;
+
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR, ("Freeze db for unknown dbid 0x%08x\n", db_id));
+		return -1;
+	}
+
+	if (ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_ERR, ("Freeze db: %s frozen\n", ctdb_db->db_name));
+		return 0;
+	}
+
+	ctdb_start_db_freeze(ctdb_db);
+
+	/* add ourselves to the list of waiters */
+	w = talloc(ctdb_db->freeze_handle, struct ctdb_db_freeze_waiter);
+	CTDB_NO_MEMORY(ctdb, w);
+	w->ctdb = ctdb;
+	w->private_data = talloc_steal(w, c);
+	w->status = -1;
+	talloc_set_destructor(w, ctdb_db_freeze_waiter_destructor);
+	DLIST_ADD(ctdb_db->freeze_handle->waiters, w);
+
+	*async_reply = true;
+	return 0;
+}
+
+/**
+ * Thaw a database
+ */
+int32_t ctdb_control_db_thaw(struct ctdb_context *ctdb, uint32_t db_id)
+{
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR, ("Thaw db for unknown dbid 0x%08x\n", db_id));
+		return -1;
+	}
+
+	DEBUG(DEBUG_ERR, ("Thaw db: %s generation %u\n", ctdb_db->db_name,
+			  ctdb_db->generation));
+
+	TALLOC_FREE(ctdb_db->freeze_handle);
+	ctdb_call_resend_db(ctdb_db);
+	return 0;
+}
+
 
 /*
   a list of control requests waiting for a freeze lock child to get
@@ -33,7 +288,7 @@
 struct ctdb_freeze_waiter {
 	struct ctdb_freeze_waiter *next, *prev;
 	struct ctdb_context *ctdb;
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	uint32_t priority;
 	int32_t status;
 };
@@ -42,36 +297,34 @@ struct ctdb_freeze_waiter {
 struct ctdb_freeze_handle {
 	struct ctdb_context *ctdb;
 	uint32_t priority;
-	struct lock_request *lreq;
+	unsigned int num_total, num_locked, num_failed;
 	struct ctdb_freeze_waiter *waiters;
 };
 
+static int db_thaw(struct ctdb_db_context *ctdb_db, void *private_data)
+{
+	talloc_free(ctdb_db->freeze_handle);
+	return 0;
+}
+
 /*
   destroy a freeze handle
- */	
+ */
 static int ctdb_freeze_handle_destructor(struct ctdb_freeze_handle *h)
 {
 	struct ctdb_context *ctdb = h->ctdb;
-	struct ctdb_db_context *ctdb_db;
 
-	DEBUG(DEBUG_ERR,("Release freeze handler for prio %u\n", h->priority));
+	DEBUG(DEBUG_ERR,("Release freeze handle for prio %u\n", h->priority));
 
 	/* cancel any pending transactions */
 	if (ctdb->freeze_transaction_started) {
-		for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
-			if (ctdb_db->priority != h->priority) {
-				continue;
-			}
-			tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
-			if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
-				DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",
-					 ctdb_db->db_name));
-			}
-			tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
-		}
+		ctdb_db_prio_iterator(ctdb, h->priority,
+				      db_transaction_cancel_handler, NULL);
 		ctdb->freeze_transaction_started = false;
 	}
 
+	ctdb_db_prio_iterator(ctdb, h->priority, db_thaw, NULL);
+
 	ctdb->freeze_mode[h->priority]    = CTDB_FREEZE_NONE;
 	ctdb->freeze_handles[h->priority] = NULL;
 
@@ -113,21 +366,85 @@ static void ctdb_freeze_lock_handler(void *private_data, bool locked)
 	}
 }
 
-/*
-  destroy a waiter for a freeze mode change
+/**
+ * When single database is frozen
  */
-static int ctdb_freeze_waiter_destructor(struct ctdb_freeze_waiter *w)
+static int db_freeze_waiter_destructor(struct ctdb_db_freeze_waiter *w)
 {
-	ctdb_request_control_reply(w->ctdb, w->c, NULL, w->status, NULL);
+	struct ctdb_freeze_handle *h = talloc_get_type_abort(
+		w->private_data, struct ctdb_freeze_handle);
+
+	if (w->status == 0) {
+		h->num_locked += 1;
+	} else {
+		h->num_failed += 1;
+	}
+
+	/* Call ctdb_freeze_lock_handler() only when the status of all
+	 * databases is known.
+	 */
+	if (h->num_locked + h->num_failed == h->num_total) {
+		bool locked;
+
+		if (h->num_locked == h->num_total) {
+			locked = true;
+		} else {
+			locked = false;
+		}
+		ctdb_freeze_lock_handler(h, locked);
+	}
+	return 0;
+}
+
+/**
+ * Count the number of databases
+ */
+static int db_count(struct ctdb_db_context *ctdb_db, void *private_data)
+{
+	int *count = (int *)private_data;
+
+	*count += 1;
+
+	return 0;
+}
+
+/**
+ * Freeze a single database
+ */
+static int db_freeze(struct ctdb_db_context *ctdb_db, void *private_data)
+{
+	struct ctdb_freeze_handle *h = talloc_get_type_abort(
+		private_data, struct ctdb_freeze_handle);
+	struct ctdb_db_freeze_waiter *w;
+
+	ctdb_start_db_freeze(ctdb_db);
+
+	w = talloc(ctdb_db->freeze_handle, struct ctdb_db_freeze_waiter);
+	CTDB_NO_MEMORY(h->ctdb, w);
+	w->ctdb = h->ctdb;
+	w->private_data = h;
+	w->status = -1;
+	talloc_set_destructor(w, db_freeze_waiter_destructor);
+
+	if (ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) {
+		/* Early return if already frozen */
+		w->status = 0;
+		talloc_free(w);
+		return 0;
+	}
+
+	DLIST_ADD(ctdb_db->freeze_handle->waiters, w);
+
 	return 0;
 }
 
 /*
   start the freeze process for a certain priority
  */
-void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority)
+static void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority)
 {
 	struct ctdb_freeze_handle *h;
+	int ret;
 
 	if ((priority < 1) || (priority > NUM_DB_PRIORITIES)) {
 		DEBUG(DEBUG_ERR,(__location__ " Invalid db priority : %u\n", priority));
@@ -135,7 +452,53 @@ void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority)
 	}
 
 	if (ctdb->freeze_mode[priority] == CTDB_FREEZE_FROZEN) {
-		/* we're already frozen */
+		int count = 0;
+
+		/*
+		 * Check if all the databases are frozen
+		 *
+		 * It's possible that the databases can get attached after
+		 * initial freeze. This typically happens during startup as
+		 * CTDB will only attach persistent databases and go in to
+		 * startup freeze.  The recovery master during recovery will
+		 * attach all the missing databases.
+		 */
+
+		h = ctdb->freeze_handles[priority];
+		if (h == NULL) {
+			ctdb->freeze_mode[priority] = CTDB_FREEZE_NONE;
+			return;
+		}
+
+		ret = ctdb_db_prio_iterator(ctdb, priority, db_count, &count);
+		if (ret != 0) {
+			TALLOC_FREE(ctdb->freeze_handles[priority]);
+			ctdb->freeze_mode[priority] = CTDB_FREEZE_NONE;
+			return;
+		}
+
+		if (count != h->num_total) {
+			DEBUG(DEBUG_ERR, ("Freeze priority %u: incremental\n",
+					  priority));
+
+			h->num_total = count;
+			h->num_locked = 0;
+			h->num_failed = 0;
+
+			ctdb->freeze_mode[priority] = CTDB_FREEZE_PENDING;
+
+			ret = ctdb_db_prio_iterator(ctdb, priority,
+						    db_freeze, h);
+			if (ret != 0) {
+				TALLOC_FREE(ctdb->freeze_handles[priority]);
+				ctdb->freeze_mode[priority] = CTDB_FREEZE_NONE;
+			}
+		}
+		return;
+	}
+
+	if (ctdb->freeze_handles[priority] != NULL) {
+		/* already trying to freeze */
 		return;
 	}
 
@@ -144,26 +507,46 @@ void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority)
 	/* Stop any vacuuming going on: we don't want to wait. */
 	ctdb_stop_vacuuming(ctdb);
 
-	/* if there isn't a freeze lock child then create one */
-	if (ctdb->freeze_handles[priority] == NULL) {
-		h = talloc_zero(ctdb, struct ctdb_freeze_handle);
-		CTDB_NO_MEMORY_FATAL(ctdb, h);
-		h->ctdb = ctdb;
-		h->priority = priority;
-		talloc_set_destructor(h, ctdb_freeze_handle_destructor);
+	/* create freeze lock children for each database */
+	h = talloc_zero(ctdb, struct ctdb_freeze_handle);
+	CTDB_NO_MEMORY_FATAL(ctdb, h);
+	h->ctdb = ctdb;
+	h->priority = priority;
+	talloc_set_destructor(h, ctdb_freeze_handle_destructor);
+	ctdb->freeze_handles[priority] = h;
 
-		h->lreq = ctdb_lock_alldb_prio(h, ctdb, priority, false,
-					       ctdb_freeze_lock_handler, h);
-		CTDB_NO_MEMORY_FATAL(ctdb, h->lreq);
-		ctdb->freeze_handles[priority] = h;
-		ctdb->freeze_mode[priority] = CTDB_FREEZE_PENDING;
+	ret = ctdb_db_prio_iterator(ctdb, priority, db_count, &h->num_total);
+	if (ret != 0) {
+		talloc_free(h);
+		return;
+	}
+
+	ctdb->freeze_mode[priority] = CTDB_FREEZE_PENDING;
+
+	ret = ctdb_db_prio_iterator(ctdb, priority, db_freeze, h);
+	if (ret != 0) {
+		talloc_free(h);
+		return;
+	}
+
+	if (h->num_total == 0) {
+		ctdb->freeze_mode[priority] = CTDB_FREEZE_FROZEN;
 	}
 }
 
 /*
+  destroy a waiter for a freeze mode change
+ */
+static int ctdb_freeze_waiter_destructor(struct ctdb_freeze_waiter *w)
+{
+	ctdb_request_control_reply(w->ctdb, w->c, NULL, w->status, NULL);
+	return 0;
+}
+
+/*
   freeze the databases
  */
-int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply)
+int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control_old *c, bool *async_reply)
 {
 	struct ctdb_freeze_waiter *w;
 	uint32_t priority;
@@ -180,20 +563,25 @@ int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *
 		return -1;
 	}
 
+	ctdb_start_freeze(ctdb, priority);
+
 	if (ctdb->freeze_mode[priority] == CTDB_FREEZE_FROZEN) {
-		DEBUG(DEBUG_ERR, ("Freeze priority %u\n", priority));
+		DEBUG(DEBUG_ERR, ("Freeze priority %u: frozen\n", priority));
 		/* we're already frozen */
 		return 0;
 	}
 
-	ctdb_start_freeze(ctdb, priority);
-
-	/* add ourselves to list of waiters */
 	if (ctdb->freeze_handles[priority] == NULL) {
 		DEBUG(DEBUG_ERR,("No freeze lock handle when adding a waiter\n"));
 		return -1;
 	}
 
+	/* If there are no databases, we are done. */
+	if (ctdb->freeze_handles[priority]->num_total == 0) {
+		return 0;
+	}
+
+	/* add ourselves to list of waiters */
 	w = talloc(ctdb->freeze_handles[priority], struct ctdb_freeze_waiter);
 	CTDB_NO_MEMORY(ctdb, w);
 	w->ctdb     = ctdb;
@@ -209,20 +597,33 @@ int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *
 }
 
 
+static int db_freeze_block(struct ctdb_db_context *ctdb_db, void *private_data)
+{
+	struct tevent_context *ev = (struct tevent_context *)private_data;
+
+	ctdb_start_db_freeze(ctdb_db);
+
+	while (ctdb_db->freeze_mode == CTDB_FREEZE_PENDING) {
+		tevent_loop_once(ev);
+	}
+
+	if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) {
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
   block until we are frozen, used during daemon startup
  */
 bool ctdb_blocking_freeze(struct ctdb_context *ctdb)
 {
-	int i;
-
-	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
-		ctdb_start_freeze(ctdb, i);
+	int ret;
 
-		/* block until frozen */
-		while (ctdb->freeze_mode[i] == CTDB_FREEZE_PENDING) {
-			event_loop_once(ctdb->ev);
-		}
+	ret = ctdb_db_iterator(ctdb, db_freeze_block, ctdb->ev);
+	if (ret != 0) {
+		return false;
 	}
 
 	return true;
@@ -235,33 +636,13 @@ static void thaw_priority(struct ctdb_context *ctdb, uint32_t priority)
 
 	/* cancel any pending transactions */
 	if (ctdb->freeze_transaction_started) {
-		struct ctdb_db_context *ctdb_db;
-
-		for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
-			tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
-			if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
-				DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",
-					 ctdb_db->db_name));
-			}
-			tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
-		}
+		ctdb_db_prio_iterator(ctdb, priority,
+				      db_transaction_cancel_handler, NULL);
+		ctdb->freeze_transaction_started = false;
 	}
-	ctdb->freeze_transaction_started = false;
-
-#if 0
-	/* this hack can be used to get a copy of the databases at the end of a recovery */
-	system("mkdir -p /var/ctdb.saved; /usr/bin/rsync --delete -a /var/ctdb/ /var/ctdb.saved/$$ 2>&1 > /dev/null");
-#endif
 
-#if 0
-	/* and this one for local testing */
-	system("mkdir -p test.db.saved; /usr/bin/rsync --delete -a test.db/ test.db.saved/$$ 2>&1 > /dev/null");
-#endif
-
-	if (ctdb->freeze_handles[priority] != NULL) {
-		talloc_free(ctdb->freeze_handles[priority]);
-		ctdb->freeze_handles[priority] = NULL;
-	}
+	ctdb_db_prio_iterator(ctdb, priority, db_thaw, NULL);
+	TALLOC_FREE(ctdb->freeze_handles[priority]);
 }
 
 /*
@@ -295,46 +676,207 @@ int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority,
 	return 0;
 }
 
+/**
+ * Database transaction wrappers
+ *
+ * These functions are wrappers around transaction start/cancel/commit handlers.
+ */
 
-/*
-  start a transaction on all databases - used for recovery
+struct db_start_transaction_state {
+	uint32_t transaction_id;
+	bool transaction_started;
+};
+
+static int db_start_transaction(struct ctdb_db_context *ctdb_db,
+				void *private_data)
+{
+	struct db_start_transaction_state *state =
+		(struct db_start_transaction_state *)private_data;
+	int ret;
+	bool transaction_started;
+
+	if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_ERR,
+		      ("Database %s not frozen, cannot start transaction\n",
+		       ctdb_db->db_name));
+		return -1;
+	}
+
+	transaction_started = state->transaction_started &
+			      ctdb_db->freeze_transaction_started;
+
+	ret = db_transaction_start_handler(ctdb_db,
+					   &transaction_started);
+	if (ret != 0) {
+		return -1;
+	}
+
+	ctdb_db->freeze_transaction_started = true;
+	ctdb_db->freeze_transaction_id = state->transaction_id;
+
+	return 0;
+}
+
+static int db_cancel_transaction(struct ctdb_db_context *ctdb_db,
+				 void *private_data)
+{
+	int ret;
+
+	ret = db_transaction_cancel_handler(ctdb_db, private_data);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ctdb_db->freeze_transaction_started = false;
+
+	return 0;
+}
+
+struct db_commit_transaction_state {
+	uint32_t transaction_id;
+	int healthy_nodes;
+};
+
+static int db_commit_transaction(struct ctdb_db_context *ctdb_db,
+				 void *private_data)
+{
+	struct db_commit_transaction_state *state =
+		(struct db_commit_transaction_state *)private_data;
+	int ret;
+
+	if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_ERR,
+		      ("Database %s not frozen, cannot commit transaction\n",
+		       ctdb_db->db_name));
+		return -1;
+	}
+
+	if (!ctdb_db->freeze_transaction_started) {
+		DEBUG(DEBUG_ERR, ("Transaction not started on %s\n",
+				  ctdb_db->db_name));
+		return -1;
+	}
+
+	if (ctdb_db->freeze_transaction_id != state->transaction_id) {
+		DEBUG(DEBUG_ERR,
+		      ("Incorrect transaction commit id 0x%08x for %s\n",
+		       state->transaction_id, ctdb_db->db_name));
+		return -1;
+	}
+
+	ret = db_transaction_commit_handler(ctdb_db, &state->healthy_nodes);
+	if (ret != 0) {
+		return -1;
+	}
+
+	ctdb_db->freeze_transaction_started = false;
+	ctdb_db->freeze_transaction_id = 0;
+	ctdb_db->generation = state->transaction_id;
+	return 0;
+}
+
+/**
+ * Start a transaction on a database - used for db recovery
  */
-int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id)
+int32_t ctdb_control_db_transaction_start(struct ctdb_context *ctdb,
+					  TDB_DATA indata)
 {
+	struct ctdb_transdb *w =
+		(struct ctdb_transdb *)indata.dptr;
 	struct ctdb_db_context *ctdb_db;
-	int i;
+	struct db_start_transaction_state state;
 
-	for (i=1;i<=NUM_DB_PRIORITIES; i++) {
-		if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) {
-			DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n"));
-			return -1;
-		}
+	ctdb_db = find_ctdb_db(ctdb, w->db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,
+		      ("Transaction start for unknown dbid 0x%08x\n",
+		       w->db_id));
+		return -1;
 	}
 
-	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
-		int ret;
+	state.transaction_id = w->tid;
+	state.transaction_started = true;
 
-		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	return db_start_transaction(ctdb_db, &state);
+}
 
-		if (ctdb->freeze_transaction_started) {
-			if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
-				DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",
-					 ctdb_db->db_name));
-				/* not a fatal error */
-			}
-		}
+/**
+ * Cancel a transaction on a database - used for db recovery
+ */
+int32_t ctdb_control_db_transaction_cancel(struct ctdb_context *ctdb,
+					   TDB_DATA indata)
+{
+	uint32_t db_id = *(uint32_t *)indata.dptr;
+	struct ctdb_db_context *ctdb_db;
 
-		ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,
+		      ("Transaction cancel for unknown dbid 0x%08x\n", db_id));
+		return -1;
+	}
 
-		tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	DEBUG(DEBUG_ERR, ("Recovery db transaction cancelled for %s\n",
+			  ctdb_db->db_name));
 
-		if (ret != 0) {
-			DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction for db '%s'\n",
-				 ctdb_db->db_name));
-			return -1;
+	return db_cancel_transaction(ctdb_db, NULL);
+}
+
+/**
+ * Commit a transaction on a database - used for db recovery
+ */
+int32_t ctdb_control_db_transaction_commit(struct ctdb_context *ctdb,
+					   TDB_DATA indata)
+{
+	struct ctdb_transdb *w =
+		(struct ctdb_transdb *)indata.dptr;
+	struct ctdb_db_context *ctdb_db;
+	struct db_commit_transaction_state state;
+	int healthy_nodes, i;
+
+	ctdb_db = find_ctdb_db(ctdb, w->db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,
+		      ("Transaction commit for unknown dbid 0x%08x\n",
+		       w->db_id));
+		return -1;
+	}
+
+	healthy_nodes = 0;
+	for (i=0; i < ctdb->num_nodes; i++) {
+		if (ctdb->nodes[i]->flags == 0) {
+			healthy_nodes += 1;
 		}
 	}
 
+	state.transaction_id = w->tid;
+	state.healthy_nodes = healthy_nodes;
+
+	return db_commit_transaction(ctdb_db, &state);
+}
+
+/*
+  start a transaction on all databases - used for recovery
+ */
+int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id)
+{
+	struct db_start_transaction_state state;
+	int ret;
+
+	if (!ctdb_db_all_frozen(ctdb)) {
+		DEBUG(DEBUG_ERR, (__location__
+		      " failing transaction start while not frozen\n"));
+		return -1;
+	}
+
+	state.transaction_id = id;
+	state.transaction_started = ctdb->freeze_transaction_started;
+
+	ret = ctdb_db_iterator(ctdb, db_start_transaction, &state);
+	if (ret != 0) {
+		return -1;
+	}
+
 	ctdb->freeze_transaction_started = true;
 	ctdb->freeze_transaction_id = id;
 
@@ -346,20 +888,9 @@ int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id)
  */
 int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb)
 {
-	struct ctdb_db_context *ctdb_db;
-
 	DEBUG(DEBUG_ERR,(__location__ " recovery transaction cancelled called\n"));
 
-	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
-		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
-
-		if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
-			DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",  ctdb_db->db_name));
-			/* not a fatal error */
-		}
-
-		tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
-	}
+	ctdb_db_iterator(ctdb, db_cancel_transaction, NULL);
 
 	ctdb->freeze_transaction_started = false;
 
@@ -371,15 +902,15 @@ int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb)
  */
 int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id)
 {
-	struct ctdb_db_context *ctdb_db;
+	struct db_commit_transaction_state state;
 	int i;
 	int healthy_nodes = 0;
+	int ret;
 
-	for (i=1;i<=NUM_DB_PRIORITIES; i++) {
-		if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) {
-			DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n"));
-			return -1;
-		}
+	if (!ctdb_db_all_frozen(ctdb)) {
+		DEBUG(DEBUG_ERR, (__location__
+		      " failing transaction commit while not frozen\n"));
+		return -1;
 	}
 
 	if (!ctdb->freeze_transaction_started) {
@@ -402,25 +933,13 @@ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id)
 	}
 	DEBUG(DEBUG_INFO,(__location__ " healthy_nodes[%d]\n", healthy_nodes));
 
-	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
-		int ret;
-
-		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
-		ret = tdb_transaction_commit(ctdb_db->ltdb->tdb);
-		if (ret != 0) {
-			DEBUG(DEBUG_ERR,(__location__ " Failed to commit transaction for db '%s'. Cancel all transactions and resetting transaction_started to false.\n",
-				 ctdb_db->db_name));
-			goto fail;
-		}
-		tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	state.transaction_id = id;
+	state.healthy_nodes = healthy_nodes;
 
-		ret = ctdb_update_persistent_health(ctdb, ctdb_db, NULL, healthy_nodes);
-		if (ret != 0) {
-			DEBUG(DEBUG_CRIT,(__location__ " Failed to update persistent health for db '%s'. "
-					 "Cancel all remaining transactions and resetting transaction_started to false.\n",
-					 ctdb_db->db_name));
-			goto fail;
-		}
+	ret = ctdb_db_iterator(ctdb, db_commit_transaction, &state);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Cancel all transactions\n"));
+		goto fail;
 	}
 
 	ctdb->freeze_transaction_started = false;
@@ -430,14 +949,7 @@ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id)
 
 fail:
 	/* cancel any pending transactions */
-	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
-		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
-		if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
-			DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",
-				 ctdb_db->db_name));
-		}
-		tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
-	}
+	ctdb_db_iterator(ctdb, db_cancel_transaction, NULL);
 	ctdb->freeze_transaction_started = false;
 
 	return -1;
@@ -448,7 +960,7 @@ fail:
  */
 int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-	struct ctdb_control_wipe_database w = *(struct ctdb_control_wipe_database *)indata.dptr;
+	struct ctdb_transdb w = *(struct ctdb_transdb *)indata.dptr;
 	struct ctdb_db_context *ctdb_db;
 
 	ctdb_db = find_ctdb_db(ctdb, w.db_id);
@@ -457,18 +969,18 @@ int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata)
 		return -1;
 	}
 
-	if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) {
+	if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) {
 		DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n"));
 		return -1;
 	}
 
-	if (!ctdb->freeze_transaction_started) {
+	if (!ctdb_db->freeze_transaction_started) {
 		DEBUG(DEBUG_ERR,(__location__ " transaction not started\n"));
 		return -1;
 	}
 
-	if (w.transaction_id != ctdb->freeze_transaction_id) {
-		DEBUG(DEBUG_ERR,(__location__ " incorrect transaction id 0x%x in commit\n", w.transaction_id));
+	if (w.tid != ctdb_db->freeze_transaction_id) {
+		DEBUG(DEBUG_ERR,(__location__ " incorrect transaction id 0x%x in commit\n", w.tid));
 		return -1;
 	}
 
@@ -490,3 +1002,41 @@ int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata)
 
 	return 0;
 }
+
+bool ctdb_db_frozen(struct ctdb_db_context *ctdb_db)
+{
+	if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) {
+		return false;
+	}
+
+	return true;
+}
+
+bool ctdb_db_prio_frozen(struct ctdb_context *ctdb, uint32_t priority)
+{
+	if (priority == 0) {
+		priority = 1;
+	}
+	if (priority > NUM_DB_PRIORITIES) {
+		DEBUG(DEBUG_ERR, ("Invalid DB priority specified\n"));
+		return false;
+	}
+
+	if (ctdb->freeze_mode[priority] != CTDB_FREEZE_FROZEN) {
+		return false;
+	}
+
+	return true;
+}
+
+bool ctdb_db_all_frozen(struct ctdb_context *ctdb)
+{
+	int i;
+
+	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+		if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) {
+			return false;
+		}
+	}
+	return true;
+}
diff --git a/ctdb/server/ctdb_keepalive.c b/ctdb/server/ctdb_keepalive.c
index 5c95eb0..a8acded 100644
--- a/ctdb/server/ctdb_keepalive.c
+++ b/ctdb/server/ctdb_keepalive.c
@@ -18,16 +18,29 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
+#include "system/time.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+
+#include "common/common.h"
+#include "common/logging.h"
 
 
 /*
   see if any nodes are dead
  */
-static void ctdb_check_for_dead_nodes(struct event_context *ev, struct timed_event *te, 
+static void ctdb_check_for_dead_nodes(struct tevent_context *ev,
+				      struct tevent_timer *te,
 				      struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
@@ -77,23 +90,23 @@ static void ctdb_check_for_dead_nodes(struct event_context *ev, struct timed_eve
 
 		node->tx_cnt = 0;
 	}
-	
-	event_add_timed(ctdb->ev, ctdb->keepalive_ctx,
-			timeval_current_ofs(ctdb->tunable.keepalive_interval, 0), 
-			ctdb_check_for_dead_nodes, ctdb);
+
+	tevent_add_timer(ctdb->ev, ctdb->keepalive_ctx,
+			 timeval_current_ofs(ctdb->tunable.keepalive_interval, 0),
+			 ctdb_check_for_dead_nodes, ctdb);
 }
 
 
 void ctdb_start_keepalive(struct ctdb_context *ctdb)
 {
-	struct timed_event *te;
+	struct tevent_timer *te;
 
 	ctdb->keepalive_ctx = talloc_new(ctdb);
 	CTDB_NO_MEMORY_FATAL(ctdb, ctdb->keepalive_ctx);
 
-	te = event_add_timed(ctdb->ev, ctdb->keepalive_ctx,
-			     timeval_current_ofs(ctdb->tunable.keepalive_interval, 0), 
-			     ctdb_check_for_dead_nodes, ctdb);
+	te = tevent_add_timer(ctdb->ev, ctdb->keepalive_ctx,
+			      timeval_current_ofs(ctdb->tunable.keepalive_interval, 0),
+			      ctdb_check_for_dead_nodes, ctdb);
 	CTDB_NO_MEMORY_FATAL(ctdb, te);
 
 	DEBUG(DEBUG_NOTICE,("Keepalive monitoring has been started\n"));
diff --git a/ctdb/server/ctdb_lock.c b/ctdb/server/ctdb_lock.c
index 82295ea..7962e94 100644
--- a/ctdb/server/ctdb_lock.c
+++ b/ctdb/server/ctdb_lock.c
@@ -17,14 +17,23 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
-#include "includes.h"
-#include "include/ctdb_private.h"
-#include "include/ctdb_protocol.h"
-#include "tevent.h"
-#include "tdb.h"
-#include "lib/tdb_wrap/tdb_wrap.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/tdb_wrap/tdb_wrap.h"
 #include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 /*
  * Non-blocking Locking API
@@ -113,12 +122,8 @@ static bool later_db(struct ctdb_context *ctdb, const char *name)
 	return false;
 }
 
-typedef int (*db_handler_t)(struct ctdb_db_context *ctdb_db,
-			    uint32_t priority,
-			    void *private_data);
-
-static int ctdb_db_iterator(struct ctdb_context *ctdb, uint32_t priority,
-			    db_handler_t handler, void *private_data)
+int ctdb_db_prio_iterator(struct ctdb_context *ctdb, uint32_t priority,
+			  ctdb_db_handler_t handler, void *private_data)
 {
 	struct ctdb_db_context *ctdb_db;
 	int ret;
@@ -130,7 +135,7 @@ static int ctdb_db_iterator(struct ctdb_context *ctdb, uint32_t priority,
 		if (later_db(ctdb, ctdb_db->db_name)) {
 			continue;
 		}
-		ret = handler(ctdb_db, priority, private_data);
+		ret = handler(ctdb_db, private_data);
 		if (ret != 0) {
 			return -1;
 		}
@@ -145,7 +150,7 @@ static int ctdb_db_iterator(struct ctdb_context *ctdb, uint32_t priority,
 		if (!later_db(ctdb, ctdb_db->db_name)) {
 			continue;
 		}
-		ret = handler(ctdb_db, priority, private_data);
+		ret = handler(ctdb_db, private_data);
 		if (ret != 0) {
 			return -1;
 		}
@@ -154,17 +159,31 @@ static int ctdb_db_iterator(struct ctdb_context *ctdb, uint32_t priority,
 	return 0;
 }
 
+int ctdb_db_iterator(struct ctdb_context *ctdb, ctdb_db_handler_t handler,
+		     void *private_data)
+{
+	struct ctdb_db_context *ctdb_db;
+	int ret;
+
+	for (ctdb_db = ctdb->db_list; ctdb_db; ctdb_db = ctdb_db->next) {
+		ret = handler(ctdb_db, private_data);
+		if (ret != 0) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
 
 /*
  * lock all databases - mark only
  */
-static int db_lock_mark_handler(struct ctdb_db_context *ctdb_db, uint32_t priority,
+static int db_lock_mark_handler(struct ctdb_db_context *ctdb_db,
 				void *private_data)
 {
 	int tdb_transaction_write_lock_mark(struct tdb_context *);
 
-	DEBUG(DEBUG_INFO, ("marking locked database %s, priority:%u\n",
-			   ctdb_db->db_name, priority));
+	DEBUG(DEBUG_INFO, ("marking locked database %s\n", ctdb_db->db_name));
 
 	if (tdb_transaction_write_lock_mark(ctdb_db->ltdb->tdb) != 0) {
 		DEBUG(DEBUG_ERR, ("Failed to mark (transaction lock) database %s\n",
@@ -181,21 +200,31 @@ static int db_lock_mark_handler(struct ctdb_db_context *ctdb_db, uint32_t priori
 	return 0;
 }
 
+int ctdb_lockdb_mark(struct ctdb_db_context *ctdb_db)
+{
+	if (!ctdb_db_frozen(ctdb_db)) {
+		DEBUG(DEBUG_ERR,
+		      ("Attempt to mark database locked when not frozen\n"));
+		return -1;
+	}
+
+	return db_lock_mark_handler(ctdb_db, NULL);
+}
+
 int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority)
 {
 	/*
 	 * This function is only used by the main dameon during recovery.
 	 * At this stage, the databases have already been locked, by a
-	 * dedicated child process. The freeze_mode variable is used to track
-	 * whether the actual locks are held by the child process or not.
+	 * dedicated child process.
 	 */
 
-	if (ctdb->freeze_mode[priority] != CTDB_FREEZE_FROZEN) {
+	if (!ctdb_db_prio_frozen(ctdb, priority)) {
 		DEBUG(DEBUG_ERR, ("Attempt to mark all databases locked when not frozen\n"));
 		return -1;
 	}
 
-	return ctdb_db_iterator(ctdb, priority, db_lock_mark_handler, NULL);
+	return ctdb_db_prio_iterator(ctdb, priority, db_lock_mark_handler, NULL);
 }
 
 static int ctdb_lockall_mark(struct ctdb_context *ctdb)
@@ -203,7 +232,11 @@ static int ctdb_lockall_mark(struct ctdb_context *ctdb)
 	uint32_t priority;
 
 	for (priority=1; priority<=NUM_DB_PRIORITIES; priority++) {
-		if (ctdb_db_iterator(ctdb, priority, db_lock_mark_handler, NULL) != 0) {
+		int ret;
+
+		ret = ctdb_db_prio_iterator(ctdb, priority,
+					    db_lock_mark_handler, NULL);
+		if (ret != 0) {
 			return -1;
 		}
 	}
@@ -215,13 +248,12 @@ static int ctdb_lockall_mark(struct ctdb_context *ctdb)
 /*
  * lock all databases - unmark only
  */
-static int db_lock_unmark_handler(struct ctdb_db_context *ctdb_db, uint32_t priority,
+static int db_lock_unmark_handler(struct ctdb_db_context *ctdb_db,
 				  void *private_data)
 {
 	int tdb_transaction_write_lock_unmark(struct tdb_context *);
 
-	DEBUG(DEBUG_INFO, ("unmarking locked database %s, priority:%u\n",
-			   ctdb_db->db_name, priority));
+	DEBUG(DEBUG_INFO, ("unmarking locked database %s\n", ctdb_db->db_name));
 
 	if (tdb_transaction_write_lock_unmark(ctdb_db->ltdb->tdb) != 0) {
 		DEBUG(DEBUG_ERR, ("Failed to unmark (transaction lock) database %s\n",
@@ -238,21 +270,32 @@ static int db_lock_unmark_handler(struct ctdb_db_context *ctdb_db, uint32_t prio
 	return 0;
 }
 
+int ctdb_lockdb_unmark(struct ctdb_db_context *ctdb_db)
+{
+	if (!ctdb_db_frozen(ctdb_db)) {
+		DEBUG(DEBUG_ERR,
+		      ("Attempt to unmark database locked when not frozen\n"));
+		return -1;
+	}
+
+	return db_lock_unmark_handler(ctdb_db, NULL);
+}
+
 int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority)
 {
 	/*
 	 * This function is only used by the main daemon during recovery.
 	 * At this stage, the databases have already been locked, by a
-	 * dedicated child process. The freeze_mode variable is used to track
-	 * whether the actual locks are held by the child process or not.
+	 * dedicated child process.
 	 */
 
-	if (ctdb->freeze_mode[priority] != CTDB_FREEZE_FROZEN) {
+	if (!ctdb_db_prio_frozen(ctdb, priority)) {
 		DEBUG(DEBUG_ERR, ("Attempt to unmark all databases locked when not frozen\n"));
 		return -1;
 	}
 
-	return ctdb_db_iterator(ctdb, priority, db_lock_unmark_handler, NULL);
+	return ctdb_db_prio_iterator(ctdb, priority, db_lock_unmark_handler,
+				     NULL);
 }
 
 static int ctdb_lockall_unmark(struct ctdb_context *ctdb)
@@ -260,7 +303,11 @@ static int ctdb_lockall_unmark(struct ctdb_context *ctdb)
 	uint32_t priority;
 
 	for (priority=NUM_DB_PRIORITIES; priority>0; priority--) {
-		if (ctdb_db_iterator(ctdb, priority, db_lock_unmark_handler, NULL) != 0) {
+		int ret;
+
+		ret = ctdb_db_prio_iterator(ctdb, priority,
+					    db_lock_unmark_handler, NULL);
+		if (ret != 0) {
 			return -1;
 		}
 	}
@@ -343,7 +390,7 @@ static void process_callbacks(struct lock_context *lock_ctx, bool locked)
 			break;
 
 		case LOCK_DB:
-			tdb_lockall_mark(lock_ctx->ctdb_db->ltdb->tdb);
+			ctdb_lockdb_mark(lock_ctx->ctdb_db);
 			break;
 
 		case LOCK_ALLDB_PRIO:
@@ -380,7 +427,7 @@ static void process_callbacks(struct lock_context *lock_ctx, bool locked)
 			break;
 
 		case LOCK_DB:
-			tdb_lockall_unmark(lock_ctx->ctdb_db->ltdb->tdb);
+			ctdb_lockdb_unmark(lock_ctx->ctdb_db);
 			break;
 
 		case LOCK_ALLDB_PRIO:
@@ -558,8 +605,7 @@ static void ctdb_lock_timeout_handler(struct tevent_context *ev,
 }
 
 
-static int db_count_handler(struct ctdb_db_context *ctdb_db, uint32_t priority,
-			    void *private_data)
+static int db_count_handler(struct ctdb_db_context *ctdb_db, void *private_data)
 {
 	int *count = (int *)private_data;
 
@@ -585,8 +631,7 @@ struct db_namelist {
 	int n;
 };
 
-static int db_name_handler(struct ctdb_db_context *ctdb_db, uint32_t priority,
-			   void *private_data)
+static int db_name_handler(struct ctdb_db_context *ctdb_db, void *private_data)
 {
 	struct db_namelist *list = (struct db_namelist *)private_data;
 
@@ -619,13 +664,15 @@ static bool lock_helper_args(TALLOC_CTX *mem_ctx,
 
 	case LOCK_ALLDB_PRIO:
 		nargs = 3;
-		ctdb_db_iterator(ctdb, lock_ctx->priority, db_count_handler, &nargs);
+		ctdb_db_prio_iterator(ctdb, lock_ctx->priority,
+				      db_count_handler, &nargs);
 		break;
 
 	case LOCK_ALLDB:
 		nargs = 3;
 		for (priority=1; priority<NUM_DB_PRIORITIES; priority++) {
-			ctdb_db_iterator(ctdb, priority, db_count_handler, &nargs);
+			ctdb_db_prio_iterator(ctdb, priority,
+					      db_count_handler, &nargs);
 		}
 		break;
 	}
@@ -665,7 +712,8 @@ static bool lock_helper_args(TALLOC_CTX *mem_ctx,
 		args[2] = talloc_strdup(args, "DB");
 		list.names = args;
 		list.n = 3;
-		ctdb_db_iterator(ctdb, lock_ctx->priority, db_name_handler, &list);
+		ctdb_db_prio_iterator(ctdb, lock_ctx->priority,
+				      db_name_handler, &list);
 		break;
 
 	case LOCK_ALLDB:
@@ -673,7 +721,8 @@ static bool lock_helper_args(TALLOC_CTX *mem_ctx,
 		list.names = args;
 		list.n = 3;
 		for (priority=1; priority<NUM_DB_PRIORITIES; priority++) {
-			ctdb_db_iterator(ctdb, priority, db_name_handler, &list);
+			ctdb_db_prio_iterator(ctdb, priority,
+					      db_name_handler, &list);
 		}
 		break;
 	}
@@ -838,7 +887,7 @@ static void ctdb_lock_schedule(struct ctdb_context *ctdb)
 	lock_ctx->tfd = tevent_add_fd(ctdb->ev,
 				      lock_ctx,
 				      lock_ctx->fd[0],
-				      EVENT_FD_READ,
+				      TEVENT_FD_READ,
 				      ctdb_lock_handler,
 				      (void *)lock_ctx);
 	if (lock_ctx->tfd == NULL) {
@@ -853,10 +902,10 @@ static void ctdb_lock_schedule(struct ctdb_context *ctdb)
 	/* Move the context from pending to current */
 	if (lock_ctx->type == LOCK_RECORD) {
 		DLIST_REMOVE(lock_ctx->ctdb_db->lock_pending, lock_ctx);
-		DLIST_ADD_END(lock_ctx->ctdb_db->lock_current, lock_ctx, NULL);
+		DLIST_ADD_END(lock_ctx->ctdb_db->lock_current, lock_ctx);
 	} else {
 		DLIST_REMOVE(ctdb->lock_pending, lock_ctx);
-		DLIST_ADD_END(ctdb->lock_current, lock_ctx, NULL);
+		DLIST_ADD_END(ctdb->lock_current, lock_ctx);
 	}
 	CTDB_DECREMENT_STAT(lock_ctx->ctdb, locks.num_pending);
 	CTDB_INCREMENT_STAT(lock_ctx->ctdb, locks.num_current);
@@ -926,9 +975,9 @@ static struct lock_request *ctdb_lock_internal(TALLOC_CTX *mem_ctx,
 	 * immediately, so keep them at the head of the pending queue.
 	 */
 	if (lock_ctx->type == LOCK_RECORD) {
-		DLIST_ADD_END(ctdb_db->lock_pending, lock_ctx, NULL);
+		DLIST_ADD_END(ctdb_db->lock_pending, lock_ctx);
 	} else {
-		DLIST_ADD_END(ctdb->lock_pending, lock_ctx, NULL);
+		DLIST_ADD_END(ctdb->lock_pending, lock_ctx);
 	}
 	CTDB_INCREMENT_STAT(ctdb, locks.num_pending);
 	if (ctdb_db) {
diff --git a/ctdb/server/ctdb_lock_helper.c b/ctdb/server/ctdb_lock_helper.c
index 7a09ecf..543c5d0 100644
--- a/ctdb/server/ctdb_lock_helper.c
+++ b/ctdb/server/ctdb_lock_helper.c
@@ -17,11 +17,16 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
+
+#include <talloc.h>
+
 #include "ctdb_private.h"
 
+#include "common/system.h"
+
 static char *progname = NULL;
 
 static void send_result(int fd, char result)
diff --git a/ctdb/server/ctdb_logging.c b/ctdb/server/ctdb_logging.c
index 129bdc9..1819ab7 100644
--- a/ctdb/server/ctdb_logging.c
+++ b/ctdb/server/ctdb_logging.c
@@ -17,14 +17,26 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/network.h"
 #include "system/syslog.h"
 #include "system/time.h"
-#include "system/filesys.h"
-#include "lib/util/debug.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
+
+const char *debug_extra = "";
 
 struct ctdb_log_backend {
 	struct ctdb_log_backend *prev, *next;
@@ -59,7 +71,7 @@ void ctdb_log_register_backend(const char *prefix, ctdb_log_setup_fn_t setup)
 	b->prefix = prefix;
 	b->setup = setup;
 
-	DLIST_ADD_END(log_state->backends, b, NULL);
+	DLIST_ADD_END(log_state->backends, b);
 }
 
 
@@ -117,15 +129,15 @@ static void write_to_log(struct ctdb_log_state *log,
 /*
   called when log data comes in from a child process
  */
-static void ctdb_child_log_handler(struct event_context *ev,
-				   struct fd_event *fde,
+static void ctdb_child_log_handler(struct tevent_context *ev,
+				   struct tevent_fd *fde,
 				   uint16_t flags, void *private)
 {
 	struct ctdb_log_state *log = talloc_get_type(private, struct ctdb_log_state);
 	char *p;
 	int n;
 
-	if (!(flags & EVENT_FD_READ)) {
+	if (!(flags & TEVENT_FD_READ)) {
 		return;
 	}
 
@@ -235,7 +247,7 @@ struct ctdb_log_state *ctdb_vfork_with_logging(TALLOC_CTX *mem_ctx,
 	log->pfd = p[0];
 	set_close_on_exec(log->pfd);
 	talloc_set_destructor(log, log_context_destructor);
-	fde = tevent_add_fd(ctdb->ev, log, log->pfd, EVENT_FD_READ,
+	fde = tevent_add_fd(ctdb->ev, log, log->pfd, TEVENT_FD_READ,
 			    ctdb_child_log_handler, log);
 	tevent_fd_set_auto_close(fde);
 
@@ -292,8 +304,8 @@ int ctdb_set_child_logging(struct ctdb_context *ctdb)
 	close(old_stdout);
 	close(old_stderr);
 
-	fde = event_add_fd(ctdb->ev, log_state, p[0],
-			   EVENT_FD_READ, ctdb_child_log_handler, log_state);
+	fde = tevent_add_fd(ctdb->ev, log_state, p[0], TEVENT_FD_READ,
+			    ctdb_child_log_handler, log_state);
 	tevent_fd_set_auto_close(fde);
 
 	log_state->pfd = p[0];
diff --git a/ctdb/server/ctdb_logging_file.c b/ctdb/server/ctdb_logging_file.c
index f931b4a..488de26 100644
--- a/ctdb/server/ctdb_logging_file.c
+++ b/ctdb/server/ctdb_logging_file.c
@@ -17,13 +17,21 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
+#include "replace.h"
 #include "system/time.h"
 #include "system/filesys.h"
+#include "system/network.h"
+
+#include <talloc.h>
+
+#include "lib/util/debug.h"
 #include "lib/util/time_basic.h"
 
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/system.h"
+
 #define CTDB_LOG_FILE_PREFIX "file"
 
 struct file_state {
diff --git a/ctdb/server/ctdb_logging_syslog.c b/ctdb/server/ctdb_logging_syslog.c
index f651207..54643e2 100644
--- a/ctdb/server/ctdb_logging_syslog.c
+++ b/ctdb/server/ctdb_logging_syslog.c
@@ -21,11 +21,15 @@
 #include "replace.h"
 #include "system/network.h"
 #include "system/syslog.h"
+
 #include "lib/util/debug.h"
 #include "lib/util/blocking.h"
 #include "lib/util/time_basic.h"
 #include "lib/util/samba_util.h" /* get_myname */
-#include "ctdb_logging.h"
+
+#include "ctdb_private.h"
+
+#include "common/logging.h"
 
 /* Linux and FreeBSD define this appropriately - try good old /dev/log
  * for anything that doesn't... */
diff --git a/ctdb/server/ctdb_ltdb_server.c b/ctdb/server/ctdb_ltdb_server.c
index 19dbb00..8724791 100644
--- a/ctdb/server/ctdb_ltdb_server.c
+++ b/ctdb/server/ctdb_ltdb_server.c
@@ -17,17 +17,29 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/dir.h"
 #include "system/time.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
+#include "system/locale.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
 #include "lib/util/dlinklist.h"
-#include <ctype.h>
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/rb_tree.h"
+#include "common/reqid.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 #define PERSISTENT_HEALTH_TDB "persistent_health.tdb"
 
@@ -241,6 +253,7 @@ store:
 
 struct lock_fetch_state {
 	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
 	void (*recv_pkt)(void *, struct ctdb_req_header *);
 	void *recv_context;
 	struct ctdb_req_header *hdr;
@@ -255,7 +268,7 @@ static void lock_fetch_callback(void *p, bool locked)
 {
 	struct lock_fetch_state *state = talloc_get_type(p, struct lock_fetch_state);
 	if (!state->ignore_generation &&
-	    state->generation != state->ctdb->vnn_map->generation) {
+	    state->generation != state->ctdb_db->generation) {
 		DEBUG(DEBUG_NOTICE,("Discarding previous generation lockwait packet\n"));
 		talloc_free(state->hdr);
 		return;
@@ -321,10 +334,11 @@ int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db,
 
 	state = talloc(hdr, struct lock_fetch_state);
 	state->ctdb = ctdb_db->ctdb;
+	state->ctdb_db = ctdb_db;
 	state->hdr = hdr;
 	state->recv_pkt = recv_pkt;
 	state->recv_context = recv_context;
-	state->generation = ctdb_db->ctdb->vnn_map->generation;
+	state->generation = ctdb_db->generation;
 	state->ignore_generation = ignore_generation;
 
 	/* now the contended path */
@@ -1009,6 +1023,7 @@ again:
 		return -1;
 	}
 
+	ctdb_db->generation = ctdb->vnn_map->generation;
 
 	DEBUG(DEBUG_NOTICE,("Attached to database '%s' with flags 0x%x\n",
 			    ctdb_db->db_path, tdb_flags));
@@ -1021,7 +1036,7 @@ again:
 struct ctdb_deferred_attach_context {
 	struct ctdb_deferred_attach_context *next, *prev;
 	struct ctdb_context *ctdb;
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 };
 
 
@@ -1032,7 +1047,9 @@ static int ctdb_deferred_attach_destructor(struct ctdb_deferred_attach_context *
 	return 0;
 }
 
-static void ctdb_deferred_attach_timeout(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data)
+static void ctdb_deferred_attach_timeout(struct tevent_context *ev,
+					 struct tevent_timer *te,
+					 struct timeval t, void *private_data)
 {
 	struct ctdb_deferred_attach_context *da_ctx = talloc_get_type(private_data, struct ctdb_deferred_attach_context);
 	struct ctdb_context *ctdb = da_ctx->ctdb;
@@ -1041,7 +1058,9 @@ static void ctdb_deferred_attach_timeout(struct event_context *ev, struct timed_
 	talloc_free(da_ctx);
 }
 
-static void ctdb_deferred_attach_callback(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data)
+static void ctdb_deferred_attach_callback(struct tevent_context *ev,
+					  struct tevent_timer *te,
+					  struct timeval t, void *private_data)
 {
 	struct ctdb_deferred_attach_context *da_ctx = talloc_get_type(private_data, struct ctdb_deferred_attach_context);
 	struct ctdb_context *ctdb = da_ctx->ctdb;
@@ -1060,7 +1079,9 @@ int ctdb_process_deferred_attach(struct ctdb_context *ctdb)
 	 */
 	while ((da_ctx = ctdb->deferred_attach) != NULL) {
 		DLIST_REMOVE(ctdb->deferred_attach, da_ctx);
-		event_add_timed(ctdb->ev, da_ctx, timeval_current_ofs(1,0), ctdb_deferred_attach_callback, da_ctx);
+		tevent_add_timer(ctdb->ev, da_ctx,
+				 timeval_current_ofs(1,0),
+				 ctdb_deferred_attach_callback, da_ctx);
 	}
 
 	return 0;
@@ -1072,7 +1093,7 @@ int ctdb_process_deferred_attach(struct ctdb_context *ctdb)
 int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata,
 			       TDB_DATA *outdata, uint64_t tdb_flags, 
 			       bool persistent, uint32_t client_id,
-			       struct ctdb_req_control *c,
+			       struct ctdb_req_control_old *c,
 			       bool *async_reply)
 {
 	const char *db_name = (const char *)indata.dptr;
@@ -1087,13 +1108,13 @@ int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata,
 		return -1;
 	}
 
-	/* dont allow any local clients to attach while we are in recovery mode
+	/* don't allow any local clients to attach while we are in recovery mode
 	 * except for the recovery daemon.
 	 * allow all attach from the network since these are always from remote
 	 * recovery daemons.
 	 */
 	if (client_id != 0) {
-		client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+		client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
 	}
 	if (client != NULL) {
 		/* If the node is inactive it is not part of the cluster
@@ -1120,7 +1141,9 @@ int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata,
 			talloc_set_destructor(da_ctx, ctdb_deferred_attach_destructor);
 			DLIST_ADD(ctdb->deferred_attach, da_ctx);
 
-			event_add_timed(ctdb->ev, da_ctx, timeval_current_ofs(ctdb->tunable.deferred_attach_timeout, 0), ctdb_deferred_attach_timeout, da_ctx);
+			tevent_add_timer(ctdb->ev, da_ctx,
+					 timeval_current_ofs(ctdb->tunable.deferred_attach_timeout, 0),
+					 ctdb_deferred_attach_timeout, da_ctx);
 
 			DEBUG(DEBUG_ERR,("DB Attach to database %s deferred for client with pid:%d since node is in recovery mode.\n", db_name, client->pid));
 			*async_reply = true;
@@ -1233,7 +1256,7 @@ int32_t ctdb_control_db_detach(struct ctdb_context *ctdb, TDB_DATA indata,
 	 * Do the actual detach only if the control comes from other daemons.
 	 */
 	if (client_id != 0) {
-		client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+		client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
 		if (client != NULL) {
 			/* forward the control to all the nodes */
 			ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_ALL, 0,
@@ -1498,7 +1521,8 @@ int32_t ctdb_ltdb_update_seqnum(struct ctdb_context *ctdb, uint32_t db_id, uint3
 /*
   timer to check for seqnum changes in a ltdb and propogate them
  */
-static void ctdb_ltdb_seqnum_check(struct event_context *ev, struct timed_event *te, 
+static void ctdb_ltdb_seqnum_check(struct tevent_context *ev,
+				   struct tevent_timer *te,
 				   struct timeval t, void *p)
 {
 	struct ctdb_db_context *ctdb_db = talloc_get_type(p, struct ctdb_db_context);
@@ -1517,9 +1541,10 @@ static void ctdb_ltdb_seqnum_check(struct event_context *ev, struct timed_event
 
 	/* setup a new timer */
 	ctdb_db->seqnum_update =
-		event_add_timed(ctdb->ev, ctdb_db, 
-				timeval_current_ofs(ctdb->tunable.seqnum_interval/1000, (ctdb->tunable.seqnum_interval%1000)*1000),
-				ctdb_ltdb_seqnum_check, ctdb_db);
+		tevent_add_timer(ctdb->ev, ctdb_db,
+				 timeval_current_ofs(ctdb->tunable.seqnum_interval/1000,
+						     (ctdb->tunable.seqnum_interval%1000)*1000),
+				 ctdb_ltdb_seqnum_check, ctdb_db);
 }
 
 /*
@@ -1535,10 +1560,11 @@ int32_t ctdb_ltdb_enable_seqnum(struct ctdb_context *ctdb, uint32_t db_id)
 	}
 
 	if (ctdb_db->seqnum_update == NULL) {
-		ctdb_db->seqnum_update =
-			event_add_timed(ctdb->ev, ctdb_db, 
-					timeval_current_ofs(ctdb->tunable.seqnum_interval/1000, (ctdb->tunable.seqnum_interval%1000)*1000),
-					ctdb_ltdb_seqnum_check, ctdb_db);
+		ctdb_db->seqnum_update = tevent_add_timer(
+			ctdb->ev, ctdb_db,
+			timeval_current_ofs(ctdb->tunable.seqnum_interval/1000,
+					    (ctdb->tunable.seqnum_interval%1000)*1000),
+			ctdb_ltdb_seqnum_check, ctdb_db);
 	}
 
 	tdb_enable_seqnum(ctdb_db->ltdb->tdb);
@@ -1600,12 +1626,26 @@ int ctdb_set_db_sticky(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_d
 	return 0;
 }
 
+void ctdb_db_statistics_reset(struct ctdb_db_context *ctdb_db)
+{
+	struct ctdb_db_statistics_old *s = &ctdb_db->statistics;
+	int i;
+
+	for (i=0; i<MAX_HOT_KEYS; i++) {
+		if (s->hot_keys[i].key.dsize > 0) {
+			talloc_free(s->hot_keys[i].key.dptr);
+		}
+	}
+
+	ZERO_STRUCT(ctdb_db->statistics);
+}
+
 int32_t ctdb_control_get_db_statistics(struct ctdb_context *ctdb,
 				uint32_t db_id,
 				TDB_DATA *outdata)
 {
 	struct ctdb_db_context *ctdb_db;
-	struct ctdb_db_statistics *stats;
+	struct ctdb_db_statistics_old *stats;
 	int i;
 	int len;
 	char *ptr;
@@ -1616,7 +1656,7 @@ int32_t ctdb_control_get_db_statistics(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	len = offsetof(struct ctdb_db_statistics, hot_keys_wire);
+	len = offsetof(struct ctdb_db_statistics_old, hot_keys_wire);
 	for (i = 0; i < MAX_HOT_KEYS; i++) {
 		len += ctdb_db->statistics.hot_keys[i].key.dsize;
 	}
@@ -1628,7 +1668,7 @@ int32_t ctdb_control_get_db_statistics(struct ctdb_context *ctdb,
 	}
 
 	memcpy(stats, &ctdb_db->statistics,
-	       offsetof(struct ctdb_db_statistics, hot_keys_wire));
+	       offsetof(struct ctdb_db_statistics_old, hot_keys_wire));
 
 	stats->num_hot_keys = MAX_HOT_KEYS;
 
diff --git a/ctdb/server/ctdb_monitor.c b/ctdb/server/ctdb_monitor.c
index 6dd7c1e..0a8273a 100644
--- a/ctdb/server/ctdb_monitor.c
+++ b/ctdb/server/ctdb_monitor.c
@@ -18,18 +18,33 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/util_process.h"
+
+#include "ctdb_private.h"
+
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 struct ctdb_monitor_state {
 	uint32_t monitoring_mode;
 	TALLOC_CTX *monitor_context;
 	uint32_t next_interval;
+	uint32_t event_script_timeouts;
 };
 
-static void ctdb_check_health(struct event_context *ev, struct timed_event *te, 
+static void ctdb_check_health(struct tevent_context *ev,
+			      struct tevent_timer *te,
 			      struct timeval t, void *private_data);
 
 /*
@@ -90,7 +105,7 @@ void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event)
 	if (child == 0) {
 		int ret;
 
-		ctdb_set_process_name("ctdb_notification");
+		prctl_set_comment("ctdb_notification");
 		debug_extra = talloc_asprintf(NULL, "notification-%s:", event);
 		ret = ctdb_run_notification_script_child(ctdb, event);
 		if (ret != 0) {
@@ -113,12 +128,13 @@ static void ctdb_health_callback(struct ctdb_context *ctdb, int status, void *p)
 	uint32_t next_interval;
 	int ret;
 	TDB_DATA rddata;
-	struct srvid_request rd;
+	struct ctdb_srvid_message rd;
 	const char *state_str = NULL;
 
 	c.pnn = ctdb->pnn;
 	c.old_flags = node->flags;
 
+	ZERO_STRUCT(rd);
 	rd.pnn   = ctdb->pnn;
 	rd.srvid = CTDB_SRVID_TAKEOVER_RUN_RESPONSE;
 
@@ -131,14 +147,20 @@ static void ctdb_health_callback(struct ctdb_context *ctdb, int status, void *p)
 	}
 
 	if (status == -ETIME) {
-		ctdb->event_script_timeouts++;
-
-		if (ctdb->event_script_timeouts >= ctdb->tunable.script_timeout_count) {
-			DEBUG(DEBUG_ERR, ("Maximum timeout count %u reached for eventscript. Making node unhealthy\n", ctdb->tunable.script_timeout_count));
+		ctdb->monitor->event_script_timeouts++;
+
+		if (ctdb->monitor->event_script_timeouts >=
+		    ctdb->tunable.monitor_timeout_count) {
+			DEBUG(DEBUG_ERR,
+			      ("Maximum monitor timeout count %u reached."
+			       " Making node unhealthy\n",
+			       ctdb->tunable.monitor_timeout_count));
 		} else {
 			/* We pretend this is OK. */
 			goto after_change_status;
 		}
+	} else {
+		ctdb->monitor->event_script_timeouts = 0;
 	}
 
 	if (status != 0 && !(node->flags & NODE_FLAGS_UNHEALTHY)) {
@@ -163,9 +185,9 @@ after_change_status:
 		ctdb->monitor->next_interval = ctdb->tunable.monitor_interval;
 	}
 
-	event_add_timed(ctdb->ev, ctdb->monitor->monitor_context, 
-				timeval_current_ofs(next_interval, 0), 
-				ctdb_check_health, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+			 timeval_current_ofs(next_interval, 0),
+			 ctdb_check_health, ctdb);
 
 	if (c.old_flags == node->flags) {
 		return;
@@ -199,7 +221,8 @@ after_change_status:
 }
 
 
-static void ctdb_run_startup(struct event_context *ev, struct timed_event *te,
+static void ctdb_run_startup(struct tevent_context *ev,
+			     struct tevent_timer *te,
 			     struct timeval t, void *private_data);
 /*
   called when the startup event script finishes
@@ -208,9 +231,9 @@ static void ctdb_startup_callback(struct ctdb_context *ctdb, int status, void *p
 {
 	if (status != 0) {
 		DEBUG(DEBUG_ERR,("startup event failed\n"));
-		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-				timeval_current_ofs(5, 0),
-				ctdb_run_startup, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+				 timeval_current_ofs(5, 0),
+				 ctdb_run_startup, ctdb);
 		return;
 	}
 
@@ -221,12 +244,13 @@ static void ctdb_startup_callback(struct ctdb_context *ctdb, int status, void *p
 
 	ctdb->monitor->monitoring_mode = CTDB_MONITORING_ACTIVE;
 
-	event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-			timeval_current_ofs(ctdb->monitor->next_interval, 0),
-			ctdb_check_health, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+			 timeval_current_ofs(ctdb->monitor->next_interval, 0),
+			 ctdb_check_health, ctdb);
 }
 
-static void ctdb_run_startup(struct event_context *ev, struct timed_event *te,
+static void ctdb_run_startup(struct tevent_context *ev,
+			     struct tevent_timer *te,
 			     struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data,
@@ -241,9 +265,9 @@ static void ctdb_run_startup(struct event_context *ev, struct timed_event *te,
 	if (ctdb->runstate < CTDB_RUNSTATE_STARTUP) {
 		DEBUG(DEBUG_NOTICE,
 		      ("Not yet in startup runstate. Wait one more second\n"));
-		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-				timeval_current_ofs(1, 0),
-				ctdb_run_startup, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+				 timeval_current_ofs(1, 0),
+				 ctdb_run_startup, ctdb);
 		return;
 	}
 
@@ -258,9 +282,9 @@ static void ctdb_run_startup(struct event_context *ev, struct timed_event *te,
 
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR,("Unable to launch startup event script\n"));
-		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-				timeval_current_ofs(5, 0),
-				ctdb_run_startup, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+				 timeval_current_ofs(5, 0),
+				 ctdb_run_startup, ctdb);
 	}
 }
 
@@ -268,8 +292,9 @@ static void ctdb_run_startup(struct event_context *ev, struct timed_event *te,
   wait until we have finished initial recoveries before we start the
   monitoring events
  */
-static void ctdb_wait_until_recovered(struct event_context *ev, struct timed_event *te, 
-			      struct timeval t, void *private_data)
+static void ctdb_wait_until_recovered(struct tevent_context *ev,
+				      struct tevent_timer *te,
+				      struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
 	int ret;
@@ -287,9 +312,9 @@ static void ctdb_wait_until_recovered(struct event_context *ev, struct timed_eve
 	if (ctdb->vnn_map->generation == INVALID_GENERATION) {
 		ctdb->db_persistent_startup_generation = INVALID_GENERATION;
 
-		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-				     timeval_current_ofs(1, 0), 
-				     ctdb_wait_until_recovered, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+				 timeval_current_ofs(1, 0),
+				 ctdb_wait_until_recovered, ctdb);
 		return;
 	}
 
@@ -297,9 +322,9 @@ static void ctdb_wait_until_recovered(struct event_context *ev, struct timed_eve
 		ctdb->db_persistent_startup_generation = INVALID_GENERATION;
 
 		DEBUG(DEBUG_NOTICE,(__location__ " in recovery. Wait one more second\n"));
-		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-				     timeval_current_ofs(1, 0), 
-				     ctdb_wait_until_recovered, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+				 timeval_current_ofs(1, 0),
+				 ctdb_wait_until_recovered, ctdb);
 		return;
 	}
 
@@ -309,18 +334,18 @@ static void ctdb_wait_until_recovered(struct event_context *ev, struct timed_eve
 
 		DEBUG(DEBUG_NOTICE,(__location__ " wait for pending recoveries to end. Wait one more second.\n"));
 
-		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-				     timeval_current_ofs(1, 0), 
-				     ctdb_wait_until_recovered, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+				 timeval_current_ofs(1, 0),
+				 ctdb_wait_until_recovered, ctdb);
 		return;
 	}
 
 	if (ctdb->vnn_map->generation == ctdb->db_persistent_startup_generation) {
 		DEBUG(DEBUG_INFO,(__location__ " skip ctdb_recheck_persistent_health() "
 				  "until the next recovery\n"));
-		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-				     timeval_current_ofs(1, 0),
-				     ctdb_wait_until_recovered, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+				 timeval_current_ofs(1, 0),
+				 ctdb_wait_until_recovered, ctdb);
 		return;
 	}
 
@@ -334,10 +359,10 @@ static void ctdb_wait_until_recovered(struct event_context *ev, struct timed_eve
 			      "failed (%llu of %llu times) - retry later\n",
 			      (unsigned long long)ctdb->db_persistent_check_errors,
 			      (unsigned long long)ctdb->max_persistent_check_errors));
-			event_add_timed(ctdb->ev,
-					ctdb->monitor->monitor_context,
-					timeval_current_ofs(1, 0),
-					ctdb_wait_until_recovered, ctdb);
+			tevent_add_timer(ctdb->ev,
+					 ctdb->monitor->monitor_context,
+					 timeval_current_ofs(1, 0),
+					 ctdb_wait_until_recovered, ctdb);
 			return;
 		}
 		DEBUG(DEBUG_ALERT,(__location__
@@ -349,15 +374,16 @@ static void ctdb_wait_until_recovered(struct event_context *ev, struct timed_eve
 	}
 	ctdb->db_persistent_check_errors = 0;
 
-	event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-			timeval_current(), ctdb_run_startup, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+			 timeval_current(), ctdb_run_startup, ctdb);
 }
 
 
 /*
   see if the event scripts think we are healthy
  */
-static void ctdb_check_health(struct event_context *ev, struct timed_event *te, 
+static void ctdb_check_health(struct tevent_context *ev,
+			      struct tevent_timer *te,
 			      struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
@@ -368,21 +394,17 @@ static void ctdb_check_health(struct event_context *ev, struct timed_event *te,
 	    ctdb->monitor->monitoring_mode == CTDB_MONITORING_DISABLED) {
 		skip_monitoring = true;
 	} else {
-		int i;
-		for (i=1; i<=NUM_DB_PRIORITIES; i++) {
-			if (ctdb->freeze_handles[i] != NULL) {
-				DEBUG(DEBUG_ERR,
-				      ("Skip monitoring since databases are frozen\n"));
-				skip_monitoring = true;
-				break;
-			}
+		if (ctdb_db_all_frozen(ctdb)) {
+			DEBUG(DEBUG_ERR,
+			      ("Skip monitoring since databases are frozen\n"));
+			skip_monitoring = true;
 		}
 	}
 
 	if (skip_monitoring) {
-		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-				timeval_current_ofs(ctdb->monitor->next_interval, 0),
-				ctdb_check_health, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+				 timeval_current_ofs(ctdb->monitor->next_interval, 0),
+				 ctdb_check_health, ctdb);
 		return;
 	}
 
@@ -393,9 +415,9 @@ static void ctdb_check_health(struct event_context *ev, struct timed_event *te,
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR,("Unable to launch monitor event script\n"));
 		ctdb->monitor->next_interval = 5;
-		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-				timeval_current_ofs(5, 0),
-				ctdb_check_health, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+				 timeval_current_ofs(5, 0),
+				 ctdb_check_health, ctdb);
 	}
 }
 
@@ -445,9 +467,9 @@ void ctdb_wait_for_first_recovery(struct ctdb_context *ctdb)
 	ctdb->monitor->monitor_context = talloc_new(ctdb->monitor);
 	CTDB_NO_MEMORY_FATAL(ctdb, ctdb->monitor->monitor_context);
 
-	event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
-			timeval_current_ofs(1, 0),
-			ctdb_wait_until_recovered, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
+			 timeval_current_ofs(1, 0),
+			 ctdb_wait_until_recovered, ctdb);
 }
 
 
@@ -473,7 +495,7 @@ int32_t ctdb_control_modflags(struct ctdb_context *ctdb, TDB_DATA indata)
 	node->flags   = c->new_flags & ~NODE_FLAGS_DISCONNECTED;
 	node->flags  |= (c->old_flags & NODE_FLAGS_DISCONNECTED);
 
-	/* we dont let other nodes modify our STOPPED status */
+	/* we don't let other nodes modify our STOPPED status */
 	if (c->pnn == ctdb->pnn) {
 		node->flags &= ~NODE_FLAGS_STOPPED;
 		if (old_flags & NODE_FLAGS_STOPPED) {
@@ -481,7 +503,7 @@ int32_t ctdb_control_modflags(struct ctdb_context *ctdb, TDB_DATA indata)
 		}
 	}
 
-	/* we dont let other nodes modify our BANNED status */
+	/* we don't let other nodes modify our BANNED status */
 	if (c->pnn == ctdb->pnn) {
 		node->flags &= ~NODE_FLAGS_BANNED;
 		if (old_flags & NODE_FLAGS_BANNED) {
diff --git a/ctdb/server/ctdb_persistent.c b/ctdb/server/ctdb_persistent.c
index 5c54b9e..1811ae8 100644
--- a/ctdb/server/ctdb_persistent.c
+++ b/ctdb/server/ctdb_persistent.c
@@ -18,18 +18,30 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
+#include "system/time.h"
 #include "system/wait.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
-#include "tdb.h"
-#include "../include/ctdb_private.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+
+#include "common/reqid.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 struct ctdb_persistent_state {
 	struct ctdb_context *ctdb;
 	struct ctdb_db_context *ctdb_db; /* used by trans3_commit */
 	struct ctdb_client *client; /* used by trans3_commit */
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	const char *errormsg;
 	uint32_t num_pending;
 	int32_t status;
@@ -91,8 +103,9 @@ static void ctdb_persistent_callback(struct ctdb_context *ctdb,
 /*
   called if persistent store times out
  */
-static void ctdb_persistent_store_timeout(struct event_context *ev, struct timed_event *te, 
-					 struct timeval t, void *private_data)
+static void ctdb_persistent_store_timeout(struct tevent_context *ev,
+					  struct tevent_timer *te,
+					  struct timeval t, void *private_data)
 {
 	struct ctdb_persistent_state *state = talloc_get_type(private_data, struct ctdb_persistent_state);
 
@@ -160,7 +173,7 @@ static int ctdb_persistent_state_destructor(struct ctdb_persistent_state *state)
  * This is used to roll out a transaction to all nodes.
  */
 int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb,
-				   struct ctdb_req_control *c,
+				   struct ctdb_req_control_old *c,
 				   TDB_DATA recdata, bool *async_reply)
 {
 	struct ctdb_client *client;
@@ -174,7 +187,7 @@ int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb,
 		return -1;
 	}
 
-	client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+	client = reqid_find(ctdb->idr, c->client_id, struct ctdb_client);
 	if (client == NULL) {
 		DEBUG(DEBUG_ERR,(__location__ " can not match persistent_store "
 				 "to a client. Returning error\n"));
@@ -256,9 +269,9 @@ int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb,
 	talloc_steal(state, c);
 
 	/* but we won't wait forever */
-	event_add_timed(ctdb->ev, state,
-			timeval_current_ofs(ctdb->tunable.control_timeout, 0),
-			ctdb_persistent_store_timeout, state);
+	tevent_add_timer(ctdb->ev, state,
+			 timeval_current_ofs(ctdb->tunable.control_timeout, 0),
+			 ctdb_persistent_store_timeout, state);
 
 	return 0;
 }
@@ -274,10 +287,10 @@ int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb,
   for now we ignore the recdata that the client has passed to us.
  */
 int32_t ctdb_control_start_persistent_update(struct ctdb_context *ctdb, 
-				      struct ctdb_req_control *c,
+				      struct ctdb_req_control_old *c,
 				      TDB_DATA recdata)
 {
-	struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+	struct ctdb_client *client = reqid_find(ctdb->idr, c->client_id, struct ctdb_client);
 
 	if (client == NULL) {
 		DEBUG(DEBUG_ERR,(__location__ " can not match start_persistent_update to a client. Returning error\n"));
@@ -295,10 +308,10 @@ int32_t ctdb_control_start_persistent_update(struct ctdb_context *ctdb,
   called to tell ctdbd that it is no longer doing a persistent update 
 */
 int32_t ctdb_control_cancel_persistent_update(struct ctdb_context *ctdb, 
-					      struct ctdb_req_control *c,
+					      struct ctdb_req_control_old *c,
 					      TDB_DATA recdata)
 {
-	struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+	struct ctdb_client *client = reqid_find(ctdb->idr, c->client_id, struct ctdb_client);
 
 	if (client == NULL) {
 		DEBUG(DEBUG_ERR,(__location__ " can not match cancel_persistent_update to a client. Returning error\n"));
diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c
index 23f793b..127ff6b 100644
--- a/ctdb/server/ctdb_recover.c
+++ b/ctdb/server/ctdb_recover.c
@@ -17,16 +17,28 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/time.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
-#include "lib/util/dlinklist.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/util_process.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
 
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 int 
 ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
@@ -50,17 +62,14 @@ ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA inda
 	return 0;
 }
 
-int 
+int
 ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
 {
 	struct ctdb_vnn_map_wire *map = (struct ctdb_vnn_map_wire *)indata.dptr;
-	int i;
 
-	for(i=1; i<=NUM_DB_PRIORITIES; i++) {
-		if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) {
-			DEBUG(DEBUG_ERR,("Attempt to set vnnmap when not frozen\n"));
-			return -1;
-		}
+	if (ctdb->recovery_mode != CTDB_RECOVERY_ACTIVE) {
+		DEBUG(DEBUG_ERR, ("Attempt to set vnnmap when not in recovery\n"));
+		return -1;
 	}
 
 	talloc_free(ctdb->vnn_map);
@@ -83,7 +92,7 @@ ctdb_control_getdbmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indat
 {
 	uint32_t i, len;
 	struct ctdb_db_context *ctdb_db;
-	struct ctdb_dbid_map *dbid_map;
+	struct ctdb_dbid_map_old *dbid_map;
 
 	CHECK_CONTROL_DATA_SIZE(0);
 
@@ -93,17 +102,17 @@ ctdb_control_getdbmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indat
 	}
 
 
-	outdata->dsize = offsetof(struct ctdb_dbid_map, dbs) + sizeof(dbid_map->dbs[0])*len;
+	outdata->dsize = offsetof(struct ctdb_dbid_map_old, dbs) + sizeof(dbid_map->dbs[0])*len;
 	outdata->dptr  = (unsigned char *)talloc_zero_size(outdata, outdata->dsize);
 	if (!outdata->dptr) {
 		DEBUG(DEBUG_ALERT, (__location__ " Failed to allocate dbmap array\n"));
 		exit(1);
 	}
 
-	dbid_map = (struct ctdb_dbid_map *)outdata->dptr;
+	dbid_map = (struct ctdb_dbid_map_old *)outdata->dptr;
 	dbid_map->num = len;
 	for (i=0,ctdb_db=ctdb->db_list;ctdb_db;i++,ctdb_db=ctdb_db->next){
-		dbid_map->dbs[i].dbid       = ctdb_db->db_id;
+		dbid_map->dbs[i].db_id       = ctdb_db->db_id;
 		if (ctdb_db->persistent != 0) {
 			dbid_map->dbs[i].flags |= CTDB_DB_FLAGS_PERSISTENT;
 		}
@@ -203,7 +212,7 @@ struct pulldb_data {
 static int traverse_pulldb(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *p)
 {
 	struct pulldb_data *params = (struct pulldb_data *)p;
-	struct ctdb_rec_data *rec;
+	struct ctdb_rec_data_old *rec;
 	struct ctdb_context *ctdb = params->ctdb;
 	struct ctdb_db_context *ctdb_db = params->ctdb_db;
 
@@ -239,21 +248,22 @@ static int traverse_pulldb(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
  */
 int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata)
 {
-	struct ctdb_control_pulldb *pull;
+	struct ctdb_pulldb *pull;
 	struct ctdb_db_context *ctdb_db;
 	struct pulldb_data params;
 	struct ctdb_marshall_buffer *reply;
 
-	pull = (struct ctdb_control_pulldb *)indata.dptr;
-	
+	pull = (struct ctdb_pulldb *)indata.dptr;
+
 	ctdb_db = find_ctdb_db(ctdb, pull->db_id);
 	if (!ctdb_db) {
 		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", pull->db_id));
 		return -1;
 	}
 
-	if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) {
-		DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_pull_db when not frozen\n"));
+	if (!ctdb_db_frozen(ctdb_db)) {
+		DEBUG(DEBUG_ERR,
+		      ("rejecting ctdb_control_pull_db when not frozen\n"));
 		return -1;
 	}
 
@@ -275,19 +285,19 @@ int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DAT
 				     ctdb_db->db_name, ctdb_db->unhealthy_reason));
 	}
 
-	if (ctdb_lockall_mark_prio(ctdb, ctdb_db->priority) != 0) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entired db - failing\n"));
+	if (ctdb_lockdb_mark(ctdb_db) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entire db - failing\n"));
 		return -1;
 	}
 
 	if (tdb_traverse_read(ctdb_db->ltdb->tdb, traverse_pulldb, &params) == -1) {
 		DEBUG(DEBUG_ERR,(__location__ " Failed to get traverse db '%s'\n", ctdb_db->db_name));
-		ctdb_lockall_unmark_prio(ctdb, ctdb_db->priority);
+		ctdb_lockdb_unmark(ctdb_db);
 		talloc_free(params.pulldata);
 		return -1;
 	}
 
-	ctdb_lockall_unmark_prio(ctdb, ctdb_db->priority);
+	ctdb_lockdb_unmark(ctdb_db);
 
 	outdata->dptr = (uint8_t *)params.pulldata;
 	outdata->dsize = params.len;
@@ -311,7 +321,7 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata)
 	struct ctdb_marshall_buffer *reply = (struct ctdb_marshall_buffer *)indata.dptr;
 	struct ctdb_db_context *ctdb_db;
 	int i, ret;
-	struct ctdb_rec_data *rec;
+	struct ctdb_rec_data_old *rec;
 
 	if (indata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
 		DEBUG(DEBUG_ERR,(__location__ " invalid data in pulldb reply\n"));
@@ -324,17 +334,18 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata)
 		return -1;
 	}
 
-	if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) {
-		DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_push_db when not frozen\n"));
+	if (!ctdb_db_frozen(ctdb_db)) {
+		DEBUG(DEBUG_ERR,
+		      ("rejecting ctdb_control_push_db when not frozen\n"));
 		return -1;
 	}
 
-	if (ctdb_lockall_mark_prio(ctdb, ctdb_db->priority) != 0) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entired db - failing\n"));
+	if (ctdb_lockdb_mark(ctdb_db) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entire db - failing\n"));
 		return -1;
 	}
 
-	rec = (struct ctdb_rec_data *)&reply->data[0];
+	rec = (struct ctdb_rec_data_old *)&reply->data[0];
 
 	DEBUG(DEBUG_INFO,("starting push of %u records for dbid 0x%x\n",
 		 reply->count, reply->db_id));
@@ -367,7 +378,7 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata)
 			goto failed;
 		}
 
-		rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+		rec = (struct ctdb_rec_data_old *)(rec->length + (uint8_t *)rec);
 	}	    
 
 	DEBUG(DEBUG_DEBUG,("finished push of %u records for dbid 0x%x\n",
@@ -388,21 +399,21 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata)
 		}
 	}
 
-	ctdb_lockall_unmark_prio(ctdb, ctdb_db->priority);
+	ctdb_lockdb_unmark(ctdb_db);
 	return 0;
 
 failed:
-	ctdb_lockall_unmark_prio(ctdb, ctdb_db->priority);
+	ctdb_lockdb_unmark(ctdb_db);
 	return -1;
 }
 
 struct ctdb_set_recmode_state {
 	struct ctdb_context *ctdb;
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	uint32_t recmode;
 	int fd[2];
-	struct timed_event *te;
-	struct fd_event *fde;
+	struct tevent_timer *te;
+	struct tevent_fd *fde;
 	pid_t child;
 	struct timeval start_time;
 };
@@ -411,8 +422,9 @@ struct ctdb_set_recmode_state {
   called if our set_recmode child times out. this would happen if
   ctdb_recovery_lock() would block.
  */
-static void ctdb_set_recmode_timeout(struct event_context *ev, struct timed_event *te, 
-					 struct timeval t, void *private_data)
+static void ctdb_set_recmode_timeout(struct tevent_context *ev,
+				     struct tevent_timer *te,
+				     struct timeval t, void *private_data)
 {
 	struct ctdb_set_recmode_state *state = talloc_get_type(private_data, 
 					   struct ctdb_set_recmode_state);
@@ -450,8 +462,9 @@ static int set_recmode_destructor(struct ctdb_set_recmode_state *state)
 /* this is called when the client process has completed ctdb_recovery_lock()
    and has written data back to us through the pipe.
 */
-static void set_recmode_handler(struct event_context *ev, struct fd_event *fde, 
-			     uint16_t flags, void *private_data)
+static void set_recmode_handler(struct tevent_context *ev,
+				struct tevent_fd *fde,
+				uint16_t flags, void *private_data)
 {
 	struct ctdb_set_recmode_state *state= talloc_get_type(private_data, 
 					     struct ctdb_set_recmode_state);
@@ -493,8 +506,8 @@ static void set_recmode_handler(struct event_context *ev, struct fd_event *fde,
 }
 
 static void
-ctdb_drop_all_ips_event(struct event_context *ev, struct timed_event *te, 
-			       struct timeval t, void *private_data)
+ctdb_drop_all_ips_event(struct tevent_context *ev, struct tevent_timer *te,
+			struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
 
@@ -517,7 +530,9 @@ int ctdb_deferred_drop_all_ips(struct ctdb_context *ctdb)
 	ctdb->release_ips_ctx = talloc_new(ctdb);
 	CTDB_NO_MEMORY(ctdb, ctdb->release_ips_ctx);
 
-	event_add_timed(ctdb->ev, ctdb->release_ips_ctx, timeval_current_ofs(ctdb->tunable.recovery_drop_all_ips, 0), ctdb_drop_all_ips_event, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb->release_ips_ctx,
+			 timeval_current_ofs(ctdb->tunable.recovery_drop_all_ips, 0),
+			 ctdb_drop_all_ips_event, ctdb);
 	return 0;
 }
 
@@ -525,7 +540,7 @@ int ctdb_deferred_drop_all_ips(struct ctdb_context *ctdb)
   set the recovery mode
  */
 int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, 
-				 struct ctdb_req_control *c,
+				 struct ctdb_req_control_old *c,
 				 TDB_DATA indata, bool *async_reply,
 				 const char **errormsg)
 {
@@ -533,6 +548,7 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb,
 	int i, ret;
 	struct ctdb_set_recmode_state *state;
 	pid_t parent = getpid();
+	struct ctdb_db_context *ctdb_db;
 
 	/* if we enter recovery but stay in recovery for too long
 	   we will eventually drop all our ip addresses
@@ -559,20 +575,23 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb,
 
 	/* some special handling when ending recovery mode */
 
+	for (ctdb_db = ctdb->db_list; ctdb_db != NULL; ctdb_db = ctdb_db->next) {
+		if (ctdb_db->generation != ctdb->vnn_map->generation) {
+			DEBUG(DEBUG_ERR,
+			      ("Inconsistent DB generation %u for %s\n",
+			       ctdb_db->generation, ctdb_db->db_name));
+			DEBUG(DEBUG_ERR, ("Recovery mode set to ACTIVE\n"));
+			return -1;
+		}
+	}
+
 	/* force the databases to thaw */
 	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
-		if (ctdb->freeze_handles[i] != NULL) {
+		if (ctdb_db_prio_frozen(ctdb, i)) {
 			ctdb_control_thaw(ctdb, i, false);
 		}
 	}
 
-	state = talloc(ctdb, struct ctdb_set_recmode_state);
-	CTDB_NO_MEMORY(ctdb, state);
-
-	state->start_time = timeval_current();
-	state->fd[0] = -1;
-	state->fd[1] = -1;
-
 	/* release any deferred attach calls from clients */
 	if (recmode == CTDB_RECOVERY_NORMAL) {
 		ctdb_process_deferred_attach(ctdb);
@@ -584,6 +603,13 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb,
 		return 0;
 	}
 
+	state = talloc(ctdb, struct ctdb_set_recmode_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->start_time = timeval_current();
+	state->fd[0] = -1;
+	state->fd[1] = -1;
+
 	/* For the rest of what needs to be done, we need to do this in
 	   a child process since 
 	   1, the call to ctdb_recovery_lock() can block if the cluster
@@ -608,7 +634,7 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb,
 		char cc = 0;
 		close(state->fd[0]);
 
-		ctdb_set_process_name("ctdb_recmode");
+		prctl_set_comment("ctdb_recmode");
 		debug_extra = talloc_asprintf(NULL, "set_recmode:");
 		/* Daemon should not be able to get the recover lock,
 		 * as it should be held by the recovery master */
@@ -637,13 +663,11 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb,
 
 	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d for setrecmode\n", state->fd[0]));
 
-	state->te = event_add_timed(ctdb->ev, state, timeval_current_ofs(5, 0),
-				    ctdb_set_recmode_timeout, state);
+	state->te = tevent_add_timer(ctdb->ev, state, timeval_current_ofs(5, 0),
+				     ctdb_set_recmode_timeout, state);
 
-	state->fde = event_add_fd(ctdb->ev, state, state->fd[0],
-				EVENT_FD_READ,
-				set_recmode_handler,
-				(void *)state);
+	state->fde = tevent_add_fd(ctdb->ev, state, state->fd[0], TEVENT_FD_READ,
+				   set_recmode_handler, (void *)state);
 
 	if (state->fde == NULL) {
 		talloc_free(state);
@@ -729,7 +753,7 @@ void ctdb_recovery_unlock(struct ctdb_context *ctdb)
   when the function returns)
   or !0 is the record still exists in the tdb after returning.
  */
-static int delete_tdb_record(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, struct ctdb_rec_data *rec)
+static int delete_tdb_record(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, struct ctdb_rec_data_old *rec)
 {
 	TDB_DATA key, data, data2;
 	struct ctdb_ltdb_header *hdr, *hdr2;
@@ -835,7 +859,7 @@ static int delete_tdb_record(struct ctdb_context *ctdb, struct ctdb_db_context *
 
 
 struct recovery_callback_state {
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 };
 
 
@@ -870,7 +894,7 @@ static void ctdb_end_recovery_callback(struct ctdb_context *ctdb, int status, vo
   recovery has finished
  */
 int32_t ctdb_control_end_recovery(struct ctdb_context *ctdb, 
-				struct ctdb_req_control *c,
+				struct ctdb_req_control_old *c,
 				bool *async_reply)
 {
 	int ret;
@@ -925,7 +949,7 @@ static void ctdb_start_recovery_callback(struct ctdb_context *ctdb, int status,
   run the startrecovery eventscript
  */
 int32_t ctdb_control_start_recovery(struct ctdb_context *ctdb, 
-				struct ctdb_req_control *c,
+				struct ctdb_req_control_old *c,
 				bool *async_reply)
 {
 	int ret;
@@ -967,7 +991,7 @@ int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA inda
 	struct ctdb_marshall_buffer *reply = (struct ctdb_marshall_buffer *)indata.dptr;
 	struct ctdb_db_context *ctdb_db;
 	int i;
-	struct ctdb_rec_data *rec;
+	struct ctdb_rec_data_old *rec;
 	struct ctdb_marshall_buffer *records;
 
 	if (indata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
@@ -997,7 +1021,7 @@ int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA inda
 	records->db_id = ctdb_db->db_id;
 
 
-	rec = (struct ctdb_rec_data *)&reply->data[0];
+	rec = (struct ctdb_rec_data_old *)&reply->data[0];
 	for (i=0;i<reply->count;i++) {
 		TDB_DATA key, data;
 
@@ -1034,7 +1058,7 @@ int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA inda
 			memcpy(old_size+(uint8_t *)records, rec, rec->length);
 		} 
 
-		rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+		rec = (struct ctdb_rec_data_old *)(rec->length + (uint8_t *)rec);
 	}	    
 
 
@@ -1059,7 +1083,7 @@ int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA inda
  */
 static int store_tdb_record(struct ctdb_context *ctdb,
 			    struct ctdb_db_context *ctdb_db,
-			    struct ctdb_rec_data *rec)
+			    struct ctdb_rec_data_old *rec)
 {
 	TDB_DATA key, data, data2;
 	struct ctdb_ltdb_header *hdr, *hdr2;
@@ -1159,7 +1183,7 @@ int32_t ctdb_control_receive_records(struct ctdb_context *ctdb,
 	struct ctdb_marshall_buffer *reply = (struct ctdb_marshall_buffer *)indata.dptr;
 	struct ctdb_db_context *ctdb_db;
 	int i;
-	struct ctdb_rec_data *rec;
+	struct ctdb_rec_data_old *rec;
 	struct ctdb_marshall_buffer *records;
 
 	if (indata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
@@ -1188,7 +1212,7 @@ int32_t ctdb_control_receive_records(struct ctdb_context *ctdb,
 	}
 	records->db_id = ctdb_db->db_id;
 
-	rec = (struct ctdb_rec_data *)&reply->data[0];
+	rec = (struct ctdb_rec_data_old *)&reply->data[0];
 	for (i=0; i<reply->count; i++) {
 		TDB_DATA key, data;
 
@@ -1232,7 +1256,7 @@ int32_t ctdb_control_receive_records(struct ctdb_context *ctdb,
 			memcpy(old_size+(uint8_t *)records, rec, rec->length);
 		}
 
-		rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+		rec = (struct ctdb_rec_data_old *)(rec->length + (uint8_t *)rec);
 	}
 
 	*outdata = ctdb_marshall_finish(records);
@@ -1262,7 +1286,9 @@ int32_t ctdb_control_get_capabilities(struct ctdb_context *ctdb, TDB_DATA *outda
    If we havent been pinged for a while we assume the recovery
    daemon is inoperable and we restart.
 */
-static void ctdb_recd_ping_timeout(struct event_context *ev, struct timed_event *te, struct timeval t, void *p)
+static void ctdb_recd_ping_timeout(struct tevent_context *ev,
+				   struct tevent_timer *te,
+				   struct timeval t, void *p)
 {
 	struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
 	uint32_t *count = talloc_get_type(ctdb->recd_ping_count, uint32_t);
@@ -1271,9 +1297,9 @@ static void ctdb_recd_ping_timeout(struct event_context *ev, struct timed_event
 
 	if (*count < ctdb->tunable.recd_ping_failcount) {
 		(*count)++;
-		event_add_timed(ctdb->ev, ctdb->recd_ping_count, 
-			timeval_current_ofs(ctdb->tunable.recd_ping_timeout, 0),
-			ctdb_recd_ping_timeout, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->recd_ping_count,
+				 timeval_current_ofs(ctdb->tunable.recd_ping_timeout, 0),
+				 ctdb_recd_ping_timeout, ctdb);
 		return;
 	}
 
@@ -1291,9 +1317,9 @@ int32_t ctdb_control_recd_ping(struct ctdb_context *ctdb)
 	CTDB_NO_MEMORY(ctdb, ctdb->recd_ping_count);
 
 	if (ctdb->tunable.recd_ping_timeout != 0) {
-		event_add_timed(ctdb->ev, ctdb->recd_ping_count, 
-			timeval_current_ofs(ctdb->tunable.recd_ping_timeout, 0),
-			ctdb_recd_ping_timeout, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->recd_ping_count,
+				 timeval_current_ofs(ctdb->tunable.recd_ping_timeout, 0),
+				 ctdb_recd_ping_timeout, ctdb);
 	}
 
 	return 0;
diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c
index be53de6..c89649a 100644
--- a/ctdb/server/ctdb_recoverd.c
+++ b/ctdb/server/ctdb_recoverd.c
@@ -17,23 +17,36 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
 #include "system/time.h"
 #include "system/network.h"
 #include "system/wait.h"
-#include "popt.h"
-#include "cmdline.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
 #include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/util_process.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/system.h"
+#include "common/cmdline.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 
 /* List of SRVID requests that need to be processed */
 struct srvid_list {
 	struct srvid_list *next, *prev;
-	struct srvid_request *request;
+	struct ctdb_srvid_message *request;
 };
 
 struct srvid_requests {
@@ -41,7 +54,7 @@ struct srvid_requests {
 };
 
 static void srvid_request_reply(struct ctdb_context *ctdb,
-				struct srvid_request *request,
+				struct ctdb_srvid_message *request,
 				TDB_DATA result)
 {
 	/* Someone that sent srvid==0 does not want a reply */
@@ -80,7 +93,7 @@ static void srvid_requests_reply(struct ctdb_context *ctdb,
 
 static void srvid_request_add(struct ctdb_context *ctdb,
 			      struct srvid_requests **requests,
-			      struct srvid_request *request)
+			      struct ctdb_srvid_message *request)
 {
 	struct srvid_list *t;
 	int32_t ret;
@@ -102,7 +115,7 @@ static void srvid_request_add(struct ctdb_context *ctdb,
 		goto nomem;
 	}
 
-	t->request = (struct srvid_request *)talloc_steal(t, request);
+	t->request = (struct ctdb_srvid_message *)talloc_steal(t, request);
 	DLIST_ADD((*requests)->requests, t);
 
 	return;
@@ -169,8 +182,8 @@ static void ctdb_op_enable(struct ctdb_op_state *state)
 	TALLOC_FREE(state->timer);
 }
 
-static void ctdb_op_timeout_handler(struct event_context *ev,
-				    struct timed_event *te,
+static void ctdb_op_timeout_handler(struct tevent_context *ev,
+				    struct tevent_timer *te,
 				    struct timeval yt, void *p)
 {
 	struct ctdb_op_state *state =
@@ -226,17 +239,17 @@ struct ctdb_recoverd {
 	struct ctdb_context *ctdb;
 	uint32_t recmaster;
 	uint32_t last_culprit_node;
-	struct ctdb_node_map *nodemap;
+	struct ctdb_node_map_old *nodemap;
 	struct timeval priority_time;
 	bool need_takeover_run;
 	bool need_recovery;
 	uint32_t node_flags;
-	struct timed_event *send_election_te;
-	struct timed_event *election_timeout;
+	struct tevent_timer *send_election_te;
+	struct tevent_timer *election_timeout;
 	struct srvid_requests *reallocate_requests;
 	struct ctdb_op_state *takeover_run;
 	struct ctdb_op_state *recovery;
-	struct ctdb_control_get_ifaces *ifaces;
+	struct ctdb_iface_list_old *ifaces;
 	uint32_t *force_rebalance_nodes;
 	struct ctdb_node_capabilities *caps;
 };
@@ -244,7 +257,9 @@ struct ctdb_recoverd {
 #define CONTROL_TIMEOUT() timeval_current_ofs(ctdb->tunable.recover_timeout, 0)
 #define MONITOR_TIMEOUT() timeval_current_ofs(ctdb->tunable.recover_interval, 0)
 
-static void ctdb_restart_recd(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data);
+static void ctdb_restart_recd(struct tevent_context *ev,
+			      struct tevent_timer *te, struct timeval t,
+			      void *private_data);
 
 /*
   ban a node for a period of time
@@ -253,8 +268,8 @@ static void ctdb_ban_node(struct ctdb_recoverd *rec, uint32_t pnn, uint32_t ban_
 {
 	int ret;
 	struct ctdb_context *ctdb = rec->ctdb;
-	struct ctdb_ban_time bantime;
-       
+	struct ctdb_ban_state bantime;
+
 	if (!ctdb_validate_pnn(ctdb, pnn)) {
 		DEBUG(DEBUG_ERR,("Bad pnn %u in ctdb_ban_node\n", pnn));
 		return;
@@ -338,7 +353,7 @@ static void recovered_fail_callback(struct ctdb_context *ctdb, uint32_t node_pnn
 /*
   run the "recovered" eventscript on all nodes
  */
-static int run_recovered_eventscript(struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap, const char *caller)
+static int run_recovered_eventscript(struct ctdb_recoverd *rec, struct ctdb_node_map_old *nodemap, const char *caller)
 {
 	TALLOC_CTX *tmp_ctx;
 	uint32_t *nodes;
@@ -378,7 +393,7 @@ static void startrecovery_fail_callback(struct ctdb_context *ctdb, uint32_t node
 /*
   run the "startrecovery" eventscript on all nodes
  */
-static int run_startrecovery_eventscript(struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap)
+static int run_startrecovery_eventscript(struct ctdb_recoverd *rec, struct ctdb_node_map_old *nodemap)
 {
 	TALLOC_CTX *tmp_ctx;
 	uint32_t *nodes;
@@ -404,10 +419,10 @@ static int run_startrecovery_eventscript(struct ctdb_recoverd *rec, struct ctdb_
 }
 
 /*
-  update the node capabilities for all connected nodes
+  Retrieve capabilities from all connected nodes
  */
 static int update_capabilities(struct ctdb_recoverd *rec,
-			       struct ctdb_node_map *nodemap)
+			       struct ctdb_node_map_old *nodemap)
 {
 	uint32_t *capp;
 	TALLOC_CTX *tmp_ctx;
@@ -463,7 +478,10 @@ static void transaction_start_fail_callback(struct ctdb_context *ctdb, uint32_t
 /*
   change recovery mode on all nodes
  */
-static int set_recovery_mode(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap, uint32_t rec_mode)
+static int set_recovery_mode(struct ctdb_context *ctdb,
+			     struct ctdb_recoverd *rec,
+			     struct ctdb_node_map_old *nodemap,
+			     uint32_t rec_mode, bool freeze)
 {
 	TDB_DATA data;
 	uint32_t *nodes;
@@ -489,7 +507,7 @@ static int set_recovery_mode(struct ctdb_context *ctdb, struct ctdb_recoverd *re
 	}
 
 	/* freeze all nodes */
-	if (rec_mode == CTDB_RECOVERY_ACTIVE) {
+	if (freeze && rec_mode == CTDB_RECOVERY_ACTIVE) {
 		int i;
 
 		for (i=1; i<=NUM_DB_PRIORITIES; i++) {
@@ -511,44 +529,14 @@ static int set_recovery_mode(struct ctdb_context *ctdb, struct ctdb_recoverd *re
 	return 0;
 }
 
-/*
-  change recovery master on all node
- */
-static int set_recovery_master(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, uint32_t pnn)
-{
-	TDB_DATA data;
-	TALLOC_CTX *tmp_ctx;
-	uint32_t *nodes;
-
-	tmp_ctx = talloc_new(ctdb);
-	CTDB_NO_MEMORY(ctdb, tmp_ctx);
-
-	data.dsize = sizeof(uint32_t);
-	data.dptr = (unsigned char *)&pnn;
-
-	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
-	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_SET_RECMASTER,
-					nodes, 0,
-					CONTROL_TIMEOUT(), false, data,
-					NULL, NULL,
-					NULL) != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to set recmaster. Recovery failed.\n"));
-		talloc_free(tmp_ctx);
-		return -1;
-	}
-
-	talloc_free(tmp_ctx);
-	return 0;
-}
-
 /* update all remote nodes to use the same db priority that we have
    this can fail if the remove node has not yet been upgraded to 
    support this function, so we always return success and never fail
    a recovery if this call fails.
 */
 static int update_db_priority_on_remote_nodes(struct ctdb_context *ctdb,
-	struct ctdb_node_map *nodemap, 
-	uint32_t pnn, struct ctdb_dbid_map *dbmap, TALLOC_CTX *mem_ctx)
+	struct ctdb_node_map_old *nodemap, 
+	uint32_t pnn, struct ctdb_dbid_map_old *dbmap, TALLOC_CTX *mem_ctx)
 {
 	int db;
 
@@ -557,14 +545,14 @@ static int update_db_priority_on_remote_nodes(struct ctdb_context *ctdb,
 		struct ctdb_db_priority db_prio;
 		int ret;
 
-		db_prio.db_id     = dbmap->dbs[db].dbid;
-		ret = ctdb_ctrl_get_db_priority(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, dbmap->dbs[db].dbid, &db_prio.priority);
+		db_prio.db_id     = dbmap->dbs[db].db_id;
+		ret = ctdb_ctrl_get_db_priority(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, dbmap->dbs[db].db_id, &db_prio.priority);
 		if (ret != 0) {
-			DEBUG(DEBUG_ERR,(__location__ " Failed to read database priority from local node for db 0x%08x\n", dbmap->dbs[db].dbid));
+			DEBUG(DEBUG_ERR,(__location__ " Failed to read database priority from local node for db 0x%08x\n", dbmap->dbs[db].db_id));
 			continue;
 		}
 
-		DEBUG(DEBUG_INFO,("Update DB priority for db 0x%08x to %u\n", dbmap->dbs[db].dbid, db_prio.priority)); 
+		DEBUG(DEBUG_INFO,("Update DB priority for db 0x%08x to %u\n", dbmap->dbs[db].db_id, db_prio.priority)); 
 
 		ret = ctdb_ctrl_set_db_priority(ctdb, CONTROL_TIMEOUT(),
 						CTDB_CURRENT_NODE, &db_prio);
@@ -580,19 +568,19 @@ static int update_db_priority_on_remote_nodes(struct ctdb_context *ctdb,
 /*
   ensure all other nodes have attached to any databases that we have
  */
-static int create_missing_remote_databases(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, 
-					   uint32_t pnn, struct ctdb_dbid_map *dbmap, TALLOC_CTX *mem_ctx)
+static int create_missing_remote_databases(struct ctdb_context *ctdb, struct ctdb_node_map_old *nodemap, 
+					   uint32_t pnn, struct ctdb_dbid_map_old *dbmap, TALLOC_CTX *mem_ctx)
 {
 	int i, j, db, ret;
-	struct ctdb_dbid_map *remote_dbmap;
+	struct ctdb_dbid_map_old *remote_dbmap;
 
 	/* verify that all other nodes have all our databases */
 	for (j=0; j<nodemap->num; j++) {
-		/* we dont need to ourself ourselves */
+		/* we don't need to ourself ourselves */
 		if (nodemap->nodes[j].pnn == pnn) {
 			continue;
 		}
-		/* dont check nodes that are unavailable */
+		/* don't check nodes that are unavailable */
 		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
 			continue;
 		}
@@ -610,7 +598,7 @@ static int create_missing_remote_databases(struct ctdb_context *ctdb, struct ctd
 
 
 			for (i=0;i<remote_dbmap->num;i++) {
-				if (dbmap->dbs[db].dbid == remote_dbmap->dbs[i].dbid) {
+				if (dbmap->dbs[db].db_id == remote_dbmap->dbs[i].db_id) {
 					break;
 				}
 			}
@@ -620,7 +608,7 @@ static int create_missing_remote_databases(struct ctdb_context *ctdb, struct ctd
 			}
 			/* ok so we need to create this database */
 			ret = ctdb_ctrl_getdbname(ctdb, CONTROL_TIMEOUT(), pnn,
-						  dbmap->dbs[db].dbid, mem_ctx,
+						  dbmap->dbs[db].db_id, mem_ctx,
 						  &name);
 			if (ret != 0) {
 				DEBUG(DEBUG_ERR, (__location__ " Unable to get dbname from node %u\n", pnn));
@@ -644,19 +632,19 @@ static int create_missing_remote_databases(struct ctdb_context *ctdb, struct ctd
 /*
   ensure we are attached to any databases that anyone else is attached to
  */
-static int create_missing_local_databases(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, 
-					  uint32_t pnn, struct ctdb_dbid_map **dbmap, TALLOC_CTX *mem_ctx)
+static int create_missing_local_databases(struct ctdb_context *ctdb, struct ctdb_node_map_old *nodemap, 
+					  uint32_t pnn, struct ctdb_dbid_map_old **dbmap, TALLOC_CTX *mem_ctx)
 {
 	int i, j, db, ret;
-	struct ctdb_dbid_map *remote_dbmap;
+	struct ctdb_dbid_map_old *remote_dbmap;
 
 	/* verify that we have all database any other node has */
 	for (j=0; j<nodemap->num; j++) {
-		/* we dont need to ourself ourselves */
+		/* we don't need to ourself ourselves */
 		if (nodemap->nodes[j].pnn == pnn) {
 			continue;
 		}
-		/* dont check nodes that are unavailable */
+		/* don't check nodes that are unavailable */
 		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
 			continue;
 		}
@@ -673,7 +661,7 @@ static int create_missing_local_databases(struct ctdb_context *ctdb, struct ctdb
 			const char *name;
 
 			for (i=0;i<(*dbmap)->num;i++) {
-				if (remote_dbmap->dbs[db].dbid == (*dbmap)->dbs[i].dbid) {
+				if (remote_dbmap->dbs[db].db_id == (*dbmap)->dbs[i].db_id) {
 					break;
 				}
 			}
@@ -685,7 +673,7 @@ static int create_missing_local_databases(struct ctdb_context *ctdb, struct ctdb
 			   rebuild dbmap
 			 */
 			ctdb_ctrl_getdbname(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, 
-					    remote_dbmap->dbs[db].dbid, mem_ctx, &name);
+					    remote_dbmap->dbs[db].db_id, mem_ctx, &name);
 			if (ret != 0) {
 				DEBUG(DEBUG_ERR, (__location__ " Unable to get dbname from node %u\n", 
 					  nodemap->nodes[j].pnn));
@@ -718,7 +706,7 @@ static int pull_one_remote_database(struct ctdb_context *ctdb, uint32_t srcnode,
 	int ret;
 	TDB_DATA outdata;
 	struct ctdb_marshall_buffer *reply;
-	struct ctdb_rec_data *recdata;
+	struct ctdb_rec_data_old *recdata;
 	int i;
 	TALLOC_CTX *tmp_ctx = talloc_new(recdb);
 
@@ -738,11 +726,11 @@ static int pull_one_remote_database(struct ctdb_context *ctdb, uint32_t srcnode,
 		return -1;
 	}
 
-	recdata = (struct ctdb_rec_data *)&reply->data[0];
+	recdata = (struct ctdb_rec_data_old *)&reply->data[0];
 
 	for (i=0;
 	     i<reply->count;
-	     recdata = (struct ctdb_rec_data *)(recdata->length + (uint8_t *)recdata), i++) {
+	     recdata = (struct ctdb_rec_data_old *)(recdata->length + (uint8_t *)recdata), i++) {
 		TDB_DATA key, data;
 		struct ctdb_ltdb_header *hdr;
 		TDB_DATA existing;
@@ -841,7 +829,7 @@ static void pull_seqnum_fail_cb(struct ctdb_context *ctdb, uint32_t node_pnn, in
 
 static int pull_highest_seqnum_pdb(struct ctdb_context *ctdb,
 				struct ctdb_recoverd *rec, 
-				struct ctdb_node_map *nodemap, 
+				struct ctdb_node_map_old *nodemap, 
 				struct tdb_wrap *recdb, uint32_t dbid)
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
@@ -912,7 +900,7 @@ static int pull_highest_seqnum_pdb(struct ctdb_context *ctdb,
  */
 static int pull_remote_database(struct ctdb_context *ctdb,
 				struct ctdb_recoverd *rec, 
-				struct ctdb_node_map *nodemap, 
+				struct ctdb_node_map_old *nodemap, 
 				struct tdb_wrap *recdb, uint32_t dbid,
 				bool persistent)
 {
@@ -930,7 +918,7 @@ static int pull_remote_database(struct ctdb_context *ctdb,
 	   (this merges based on rsn)
 	*/
 	for (j=0; j<nodemap->num; j++) {
-		/* dont merge from nodes that are unavailable */
+		/* don't merge from nodes that are unavailable */
 		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
 			continue;
 		}
@@ -949,7 +937,7 @@ static int pull_remote_database(struct ctdb_context *ctdb,
 /*
   update flags on all active nodes
  */
-static int update_flags_on_all_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, uint32_t pnn, uint32_t flags)
+static int update_flags_on_all_nodes(struct ctdb_context *ctdb, struct ctdb_node_map_old *nodemap, uint32_t pnn, uint32_t flags)
 {
 	int ret;
 
@@ -965,14 +953,14 @@ static int update_flags_on_all_nodes(struct ctdb_context *ctdb, struct ctdb_node
 /*
   ensure all nodes have the same vnnmap we do
  */
-static int update_vnnmap_on_all_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, 
+static int update_vnnmap_on_all_nodes(struct ctdb_context *ctdb, struct ctdb_node_map_old *nodemap, 
 				      uint32_t pnn, struct ctdb_vnn_map *vnnmap, TALLOC_CTX *mem_ctx)
 {
 	int j, ret;
 
 	/* push the new vnn map out to all the nodes */
 	for (j=0; j<nodemap->num; j++) {
-		/* dont push to nodes that are unavailable */
+		/* don't push to nodes that are unavailable */
 		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
 			continue;
 		}
@@ -1004,7 +992,7 @@ static void vacuum_fetch_callback(struct ctdb_client_call_state *state)
  */
 static bool vacuum_fetch_process_one(struct ctdb_db_context *ctdb_db,
 				     uint32_t pnn,
-				     struct ctdb_rec_data *r)
+				     struct ctdb_rec_data_old *r)
 {
 	struct ctdb_client_call_state *state;
 	TDB_DATA data;
@@ -1063,18 +1051,20 @@ static bool vacuum_fetch_process_one(struct ctdb_db_context *ctdb_db,
 /*
   handler for vacuum fetch
 */
-static void vacuum_fetch_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-				 TDB_DATA data, void *private_data)
+static void vacuum_fetch_handler(uint64_t srvid, TDB_DATA data,
+				 void *private_data)
 {
-	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
+	struct ctdb_context *ctdb = rec->ctdb;
 	struct ctdb_marshall_buffer *recs;
 	int ret, i;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	const char *name;
-	struct ctdb_dbid_map *dbmap=NULL;
+	struct ctdb_dbid_map_old *dbmap=NULL;
 	bool persistent = false;
 	struct ctdb_db_context *ctdb_db;
-	struct ctdb_rec_data *r;
+	struct ctdb_rec_data_old *r;
 
 	recs = (struct ctdb_marshall_buffer *)data.dptr;
 
@@ -1090,7 +1080,7 @@ static void vacuum_fetch_handler(struct ctdb_context *ctdb, uint64_t srvid,
 	}
 
 	for (i=0;i<dbmap->num;i++) {
-		if (dbmap->dbs[i].dbid == recs->db_id) {
+		if (dbmap->dbs[i].db_id == recs->db_id) {
 			persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
 			break;
 		}
@@ -1113,7 +1103,7 @@ static void vacuum_fetch_handler(struct ctdb_context *ctdb, uint64_t srvid,
 		goto done;
 	}
 
-	r = (struct ctdb_rec_data *)&recs->data[0];
+	r = (struct ctdb_rec_data_old *)&recs->data[0];
 	while (recs->count) {
 		bool ok;
 
@@ -1122,7 +1112,7 @@ static void vacuum_fetch_handler(struct ctdb_context *ctdb, uint64_t srvid,
 			break;
 		}
 
-		r = (struct ctdb_rec_data *)(r->length + (uint8_t *)r);
+		r = (struct ctdb_rec_data_old *)(r->length + (uint8_t *)r);
 		recs->count--;
 	}
 
@@ -1134,9 +1124,12 @@ done:
 /*
  * handler for database detach
  */
-static void detach_database_handler(struct ctdb_context *ctdb, uint64_t srvid,
-				    TDB_DATA data, void *private_data)
+static void detach_database_handler(uint64_t srvid, TDB_DATA data,
+				    void *private_data)
 {
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
+	struct ctdb_context *ctdb = rec->ctdb;
 	uint32_t db_id;
 	struct ctdb_db_context *ctdb_db;
 
@@ -1161,7 +1154,8 @@ static void detach_database_handler(struct ctdb_context *ctdb, uint64_t srvid,
 /*
   called when ctdb_wait_timeout should finish
  */
-static void ctdb_wait_handler(struct event_context *ev, struct timed_event *te, 
+static void ctdb_wait_handler(struct tevent_context *ev,
+			      struct tevent_timer *te,
 			      struct timeval yt, void *p)
 {
 	uint32_t *timed_out = (uint32_t *)p;
@@ -1175,16 +1169,18 @@ static void ctdb_wait_timeout(struct ctdb_context *ctdb, double secs)
 {
 	uint32_t timed_out = 0;
 	time_t usecs = (secs - (time_t)secs) * 1000000;
-	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(secs, usecs), ctdb_wait_handler, &timed_out);
+	tevent_add_timer(ctdb->ev, ctdb, timeval_current_ofs(secs, usecs),
+			 ctdb_wait_handler, &timed_out);
 	while (!timed_out) {
-		event_loop_once(ctdb->ev);
+		tevent_loop_once(ctdb->ev);
 	}
 }
 
 /*
   called when an election times out (ends)
  */
-static void ctdb_election_timeout(struct event_context *ev, struct timed_event *te, 
+static void ctdb_election_timeout(struct tevent_context *ev,
+				  struct tevent_timer *te,
 				  struct timeval t, void *p)
 {
 	struct ctdb_recoverd *rec = talloc_get_type(p, struct ctdb_recoverd);
@@ -1203,7 +1199,7 @@ static void ctdb_wait_election(struct ctdb_recoverd *rec)
 {
 	struct ctdb_context *ctdb = rec->ctdb;
 	while (rec->election_timeout) {
-		event_loop_once(ctdb->ev);
+		tevent_loop_once(ctdb->ev);
 	}
 }
 
@@ -1211,7 +1207,7 @@ static void ctdb_wait_election(struct ctdb_recoverd *rec)
   Update our local flags from all remote connected nodes. 
   This is only run when we are or we belive we are the recovery master
  */
-static int update_local_flags(struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap)
+static int update_local_flags(struct ctdb_recoverd *rec, struct ctdb_node_map_old *nodemap)
 {
 	int j;
 	struct ctdb_context *ctdb = rec->ctdb;
@@ -1221,7 +1217,7 @@ static int update_local_flags(struct ctdb_recoverd *rec, struct ctdb_node_map *n
 	   they are the same as for this node
 	 */
 	for (j=0; j<nodemap->num; j++) {
-		struct ctdb_node_map *remote_nodemap=NULL;
+		struct ctdb_node_map_old *remote_nodemap=NULL;
 		int ret;
 
 		if (nodemap->nodes[j].flags & NODE_FLAGS_DISCONNECTED) {
@@ -1268,7 +1264,7 @@ static int update_local_flags(struct ctdb_recoverd *rec, struct ctdb_node_map *n
 }
 
 
-/* Create a new random generation ip. 
+/* Create a new random generation id.
    The generation id can not be the INVALID_GENERATION id
 */
 static uint32_t new_generation(void)
@@ -1338,7 +1334,7 @@ struct recdb_data {
 static int traverse_recdb(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *p)
 {
 	struct recdb_data *params = (struct recdb_data *)p;
-	struct ctdb_rec_data *recdata;
+	struct ctdb_rec_data_old *recdata;
 	struct ctdb_ltdb_header *hdr;
 
 	/*
@@ -1411,7 +1407,7 @@ static int traverse_recdb(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
  */
 static int push_recdb_database(struct ctdb_context *ctdb, uint32_t dbid,
 			       bool persistent,
-			       struct tdb_wrap *recdb, struct ctdb_node_map *nodemap)
+			       struct tdb_wrap *recdb, struct ctdb_node_map_old *nodemap)
 {
 	struct recdb_data params;
 	struct ctdb_marshall_buffer *recdata;
@@ -1483,14 +1479,14 @@ static int recover_database(struct ctdb_recoverd *rec,
 			    uint32_t dbid,
 			    bool persistent,
 			    uint32_t pnn, 
-			    struct ctdb_node_map *nodemap,
+			    struct ctdb_node_map_old *nodemap,
 			    uint32_t transaction_id)
 {
 	struct tdb_wrap *recdb;
 	int ret;
 	struct ctdb_context *ctdb = rec->ctdb;
 	TDB_DATA data;
-	struct ctdb_control_wipe_database w;
+	struct ctdb_transdb w;
 	uint32_t *nodes;
 
 	recdb = create_recdb(ctdb, mem_ctx);
@@ -1509,7 +1505,7 @@ static int recover_database(struct ctdb_recoverd *rec,
 
 	/* wipe all the remote databases. This is safe as we are in a transaction */
 	w.db_id = dbid;
-	w.transaction_id = transaction_id;
+	w.tid = transaction_id;
 
 	data.dptr = (void *)&w;
 	data.dsize = sizeof(w);
@@ -1539,88 +1535,6 @@ static int recover_database(struct ctdb_recoverd *rec,
 	return 0;
 }
 
-static int ctdb_reload_remote_public_ips(struct ctdb_context *ctdb,
-					 struct ctdb_recoverd *rec,
-					 struct ctdb_node_map *nodemap,
-					 uint32_t *culprit)
-{
-	int j;
-	int ret;
-
-	if (ctdb->num_nodes != nodemap->num) {
-		DEBUG(DEBUG_ERR, (__location__ " ctdb->num_nodes (%d) != nodemap->num (%d) invalid param\n",
-				  ctdb->num_nodes, nodemap->num));
-		if (culprit) {
-			*culprit = ctdb->pnn;
-		}
-		return -1;
-	}
-
-	for (j=0; j<nodemap->num; j++) {
-		/* For readability */
-		struct ctdb_node *node = ctdb->nodes[j];
-
-		/* release any existing data */
-		if (node->known_public_ips) {
-			talloc_free(node->known_public_ips);
-			node->known_public_ips = NULL;
-		}
-		if (node->available_public_ips) {
-			talloc_free(node->available_public_ips);
-			node->available_public_ips = NULL;
-		}
-
-		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
-			continue;
-		}
-
-		/* Retrieve the list of known public IPs from the node */
-		ret = ctdb_ctrl_get_public_ips_flags(ctdb,
-					CONTROL_TIMEOUT(),
-					node->pnn,
-					ctdb->nodes,
-					0,
-					&node->known_public_ips);
-		if (ret != 0) {
-			DEBUG(DEBUG_ERR,
-			      ("Failed to read known public IPs from node: %u\n",
-			       node->pnn));
-			if (culprit) {
-				*culprit = node->pnn;
-			}
-			return -1;
-		}
-
-		if (ctdb->do_checkpublicip &&
-		    !ctdb_op_is_disabled(rec->takeover_run) &&
-		    verify_remote_ip_allocation(ctdb,
-						 node->known_public_ips,
-						 node->pnn)) {
-			DEBUG(DEBUG_ERR,("Trigger IP reallocation\n"));
-			rec->need_takeover_run = true;
-		}
-
-		/* Retrieve the list of available public IPs from the node */
-		ret = ctdb_ctrl_get_public_ips_flags(ctdb,
-					CONTROL_TIMEOUT(),
-					node->pnn,
-					ctdb->nodes,
-					CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE,
-					&node->available_public_ips);
-		if (ret != 0) {
-			DEBUG(DEBUG_ERR,
-			      ("Failed to read available public IPs from node: %u\n",
-			       node->pnn));
-			if (culprit) {
-				*culprit = node->pnn;
-			}
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
 /* when we start a recovery, make sure all nodes use the same reclock file
    setting
 */
@@ -1704,11 +1618,11 @@ static void ban_misbehaving_nodes(struct ctdb_recoverd *rec, bool *self_ban)
 }
 
 static bool do_takeover_run(struct ctdb_recoverd *rec,
-			    struct ctdb_node_map *nodemap,
+			    struct ctdb_node_map_old *nodemap,
 			    bool banning_credits_on_fail)
 {
 	uint32_t *nodes = NULL;
-	struct srvid_request_data dtr;
+	struct ctdb_disable_message dtr;
 	TDB_DATA data;
 	int i;
 	uint32_t *rebalance_nodes = rec->force_rebalance_nodes;
@@ -1736,6 +1650,7 @@ static bool do_takeover_run(struct ctdb_recoverd *rec,
 	 * wait for replies since a failure here might cause some
 	 * noise in the logs but will not actually cause a problem.
 	 */
+	ZERO_STRUCT(dtr);
 	dtr.srvid = 0; /* No reply */
 	dtr.pnn = -1;
 
@@ -1747,7 +1662,7 @@ static bool do_takeover_run(struct ctdb_recoverd *rec,
 	/* Disable for 60 seconds.  This can be a tunable later if
 	 * necessary.
 	 */
-	dtr.data = 60;
+	dtr.timeout = 60;
 	for (i = 0; i < talloc_array_length(nodes); i++) {
 		if (ctdb_client_send_message(rec->ctdb, nodes[i],
 					     CTDB_SRVID_DISABLE_TAKEOVER_RUNS,
@@ -1762,12 +1677,12 @@ static bool do_takeover_run(struct ctdb_recoverd *rec,
 				banning_credits_on_fail ? rec : NULL);
 
 	/* Reenable takeover runs and IP checks on other nodes */
-	dtr.data = 0;
+	dtr.timeout = 0;
 	for (i = 0; i < talloc_array_length(nodes); i++) {
 		if (ctdb_client_send_message(rec->ctdb, nodes[i],
 					     CTDB_SRVID_DISABLE_TAKEOVER_RUNS,
 					     data) != 0) {
-			DEBUG(DEBUG_INFO,("Failed to reenable takeover runs\n"));
+			DEBUG(DEBUG_INFO,("Failed to re-enable takeover runs\n"));
 		}
 	}
 
@@ -1794,152 +1709,151 @@ done:
 	return ok;
 }
 
+struct recovery_helper_state {
+	int fd[2];
+	pid_t pid;
+	int result;
+	bool done;
+};
 
-/*
-  we are the recmaster, and recovery is needed - start a recovery run
- */
-static int do_recovery(struct ctdb_recoverd *rec, 
-		       TALLOC_CTX *mem_ctx, uint32_t pnn,
-		       struct ctdb_node_map *nodemap, struct ctdb_vnn_map *vnnmap)
+static void ctdb_recovery_handler(struct tevent_context *ev,
+				  struct tevent_fd *fde,
+				  uint16_t flags, void *private_data)
 {
-	struct ctdb_context *ctdb = rec->ctdb;
-	int i, j, ret;
-	uint32_t generation;
-	struct ctdb_dbid_map *dbmap;
-	TDB_DATA data;
-	uint32_t *nodes;
-	struct timeval start_time;
-	uint32_t culprit = (uint32_t)-1;
-	bool self_ban;
+	struct recovery_helper_state *state = talloc_get_type_abort(
+		private_data, struct recovery_helper_state);
+	int ret;
 
-	DEBUG(DEBUG_NOTICE, (__location__ " Starting do_recovery\n"));
+	ret = sys_read(state->fd[0], &state->result, sizeof(state->result));
+	if (ret != sizeof(state->result)) {
+		state->result = EPIPE;
+	}
 
-	/* if recovery fails, force it again */
-	rec->need_recovery = true;
+	state->done = true;
+}
 
-	if (!ctdb_op_begin(rec->recovery)) {
+
+static int db_recovery_parallel(struct ctdb_recoverd *rec, TALLOC_CTX *mem_ctx)
+{
+	static char prog[PATH_MAX+1] = "";
+	const char **args;
+	struct recovery_helper_state *state;
+	struct tevent_fd *fde;
+	int nargs, ret;
+
+	if (!ctdb_set_helper("recovery_helper", prog, sizeof(prog),
+			     "CTDB_RECOVERY_HELPER", CTDB_HELPER_BINDIR,
+			     "ctdb_recovery_helper")) {
+		ctdb_die(rec->ctdb, "Unable to set recovery helper\n");
+	}
+
+	state = talloc_zero(mem_ctx, struct recovery_helper_state);
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " memory error\n"));
 		return -1;
 	}
 
-	if (rec->election_timeout) {
-		/* an election is in progress */
-		DEBUG(DEBUG_ERR, ("do_recovery called while election in progress - try again later\n"));
+	state->pid = -1;
+
+	ret = pipe(state->fd);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      ("Failed to create pipe for recovery helper\n"));
 		goto fail;
 	}
 
-	ban_misbehaving_nodes(rec, &self_ban);
-	if (self_ban) {
-		DEBUG(DEBUG_NOTICE, ("This node was banned, aborting recovery\n"));
+	set_close_on_exec(state->fd[0]);
+
+	nargs = 4;
+	args = talloc_array(state, const char *, nargs);
+	if (args == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " memory error\n"));
 		goto fail;
 	}
 
-        if (ctdb->recovery_lock_file != NULL) {
-		if (ctdb_recovery_have_lock(ctdb)) {
-			DEBUG(DEBUG_NOTICE, ("Already holding recovery lock\n"));
-		} else {
-			start_time = timeval_current();
-			DEBUG(DEBUG_NOTICE, ("Attempting to take recovery lock (%s)\n",
-					     ctdb->recovery_lock_file));
-			if (!ctdb_recovery_lock(ctdb)) {
-				if (ctdb->runstate == CTDB_RUNSTATE_FIRST_RECOVERY) {
-					/* If ctdb is trying first recovery, it's
-					 * possible that current node does not know
-					 * yet who the recmaster is.
-					 */
-					DEBUG(DEBUG_ERR, ("Unable to get recovery lock"
-							  " - retrying recovery\n"));
-					goto fail;
-				}
+	args[0] = talloc_asprintf(args, "%d", state->fd[1]);
+	args[1] = rec->ctdb->daemon.name;
+	args[2] = talloc_asprintf(args, "%u", new_generation());
+	args[3] = NULL;
 
-				DEBUG(DEBUG_ERR,("Unable to get recovery lock - aborting recovery "
-						 "and ban ourself for %u seconds\n",
-						 ctdb->tunable.recovery_ban_period));
-				ctdb_ban_node(rec, pnn, ctdb->tunable.recovery_ban_period);
-				goto fail;
-			}
-			ctdb_ctrl_report_recd_lock_latency(ctdb,
-							   CONTROL_TIMEOUT(),
-							   timeval_elapsed(&start_time));
-			DEBUG(DEBUG_NOTICE,
-			      ("Recovery lock taken successfully by recovery daemon\n"));
-		}
+	if (args[0] == NULL || args[2] == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " memory error\n"));
+		goto fail;
 	}
 
-	DEBUG(DEBUG_NOTICE, (__location__ " Recovery initiated due to problem with node %u\n", rec->last_culprit_node));
-
-	/* get a list of all databases */
-	ret = ctdb_ctrl_getdbmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, &dbmap);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to get dbids from node :%u\n", pnn));
+	if (!ctdb_vfork_with_logging(state, rec->ctdb, "recovery", prog, nargs,
+				     args, NULL, NULL, &state->pid)) {
+		DEBUG(DEBUG_ERR,
+		      ("Failed to create child for recovery helper\n"));
 		goto fail;
 	}
 
-	/* we do the db creation before we set the recovery mode, so the freeze happens
-	   on all databases we will be dealing with. */
+	close(state->fd[1]);
+	state->fd[1] = -1;
 
-	/* verify that we have all the databases any other node has */
-	ret = create_missing_local_databases(ctdb, nodemap, pnn, &dbmap, mem_ctx);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to create missing local databases\n"));
+	state->done = false;
+
+	fde = tevent_add_fd(rec->ctdb->ev, rec->ctdb, state->fd[0],
+			    TEVENT_FD_READ, ctdb_recovery_handler, state);
+	if (fde == NULL) {
 		goto fail;
 	}
+	tevent_fd_set_auto_close(fde);
 
-	/* verify that all other nodes have all our databases */
-	ret = create_missing_remote_databases(ctdb, nodemap, pnn, dbmap, mem_ctx);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to create missing remote databases\n"));
-		goto fail;
+	while (!state->done) {
+		tevent_loop_once(rec->ctdb->ev);
 	}
-	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - created remote databases\n"));
 
-	/* update the database priority for all remote databases */
-	ret = update_db_priority_on_remote_nodes(ctdb, nodemap, pnn, dbmap, mem_ctx);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to set db priority on remote nodes\n"));
+	close(state->fd[0]);
+	state->fd[0] = -1;
+
+	if (state->result != 0) {
+		goto fail;
 	}
-	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated db priority for all databases\n"));
 
+	ctdb_kill(rec->ctdb, state->pid, SIGKILL);
+	talloc_free(state);
+	return 0;
 
-	/* update all other nodes to use the same setting for reclock files
-	   as the local recovery master.
-	*/
-	sync_recovery_lock_file_across_cluster(rec);
+fail:
+	if (state->fd[0] != -1) {
+		close(state->fd[0]);
+	}
+	if (state->fd[1] != -1) {
+		close(state->fd[1]);
+	}
+	if (state->pid != -1) {
+		ctdb_kill(rec->ctdb, state->pid, SIGKILL);
+	}
+	talloc_free(state);
+	return -1;
+}
+
+static int db_recovery_serial(struct ctdb_recoverd *rec, TALLOC_CTX *mem_ctx,
+			      uint32_t pnn, struct ctdb_node_map_old *nodemap,
+			      struct ctdb_vnn_map *vnnmap,
+			      struct ctdb_dbid_map_old *dbmap)
+{
+	struct ctdb_context *ctdb = rec->ctdb;
+	uint32_t generation;
+	TDB_DATA data;
+	uint32_t *nodes;
+	int ret, i, j;
 
 	/* set recovery mode to active on all nodes */
-	ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE);
+	ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE, true);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to active on cluster\n"));
-		goto fail;
+		return -1;
 	}
 
 	/* execute the "startrecovery" event script on all nodes */
 	ret = run_startrecovery_eventscript(rec, nodemap);
 	if (ret!=0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'startrecovery' event on cluster\n"));
-		goto fail;
-	}
-
-	/*
-	  update all nodes to have the same flags that we have
-	 */
-	for (i=0;i<nodemap->num;i++) {
-		if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
-			continue;
-		}
-
-		ret = update_flags_on_all_nodes(ctdb, nodemap, i, nodemap->nodes[i].flags);
-		if (ret != 0) {
-			if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
-				DEBUG(DEBUG_WARNING, (__location__ "Unable to update flags on inactive node %d\n", i));
-			} else {
-				DEBUG(DEBUG_ERR, (__location__ " Unable to update flags on all nodes for node %d\n", i));
-				goto fail;
-			}
-		}
+		return -1;
 	}
 
-	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated flags\n"));
-
 	/* pick a new generation number */
 	generation = new_generation();
 
@@ -1957,9 +1871,15 @@ static int do_recovery(struct ctdb_recoverd *rec,
 	ret = ctdb_ctrl_setvnnmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, vnnmap);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to set vnnmap for node %u\n", pnn));
-		goto fail;
+		return -1;
 	}
 
+	/* Database generations are updated when the transaction is commited to
+	 * the databases.  So make sure to use the final generation as the
+	 * transaction id
+	 */
+	generation = new_generation();
+
 	data.dptr = (void *)&generation;
 	data.dsize = sizeof(uint32_t);
 
@@ -1979,19 +1899,19 @@ static int do_recovery(struct ctdb_recoverd *rec,
 					NULL) != 0) {
 			DEBUG(DEBUG_ERR,("Failed to cancel recovery transaction\n"));
 		}
-		goto fail;
+		return -1;
 	}
 
 	DEBUG(DEBUG_NOTICE,(__location__ " started transactions on all nodes\n"));
 
 	for (i=0;i<dbmap->num;i++) {
 		ret = recover_database(rec, mem_ctx,
-				       dbmap->dbs[i].dbid,
+				       dbmap->dbs[i].db_id,
 				       dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT,
 				       pnn, nodemap, generation);
 		if (ret != 0) {
-			DEBUG(DEBUG_ERR, (__location__ " Failed to recover database 0x%x\n", dbmap->dbs[i].dbid));
-			goto fail;
+			DEBUG(DEBUG_ERR, (__location__ " Failed to recover database 0x%x\n", dbmap->dbs[i].db_id));
+			return -1;
 		}
 	}
 
@@ -2004,22 +1924,13 @@ static int do_recovery(struct ctdb_recoverd *rec,
 					NULL, NULL,
 					NULL) != 0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to commit recovery changes. Recovery failed.\n"));
-		goto fail;
+		return -1;
 	}
 
 	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - committed databases\n"));
-	
-
-	/* update the capabilities for all nodes */
-	ret = update_capabilities(rec, nodemap);
-	if (ret!=0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to update node capabilities.\n"));
-		goto fail;
-	}
 
 	/* build a new vnn map with all the currently active and
 	   unbanned nodes */
-	generation = new_generation();
 	vnnmap = talloc(mem_ctx, struct ctdb_vnn_map);
 	CTDB_NO_MEMORY(ctdb, vnnmap);
 	vnnmap->generation = generation;
@@ -2050,52 +1961,207 @@ static int do_recovery(struct ctdb_recoverd *rec,
 		vnnmap->map = talloc_realloc(vnnmap, vnnmap->map, uint32_t, vnnmap->size);
 		CTDB_NO_MEMORY(ctdb, vnnmap->map);
 		vnnmap->map[0] = pnn;
-	}	
+	}
 
 	/* update to the new vnnmap on all nodes */
 	ret = update_vnnmap_on_all_nodes(ctdb, nodemap, pnn, vnnmap, mem_ctx);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to update vnnmap on all nodes\n"));
-		goto fail;
+		return -1;
 	}
 
 	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated vnnmap\n"));
 
-	/* update recmaster to point to us for all nodes */
-	ret = set_recovery_master(ctdb, nodemap, pnn);
-	if (ret!=0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery master\n"));
-		goto fail;
-	}
-
-	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated recmaster\n"));
-
 	/* disable recovery mode */
-	ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_NORMAL);
+	ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_NORMAL, false);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to normal on cluster\n"));
-		goto fail;
+		return -1;
 	}
 
 	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - disabled recovery mode\n"));
 
-	/* Fetch known/available public IPs from each active node */
-	ret = ctdb_reload_remote_public_ips(ctdb, rec, nodemap, &culprit);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
-				 culprit));
-		rec->need_takeover_run = true;
-		goto fail;
-	}
+	return 0;
+}
 
-	do_takeover_run(rec, nodemap, false);
+/*
+  we are the recmaster, and recovery is needed - start a recovery run
+ */
+static int do_recovery(struct ctdb_recoverd *rec,
+		       TALLOC_CTX *mem_ctx, uint32_t pnn,
+		       struct ctdb_node_map_old *nodemap, struct ctdb_vnn_map *vnnmap)
+{
+	struct ctdb_context *ctdb = rec->ctdb;
+	int i, ret;
+	struct ctdb_dbid_map_old *dbmap;
+	struct timeval start_time;
+	bool self_ban;
+	bool par_recovery;
 
-	/* execute the "recovered" event script on all nodes */
-	ret = run_recovered_eventscript(rec, nodemap, "do_recovery");
-	if (ret!=0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'recovered' event on cluster. Recovery process failed.\n"));
-		goto fail;
-	}
+	DEBUG(DEBUG_NOTICE, (__location__ " Starting do_recovery\n"));
+
+	/* Check if the current node is still the recmaster.  It's possible that
+	 * re-election has changed the recmaster.
+	 */
+	if (pnn != rec->recmaster) {
+		DEBUG(DEBUG_NOTICE,
+		      ("Recovery master changed to %u, aborting recovery\n",
+		       rec->recmaster));
+		return -1;
+	}
+
+	/* if recovery fails, force it again */
+	rec->need_recovery = true;
+
+	if (!ctdb_op_begin(rec->recovery)) {
+		return -1;
+	}
+
+	if (rec->election_timeout) {
+		/* an election is in progress */
+		DEBUG(DEBUG_ERR, ("do_recovery called while election in progress - try again later\n"));
+		goto fail;
+	}
+
+	ban_misbehaving_nodes(rec, &self_ban);
+	if (self_ban) {
+		DEBUG(DEBUG_NOTICE, ("This node was banned, aborting recovery\n"));
+		goto fail;
+	}
+
+        if (ctdb->recovery_lock_file != NULL) {
+		if (ctdb_recovery_have_lock(ctdb)) {
+			DEBUG(DEBUG_NOTICE, ("Already holding recovery lock\n"));
+		} else {
+			start_time = timeval_current();
+			DEBUG(DEBUG_NOTICE, ("Attempting to take recovery lock (%s)\n",
+					     ctdb->recovery_lock_file));
+			if (!ctdb_recovery_lock(ctdb)) {
+				if (ctdb->runstate == CTDB_RUNSTATE_FIRST_RECOVERY) {
+					/* If ctdb is trying first recovery, it's
+					 * possible that current node does not know
+					 * yet who the recmaster is.
+					 */
+					DEBUG(DEBUG_ERR, ("Unable to get recovery lock"
+							  " - retrying recovery\n"));
+					goto fail;
+				}
+
+				DEBUG(DEBUG_ERR,("Unable to get recovery lock - aborting recovery "
+						 "and ban ourself for %u seconds\n",
+						 ctdb->tunable.recovery_ban_period));
+				ctdb_ban_node(rec, pnn, ctdb->tunable.recovery_ban_period);
+				goto fail;
+			}
+			ctdb_ctrl_report_recd_lock_latency(ctdb,
+							   CONTROL_TIMEOUT(),
+							   timeval_elapsed(&start_time));
+			DEBUG(DEBUG_NOTICE,
+			      ("Recovery lock taken successfully by recovery daemon\n"));
+		}
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery initiated due to problem with node %u\n", rec->last_culprit_node));
+
+	/* get a list of all databases */
+	ret = ctdb_ctrl_getdbmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get dbids from node :%u\n", pnn));
+		goto fail;
+	}
+
+	/* we do the db creation before we set the recovery mode, so the freeze happens
+	   on all databases we will be dealing with. */
+
+	/* verify that we have all the databases any other node has */
+	ret = create_missing_local_databases(ctdb, nodemap, pnn, &dbmap, mem_ctx);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to create missing local databases\n"));
+		goto fail;
+	}
+
+	/* verify that all other nodes have all our databases */
+	ret = create_missing_remote_databases(ctdb, nodemap, pnn, dbmap, mem_ctx);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to create missing remote databases\n"));
+		goto fail;
+	}
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - created remote databases\n"));
+
+	/* update the database priority for all remote databases */
+	ret = update_db_priority_on_remote_nodes(ctdb, nodemap, pnn, dbmap, mem_ctx);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to set db priority on remote nodes\n"));
+	}
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated db priority for all databases\n"));
+
+
+	/* update all other nodes to use the same setting for reclock files
+	   as the local recovery master.
+	*/
+	sync_recovery_lock_file_across_cluster(rec);
+
+	/* Retrieve capabilities from all connected nodes */
+	ret = update_capabilities(rec, nodemap);
+	if (ret!=0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to update node capabilities.\n"));
+		return -1;
+	}
+
+	/*
+	  update all nodes to have the same flags that we have
+	 */
+	for (i=0;i<nodemap->num;i++) {
+		if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+			continue;
+		}
+
+		ret = update_flags_on_all_nodes(ctdb, nodemap, i, nodemap->nodes[i].flags);
+		if (ret != 0) {
+			if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+				DEBUG(DEBUG_WARNING, (__location__ "Unable to update flags on inactive node %d\n", i));
+			} else {
+				DEBUG(DEBUG_ERR, (__location__ " Unable to update flags on all nodes for node %d\n", i));
+				return -1;
+			}
+		}
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated flags\n"));
+
+	/* Check if all participating nodes have parallel recovery capability */
+	par_recovery = true;
+	for (i=0; i<nodemap->num; i++) {
+		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+
+		if (!(rec->caps[i].capabilities &
+		      CTDB_CAP_PARALLEL_RECOVERY)) {
+			par_recovery = false;
+			break;
+		}
+	}
+
+	if (par_recovery) {
+		ret = db_recovery_parallel(rec, mem_ctx);
+	} else {
+		ret = db_recovery_serial(rec, mem_ctx, pnn, nodemap, vnnmap,
+					 dbmap);
+	}
+
+	if (ret != 0) {
+		goto fail;
+	}
+
+	do_takeover_run(rec, nodemap, false);
+
+	/* execute the "recovered" event script on all nodes */
+	ret = run_recovered_eventscript(rec, nodemap, "do_recovery");
+	if (ret!=0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'recovered' event on cluster. Recovery process failed.\n"));
+		goto fail;
+	}
 
 	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - finished the recovered event\n"));
 
@@ -2165,7 +2231,7 @@ struct election_message {
 static void ctdb_election_data(struct ctdb_recoverd *rec, struct election_message *em)
 {
 	int ret, i;
-	struct ctdb_node_map *nodemap;
+	struct ctdb_node_map_old *nodemap;
 	struct ctdb_context *ctdb = rec->ctdb;
 
 	ZERO_STRUCTP(em);
@@ -2207,7 +2273,7 @@ static bool ctdb_election_win(struct ctdb_recoverd *rec, struct election_message
 
 	ctdb_election_data(rec, &myem);
 
-	/* we cant win if we dont have the recmaster capability */
+	/* we cant win if we don't have the recmaster capability */
 	if ((rec->ctdb->capabilities & CTDB_CAP_RECMASTER) == 0) {
 		return false;
 	}
@@ -2232,11 +2298,6 @@ static bool ctdb_election_win(struct ctdb_recoverd *rec, struct election_message
 		return true;
 	}
 
-	/* try to use the most connected node */
-	if (cmp == 0) {
-		cmp = (int)myem.num_connected - (int)em->num_connected;
-	}
-
 	/* then the longest running node */
 	if (cmp == 0) {
 		cmp = timeval_compare(&em->priority_time, &myem.priority_time);
@@ -2260,7 +2321,7 @@ static int send_election_request(struct ctdb_recoverd *rec, uint32_t pnn)
 	uint64_t srvid;
 	struct ctdb_context *ctdb = rec->ctdb;
 
-	srvid = CTDB_SRVID_RECOVERY;
+	srvid = CTDB_SRVID_ELECTION;
 
 	ctdb_election_data(rec, &emsg);
 
@@ -2271,12 +2332,13 @@ static int send_election_request(struct ctdb_recoverd *rec, uint32_t pnn)
 	/* first we assume we will win the election and set 
 	   recoverymaster to be ourself on the current node
 	 */
-	ret = ctdb_ctrl_setrecmaster(ctdb, CONTROL_TIMEOUT(), pnn, pnn);
+	ret = ctdb_ctrl_setrecmaster(ctdb, CONTROL_TIMEOUT(),
+				     CTDB_CURRENT_NODE, pnn);
 	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " failed to send recmaster election request\n"));
+		DEBUG(DEBUG_ERR, (__location__ " failed to set recmaster\n"));
 		return -1;
 	}
-
+	rec->recmaster = pnn;
 
 	/* send an election message to all active nodes */
 	DEBUG(DEBUG_INFO,(__location__ " Send election request to all active nodes\n"));
@@ -2284,40 +2346,11 @@ static int send_election_request(struct ctdb_recoverd *rec, uint32_t pnn)
 }
 
 /*
-  this function will unban all nodes in the cluster
-*/
-static void unban_all_nodes(struct ctdb_context *ctdb)
-{
-	int ret, i;
-	struct ctdb_node_map *nodemap;
-	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	
-	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR,(__location__ " failed to get nodemap to unban all nodes\n"));
-		return;
-	}
-
-	for (i=0;i<nodemap->num;i++) {
-		if ( (!(nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED))
-		  && (nodemap->nodes[i].flags & NODE_FLAGS_BANNED) ) {
-			ret = ctdb_ctrl_modflags(ctdb, CONTROL_TIMEOUT(),
-						 nodemap->nodes[i].pnn, 0,
-						 NODE_FLAGS_BANNED);
-			if (ret != 0) {
-				DEBUG(DEBUG_ERR, (__location__ " failed to reset ban state\n"));
-			}
-		}
-	}
-
-	talloc_free(tmp_ctx);
-}
-
-
-/*
   we think we are winning the election - send a broadcast election request
  */
-static void election_send_request(struct event_context *ev, struct timed_event *te, struct timeval t, void *p)
+static void election_send_request(struct tevent_context *ev,
+				  struct tevent_timer *te,
+				  struct timeval t, void *p)
 {
 	struct ctdb_recoverd *rec = talloc_get_type(p, struct ctdb_recoverd);
 	int ret;
@@ -2327,27 +2360,28 @@ static void election_send_request(struct event_context *ev, struct timed_event *
 		DEBUG(DEBUG_ERR,("Failed to send election request!\n"));
 	}
 
-	talloc_free(rec->send_election_te);
-	rec->send_election_te = NULL;
+	TALLOC_FREE(rec->send_election_te);
 }
 
 /*
   handler for memory dumps
 */
-static void mem_dump_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			     TDB_DATA data, void *private_data)
+static void mem_dump_handler(uint64_t srvid, TDB_DATA data, void *private_data)
 {
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
+	struct ctdb_context *ctdb = rec->ctdb;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	TDB_DATA *dump;
 	int ret;
-	struct srvid_request *rd;
+	struct ctdb_srvid_message *rd;
 
-	if (data.dsize != sizeof(struct srvid_request)) {
+	if (data.dsize != sizeof(struct ctdb_srvid_message)) {
 		DEBUG(DEBUG_ERR, (__location__ " Wrong size of return address.\n"));
 		talloc_free(tmp_ctx);
 		return;
 	}
-	rd = (struct srvid_request *)data.dptr;
+	rd = (struct ctdb_srvid_message *)data.dptr;
 
 	dump = talloc_zero(tmp_ctx, TDB_DATA);
 	if (dump == NULL) {
@@ -2377,10 +2411,11 @@ DEBUG(DEBUG_ERR, ("recovery master memory dump\n"));
 /*
   handler for reload_nodes
 */
-static void reload_nodes_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			     TDB_DATA data, void *private_data)
+static void reload_nodes_handler(uint64_t srvid, TDB_DATA data,
+				 void *private_data)
 {
-	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
 
 	DEBUG(DEBUG_ERR, (__location__ " Reload nodes file from recovery daemon\n"));
 
@@ -2388,8 +2423,8 @@ static void reload_nodes_handler(struct ctdb_context *ctdb, uint64_t srvid,
 }
 
 
-static void ctdb_rebalance_timeout(struct event_context *ev,
-				   struct timed_event *te,
+static void ctdb_rebalance_timeout(struct tevent_context *ev,
+				   struct tevent_timer *te,
 				   struct timeval t, void *p)
 {
 	struct ctdb_recoverd *rec = talloc_get_type(p, struct ctdb_recoverd);
@@ -2401,20 +2436,21 @@ static void ctdb_rebalance_timeout(struct event_context *ev,
 	}
 
 	DEBUG(DEBUG_NOTICE,
-	      ("Rebalance timeout occurred - do takeover run\n"));
-	do_takeover_run(rec, rec->nodemap, false);
+	      ("Rebalance timeout occurred - trigger takeover run\n"));
+	rec->need_takeover_run = true;
 }
 
-	
-static void recd_node_rebalance_handler(struct ctdb_context *ctdb,
-					uint64_t srvid,
-					TDB_DATA data, void *private_data)
+
+static void recd_node_rebalance_handler(uint64_t srvid, TDB_DATA data,
+					void *private_data)
 {
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
+	struct ctdb_context *ctdb = rec->ctdb;
 	uint32_t pnn;
 	uint32_t *t;
 	int len;
 	uint32_t deferred_rebalance;
-	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
 
 	if (rec->recmaster != ctdb_get_pnn(ctdb)) {
 		return;
@@ -2462,18 +2498,19 @@ static void recd_node_rebalance_handler(struct ctdb_context *ctdb,
 	 */
 	deferred_rebalance = ctdb->tunable.deferred_rebalance_on_node_add;
 	if (deferred_rebalance != 0) {
-		event_add_timed(ctdb->ev, rec->force_rebalance_nodes,
-				timeval_current_ofs(deferred_rebalance, 0),
-				ctdb_rebalance_timeout, rec);
+		tevent_add_timer(ctdb->ev, rec->force_rebalance_nodes,
+				 timeval_current_ofs(deferred_rebalance, 0),
+				 ctdb_rebalance_timeout, rec);
 	}
 }
 
 
 
-static void recd_update_ip_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			     TDB_DATA data, void *private_data)
+static void recd_update_ip_handler(uint64_t srvid, TDB_DATA data,
+				   void *private_data)
 {
-	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
 	struct ctdb_public_ip *ip;
 
 	if (rec->recmaster != rec->ctdb->pnn) {
@@ -2495,16 +2532,16 @@ static void srvid_disable_and_reply(struct ctdb_context *ctdb,
 				    TDB_DATA data,
 				    struct ctdb_op_state *op_state)
 {
-	struct srvid_request_data *r;
+	struct ctdb_disable_message *r;
 	uint32_t timeout;
 	TDB_DATA result;
 	int32_t ret = 0;
 
 	/* Validate input data */
-	if (data.dsize != sizeof(struct srvid_request_data)) {
+	if (data.dsize != sizeof(struct ctdb_disable_message)) {
 		DEBUG(DEBUG_ERR,(__location__ " Wrong size for data :%lu "
 				 "expecting %lu\n", (long unsigned)data.dsize,
-				 (long unsigned)sizeof(struct srvid_request)));
+				 (long unsigned)sizeof(struct ctdb_srvid_message)));
 		return;
 	}
 	if (data.dptr == NULL) {
@@ -2512,8 +2549,8 @@ static void srvid_disable_and_reply(struct ctdb_context *ctdb,
 		return;
 	}
 
-	r = (struct srvid_request_data *)data.dptr;
-	timeout = r->data;
+	r = (struct ctdb_disable_message *)data.dptr;
+	timeout = r->timeout;
 
 	ret = ctdb_op_disable(op_state, ctdb->ev, timeout);
 	if (ret != 0) {
@@ -2525,25 +2562,24 @@ static void srvid_disable_and_reply(struct ctdb_context *ctdb,
 done:
 	result.dsize = sizeof(int32_t);
 	result.dptr  = (uint8_t *)&ret;
-	srvid_request_reply(ctdb, (struct srvid_request *)r, result);
+	srvid_request_reply(ctdb, (struct ctdb_srvid_message *)r, result);
 }
 
-static void disable_takeover_runs_handler(struct ctdb_context *ctdb,
-					  uint64_t srvid, TDB_DATA data,
+static void disable_takeover_runs_handler(uint64_t srvid, TDB_DATA data,
 					  void *private_data)
 {
-	struct ctdb_recoverd *rec = talloc_get_type(private_data,
-						    struct ctdb_recoverd);
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
 
-	srvid_disable_and_reply(ctdb, data, rec->takeover_run);
+	srvid_disable_and_reply(rec->ctdb, data, rec->takeover_run);
 }
 
 /* Backward compatibility for this SRVID */
-static void disable_ip_check_handler(struct ctdb_context *ctdb, uint64_t srvid,
-				     TDB_DATA data, void *private_data)
+static void disable_ip_check_handler(uint64_t srvid, TDB_DATA data,
+				     void *private_data)
 {
-	struct ctdb_recoverd *rec = talloc_get_type(private_data,
-						    struct ctdb_recoverd);
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
 	uint32_t timeout;
 
 	if (data.dsize != sizeof(uint32_t)) {
@@ -2559,17 +2595,16 @@ static void disable_ip_check_handler(struct ctdb_context *ctdb, uint64_t srvid,
 
 	timeout = *((uint32_t *)data.dptr);
 
-	ctdb_op_disable(rec->takeover_run, ctdb->ev, timeout);
+	ctdb_op_disable(rec->takeover_run, rec->ctdb->ev, timeout);
 }
 
-static void disable_recoveries_handler(struct ctdb_context *ctdb,
-				       uint64_t srvid, TDB_DATA data,
+static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
 				       void *private_data)
 {
-	struct ctdb_recoverd *rec = talloc_get_type(private_data,
-						    struct ctdb_recoverd);
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
 
-	srvid_disable_and_reply(ctdb, data, rec->recovery);
+	srvid_disable_and_reply(rec->ctdb, data, rec->recovery);
 }
 
 /*
@@ -2577,21 +2612,21 @@ static void disable_recoveries_handler(struct ctdb_context *ctdb,
   handle this later in the monitor_cluster loop so we do not recurse
   with other requests to takeover_run()
 */
-static void ip_reallocate_handler(struct ctdb_context *ctdb, uint64_t srvid,
-				  TDB_DATA data, void *private_data)
+static void ip_reallocate_handler(uint64_t srvid, TDB_DATA data,
+				  void *private_data)
 {
-	struct srvid_request *request;
-	struct ctdb_recoverd *rec = talloc_get_type(private_data,
-						    struct ctdb_recoverd);
+	struct ctdb_srvid_message *request;
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
 
-	if (data.dsize != sizeof(struct srvid_request)) {
+	if (data.dsize != sizeof(struct ctdb_srvid_message)) {
 		DEBUG(DEBUG_ERR, (__location__ " Wrong size of return address.\n"));
 		return;
 	}
 
-	request = (struct srvid_request *)data.dptr;
+	request = (struct ctdb_srvid_message *)data.dptr;
 
-	srvid_request_add(ctdb, &rec->reallocate_requests, request);
+	srvid_request_add(rec->ctdb, &rec->reallocate_requests, request);
 }
 
 static void process_ipreallocate_requests(struct ctdb_context *ctdb,
@@ -2599,7 +2634,6 @@ static void process_ipreallocate_requests(struct ctdb_context *ctdb,
 {
 	TDB_DATA result;
 	int32_t ret;
-	uint32_t culprit;
 	struct srvid_requests *current;
 
 	DEBUG(DEBUG_INFO, ("recovery master forced ip reallocation\n"));
@@ -2612,21 +2646,10 @@ static void process_ipreallocate_requests(struct ctdb_context *ctdb,
 	current = rec->reallocate_requests;
 	rec->reallocate_requests = NULL;
 
-	/* update the list of public ips that a node can handle for
-	   all connected nodes
-	*/
-	ret = ctdb_reload_remote_public_ips(ctdb, rec, rec->nodemap, &culprit);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
-				 culprit));
-		rec->need_takeover_run = true;
-	}
-	if (ret == 0) {
-		if (do_takeover_run(rec, rec->nodemap, false)) {
-			ret = ctdb_get_pnn(ctdb);
-		} else {
-			ret = -1;
-		}
+	if (do_takeover_run(rec, rec->nodemap, false)) {
+		ret = ctdb_get_pnn(ctdb);
+	} else {
+		ret = -1;
 	}
 
 	result.dsize = sizeof(int32_t);
@@ -2639,10 +2662,11 @@ static void process_ipreallocate_requests(struct ctdb_context *ctdb,
 /*
   handler for recovery master elections
 */
-static void election_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			     TDB_DATA data, void *private_data)
+static void election_handler(uint64_t srvid, TDB_DATA data, void *private_data)
 {
-	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
+	struct ctdb_context *ctdb = rec->ctdb;
 	int ret;
 	struct election_message *em = (struct election_message *)data.dptr;
 
@@ -2653,11 +2677,12 @@ static void election_handler(struct ctdb_context *ctdb, uint64_t srvid,
 
 	/* we got an election packet - update the timeout for the election */
 	talloc_free(rec->election_timeout);
-	rec->election_timeout = event_add_timed(ctdb->ev, ctdb, 
-						fast_start ?
-						timeval_current_ofs(0, 500000) :
-						timeval_current_ofs(ctdb->tunable.election_timeout, 0), 
-						ctdb_election_timeout, rec);
+	rec->election_timeout = tevent_add_timer(
+			ctdb->ev, ctdb,
+			fast_start ?
+				timeval_current_ofs(0, 500000) :
+				timeval_current_ofs(ctdb->tunable.election_timeout, 0),
+			ctdb_election_timeout, rec);
 
 	/* someone called an election. check their election data
 	   and if we disagree and we would rather be the elected node, 
@@ -2665,11 +2690,11 @@ static void election_handler(struct ctdb_context *ctdb, uint64_t srvid,
 	 */
 	if (ctdb_election_win(rec, em)) {
 		if (!rec->send_election_te) {
-			rec->send_election_te = event_add_timed(ctdb->ev, rec, 
-								timeval_current_ofs(0, 500000),
-								election_send_request, rec);
+			rec->send_election_te = tevent_add_timer(
+					ctdb->ev, rec,
+					timeval_current_ofs(0, 500000),
+					election_send_request, rec);
 		}
-		/*unban_all_nodes(ctdb);*/
 		return;
 	}
 
@@ -2679,17 +2704,18 @@ static void election_handler(struct ctdb_context *ctdb, uint64_t srvid,
 	/* Release the recovery lock file */
 	if (ctdb_recovery_have_lock(ctdb)) {
 		ctdb_recovery_unlock(ctdb);
-		unban_all_nodes(ctdb);
 	}
 
 	clear_ip_assignment_tree(ctdb);
 
 	/* ok, let that guy become recmaster then */
-	ret = ctdb_ctrl_setrecmaster(ctdb, CONTROL_TIMEOUT(), ctdb_get_pnn(ctdb), em->pnn);
+	ret = ctdb_ctrl_setrecmaster(ctdb, CONTROL_TIMEOUT(),
+				     CTDB_CURRENT_NODE, em->pnn);
 	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " failed to send recmaster election request"));
+		DEBUG(DEBUG_ERR, (__location__ " failed to set recmaster"));
 		return;
 	}
+	rec->recmaster = em->pnn;
 
 	return;
 }
@@ -2699,7 +2725,7 @@ static void election_handler(struct ctdb_context *ctdb, uint64_t srvid,
   force the start of the election process
  */
 static void force_election(struct ctdb_recoverd *rec, uint32_t pnn, 
-			   struct ctdb_node_map *nodemap)
+			   struct ctdb_node_map_old *nodemap)
 {
 	int ret;
 	struct ctdb_context *ctdb = rec->ctdb;
@@ -2707,18 +2733,19 @@ static void force_election(struct ctdb_recoverd *rec, uint32_t pnn,
 	DEBUG(DEBUG_INFO,(__location__ " Force an election\n"));
 
 	/* set all nodes to recovery mode to stop all internode traffic */
-	ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE);
+	ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE, false);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to active on cluster\n"));
 		return;
 	}
 
 	talloc_free(rec->election_timeout);
-	rec->election_timeout = event_add_timed(ctdb->ev, ctdb, 
-						fast_start ?
-						timeval_current_ofs(0, 500000) :
-						timeval_current_ofs(ctdb->tunable.election_timeout, 0), 
-						ctdb_election_timeout, rec);
+	rec->election_timeout = tevent_add_timer(
+			ctdb->ev, ctdb,
+			fast_start ?
+				timeval_current_ofs(0, 500000) :
+				timeval_current_ofs(ctdb->tunable.election_timeout, 0),
+			ctdb_election_timeout, rec);
 
 	ret = send_election_request(rec, pnn);
 	if (ret!=0) {
@@ -2735,15 +2762,16 @@ static void force_election(struct ctdb_recoverd *rec, uint32_t pnn,
 /*
   handler for when a node changes its flags
 */
-static void monitor_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			    TDB_DATA data, void *private_data)
+static void monitor_handler(uint64_t srvid, TDB_DATA data, void *private_data)
 {
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
+	struct ctdb_context *ctdb = rec->ctdb;
 	int ret;
 	struct ctdb_node_flag_change *c = (struct ctdb_node_flag_change *)data.dptr;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	TALLOC_CTX *tmp_ctx;
 	int i;
-	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
 	int disabled_flag_changed;
 
 	if (data.dsize != sizeof(*c)) {
@@ -2780,16 +2808,11 @@ static void monitor_handler(struct ctdb_context *ctdb, uint64_t srvid,
 
 	nodemap->nodes[i].flags = c->new_flags;
 
-	ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, CONTROL_TIMEOUT(), 
-				     CTDB_CURRENT_NODE, &ctdb->recovery_master);
+	ret = ctdb_ctrl_getrecmode(ctdb, tmp_ctx, CONTROL_TIMEOUT(),
+				   CTDB_CURRENT_NODE, &ctdb->recovery_mode);
 
-	if (ret == 0) {
-		ret = ctdb_ctrl_getrecmode(ctdb, tmp_ctx, CONTROL_TIMEOUT(), 
-					   CTDB_CURRENT_NODE, &ctdb->recovery_mode);
-	}
-	
 	if (ret == 0 &&
-	    ctdb->recovery_master == ctdb->pnn &&
+	    rec->recmaster == ctdb->pnn &&
 	    ctdb->recovery_mode == CTDB_RECOVERY_NORMAL) {
 		/* Only do the takeover run if the perm disabled or unhealthy
 		   flags changed since these will cause an ip failover but not
@@ -2809,26 +2832,21 @@ static void monitor_handler(struct ctdb_context *ctdb, uint64_t srvid,
 /*
   handler for when we need to push out flag changes ot all other nodes
 */
-static void push_flags_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			    TDB_DATA data, void *private_data)
+static void push_flags_handler(uint64_t srvid, TDB_DATA data,
+			       void *private_data)
 {
+	struct ctdb_recoverd *rec = talloc_get_type(
+		private_data, struct ctdb_recoverd);
+	struct ctdb_context *ctdb = rec->ctdb;
 	int ret;
 	struct ctdb_node_flag_change *c = (struct ctdb_node_flag_change *)data.dptr;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	uint32_t recmaster;
 	uint32_t *nodes;
 
-	/* find the recovery master */
-	ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, &recmaster);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to get recmaster from local node\n"));
-		talloc_free(tmp_ctx);
-		return;
-	}
-
 	/* read the node flags from the recmaster */
-	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), recmaster, tmp_ctx, &nodemap);
+	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), rec->recmaster,
+				   tmp_ctx, &nodemap);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to get nodemap from node %u\n", c->pnn));
 		talloc_free(tmp_ctx);
@@ -2894,7 +2912,7 @@ static void verify_recmode_normal_callback(struct ctdb_client_control_state *sta
 
 
 /* verify that all nodes are in normal recovery mode */
-static enum monitor_result verify_recmode(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap)
+static enum monitor_result verify_recmode(struct ctdb_context *ctdb, struct ctdb_node_map_old *nodemap)
 {
 	struct verify_recmode_normal_data *rmdata;
 	TALLOC_CTX *mem_ctx = talloc_new(ctdb);
@@ -2938,7 +2956,7 @@ static enum monitor_result verify_recmode(struct ctdb_context *ctdb, struct ctdb
 	   or until all nodes we expect a response from has replied
 	*/
 	while (rmdata->count > 0) {
-		event_loop_once(ctdb->ev);
+		tevent_loop_once(ctdb->ev);
 	}
 
 	status = rmdata->status;
@@ -2986,7 +3004,7 @@ static void verify_recmaster_callback(struct ctdb_client_control_state *state)
 
 
 /* verify that all nodes agree that we are the recmaster */
-static enum monitor_result verify_recmaster(struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap, uint32_t pnn)
+static enum monitor_result verify_recmaster(struct ctdb_recoverd *rec, struct ctdb_node_map_old *nodemap, uint32_t pnn)
 {
 	struct ctdb_context *ctdb = rec->ctdb;
 	struct verify_recmaster_data *rmdata;
@@ -3002,9 +3020,12 @@ static enum monitor_result verify_recmaster(struct ctdb_recoverd *rec, struct ct
 	rmdata->pnn    = pnn;
 	rmdata->status = MONITOR_OK;
 
-	/* loop over all active nodes and send an async getrecmaster call to 
+	/* loop over all active nodes and send an async getrecmaster call to
 	   them*/
 	for (j=0; j<nodemap->num; j++) {
+		if (nodemap->nodes[j].pnn == rec->recmaster) {
+			continue;
+		}
 		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
 			continue;
 		}
@@ -3033,7 +3054,7 @@ static enum monitor_result verify_recmaster(struct ctdb_recoverd *rec, struct ct
 	   or until all nodes we expect a response from has replied
 	*/
 	while (rmdata->count > 0) {
-		event_loop_once(ctdb->ev);
+		tevent_loop_once(ctdb->ev);
 	}
 
 	status = rmdata->status;
@@ -3044,7 +3065,7 @@ static enum monitor_result verify_recmaster(struct ctdb_recoverd *rec, struct ct
 static bool interfaces_have_changed(struct ctdb_context *ctdb,
 				    struct ctdb_recoverd *rec)
 {
-	struct ctdb_control_get_ifaces *ifaces = NULL;
+	struct ctdb_iface_list_old *ifaces = NULL;
 	TALLOC_CTX *mem_ctx;
 	bool ret = false;
 
@@ -3075,7 +3096,7 @@ static bool interfaces_have_changed(struct ctdb_context *ctdb,
 		/* See if interface names or link states have changed */
 		int i;
 		for (i = 0; i < rec->ifaces->num; i++) {
-			struct ctdb_control_iface_info * iface = &rec->ifaces->ifaces[i];
+			struct ctdb_iface * iface = &rec->ifaces->ifaces[i];
 			if (strcmp(iface->name, ifaces->ifaces[i].name) != 0) {
 				DEBUG(DEBUG_NOTICE,
 				      ("Interface in slot %d changed: %s => %s\n",
@@ -3103,22 +3124,12 @@ static bool interfaces_have_changed(struct ctdb_context *ctdb,
 
 /* called to check that the local allocation of public ip addresses is ok.
 */
-static int verify_local_ip_allocation(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, uint32_t pnn, struct ctdb_node_map *nodemap)
+static int verify_local_ip_allocation(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, uint32_t pnn, struct ctdb_node_map_old *nodemap)
 {
 	TALLOC_CTX *mem_ctx = talloc_new(NULL);
-	struct ctdb_uptime *uptime1 = NULL;
-	struct ctdb_uptime *uptime2 = NULL;
 	int ret, j;
 	bool need_takeover_run = false;
 
-	ret = ctdb_ctrl_uptime(ctdb, mem_ctx, CONTROL_TIMEOUT(),
-				CTDB_CURRENT_NODE, &uptime1);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, ("Unable to get uptime from local node %u\n", pnn));
-		talloc_free(mem_ctx);
-		return -1;
-	}
-
 	if (interfaces_have_changed(ctdb, rec)) {
 		DEBUG(DEBUG_NOTICE, ("The interfaces status has changed on "
 				     "local node %u - force takeover run\n",
@@ -3126,41 +3137,8 @@ static int verify_local_ip_allocation(struct ctdb_context *ctdb, struct ctdb_rec
 		need_takeover_run = true;
 	}
 
-	ret = ctdb_ctrl_uptime(ctdb, mem_ctx, CONTROL_TIMEOUT(),
-				CTDB_CURRENT_NODE, &uptime2);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, ("Unable to get uptime from local node %u\n", pnn));
-		talloc_free(mem_ctx);
-		return -1;
-	}
-
-	/* skip the check if the startrecovery time has changed */
-	if (timeval_compare(&uptime1->last_recovery_started,
-			    &uptime2->last_recovery_started) != 0) {
-		DEBUG(DEBUG_NOTICE, (__location__ " last recovery time changed while we read the public ip list. skipping public ip address check\n"));
-		talloc_free(mem_ctx);
-		return 0;
-	}
-
-	/* skip the check if the endrecovery time has changed */
-	if (timeval_compare(&uptime1->last_recovery_finished,
-			    &uptime2->last_recovery_finished) != 0) {
-		DEBUG(DEBUG_NOTICE, (__location__ " last recovery time changed while we read the public ip list. skipping public ip address check\n"));
-		talloc_free(mem_ctx);
-		return 0;
-	}
-
-	/* skip the check if we have started but not finished recovery */
-	if (timeval_compare(&uptime1->last_recovery_finished,
-			    &uptime1->last_recovery_started) != 1) {
-		DEBUG(DEBUG_INFO, (__location__ " in the middle of recovery or ip reallocation. skipping public ip address check\n"));
-		talloc_free(mem_ctx);
-
-		return 0;
-	}
-
 	/* verify that we have the ip addresses we should have
-	   and we dont have ones we shouldnt have.
+	   and we don't have ones we shouldnt have.
 	   if we find an inconsistency we set recmode to
 	   active on the local node and wait for the recmaster
 	   to do a full blown recovery.
@@ -3168,7 +3146,7 @@ static int verify_local_ip_allocation(struct ctdb_context *ctdb, struct ctdb_rec
 	   we also request a ip reallocation.
 	*/
 	if (ctdb->tunable.disable_ip_failover == 0) {
-		struct ctdb_all_public_ips *ips = NULL;
+		struct ctdb_public_ip_list_old *ips = NULL;
 
 		/* read the *available* IPs from the local node */
 		ret = ctdb_ctrl_get_public_ips_flags(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, mem_ctx, CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE, &ips);
@@ -3220,11 +3198,12 @@ static int verify_local_ip_allocation(struct ctdb_context *ctdb, struct ctdb_rec
 	}
 
 	if (need_takeover_run) {
-		struct srvid_request rd;
+		struct ctdb_srvid_message rd;
 		TDB_DATA data;
 
 		DEBUG(DEBUG_CRIT,("Trigger takeoverrun\n"));
 
+		ZERO_STRUCT(rd);
 		rd.pnn = ctdb->pnn;
 		rd.srvid = 0;
 		data.dptr = (uint8_t *)&rd;
@@ -3242,20 +3221,20 @@ static int verify_local_ip_allocation(struct ctdb_context *ctdb, struct ctdb_rec
 
 static void async_getnodemap_callback(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data)
 {
-	struct ctdb_node_map **remote_nodemaps = callback_data;
+	struct ctdb_node_map_old **remote_nodemaps = callback_data;
 
 	if (node_pnn >= ctdb->num_nodes) {
 		DEBUG(DEBUG_ERR,(__location__ " pnn from invalid node\n"));
 		return;
 	}
 
-	remote_nodemaps[node_pnn] = (struct ctdb_node_map *)talloc_steal(remote_nodemaps, outdata.dptr);
+	remote_nodemaps[node_pnn] = (struct ctdb_node_map_old *)talloc_steal(remote_nodemaps, outdata.dptr);
 
 }
 
 static int get_remote_nodemaps(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
-	struct ctdb_node_map *nodemap,
-	struct ctdb_node_map **remote_nodemaps)
+	struct ctdb_node_map_old *nodemap,
+	struct ctdb_node_map_old **remote_nodemaps)
 {
 	uint32_t *nodes;
 
@@ -3321,13 +3300,99 @@ static int update_recovery_lock_file(struct ctdb_context *ctdb)
 	return 0;
 }
 
+static enum monitor_result validate_recovery_master(struct ctdb_recoverd *rec,
+						    TALLOC_CTX *mem_ctx)
+{
+	struct ctdb_context *ctdb = rec->ctdb;
+	uint32_t pnn = ctdb_get_pnn(ctdb);
+	struct ctdb_node_map_old *nodemap = rec->nodemap;
+	struct ctdb_node_map_old *recmaster_nodemap = NULL;
+	int ret;
+
+	/* When recovery daemon is started, recmaster is set to
+	 * "unknown" so it knows to start an election.
+	 */
+	if (rec->recmaster == CTDB_UNKNOWN_PNN) {
+		DEBUG(DEBUG_NOTICE,
+		      ("Initial recovery master set - forcing election\n"));
+		return MONITOR_ELECTION_NEEDED;
+	}
+
+	/*
+	 * If the current recmaster does not have CTDB_CAP_RECMASTER,
+	 * but we have, then force an election and try to become the new
+	 * recmaster.
+	 */
+	if (!ctdb_node_has_capabilities(rec->caps,
+					rec->recmaster,
+					CTDB_CAP_RECMASTER) &&
+	    (rec->ctdb->capabilities & CTDB_CAP_RECMASTER) &&
+	    !(nodemap->nodes[pnn].flags & NODE_FLAGS_INACTIVE)) {
+		DEBUG(DEBUG_ERR,
+		      (" Current recmaster node %u does not have CAP_RECMASTER,"
+		       " but we (node %u) have - force an election\n",
+		       rec->recmaster, pnn));
+		return MONITOR_ELECTION_NEEDED;
+	}
+
+	/* Verify that the master node has not been deleted.  This
+	 * should not happen because a node should always be shutdown
+	 * before being deleted, causing a new master to be elected
+	 * before now.  However, if something strange has happened
+	 * then checking here will ensure we don't index beyond the
+	 * end of the nodemap array. */
+	if (rec->recmaster >= nodemap->num) {
+		DEBUG(DEBUG_ERR,
+		      ("Recmaster node %u has been deleted. Force election\n",
+		       rec->recmaster));
+		return MONITOR_ELECTION_NEEDED;
+	}
+
+	/* if recovery master is disconnected/deleted we must elect a new recmaster */
+	if (nodemap->nodes[rec->recmaster].flags &
+	    (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
+		DEBUG(DEBUG_NOTICE,
+		      ("Recmaster node %u is disconnected/deleted. Force election\n",
+		       rec->recmaster));
+		return MONITOR_ELECTION_NEEDED;
+	}
+
+	/* get nodemap from the recovery master to check if it is inactive */
+	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), rec->recmaster,
+				   mem_ctx, &recmaster_nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,
+		      (__location__
+		       " Unable to get nodemap from recovery master %u\n",
+			  rec->recmaster));
+		return MONITOR_FAILED;
+	}
+
+
+	if ((recmaster_nodemap->nodes[rec->recmaster].flags & NODE_FLAGS_INACTIVE) &&
+	    (rec->node_flags & NODE_FLAGS_INACTIVE) == 0) {
+		DEBUG(DEBUG_NOTICE,
+		      ("Recmaster node %u is inactive. Force election\n",
+		       rec->recmaster));
+		/*
+		 * update our nodemap to carry the recmaster's notion of
+		 * its own flags, so that we don't keep freezing the
+		 * inactive recmaster node...
+		 */
+		nodemap->nodes[rec->recmaster].flags =
+			recmaster_nodemap->nodes[rec->recmaster].flags;
+		return MONITOR_ELECTION_NEEDED;
+	}
+
+	return MONITOR_OK;
+}
+
 static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec,
 		      TALLOC_CTX *mem_ctx)
 {
 	uint32_t pnn;
-	struct ctdb_node_map *nodemap=NULL;
-	struct ctdb_node_map *recmaster_nodemap=NULL;
-	struct ctdb_node_map **remote_nodemaps=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
+	struct ctdb_node_map_old **remote_nodemaps=NULL;
 	struct ctdb_vnn_map *vnnmap=NULL;
 	struct ctdb_vnn_map *remote_vnnmap=NULL;
 	uint32_t num_lmasters;
@@ -3379,29 +3444,10 @@ static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec,
 		return;
 	}
 
-	/* Make sure that if recovery lock verification becomes disabled when
-	   we close the file
-	*/
-        if (ctdb->recovery_lock_file == NULL) {
-		ctdb_recovery_unlock(ctdb);
-	}
-
 	pnn = ctdb_get_pnn(ctdb);
 
-	/* get the vnnmap */
-	ret = ctdb_ctrl_getvnnmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, &vnnmap);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to get vnnmap from node %u\n", pnn));
-		return;
-	}
-
-
-	/* get number of nodes */
-	if (rec->nodemap) {
-		talloc_free(rec->nodemap);
-		rec->nodemap = NULL;
-		nodemap=NULL;
-	}
+	/* get nodemap */
+	TALLOC_FREE(rec->nodemap);
 	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), pnn, rec, &rec->nodemap);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to get nodemap from node %u\n", pnn));
@@ -3457,13 +3503,6 @@ static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec,
 		return;
 	}
 
-	/* check which node is the recovery master */
-	ret = ctdb_ctrl_getrecmaster(ctdb, mem_ctx, CONTROL_TIMEOUT(), pnn, &rec->recmaster);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to get recmaster from node %u\n", pnn));
-		return;
-	}
-
 	/* If we are not the recmaster then do some housekeeping */
 	if (rec->recmaster != pnn) {
 		/* Ignore any IP reallocate requests - only recmaster
@@ -3478,80 +3517,23 @@ static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec,
 		TALLOC_FREE(rec->force_rebalance_nodes);
 	}
 
-	/* This is a special case.  When recovery daemon is started, recmaster
-	 * is set to -1.  If a node is not started in stopped state, then
-	 * start election to decide recovery master
-	 */
-	if (rec->recmaster == (uint32_t)-1) {
-		DEBUG(DEBUG_NOTICE,(__location__ " Initial recovery master set - forcing election\n"));
-		force_election(rec, pnn, nodemap);
-		return;
-	}
-
-	/* update the capabilities for all nodes */
+	/* Retrieve capabilities from all connected nodes */
 	ret = update_capabilities(rec, nodemap);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR, (__location__ " Unable to update node capabilities.\n"));
 		return;
 	}
 
-	/*
-	 * If the current recmaster does not have CTDB_CAP_RECMASTER,
-	 * but we have, then force an election and try to become the new
-	 * recmaster.
-	 */
-	if (!ctdb_node_has_capabilities(rec->caps,
-					rec->recmaster,
-					CTDB_CAP_RECMASTER) &&
-	    (rec->ctdb->capabilities & CTDB_CAP_RECMASTER) &&
-	    !(nodemap->nodes[pnn].flags & NODE_FLAGS_INACTIVE)) {
-		DEBUG(DEBUG_ERR, (__location__ " Current recmaster node %u does not have CAP_RECMASTER,"
-				  " but we (node %u) have - force an election\n",
-				  rec->recmaster, pnn));
-		force_election(rec, pnn, nodemap);
-		return;
-	}
-
-	/* verify that the recmaster node is still active */
-	for (j=0; j<nodemap->num; j++) {
-		if (nodemap->nodes[j].pnn==rec->recmaster) {
-			break;
-		}
-	}
-
-	if (j == nodemap->num) {
-		DEBUG(DEBUG_ERR, ("Recmaster node %u not in list. Force reelection\n", rec->recmaster));
-		force_election(rec, pnn, nodemap);
+	switch (validate_recovery_master(rec, mem_ctx)) {
+	case MONITOR_RECOVERY_NEEDED:
+		/* can not happen */
 		return;
-	}
-
-	/* if recovery master is disconnected we must elect a new recmaster */
-	if (nodemap->nodes[j].flags & NODE_FLAGS_DISCONNECTED) {
-		DEBUG(DEBUG_NOTICE, ("Recmaster node %u is disconnected. Force reelection\n", nodemap->nodes[j].pnn));
+	case MONITOR_ELECTION_NEEDED:
 		force_election(rec, pnn, nodemap);
 		return;
-	}
-
-	/* get nodemap from the recovery master to check if it is inactive */
-	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, 
-				   mem_ctx, &recmaster_nodemap);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, (__location__ " Unable to get nodemap from recovery master %u\n", 
-			  nodemap->nodes[j].pnn));
-		return;
-	}
-
-
-	if ((recmaster_nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) &&
-	    (rec->node_flags & NODE_FLAGS_INACTIVE) == 0) {
-		DEBUG(DEBUG_NOTICE, ("Recmaster node %u no longer available. Force reelection\n", nodemap->nodes[j].pnn));
-		/*
-		 * update our nodemap to carry the recmaster's notion of
-		 * its own flags, so that we don't keep freezing the
-		 * inactive recmaster node...
-		 */
-		nodemap->nodes[j].flags = recmaster_nodemap->nodes[j].flags;
-		force_election(rec, pnn, nodemap);
+	case MONITOR_OK:
+		break;
+	case MONITOR_FAILED:
 		return;
 	}
 
@@ -3607,6 +3589,13 @@ static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec,
 	}
 
 
+	/* get the vnnmap */
+	ret = ctdb_ctrl_getvnnmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, &vnnmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get vnnmap from node %u\n", pnn));
+		return;
+	}
+
 	if (rec->need_recovery) {
 		/* a previous recovery didn't finish */
 		do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
@@ -3656,7 +3645,7 @@ static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec,
 
 	/* get the nodemap for all active remote nodes
 	 */
-	remote_nodemaps = talloc_array(mem_ctx, struct ctdb_node_map *, nodemap->num);
+	remote_nodemaps = talloc_array(mem_ctx, struct ctdb_node_map_old *, nodemap->num);
 	if (remote_nodemaps == NULL) {
 		DEBUG(DEBUG_ERR, (__location__ " failed to allocate remote nodemap array\n"));
 		return;
@@ -3862,56 +3851,12 @@ static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec,
 
 	/* we might need to change who has what IP assigned */
 	if (rec->need_takeover_run) {
-		uint32_t culprit = (uint32_t)-1;
-
-		rec->need_takeover_run = false;
-
-		/* update the list of public ips that a node can handle for
-		   all connected nodes
-		*/
-		ret = ctdb_reload_remote_public_ips(ctdb, rec, nodemap, &culprit);
-		if (ret != 0) {
-			DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
-					 culprit));
-			rec->need_takeover_run = true;
-			return;
-		}
-
-		/* execute the "startrecovery" event script on all nodes */
-		ret = run_startrecovery_eventscript(rec, nodemap);
-		if (ret!=0) {
-			DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'startrecovery' event on cluster\n"));
-			ctdb_set_culprit(rec, ctdb->pnn);
-			do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
-			return;
-		}
-
 		/* If takeover run fails, then the offending nodes are
 		 * assigned ban culprit counts. And we re-try takeover.
 		 * If takeover run fails repeatedly, the node would get
 		 * banned.
-		 *
-		 * If rec->need_takeover_run is not set to true at this
-		 * failure, monitoring is disabled cluster-wide (via
-		 * startrecovery eventscript) and will not get enabled.
 		 */
-		if (!do_takeover_run(rec, nodemap, true)) {
-			return;
-		}
-
-		/* execute the "recovered" event script on all nodes */
-		ret = run_recovered_eventscript(rec, nodemap, "monitor_cluster");
-#if 0
-// we cant check whether the event completed successfully
-// since this script WILL fail if the node is in recovery mode
-// and if that race happens, the code here would just cause a second
-// cascading recovery.
-		if (ret!=0) {
-			DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'recovered' event on cluster. Update of public ips failed.\n"));
-			ctdb_set_culprit(rec, ctdb->pnn);
-			do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
-		}
-#endif
+		do_takeover_run(rec, nodemap, true);
 	}
 }
 
@@ -3928,6 +3873,7 @@ static void monitor_cluster(struct ctdb_context *ctdb)
 	CTDB_NO_MEMORY_FATAL(ctdb, rec);
 
 	rec->ctdb = ctdb;
+	rec->recmaster = CTDB_UNKNOWN_PNN;
 
 	rec->takeover_run = ctdb_op_init(rec, "takeover runs");
 	CTDB_NO_MEMORY_FATAL(ctdb, rec->takeover_run);
@@ -3941,7 +3887,7 @@ static void monitor_cluster(struct ctdb_context *ctdb)
 	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_MEM_DUMP, mem_dump_handler, rec);
 
 	/* register a message port for recovery elections */
-	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_RECOVERY, election_handler, rec);
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_ELECTION, election_handler, rec);
 
 	/* when nodes are disabled/enabled */
 	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_SET_NODE_FLAGS, monitor_handler, rec);
@@ -4010,7 +3956,8 @@ static void monitor_cluster(struct ctdb_context *ctdb)
 /*
   event handler for when the main ctdbd dies
  */
-static void ctdb_recoverd_parent(struct event_context *ev, struct fd_event *fde, 
+static void ctdb_recoverd_parent(struct tevent_context *ev,
+				 struct tevent_fd *fde,
 				 uint16_t flags, void *private_data)
 {
 	DEBUG(DEBUG_ALERT,("recovery daemon parent died - exiting\n"));
@@ -4020,29 +3967,30 @@ static void ctdb_recoverd_parent(struct event_context *ev, struct fd_event *fde,
 /*
   called regularly to verify that the recovery daemon is still running
  */
-static void ctdb_check_recd(struct event_context *ev, struct timed_event *te, 
-			      struct timeval yt, void *p)
+static void ctdb_check_recd(struct tevent_context *ev,
+			    struct tevent_timer *te,
+			    struct timeval yt, void *p)
 {
 	struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
 
 	if (ctdb_kill(ctdb, ctdb->recoverd_pid, 0) != 0) {
 		DEBUG(DEBUG_ERR,("Recovery daemon (pid:%d) is no longer running. Trying to restart recovery daemon.\n", (int)ctdb->recoverd_pid));
 
-		event_add_timed(ctdb->ev, ctdb, timeval_zero(), 
-				ctdb_restart_recd, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb, timeval_zero(),
+				 ctdb_restart_recd, ctdb);
 
 		return;
 	}
 
-	event_add_timed(ctdb->ev, ctdb->recd_ctx,
-			timeval_current_ofs(30, 0),
-			ctdb_check_recd, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb->recd_ctx,
+			 timeval_current_ofs(30, 0),
+			 ctdb_check_recd, ctdb);
 }
 
-static void recd_sig_child_handler(struct event_context *ev,
-	struct signal_event *se, int signum, int count,
-	void *dont_care, 
-	void *private_data)
+static void recd_sig_child_handler(struct tevent_context *ev,
+				   struct tevent_signal *se, int signum,
+				   int count, void *dont_care,
+				   void *private_data)
 {
 //	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
 	int status;
@@ -4068,7 +4016,7 @@ static void recd_sig_child_handler(struct event_context *ev,
 int ctdb_start_recoverd(struct ctdb_context *ctdb)
 {
 	int fd[2];
-	struct signal_event *se;
+	struct tevent_signal *se;
 	struct tevent_fd *fde;
 
 	if (pipe(fd) != 0) {
@@ -4086,9 +4034,9 @@ int ctdb_start_recoverd(struct ctdb_context *ctdb)
 		CTDB_NO_MEMORY(ctdb, ctdb->recd_ctx);
 
 		close(fd[0]);
-		event_add_timed(ctdb->ev, ctdb->recd_ctx,
-				timeval_current_ofs(30, 0),
-				ctdb_check_recd, ctdb);
+		tevent_add_timer(ctdb->ev, ctdb->recd_ctx,
+				 timeval_current_ofs(30, 0),
+				 ctdb_check_recd, ctdb);
 		return 0;
 	}
 
@@ -4096,7 +4044,7 @@ int ctdb_start_recoverd(struct ctdb_context *ctdb)
 
 	srandom(getpid() ^ time(NULL));
 
-	ctdb_set_process_name("ctdb_recovered");
+	prctl_set_comment("ctdb_recovered");
 	if (switch_from_server_to_client(ctdb, "recoverd") != 0) {
 		DEBUG(DEBUG_CRIT, (__location__ "ERROR: failed to switch recovery daemon into client mode. shutting down.\n"));
 		exit(1);
@@ -4104,15 +4052,13 @@ int ctdb_start_recoverd(struct ctdb_context *ctdb)
 
 	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d to recovery daemon\n", fd[0]));
 
-	fde = event_add_fd(ctdb->ev, ctdb, fd[0], EVENT_FD_READ,
-		     ctdb_recoverd_parent, &fd[0]);
+	fde = tevent_add_fd(ctdb->ev, ctdb, fd[0], TEVENT_FD_READ,
+			    ctdb_recoverd_parent, &fd[0]);
 	tevent_fd_set_auto_close(fde);
 
 	/* set up a handler to pick up sigchld */
-	se = event_add_signal(ctdb->ev, ctdb,
-				     SIGCHLD, 0,
-				     recd_sig_child_handler,
-				     ctdb);
+	se = tevent_add_signal(ctdb->ev, ctdb, SIGCHLD, 0,
+			       recd_sig_child_handler, ctdb);
 	if (se == NULL) {
 		DEBUG(DEBUG_CRIT,("Failed to set up signal handler for SIGCHLD in recovery daemon\n"));
 		exit(1);
@@ -4140,8 +4086,9 @@ void ctdb_stop_recoverd(struct ctdb_context *ctdb)
 	TALLOC_FREE(ctdb->recd_ping_count);
 }
 
-static void ctdb_restart_recd(struct event_context *ev, struct timed_event *te, 
-		       struct timeval t, void *private_data)
+static void ctdb_restart_recd(struct tevent_context *ev,
+			      struct tevent_timer *te,
+			      struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
 
diff --git a/ctdb/server/ctdb_recovery_helper.c b/ctdb/server/ctdb_recovery_helper.c
new file mode 100644
index 0000000..6d6a835
--- /dev/null
+++ b/ctdb/server/ctdb_recovery_helper.c
@@ -0,0 +1,1888 @@
+/*
+   ctdb parallel database recovery
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+#include <libgen.h>
+
+#include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/time.h"
+#include "lib/util/tevent_unix.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+#include "client/client.h"
+
+#define TIMEOUT()	timeval_current_ofs(10, 0)
+
+static void LOG(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * Utility functions
+ */
+
+static ssize_t sys_write(int fd, const void *buf, size_t count)
+{
+        ssize_t ret;
+
+        do {
+                ret = write(fd, buf, count);
+#if defined(EWOULDBLOCK)
+        } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+#else
+        } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+#endif
+        return ret;
+}
+
+/*
+ * Recovery database functions
+ */
+
+struct recdb_context {
+	uint32_t db_id;
+	const char *db_name;
+	const char *db_path;
+	struct tdb_wrap *db;
+	bool persistent;
+};
+
+static struct recdb_context *recdb_create(TALLOC_CTX *mem_ctx, uint32_t db_id,
+					  const char *db_name,
+					  const char *db_path,
+					  uint32_t hash_size, bool persistent)
+{
+	struct recdb_context *recdb;
+	unsigned int tdb_flags;
+
+	recdb = talloc(mem_ctx, struct recdb_context);
+	if (recdb == NULL) {
+		return NULL;
+	}
+
+	recdb->db_name = db_name;
+	recdb->db_id = db_id;
+	recdb->db_path = talloc_asprintf(recdb, "%s/recdb.%s",
+					 dirname(discard_const(db_path)),
+					 db_name);
+	if (recdb->db_path == NULL) {
+		talloc_free(recdb);
+		return NULL;
+	}
+	unlink(recdb->db_path);
+
+	tdb_flags = TDB_NOLOCK | TDB_INCOMPATIBLE_HASH | TDB_DISALLOW_NESTING;
+	recdb->db = tdb_wrap_open(mem_ctx, recdb->db_path, hash_size,
+				  tdb_flags, O_RDWR|O_CREAT|O_EXCL, 0600);
+	if (recdb->db == NULL) {
+		talloc_free(recdb);
+		LOG("failed to create recovery db %s\n", recdb->db_path);
+	}
+
+	recdb->persistent = persistent;
+
+	return recdb;
+}
+
+static const char *recdb_name(struct recdb_context *recdb)
+{
+	return recdb->db_name;
+}
+
+struct recdb_add_traverse_state {
+	struct recdb_context *recdb;
+	int mypnn;
+};
+
+static int recdb_add_traverse(uint32_t reqid, struct ctdb_ltdb_header *header,
+			      TDB_DATA key, TDB_DATA data,
+			      void *private_data)
+{
+	struct recdb_add_traverse_state *state =
+		(struct recdb_add_traverse_state *)private_data;
+	struct ctdb_ltdb_header *hdr;
+	TDB_DATA prev_data;
+	int ret;
+
+	/* header is not marshalled separately in the pulldb control */
+	if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
+		return -1;
+	}
+
+	hdr = (struct ctdb_ltdb_header *)data.dptr;
+
+	/* fetch the existing record, if any */
+	prev_data = tdb_fetch(state->recdb->db->tdb, key);
+
+	if (prev_data.dptr != NULL) {
+		struct ctdb_ltdb_header prev_hdr;
+
+		prev_hdr = *(struct ctdb_ltdb_header *)prev_data.dptr;
+		free(prev_data.dptr);
+		if (hdr->rsn < prev_hdr.rsn ||
+		    (hdr->rsn == prev_hdr.rsn &&
+		     prev_hdr.dmaster != state->mypnn)) {
+			return 0;
+		}
+	}
+
+	ret = tdb_store(state->recdb->db->tdb, key, data, TDB_REPLACE);
+	if (ret != 0) {
+		return -1;
+	}
+	return 0;
+}
+
+static bool recdb_add(struct recdb_context *recdb, int mypnn,
+		      struct ctdb_rec_buffer *recbuf)
+{
+	struct recdb_add_traverse_state state;
+	int ret;
+
+	state.recdb = recdb;
+	state.mypnn = mypnn;
+
+	ret = ctdb_rec_buffer_traverse(recbuf, recdb_add_traverse, &state);
+	if (ret != 0) {
+		return false;
+	}
+
+	return true;
+}
+
+struct recdb_traverse_state {
+	struct ctdb_rec_buffer *recbuf;
+	uint32_t pnn;
+	uint32_t reqid;
+	bool persistent;
+	bool failed;
+};
+
+static int recdb_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+			  void *private_data)
+{
+	struct recdb_traverse_state *state =
+		(struct recdb_traverse_state *)private_data;
+	struct ctdb_ltdb_header *header;
+	int ret;
+
+	/*
+	 * skip empty records - but NOT for persistent databases:
+	 *
+	 * The record-by-record mode of recovery deletes empty records.
+	 * For persistent databases, this can lead to data corruption
+	 * by deleting records that should be there:
+	 *
+	 * - Assume the cluster has been running for a while.
+	 *
+	 * - A record R in a persistent database has been created and
+	 *   deleted a couple of times, the last operation being deletion,
+	 *   leaving an empty record with a high RSN, say 10.
+	 *
+	 * - Now a node N is turned off.
+	 *
+	 * - This leaves the local database copy of D on N with the empty
+	 *   copy of R and RSN 10. On all other nodes, the recovery has deleted
+	 *   the copy of record R.
+	 *
+	 * - Now the record is created again while node N is turned off.
+	 *   This creates R with RSN = 1 on all nodes except for N.
+	 *
+	 * - Now node N is turned on again. The following recovery will chose
+	 *   the older empty copy of R due to RSN 10 > RSN 1.
+	 *
+	 * ==> Hence the record is gone after the recovery.
+	 *
+	 * On databases like Samba's registry, this can damage the higher-level
+	 * data structures built from the various tdb-level records.
+	 */
+	if (!state->persistent &&
+	    data.dsize <= sizeof(struct ctdb_ltdb_header)) {
+		return 0;
+	}
+
+	/* update the dmaster field to point to us */
+	header = (struct ctdb_ltdb_header *)data.dptr;
+	if (!state->persistent) {
+		header->dmaster = state->pnn;
+		header->flags |= CTDB_REC_FLAG_MIGRATED_WITH_DATA;
+	}
+
+	ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, state->reqid,
+				  NULL, key, data);
+	if (ret != 0) {
+		state->failed = true;
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct ctdb_rec_buffer *recdb_records(struct recdb_context *recdb,
+					     TALLOC_CTX *mem_ctx, uint32_t pnn)
+{
+	struct recdb_traverse_state state;
+	int ret;
+
+	state.recbuf = ctdb_rec_buffer_init(mem_ctx, recdb->db_id);
+	if (state.recbuf == NULL) {
+		return NULL;
+	}
+	state.pnn = pnn;
+	state.reqid = 0;
+	state.persistent = recdb->persistent;
+	state.failed = false;
+
+	ret = tdb_traverse_read(recdb->db->tdb, recdb_traverse, &state);
+	if (ret == -1 || state.failed) {
+		TALLOC_FREE(state.recbuf);
+		return NULL;
+	}
+
+	return state.recbuf;
+}
+
+/*
+ * Collect databases using highest sequence number
+ */
+
+struct collect_highseqnum_db_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	uint32_t *pnn_list;
+	int count;
+	uint32_t db_id;
+	struct recdb_context *recdb;
+	uint32_t max_pnn;
+};
+
+static void collect_highseqnum_db_seqnum_done(struct tevent_req *subreq);
+static void collect_highseqnum_db_pulldb_done(struct tevent_req *subreq);
+
+static struct tevent_req *collect_highseqnum_db_send(
+			TALLOC_CTX *mem_ctx,
+			struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			uint32_t *pnn_list, int count,
+			uint32_t db_id, struct recdb_context *recdb)
+{
+	struct tevent_req *req, *subreq;
+	struct collect_highseqnum_db_state *state;
+	struct ctdb_req_control request;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct collect_highseqnum_db_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->client = client;
+	state->pnn_list = pnn_list;
+	state->count = count;
+	state->db_id = db_id;
+	state->recdb = recdb;
+
+	ctdb_req_control_get_db_seqnum(&request, db_id);
+	subreq = ctdb_client_control_multi_send(mem_ctx, ev, client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, collect_highseqnum_db_seqnum_done,
+				req);
+
+	return req;
+}
+
+static void collect_highseqnum_db_seqnum_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct collect_highseqnum_db_state *state = tevent_req_data(
+		req, struct collect_highseqnum_db_state);
+	struct ctdb_reply_control **reply;
+	struct ctdb_req_control request;
+	struct ctdb_pulldb pulldb;
+	int *err_list;
+	bool status;
+	int ret, i;
+	uint64_t seqnum, max_seqnum;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, state,
+						&err_list, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count, err_list,
+						       &pnn);
+		if (ret2 != 0) {
+			LOG("control GET_DB_SEQNUM failed for %s on node %u,"
+			    " ret=%d\n", recdb_name(state->recdb), pnn, ret2);
+		} else {
+			LOG("control GET_DB_SEQNUM failed for %s, ret=%d\n",
+			    recdb_name(state->recdb), ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	max_seqnum = 0;
+	state->max_pnn = state->pnn_list[0];
+	for (i=0; i<state->count; i++) {
+		ret = ctdb_reply_control_get_db_seqnum(reply[i], &seqnum);
+		if (ret != 0) {
+			tevent_req_error(req, EPROTO);
+			return;
+		}
+
+		if (max_seqnum < seqnum) {
+			max_seqnum = seqnum;
+			state->max_pnn = state->pnn_list[i];
+		}
+	}
+
+	talloc_free(reply);
+
+	LOG("Pull persistent db %s from node %d with seqnum 0x%"PRIx64"\n",
+	    recdb_name(state->recdb), state->max_pnn, max_seqnum);
+
+	pulldb.db_id = state->db_id;
+	pulldb.lmaster = CTDB_LMASTER_ANY;
+
+	ctdb_req_control_pull_db(&request, &pulldb);
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->max_pnn, TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, collect_highseqnum_db_pulldb_done,
+				req);
+}
+
+static void collect_highseqnum_db_pulldb_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct collect_highseqnum_db_state *state = tevent_req_data(
+		req, struct collect_highseqnum_db_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_rec_buffer *recbuf;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		LOG("control PULL_DB failed for %s on node %u, ret=%d\n",
+		    recdb_name(state->recdb), state->max_pnn, ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_pull_db(reply, state, &recbuf);
+	if (ret != 0) {
+		tevent_req_error(req, EPROTO);
+		return;
+	}
+
+	talloc_free(reply);
+
+	ret = recdb_add(state->recdb, ctdb_client_pnn(state->client), recbuf);
+	talloc_free(recbuf);
+	if (! ret) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+static bool collect_highseqnum_db_recv(struct tevent_req *req, int *perr)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * Collect all databases
+ */
+
+struct collect_all_db_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	uint32_t *pnn_list;
+	int count;
+	uint32_t db_id;
+	struct recdb_context *recdb;
+	struct ctdb_pulldb pulldb;
+	int index;
+};
+
+static void collect_all_db_pulldb_done(struct tevent_req *subreq);
+
+static struct tevent_req *collect_all_db_send(
+			TALLOC_CTX *mem_ctx,
+			struct tevent_context *ev,
+			struct ctdb_client_context *client,
+			uint32_t *pnn_list, int count,
+			uint32_t db_id, struct recdb_context *recdb)
+{
+	struct tevent_req *req, *subreq;
+	struct collect_all_db_state *state;
+	struct ctdb_req_control request;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct collect_all_db_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->client = client;
+	state->pnn_list = pnn_list;
+	state->count = count;
+	state->db_id = db_id;
+	state->recdb = recdb;
+
+	state->pulldb.db_id = db_id;
+	state->pulldb.lmaster = CTDB_LMASTER_ANY;
+
+	state->index = 0;
+
+	ctdb_req_control_pull_db(&request, &state->pulldb);
+	subreq = ctdb_client_control_send(state, ev, client,
+					  state->pnn_list[state->index],
+					  TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, collect_all_db_pulldb_done, req);
+
+	return req;
+}
+
+static void collect_all_db_pulldb_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct collect_all_db_state *state = tevent_req_data(
+		req, struct collect_all_db_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_req_control request;
+	struct ctdb_rec_buffer *recbuf;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		LOG("control PULL_DB failed for %s from node %u, ret=%d\n",
+		    recdb_name(state->recdb), state->pnn_list[state->index],
+		    ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_pull_db(reply, state, &recbuf);
+	if (ret != 0) {
+		LOG("control PULL_DB failed for %s, ret=%d\n",
+		    recdb_name(state->recdb), ret);
+		tevent_req_error(req, EPROTO);
+		return;
+	}
+
+	talloc_free(reply);
+
+	status = recdb_add(state->recdb, ctdb_client_pnn(state->client), recbuf);
+	talloc_free(recbuf);
+	if (! status) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	state->index += 1;
+	if (state->index == state->count) {
+		tevent_req_done(req);
+		return;
+	}
+
+	ctdb_req_control_pull_db(&request, &state->pulldb);
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->pnn_list[state->index],
+					  TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, collect_all_db_pulldb_done, req);
+}
+
+static bool collect_all_db_recv(struct tevent_req *req, int *perr)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+
+/**
+ * For each database do the following:
+ *  - Get DB name
+ *  - Get DB path
+ *  - Freeze database on all nodes
+ *  - Start transaction on all nodes
+ *  - Collect database from all nodes
+ *  - Wipe database on all nodes
+ *  - Push database to all nodes
+ *  - Commit transaction on all nodes
+ *  - Thaw database on all nodes
+ */
+
+struct recover_db_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	struct ctdb_tunable_list *tun_list;
+	uint32_t *pnn_list;
+	int count;
+	uint32_t db_id;
+	bool persistent;
+
+	uint32_t destnode;
+	struct ctdb_transdb transdb;
+
+	const char *db_name, *db_path;
+	struct recdb_context *recdb;
+	struct ctdb_rec_buffer *recbuf;
+
+};
+
+static void recover_db_name_done(struct tevent_req *subreq);
+static void recover_db_path_done(struct tevent_req *subreq);
+static void recover_db_freeze_done(struct tevent_req *subreq);
+static void recover_db_transaction_started(struct tevent_req *subreq);
+static void recover_db_collect_done(struct tevent_req *subreq);
+static void recover_db_wipedb_done(struct tevent_req *subreq);
+static void recover_db_pushdb_done(struct tevent_req *subreq);
+static void recover_db_transaction_committed(struct tevent_req *subreq);
+static void recover_db_thaw_done(struct tevent_req *subreq);
+
+static struct tevent_req *recover_db_send(TALLOC_CTX *mem_ctx,
+					  struct tevent_context *ev,
+					  struct ctdb_client_context *client,
+					  struct ctdb_tunable_list *tun_list,
+					  uint32_t *pnn_list, int count,
+					  uint32_t generation,
+					  uint32_t db_id, bool persistent)
+{
+	struct tevent_req *req, *subreq;
+	struct recover_db_state *state;
+	struct ctdb_req_control request;
+
+	req = tevent_req_create(mem_ctx, &state, struct recover_db_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->client = client;
+	state->tun_list = tun_list;
+	state->pnn_list = pnn_list;
+	state->count = count;
+	state->db_id = db_id;
+	state->persistent = persistent;
+
+	state->destnode = ctdb_client_pnn(client);
+	state->transdb.db_id = db_id;
+	state->transdb.tid = generation;
+
+	ctdb_req_control_get_dbname(&request, db_id);
+	subreq = ctdb_client_control_send(state, ev, client, state->destnode,
+					  TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, recover_db_name_done, req);
+
+	return req;
+}
+
+static void recover_db_name_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recover_db_state *state = tevent_req_data(
+		req, struct recover_db_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_req_control request;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		LOG("control GET_DBNAME failed for db=0x%x\n, ret=%d",
+		    state->db_id, ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_get_dbname(reply, state, &state->db_name);
+	if (ret != 0) {
+		LOG("control GET_DBNAME failed for db=0x%x\n, ret=%d\n",
+		    state->db_id, ret);
+		tevent_req_error(req, EPROTO);
+		return;
+	}
+
+	talloc_free(reply);
+
+	ctdb_req_control_getdbpath(&request, state->db_id);
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->destnode, TIMEOUT(),
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recover_db_path_done, req);
+}
+
+static void recover_db_path_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recover_db_state *state = tevent_req_data(
+		req, struct recover_db_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_req_control request;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		LOG("control GETDBPATH failed for db %s, ret=%d\n",
+		    state->db_name, ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_getdbpath(reply, state, &state->db_path);
+	if (ret != 0) {
+		LOG("control GETDBPATH failed for db %s, ret=%d\n",
+		    state->db_name, ret);
+		tevent_req_error(req, EPROTO);
+		return;
+	}
+
+	talloc_free(reply);
+
+	ctdb_req_control_db_freeze(&request, state->db_id);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recover_db_freeze_done, req);
+}
+
+static void recover_db_freeze_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recover_db_state *state = tevent_req_data(
+		req, struct recover_db_state);
+	struct ctdb_req_control request;
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count, err_list,
+						       &pnn);
+		if (ret2 != 0) {
+			LOG("control FREEZE_DB failed for db %s on node %u,"
+			    " ret=%d\n", state->db_name, pnn, ret2);
+		} else {
+			LOG("control FREEZE_DB failed for db %s, ret=%d\n",
+			    state->db_name, ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_req_control_db_transaction_start(&request, &state->transdb);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recover_db_transaction_started, req);
+}
+
+static void recover_db_transaction_started(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recover_db_state *state = tevent_req_data(
+		req, struct recover_db_state);
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("control TRANSACTION_DB failed for db=%s,"
+			    " ret=%d\n", state->db_name, pnn, ret2);
+		} else {
+			LOG("control TRANSACTION_DB failed for db=%s,"
+			    " ret=%d\n", state->db_name, ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	state->recdb = recdb_create(state, state->db_id, state->db_name,
+				    state->db_path,
+				    state->tun_list->database_hash_size,
+				    state->persistent);
+	if (tevent_req_nomem(state->recdb, req)) {
+		return;
+	}
+
+	if (state->persistent && state->tun_list->recover_pdb_by_seqnum != 0) {
+		subreq = collect_highseqnum_db_send(
+				state, state->ev, state->client,
+				state->pnn_list, state->count,
+				state->db_id, state->recdb);
+	} else {
+		subreq = collect_all_db_send(
+				state, state->ev, state->client,
+				state->pnn_list, state->count,
+				state->db_id, state->recdb);
+	}
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recover_db_collect_done, req);
+}
+
+static void recover_db_collect_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recover_db_state *state = tevent_req_data(
+		req, struct recover_db_state);
+	struct ctdb_req_control request;
+	int ret;
+	bool status;
+
+	if (state->persistent && state->tun_list->recover_pdb_by_seqnum != 0) {
+		status = collect_highseqnum_db_recv(subreq, &ret);
+	} else {
+		status = collect_all_db_recv(subreq, &ret);
+	}
+	TALLOC_FREE(subreq);
+	if (! status) {
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_req_control_wipe_database(&request, &state->transdb);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recover_db_wipedb_done, req);
+}
+
+static void recover_db_wipedb_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recover_db_state *state = tevent_req_data(
+		req, struct recover_db_state);
+	struct ctdb_req_control request;
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("control WIPEDB failed for db %s on node %u,"
+			    " ret=%d\n", state->db_name, pnn, ret2);
+		} else {
+			LOG("control WIPEDB failed for db %s, ret=%d\n",
+			    state->db_name, pnn, ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	state->recbuf = recdb_records(state->recdb, state, state->destnode);
+	if (tevent_req_nomem(state->recbuf, req)) {
+		return;
+	}
+
+	TALLOC_FREE(state->recdb);
+
+	ctdb_req_control_push_db(&request, state->recbuf);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recover_db_pushdb_done, req);
+}
+
+static void recover_db_pushdb_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recover_db_state *state = tevent_req_data(
+		req, struct recover_db_state);
+	struct ctdb_req_control request;
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("control PUSHDB failed for db %s on node %u,"
+			    " ret=%d\n", state->db_name, pnn, ret2);
+		} else {
+			LOG("control PUSHDB failed for db %s, ret=%d\n",
+			    state->db_name, ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	TALLOC_FREE(state->recbuf);
+
+	ctdb_req_control_db_transaction_commit(&request, &state->transdb);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recover_db_transaction_committed, req);
+}
+
+static void recover_db_transaction_committed(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recover_db_state *state = tevent_req_data(
+		req, struct recover_db_state);
+	struct ctdb_req_control request;
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("control DB_TRANSACTION_COMMIT failed for db %s"
+			    " on node %u, ret=%d", state->db_name, pnn, ret2);
+		} else {
+			LOG("control DB_TRANSACTION_COMMIT failed for db %s\n,"
+			    " ret=%d", state->db_name, ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_req_control_db_thaw(&request, state->db_id);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recover_db_thaw_done, req);
+}
+
+static void recover_db_thaw_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recover_db_state *state = tevent_req_data(
+		req, struct recover_db_state);
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("control DB_THAW failed for db %s on node %u,"
+			    " ret=%d\n", state->db_name, pnn, ret2);
+		} else {
+			LOG("control DB_THAW failed for db %s, ret=%d\n",
+			    state->db_name, ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+static bool recover_db_recv(struct tevent_req *req)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		return false;
+	}
+
+	return true;
+}
+
+
+/*
+ * Start database recovery for each database
+ *
+ * Try to recover each database 5 times before failing recovery.
+ */
+
+struct db_recovery_state {
+	struct tevent_context *ev;
+	struct ctdb_dbid_map *dbmap;
+	int num_replies;
+	int num_failed;
+};
+
+struct db_recovery_one_state {
+	struct tevent_req *req;
+	struct ctdb_client_context *client;
+	struct ctdb_dbid_map *dbmap;
+	struct ctdb_tunable_list *tun_list;
+	uint32_t *pnn_list;
+	int count;
+	uint32_t generation;
+	uint32_t db_id;
+	bool persistent;
+	int num_fails;
+};
+
+static void db_recovery_one_done(struct tevent_req *subreq);
+
+static struct tevent_req *db_recovery_send(TALLOC_CTX *mem_ctx,
+					   struct tevent_context *ev,
+					   struct ctdb_client_context *client,
+					   struct ctdb_dbid_map *dbmap,
+					   struct ctdb_tunable_list *tun_list,
+					   uint32_t *pnn_list, int count,
+					   uint32_t generation)
+{
+	struct tevent_req *req, *subreq;
+	struct db_recovery_state *state;
+	int i;
+
+	req = tevent_req_create(mem_ctx, &state, struct db_recovery_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->dbmap = dbmap;
+	state->num_replies = 0;
+	state->num_failed = 0;
+
+	if (dbmap->num == 0) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	for (i=0; i<dbmap->num; i++) {
+		struct db_recovery_one_state *substate;
+
+		substate = talloc_zero(state, struct db_recovery_one_state);
+		if (tevent_req_nomem(substate, req)) {
+			return tevent_req_post(req, ev);
+		}
+
+		substate->req = req;
+		substate->client = client;
+		substate->dbmap = dbmap;
+		substate->tun_list = tun_list;
+		substate->pnn_list = pnn_list;
+		substate->count = count;
+		substate->generation = generation;
+		substate->db_id = dbmap->dbs[i].db_id;
+		substate->persistent = dbmap->dbs[i].flags &
+				       CTDB_DB_FLAGS_PERSISTENT;
+
+		subreq = recover_db_send(state, ev, client, tun_list,
+					 pnn_list, count, generation,
+					 substate->db_id,
+					 substate->persistent);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(subreq, db_recovery_one_done,
+					substate);
+		LOG("recover database 0x%08x\n", substate->db_id);
+	}
+
+	return req;
+}
+
+static void db_recovery_one_done(struct tevent_req *subreq)
+{
+	struct db_recovery_one_state *substate = tevent_req_callback_data(
+		subreq, struct db_recovery_one_state);
+	struct tevent_req *req = substate->req;
+	struct db_recovery_state *state = tevent_req_data(
+		req, struct db_recovery_state);
+	bool status;
+
+	status = recover_db_recv(subreq);
+	TALLOC_FREE(subreq);
+
+	if (status) {
+		talloc_free(substate);
+		goto done;
+	}
+
+	substate->num_fails += 1;
+	if (substate->num_fails < 5) {
+		subreq = recover_db_send(state, state->ev, substate->client,
+					 substate->tun_list,
+					 substate->pnn_list, substate->count,
+					 substate->generation, substate->db_id,
+					 substate->persistent);
+		if (tevent_req_nomem(subreq, req)) {
+			goto failed;
+		}
+		tevent_req_set_callback(subreq, db_recovery_one_done, substate);
+		LOG("recover database 0x%08x, attempt %d\n", substate->db_id,
+		    substate->num_fails+1);
+		return;
+	}
+
+failed:
+	state->num_failed += 1;
+
+done:
+	state->num_replies += 1;
+
+	if (state->num_replies == state->dbmap->num) {
+		tevent_req_done(req);
+	}
+}
+
+static bool db_recovery_recv(struct tevent_req *req, int *count)
+{
+	struct db_recovery_state *state = tevent_req_data(
+		req, struct db_recovery_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		*count = 0;
+		return false;
+	}
+
+	*count = state->num_replies - state->num_failed;
+
+	if (state->num_failed > 0) {
+		return false;
+	}
+
+	return true;
+}
+
+
+/*
+ * Run the parallel database recovery
+ *
+ * - Get nodemap
+ * - Get vnnmap
+ * - Get capabilities from all nodes
+ * - Get tunables from all nodes
+ * - Get dbmap
+ * - Set RECOVERY_ACTIVE
+ * - Send START_RECOVERY
+ * - Update vnnmap on all nodes
+ * - Run database recovery
+ * - Send END_RECOVERY
+ * - Set RECOVERY_NORMAL
+ */
+
+struct recovery_state {
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	uint32_t generation;
+	uint32_t *pnn_list;
+	int count;
+	uint32_t destnode;
+	struct ctdb_node_map *nodemap;
+	uint32_t *caps;
+	struct ctdb_tunable_list *tun_list;
+	struct ctdb_vnn_map *vnnmap;
+	struct ctdb_dbid_map *dbmap;
+};
+
+static void recovery_nodemap_done(struct tevent_req *subreq);
+static void recovery_vnnmap_done(struct tevent_req *subreq);
+static void recovery_capabilities_done(struct tevent_req *subreq);
+static void recovery_tunables_done(struct tevent_req *subreq);
+static void recovery_dbmap_done(struct tevent_req *subreq);
+static void recovery_active_done(struct tevent_req *subreq);
+static void recovery_start_recovery_done(struct tevent_req *subreq);
+static void recovery_vnnmap_update_done(struct tevent_req *subreq);
+static void recovery_db_recovery_done(struct tevent_req *subreq);
+static void recovery_normal_done(struct tevent_req *subreq);
+static void recovery_end_recovery_done(struct tevent_req *subreq);
+
+static struct tevent_req *recovery_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct ctdb_client_context *client,
+					uint32_t generation)
+{
+	struct tevent_req *req, *subreq;
+	struct recovery_state *state;
+	struct ctdb_req_control request;
+
+	req = tevent_req_create(mem_ctx, &state, struct recovery_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->client = client;
+	state->generation = generation;
+	state->destnode = ctdb_client_pnn(client);
+
+	ctdb_req_control_get_nodemap(&request);
+	subreq = ctdb_client_control_send(mem_ctx, ev, client, state->destnode,
+					  TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, recovery_nodemap_done, req);
+
+	return req;
+}
+
+static void recovery_nodemap_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_req_control request;
+	bool status;
+	int ret;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		LOG("control GET_NODEMAP failed to node %u, ret=%d\n",
+		    state->destnode, ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_get_nodemap(reply, state, &state->nodemap);
+	if (ret != 0) {
+		LOG("control GET_NODEMAP failed, ret=%d\n", ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	state->count = list_of_active_nodes(state->nodemap, CTDB_UNKNOWN_PNN,
+					    state, &state->pnn_list);
+	if (state->count <= 0) {
+		tevent_req_error(req, ENOMEM);
+		return;
+	}
+
+	ctdb_req_control_getvnnmap(&request);
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->destnode, TIMEOUT(),
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_vnnmap_done, req);
+}
+
+static void recovery_vnnmap_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_req_control request;
+	bool status;
+	int ret;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		LOG("control GETVNNMAP failed to node %u, ret=%d\n",
+		    state->destnode, ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_getvnnmap(reply, state, &state->vnnmap);
+	if (ret != 0) {
+		LOG("control GETVNNMAP failed, ret=%d\n", ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_req_control_get_capabilities(&request);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_capabilities_done, req);
+}
+
+static void recovery_capabilities_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	struct ctdb_reply_control **reply;
+	struct ctdb_req_control request;
+	int *err_list;
+	int ret, i;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, state, &err_list,
+						&reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("control GET_CAPABILITIES failed on node %u,"
+			    " ret=%d\n", pnn, ret2);
+		} else {
+			LOG("control GET_CAPABILITIES failed, ret=%d\n", ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	/* Make the array size same as nodemap */
+	state->caps = talloc_zero_array(state, uint32_t,
+					state->nodemap->num);
+	if (tevent_req_nomem(state->caps, req)) {
+		return;
+	}
+
+	for (i=0; i<state->count; i++) {
+		uint32_t pnn;
+
+		pnn = state->pnn_list[i];
+		ret = ctdb_reply_control_get_capabilities(reply[i],
+							  &state->caps[pnn]);
+		if (ret != 0) {
+			LOG("control GET_CAPABILITIES failed on node %u\n", pnn);
+			tevent_req_error(req, EPROTO);
+			return;
+		}
+	}
+
+	talloc_free(reply);
+
+	ctdb_req_control_get_all_tunables(&request);
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->destnode, TIMEOUT(),
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_tunables_done, req);
+}
+
+static void recovery_tunables_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_req_control request;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		LOG("control GET_ALL_TUNABLES failed, ret=%d\n", ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_get_all_tunables(reply, state,
+						  &state->tun_list);
+	if (ret != 0) {
+		LOG("control GET_ALL_TUNABLES failed, ret=%d\n", ret);
+		tevent_req_error(req, EPROTO);
+		return;
+	}
+
+	talloc_free(reply);
+
+	ctdb_req_control_get_dbmap(&request);
+	subreq = ctdb_client_control_send(state, state->ev, state->client,
+					  state->destnode, TIMEOUT(),
+					  &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_dbmap_done, req);
+}
+
+static void recovery_dbmap_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	struct ctdb_reply_control *reply;
+	struct ctdb_req_control request;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		LOG("control GET_DBMAP failed to node %u, ret=%d\n",
+		    state->destnode, ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ret = ctdb_reply_control_get_dbmap(reply, state, &state->dbmap);
+	if (ret != 0) {
+		LOG("control GET_DBMAP failed, ret=%d\n", ret);
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	ctdb_req_control_set_recmode(&request, CTDB_RECOVERY_ACTIVE);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_active_done, req);
+}
+
+static void recovery_active_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	struct ctdb_req_control request;
+	struct ctdb_vnn_map *vnnmap;
+	int *err_list;
+	int ret, count, i;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("failed to set recovery mode to ACTIVE on node %u,"
+			    " ret=%d\n", pnn, ret2);
+		} else {
+			LOG("failed to set recovery mode to ACTIVE, ret=%d\n",
+			    ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	LOG("set recovery mode to ACTIVE\n");
+
+	/* Calculate new VNNMAP */
+	count = 0;
+	for (i=0; i<state->nodemap->num; i++) {
+		if (state->nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (!(state->caps[i] & CTDB_CAP_LMASTER)) {
+			continue;
+		}
+		count += 1;
+	}
+
+	if (count == 0) {
+		LOG("no active lmasters found. Adding recmaster anyway\n");
+	}
+
+	vnnmap = talloc_zero(state, struct ctdb_vnn_map);
+	if (tevent_req_nomem(vnnmap, req)) {
+		return;
+	}
+
+	vnnmap->size = (count == 0 ? 1 : count);
+	vnnmap->map = talloc_array(vnnmap, uint32_t, vnnmap->size);
+	if (tevent_req_nomem(vnnmap->map, req)) {
+		return;
+	}
+
+	if (count == 0) {
+		vnnmap->map[0] = state->destnode;
+	} else {
+		count = 0;
+		for (i=0; i<state->nodemap->num; i++) {
+			if (state->nodemap->node[i].flags &
+			    NODE_FLAGS_INACTIVE) {
+				continue;
+			}
+			if (!(state->caps[i] & CTDB_CAP_LMASTER)) {
+				continue;
+			}
+
+			vnnmap->map[count] = state->nodemap->node[i].pnn;
+			count += 1;
+		}
+	}
+
+	vnnmap->generation = state->generation;
+
+	talloc_free(state->vnnmap);
+	state->vnnmap = vnnmap;
+
+	ctdb_req_control_start_recovery(&request);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_start_recovery_done, req);
+}
+
+static void recovery_start_recovery_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	struct ctdb_req_control request;
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("failed to run start_recovery event on node %u,"
+			    " ret=%d\n", pnn, ret2);
+		} else {
+			LOG("failed to run start_recovery event, ret=%d\n",
+			    ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	LOG("start_recovery event finished\n");
+
+	ctdb_req_control_setvnnmap(&request, state->vnnmap);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_vnnmap_update_done, req);
+}
+
+static void recovery_vnnmap_update_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("failed to update VNNMAP on node %u, ret=%d\n",
+			    pnn, ret2);
+		} else {
+			LOG("failed to update VNNMAP, ret=%d\n", ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	LOG("updated VNNMAP\n");
+
+	subreq = db_recovery_send(state, state->ev, state->client,
+				  state->dbmap, state->tun_list,
+				  state->pnn_list, state->count,
+				  state->vnnmap->generation);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_db_recovery_done, req);
+}
+
+static void recovery_db_recovery_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	struct ctdb_req_control request;
+	bool status;
+	int count;
+
+	status = db_recovery_recv(subreq, &count);
+	TALLOC_FREE(subreq);
+
+	LOG("%d databases recovered\n", count);
+
+	if (! status) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	ctdb_req_control_set_recmode(&request, CTDB_RECOVERY_NORMAL);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_normal_done, req);
+}
+
+static void recovery_normal_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	struct ctdb_req_control request;
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, state, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("failed to set recovery mode to NORMAL on node %u,"
+			    " ret=%d\n", pnn, ret2);
+		} else {
+			LOG("failed to set recovery mode to NORMAL, ret=%d\n",
+			    ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	LOG("set recovery mode to NORMAL\n");
+
+	ctdb_req_control_end_recovery(&request);
+	subreq = ctdb_client_control_multi_send(state, state->ev,
+						state->client,
+						state->pnn_list, state->count,
+						TIMEOUT(), &request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, recovery_end_recovery_done, req);
+}
+
+static void recovery_end_recovery_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct recovery_state *state = tevent_req_data(
+		req, struct recovery_state);
+	int *err_list;
+	int ret;
+	bool status;
+
+	status = ctdb_client_control_multi_recv(subreq, &ret, state, &err_list,
+						NULL);
+	TALLOC_FREE(subreq);
+	if (! status) {
+		int ret2;
+		uint32_t pnn;
+
+		ret2 = ctdb_client_control_multi_error(state->pnn_list,
+						       state->count,
+						       err_list, &pnn);
+		if (ret2 != 0) {
+			LOG("failed to run recovered event on node %u,"
+			    " ret=%d\n", pnn, ret2);
+		} else {
+			LOG("failed to run recovered event, ret=%d\n", ret);
+		}
+		tevent_req_error(req, ret);
+		return;
+	}
+
+	LOG("recovered event finished\n");
+
+	tevent_req_done(req);
+}
+
+static void recovery_recv(struct tevent_req *req, int *perr)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return;
+	}
+}
+
+static void usage(const char *progname)
+{
+	fprintf(stderr, "\nUsage: %s <log-fd> <output-fd> <ctdb-socket-path> <generation>\n",
+		progname);
+}
+
+
+/*
+ * Arguments - log fd, write fd, socket path, generation
+ */
+int main(int argc, char *argv[])
+{
+	int log_fd, write_fd;
+	const char *sockpath;
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *ev;
+	struct ctdb_client_context *client;
+	int ret;
+	struct tevent_req *req;
+	uint32_t generation;
+
+	if (argc != 5) {
+		usage(argv[0]);
+		exit(1);
+	}
+
+	log_fd = atoi(argv[1]);
+	if (log_fd != STDOUT_FILENO && log_fd != STDERR_FILENO) {
+		close(STDOUT_FILENO);
+		close(STDERR_FILENO);
+		dup2(log_fd, STDOUT_FILENO);
+		dup2(log_fd, STDERR_FILENO);
+	}
+	close(log_fd);
+
+	write_fd = atoi(argv[2]);
+	sockpath = argv[3];
+	generation = (uint32_t)strtoul(argv[4], NULL, 0);
+
+	mem_ctx = talloc_new(NULL);
+	if (mem_ctx == NULL) {
+		LOG("talloc_new() failed\n");
+		goto failed;
+	}
+
+	ev = tevent_context_init(mem_ctx);
+	if (ev == NULL) {
+		LOG("tevent_context_init() failed\n");
+		goto failed;
+	}
+
+	ret = ctdb_client_init(mem_ctx, ev, sockpath, &client);
+	if (ret != 0) {
+		LOG("ctdb_client_init() failed, ret=%d\n", ret);
+		goto failed;
+	}
+
+	req = recovery_send(mem_ctx, ev, client, generation);
+	if (req == NULL) {
+		LOG("database_recover_send() failed\n");
+		goto failed;
+	}
+
+	if (! tevent_req_poll(req, ev)) {
+		LOG("tevent_req_poll() failed\n");
+		goto failed;
+	}
+
+	recovery_recv(req, &ret);
+	TALLOC_FREE(req);
+	if (ret != 0) {
+		LOG("database recovery failed, ret=%d\n", ret);
+		goto failed;
+	}
+
+	sys_write(write_fd, &ret, sizeof(ret));
+	return 0;
+
+failed:
+	talloc_free(mem_ctx);
+	return 1;
+}
diff --git a/ctdb/server/ctdb_server.c b/ctdb/server/ctdb_server.c
index 81ef361..7d42c38 100644
--- a/ctdb/server/ctdb_server.c
+++ b/ctdb/server/ctdb_server.c
@@ -17,12 +17,22 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "tdb.h"
-#include "lib/util/dlinklist.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
-#include "../include/ctdb_private.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/common.h"
+#include "common/logging.h"
 
 /*
   choose the transport we will use
@@ -79,7 +89,7 @@ int ctdb_set_recovery_lock_file(struct ctdb_context *ctdb, const char *file)
 /* Load a nodes list file into a nodes array */
 static int convert_node_map_to_list(struct ctdb_context *ctdb,
 				    TALLOC_CTX *mem_ctx,
-				    struct ctdb_node_map *node_map,
+				    struct ctdb_node_map_old *node_map,
 				    struct ctdb_node ***nodes,
 				    uint32_t *num_nodes)
 {
@@ -119,7 +129,7 @@ static int convert_node_map_to_list(struct ctdb_context *ctdb,
 /* Load the nodes list from a file */
 void ctdb_load_nodes_file(struct ctdb_context *ctdb)
 {
-	struct ctdb_node_map *node_map;
+	struct ctdb_node_map_old *node_map;
 	int ret;
 
 	node_map = ctdb_read_nodes_file(ctdb, ctdb->nodes_file);
@@ -203,7 +213,7 @@ void ctdb_input_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 	case CTDB_REPLY_CALL:
 	case CTDB_REQ_DMASTER:
 	case CTDB_REPLY_DMASTER:
-		/* we dont allow these calls when banned */
+		/* we don't allow these calls when banned */
 		if (ctdb->nodes[ctdb->pnn]->flags & NODE_FLAGS_BANNED) {
 			DEBUG(DEBUG_DEBUG,(__location__ " ctdb operation %u"
 				" request %u"
@@ -346,7 +356,8 @@ struct queue_next {
 /*
   triggered when a deferred packet is due
  */
-static void queue_next_trigger(struct event_context *ev, struct timed_event *te, 
+static void queue_next_trigger(struct tevent_context *ev,
+			       struct tevent_timer *te,
 			       struct timeval t, void *private_data)
 {
 	struct queue_next *q = talloc_get_type(private_data, struct queue_next);
@@ -376,7 +387,7 @@ static void ctdb_defer_packet(struct ctdb_context *ctdb, struct ctdb_req_header
 	/* use this to put packets directly into our recv function */
 	ctdb_input_pkt(q->ctdb, q->hdr);
 #else
-	event_add_timed(ctdb->ev, q, timeval_zero(), queue_next_trigger, q);
+	tevent_add_timer(ctdb->ev, q, timeval_zero(), queue_next_trigger, q);
 #endif
 }
 
diff --git a/ctdb/server/ctdb_serverids.c b/ctdb/server/ctdb_serverids.c
index dba25ed..11ee99b 100644
--- a/ctdb/server/ctdb_serverids.c
+++ b/ctdb/server/ctdb_serverids.c
@@ -16,13 +16,23 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
-#include "includes.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+
+#include "common/rb_tree.h"
+#include "common/reqid.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 
 #define SERVER_ID_KEY_SIZE 3
-static uint32_t *get_server_id_key(struct ctdb_server_id *server_id)
+static uint32_t *get_server_id_key(struct ctdb_client_id *server_id)
 {
 	static uint32_t key[SERVER_ID_KEY_SIZE];
 
@@ -57,8 +67,8 @@ int32_t ctdb_control_register_server_id(struct ctdb_context *ctdb,
 				 uint32_t client_id,
 				 TDB_DATA indata)
 {
-	struct ctdb_server_id *server_id;
-	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+	struct ctdb_client_id *server_id;
+	struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
 
 
 	if (client == NULL) {
@@ -72,9 +82,9 @@ int32_t ctdb_control_register_server_id(struct ctdb_context *ctdb,
 	   when the structure is free'd it will be automatically
 	   removed from the tree
 	*/
-	server_id = talloc_zero(client, struct ctdb_server_id);
+	server_id = talloc_zero(client, struct ctdb_client_id);
 	CTDB_NO_MEMORY(ctdb, server_id);
-	memcpy(server_id, indata.dptr, sizeof(struct ctdb_server_id));
+	memcpy(server_id, indata.dptr, sizeof(struct ctdb_client_id));
 
 	trbt_insertarray32_callback(ctdb->server_ids, SERVER_ID_KEY_SIZE,
 		get_server_id_key(server_id), 
@@ -90,7 +100,7 @@ int32_t ctdb_control_register_server_id(struct ctdb_context *ctdb,
 int32_t ctdb_control_check_server_id(struct ctdb_context *ctdb, 
 				 TDB_DATA indata)
 {
-	struct ctdb_server_id *server_id = (struct ctdb_server_id *)indata.dptr;
+	struct ctdb_client_id *server_id = (struct ctdb_client_id *)indata.dptr;
 
 	return trbt_lookuparray32(ctdb->server_ids, 
 				  SERVER_ID_KEY_SIZE,
@@ -103,7 +113,7 @@ int32_t ctdb_control_check_server_id(struct ctdb_context *ctdb,
 int32_t ctdb_control_unregister_server_id(struct ctdb_context *ctdb, 
 				 TDB_DATA indata)
 {
-	struct ctdb_server_id *server_id = (struct ctdb_server_id *)indata.dptr;
+	struct ctdb_client_id *server_id = (struct ctdb_client_id *)indata.dptr;
 
 	talloc_free(trbt_lookuparray32(ctdb->server_ids, 
 			SERVER_ID_KEY_SIZE,
@@ -116,7 +126,7 @@ int32_t ctdb_control_unregister_server_id(struct ctdb_context *ctdb,
 
 struct count_server_ids {
 	int count;
-	struct ctdb_server_id_list *list;
+	struct ctdb_client_id_list_old *list;
 };
 
 static int server_id_count(void *param, void *data)
@@ -137,8 +147,8 @@ static int server_id_store(void *param, void *data)
 {
 	struct count_server_ids *svid = talloc_get_type(param, 
 						struct count_server_ids);
-	struct ctdb_server_id *server_id = talloc_get_type(data, 
-						struct ctdb_server_id);
+	struct ctdb_client_id *server_id = talloc_get_type(data,
+						struct ctdb_client_id);
 
 	if (svid == NULL) {
 		DEBUG(DEBUG_ERR, (__location__ " Got null pointer for svid\n"));
@@ -150,7 +160,7 @@ static int server_id_store(void *param, void *data)
 		return -1;
 	}
 
-	memcpy(&svid->list->server_ids[svid->count], server_id, sizeof(struct ctdb_server_id));
+	memcpy(&svid->list->server_ids[svid->count], server_id, sizeof(struct ctdb_client_id));
 	svid->count++;
 	return 0;
 }
@@ -172,15 +182,14 @@ int32_t ctdb_control_get_server_id_list(struct ctdb_context *ctdb, TDB_DATA *out
 			server_id_count, svid);
 
 
-	outdata->dsize = offsetof(struct ctdb_server_id_list, 
-				server_ids)
-			+ sizeof(struct ctdb_server_id) * svid->count;
+	outdata->dsize = offsetof(struct ctdb_client_id_list_old, server_ids)
+			+ sizeof(struct ctdb_client_id) * svid->count;
 	outdata->dptr  = talloc_size(outdata, outdata->dsize);
 	CTDB_NO_MEMORY(ctdb, outdata->dptr);
 
 
 	/* now fill the structure in */
-	svid->list = (struct ctdb_server_id_list *)(outdata->dptr);
+	svid->list = (struct ctdb_client_id_list_old *)(outdata->dptr);
 	svid->list->num = svid->count;
 	svid->count=0;
 	trbt_traversearray32(ctdb->server_ids, SERVER_ID_KEY_SIZE,
diff --git a/ctdb/server/ctdb_statistics.c b/ctdb/server/ctdb_statistics.c
index 96aad78..4cf8f9e 100644
--- a/ctdb/server/ctdb_statistics.c
+++ b/ctdb/server/ctdb_statistics.c
@@ -17,11 +17,22 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include <string.h>
-#include "../include/ctdb_private.h"
+#include "replace.h"
+#include "system/network.h"
+#include "system/time.h"
 
-static void ctdb_statistics_update(struct event_context *ev, struct timed_event *te, 
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+
+#include "common/logging.h"
+
+static void ctdb_statistics_update(struct tevent_context *ev,
+				   struct tevent_timer *te,
 				   struct timeval t, void *p)
 {
 	struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
@@ -34,8 +45,9 @@ static void ctdb_statistics_update(struct event_context *ev, struct timed_event
 	bzero(&ctdb->statistics_current, sizeof(struct ctdb_statistics));
 	ctdb->statistics_current.statistics_start_time = timeval_current();
 
-	
-	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(ctdb->tunable.stat_history_interval, 0), ctdb_statistics_update, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb,
+			 timeval_current_ofs(ctdb->tunable.stat_history_interval, 0),
+			 ctdb_statistics_update, ctdb);
 }
 
 int ctdb_statistics_init(struct ctdb_context *ctdb)
@@ -48,19 +60,22 @@ int ctdb_statistics_init(struct ctdb_context *ctdb)
 
 	bzero(ctdb->statistics_history, sizeof(ctdb->statistics_history));
 
-	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(ctdb->tunable.stat_history_interval, 0), ctdb_statistics_update, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb,
+			 timeval_current_ofs(ctdb->tunable.stat_history_interval, 0),
+			 ctdb_statistics_update, ctdb);
 	return 0;
 }
 
 
 int32_t ctdb_control_get_stat_history(struct ctdb_context *ctdb, 
-				      struct ctdb_req_control *c,
+				      struct ctdb_req_control_old *c,
 				      TDB_DATA *outdata)
 {
 	int len;
-	struct ctdb_statistics_wire *s;
+	struct ctdb_statistics_list_old *s;
 
-	len = offsetof(struct ctdb_statistics_wire, stats) + MAX_STAT_HISTORY*sizeof(struct ctdb_statistics);
+	len = offsetof(struct ctdb_statistics_list_old, stats) +
+		MAX_STAT_HISTORY*sizeof(struct ctdb_statistics);
 
 	s = talloc_size(outdata, len);
 	if (s == NULL) {
diff --git a/ctdb/server/ctdb_takeover.c b/ctdb/server/ctdb_takeover.c
index efc80b1..a613aa0 100644
--- a/ctdb/server/ctdb_takeover.c
+++ b/ctdb/server/ctdb_takeover.c
@@ -18,30 +18,38 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
-#include "includes.h"
-#include "tdb.h"
-#include "lib/util/dlinklist.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
+#include "system/time.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
 
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/util_process.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/rb_tree.h"
+#include "common/reqid.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
+
+#include "server/ipalloc.h"
 
 #define TAKEOVER_TIMEOUT() timeval_current_ofs(ctdb->tunable.takeover_timeout,0)
 
 #define CTDB_ARP_INTERVAL 1
 #define CTDB_ARP_REPEAT   3
 
-/* Flags used in IP allocation algorithms. */
-struct ctdb_ipflags {
-	bool noiptakeover;
-	bool noiphost;
-	enum ctdb_runstate runstate;
-};
-
-struct ctdb_iface {
-	struct ctdb_iface *prev, *next;
+struct ctdb_interface {
+	struct ctdb_interface *prev, *next;
 	const char *name;
 	bool link_up;
 	uint32_t references;
@@ -58,9 +66,9 @@ static const char *ctdb_vnn_iface_string(const struct ctdb_vnn *vnn)
 
 static int ctdb_add_local_iface(struct ctdb_context *ctdb, const char *iface)
 {
-	struct ctdb_iface *i;
+	struct ctdb_interface *i;
 
-	/* Verify that we dont have an entry for this ip yet */
+	/* Verify that we don't have an entry for this ip yet */
 	for (i=ctdb->ifaces;i;i=i->next) {
 		if (strcmp(i->name, iface) == 0) {
 			return 0;
@@ -68,7 +76,7 @@ static int ctdb_add_local_iface(struct ctdb_context *ctdb, const char *iface)
 	}
 
 	/* create a new structure for this interface */
-	i = talloc_zero(ctdb, struct ctdb_iface);
+	i = talloc_zero(ctdb, struct ctdb_interface);
 	CTDB_NO_MEMORY_FATAL(ctdb, i);
 	i->name = talloc_strdup(i, iface);
 	CTDB_NO_MEMORY(ctdb, i->name);
@@ -109,7 +117,7 @@ static bool vnn_has_interface_with_name(struct ctdb_vnn *vnn,
 static void ctdb_remove_orphaned_ifaces(struct ctdb_context *ctdb,
 					struct ctdb_vnn *vnn)
 {
-	struct ctdb_iface *i, *next;
+	struct ctdb_interface *i, *next;
 
 	/* For each interface, check if there's an IP using it. */
 	for (i = ctdb->ifaces; i != NULL; i = next) {
@@ -147,10 +155,10 @@ static void ctdb_remove_orphaned_ifaces(struct ctdb_context *ctdb,
 }
 
 
-static struct ctdb_iface *ctdb_find_iface(struct ctdb_context *ctdb,
-					  const char *iface)
+static struct ctdb_interface *ctdb_find_iface(struct ctdb_context *ctdb,
+					      const char *iface)
 {
-	struct ctdb_iface *i;
+	struct ctdb_interface *i;
 
 	for (i=ctdb->ifaces;i;i=i->next) {
 		if (strcmp(i->name, iface) == 0) {
@@ -161,12 +169,12 @@ static struct ctdb_iface *ctdb_find_iface(struct ctdb_context *ctdb,
 	return NULL;
 }
 
-static struct ctdb_iface *ctdb_vnn_best_iface(struct ctdb_context *ctdb,
-					      struct ctdb_vnn *vnn)
+static struct ctdb_interface *ctdb_vnn_best_iface(struct ctdb_context *ctdb,
+						  struct ctdb_vnn *vnn)
 {
 	int i;
-	struct ctdb_iface *cur = NULL;
-	struct ctdb_iface *best = NULL;
+	struct ctdb_interface *cur = NULL;
+	struct ctdb_interface *best = NULL;
 
 	for (i=0; vnn->ifaces[i]; i++) {
 
@@ -196,7 +204,7 @@ static struct ctdb_iface *ctdb_vnn_best_iface(struct ctdb_context *ctdb,
 static int32_t ctdb_vnn_assign_iface(struct ctdb_context *ctdb,
 				     struct ctdb_vnn *vnn)
 {
-	struct ctdb_iface *best = NULL;
+	struct ctdb_interface *best = NULL;
 
 	if (vnn->iface) {
 		DEBUG(DEBUG_INFO, (__location__ " public address '%s' "
@@ -248,6 +256,11 @@ static bool ctdb_vnn_available(struct ctdb_context *ctdb,
 {
 	int i;
 
+	/* Nodes that are not RUNNING can not host IPs */
+	if (ctdb->runstate != CTDB_RUNSTATE_RUNNING) {
+		return false;
+	}
+
 	if (vnn->delete_pending) {
 		return false;
 	}
@@ -257,7 +270,7 @@ static bool ctdb_vnn_available(struct ctdb_context *ctdb,
 	}
 
 	for (i=0; vnn->ifaces[i]; i++) {
-		struct ctdb_iface *cur;
+		struct ctdb_interface *cur;
 
 		cur = ctdb_find_iface(ctdb, vnn->ifaces[i]);
 		if (cur == NULL) {
@@ -286,7 +299,7 @@ struct ctdb_takeover_arp {
  */
 struct ctdb_tcp_list {
 	struct ctdb_tcp_list *prev, *next;
-	struct ctdb_tcp_connection connection;
+	struct ctdb_connection connection;
 };
 
 /*
@@ -303,7 +316,8 @@ struct ctdb_client_ip {
 /*
   send a gratuitous arp
  */
-static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *te, 
+static void ctdb_control_send_arp(struct tevent_context *ev,
+				  struct tevent_timer *te,
 				  struct timeval t, void *private_data)
 {
 	struct ctdb_takeover_arp *arp = talloc_get_type(private_data, 
@@ -321,20 +335,20 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
 	tcparray = arp->tcparray;
 	if (tcparray) {
 		for (i=0;i<tcparray->num;i++) {
-			struct ctdb_tcp_connection *tcon;
+			struct ctdb_connection *tcon;
 
 			tcon = &tcparray->connections[i];
 			DEBUG(DEBUG_INFO,("sending tcp tickle ack for %u->%s:%u\n",
-				(unsigned)ntohs(tcon->dst_addr.ip.sin_port), 
-				ctdb_addr_to_str(&tcon->src_addr),
-				(unsigned)ntohs(tcon->src_addr.ip.sin_port)));
+				(unsigned)ntohs(tcon->dst.ip.sin_port),
+				ctdb_addr_to_str(&tcon->src),
+				(unsigned)ntohs(tcon->src.ip.sin_port)));
 			ret = ctdb_sys_send_tcp(
-				&tcon->src_addr, 
-				&tcon->dst_addr,
+				&tcon->src,
+				&tcon->dst,
 				0, 0, 0);
 			if (ret != 0) {
 				DEBUG(DEBUG_CRIT,(__location__ " Failed to send tcp tickle ack for %s\n",
-					ctdb_addr_to_str(&tcon->src_addr)));
+					ctdb_addr_to_str(&tcon->src)));
 			}
 		}
 	}
@@ -346,9 +360,9 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
 		return;
 	}
 
-	event_add_timed(arp->ctdb->ev, arp->vnn->takeover_ctx, 
-			timeval_current_ofs(CTDB_ARP_INTERVAL, 100000), 
-			ctdb_control_send_arp, arp);
+	tevent_add_timer(arp->ctdb->ev, arp->vnn->takeover_ctx,
+			 timeval_current_ofs(CTDB_ARP_INTERVAL, 100000),
+			 ctdb_control_send_arp, arp);
 }
 
 static int32_t ctdb_announce_vnn_iface(struct ctdb_context *ctdb,
@@ -383,20 +397,20 @@ static int32_t ctdb_announce_vnn_iface(struct ctdb_context *ctdb,
 		vnn->tcp_update_needed = true;
 	}
 
-	event_add_timed(arp->ctdb->ev, vnn->takeover_ctx,
-			timeval_zero(), ctdb_control_send_arp, arp);
+	tevent_add_timer(arp->ctdb->ev, vnn->takeover_ctx,
+			 timeval_zero(), ctdb_control_send_arp, arp);
 
 	return 0;
 }
 
 struct takeover_callback_state {
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	ctdb_sock_addr *addr;
 	struct ctdb_vnn *vnn;
 };
 
 struct ctdb_do_takeip_state {
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	struct ctdb_vnn *vnn;
 };
 
@@ -461,7 +475,7 @@ static int ctdb_takeip_destructor(struct ctdb_do_takeip_state *state)
   take over an ip address
  */
 static int32_t ctdb_do_takeip(struct ctdb_context *ctdb,
-			      struct ctdb_req_control *c,
+			      struct ctdb_req_control_old *c,
 			      struct ctdb_vnn *vnn)
 {
 	int ret;
@@ -520,8 +534,8 @@ static int32_t ctdb_do_takeip(struct ctdb_context *ctdb,
 }
 
 struct ctdb_do_updateip_state {
-	struct ctdb_req_control *c;
-	struct ctdb_iface *old;
+	struct ctdb_req_control_old *c;
+	struct ctdb_interface *old;
 	struct ctdb_vnn *vnn;
 };
 
@@ -584,12 +598,12 @@ static int ctdb_updateip_destructor(struct ctdb_do_updateip_state *state)
   update (move) an ip address
  */
 static int32_t ctdb_do_updateip(struct ctdb_context *ctdb,
-				struct ctdb_req_control *c,
+				struct ctdb_req_control_old *c,
 				struct ctdb_vnn *vnn)
 {
 	int ret;
 	struct ctdb_do_updateip_state *state;
-	struct ctdb_iface *old = vnn->iface;
+	struct ctdb_interface *old = vnn->iface;
 	const char *new_name;
 
 	if (vnn->update_in_flight) {
@@ -680,7 +694,7 @@ static struct ctdb_vnn *find_public_ip_vnn(struct ctdb_context *ctdb, ctdb_sock_
   take over an ip address
  */
 int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb,
-				 struct ctdb_req_control *c,
+				 struct ctdb_req_control_old *c,
 				 TDB_DATA indata,
 				 bool *async_reply)
 {
@@ -690,7 +704,7 @@ int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb,
 	bool have_ip = false;
 	bool do_updateip = false;
 	bool do_takeip = false;
-	struct ctdb_iface *best_iface = NULL;
+	struct ctdb_interface *best_iface = NULL;
 
 	if (pip->pnn != ctdb->pnn) {
 		DEBUG(DEBUG_ERR,(__location__" takeoverip called for an ip '%s' "
@@ -820,9 +834,9 @@ static void release_kill_clients(struct ctdb_context *ctdb, ctdb_sock_addr *addr
 			ctdb_addr_to_str(&ip->addr)));
 
 		if (ctdb_same_ip(&tmp_addr, addr)) {
-			struct ctdb_client *client = ctdb_reqid_find(ctdb, 
-								     ip->client_id, 
-								     struct ctdb_client);
+			struct ctdb_client *client = reqid_find(ctdb->idr,
+								ip->client_id,
+								struct ctdb_client);
 			DEBUG(DEBUG_INFO,("matched client %u with IP %s and pid %u\n", 
 				ip->client_id,
 				ctdb_addr_to_str(&ip->addr),
@@ -912,7 +926,7 @@ static int ctdb_releaseip_destructor(struct takeover_callback_state *state)
   release an ip address
  */
 int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, 
-				struct ctdb_req_control *c,
+				struct ctdb_req_control_old *c,
 				TDB_DATA indata, 
 				bool *async_reply)
 {
@@ -1045,7 +1059,7 @@ static int ctdb_add_public_address(struct ctdb_context *ctdb,
 	}
 	free(tmp);
 
-	/* Verify that we dont have an entry for this ip yet */
+	/* Verify that we don't have an entry for this ip yet */
 	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
 		if (ctdb_same_sockaddr(addr, &vnn->public_address)) {
 			DEBUG(DEBUG_CRIT,("Same ip '%s' specified multiple times in the public address list \n", 
@@ -1167,7 +1181,7 @@ int ctdb_set_single_public_ip(struct ctdb_context *ctdb,
 			      const char *ip)
 {
 	struct ctdb_vnn *svnn;
-	struct ctdb_iface *cur = NULL;
+	struct ctdb_interface *cur = NULL;
 	bool ok;
 	int ret;
 
@@ -1214,182 +1228,105 @@ int ctdb_set_single_public_ip(struct ctdb_context *ctdb,
 	return 0;
 }
 
-struct ctdb_public_ip_list {
-	struct ctdb_public_ip_list *next;
-	uint32_t pnn;
-	ctdb_sock_addr addr;
-};
-
-/* Given a physical node, return the number of
-   public addresses that is currently assigned to this node.
-*/
-static int node_ip_coverage(struct ctdb_context *ctdb, 
-	int32_t pnn,
-	struct ctdb_public_ip_list *ips)
-{
-	int num=0;
-
-	for (;ips;ips=ips->next) {
-		if (ips->pnn == pnn) {
-			num++;
-		}
-	}
-	return num;
-}
-
-
-/* Can the given node host the given IP: is the public IP known to the
- * node and is NOIPHOST unset?
-*/
-static bool can_node_host_ip(struct ctdb_context *ctdb, int32_t pnn, 
-			     struct ctdb_ipflags ipflags,
-			     struct ctdb_public_ip_list *ip)
+static void *add_ip_callback(void *parm, void *data)
 {
-	struct ctdb_all_public_ips *public_ips;
-	int i;
-
-	if (ipflags.noiphost) {
-		return false;
-	}
+	struct public_ip_list *this_ip = parm;
+	struct public_ip_list *prev_ip = data;
 
-	public_ips = ctdb->nodes[pnn]->available_public_ips;
-
-	if (public_ips == NULL) {
-		return false;
+	if (prev_ip == NULL) {
+		return parm;
 	}
-
-	for (i=0; i<public_ips->num; i++) {
-		if (ctdb_same_ip(&ip->addr, &public_ips->ips[i].addr)) {
-			/* yes, this node can serve this public ip */
-			return true;
-		}
+	if (this_ip->pnn == -1) {
+		this_ip->pnn = prev_ip->pnn;
 	}
 
-	return false;
+	return parm;
 }
 
-static bool can_node_takeover_ip(struct ctdb_context *ctdb, int32_t pnn, 
-				 struct ctdb_ipflags ipflags,
-				 struct ctdb_public_ip_list *ip)
+static int getips_count_callback(void *param, void *data)
 {
-	if (ipflags.noiptakeover) {
-		return false;
-	}
+	struct public_ip_list **ip_list = (struct public_ip_list **)param;
+	struct public_ip_list *new_ip = (struct public_ip_list *)data;
 
-	return can_node_host_ip(ctdb, pnn, ipflags, ip);
+	new_ip->next = *ip_list;
+	*ip_list     = new_ip;
+	return 0;
 }
 
-/* search the node lists list for a node to takeover this ip.
-   pick the node that currently are serving the least number of ips
-   so that the ips get spread out evenly.
-*/
-static int find_takeover_node(struct ctdb_context *ctdb, 
-		struct ctdb_ipflags *ipflags,
-		struct ctdb_public_ip_list *ip,
-		struct ctdb_public_ip_list *all_ips)
-{
-	int pnn, min=0, num;
-	int i, numnodes;
-
-	numnodes = talloc_array_length(ipflags);
-	pnn    = -1;
-	for (i=0; i<numnodes; i++) {
-		/* verify that this node can serve this ip */
-		if (!can_node_takeover_ip(ctdb, i, ipflags[i], ip)) {
-			/* no it couldnt   so skip to the next node */
-			continue;
-		}
+static int verify_remote_ip_allocation(struct ctdb_context *ctdb,
+				       struct ctdb_public_ip_list_old *ips,
+				       uint32_t pnn);
 
-		num = node_ip_coverage(ctdb, i, all_ips);
-		/* was this the first node we checked ? */
-		if (pnn == -1) {
-			pnn = i;
-			min  = num;
-		} else {
-			if (num < min) {
-				pnn = i;
-				min  = num;
-			}
-		}
-	}	
-	if (pnn == -1) {
-		DEBUG(DEBUG_WARNING,(__location__ " Could not find node to take over public address '%s'\n",
-			ctdb_addr_to_str(&ip->addr)));
+static int ctdb_reload_remote_public_ips(struct ctdb_context *ctdb,
+					 struct ipalloc_state *ipalloc_state,
+					 struct ctdb_node_map_old *nodemap)
+{
+	int j;
+	int ret;
 
+	if (ipalloc_state->num != nodemap->num) {
+		DEBUG(DEBUG_ERR,
+		      (__location__
+		       " ipalloc_state->num (%d) != nodemap->num (%d) invalid param\n",
+		       ipalloc_state->num, nodemap->num));
 		return -1;
 	}
 
-	ip->pnn = pnn;
-	return 0;
-}
-
-#define IP_KEYLEN	4
-static uint32_t *ip_key(ctdb_sock_addr *ip)
-{
-	static uint32_t key[IP_KEYLEN];
-
-	bzero(key, sizeof(key));
-
-	switch (ip->sa.sa_family) {
-	case AF_INET:
-		key[3]	= htonl(ip->ip.sin_addr.s_addr);
-		break;
-	case AF_INET6: {
-		uint32_t *s6_a32 = (uint32_t *)&(ip->ip6.sin6_addr.s6_addr);
-		key[0]	= htonl(s6_a32[0]);
-		key[1]	= htonl(s6_a32[1]);
-		key[2]	= htonl(s6_a32[2]);
-		key[3]	= htonl(s6_a32[3]);
-		break;
-	}
-	default:
-		DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", ip->sa.sa_family));
-		return key;
-	}
+	for (j=0; j<nodemap->num; j++) {
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
 
-	return key;
-}
+		/* Retrieve the list of known public IPs from the node */
+		ret = ctdb_ctrl_get_public_ips_flags(ctdb,
+					TAKEOVER_TIMEOUT(),
+					j,
+					ipalloc_state->known_public_ips,
+					0,
+					&ipalloc_state->known_public_ips[j]);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,
+			      ("Failed to read known public IPs from node: %u\n",
+			       j));
+			return -1;
+		}
 
-static void *add_ip_callback(void *parm, void *data)
-{
-	struct ctdb_public_ip_list *this_ip = parm; 
-	struct ctdb_public_ip_list *prev_ip = data; 
+		if (ctdb->do_checkpublicip) {
+			verify_remote_ip_allocation(ctdb,
+						    ipalloc_state->known_public_ips[j],
+						    j);
+		}
 
-	if (prev_ip == NULL) {
-		return parm;
-	}
-	if (this_ip->pnn == -1) {
-		this_ip->pnn = prev_ip->pnn;
+		/* Retrieve the list of available public IPs from the node */
+		ret = ctdb_ctrl_get_public_ips_flags(ctdb,
+					TAKEOVER_TIMEOUT(),
+					j,
+					ipalloc_state->available_public_ips,
+					CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE,
+					&ipalloc_state->available_public_ips[j]);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,
+			      ("Failed to read available public IPs from node: %u\n",
+			       j));
+			return -1;
+		}
 	}
 
-	return parm;
-}
-
-static int getips_count_callback(void *param, void *data)
-{
-	struct ctdb_public_ip_list **ip_list = (struct ctdb_public_ip_list **)param;
-	struct ctdb_public_ip_list *new_ip = (struct ctdb_public_ip_list *)data;
-
-	new_ip->next = *ip_list;
-	*ip_list     = new_ip;
 	return 0;
 }
 
-static struct ctdb_public_ip_list *
-create_merged_ip_list(struct ctdb_context *ctdb)
+static struct public_ip_list *
+create_merged_ip_list(struct ctdb_context *ctdb, struct ipalloc_state *ipalloc_state)
 {
 	int i, j;
-	struct ctdb_public_ip_list *ip_list;
-	struct ctdb_all_public_ips *public_ips;
+	struct public_ip_list *ip_list;
+	struct ctdb_public_ip_list_old *public_ips;
 
-	if (ctdb->ip_tree != NULL) {
-		talloc_free(ctdb->ip_tree);
-		ctdb->ip_tree = NULL;
-	}
+	TALLOC_FREE(ctdb->ip_tree);
 	ctdb->ip_tree = trbt_create(ctdb, 0);
 
-	for (i=0;i<ctdb->num_nodes;i++) {
-		public_ips = ctdb->nodes[i]->known_public_ips;
+	for (i=0; i < ctdb->num_nodes; i++) {
+		public_ips = ipalloc_state->known_public_ips[i];
 
 		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
 			continue;
@@ -1398,12 +1335,12 @@ create_merged_ip_list(struct ctdb_context *ctdb)
 		/* there were no public ips for this node */
 		if (public_ips == NULL) {
 			continue;
-		}		
+		}
 
-		for (j=0;j<public_ips->num;j++) {
-			struct ctdb_public_ip_list *tmp_ip; 
+		for (j=0; j < public_ips->num; j++) {
+			struct public_ip_list *tmp_ip;
 
-			tmp_ip = talloc_zero(ctdb->ip_tree, struct ctdb_public_ip_list);
+			tmp_ip = talloc_zero(ctdb->ip_tree, struct public_ip_list);
 			CTDB_NO_MEMORY_NULL(ctdb, tmp_ip);
 			/* Do not use information about IP addresses hosted
 			 * on other nodes, it may not be accurate */
@@ -1428,676 +1365,7 @@ create_merged_ip_list(struct ctdb_context *ctdb)
 	return ip_list;
 }
 
-/* 
- * This is the length of the longtest common prefix between the IPs.
- * It is calculated by XOR-ing the 2 IPs together and counting the
- * number of leading zeroes.  The implementation means that all
- * addresses end up being 128 bits long.
- *
- * FIXME? Should we consider IPv4 and IPv6 separately given that the
- * 12 bytes of 0 prefix padding will hurt the algorithm if there are
- * lots of nodes and IP addresses?
- */
-static uint32_t ip_distance(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
-{
-	uint32_t ip1_k[IP_KEYLEN];
-	uint32_t *t;
-	int i;
-	uint32_t x;
-
-	uint32_t distance = 0;
-
-	memcpy(ip1_k, ip_key(ip1), sizeof(ip1_k));
-	t = ip_key(ip2);
-	for (i=0; i<IP_KEYLEN; i++) {
-		x = ip1_k[i] ^ t[i];
-		if (x == 0) {
-			distance += 32;
-		} else {
-			/* Count number of leading zeroes. 
-			 * FIXME? This could be optimised...
-			 */
-			while ((x & (1 << 31)) == 0) {
-				x <<= 1;
-				distance += 1;
-			}
-		}
-	}
-
-	return distance;
-}
-
-/* Calculate the IP distance for the given IP relative to IPs on the
-   given node.  The ips argument is generally the all_ips variable
-   used in the main part of the algorithm.
- */
-static uint32_t ip_distance_2_sum(ctdb_sock_addr *ip,
-				  struct ctdb_public_ip_list *ips,
-				  int pnn)
-{
-	struct ctdb_public_ip_list *t;
-	uint32_t d;
-
-	uint32_t sum = 0;
-
-	for (t=ips; t != NULL; t=t->next) {
-		if (t->pnn != pnn) {
-			continue;
-		}
-
-		/* Optimisation: We never calculate the distance
-		 * between an address and itself.  This allows us to
-		 * calculate the effect of removing an address from a
-		 * node by simply calculating the distance between
-		 * that address and all of the exitsing addresses.
-		 * Moreover, we assume that we're only ever dealing
-		 * with addresses from all_ips so we can identify an
-		 * address via a pointer rather than doing a more
-		 * expensive address comparison. */
-		if (&(t->addr) == ip) {
-			continue;
-		}
-
-		d = ip_distance(ip, &(t->addr));
-		sum += d * d;  /* Cheaper than pulling in math.h :-) */
-	}
-
-	return sum;
-}
-
-/* Return the LCP2 imbalance metric for addresses currently assigned
-   to the given node.
- */
-static uint32_t lcp2_imbalance(struct ctdb_public_ip_list * all_ips, int pnn)
-{
-	struct ctdb_public_ip_list *t;
-
-	uint32_t imbalance = 0;
-
-	for (t=all_ips; t!=NULL; t=t->next) {
-		if (t->pnn != pnn) {
-			continue;
-		}
-		/* Pass the rest of the IPs rather than the whole
-		   all_ips input list.
-		*/
-		imbalance += ip_distance_2_sum(&(t->addr), t->next, pnn);
-	}
-
-	return imbalance;
-}
-
-/* Allocate any unassigned IPs just by looping through the IPs and
- * finding the best node for each.
- */
-static void basic_allocate_unassigned(struct ctdb_context *ctdb,
-				      struct ctdb_ipflags *ipflags,
-				      struct ctdb_public_ip_list *all_ips)
-{
-	struct ctdb_public_ip_list *tmp_ip;
-
-	/* loop over all ip's and find a physical node to cover for 
-	   each unassigned ip.
-	*/
-	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
-		if (tmp_ip->pnn == -1) {
-			if (find_takeover_node(ctdb, ipflags, tmp_ip, all_ips)) {
-				DEBUG(DEBUG_WARNING,("Failed to find node to cover ip %s\n",
-					ctdb_addr_to_str(&tmp_ip->addr)));
-			}
-		}
-	}
-}
-
-/* Basic non-deterministic rebalancing algorithm.
- */
-static void basic_failback(struct ctdb_context *ctdb,
-			   struct ctdb_ipflags *ipflags,
-			   struct ctdb_public_ip_list *all_ips,
-			   int num_ips)
-{
-	int i, numnodes;
-	int maxnode, maxnum, minnode, minnum, num, retries;
-	struct ctdb_public_ip_list *tmp_ip;
-
-	numnodes = talloc_array_length(ipflags);
-	retries = 0;
-
-try_again:
-	maxnum=0;
-	minnum=0;
-
-	/* for each ip address, loop over all nodes that can serve
-	   this ip and make sure that the difference between the node
-	   serving the most and the node serving the least ip's are
-	   not greater than 1.
-	*/
-	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
-		if (tmp_ip->pnn == -1) {
-			continue;
-		}
-
-		/* Get the highest and lowest number of ips's served by any 
-		   valid node which can serve this ip.
-		*/
-		maxnode = -1;
-		minnode = -1;
-		for (i=0; i<numnodes; i++) {
-			/* only check nodes that can actually serve this ip */
-			if (!can_node_takeover_ip(ctdb, i, ipflags[i], tmp_ip)) {
-				/* no it couldnt   so skip to the next node */
-				continue;
-			}
-
-			num = node_ip_coverage(ctdb, i, all_ips);
-			if (maxnode == -1) {
-				maxnode = i;
-				maxnum  = num;
-			} else {
-				if (num > maxnum) {
-					maxnode = i;
-					maxnum  = num;
-				}
-			}
-			if (minnode == -1) {
-				minnode = i;
-				minnum  = num;
-			} else {
-				if (num < minnum) {
-					minnode = i;
-					minnum  = num;
-				}
-			}
-		}
-		if (maxnode == -1) {
-			DEBUG(DEBUG_WARNING,(__location__ " Could not find maxnode. May not be able to serve ip '%s'\n",
-				ctdb_addr_to_str(&tmp_ip->addr)));
-
-			continue;
-		}
-
-		/* if the spread between the smallest and largest coverage by
-		   a node is >=2 we steal one of the ips from the node with
-		   most coverage to even things out a bit.
-		   try to do this a limited number of times since we dont
-		   want to spend too much time balancing the ip coverage.
-		*/
-		if ( (maxnum > minnum+1)
-		     && (retries < (num_ips + 5)) ){
-			struct ctdb_public_ip_list *tmp;
-
-			/* Reassign one of maxnode's VNNs */
-			for (tmp=all_ips;tmp;tmp=tmp->next) {
-				if (tmp->pnn == maxnode) {
-					(void)find_takeover_node(ctdb, ipflags, tmp, all_ips);
-					retries++;
-					goto try_again;;
-				}
-			}
-		}
-	}
-}
-
-static void lcp2_init(struct ctdb_context *tmp_ctx,
-		      struct ctdb_ipflags *ipflags,
-		      struct ctdb_public_ip_list *all_ips,
-		      uint32_t *force_rebalance_nodes,
-		      uint32_t **lcp2_imbalances,
-		      bool **rebalance_candidates)
-{
-	int i, numnodes;
-	struct ctdb_public_ip_list *tmp_ip;
-
-	numnodes = talloc_array_length(ipflags);
-
-	*rebalance_candidates = talloc_array(tmp_ctx, bool, numnodes);
-	CTDB_NO_MEMORY_FATAL(tmp_ctx, *rebalance_candidates);
-	*lcp2_imbalances = talloc_array(tmp_ctx, uint32_t, numnodes);
-	CTDB_NO_MEMORY_FATAL(tmp_ctx, *lcp2_imbalances);
-
-	for (i=0; i<numnodes; i++) {
-		(*lcp2_imbalances)[i] = lcp2_imbalance(all_ips, i);
-		/* First step: assume all nodes are candidates */
-		(*rebalance_candidates)[i] = true;
-	}
-
-	/* 2nd step: if a node has IPs assigned then it must have been
-	 * healthy before, so we remove it from consideration.  This
-	 * is overkill but is all we have because we don't maintain
-	 * state between takeover runs.  An alternative would be to
-	 * keep state and invalidate it every time the recovery master
-	 * changes.
-	 */
-	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
-		if (tmp_ip->pnn != -1) {
-			(*rebalance_candidates)[tmp_ip->pnn] = false;
-		}
-	}
-
-	/* 3rd step: if a node is forced to re-balance then
-	   we allow failback onto the node */
-	if (force_rebalance_nodes == NULL) {
-		return;
-	}
-	for (i = 0; i < talloc_array_length(force_rebalance_nodes); i++) {
-		uint32_t pnn = force_rebalance_nodes[i];
-		if (pnn >= numnodes) {
-			DEBUG(DEBUG_ERR,
-			      (__location__ "unknown node %u\n", pnn));
-			continue;
-		}
-
-		DEBUG(DEBUG_NOTICE,
-		      ("Forcing rebalancing of IPs to node %u\n", pnn));
-		(*rebalance_candidates)[pnn] = true;
-	}
-}
-
-/* Allocate any unassigned addresses using the LCP2 algorithm to find
- * the IP/node combination that will cost the least.
- */
-static void lcp2_allocate_unassigned(struct ctdb_context *ctdb,
-				     struct ctdb_ipflags *ipflags,
-				     struct ctdb_public_ip_list *all_ips,
-				     uint32_t *lcp2_imbalances)
-{
-	struct ctdb_public_ip_list *tmp_ip;
-	int dstnode, numnodes;
-
-	int minnode;
-	uint32_t mindsum, dstdsum, dstimbl, minimbl;
-	struct ctdb_public_ip_list *minip;
-
-	bool should_loop = true;
-	bool have_unassigned = true;
-
-	numnodes = talloc_array_length(ipflags);
-
-	while (have_unassigned && should_loop) {
-		should_loop = false;
-
-		DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
-		DEBUG(DEBUG_DEBUG,(" CONSIDERING MOVES (UNASSIGNED)\n"));
-
-		minnode = -1;
-		mindsum = 0;
-		minip = NULL;
-
-		/* loop over each unassigned ip. */
-		for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
-			if (tmp_ip->pnn != -1) {
-				continue;
-			}
-
-			for (dstnode=0; dstnode<numnodes; dstnode++) {
-				/* only check nodes that can actually takeover this ip */
-				if (!can_node_takeover_ip(ctdb, dstnode,
-							  ipflags[dstnode],
-							  tmp_ip)) {
-					/* no it couldnt   so skip to the next node */
-					continue;
-				}
-
-				dstdsum = ip_distance_2_sum(&(tmp_ip->addr), all_ips, dstnode);
-				dstimbl = lcp2_imbalances[dstnode] + dstdsum;
-				DEBUG(DEBUG_DEBUG,(" %s -> %d [+%d]\n",
-						   ctdb_addr_to_str(&(tmp_ip->addr)),
-						   dstnode,
-						   dstimbl - lcp2_imbalances[dstnode]));
-
-
-				if ((minnode == -1) || (dstdsum < mindsum)) {
-					minnode = dstnode;
-					minimbl = dstimbl;
-					mindsum = dstdsum;
-					minip = tmp_ip;
-					should_loop = true;
-				}
-			}
-		}
-
-		DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
-
-		/* If we found one then assign it to the given node. */
-		if (minnode != -1) {
-			minip->pnn = minnode;
-			lcp2_imbalances[minnode] = minimbl;
-			DEBUG(DEBUG_INFO,(" %s -> %d [+%d]\n",
-					  ctdb_addr_to_str(&(minip->addr)),
-					  minnode,
-					  mindsum));
-		}
-
-		/* There might be a better way but at least this is clear. */
-		have_unassigned = false;
-		for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
-			if (tmp_ip->pnn == -1) {
-				have_unassigned = true;
-			}
-		}
-	}
-
-	/* We know if we have an unassigned addresses so we might as
-	 * well optimise.
-	 */
-	if (have_unassigned) {
-		for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
-			if (tmp_ip->pnn == -1) {
-				DEBUG(DEBUG_WARNING,("Failed to find node to cover ip %s\n",
-						     ctdb_addr_to_str(&tmp_ip->addr)));
-			}
-		}
-	}
-}
-
-/* LCP2 algorithm for rebalancing the cluster.  Given a candidate node
- * to move IPs from, determines the best IP/destination node
- * combination to move from the source node.
- */
-static bool lcp2_failback_candidate(struct ctdb_context *ctdb,
-				    struct ctdb_ipflags *ipflags,
-				    struct ctdb_public_ip_list *all_ips,
-				    int srcnode,
-				    uint32_t *lcp2_imbalances,
-				    bool *rebalance_candidates)
-{
-	int dstnode, mindstnode, numnodes;
-	uint32_t srcimbl, srcdsum, dstimbl, dstdsum;
-	uint32_t minsrcimbl, mindstimbl;
-	struct ctdb_public_ip_list *minip;
-	struct ctdb_public_ip_list *tmp_ip;
-
-	/* Find an IP and destination node that best reduces imbalance. */
-	srcimbl = 0;
-	minip = NULL;
-	minsrcimbl = 0;
-	mindstnode = -1;
-	mindstimbl = 0;
-
-	numnodes = talloc_array_length(ipflags);
-
-	DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
-	DEBUG(DEBUG_DEBUG,(" CONSIDERING MOVES FROM %d [%d]\n",
-			   srcnode, lcp2_imbalances[srcnode]));
-
-	for (tmp_ip=all_ips; tmp_ip; tmp_ip=tmp_ip->next) {
-		/* Only consider addresses on srcnode. */
-		if (tmp_ip->pnn != srcnode) {
-			continue;
-		}
-
-		/* What is this IP address costing the source node? */
-		srcdsum = ip_distance_2_sum(&(tmp_ip->addr), all_ips, srcnode);
-		srcimbl = lcp2_imbalances[srcnode] - srcdsum;
-
-		/* Consider this IP address would cost each potential
-		 * destination node.  Destination nodes are limited to
-		 * those that are newly healthy, since we don't want
-		 * to do gratuitous failover of IPs just to make minor
-		 * balance improvements.
-		 */
-		for (dstnode=0; dstnode<numnodes; dstnode++) {
-			if (!rebalance_candidates[dstnode]) {
-				continue;
-			}
-
-			/* only check nodes that can actually takeover this ip */
-			if (!can_node_takeover_ip(ctdb, dstnode,
-						  ipflags[dstnode], tmp_ip)) {
-				/* no it couldnt   so skip to the next node */
-				continue;
-			}
-
-			dstdsum = ip_distance_2_sum(&(tmp_ip->addr), all_ips, dstnode);
-			dstimbl = lcp2_imbalances[dstnode] + dstdsum;
-			DEBUG(DEBUG_DEBUG,(" %d [%d] -> %s -> %d [+%d]\n",
-					   srcnode, -srcdsum,
-					   ctdb_addr_to_str(&(tmp_ip->addr)),
-					   dstnode, dstdsum));
-
-			if ((dstimbl < lcp2_imbalances[srcnode]) &&
-			    (dstdsum < srcdsum) &&			\
-			    ((mindstnode == -1) ||				\
-			     ((srcimbl + dstimbl) < (minsrcimbl + mindstimbl)))) {
-
-				minip = tmp_ip;
-				minsrcimbl = srcimbl;
-				mindstnode = dstnode;
-				mindstimbl = dstimbl;
-			}
-		}
-	}
-	DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
-
-        if (mindstnode != -1) {
-		/* We found a move that makes things better... */
-		DEBUG(DEBUG_INFO,("%d [%d] -> %s -> %d [+%d]\n",
-				  srcnode, minsrcimbl - lcp2_imbalances[srcnode],
-				  ctdb_addr_to_str(&(minip->addr)),
-				  mindstnode, mindstimbl - lcp2_imbalances[mindstnode]));
-
-
-		lcp2_imbalances[srcnode] = minsrcimbl;
-		lcp2_imbalances[mindstnode] = mindstimbl;
-		minip->pnn = mindstnode;
-
-		return true;
-	}
-
-        return false;
-	
-}
-
-struct lcp2_imbalance_pnn {
-	uint32_t imbalance;
-	int pnn;
-};
-
-static int lcp2_cmp_imbalance_pnn(const void * a, const void * b)
-{
-	const struct lcp2_imbalance_pnn * lipa = (const struct lcp2_imbalance_pnn *) a;
-	const struct lcp2_imbalance_pnn * lipb = (const struct lcp2_imbalance_pnn *) b;
-
-	if (lipa->imbalance > lipb->imbalance) {
-		return -1;
-	} else if (lipa->imbalance == lipb->imbalance) {
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-/* LCP2 algorithm for rebalancing the cluster.  This finds the source
- * node with the highest LCP2 imbalance, and then determines the best
- * IP/destination node combination to move from the source node.
- */
-static void lcp2_failback(struct ctdb_context *ctdb,
-			  struct ctdb_ipflags *ipflags,
-			  struct ctdb_public_ip_list *all_ips,
-			  uint32_t *lcp2_imbalances,
-			  bool *rebalance_candidates)
-{
-	int i, numnodes;
-	struct lcp2_imbalance_pnn * lips;
-	bool again;
-
-	numnodes = talloc_array_length(ipflags);
-
-try_again:
-	/* Put the imbalances and nodes into an array, sort them and
-	 * iterate through candidates.  Usually the 1st one will be
-	 * used, so this doesn't cost much...
-	 */
-	DEBUG(DEBUG_DEBUG,("+++++++++++++++++++++++++++++++++++++++++\n"));
-	DEBUG(DEBUG_DEBUG,("Selecting most imbalanced node from:\n"));
-	lips = talloc_array(ctdb, struct lcp2_imbalance_pnn, numnodes);
-	for (i=0; i<numnodes; i++) {
-		lips[i].imbalance = lcp2_imbalances[i];
-		lips[i].pnn = i;
-		DEBUG(DEBUG_DEBUG,(" %d [%d]\n", i, lcp2_imbalances[i]));
-	}
-	qsort(lips, numnodes, sizeof(struct lcp2_imbalance_pnn),
-	      lcp2_cmp_imbalance_pnn);
-
-	again = false;
-	for (i=0; i<numnodes; i++) {
-		/* This means that all nodes had 0 or 1 addresses, so
-		 * can't be imbalanced.
-		 */
-		if (lips[i].imbalance == 0) {
-			break;
-		}
-
-		if (lcp2_failback_candidate(ctdb,
-					    ipflags,
-					    all_ips,
-					    lips[i].pnn,
-					    lcp2_imbalances,
-					    rebalance_candidates)) {
-			again = true;
-			break;
-		}
-	}
-
-	talloc_free(lips);
-	if (again) {
-		goto try_again;
-	}
-}
-
-static void unassign_unsuitable_ips(struct ctdb_context *ctdb,
-				    struct ctdb_ipflags *ipflags,
-				    struct ctdb_public_ip_list *all_ips)
-{
-	struct ctdb_public_ip_list *tmp_ip;
-
-	/* verify that the assigned nodes can serve that public ip
-	   and set it to -1 if not
-	*/
-	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
-		if (tmp_ip->pnn == -1) {
-			continue;
-		}
-		if (!can_node_host_ip(ctdb, tmp_ip->pnn,
-				      ipflags[tmp_ip->pnn], tmp_ip) != 0) {
-			/* this node can not serve this ip. */
-			DEBUG(DEBUG_DEBUG,("Unassign IP: %s from %d\n",
-					   ctdb_addr_to_str(&(tmp_ip->addr)),
-					   tmp_ip->pnn));
-			tmp_ip->pnn = -1;
-		}
-	}
-}
-
-static void ip_alloc_deterministic_ips(struct ctdb_context *ctdb,
-				       struct ctdb_ipflags *ipflags,
-				       struct ctdb_public_ip_list *all_ips)
-{
-	struct ctdb_public_ip_list *tmp_ip;
-	int i, numnodes;
-
-	numnodes = talloc_array_length(ipflags);
-
-	DEBUG(DEBUG_NOTICE,("Deterministic IPs enabled. Resetting all ip allocations\n"));
-       /* Allocate IPs to nodes in a modulo fashion so that IPs will
-        *  always be allocated the same way for a specific set of
-        *  available/unavailable nodes.
-	*/
-
-	for (i=0,tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next,i++) {
-		tmp_ip->pnn = i % numnodes;
-	}
-
-	/* IP failback doesn't make sense with deterministic
-	 * IPs, since the modulo step above implicitly fails
-	 * back IPs to their "home" node.
-	 */
-	if (1 == ctdb->tunable.no_ip_failback) {
-		DEBUG(DEBUG_WARNING, ("WARNING: 'NoIPFailback' set but ignored - incompatible with 'DeterministicIPs\n"));
-	}
-
-	unassign_unsuitable_ips(ctdb, ipflags, all_ips);
-
-	basic_allocate_unassigned(ctdb, ipflags, all_ips);
-
-	/* No failback here! */
-}
-
-static void ip_alloc_nondeterministic_ips(struct ctdb_context *ctdb,
-					  struct ctdb_ipflags *ipflags,
-					  struct ctdb_public_ip_list *all_ips)
-{
-	/* This should be pushed down into basic_failback. */
-	struct ctdb_public_ip_list *tmp_ip;
-	int num_ips = 0;
-	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
-		num_ips++;
-	}
-
-	unassign_unsuitable_ips(ctdb, ipflags, all_ips);
-
-	basic_allocate_unassigned(ctdb, ipflags, all_ips);
-
-	/* If we don't want IPs to fail back then don't rebalance IPs. */
-	if (1 == ctdb->tunable.no_ip_failback) {
-		return;
-	}
-
-	/* Now, try to make sure the ip adresses are evenly distributed
-	   across the nodes.
-	*/
-	basic_failback(ctdb, ipflags, all_ips, num_ips);
-}
-
-static void ip_alloc_lcp2(struct ctdb_context *ctdb,
-			  struct ctdb_ipflags *ipflags,
-			  struct ctdb_public_ip_list *all_ips,
-			  uint32_t *force_rebalance_nodes)
-{
-	uint32_t *lcp2_imbalances;
-	bool *rebalance_candidates;
-	int numnodes, num_rebalance_candidates, i;
-
-	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-
-	unassign_unsuitable_ips(ctdb, ipflags, all_ips);
-
-	lcp2_init(tmp_ctx, ipflags, all_ips,force_rebalance_nodes,
-		  &lcp2_imbalances, &rebalance_candidates);
-
-	lcp2_allocate_unassigned(ctdb, ipflags, all_ips, lcp2_imbalances);
-
-	/* If we don't want IPs to fail back then don't rebalance IPs. */
-	if (1 == ctdb->tunable.no_ip_failback) {
-		goto finished;
-	}
-
-	/* It is only worth continuing if we have suitable target
-	 * nodes to transfer IPs to.  This check is much cheaper than
-	 * continuing on...
-	 */
-	numnodes = talloc_array_length(ipflags);
-	num_rebalance_candidates = 0;
-	for (i=0; i<numnodes; i++) {
-		if (rebalance_candidates[i]) {
-			num_rebalance_candidates++;
-		}
-	}
-	if (num_rebalance_candidates == 0) {
-		goto finished;
-	}
-
-	/* Now, try to make sure the ip adresses are evenly distributed
-	   across the nodes.
-	*/
-	lcp2_failback(ctdb, ipflags, all_ips,
-		      lcp2_imbalances, rebalance_candidates);
-
-finished:
-	talloc_free(tmp_ctx);
-}
-
-static bool all_nodes_are_disabled(struct ctdb_node_map *nodemap)
+static bool all_nodes_are_disabled(struct ctdb_node_map_old *nodemap)
 {
 	int i;
 
@@ -2111,37 +1379,6 @@ static bool all_nodes_are_disabled(struct ctdb_node_map *nodemap)
 	return true;
 }
 
-/* The calculation part of the IP allocation algorithm. */
-static void ctdb_takeover_run_core(struct ctdb_context *ctdb,
-				   struct ctdb_ipflags *ipflags,
-				   struct ctdb_public_ip_list **all_ips_p,
-				   uint32_t *force_rebalance_nodes)
-{
-	/* since nodes only know about those public addresses that
-	   can be served by that particular node, no single node has
-	   a full list of all public addresses that exist in the cluster.
-	   Walk over all node structures and create a merged list of
-	   all public addresses that exist in the cluster.
-
-	   keep the tree of ips around as ctdb->ip_tree
-	*/
-	*all_ips_p = create_merged_ip_list(ctdb);
-
-        if (1 == ctdb->tunable.lcp2_public_ip_assignment) {
-		ip_alloc_lcp2(ctdb, ipflags, *all_ips_p, force_rebalance_nodes);
-	} else if (1 == ctdb->tunable.deterministic_public_ips) {
-		ip_alloc_deterministic_ips(ctdb, ipflags, *all_ips_p);
-	} else {
-		ip_alloc_nondeterministic_ips(ctdb, ipflags, *all_ips_p);
-	}
-
-	/* at this point ->pnn is the node which will own each IP
-	   or -1 if there is no node that can cover this ip
-	*/
-
-	return;
-}
-
 struct get_tunable_callback_data {
 	const char *tunable;
 	uint32_t *out;
@@ -2210,7 +1447,7 @@ static void get_tunable_fail_callback(struct ctdb_context *ctdb, uint32_t pnn,
 
 static uint32_t *get_tunable_from_nodes(struct ctdb_context *ctdb,
 					TALLOC_CTX *tmp_ctx,
-					struct ctdb_node_map *nodemap,
+					struct ctdb_node_map_old *nodemap,
 					const char *tunable,
 					uint32_t default_value)
 {
@@ -2254,98 +1491,6 @@ static uint32_t *get_tunable_from_nodes(struct ctdb_context *ctdb,
 	return tvals;
 }
 
-struct get_runstate_callback_data {
-	enum ctdb_runstate *out;
-	bool fatal;
-};
-
-static void get_runstate_callback(struct ctdb_context *ctdb, uint32_t pnn,
-				  int32_t res, TDB_DATA outdata,
-				  void *callback_data)
-{
-	struct get_runstate_callback_data *cd =
-		(struct get_runstate_callback_data *)callback_data;
-	int size;
-
-	if (res != 0) {
-		/* Already handled in fail callback */
-		return;
-	}
-
-	if (outdata.dsize != sizeof(uint32_t)) {
-		DEBUG(DEBUG_ERR,("Wrong size of returned data when getting runstate from node %d. Expected %d bytes but received %d bytes\n",
-				 pnn, (int)sizeof(uint32_t),
-				 (int)outdata.dsize));
-		cd->fatal = true;
-		return;
-	}
-
-	size = talloc_array_length(cd->out);
-	if (pnn >= size) {
-		DEBUG(DEBUG_ERR,("Got reply from node %d but nodemap only has %d entries\n",
-				 pnn, size));
-		return;
-	}
-
-	cd->out[pnn] = (enum ctdb_runstate)*(uint32_t *)outdata.dptr;
-}
-
-static void get_runstate_fail_callback(struct ctdb_context *ctdb, uint32_t pnn,
-				       int32_t res, TDB_DATA outdata,
-				       void *callback)
-{
-	struct get_runstate_callback_data *cd =
-		(struct get_runstate_callback_data *)callback;
-
-	switch (res) {
-	case -ETIME:
-		DEBUG(DEBUG_ERR,
-		      ("Timed out getting runstate from node %d\n", pnn));
-		cd->fatal = true;
-		break;
-	default:
-		DEBUG(DEBUG_WARNING,
-		      ("Error getting runstate from node %d - assuming runstates not supported\n",
-		       pnn));
-	}
-}
-
-static enum ctdb_runstate * get_runstate_from_nodes(struct ctdb_context *ctdb,
-						    TALLOC_CTX *tmp_ctx,
-						    struct ctdb_node_map *nodemap,
-						    enum ctdb_runstate default_value)
-{
-	uint32_t *nodes;
-	enum ctdb_runstate *rs;
-	struct get_runstate_callback_data callback_data;
-	int i;
-
-	rs = talloc_array(tmp_ctx, enum ctdb_runstate, nodemap->num);
-	CTDB_NO_MEMORY_NULL(ctdb, rs);
-	for (i=0; i<nodemap->num; i++) {
-		rs[i] = default_value;
-	}
-
-	callback_data.out = rs;
-	callback_data.fatal = false;
-
-	nodes = list_of_connected_nodes(ctdb, nodemap, tmp_ctx, true);
-	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_GET_RUNSTATE,
-				      nodes, 0, TAKEOVER_TIMEOUT(),
-				      true, tdb_null,
-				      get_runstate_callback,
-				      get_runstate_fail_callback,
-				      &callback_data) != 0) {
-		if (callback_data.fatal) {
-			free(rs);
-			rs = NULL;
-		}
-	}
-	talloc_free(nodes);
-
-	return rs;
-}
-
 /* Set internal flags for IP allocation:
  *   Clear ip flags
  *   Set NOIPTAKOVER ip flags from per-node NoIPTakeover tunable
@@ -2355,38 +1500,23 @@ static enum ctdb_runstate * get_runstate_from_nodes(struct ctdb_context *ctdb,
  *   else
  *     Set NOIPHOST ip flags for disabled nodes
  */
-static struct ctdb_ipflags *
-set_ipflags_internal(struct ctdb_context *ctdb,
-		     TALLOC_CTX *tmp_ctx,
-		     struct ctdb_node_map *nodemap,
-		     uint32_t *tval_noiptakeover,
-		     uint32_t *tval_noiphostonalldisabled,
-		     enum ctdb_runstate *runstate)
+static void set_ipflags_internal(struct ipalloc_state *ipalloc_state,
+				 struct ctdb_node_map_old *nodemap,
+				 uint32_t *tval_noiptakeover,
+				 uint32_t *tval_noiphostonalldisabled)
 {
 	int i;
-	struct ctdb_ipflags *ipflags;
-
-	/* Clear IP flags - implicit due to talloc_zero */
-	ipflags = talloc_zero_array(tmp_ctx, struct ctdb_ipflags, nodemap->num);
-	CTDB_NO_MEMORY_NULL(ctdb, ipflags);
 
 	for (i=0;i<nodemap->num;i++) {
 		/* Can not take IPs on node with NoIPTakeover set */
 		if (tval_noiptakeover[i] != 0) {
-			ipflags[i].noiptakeover = true;
+			ipalloc_state->noiptakeover[i] = true;
 		}
 
-		/* Can not host IPs on node not in RUNNING state */
-		if (runstate[i] != CTDB_RUNSTATE_RUNNING) {
-			ipflags[i].noiphost = true;
-			continue;
-		}
 		/* Can not host IPs on INACTIVE node */
 		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
-			ipflags[i].noiphost = true;
+			ipalloc_state->noiphost[i] = true;
 		}
-		/* Remember the runstate */
-		ipflags[i].runstate = runstate[i];
 	}
 
 	if (all_nodes_are_disabled(nodemap)) {
@@ -2395,7 +1525,7 @@ set_ipflags_internal(struct ctdb_context *ctdb,
 		 */
 		for (i=0;i<nodemap->num;i++) {
 			if (tval_noiphostonalldisabled[i] != 0) {
-				ipflags[i].noiphost = true;
+				ipalloc_state->noiphost[i] = true;
 			}
 		}
 	} else {
@@ -2404,59 +1534,102 @@ set_ipflags_internal(struct ctdb_context *ctdb,
 		 */
 		for (i=0;i<nodemap->num;i++) {
 			if (nodemap->nodes[i].flags & NODE_FLAGS_DISABLED) {
-				ipflags[i].noiphost = true;
+				ipalloc_state->noiphost[i] = true;
 			}
 		}
 	}
-
-	return ipflags;
 }
 
-static struct ctdb_ipflags *set_ipflags(struct ctdb_context *ctdb,
-					TALLOC_CTX *tmp_ctx,
-					struct ctdb_node_map *nodemap)
+static bool set_ipflags(struct ctdb_context *ctdb,
+			struct ipalloc_state *ipalloc_state,
+			struct ctdb_node_map_old *nodemap)
 {
 	uint32_t *tval_noiptakeover;
 	uint32_t *tval_noiphostonalldisabled;
-	struct ctdb_ipflags *ipflags;
-	enum ctdb_runstate *runstate;
 
-
-	tval_noiptakeover = get_tunable_from_nodes(ctdb, tmp_ctx, nodemap,
+	tval_noiptakeover = get_tunable_from_nodes(ctdb, ipalloc_state, nodemap,
 						   "NoIPTakeover", 0);
 	if (tval_noiptakeover == NULL) {
-		return NULL;
+		return false;
 	}
 
 	tval_noiphostonalldisabled =
-		get_tunable_from_nodes(ctdb, tmp_ctx, nodemap,
+		get_tunable_from_nodes(ctdb, ipalloc_state, nodemap,
 				       "NoIPHostOnAllDisabled", 0);
 	if (tval_noiphostonalldisabled == NULL) {
 		/* Caller frees tmp_ctx */
+		return false;
+	}
+
+	set_ipflags_internal(ipalloc_state, nodemap,
+			     tval_noiptakeover,
+			     tval_noiphostonalldisabled);
+
+	talloc_free(tval_noiptakeover);
+	talloc_free(tval_noiphostonalldisabled);
+
+	return true;
+}
+
+static struct ipalloc_state * ipalloc_state_init(struct ctdb_context *ctdb,
+						 TALLOC_CTX *mem_ctx)
+{
+	struct ipalloc_state *ipalloc_state =
+		talloc_zero(mem_ctx, struct ipalloc_state);
+	if (ipalloc_state == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
 		return NULL;
 	}
 
-	/* Any nodes where CTDB_CONTROL_GET_RUNSTATE is not supported
-	 * will default to CTDB_RUNSTATE_RUNNING.  This ensures
-	 * reasonable behaviour on a mixed cluster during upgrade.
-	 */
-	runstate = get_runstate_from_nodes(ctdb, tmp_ctx, nodemap,
-					   CTDB_RUNSTATE_RUNNING);
-	if (runstate == NULL) {
-		/* Caller frees tmp_ctx */
+	ipalloc_state->num = ctdb->num_nodes;
+	ipalloc_state->known_public_ips =
+		talloc_zero_array(ipalloc_state,
+				  struct ctdb_public_ip_list_old *,
+				  ipalloc_state->num);
+	if (ipalloc_state->known_public_ips == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
+		talloc_free(ipalloc_state);
+		return NULL;
+	}
+	ipalloc_state->available_public_ips =
+		talloc_zero_array(ipalloc_state,
+				  struct ctdb_public_ip_list_old *,
+				  ipalloc_state->num);
+	if (ipalloc_state->available_public_ips == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
+		talloc_free(ipalloc_state);
+		return NULL;
+	}
+	ipalloc_state->noiptakeover =
+		talloc_zero_array(ipalloc_state,
+				  bool,
+				  ipalloc_state->num);
+	if (ipalloc_state->noiptakeover == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
+		talloc_free(ipalloc_state);
+		return NULL;
+	}
+	ipalloc_state->noiphost =
+		talloc_zero_array(ipalloc_state,
+				  bool,
+				  ipalloc_state->num);
+	if (ipalloc_state->noiphost == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
+		talloc_free(ipalloc_state);
 		return NULL;
 	}
 
-	ipflags = set_ipflags_internal(ctdb, tmp_ctx, nodemap,
-				       tval_noiptakeover,
-				       tval_noiphostonalldisabled,
-				       runstate);
+	if (1 == ctdb->tunable.lcp2_public_ip_assignment) {
+		ipalloc_state->algorithm = IPALLOC_LCP2;
+	} else if (1 == ctdb->tunable.deterministic_public_ips) {
+		ipalloc_state->algorithm = IPALLOC_DETERMINISTIC;
+	} else {
+		ipalloc_state->algorithm = IPALLOC_NONDETERMINISTIC;
+	}
 
-	talloc_free(tval_noiptakeover);
-	talloc_free(tval_noiphostonalldisabled);
-	talloc_free(runstate);
+	ipalloc_state->no_ip_failback = ctdb->tunable.no_ip_failback;
 
-	return ipflags;
+	return ipalloc_state;
 }
 
 struct iprealloc_callback_data {
@@ -2464,7 +1637,7 @@ struct iprealloc_callback_data {
 	int retry_count;
 	client_async_callback fail_callback;
 	void *fail_callback_data;
-	struct ctdb_node_map *nodemap;
+	struct ctdb_node_map_old *nodemap;
 };
 
 static void iprealloc_fail_callback(struct ctdb_context *ctdb, uint32_t pnn,
@@ -2525,7 +1698,7 @@ struct takeover_callback_data {
 	bool *node_failed;
 	client_async_callback fail_callback;
 	void *fail_callback_data;
-	struct ctdb_node_map *nodemap;
+	struct ctdb_node_map_old *nodemap;
 };
 
 static void takeover_run_fail_callback(struct ctdb_context *ctdb,
@@ -2556,22 +1729,47 @@ static void takeover_run_fail_callback(struct ctdb_context *ctdb,
 }
 
 /*
-  make any IP alias changes for public addresses that are necessary 
+ * Recalculate the allocation of public IPs to nodes and have the
+ * nodes host their allocated addresses.
+ *
+ * - Allocate memory for IP allocation state, including per node
+ *   arrays
+ * - Populate IP allocation algorithm in IP allocation state
+ * - Populate local value of tunable NoIPFailback in IP allocation
+     state - this is really a cluster-wide configuration variable and
+     only the value form the master node is used
+ * - Retrieve tunables NoIPTakeover and NoIPHostOnAllDisabled from all
+ *   connected nodes - this is done separately so tunable values can
+ *   be faked in unit testing
+ * - Populate NoIPTakover tunable in IP allocation state
+ * - Populate NoIPHost in IP allocation state, derived from node flags
+ *   and NoIPHostOnAllDisabled tunable
+ * - Retrieve and populate known and available IP lists in IP
+ *   allocation state
+ * - If no available IP addresses then early exit
+ * - Build list of (known IPs, currently assigned node)
+ * - Populate list of nodes to force rebalance - internal structure,
+ *   currently no way to fetch, only used by LCP2 for nodes that have
+ *   had new IP addresses added
+ * - Run IP allocation algorithm
+ * - Send RELEASE_IP to all nodes for IPs they should not host
+ * - Send TAKE_IP to all nodes for IPs they should host
+ * - Send IPREALLOCATED to all nodes (with backward compatibility hack)
  */
-int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap,
+int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map_old *nodemap,
 		      uint32_t *force_rebalance_nodes,
 		      client_async_callback fail_callback, void *callback_data)
 {
 	int i, j, ret;
 	struct ctdb_public_ip ip;
 	uint32_t *nodes;
-	struct ctdb_public_ip_list *all_ips, *tmp_ip;
+	struct public_ip_list *all_ips, *tmp_ip;
 	TDB_DATA data;
 	struct timeval timeout;
 	struct client_async_data *async_data;
 	struct ctdb_client_control_state *state;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_ipflags *ipflags;
+	struct ipalloc_state *ipalloc_state;
 	struct takeover_callback_data *takeover_data;
 	struct iprealloc_callback_data iprealloc_data;
 	bool *retry_data;
@@ -2585,18 +1783,29 @@ int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap,
 		goto ipreallocated;
 	}
 
-	ipflags = set_ipflags(ctdb, tmp_ctx, nodemap);
-	if (ipflags == NULL) {
+	ipalloc_state = ipalloc_state_init(ctdb, tmp_ctx);
+	if (ipalloc_state == NULL) {
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (!set_ipflags(ctdb, ipalloc_state, nodemap)) {
 		DEBUG(DEBUG_ERR,("Failed to set IP flags - aborting takeover run\n"));
 		talloc_free(tmp_ctx);
 		return -1;
 	}
 
-	/* Short-circuit IP allocation if no nodes are in the RUNNING
-	 * runstate yet, since no nodes will be able to host IPs */
+	/* Fetch known/available public IPs from each active node */
+	ret = ctdb_reload_remote_public_ips(ctdb, ipalloc_state, nodemap);
+	if (ret != 0) {
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	/* Short-circuit IP allocation if no node has available IPs */
 	can_host_ips = false;
-	for (i=0; i<nodemap->num; i++) {
-		if (ipflags[i].runstate == CTDB_RUNSTATE_RUNNING) {
+	for (i=0; i < ipalloc_state->num; i++) {
+		if (ipalloc_state->available_public_ips[i] != NULL) {
 			can_host_ips = true;
 		}
 	}
@@ -2605,8 +1814,21 @@ int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap,
 		return 0;
 	}
 
+	/* since nodes only know about those public addresses that
+	   can be served by that particular node, no single node has
+	   a full list of all public addresses that exist in the cluster.
+	   Walk over all node structures and create a merged list of
+	   all public addresses that exist in the cluster.
+
+	   keep the tree of ips around as ctdb->ip_tree
+	*/
+	all_ips = create_merged_ip_list(ctdb, ipalloc_state);
+	ipalloc_state->all_ips = all_ips;
+
+	ipalloc_state->force_rebalance_nodes = force_rebalance_nodes;
+
 	/* Do the IP reassignment calculations */
-	ctdb_takeover_run_core(ctdb, ipflags, &all_ips, force_rebalance_nodes);
+	ipalloc(ipalloc_state);
 
 	/* Now tell all nodes to release any public IPs should not
 	 * host.  This will be a NOOP on nodes that don't currently
@@ -2645,7 +1867,7 @@ int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap,
 		for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
 			if (tmp_ip->pnn == nodemap->nodes[i].pnn) {
 				/* This node should be serving this
-				   vnn so dont tell it to release the ip
+				   vnn so don't tell it to release the ip
 				*/
 				continue;
 			}
@@ -2799,10 +2021,10 @@ static int ctdb_client_ip_destructor(struct ctdb_client_ip *ip)
 int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
 				TDB_DATA indata)
 {
-	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
-	struct ctdb_control_tcp_addr *tcp_sock = NULL;
+	struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
+	struct ctdb_connection *tcp_sock = NULL;
 	struct ctdb_tcp_list *tcp;
-	struct ctdb_tcp_connection t;
+	struct ctdb_connection t;
 	int ret;
 	TDB_DATA data;
 	struct ctdb_client_ip *ip;
@@ -2814,15 +2036,15 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
 		return 0;
 	}
 
-	tcp_sock = (struct ctdb_control_tcp_addr *)indata.dptr;
+	tcp_sock = (struct ctdb_connection *)indata.dptr;
 
 	addr = tcp_sock->src;
 	ctdb_canonicalize_ip(&addr,  &tcp_sock->src);
-	addr = tcp_sock->dest;
-	ctdb_canonicalize_ip(&addr, &tcp_sock->dest);
+	addr = tcp_sock->dst;
+	ctdb_canonicalize_ip(&addr, &tcp_sock->dst);
 
 	ZERO_STRUCT(addr);
-	memcpy(&addr, &tcp_sock->dest, sizeof(addr));
+	memcpy(&addr, &tcp_sock->dst, sizeof(addr));
 	vnn = find_public_ip_vnn(ctdb, &addr);
 	if (vnn == NULL) {
 		switch (addr.sa.sa_family) {
@@ -2863,13 +2085,13 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
 	tcp = talloc(client, struct ctdb_tcp_list);
 	CTDB_NO_MEMORY(ctdb, tcp);
 
-	tcp->connection.src_addr = tcp_sock->src;
-	tcp->connection.dst_addr = tcp_sock->dest;
+	tcp->connection.src = tcp_sock->src;
+	tcp->connection.dst = tcp_sock->dst;
 
 	DLIST_ADD(client->tcp_list, tcp);
 
-	t.src_addr = tcp_sock->src;
-	t.dst_addr = tcp_sock->dest;
+	t.src = tcp_sock->src;
+	t.dst = tcp_sock->dst;
 
 	data.dptr = (uint8_t *)&t;
 	data.dsize = sizeof(t);
@@ -2877,13 +2099,13 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
 	switch (addr.sa.sa_family) {
 	case AF_INET:
 		DEBUG(DEBUG_INFO,("registered tcp client for %u->%s:%u (client_id %u pid %u)\n",
-			(unsigned)ntohs(tcp_sock->dest.ip.sin_port), 
+			(unsigned)ntohs(tcp_sock->dst.ip.sin_port),
 			ctdb_addr_to_str(&tcp_sock->src),
 			(unsigned)ntohs(tcp_sock->src.ip.sin_port), client_id, client->pid));
 		break;
 	case AF_INET6:
 		DEBUG(DEBUG_INFO,("registered tcp client for %u->%s:%u (client_id %u pid %u)\n",
-			(unsigned)ntohs(tcp_sock->dest.ip6.sin6_port), 
+			(unsigned)ntohs(tcp_sock->dst.ip6.sin6_port),
 			ctdb_addr_to_str(&tcp_sock->src),
 			(unsigned)ntohs(tcp_sock->src.ip6.sin6_port), client_id, client->pid));
 		break;
@@ -2907,8 +2129,8 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
 /*
   find a tcp address on a list
  */
-static struct ctdb_tcp_connection *ctdb_tcp_find(struct ctdb_tcp_array *array, 
-					   struct ctdb_tcp_connection *tcp)
+static struct ctdb_connection *ctdb_tcp_find(struct ctdb_tcp_array *array,
+					   struct ctdb_connection *tcp)
 {
 	int i;
 
@@ -2917,8 +2139,8 @@ static struct ctdb_tcp_connection *ctdb_tcp_find(struct ctdb_tcp_array *array,
 	}
 
 	for (i=0;i<array->num;i++) {
-		if (ctdb_same_sockaddr(&array->connections[i].src_addr, &tcp->src_addr) &&
-		    ctdb_same_sockaddr(&array->connections[i].dst_addr, &tcp->dst_addr)) {
+		if (ctdb_same_sockaddr(&array->connections[i].src, &tcp->src) &&
+		    ctdb_same_sockaddr(&array->connections[i].dst, &tcp->dst)) {
 			return &array->connections[i];
 		}
 	}
@@ -2934,9 +2156,9 @@ static struct ctdb_tcp_connection *ctdb_tcp_find(struct ctdb_tcp_array *array,
  */
 int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tcp_update_needed)
 {
-	struct ctdb_tcp_connection *p = (struct ctdb_tcp_connection *)indata.dptr;
+	struct ctdb_connection *p = (struct ctdb_connection *)indata.dptr;
 	struct ctdb_tcp_array *tcparray;
-	struct ctdb_tcp_connection tcp;
+	struct ctdb_connection tcp;
 	struct ctdb_vnn *vnn;
 
 	/* If we don't have public IPs, tickles are useless */
@@ -2944,10 +2166,10 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tc
 		return 0;
 	}
 
-	vnn = find_public_ip_vnn(ctdb, &p->dst_addr);
+	vnn = find_public_ip_vnn(ctdb, &p->dst);
 	if (vnn == NULL) {
 		DEBUG(DEBUG_INFO,(__location__ " got TCP_ADD control for an address which is not a public address '%s'\n",
-			ctdb_addr_to_str(&p->dst_addr)));
+			ctdb_addr_to_str(&p->dst)));
 
 		return -1;
 	}
@@ -2962,11 +2184,11 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tc
 		vnn->tcp_array = tcparray;
 
 		tcparray->num = 0;
-		tcparray->connections = talloc_size(tcparray, sizeof(struct ctdb_tcp_connection));
+		tcparray->connections = talloc_size(tcparray, sizeof(struct ctdb_connection));
 		CTDB_NO_MEMORY(ctdb, tcparray->connections);
 
-		tcparray->connections[tcparray->num].src_addr = p->src_addr;
-		tcparray->connections[tcparray->num].dst_addr = p->dst_addr;
+		tcparray->connections[tcparray->num].src = p->src;
+		tcparray->connections[tcparray->num].dst = p->dst;
 		tcparray->num++;
 
 		if (tcp_update_needed) {
@@ -2977,29 +2199,29 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tc
 
 
 	/* Do we already have this tickle ?*/
-	tcp.src_addr = p->src_addr;
-	tcp.dst_addr = p->dst_addr;
+	tcp.src = p->src;
+	tcp.dst = p->dst;
 	if (ctdb_tcp_find(tcparray, &tcp) != NULL) {
 		DEBUG(DEBUG_DEBUG,("Already had tickle info for %s:%u for vnn:%u\n",
-			ctdb_addr_to_str(&tcp.dst_addr),
-			ntohs(tcp.dst_addr.ip.sin_port),
+			ctdb_addr_to_str(&tcp.dst),
+			ntohs(tcp.dst.ip.sin_port),
 			vnn->pnn));
 		return 0;
 	}
 
 	/* A new tickle, we must add it to the array */
 	tcparray->connections = talloc_realloc(tcparray, tcparray->connections,
-					struct ctdb_tcp_connection,
+					struct ctdb_connection,
 					tcparray->num+1);
 	CTDB_NO_MEMORY(ctdb, tcparray->connections);
 
-	tcparray->connections[tcparray->num].src_addr = p->src_addr;
-	tcparray->connections[tcparray->num].dst_addr = p->dst_addr;
+	tcparray->connections[tcparray->num].src = p->src;
+	tcparray->connections[tcparray->num].dst = p->dst;
 	tcparray->num++;
 
 	DEBUG(DEBUG_INFO,("Added tickle info for %s:%u from vnn %u\n",
-		ctdb_addr_to_str(&tcp.dst_addr),
-		ntohs(tcp.dst_addr.ip.sin_port),
+		ctdb_addr_to_str(&tcp.dst),
+		ntohs(tcp.dst.ip.sin_port),
 		vnn->pnn));
 
 	if (tcp_update_needed) {
@@ -3010,41 +2232,33 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tc
 }
 
 
-/*
-  called by a daemon to inform us of a TCP connection that one of its
-  clients managing that should tickled with an ACK when IP takeover is
-  done
- */
-static void ctdb_remove_tcp_connection(struct ctdb_context *ctdb, struct ctdb_tcp_connection *conn)
+static void ctdb_remove_connection(struct ctdb_vnn *vnn, struct ctdb_connection *conn)
 {
-	struct ctdb_tcp_connection *tcpp;
-	struct ctdb_vnn *vnn = find_public_ip_vnn(ctdb, &conn->dst_addr);
+	struct ctdb_connection *tcpp;
 
 	if (vnn == NULL) {
-		DEBUG(DEBUG_ERR,(__location__ " unable to find public address %s\n",
-			ctdb_addr_to_str(&conn->dst_addr)));
 		return;
 	}
 
 	/* if the array is empty we cant remove it
-	   and we dont need to do anything
+	   and we don't need to do anything
 	 */
 	if (vnn->tcp_array == NULL) {
 		DEBUG(DEBUG_INFO,("Trying to remove tickle that doesnt exist (array is empty) %s:%u\n",
-			ctdb_addr_to_str(&conn->dst_addr),
-			ntohs(conn->dst_addr.ip.sin_port)));
+			ctdb_addr_to_str(&conn->dst),
+			ntohs(conn->dst.ip.sin_port)));
 		return;
 	}
 
 
 	/* See if we know this connection
-	   if we dont know this connection  then we dont need to do anything
+	   if we don't know this connection  then we dont need to do anything
 	 */
 	tcpp = ctdb_tcp_find(vnn->tcp_array, conn);
 	if (tcpp == NULL) {
 		DEBUG(DEBUG_INFO,("Trying to remove tickle that doesnt exist %s:%u\n",
-			ctdb_addr_to_str(&conn->dst_addr),
-			ntohs(conn->dst_addr.ip.sin_port)));
+			ctdb_addr_to_str(&conn->dst),
+			ntohs(conn->dst.ip.sin_port)));
 		return;
 	}
 
@@ -3068,8 +2282,8 @@ static void ctdb_remove_tcp_connection(struct ctdb_context *ctdb, struct ctdb_tc
 	vnn->tcp_update_needed = true;
 
 	DEBUG(DEBUG_INFO,("Removed tickle info for %s:%u\n",
-		ctdb_addr_to_str(&conn->src_addr),
-		ntohs(conn->src_addr.ip.sin_port)));
+		ctdb_addr_to_str(&conn->src),
+		ntohs(conn->src.ip.sin_port)));
 }
 
 
@@ -3079,14 +2293,23 @@ static void ctdb_remove_tcp_connection(struct ctdb_context *ctdb, struct ctdb_tc
  */
 int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-	struct ctdb_tcp_connection *conn = (struct ctdb_tcp_connection *)indata.dptr;
+	struct ctdb_vnn *vnn;
+	struct ctdb_connection *conn = (struct ctdb_connection *)indata.dptr;
 
 	/* If we don't have public IPs, tickles are useless */
 	if (ctdb->vnn == NULL) {
 		return 0;
 	}
 
-	ctdb_remove_tcp_connection(ctdb, conn);
+	vnn = find_public_ip_vnn(ctdb, &conn->dst);
+	if (vnn == NULL) {
+		DEBUG(DEBUG_ERR,
+		      (__location__ " unable to find public address %s\n",
+		       ctdb_addr_to_str(&conn->dst)));
+		return 0;
+	}
+
+	ctdb_remove_connection(vnn, conn);
 
 	return 0;
 }
@@ -3121,9 +2344,32 @@ int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t pnn)
 void ctdb_takeover_client_destructor_hook(struct ctdb_client *client)
 {
 	while (client->tcp_list) {
+		struct ctdb_vnn *vnn;
 		struct ctdb_tcp_list *tcp = client->tcp_list;
+		struct ctdb_connection *conn = &tcp->connection;
+
 		DLIST_REMOVE(client->tcp_list, tcp);
-		ctdb_remove_tcp_connection(client->ctdb, &tcp->connection);
+
+		vnn = find_public_ip_vnn(client->ctdb,
+					 &conn->dst);
+		if (vnn == NULL) {
+			DEBUG(DEBUG_ERR,
+			      (__location__ " unable to find public address %s\n",
+			       ctdb_addr_to_str(&conn->dst)));
+			continue;
+		}
+
+		/* If the IP address is hosted on this node then
+		 * remove the connection. */
+		if (vnn->pnn == client->ctdb->pnn) {
+			ctdb_remove_connection(vnn, conn);
+		}
+
+		/* Otherwise this function has been called because the
+		 * server IP address has been released to another node
+		 * and the client has exited.  This means that we
+		 * should not delete the connection information.  The
+		 * takeover node processes connections too. */
 	}
 }
 
@@ -3183,10 +2429,10 @@ void ctdb_release_all_ips(struct ctdb_context *ctdb)
   get list of public IPs
  */
 int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb, 
-				    struct ctdb_req_control *c, TDB_DATA *outdata)
+				    struct ctdb_req_control_old *c, TDB_DATA *outdata)
 {
 	int i, num, len;
-	struct ctdb_all_public_ips *ips;
+	struct ctdb_public_ip_list_old *ips;
 	struct ctdb_vnn *vnn;
 	bool only_available = false;
 
@@ -3200,7 +2446,7 @@ int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb,
 		num++;
 	}
 
-	len = offsetof(struct ctdb_all_public_ips, ips) + 
+	len = offsetof(struct ctdb_public_ip_list_old, ips) +
 		num*sizeof(struct ctdb_public_ip);
 	ips = talloc_zero_size(outdata, len);
 	CTDB_NO_MEMORY(ctdb, ips);
@@ -3215,7 +2461,7 @@ int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb,
 		i++;
 	}
 	ips->num = i;
-	len = offsetof(struct ctdb_all_public_ips, ips) +
+	len = offsetof(struct ctdb_public_ip_list_old, ips) +
 		i*sizeof(struct ctdb_public_ip);
 
 	outdata->dsize = len;
@@ -3226,13 +2472,13 @@ int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb,
 
 
 int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
-					struct ctdb_req_control *c,
+					struct ctdb_req_control_old *c,
 					TDB_DATA indata,
 					TDB_DATA *outdata)
 {
 	int i, num, len;
 	ctdb_sock_addr *addr;
-	struct ctdb_control_public_ip_info *info;
+	struct ctdb_public_ip_info_old *info;
 	struct ctdb_vnn *vnn;
 
 	addr = (ctdb_sock_addr *)indata.dptr;
@@ -3259,8 +2505,8 @@ int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
 		num++;
 	}
 
-	len = offsetof(struct ctdb_control_public_ip_info, ifaces) +
-		num*sizeof(struct ctdb_control_iface_info);
+	len = offsetof(struct ctdb_public_ip_info_old, ifaces) +
+		num*sizeof(struct ctdb_iface);
 	info = talloc_zero_size(outdata, len);
 	CTDB_NO_MEMORY(ctdb, info);
 
@@ -3269,7 +2515,7 @@ int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
 	info->active_idx = 0xFFFFFFFF;
 
 	for (i=0; vnn->ifaces[i]; i++) {
-		struct ctdb_iface *cur;
+		struct ctdb_interface *cur;
 
 		cur = ctdb_find_iface(ctdb, vnn->ifaces[i]);
 		if (cur == NULL) {
@@ -3285,8 +2531,8 @@ int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
 		info->ifaces[i].references = cur->references;
 	}
 	info->num = i;
-	len = offsetof(struct ctdb_control_public_ip_info, ifaces) +
-		i*sizeof(struct ctdb_control_iface_info);
+	len = offsetof(struct ctdb_public_ip_info_old, ifaces) +
+		i*sizeof(struct ctdb_iface);
 
 	outdata->dsize = len;
 	outdata->dptr  = (uint8_t *)info;
@@ -3295,12 +2541,12 @@ int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
 }
 
 int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
-				struct ctdb_req_control *c,
+				struct ctdb_req_control_old *c,
 				TDB_DATA *outdata)
 {
 	int i, num, len;
-	struct ctdb_control_get_ifaces *ifaces;
-	struct ctdb_iface *cur;
+	struct ctdb_iface_list_old *ifaces;
+	struct ctdb_interface *cur;
 
 	/* count how many public ip structures we have */
 	num = 0;
@@ -3308,8 +2554,8 @@ int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
 		num++;
 	}
 
-	len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
-		num*sizeof(struct ctdb_control_iface_info);
+	len = offsetof(struct ctdb_iface_list_old, ifaces) +
+		num*sizeof(struct ctdb_iface);
 	ifaces = talloc_zero_size(outdata, len);
 	CTDB_NO_MEMORY(ctdb, ifaces);
 
@@ -3321,8 +2567,8 @@ int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
 		i++;
 	}
 	ifaces->num = i;
-	len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
-		i*sizeof(struct ctdb_control_iface_info);
+	len = offsetof(struct ctdb_iface_list_old, ifaces) +
+		i*sizeof(struct ctdb_iface);
 
 	outdata->dsize = len;
 	outdata->dptr  = (uint8_t *)ifaces;
@@ -3331,14 +2577,14 @@ int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
 }
 
 int32_t ctdb_control_set_iface_link(struct ctdb_context *ctdb,
-				    struct ctdb_req_control *c,
+				    struct ctdb_req_control_old *c,
 				    TDB_DATA indata)
 {
-	struct ctdb_control_iface_info *info;
-	struct ctdb_iface *iface;
+	struct ctdb_iface *info;
+	struct ctdb_interface *iface;
 	bool link_up = false;
 
-	info = (struct ctdb_control_iface_info *)indata.dptr;
+	info = (struct ctdb_iface *)indata.dptr;
 
 	if (info->name[CTDB_IFACE_SIZE] != '\0') {
 		int len = strnlen(info->name, CTDB_IFACE_SIZE);
@@ -3394,7 +2640,7 @@ struct ctdb_kill_tcp {
 	struct ctdb_vnn *vnn;
 	struct ctdb_context *ctdb;
 	int capture_fd;
-	struct fd_event *fde;
+	struct tevent_fd *fde;
 	trbt_tree_t *connections;
 	void *private_data;
 };
@@ -3461,7 +2707,8 @@ static uint32_t *killtcp_key(ctdb_sock_addr *src, ctdb_sock_addr *dst)
 /*
   called when we get a read event on the raw socket
  */
-static void capture_tcp_handler(struct event_context *ev, struct fd_event *fde, 
+static void capture_tcp_handler(struct tevent_context *ev,
+				struct tevent_fd *fde,
 				uint16_t flags, void *private_data)
 {
 	struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
@@ -3469,7 +2716,7 @@ static void capture_tcp_handler(struct event_context *ev, struct fd_event *fde,
 	ctdb_sock_addr src, dst;
 	uint32_t ack_seq, seq;
 
-	if (!(flags & EVENT_FD_READ)) {
+	if (!(flags & TEVENT_FD_READ)) {
 		return;
 	}
 
@@ -3533,7 +2780,8 @@ static int tickle_connection_traverse(void *param, void *data)
 /* 
    called every second until all sentenced connections have been reset
  */
-static void ctdb_tickle_sentenced_connections(struct event_context *ev, struct timed_event *te, 
+static void ctdb_tickle_sentenced_connections(struct tevent_context *ev,
+					      struct tevent_timer *te,
 					      struct timeval t, void *private_data)
 {
 	struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
@@ -3556,8 +2804,9 @@ static void ctdb_tickle_sentenced_connections(struct event_context *ev, struct t
 
 	/* try tickling them again in a seconds time
 	 */
-	event_add_timed(killtcp->ctdb->ev, killtcp, timeval_current_ofs(1, 0), 
-			ctdb_tickle_sentenced_connections, killtcp);
+	tevent_add_timer(killtcp->ctdb->ev, killtcp,
+			 timeval_current_ofs(1, 0),
+			 ctdb_tickle_sentenced_connections, killtcp);
 }
 
 /*
@@ -3591,7 +2840,7 @@ static int ctdb_killtcp_destructor(struct ctdb_kill_tcp *killtcp)
 /* nothing fancy here, just unconditionally replace any existing
    connection structure with the new one.
 
-   dont even free the old one if it did exist, that one is talloc_stolen
+   don't even free the old one if it did exist, that one is talloc_stolen
    by the same node in the tree anyway and will be deleted when the new data 
    is deleted
 */
@@ -3668,7 +2917,7 @@ static int ctdb_killtcp_add_connection(struct ctdb_context *ctdb,
 			add_killtcp_callback, con);
 
 	/* 
-	   If we dont have a socket to listen on yet we must create it
+	   If we don't have a socket to listen on yet we must create it
 	 */
 	if (killtcp->capture_fd == -1) {
 		const char *iface = ctdb_vnn_iface_string(vnn);
@@ -3683,16 +2932,17 @@ static int ctdb_killtcp_add_connection(struct ctdb_context *ctdb,
 
 
 	if (killtcp->fde == NULL) {
-		killtcp->fde = event_add_fd(ctdb->ev, killtcp, killtcp->capture_fd, 
-					    EVENT_FD_READ,
-					    capture_tcp_handler, killtcp);
+		killtcp->fde = tevent_add_fd(ctdb->ev, killtcp,
+					     killtcp->capture_fd,
+					     TEVENT_FD_READ,
+					     capture_tcp_handler, killtcp);
 		tevent_fd_set_auto_close(killtcp->fde);
 
 		/* We also need to set up some events to tickle all these connections
 		   until they are all reset
 		*/
-		event_add_timed(ctdb->ev, killtcp, timeval_current_ofs(1, 0), 
-				ctdb_tickle_sentenced_connections, killtcp);
+		tevent_add_timer(ctdb->ev, killtcp, timeval_current_ofs(1, 0),
+				 ctdb_tickle_sentenced_connections, killtcp);
 	}
 
 	/* tickle him once now */
@@ -3714,9 +2964,9 @@ failed:
  */
 int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-	struct ctdb_control_killtcp *killtcp = (struct ctdb_control_killtcp *)indata.dptr;
+	struct ctdb_connection *killtcp = (struct ctdb_connection *)indata.dptr;
 
-	return ctdb_killtcp_add_connection(ctdb, &killtcp->src_addr, &killtcp->dst_addr);
+	return ctdb_killtcp_add_connection(ctdb, &killtcp->src, &killtcp->dst);
 }
 
 /*
@@ -3727,25 +2977,22 @@ int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata)
  */
 int32_t ctdb_control_set_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-	struct ctdb_control_tcp_tickle_list *list = (struct ctdb_control_tcp_tickle_list *)indata.dptr;
+	struct ctdb_tickle_list_old *list = (struct ctdb_tickle_list_old *)indata.dptr;
 	struct ctdb_tcp_array *tcparray;
 	struct ctdb_vnn *vnn;
 
 	/* We must at least have tickles.num or else we cant verify the size
 	   of the received data blob
 	 */
-	if (indata.dsize < offsetof(struct ctdb_control_tcp_tickle_list, 
-					tickles.connections)) {
-		DEBUG(DEBUG_ERR,("Bad indata in ctdb_control_set_tcp_tickle_list. Not enough data for the tickle.num field\n"));
+	if (indata.dsize < offsetof(struct ctdb_tickle_list_old, connections)) {
+		DEBUG(DEBUG_ERR,("Bad indata in ctdb_tickle_list. Not enough data for the tickle.num field\n"));
 		return -1;
 	}
 
 	/* verify that the size of data matches what we expect */
-	if (indata.dsize < offsetof(struct ctdb_control_tcp_tickle_list, 
-				tickles.connections)
-			 + sizeof(struct ctdb_tcp_connection)
-				 * list->tickles.num) {
-		DEBUG(DEBUG_ERR,("Bad indata in ctdb_control_set_tcp_tickle_list\n"));
+	if (indata.dsize < offsetof(struct ctdb_tickle_list_old, connections)
+			 + sizeof(struct ctdb_connection) * list->num) {
+		DEBUG(DEBUG_ERR,("Bad indata in ctdb_tickle_list\n"));
 		return -1;
 	}
 
@@ -3760,6 +3007,13 @@ int32_t ctdb_control_set_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA ind
 		return 1;
 	}
 
+	if (vnn->pnn == ctdb->pnn) {
+		DEBUG(DEBUG_INFO,
+		      ("Ignoring redundant set tcp tickle list, this node hosts '%s'\n",
+		       ctdb_addr_to_str(&list->addr)));
+		return 0;
+	}
+
 	/* remove any old ticklelist we might have */
 	talloc_free(vnn->tcp_array);
 	vnn->tcp_array = NULL;
@@ -3767,13 +3021,13 @@ int32_t ctdb_control_set_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA ind
 	tcparray = talloc(vnn, struct ctdb_tcp_array);
 	CTDB_NO_MEMORY(ctdb, tcparray);
 
-	tcparray->num = list->tickles.num;
+	tcparray->num = list->num;
 
-	tcparray->connections = talloc_array(tcparray, struct ctdb_tcp_connection, tcparray->num);
+	tcparray->connections = talloc_array(tcparray, struct ctdb_connection, tcparray->num);
 	CTDB_NO_MEMORY(ctdb, tcparray->connections);
 
-	memcpy(tcparray->connections, &list->tickles.connections[0],
-	       sizeof(struct ctdb_tcp_connection)*tcparray->num);
+	memcpy(tcparray->connections, &list->connections[0],
+	       sizeof(struct ctdb_connection)*tcparray->num);
 
 	/* We now have a new fresh tickle list array for this vnn */
 	vnn->tcp_array = tcparray;
@@ -3788,7 +3042,7 @@ int32_t ctdb_control_set_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA ind
 int32_t ctdb_control_get_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata)
 {
 	ctdb_sock_addr *addr = (ctdb_sock_addr *)indata.dptr;
-	struct ctdb_control_tcp_tickle_list *list;
+	struct ctdb_tickle_list_old *list;
 	struct ctdb_tcp_array *tcparray;
 	int num;
 	struct ctdb_vnn *vnn;
@@ -3808,19 +3062,18 @@ int32_t ctdb_control_get_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA ind
 		num = 0;
 	}
 
-	outdata->dsize = offsetof(struct ctdb_control_tcp_tickle_list, 
-				tickles.connections)
-			+ sizeof(struct ctdb_tcp_connection) * num;
+	outdata->dsize = offsetof(struct ctdb_tickle_list_old, connections)
+			+ sizeof(struct ctdb_connection) * num;
 
 	outdata->dptr  = talloc_size(outdata, outdata->dsize);
 	CTDB_NO_MEMORY(ctdb, outdata->dptr);
-	list = (struct ctdb_control_tcp_tickle_list *)outdata->dptr;
+	list = (struct ctdb_tickle_list_old *)outdata->dptr;
 
 	list->addr = *addr;
-	list->tickles.num = num;
+	list->num = num;
 	if (num) {
-		memcpy(&list->tickles.connections[0], tcparray->connections, 
-			sizeof(struct ctdb_tcp_connection) * num);
+		memcpy(&list->connections[0], tcparray->connections,
+			sizeof(struct ctdb_connection) * num);
 	}
 
 	return 0;
@@ -3836,7 +3089,7 @@ static int ctdb_send_set_tcp_tickles_for_ip(struct ctdb_context *ctdb,
 {
 	int ret, num;
 	TDB_DATA data;
-	struct ctdb_control_tcp_tickle_list *list;
+	struct ctdb_tickle_list_old *list;
 
 	if (tcparray) {
 		num = tcparray->num;
@@ -3844,17 +3097,16 @@ static int ctdb_send_set_tcp_tickles_for_ip(struct ctdb_context *ctdb,
 		num = 0;
 	}
 
-	data.dsize = offsetof(struct ctdb_control_tcp_tickle_list, 
-				tickles.connections) +
-			sizeof(struct ctdb_tcp_connection) * num;
+	data.dsize = offsetof(struct ctdb_tickle_list_old, connections) +
+			sizeof(struct ctdb_connection) * num;
 	data.dptr = talloc_size(ctdb, data.dsize);
 	CTDB_NO_MEMORY(ctdb, data.dptr);
 
-	list = (struct ctdb_control_tcp_tickle_list *)data.dptr;
+	list = (struct ctdb_tickle_list_old *)data.dptr;
 	list->addr = *addr;
-	list->tickles.num = num;
+	list->num = num;
 	if (tcparray) {
-		memcpy(&list->tickles.connections[0], tcparray->connections, sizeof(struct ctdb_tcp_connection) * num);
+		memcpy(&list->connections[0], tcparray->connections, sizeof(struct ctdb_connection) * num);
 	}
 
 	ret = ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_ALL, 0,
@@ -3874,9 +3126,9 @@ static int ctdb_send_set_tcp_tickles_for_ip(struct ctdb_context *ctdb,
 /*
   perform tickle updates if required
  */
-static void ctdb_update_tcp_tickles(struct event_context *ev, 
-				struct timed_event *te, 
-				struct timeval t, void *private_data)
+static void ctdb_update_tcp_tickles(struct tevent_context *ev,
+				    struct tevent_timer *te,
+				    struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
 	int ret;
@@ -3907,11 +3159,10 @@ static void ctdb_update_tcp_tickles(struct event_context *ev,
 		}
 	}
 
-	event_add_timed(ctdb->ev, ctdb->tickle_update_context,
-			     timeval_current_ofs(ctdb->tunable.tickle_update_interval, 0), 
-			     ctdb_update_tcp_tickles, ctdb);
-}		
-	
+	tevent_add_timer(ctdb->ev, ctdb->tickle_update_context,
+			 timeval_current_ofs(ctdb->tunable.tickle_update_interval, 0),
+			 ctdb_update_tcp_tickles, ctdb);
+}
 
 /*
   start periodic update of tcp tickles
@@ -3920,9 +3171,9 @@ void ctdb_start_tcp_tickle_update(struct ctdb_context *ctdb)
 {
 	ctdb->tickle_update_context = talloc_new(ctdb);
 
-	event_add_timed(ctdb->ev, ctdb->tickle_update_context,
-			     timeval_current_ofs(ctdb->tunable.tickle_update_interval, 0), 
-			     ctdb_update_tcp_tickles, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb->tickle_update_context,
+			 timeval_current_ofs(ctdb->tunable.tickle_update_interval, 0),
+			 ctdb_update_tcp_tickles, ctdb);
 }
 
 
@@ -3938,8 +3189,9 @@ struct control_gratious_arp {
 /*
   send a control_gratuitous arp
  */
-static void send_gratious_arp(struct event_context *ev, struct timed_event *te, 
-				  struct timeval t, void *private_data)
+static void send_gratious_arp(struct tevent_context *ev,
+			      struct tevent_timer *te,
+			      struct timeval t, void *private_data)
 {
 	int ret;
 	struct control_gratious_arp *arp = talloc_get_type(private_data, 
@@ -3958,9 +3210,9 @@ static void send_gratious_arp(struct event_context *ev, struct timed_event *te,
 		return;
 	}
 
-	event_add_timed(arp->ctdb->ev, arp, 
-			timeval_current_ofs(CTDB_ARP_INTERVAL, 0), 
-			send_gratious_arp, arp);
+	tevent_add_timer(arp->ctdb->ev, arp,
+			 timeval_current_ofs(CTDB_ARP_INTERVAL, 0),
+			 send_gratious_arp, arp);
 }
 
 
@@ -3969,24 +3221,24 @@ static void send_gratious_arp(struct event_context *ev, struct timed_event *te,
  */
 int32_t ctdb_control_send_gratious_arp(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-	struct ctdb_control_gratious_arp *gratious_arp = (struct ctdb_control_gratious_arp *)indata.dptr;
+	struct ctdb_addr_info_old *gratious_arp = (struct ctdb_addr_info_old *)indata.dptr;
 	struct control_gratious_arp *arp;
 
 	/* verify the size of indata */
-	if (indata.dsize < offsetof(struct ctdb_control_gratious_arp, iface)) {
+	if (indata.dsize < offsetof(struct ctdb_addr_info_old, iface)) {
 		DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_gratious_arp structure. Got %u require %u bytes\n", 
 				 (unsigned)indata.dsize, 
-				 (unsigned)offsetof(struct ctdb_control_gratious_arp, iface)));
+				 (unsigned)offsetof(struct ctdb_addr_info_old, iface)));
 		return -1;
 	}
 	if (indata.dsize != 
-		( offsetof(struct ctdb_control_gratious_arp, iface)
+		( offsetof(struct ctdb_addr_info_old, iface)
 		+ gratious_arp->len ) ){
 
 		DEBUG(DEBUG_ERR,(__location__ " Wrong size of indata. Was %u bytes "
 			"but should be %u bytes\n", 
 			 (unsigned)indata.dsize, 
-			 (unsigned)(offsetof(struct ctdb_control_gratious_arp, iface)+gratious_arp->len)));
+			 (unsigned)(offsetof(struct ctdb_addr_info_old, iface)+gratious_arp->len)));
 		return -1;
 	}
 
@@ -3999,31 +3251,31 @@ int32_t ctdb_control_send_gratious_arp(struct ctdb_context *ctdb, TDB_DATA indat
 	arp->iface = talloc_strdup(arp, gratious_arp->iface);
 	CTDB_NO_MEMORY(ctdb, arp->iface);
 	arp->count = 0;
-	
-	event_add_timed(arp->ctdb->ev, arp, 
-			timeval_zero(), send_gratious_arp, arp);
+
+	tevent_add_timer(arp->ctdb->ev, arp,
+			 timeval_zero(), send_gratious_arp, arp);
 
 	return 0;
 }
 
 int32_t ctdb_control_add_public_address(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-	struct ctdb_control_ip_iface *pub = (struct ctdb_control_ip_iface *)indata.dptr;
+	struct ctdb_addr_info_old *pub = (struct ctdb_addr_info_old *)indata.dptr;
 	int ret;
 
 	/* verify the size of indata */
-	if (indata.dsize < offsetof(struct ctdb_control_ip_iface, iface)) {
-		DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_ip_iface structure\n"));
+	if (indata.dsize < offsetof(struct ctdb_addr_info_old, iface)) {
+		DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_addr_info structure\n"));
 		return -1;
 	}
 	if (indata.dsize != 
-		( offsetof(struct ctdb_control_ip_iface, iface)
+		( offsetof(struct ctdb_addr_info_old, iface)
 		+ pub->len ) ){
 
 		DEBUG(DEBUG_ERR,(__location__ " Wrong size of indata. Was %u bytes "
 			"but should be %u bytes\n", 
 			 (unsigned)indata.dsize, 
-			 (unsigned)(offsetof(struct ctdb_control_ip_iface, iface)+pub->len)));
+			 (unsigned)(offsetof(struct ctdb_addr_info_old, iface)+pub->len)));
 		return -1;
 	}
 
@@ -4040,7 +3292,7 @@ int32_t ctdb_control_add_public_address(struct ctdb_context *ctdb, TDB_DATA inda
 }
 
 struct delete_ip_callback_state {
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 };
 
 /*
@@ -4060,25 +3312,25 @@ static void delete_ip_callback(struct ctdb_context *ctdb,
 }
 
 int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb,
-					struct ctdb_req_control *c,
+					struct ctdb_req_control_old *c,
 					TDB_DATA indata, bool *async_reply)
 {
-	struct ctdb_control_ip_iface *pub = (struct ctdb_control_ip_iface *)indata.dptr;
+	struct ctdb_addr_info_old *pub = (struct ctdb_addr_info_old *)indata.dptr;
 	struct ctdb_vnn *vnn;
 
 	/* verify the size of indata */
-	if (indata.dsize < offsetof(struct ctdb_control_ip_iface, iface)) {
-		DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_ip_iface structure\n"));
+	if (indata.dsize < offsetof(struct ctdb_addr_info_old, iface)) {
+		DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_addr_info structure\n"));
 		return -1;
 	}
 	if (indata.dsize != 
-		( offsetof(struct ctdb_control_ip_iface, iface)
+		( offsetof(struct ctdb_addr_info_old, iface)
 		+ pub->len ) ){
 
 		DEBUG(DEBUG_ERR,(__location__ " Wrong size of indata. Was %u bytes "
 			"but should be %u bytes\n", 
 			 (unsigned)indata.dsize, 
-			 (unsigned)(offsetof(struct ctdb_control_ip_iface, iface)+pub->len)));
+			 (unsigned)(offsetof(struct ctdb_addr_info_old, iface)+pub->len)));
 		return -1;
 	}
 
@@ -4149,7 +3401,7 @@ int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb,
 
 
 struct ipreallocated_callback_state {
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 };
 
 static void ctdb_ipreallocated_callback(struct ctdb_context *ctdb,
@@ -4173,7 +3425,7 @@ static void ctdb_ipreallocated_callback(struct ctdb_context *ctdb,
 
 /* A control to run the ipreallocated event */
 int32_t ctdb_control_ipreallocated(struct ctdb_context *ctdb,
-				   struct ctdb_req_control *c,
+				   struct ctdb_req_control_old *c,
 				   bool *async_reply)
 {
 	int ret;
@@ -4207,15 +3459,15 @@ int32_t ctdb_control_ipreallocated(struct ctdb_context *ctdb,
    node has the expected ip allocation.
    This is verified against ctdb->ip_tree
 */
-int verify_remote_ip_allocation(struct ctdb_context *ctdb,
-				struct ctdb_all_public_ips *ips,
-				uint32_t pnn)
+static int verify_remote_ip_allocation(struct ctdb_context *ctdb,
+				       struct ctdb_public_ip_list_old *ips,
+				       uint32_t pnn)
 {
-	struct ctdb_public_ip_list *tmp_ip; 
+	struct public_ip_list *tmp_ip;
 	int i;
 
 	if (ctdb->ip_tree == NULL) {
-		/* dont know the expected allocation yet, assume remote node
+		/* don't know the expected allocation yet, assume remote node
 		   is correct. */
 		return 0;
 	}
@@ -4250,7 +3502,7 @@ int verify_remote_ip_allocation(struct ctdb_context *ctdb,
 
 int update_ip_assignment_tree(struct ctdb_context *ctdb, struct ctdb_public_ip *ip)
 {
-	struct ctdb_public_ip_list *tmp_ip;
+	struct public_ip_list *tmp_ip;
 
 	/* IP tree is never built if DisableIPFailover is set */
 	if (ctdb->tunable.disable_ip_failover != 0) {
@@ -4281,11 +3533,11 @@ void clear_ip_assignment_tree(struct ctdb_context *ctdb)
 
 struct ctdb_reloadips_handle {
 	struct ctdb_context *ctdb;
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	int status;
 	int fd[2];
 	pid_t child;
-	struct fd_event *fde;
+	struct tevent_fd *fde;
 };
 
 static int ctdb_reloadips_destructor(struct ctdb_reloadips_handle *h)
@@ -4301,17 +3553,18 @@ static int ctdb_reloadips_destructor(struct ctdb_reloadips_handle *h)
 	return 0;
 }
 
-static void ctdb_reloadips_timeout_event(struct event_context *ev,
-				struct timed_event *te,
-				struct timeval t, void *private_data)
+static void ctdb_reloadips_timeout_event(struct tevent_context *ev,
+					 struct tevent_timer *te,
+					 struct timeval t, void *private_data)
 {
 	struct ctdb_reloadips_handle *h = talloc_get_type(private_data, struct ctdb_reloadips_handle);
 
 	talloc_free(h);
-}	
+}
 
-static void ctdb_reloadips_child_handler(struct event_context *ev, struct fd_event *fde, 
-			     uint16_t flags, void *private_data)
+static void ctdb_reloadips_child_handler(struct tevent_context *ev,
+					 struct tevent_fd *fde,
+					 uint16_t flags, void *private_data)
 {
 	struct ctdb_reloadips_handle *h = talloc_get_type(private_data, struct ctdb_reloadips_handle);
 
@@ -4331,7 +3584,7 @@ static void ctdb_reloadips_child_handler(struct event_context *ev, struct fd_eve
 static int ctdb_reloadips_child(struct ctdb_context *ctdb)
 {
 	TALLOC_CTX *mem_ctx = talloc_new(NULL);
-	struct ctdb_all_public_ips *ips;
+	struct ctdb_public_ip_list_old *ips;
 	struct ctdb_vnn *vnn;
 	struct client_async_data *async_data;
 	struct timeval timeout;
@@ -4376,14 +3629,13 @@ static int ctdb_reloadips_child(struct ctdb_context *ctdb)
 
 		if (vnn == NULL) {
 			/* Delete IP ips->ips[i] */
-			struct ctdb_control_ip_iface *pub;
+			struct ctdb_addr_info_old *pub;
 
 			DEBUG(DEBUG_NOTICE,
 			      ("IP %s no longer configured, deleting it\n",
 			       ctdb_addr_to_str(&ips->ips[i].addr)));
 
-			pub = talloc_zero(mem_ctx,
-					  struct ctdb_control_ip_iface);
+			pub = talloc_zero(mem_ctx, struct ctdb_addr_info_old);
 			CTDB_NO_MEMORY(ctdb, pub);
 
 			pub->addr  = ips->ips[i].addr;
@@ -4392,7 +3644,7 @@ static int ctdb_reloadips_child(struct ctdb_context *ctdb)
 
 			timeout = TAKEOVER_TIMEOUT();
 
-			data.dsize = offsetof(struct ctdb_control_ip_iface,
+			data.dsize = offsetof(struct ctdb_addr_info_old,
 					      iface) + pub->len;
 			data.dptr = (uint8_t *)pub;
 
@@ -4423,7 +3675,7 @@ static int ctdb_reloadips_child(struct ctdb_context *ctdb)
 		}
 		if (i == ips->num) {
 			/* Add IP ips->ips[i] */
-			struct ctdb_control_ip_iface *pub;
+			struct ctdb_addr_info_old *pub;
 			const char *ifaces = NULL;
 			uint32_t len;
 			int iface = 0;
@@ -4460,7 +3712,7 @@ static int ctdb_reloadips_child(struct ctdb_context *ctdb)
 
 			len   = strlen(ifaces) + 1;
 			pub = talloc_zero_size(mem_ctx,
-					       offsetof(struct ctdb_control_ip_iface, iface) + len);
+					       offsetof(struct ctdb_addr_info_old, iface) + len);
 			CTDB_NO_MEMORY(ctdb, pub);
 
 			pub->addr  = vnn->public_address;
@@ -4470,7 +3722,7 @@ static int ctdb_reloadips_child(struct ctdb_context *ctdb)
 
 			timeout = TAKEOVER_TIMEOUT();
 
-			data.dsize = offsetof(struct ctdb_control_ip_iface,
+			data.dsize = offsetof(struct ctdb_addr_info_old,
 					      iface) + pub->len;
 			data.dptr = (uint8_t *)pub;
 
@@ -4506,7 +3758,7 @@ failed:
    and drop any addresses we should nnot longer host, and add new addresses
    that we are now able to host
 */
-int32_t ctdb_control_reload_public_ips(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply)
+int32_t ctdb_control_reload_public_ips(struct ctdb_context *ctdb, struct ctdb_req_control_old *c, bool *async_reply)
 {
 	struct ctdb_reloadips_handle *h;
 	pid_t parent = getpid();
@@ -4544,7 +3796,7 @@ int32_t ctdb_control_reload_public_ips(struct ctdb_context *ctdb, struct ctdb_re
 		close(h->fd[0]);
 		debug_extra = talloc_asprintf(NULL, "reloadips:");
 
-		ctdb_set_process_name("ctdb_reloadips");
+		prctl_set_comment("ctdb_reloadips");
 		if (switch_from_server_to_client(ctdb, "reloadips-child") != 0) {
 			DEBUG(DEBUG_CRIT,("ERROR: Failed to switch reloadips child into client mode\n"));
 			res = -1;
@@ -4571,14 +3823,12 @@ int32_t ctdb_control_reload_public_ips(struct ctdb_context *ctdb, struct ctdb_re
 	talloc_set_destructor(h, ctdb_reloadips_destructor);
 
 
-	h->fde = event_add_fd(ctdb->ev, h, h->fd[0],
-			EVENT_FD_READ, ctdb_reloadips_child_handler,
-			(void *)h);
+	h->fde = tevent_add_fd(ctdb->ev, h, h->fd[0], TEVENT_FD_READ,
+			       ctdb_reloadips_child_handler, (void *)h);
 	tevent_fd_set_auto_close(h->fde);
 
-	event_add_timed(ctdb->ev, h,
-			timeval_current_ofs(120, 0),
-			ctdb_reloadips_timeout_event, h);
+	tevent_add_timer(ctdb->ev, h, timeval_current_ofs(120, 0),
+			 ctdb_reloadips_timeout_event, h);
 
 	/* we reply later */
 	*async_reply = true;
diff --git a/ctdb/server/ctdb_traverse.c b/ctdb/server/ctdb_traverse.c
index d19305a..73c3a06 100644
--- a/ctdb/server/ctdb_traverse.c
+++ b/ctdb/server/ctdb_traverse.c
@@ -17,13 +17,28 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
 #include "system/wait.h"
+#include "system/time.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
-#include "tdb.h"
-#include "../include/ctdb_private.h"
 #include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/util_process.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/reqid.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 typedef void (*ctdb_traverse_fn_t)(void *private_data, TDB_DATA key, TDB_DATA data);
 
@@ -97,7 +112,7 @@ static int ctdb_traverse_local_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DAT
 {
 	struct ctdb_traverse_local_handle *h = talloc_get_type(p,
 							       struct ctdb_traverse_local_handle);
-	struct ctdb_rec_data *d;
+	struct ctdb_rec_data_old *d;
 	struct ctdb_ltdb_header *hdr;
 	int res, status;
 	TDB_DATA outdata;
@@ -198,12 +213,12 @@ static struct ctdb_traverse_local_handle *ctdb_traverse_local(struct ctdb_db_con
 		int res, status;
 		pid_t parent = getpid();
 		struct ctdb_context *ctdb = ctdb_db->ctdb;
-		struct ctdb_rec_data *d;
+		struct ctdb_rec_data_old *d;
 		TDB_DATA outdata;
 
 		close(h->fd[0]);
 
-		ctdb_set_process_name("ctdb_traverse");
+		prctl_set_comment("ctdb_traverse");
 		if (switch_from_server_to_client(ctdb, "traverse_local-%s:",
 						 ctdb_db->db_name) != 0) {
 			DEBUG(DEBUG_CRIT, ("Failed to switch traverse child into client mode\n"));
@@ -258,7 +273,7 @@ static struct ctdb_traverse_local_handle *ctdb_traverse_local(struct ctdb_db_con
 
 	DLIST_ADD(ctdb_db->traverse, h);
 
-	h->fde = tevent_add_fd(ctdb_db->ctdb->ev, h, h->fd[0], EVENT_FD_READ,
+	h->fde = tevent_add_fd(ctdb_db->ctdb->ev, h, h->fd[0], TEVENT_FD_READ,
 			       ctdb_traverse_child_handler, h);
 	if (h->fde == NULL) {
 		close(h->fd[0]);
@@ -286,29 +301,13 @@ struct ctdb_traverse_all_handle {
  */
 static int ctdb_traverse_all_destructor(struct ctdb_traverse_all_handle *state)
 {
-	ctdb_reqid_remove(state->ctdb, state->reqid);
+	reqid_remove(state->ctdb->idr, state->reqid);
 	return 0;
 }
 
-struct ctdb_traverse_all {
-	uint32_t db_id;
-	uint32_t reqid;
-	uint32_t pnn;
-	uint32_t client_reqid;
-	uint64_t srvid;
-};
-
-struct ctdb_traverse_all_ext {
-	uint32_t db_id;
-	uint32_t reqid;
-	uint32_t pnn;
-	uint32_t client_reqid;
-	uint64_t srvid;
-	bool withemptyrecords;
-};
-
 /* called when a traverse times out */
-static void ctdb_traverse_all_timeout(struct event_context *ev, struct timed_event *te, 
+static void ctdb_traverse_all_timeout(struct tevent_context *ev,
+				      struct tevent_timer *te,
 				      struct timeval t, void *private_data)
 {
 	struct ctdb_traverse_all_handle *state = talloc_get_type(private_data, struct ctdb_traverse_all_handle);
@@ -360,7 +359,7 @@ static struct ctdb_traverse_all_handle *ctdb_daemon_traverse_all(struct ctdb_db_
 
 	state->ctdb         = ctdb;
 	state->ctdb_db      = ctdb_db;
-	state->reqid        = ctdb_reqid_new(ctdb_db->ctdb, state);
+	state->reqid        = reqid_new(ctdb_db->ctdb->idr, state);
 	state->callback     = callback;
 	state->private_data = start_state;
 	state->null_count   = 0;
@@ -436,9 +435,9 @@ static struct ctdb_traverse_all_handle *ctdb_daemon_traverse_all(struct ctdb_db_
 			    ctdb_db->db_name, state->reqid));
 
 	/* timeout the traverse */
-	event_add_timed(ctdb->ev, state, 
-			timeval_current_ofs(ctdb->tunable.traverse_timeout, 0), 
-			ctdb_traverse_all_timeout, state);
+	tevent_add_timer(ctdb->ev, state,
+			 timeval_current_ofs(ctdb->tunable.traverse_timeout, 0),
+			 ctdb_traverse_all_timeout, state);
 
 	return state;
 }
@@ -563,7 +562,7 @@ int32_t ctdb_control_traverse_all(struct ctdb_context *ctdb, TDB_DATA data, TDB_
  */
 int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata)
 {
-	struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr;
+	struct ctdb_rec_data_old *d = (struct ctdb_rec_data_old *)data.dptr;
 	struct ctdb_traverse_all_handle *state;
 	TDB_DATA key;
 	ctdb_traverse_fn_t callback;
@@ -574,7 +573,7 @@ int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB
 		return -1;
 	}
 
-	state = ctdb_reqid_find(ctdb, d->reqid, struct ctdb_traverse_all_handle);
+	state = reqid_find(ctdb->idr, d->reqid, struct ctdb_traverse_all_handle);
 	if (state == NULL || d->reqid != state->reqid) {
 		/* traverse might have been terminated already */
 		return -1;
@@ -661,7 +660,7 @@ static int ctdb_traverse_start_destructor(struct traverse_start_state *state)
 static void traverse_start_callback(void *p, TDB_DATA key, TDB_DATA data)
 {
 	struct traverse_start_state *state;
-	struct ctdb_rec_data *d;
+	struct ctdb_rec_data_old *d;
 	TDB_DATA cdata;
 
 	state = talloc_get_type(p, struct traverse_start_state);
@@ -674,7 +673,7 @@ static void traverse_start_callback(void *p, TDB_DATA key, TDB_DATA data)
 	cdata.dptr = (uint8_t *)d;
 	cdata.dsize = d->length;
 
-	ctdb_dispatch_message(state->ctdb, state->srvid, cdata);
+	srvid_dispatch(state->ctdb->srv, state->srvid, 0, cdata);
 	if (key.dsize == 0 && data.dsize == 0) {
 		DEBUG(DEBUG_NOTICE, ("Ending traverse on DB %s (id %d), records %d\n",
 				     state->h->ctdb_db->db_name, state->h->reqid,
@@ -707,7 +706,7 @@ int32_t ctdb_control_traverse_start_ext(struct ctdb_context *ctdb,
 	struct ctdb_traverse_start_ext *d = (struct ctdb_traverse_start_ext *)data.dptr;
 	struct traverse_start_state *state;
 	struct ctdb_db_context *ctdb_db;
-	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+	struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
 
 	if (client == NULL) {
 		DEBUG(DEBUG_ERR,(__location__ " No client found\n"));
diff --git a/ctdb/server/ctdb_tunables.c b/ctdb/server/ctdb_tunables.c
index 031e60f..ba184e7 100644
--- a/ctdb/server/ctdb_tunables.c
+++ b/ctdb/server/ctdb_tunables.c
@@ -16,8 +16,18 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
-#include "includes.h"
-#include "../include/ctdb_private.h"
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+
+#include "common/common.h"
+#include "common/logging.h"
 
 static const struct {
 	const char *name;
@@ -25,64 +35,64 @@ static const struct {
 	size_t offset;
 	bool obsolete;
 } tunable_map[] = {
-	{ "MaxRedirectCount",     3,  offsetof(struct ctdb_tunable, max_redirect_count), false },
-	{ "SeqnumInterval",      1000,  offsetof(struct ctdb_tunable, seqnum_interval), false },
-	{ "ControlTimeout",      60, offsetof(struct ctdb_tunable, control_timeout), false },
-	{ "TraverseTimeout",     20, offsetof(struct ctdb_tunable, traverse_timeout), false },
-	{ "KeepaliveInterval",    5,  offsetof(struct ctdb_tunable, keepalive_interval), false },
-	{ "KeepaliveLimit",       5,  offsetof(struct ctdb_tunable, keepalive_limit), false },
-	{ "RecoverTimeout",     120,  offsetof(struct ctdb_tunable, recover_timeout), false },
-	{ "RecoverInterval",      1,  offsetof(struct ctdb_tunable, recover_interval), false },
-	{ "ElectionTimeout",      3,  offsetof(struct ctdb_tunable, election_timeout), false },
-	{ "TakeoverTimeout",      9,  offsetof(struct ctdb_tunable, takeover_timeout), false },
-	{ "MonitorInterval",     15,  offsetof(struct ctdb_tunable, monitor_interval), false },
-	{ "TickleUpdateInterval",20,  offsetof(struct ctdb_tunable, tickle_update_interval), false },
-	{ "EventScriptTimeout",  30,  offsetof(struct ctdb_tunable, script_timeout), false },
-	{ "EventScriptTimeoutCount", 20,  offsetof(struct ctdb_tunable, script_timeout_count), false },
-	{ "EventScriptUnhealthyOnTimeout", 0, offsetof(struct ctdb_tunable, script_unhealthy_on_timeout), true },
-	{ "RecoveryGracePeriod", 120,  offsetof(struct ctdb_tunable, recovery_grace_period), false },
-	{ "RecoveryBanPeriod",  300,  offsetof(struct ctdb_tunable, recovery_ban_period), false },
-	{ "DatabaseHashSize", 100001, offsetof(struct ctdb_tunable, database_hash_size), false },
-	{ "DatabaseMaxDead",      5,  offsetof(struct ctdb_tunable, database_max_dead), false },
-	{ "RerecoveryTimeout",   10,  offsetof(struct ctdb_tunable, rerecovery_timeout), false },
-	{ "EnableBans",           1,  offsetof(struct ctdb_tunable, enable_bans), false },
-	{ "DeterministicIPs",     0,  offsetof(struct ctdb_tunable, deterministic_public_ips), false },
-	{ "LCP2PublicIPs",        1,  offsetof(struct ctdb_tunable, lcp2_public_ip_assignment), false },
-	{ "ReclockPingPeriod",   60,  offsetof(struct ctdb_tunable,  reclock_ping_period), false },
-	{ "NoIPFailback",         0,  offsetof(struct ctdb_tunable, no_ip_failback), false },
-	{ "DisableIPFailover",    0,  offsetof(struct ctdb_tunable, disable_ip_failover), false },
-	{ "VerboseMemoryNames",   0,  offsetof(struct ctdb_tunable, verbose_memory_names), false },
-	{ "RecdPingTimeout",	 60,  offsetof(struct ctdb_tunable, recd_ping_timeout), false },
-	{ "RecdFailCount",	 10,  offsetof(struct ctdb_tunable, recd_ping_failcount), false },
-	{ "LogLatencyMs",         0,  offsetof(struct ctdb_tunable, log_latency_ms), false },
-	{ "RecLockLatencyMs",  1000,  offsetof(struct ctdb_tunable, reclock_latency_ms), false },
-	{ "RecoveryDropAllIPs", 120,  offsetof(struct ctdb_tunable, recovery_drop_all_ips), false },
-	{ "VerifyRecoveryLock",   1,  offsetof(struct ctdb_tunable, verify_recovery_lock), true },
-	{ "VacuumInterval",   10,  offsetof(struct ctdb_tunable, vacuum_interval), false },
-	{ "VacuumMaxRunTime",     120,  offsetof(struct ctdb_tunable, vacuum_max_run_time), false },
-	{ "RepackLimit",      10000,  offsetof(struct ctdb_tunable, repack_limit), false },
-	{ "VacuumLimit",       5000,  offsetof(struct ctdb_tunable, vacuum_limit), false },
-	{ "VacuumFastPathCount", 60, offsetof(struct ctdb_tunable, vacuum_fast_path_count), false },
-	{ "MaxQueueDropMsg",  1000000, offsetof(struct ctdb_tunable, max_queue_depth_drop_msg), false },
-	{ "AllowUnhealthyDBRead", 0,  offsetof(struct ctdb_tunable, allow_unhealthy_db_read), false },
-	{ "StatHistoryInterval",  1,  offsetof(struct ctdb_tunable, stat_history_interval), false },
-	{ "DeferredAttachTO",  120,  offsetof(struct ctdb_tunable, deferred_attach_timeout), false },
-	{ "AllowClientDBAttach", 1, offsetof(struct ctdb_tunable, allow_client_db_attach), false },
-	{ "RecoverPDBBySeqNum",  1, offsetof(struct ctdb_tunable, recover_pdb_by_seqnum), false },
-	{ "DeferredRebalanceOnNodeAdd", 300, offsetof(struct ctdb_tunable, deferred_rebalance_on_node_add) },
-	{ "FetchCollapse",       1, offsetof(struct ctdb_tunable, fetch_collapse) },
-	{ "HopcountMakeSticky",   50,  offsetof(struct ctdb_tunable, hopcount_make_sticky) },
-	{ "StickyDuration",      600,  offsetof(struct ctdb_tunable, sticky_duration) },
-	{ "StickyPindown",       200,  offsetof(struct ctdb_tunable, sticky_pindown) },
-	{ "NoIPTakeover",         0,  offsetof(struct ctdb_tunable, no_ip_takeover), false },
-	{ "DBRecordCountWarn",    100000,  offsetof(struct ctdb_tunable, db_record_count_warn), false },
-	{ "DBRecordSizeWarn",   10000000,  offsetof(struct ctdb_tunable, db_record_size_warn), false },
-	{ "DBSizeWarn",        100000000,  offsetof(struct ctdb_tunable, db_size_warn), false },
-	{ "PullDBPreallocation", 10*1024*1024,  offsetof(struct ctdb_tunable, pulldb_preallocation_size), false },
-	{ "NoIPHostOnAllDisabled",    0,  offsetof(struct ctdb_tunable, no_ip_host_on_all_disabled), false },
-	{ "Samba3AvoidDeadlocks", 0, offsetof(struct ctdb_tunable, samba3_hack), false },
-	{ "TDBMutexEnabled", 0, offsetof(struct ctdb_tunable, mutex_enabled), false },
-	{ "LockProcessesPerDB", 200, offsetof(struct ctdb_tunable, lock_processes_per_db), false },
+	{ "MaxRedirectCount",     3,  offsetof(struct ctdb_tunable_list, max_redirect_count), false },
+	{ "SeqnumInterval",      1000,  offsetof(struct ctdb_tunable_list, seqnum_interval), false },
+	{ "ControlTimeout",      60, offsetof(struct ctdb_tunable_list, control_timeout), false },
+	{ "TraverseTimeout",     20, offsetof(struct ctdb_tunable_list, traverse_timeout), false },
+	{ "KeepaliveInterval",    5,  offsetof(struct ctdb_tunable_list, keepalive_interval), false },
+	{ "KeepaliveLimit",       5,  offsetof(struct ctdb_tunable_list, keepalive_limit), false },
+	{ "RecoverTimeout",     120,  offsetof(struct ctdb_tunable_list, recover_timeout), false },
+	{ "RecoverInterval",      1,  offsetof(struct ctdb_tunable_list, recover_interval), false },
+	{ "ElectionTimeout",      3,  offsetof(struct ctdb_tunable_list, election_timeout), false },
+	{ "TakeoverTimeout",      9,  offsetof(struct ctdb_tunable_list, takeover_timeout), false },
+	{ "MonitorInterval",     15,  offsetof(struct ctdb_tunable_list, monitor_interval), false },
+	{ "TickleUpdateInterval",20,  offsetof(struct ctdb_tunable_list, tickle_update_interval), false },
+	{ "EventScriptTimeout",  30,  offsetof(struct ctdb_tunable_list, script_timeout), false },
+	{ "MonitorTimeoutCount", 20,  offsetof(struct ctdb_tunable_list, monitor_timeout_count), false },
+	{ "EventScriptUnhealthyOnTimeout", 0, offsetof(struct ctdb_tunable_list, script_unhealthy_on_timeout), true },
+	{ "RecoveryGracePeriod", 120,  offsetof(struct ctdb_tunable_list, recovery_grace_period), false },
+	{ "RecoveryBanPeriod",  300,  offsetof(struct ctdb_tunable_list, recovery_ban_period), false },
+	{ "DatabaseHashSize", 100001, offsetof(struct ctdb_tunable_list, database_hash_size), false },
+	{ "DatabaseMaxDead",      5,  offsetof(struct ctdb_tunable_list, database_max_dead), false },
+	{ "RerecoveryTimeout",   10,  offsetof(struct ctdb_tunable_list, rerecovery_timeout), false },
+	{ "EnableBans",           1,  offsetof(struct ctdb_tunable_list, enable_bans), false },
+	{ "DeterministicIPs",     0,  offsetof(struct ctdb_tunable_list, deterministic_public_ips), false },
+	{ "LCP2PublicIPs",        1,  offsetof(struct ctdb_tunable_list, lcp2_public_ip_assignment), false },
+	{ "ReclockPingPeriod",   60,  offsetof(struct ctdb_tunable_list,  reclock_ping_period), false },
+	{ "NoIPFailback",         0,  offsetof(struct ctdb_tunable_list, no_ip_failback), false },
+	{ "DisableIPFailover",    0,  offsetof(struct ctdb_tunable_list, disable_ip_failover), false },
+	{ "VerboseMemoryNames",   0,  offsetof(struct ctdb_tunable_list, verbose_memory_names), false },
+	{ "RecdPingTimeout",	 60,  offsetof(struct ctdb_tunable_list, recd_ping_timeout), false },
+	{ "RecdFailCount",	 10,  offsetof(struct ctdb_tunable_list, recd_ping_failcount), false },
+	{ "LogLatencyMs",         0,  offsetof(struct ctdb_tunable_list, log_latency_ms), false },
+	{ "RecLockLatencyMs",  1000,  offsetof(struct ctdb_tunable_list, reclock_latency_ms), false },
+	{ "RecoveryDropAllIPs", 120,  offsetof(struct ctdb_tunable_list, recovery_drop_all_ips), false },
+	{ "VerifyRecoveryLock",   1,  offsetof(struct ctdb_tunable_list, verify_recovery_lock), true },
+	{ "VacuumInterval",   10,  offsetof(struct ctdb_tunable_list, vacuum_interval), false },
+	{ "VacuumMaxRunTime",     120,  offsetof(struct ctdb_tunable_list, vacuum_max_run_time), false },
+	{ "RepackLimit",      10000,  offsetof(struct ctdb_tunable_list, repack_limit), false },
+	{ "VacuumLimit",       5000,  offsetof(struct ctdb_tunable_list, vacuum_limit), false },
+	{ "VacuumFastPathCount", 60, offsetof(struct ctdb_tunable_list, vacuum_fast_path_count), false },
+	{ "MaxQueueDropMsg",  1000000, offsetof(struct ctdb_tunable_list, max_queue_depth_drop_msg), false },
+	{ "AllowUnhealthyDBRead", 0,  offsetof(struct ctdb_tunable_list, allow_unhealthy_db_read), false },
+	{ "StatHistoryInterval",  1,  offsetof(struct ctdb_tunable_list, stat_history_interval), false },
+	{ "DeferredAttachTO",  120,  offsetof(struct ctdb_tunable_list, deferred_attach_timeout), false },
+	{ "AllowClientDBAttach", 1, offsetof(struct ctdb_tunable_list, allow_client_db_attach), false },
+	{ "RecoverPDBBySeqNum",  1, offsetof(struct ctdb_tunable_list, recover_pdb_by_seqnum), false },
+	{ "DeferredRebalanceOnNodeAdd", 300, offsetof(struct ctdb_tunable_list, deferred_rebalance_on_node_add) },
+	{ "FetchCollapse",       1, offsetof(struct ctdb_tunable_list, fetch_collapse) },
+	{ "HopcountMakeSticky",   50,  offsetof(struct ctdb_tunable_list, hopcount_make_sticky) },
+	{ "StickyDuration",      600,  offsetof(struct ctdb_tunable_list, sticky_duration) },
+	{ "StickyPindown",       200,  offsetof(struct ctdb_tunable_list, sticky_pindown) },
+	{ "NoIPTakeover",         0,  offsetof(struct ctdb_tunable_list, no_ip_takeover), false },
+	{ "DBRecordCountWarn",    100000,  offsetof(struct ctdb_tunable_list, db_record_count_warn), false },
+	{ "DBRecordSizeWarn",   10000000,  offsetof(struct ctdb_tunable_list, db_record_size_warn), false },
+	{ "DBSizeWarn",        100000000,  offsetof(struct ctdb_tunable_list, db_size_warn), false },
+	{ "PullDBPreallocation", 10*1024*1024,  offsetof(struct ctdb_tunable_list, pulldb_preallocation_size), false },
+	{ "NoIPHostOnAllDisabled",    0,  offsetof(struct ctdb_tunable_list, no_ip_host_on_all_disabled), false },
+	{ "Samba3AvoidDeadlocks", 0, offsetof(struct ctdb_tunable_list, samba3_hack), false },
+	{ "TDBMutexEnabled", 0, offsetof(struct ctdb_tunable_list, mutex_enabled), false },
+	{ "LockProcessesPerDB", 200, offsetof(struct ctdb_tunable_list, lock_processes_per_db), false },
 };
 
 /*
@@ -144,13 +154,13 @@ int32_t ctdb_control_get_tunable(struct ctdb_context *ctdb, TDB_DATA indata,
  */
 int32_t ctdb_control_set_tunable(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-	struct ctdb_control_set_tunable *t =
-		(struct ctdb_control_set_tunable *)indata.dptr;
+	struct ctdb_tunable_old *t =
+		(struct ctdb_tunable_old *)indata.dptr;
 	char *name;
 	int i;
 
 	if (indata.dsize < sizeof(*t) ||
-	    t->length > indata.dsize - offsetof(struct ctdb_control_set_tunable, name)) {
+	    t->length > indata.dsize - offsetof(struct ctdb_tunable_old, name)) {
 		DEBUG(DEBUG_ERR,("Bad indata in ctdb_control_set_tunable\n"));
 		return -1;
 	}
diff --git a/ctdb/server/ctdb_update_record.c b/ctdb/server/ctdb_update_record.c
index 418bbb1..bc9c6fe 100644
--- a/ctdb/server/ctdb_update_record.c
+++ b/ctdb/server/ctdb_update_record.c
@@ -18,19 +18,33 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
+#include "system/network.h"
+#include "system/time.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
-#include "tdb.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/util_process.h"
+
 #include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 struct ctdb_persistent_write_state {
 	struct ctdb_db_context *ctdb_db;
 	struct ctdb_marshall_buffer *m;
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 	uint32_t flags;
 };
 
-/* dont create/update records that does not exist locally */
+/* don't create/update records that does not exist locally */
 #define UPDATE_FLAGS_REPLACE_ONLY	1
 
 /*
@@ -39,7 +53,7 @@ struct ctdb_persistent_write_state {
 static int ctdb_persistent_store(struct ctdb_persistent_write_state *state)
 {
 	int ret, i;
-	struct ctdb_rec_data *rec = NULL;
+	struct ctdb_rec_data_old *rec = NULL;
 	struct ctdb_marshall_buffer *m = state->m;
 
 	ret = tdb_transaction_start(state->ctdb_db->ltdb->tdb);
@@ -139,7 +153,8 @@ static void ctdb_persistent_write_callback(int status, void *private_data)
 /*
   called if our lockwait child times out
  */
-static void ctdb_persistent_lock_timeout(struct event_context *ev, struct timed_event *te,
+static void ctdb_persistent_lock_timeout(struct tevent_context *ev,
+					 struct tevent_timer *te,
 					 struct timeval t, void *private_data)
 {
 	struct ctdb_persistent_write_state *state = talloc_get_type(private_data,
@@ -151,7 +166,7 @@ static void ctdb_persistent_lock_timeout(struct event_context *ev, struct timed_
 struct childwrite_handle {
 	struct ctdb_context *ctdb;
 	struct ctdb_db_context *ctdb_db;
-	struct fd_event *fde;
+	struct tevent_fd *fde;
 	int fd[2];
 	pid_t child;
 	void *private_data;
@@ -169,8 +184,9 @@ static int childwrite_destructor(struct childwrite_handle *h)
 /* called when the child process has finished writing the record to the
    database
 */
-static void childwrite_handler(struct event_context *ev, struct fd_event *fde,
-			     uint16_t flags, void *private_data)
+static void childwrite_handler(struct tevent_context *ev,
+			       struct tevent_fd *fde,
+			       uint16_t flags, void *private_data)
 {
 	struct childwrite_handle *h = talloc_get_type(private_data,
 						     struct childwrite_handle);
@@ -250,7 +266,7 @@ static struct childwrite_handle *ctdb_childwrite(
 		char c = 0;
 
 		close(result->fd[0]);
-		ctdb_set_process_name("ctdb_write_persistent");
+		prctl_set_comment("ctdb_write_persistent");
 		debug_extra = talloc_asprintf(NULL, "childwrite-%s:", ctdb_db->db_name);
 		ret = ctdb_persistent_store(state);
 		if (ret != 0) {
@@ -274,9 +290,9 @@ static struct childwrite_handle *ctdb_childwrite(
 
 	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d for ctdb_childwrite\n", result->fd[0]));
 
-	result->fde = event_add_fd(ctdb_db->ctdb->ev, result, result->fd[0],
-				   EVENT_FD_READ, childwrite_handler,
-				   (void *)result);
+	result->fde = tevent_add_fd(ctdb_db->ctdb->ev, result, result->fd[0],
+				    TEVENT_FD_READ, childwrite_handler,
+				    (void *)result);
 	if (result->fde == NULL) {
 		talloc_free(result);
 		CTDB_DECREMENT_STAT(ctdb_db->ctdb, pending_childwrite_calls);
@@ -294,7 +310,7 @@ static struct childwrite_handle *ctdb_childwrite(
    current record
  */
 int32_t ctdb_control_update_record(struct ctdb_context *ctdb,
-				   struct ctdb_req_control *c, TDB_DATA recdata,
+				   struct ctdb_req_control_old *c, TDB_DATA recdata,
 				   bool *async_reply)
 {
 	struct ctdb_db_context *ctdb_db;
@@ -347,8 +363,9 @@ int32_t ctdb_control_update_record(struct ctdb_context *ctdb,
 	talloc_steal(state, c);
 
 	/* but we won't wait forever */
-	event_add_timed(ctdb->ev, state, timeval_current_ofs(ctdb->tunable.control_timeout, 0),
-			ctdb_persistent_lock_timeout, state);
+	tevent_add_timer(ctdb->ev, state,
+			 timeval_current_ofs(ctdb->tunable.control_timeout, 0),
+			 ctdb_persistent_lock_timeout, state);
 
 	return 0;
 }
diff --git a/ctdb/server/ctdb_uptime.c b/ctdb/server/ctdb_uptime.c
index b45ea80..53025f5 100644
--- a/ctdb/server/ctdb_uptime.c
+++ b/ctdb/server/ctdb_uptime.c
@@ -17,11 +17,21 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "../include/ctdb_private.h"
+#include "replace.h"
 #include "system/syslog.h"
 #include "system/time.h"
 #include "system/filesys.h"
+#include "system/network.h"
+
+#include <talloc.h>
+
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/common.h"
+#include "common/logging.h"
 
 /* 
    returns the ctdb uptime
diff --git a/ctdb/server/ctdb_vacuum.c b/ctdb/server/ctdb_vacuum.c
index d678ff9..f536129 100644
--- a/ctdb/server/ctdb_vacuum.c
+++ b/ctdb/server/ctdb_vacuum.c
@@ -19,16 +19,27 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
-#include "system/dir.h"
-#include "../include/ctdb_private.h"
+#include "system/time.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
 #include "lib/util/dlinklist.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/util_process.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/rb_tree.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 #define TIMELIMIT() timeval_current_ofs(10, 0)
 
@@ -202,7 +213,8 @@ static int add_record_to_vacuum_fetch_list(struct vacuum_data *vdata,
 }
 
 
-static void ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
+static void ctdb_vacuum_event(struct tevent_context *ev,
+			      struct tevent_timer *te,
 			      struct timeval t, void *private_data);
 
 static int vacuum_record_parser(TDB_DATA key, TDB_DATA data, void *private_data)
@@ -811,7 +823,7 @@ static void ctdb_process_delete_list(struct ctdb_db_context *ctdb_db,
 	struct ctdb_context *ctdb = ctdb_db->ctdb;
 	struct delete_records_list *recs;
 	TDB_DATA indata;
-	struct ctdb_node_map *nodemap;
+	struct ctdb_node_map_old *nodemap;
 	uint32_t *active_nodes;
 	int num_active_nodes;
 	TALLOC_CTX *tmp_ctx;
@@ -897,7 +909,7 @@ static void ctdb_process_delete_list(struct ctdb_db_context *ctdb_db,
 
 	for (i = 0; i < num_active_nodes; i++) {
 		struct ctdb_marshall_buffer *records;
-		struct ctdb_rec_data *rec;
+		struct ctdb_rec_data_old *rec;
 		int32_t res;
 		TDB_DATA outdata;
 
@@ -919,7 +931,7 @@ static void ctdb_process_delete_list(struct ctdb_db_context *ctdb_db,
 		 * the list to process further.
 		 */
 		records = (struct ctdb_marshall_buffer *)outdata.dptr;
-		rec = (struct ctdb_rec_data *)&records->data[0];
+		rec = (struct ctdb_rec_data_old *)&records->data[0];
 		while (records->count-- > 1) {
 			TDB_DATA reckey, recdata;
 			struct ctdb_ltdb_header *rechdr;
@@ -961,7 +973,7 @@ static void ctdb_process_delete_list(struct ctdb_db_context *ctdb_db,
 				vdata->count.delete_list.left--;
 			}
 
-			rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+			rec = (struct ctdb_rec_data_old *)(rec->length + (uint8_t *)rec);
 		}
 	}
 
@@ -1004,7 +1016,7 @@ static void ctdb_process_delete_list(struct ctdb_db_context *ctdb_db,
 
 	for (i = 0; i < num_active_nodes; i++) {
 		struct ctdb_marshall_buffer *records;
-		struct ctdb_rec_data *rec;
+		struct ctdb_rec_data_old *rec;
 		int32_t res;
 		TDB_DATA outdata;
 
@@ -1026,7 +1038,7 @@ static void ctdb_process_delete_list(struct ctdb_db_context *ctdb_db,
 		 * the list to delete locally.
 		 */
 		records = (struct ctdb_marshall_buffer *)outdata.dptr;
-		rec = (struct ctdb_rec_data *)&records->data[0];
+		rec = (struct ctdb_rec_data_old *)&records->data[0];
 		while (records->count-- > 1) {
 			TDB_DATA reckey, recdata;
 			struct ctdb_ltdb_header *rechdr;
@@ -1068,7 +1080,7 @@ static void ctdb_process_delete_list(struct ctdb_db_context *ctdb_db,
 				vdata->count.delete_list.left--;
 			}
 
-			rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+			rec = (struct ctdb_rec_data_old *)(rec->length + (uint8_t *)rec);
 		}
 	}
 
@@ -1368,9 +1380,9 @@ static int vacuum_child_destructor(struct ctdb_vacuum_child_context *child_ctx)
 
 	DLIST_REMOVE(ctdb->vacuumers, child_ctx);
 
-	event_add_timed(ctdb->ev, child_ctx->vacuum_handle,
-			timeval_current_ofs(get_vacuum_interval(ctdb_db), 0), 
-			ctdb_vacuum_event, child_ctx->vacuum_handle);
+	tevent_add_timer(ctdb->ev, child_ctx->vacuum_handle,
+			 timeval_current_ofs(get_vacuum_interval(ctdb_db), 0),
+			 ctdb_vacuum_event, child_ctx->vacuum_handle);
 
 	return 0;
 }
@@ -1378,8 +1390,9 @@ static int vacuum_child_destructor(struct ctdb_vacuum_child_context *child_ctx)
 /*
  * this event is generated when a vacuum child process times out
  */
-static void vacuum_child_timeout(struct event_context *ev, struct timed_event *te,
-					 struct timeval t, void *private_data)
+static void vacuum_child_timeout(struct tevent_context *ev,
+				 struct tevent_timer *te,
+				 struct timeval t, void *private_data)
 {
 	struct ctdb_vacuum_child_context *child_ctx = talloc_get_type(private_data, struct ctdb_vacuum_child_context);
 
@@ -1394,8 +1407,9 @@ static void vacuum_child_timeout(struct event_context *ev, struct timed_event *t
 /*
  * this event is generated when a vacuum child process has completed
  */
-static void vacuum_child_handler(struct event_context *ev, struct fd_event *fde,
-			     uint16_t flags, void *private_data)
+static void vacuum_child_handler(struct tevent_context *ev,
+				 struct tevent_fd *fde,
+				 uint16_t flags, void *private_data)
 {
 	struct ctdb_vacuum_child_context *child_ctx = talloc_get_type(private_data, struct ctdb_vacuum_child_context);
 	char c = 0;
@@ -1418,9 +1432,9 @@ static void vacuum_child_handler(struct event_context *ev, struct fd_event *fde,
 /*
  * this event is called every time we need to start a new vacuum process
  */
-static void
-ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
-			       struct timeval t, void *private_data)
+static void ctdb_vacuum_event(struct tevent_context *ev,
+			      struct tevent_timer *te,
+			      struct timeval t, void *private_data)
 {
 	struct ctdb_vacuum_handle *vacuum_handle = talloc_get_type(private_data, struct ctdb_vacuum_handle);
 	struct ctdb_db_context *ctdb_db = vacuum_handle->ctdb_db;
@@ -1429,7 +1443,7 @@ ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
 	struct tevent_fd *fde;
 	int ret;
 
-	/* we dont vacuum if we are in recovery mode, or db frozen */
+	/* we don't vacuum if we are in recovery mode, or db frozen */
 	if (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE ||
 	    ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_NONE) {
 		DEBUG(DEBUG_INFO, ("Not vacuuming %s (%s)\n", ctdb_db->db_name,
@@ -1437,9 +1451,9 @@ ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
 				   : ctdb->freeze_mode[ctdb_db->priority] == CTDB_FREEZE_PENDING
 				   ? "freeze pending"
 				   : "frozen"));
-		event_add_timed(ctdb->ev, vacuum_handle,
-			timeval_current_ofs(get_vacuum_interval(ctdb_db), 0),
-			ctdb_vacuum_event, vacuum_handle);
+		tevent_add_timer(ctdb->ev, vacuum_handle,
+				 timeval_current_ofs(get_vacuum_interval(ctdb_db), 0),
+				 ctdb_vacuum_event, vacuum_handle);
 		return;
 	}
 
@@ -1448,9 +1462,9 @@ ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
 	 * new vacuuming event to stagger vacuuming events.
 	 */
 	if (ctdb->vacuumers != NULL) {
-		event_add_timed(ctdb->ev, vacuum_handle,
-				timeval_current_ofs(0, 500*1000),
-				ctdb_vacuum_event, vacuum_handle);
+		tevent_add_timer(ctdb->ev, vacuum_handle,
+				 timeval_current_ofs(0, 500*1000),
+				 ctdb_vacuum_event, vacuum_handle);
 		return;
 	}
 
@@ -1465,9 +1479,9 @@ ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
 	if (ret != 0) {
 		talloc_free(child_ctx);
 		DEBUG(DEBUG_ERR, ("Failed to create pipe for vacuum child process.\n"));
-		event_add_timed(ctdb->ev, vacuum_handle,
-			timeval_current_ofs(get_vacuum_interval(ctdb_db), 0),
-			ctdb_vacuum_event, vacuum_handle);
+		tevent_add_timer(ctdb->ev, vacuum_handle,
+				 timeval_current_ofs(get_vacuum_interval(ctdb_db), 0),
+				 ctdb_vacuum_event, vacuum_handle);
 		return;
 	}
 
@@ -1481,9 +1495,9 @@ ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
 		close(child_ctx->fd[1]);
 		talloc_free(child_ctx);
 		DEBUG(DEBUG_ERR, ("Failed to fork vacuum child process.\n"));
-		event_add_timed(ctdb->ev, vacuum_handle,
-			timeval_current_ofs(get_vacuum_interval(ctdb_db), 0),
-			ctdb_vacuum_event, vacuum_handle);
+		tevent_add_timer(ctdb->ev, vacuum_handle,
+				 timeval_current_ofs(get_vacuum_interval(ctdb_db), 0),
+				 ctdb_vacuum_event, vacuum_handle);
 		return;
 	}
 
@@ -1494,7 +1508,7 @@ ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
 		close(child_ctx->fd[0]);
 
 		DEBUG(DEBUG_INFO,("Vacuuming child process %d for db %s started\n", getpid(), ctdb_db->db_name));
-		ctdb_set_process_name("ctdb_vacuum");
+		prctl_set_comment("ctdb_vacuum");
 		if (switch_from_server_to_client(ctdb, "vacuum-%s", ctdb_db->db_name) != 0) {
 			DEBUG(DEBUG_CRIT, (__location__ "ERROR: failed to switch vacuum daemon into client mode. Shutting down.\n"));
 			_exit(1);
@@ -1531,14 +1545,14 @@ ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
 				 "in parent context. Shutting down\n");
 	}
 
-	event_add_timed(ctdb->ev, child_ctx,
-		timeval_current_ofs(ctdb->tunable.vacuum_max_run_time, 0),
-		vacuum_child_timeout, child_ctx);
+	tevent_add_timer(ctdb->ev, child_ctx,
+			 timeval_current_ofs(ctdb->tunable.vacuum_max_run_time, 0),
+			 vacuum_child_timeout, child_ctx);
 
 	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d to child vacuum process\n", child_ctx->fd[0]));
 
-	fde = event_add_fd(ctdb->ev, child_ctx, child_ctx->fd[0],
-			   EVENT_FD_READ, vacuum_child_handler, child_ctx);
+	fde = tevent_add_fd(ctdb->ev, child_ctx, child_ctx->fd[0],
+			    TEVENT_FD_READ, vacuum_child_handler, child_ctx);
 	tevent_fd_set_auto_close(fde);
 
 	vacuum_handle->child_ctx = child_ctx;
@@ -1573,9 +1587,9 @@ int ctdb_vacuum_init(struct ctdb_db_context *ctdb_db)
 	ctdb_db->vacuum_handle->ctdb_db         = ctdb_db;
 	ctdb_db->vacuum_handle->fast_path_count = 0;
 
-	event_add_timed(ctdb_db->ctdb->ev, ctdb_db->vacuum_handle, 
-			timeval_current_ofs(get_vacuum_interval(ctdb_db), 0), 
-			ctdb_vacuum_event, ctdb_db->vacuum_handle);
+	tevent_add_timer(ctdb_db->ctdb->ev, ctdb_db->vacuum_handle,
+			 timeval_current_ofs(get_vacuum_interval(ctdb_db), 0),
+			 ctdb_vacuum_event, ctdb_db->vacuum_handle);
 
 	return 0;
 }
@@ -1645,11 +1659,11 @@ static int insert_record_into_delete_queue(struct ctdb_db_context *ctdb_db,
 
 	hash = (uint32_t)ctdb_hash(&key);
 
-	DEBUG(DEBUG_INFO, (__location__ " schedule for deletion: db[%s] "
-			   "db_id[0x%08x] "
-			   "key_hash[0x%08x] "
-			   "lmaster[%u] "
-			   "migrated_with_data[%s]\n",
+	DEBUG(DEBUG_DEBUG, (__location__ " schedule for deletion: db[%s] "
+			    "db_id[0x%08x] "
+			    "key_hash[0x%08x] "
+			    "lmaster[%u] "
+			    "migrated_with_data[%s]\n",
 			    ctdb_db->db_name, ctdb_db->db_id,
 			    hash,
 			    ctdb_lmaster(ctdb_db->ctdb, &key),
@@ -1732,7 +1746,7 @@ int32_t ctdb_local_schedule_for_deletion(struct ctdb_db_context *ctdb_db,
 		return ret;
 	}
 
-	/* if we dont have a connection to the daemon we can not send
+	/* if we don't have a connection to the daemon we can not send
 	   a control. For example sometimes from update_record control child
 	   process.
 	*/
diff --git a/ctdb/server/ctdbd.c b/ctdb/server/ctdbd.c
index ec285c0..b8b979d 100644
--- a/ctdb/server/ctdbd.c
+++ b/ctdb/server/ctdbd.c
@@ -17,14 +17,28 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
 #include "system/time.h"
 #include "system/wait.h"
 #include "system/network.h"
-#include "cmdline.h"
-#include "../include/ctdb_private.h"
+
+#include <popt.h>
+#include <talloc.h>
+/* Allow use of deprecated function tevent_loop_allow_nesting() */
+#define TEVENT_DEPRECATED
+#include <tevent.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+
+#include "common/reqid.h"
+#include "common/system.h"
+#include "common/cmdline.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 static struct {
 	const char *nlist;
@@ -78,7 +92,7 @@ static void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t len
 	if (ctdb_validate_pnn(ctdb, hdr->srcnode)) {
 		/* as a special case, redirected calls don't increment the rx_cnt */
 		if (hdr->operation != CTDB_REQ_CALL ||
-		    ((struct ctdb_req_call *)hdr)->hopcount == 0) {
+		    ((struct ctdb_req_call_old *)hdr)->hopcount == 0) {
 			ctdb->nodes[hdr->srcnode]->rx_cnt++;
 		}
 	}
@@ -139,7 +153,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
 
@@ -163,7 +177,7 @@ int main(int argc, const char *argv[])
 
 	fault_setup();
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 	tevent_loop_allow_nesting(ev);
 
 	ctdb = ctdb_cmdline_init(ev);
@@ -185,9 +199,14 @@ int main(int argc, const char *argv[])
 	ctdb->recovery_mode    = CTDB_RECOVERY_NORMAL;
 	ctdb->recovery_master  = (uint32_t)-1;
 	ctdb->upcalls          = &ctdb_upcalls;
-	ctdb->idr              = idr_init(ctdb);
 	ctdb->recovery_lock_fd = -1;
 
+	ret = reqid_init(ctdb, 0, &ctdb->idr);;
+	if (ret != 0) {
+		DEBUG(DEBUG_ALERT, ("reqid_init failed (%s)\n", strerror(ret)));
+		exit(1);
+	}
+
 	ctdb_tunables_set_defaults(ctdb);
 
 	ret = ctdb_set_recovery_lock_file(ctdb, options.recovery_lock_file);
@@ -212,12 +231,12 @@ int main(int argc, const char *argv[])
 	}
 
 	/* set ctdbd capabilities */
-	ctdb->capabilities = 0;
-	if (options.no_lmaster == 0) {
-		ctdb->capabilities |= CTDB_CAP_LMASTER;
+	ctdb->capabilities = CTDB_CAP_DEFAULT;
+	if (options.no_lmaster != 0) {
+		ctdb->capabilities &= ~CTDB_CAP_LMASTER;
 	}
-	if (options.no_recmaster == 0) {
-		ctdb->capabilities |= CTDB_CAP_RECMASTER;
+	if (options.no_recmaster != 0) {
+		ctdb->capabilities &= ~CTDB_CAP_RECMASTER;
 	}
 	if (options.lvs != 0) {
 		ctdb->capabilities |= CTDB_CAP_LVS;
diff --git a/ctdb/server/eventscript.c b/ctdb/server/eventscript.c
index 49619b2..5bc2ee8 100644
--- a/ctdb/server/eventscript.c
+++ b/ctdb/server/eventscript.c
@@ -17,17 +17,32 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include <time.h>
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
 #include "system/wait.h"
 #include "system/dir.h"
 #include "system/locale.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
+#include "system/time.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+
+#include "common/rb_tree.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
+
 
-static void ctdb_event_script_timeout(struct event_context *ev, struct timed_event *te, struct timeval t, void *p);
+static void ctdb_event_script_timeout(struct tevent_context *ev,
+				      struct tevent_timer *te,
+				      struct timeval t, void *p);
 
 /* This is attached to the event script state. */
 struct event_script_callback {
@@ -44,15 +59,15 @@ struct ctdb_event_script_state {
 	struct event_script_callback *callback;
 	pid_t child;
 	int fd[2];
-	enum ctdb_eventscript_call call;
+	enum ctdb_event call;
 	const char *options;
 	struct timeval timeout;
 
 	unsigned int current;
-	struct ctdb_scripts_wire *scripts;
+	struct ctdb_script_list_old *scripts;
 };
 
-static struct ctdb_script_wire *get_current_script(struct ctdb_event_script_state *state)
+static struct ctdb_script *get_current_script(struct ctdb_event_script_state *state)
 {
 	return &state->scripts->scripts[state->current];
 }
@@ -64,7 +79,7 @@ static void log_event_script_output(const char *str, uint16_t len, void *p)
 {
 	struct ctdb_event_script_state *state
 		= talloc_get_type(p, struct ctdb_event_script_state);
-	struct ctdb_script_wire *current;
+	struct ctdb_script *current;
 	unsigned int slen, min;
 
 	/* We may have been aborted to run something else.  Discard */
@@ -155,10 +170,12 @@ static bool check_executable(const char *dir, const char *name)
 	return true;
 }
 
-static struct ctdb_scripts_wire *ctdb_get_script_list(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx)
+static struct ctdb_script_list_old *ctdb_get_script_list(
+						struct ctdb_context *ctdb,
+						TALLOC_CTX *mem_ctx)
 {
 	struct dirent **namelist;
-	struct ctdb_scripts_wire *scripts;
+	struct ctdb_script_list_old *scripts;
 	int i, count;
 
 	/* scan all directory entries and insert all valid scripts into the
@@ -182,7 +199,7 @@ static struct ctdb_scripts_wire *ctdb_get_script_list(struct ctdb_context *ctdb,
 	scripts->num_scripts = count;
 
 	for (i = 0; i < count; i++) {
-		struct ctdb_script_wire *s = &scripts->scripts[i];
+		struct ctdb_script *s = &scripts->scripts[i];
 
 		if (strlcpy(s->name, namelist[i]->d_name, sizeof(s->name)) >=
 		    sizeof(s->name)) {
@@ -210,9 +227,9 @@ done:
 #define MAX_HELPER_ARGS		(10)
 
 static bool child_helper_args(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-			      enum ctdb_eventscript_call call,
+			      enum ctdb_event call,
 			      const char *options,
-			      struct ctdb_script_wire *current, int fd,
+			      struct ctdb_script *current, int fd,
 			      int *argc, const char ***argv)
 {
 	const char **tmp;
@@ -268,7 +285,8 @@ failed:
 
 }
 
-static void ctdb_event_script_handler(struct event_context *ev, struct fd_event *fde,
+static void ctdb_event_script_handler(struct tevent_context *ev,
+				      struct tevent_fd *fde,
 				      uint16_t flags, void *p);
 
 static char helper_prog[PATH_MAX+1] = "";
@@ -278,7 +296,7 @@ static int fork_child_for_script(struct ctdb_context *ctdb,
 {
 	int r;
 	struct tevent_fd *fde;
-	struct ctdb_script_wire *current = get_current_script(state);
+	struct ctdb_script *current = get_current_script(state);
 	int argc;
 	const char **argv;
 
@@ -324,8 +342,8 @@ static int fork_child_for_script(struct ctdb_context *ctdb,
 	set_close_on_exec(state->fd[0]);
 
 	/* Set ourselves up to be called when that's done. */
-	fde = event_add_fd(ctdb->ev, state, state->fd[0], EVENT_FD_READ,
-			   ctdb_event_script_handler, state);
+	fde = tevent_add_fd(ctdb->ev, state, state->fd[0], TEVENT_FD_READ,
+			    ctdb_event_script_handler, state);
 	tevent_fd_set_auto_close(fde);
 
 	return 0;
@@ -334,7 +352,7 @@ static int fork_child_for_script(struct ctdb_context *ctdb,
 /*
  Summarize status of this run of scripts.
  */
-static int script_status(struct ctdb_scripts_wire *scripts)
+static int script_status(struct ctdb_script_list_old *scripts)
 {
 	unsigned int i;
 
@@ -358,12 +376,13 @@ static int script_status(struct ctdb_scripts_wire *scripts)
 }
 
 /* called when child is finished */
-static void ctdb_event_script_handler(struct event_context *ev, struct fd_event *fde,
+static void ctdb_event_script_handler(struct tevent_context *ev,
+				      struct tevent_fd *fde,
 				      uint16_t flags, void *p)
 {
 	struct ctdb_event_script_state *state =
 		talloc_get_type(p, struct ctdb_event_script_state);
-	struct ctdb_script_wire *current = get_current_script(state);
+	struct ctdb_script *current = get_current_script(state);
 	struct ctdb_context *ctdb = state->ctdb;
 	int r, status;
 
@@ -401,7 +420,6 @@ static void ctdb_event_script_handler(struct event_context *ev, struct fd_event
 			       state->options, status));
 		}
 
-		ctdb->event_script_timeouts = 0;
 		talloc_free(state);
 		return;
 	}
@@ -422,7 +440,7 @@ static void ctdb_event_script_handler(struct event_context *ev, struct fd_event
 struct debug_hung_script_state {
 	struct ctdb_context *ctdb;
 	pid_t child;
-	enum ctdb_eventscript_call call;
+	enum ctdb_event call;
 };
 
 static int debug_hung_script_state_destructor(struct debug_hung_script_state *state)
@@ -508,7 +526,7 @@ static void ctdb_run_debug_hung_script(struct ctdb_context *ctdb, struct debug_h
 		return;
 	}
 
-	tfd = tevent_add_fd(ctdb->ev, state, fd[0], EVENT_FD_READ,
+	tfd = tevent_add_fd(ctdb->ev, state, fd[0], TEVENT_FD_READ,
 			    debug_hung_script_done, state);
 	if (tfd == NULL) {
 		talloc_free(ttimer);
@@ -519,18 +537,19 @@ static void ctdb_run_debug_hung_script(struct ctdb_context *ctdb, struct debug_h
 }
 
 /* called when child times out */
-static void ctdb_event_script_timeout(struct event_context *ev, struct timed_event *te,
+static void ctdb_event_script_timeout(struct tevent_context *ev,
+				      struct tevent_timer *te,
 				      struct timeval t, void *p)
 {
 	struct ctdb_event_script_state *state = talloc_get_type(p, struct ctdb_event_script_state);
 	struct ctdb_context *ctdb = state->ctdb;
-	struct ctdb_script_wire *current = get_current_script(state);
+	struct ctdb_script *current = get_current_script(state);
 	struct debug_hung_script_state *debug_state;
 
-	DEBUG(DEBUG_ERR,("Event script '%s %s %s' timed out after %.1fs, count: %u, pid: %d\n",
+	DEBUG(DEBUG_ERR,("Event script '%s %s %s' timed out after %.1fs, pid: %d\n",
 			 current->name, ctdb_eventscript_call_names[state->call], state->options,
 			 timeval_elapsed(&current->start),
-			 ctdb->event_script_timeouts, state->child));
+			 state->child));
 
 	/* ignore timeouts for these events */
 	switch (state->call) {
@@ -647,7 +666,7 @@ static unsigned int count_words(const char *options)
 	return words;
 }
 
-static bool check_options(enum ctdb_eventscript_call call, const char *options)
+static bool check_options(enum ctdb_event call, const char *options)
 {
 	switch (call) {
 	/* These all take no arguments. */
@@ -669,7 +688,7 @@ static bool check_options(enum ctdb_eventscript_call call, const char *options)
 		return count_words(options) == 4;
 
 	default:
-		DEBUG(DEBUG_ERR,(__location__ "Unknown ctdb_eventscript_call %u\n", call));
+		DEBUG(DEBUG_ERR,(__location__ "Unknown ctdb_event %u\n", call));
 		return false;
 	}
 }
@@ -688,7 +707,7 @@ static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
 					const void *mem_ctx,
 					void (*callback)(struct ctdb_context *, int, void *),
 					void *private_data,
-					enum ctdb_eventscript_call call,
+					enum ctdb_event call,
 					const char *fmt, va_list ap)
 {
 	struct ctdb_event_script_state *state;
@@ -696,7 +715,7 @@ static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
 	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
 		/* we guarantee that only some specifically allowed event scripts are run
 		   while in recovery */
-		const enum ctdb_eventscript_call allowed_calls[] = {
+		const enum ctdb_event allowed_calls[] = {
 			CTDB_EVENT_INIT,
 			CTDB_EVENT_SETUP,
 			CTDB_EVENT_START_RECOVERY,
@@ -811,7 +830,10 @@ static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
  	}
 
 	if (!timeval_is_zero(&state->timeout)) {
-		event_add_timed(ctdb->ev, state, timeval_current_ofs(state->timeout.tv_sec, state->timeout.tv_usec), ctdb_event_script_timeout, state);
+		tevent_add_timer(ctdb->ev, state,
+				 timeval_current_ofs(state->timeout.tv_sec,
+						     state->timeout.tv_usec),
+				 ctdb_event_script_timeout, state);
 	} else {
 		DEBUG(DEBUG_ERR, (__location__ " eventscript %s %s called with no timeout\n",
 				  ctdb_eventscript_call_names[state->call],
@@ -830,7 +852,7 @@ int ctdb_event_script_callback(struct ctdb_context *ctdb,
 			       TALLOC_CTX *mem_ctx,
 			       void (*callback)(struct ctdb_context *, int, void *),
 			       void *private_data,
-			       enum ctdb_eventscript_call call,
+			       enum ctdb_event call,
 			       const char *fmt, ...)
 {
 	va_list ap;
@@ -863,7 +885,7 @@ static void event_script_callback(struct ctdb_context *ctdb, int status, void *p
   run the event script, waiting for it to complete. Used when the caller
   doesn't want to continue till the event script has finished.
  */
-int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_eventscript_call call,
+int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_event call,
 			   const char *fmt, ...)
 {
 	va_list ap;
@@ -881,7 +903,7 @@ int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_eventscript_call
 		return ret;
 	}
 
-	while (status.done == false && event_loop_once(ctdb->ev) == 0) /* noop */;
+	while (status.done == false && tevent_loop_once(ctdb->ev) == 0) /* noop */;
 
 	if (status.status == -ETIME) {
 		DEBUG(DEBUG_ERR, (__location__ " eventscript for '%s' timedout."
@@ -898,14 +920,14 @@ int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_eventscript_call
 	return status.status;
 }
 
-int ctdb_event_script(struct ctdb_context *ctdb, enum ctdb_eventscript_call call)
+int ctdb_event_script(struct ctdb_context *ctdb, enum ctdb_event call)
 {
 	/* GCC complains about empty format string, so use %s and "". */
 	return ctdb_event_script_args(ctdb, call, "%s", "");
 }
 
 struct eventscript_callback_state {
-	struct ctdb_req_control *c;
+	struct ctdb_req_control_old *c;
 };
 
 /*
@@ -938,7 +960,7 @@ static void run_eventscripts_callback(struct ctdb_context *ctdb, int status,
 
 
 /* Returns rest of string, or NULL if no match. */
-static const char *get_call(const char *p, enum ctdb_eventscript_call *call)
+static const char *get_call(const char *p, enum ctdb_event *call)
 {
 	unsigned int len;
 
@@ -962,13 +984,13 @@ static const char *get_call(const char *p, enum ctdb_eventscript_call *call)
   A control to force running of the eventscripts from the ctdb client tool
 */
 int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb,
-		struct ctdb_req_control *c,
+		struct ctdb_req_control_old *c,
 		TDB_DATA indata, bool *async_reply)
 {
 	int ret;
 	struct eventscript_callback_state *state;
 	const char *options;
-	enum ctdb_eventscript_call call;
+	enum ctdb_event call;
 
 	/* Figure out what call they want. */
 	options = get_call((const char *)indata.dptr, &call);
diff --git a/ctdb/server/ipalloc.c b/ctdb/server/ipalloc.c
new file mode 100644
index 0000000..ae9e8de
--- /dev/null
+++ b/ctdb/server/ipalloc.c
@@ -0,0 +1,53 @@
+/*
+   ctdb ip takeover code
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Martin Schwenke  2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include "lib/util/debug.h"
+
+#include "common/logging.h"
+
+#include "server/ipalloc_private.h"
+
+/* The calculation part of the IP allocation algorithm. */
+bool ipalloc(struct ipalloc_state *ipalloc_state)
+{
+	bool ret = false;
+
+	switch (ipalloc_state->algorithm) {
+	case IPALLOC_LCP2:
+		ret = ipalloc_lcp2(ipalloc_state);
+		break;
+	case IPALLOC_DETERMINISTIC:
+		ret = ipalloc_deterministic(ipalloc_state);
+		break;
+	case IPALLOC_NONDETERMINISTIC:
+		ret = ipalloc_nondeterministic(ipalloc_state);
+               break;
+	}
+
+	/* at this point ->pnn is the node which will own each IP
+	   or -1 if there is no node that can cover this ip
+	*/
+
+	return ret;
+}
diff --git a/ctdb/server/ipalloc.h b/ctdb/server/ipalloc.h
new file mode 100644
index 0000000..65c7786
--- /dev/null
+++ b/ctdb/server/ipalloc.h
@@ -0,0 +1,63 @@
+/*
+   CTDB IP takeover code
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Martin Schwenke  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_IPALLOC_H__
+#define __CTDB_IPALLOC_H__
+
+#include "replace.h"
+#include "system/network.h"
+
+#include "include/ctdb_protocol.h"
+
+struct public_ip_list {
+	struct public_ip_list *next;
+	uint32_t pnn;
+	ctdb_sock_addr addr;
+};
+
+#define IP_KEYLEN	4
+uint32_t *ip_key(ctdb_sock_addr *ip);
+
+/* Flags used in IP allocation algorithms. */
+enum ipalloc_algorithm {
+	IPALLOC_DETERMINISTIC,
+	IPALLOC_NONDETERMINISTIC,
+	IPALLOC_LCP2,
+};
+
+struct ipalloc_state {
+	uint32_t num;
+
+	/* Arrays with data for each node */
+	struct ctdb_public_ip_list_old **known_public_ips;
+	struct ctdb_public_ip_list_old **available_public_ips;
+	bool *noiptakeover;
+	bool *noiphost;
+
+	struct public_ip_list *all_ips;
+	enum ipalloc_algorithm algorithm;
+	uint32_t no_ip_failback;
+	uint32_t *force_rebalance_nodes;
+};
+
+bool ipalloc(struct ipalloc_state *ipalloc_state);
+
+#endif /* __CTDB_IPALLOC_H__ */
diff --git a/ctdb/server/ipalloc_common.c b/ctdb/server/ipalloc_common.c
new file mode 100644
index 0000000..9e4de59
--- /dev/null
+++ b/ctdb/server/ipalloc_common.c
@@ -0,0 +1,206 @@
+/*
+   ctdb ip takeover code
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Martin Schwenke  2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include "ctdb_private.h"
+
+#include "lib/util/time.h"
+
+#include "lib/util/debug.h"
+#include "common/logging.h"
+
+#include "common/common.h"
+#include "common/rb_tree.h"
+
+#include "include/ctdb_protocol.h"
+
+#include "server/ipalloc_private.h"
+
+#define TAKEOVER_TIMEOUT() timeval_current_ofs(ctdb->tunable.takeover_timeout,0)
+
+/* Given a physical node, return the number of
+   public addresses that is currently assigned to this node.
+*/
+int node_ip_coverage(int32_t pnn, struct public_ip_list *ips)
+{
+	int num=0;
+
+	for (;ips;ips=ips->next) {
+		if (ips->pnn == pnn) {
+			num++;
+		}
+	}
+	return num;
+}
+
+
+/* Can the given node host the given IP: is the public IP known to the
+ * node and is NOIPHOST unset?
+*/
+static bool can_node_host_ip(struct ipalloc_state *ipalloc_state,
+			     int32_t pnn,
+			     struct public_ip_list *ip)
+{
+	struct ctdb_public_ip_list_old *public_ips;
+	int i;
+
+	if (ipalloc_state->noiphost[pnn]) {
+		return false;
+	}
+
+	public_ips = ipalloc_state->available_public_ips[pnn];
+
+	if (public_ips == NULL) {
+		return false;
+	}
+
+	for (i=0; i<public_ips->num; i++) {
+		if (ctdb_same_ip(&ip->addr, &public_ips->ips[i].addr)) {
+			/* yes, this node can serve this public ip */
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool can_node_takeover_ip(struct ipalloc_state *ipalloc_state,
+			  int32_t pnn,
+			  struct public_ip_list *ip)
+{
+	if (ipalloc_state->noiptakeover[pnn]) {
+		return false;
+	}
+
+	return can_node_host_ip(ipalloc_state, pnn, ip);
+}
+
+/* search the node lists list for a node to takeover this ip.
+   pick the node that currently are serving the least number of ips
+   so that the ips get spread out evenly.
+*/
+int find_takeover_node(struct ipalloc_state *ipalloc_state,
+		       struct public_ip_list *ip)
+{
+	int pnn, min=0, num;
+	int i, numnodes;
+
+	numnodes = ipalloc_state->num;
+	pnn    = -1;
+	for (i=0; i<numnodes; i++) {
+		/* verify that this node can serve this ip */
+		if (!can_node_takeover_ip(ipalloc_state, i, ip)) {
+			/* no it couldnt   so skip to the next node */
+			continue;
+		}
+
+		num = node_ip_coverage(i, ipalloc_state->all_ips);
+		/* was this the first node we checked ? */
+		if (pnn == -1) {
+			pnn = i;
+			min  = num;
+		} else {
+			if (num < min) {
+				pnn = i;
+				min  = num;
+			}
+		}
+	}
+	if (pnn == -1) {
+		DEBUG(DEBUG_WARNING,(__location__ " Could not find node to take over public address '%s'\n",
+			ctdb_addr_to_str(&ip->addr)));
+
+		return -1;
+	}
+
+	ip->pnn = pnn;
+	return 0;
+}
+
+uint32_t *ip_key(ctdb_sock_addr *ip)
+{
+	static uint32_t key[IP_KEYLEN];
+
+	bzero(key, sizeof(key));
+
+	switch (ip->sa.sa_family) {
+	case AF_INET:
+		key[3]	= htonl(ip->ip.sin_addr.s_addr);
+		break;
+	case AF_INET6: {
+		uint32_t *s6_a32 = (uint32_t *)&(ip->ip6.sin6_addr.s6_addr);
+		key[0]	= htonl(s6_a32[0]);
+		key[1]	= htonl(s6_a32[1]);
+		key[2]	= htonl(s6_a32[2]);
+		key[3]	= htonl(s6_a32[3]);
+		break;
+	}
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", ip->sa.sa_family));
+		return key;
+	}
+
+	return key;
+}
+
+/* Allocate any unassigned IPs just by looping through the IPs and
+ * finding the best node for each.
+ */
+void basic_allocate_unassigned(struct ipalloc_state *ipalloc_state)
+{
+	struct public_ip_list *t;
+
+	/* loop over all ip's and find a physical node to cover for
+	   each unassigned ip.
+	*/
+	for (t = ipalloc_state->all_ips; t != NULL; t = t->next) {
+		if (t->pnn == -1) {
+			if (find_takeover_node(ipalloc_state, t)) {
+				DEBUG(DEBUG_WARNING,
+				      ("Failed to find node to cover ip %s\n",
+				       ctdb_addr_to_str(&t->addr)));
+			}
+		}
+	}
+}
+
+void unassign_unsuitable_ips(struct ipalloc_state *ipalloc_state)
+{
+	struct public_ip_list *t;
+
+	/* verify that the assigned nodes can serve that public ip
+	   and set it to -1 if not
+	*/
+	for (t = ipalloc_state->all_ips; t != NULL; t = t->next) {
+		if (t->pnn == -1) {
+			continue;
+		}
+		if (!can_node_host_ip(ipalloc_state, t->pnn, t) != 0) {
+			/* this node can not serve this ip. */
+			DEBUG(DEBUG_DEBUG,("Unassign IP: %s from %d\n",
+					   ctdb_addr_to_str(&(t->addr)),
+					   t->pnn));
+			t->pnn = -1;
+		}
+	}
+}
diff --git a/ctdb/server/ipalloc_deterministic.c b/ctdb/server/ipalloc_deterministic.c
new file mode 100644
index 0000000..2801bf6
--- /dev/null
+++ b/ctdb/server/ipalloc_deterministic.c
@@ -0,0 +1,62 @@
+/*
+   ctdb ip takeover code
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Martin Schwenke  2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include "lib/util/debug.h"
+#include "common/logging.h"
+
+#include "server/ipalloc_private.h"
+
+bool ipalloc_deterministic(struct ipalloc_state *ipalloc_state)
+{
+	struct public_ip_list *t;
+	int i, numnodes;
+
+	numnodes = ipalloc_state->num;
+
+	DEBUG(DEBUG_NOTICE,("Deterministic IPs enabled. Resetting all ip allocations\n"));
+       /* Allocate IPs to nodes in a modulo fashion so that IPs will
+        *  always be allocated the same way for a specific set of
+        *  available/unavailable nodes.
+	*/
+
+	for (i = 0, t = ipalloc_state->all_ips; t!= NULL; t = t->next, i++) {
+		t->pnn = i % numnodes;
+	}
+
+	/* IP failback doesn't make sense with deterministic
+	 * IPs, since the modulo step above implicitly fails
+	 * back IPs to their "home" node.
+	 */
+	if (1 == ipalloc_state->no_ip_failback) {
+		DEBUG(DEBUG_WARNING, ("WARNING: 'NoIPFailback' set but ignored - incompatible with 'DeterministicIPs\n"));
+	}
+
+	unassign_unsuitable_ips(ipalloc_state);
+
+	basic_allocate_unassigned(ipalloc_state);
+
+	/* No failback here! */
+
+	return true;
+}
diff --git a/ctdb/server/ipalloc_lcp2.c b/ctdb/server/ipalloc_lcp2.c
new file mode 100644
index 0000000..0dd9364
--- /dev/null
+++ b/ctdb/server/ipalloc_lcp2.c
@@ -0,0 +1,515 @@
+/*
+   ctdb ip takeover code
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Martin Schwenke  2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include "lib/util/debug.h"
+#include "common/logging.h"
+
+#include "protocol/protocol_api.h"
+
+#include "server/ipalloc_private.h"
+
+/*
+ * This is the length of the longtest common prefix between the IPs.
+ * It is calculated by XOR-ing the 2 IPs together and counting the
+ * number of leading zeroes.  The implementation means that all
+ * addresses end up being 128 bits long.
+ *
+ * FIXME? Should we consider IPv4 and IPv6 separately given that the
+ * 12 bytes of 0 prefix padding will hurt the algorithm if there are
+ * lots of nodes and IP addresses?
+ */
+static uint32_t ip_distance(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
+{
+	uint32_t ip1_k[IP_KEYLEN];
+	uint32_t *t;
+	int i;
+	uint32_t x;
+
+	uint32_t distance = 0;
+
+	memcpy(ip1_k, ip_key(ip1), sizeof(ip1_k));
+	t = ip_key(ip2);
+	for (i=0; i<IP_KEYLEN; i++) {
+		x = ip1_k[i] ^ t[i];
+		if (x == 0) {
+			distance += 32;
+		} else {
+			/* Count number of leading zeroes.
+			 * FIXME? This could be optimised...
+			 */
+			while ((x & (1 << 31)) == 0) {
+				x <<= 1;
+				distance += 1;
+			}
+		}
+	}
+
+	return distance;
+}
+
+/* Calculate the IP distance for the given IP relative to IPs on the
+   given node.  The ips argument is generally the all_ips variable
+   used in the main part of the algorithm.
+ */
+static uint32_t ip_distance_2_sum(ctdb_sock_addr *ip,
+				  struct public_ip_list *ips,
+				  int pnn)
+{
+	struct public_ip_list *t;
+	uint32_t d;
+
+	uint32_t sum = 0;
+
+	for (t = ips; t != NULL; t = t->next) {
+		if (t->pnn != pnn) {
+			continue;
+		}
+
+		/* Optimisation: We never calculate the distance
+		 * between an address and itself.  This allows us to
+		 * calculate the effect of removing an address from a
+		 * node by simply calculating the distance between
+		 * that address and all of the exitsing addresses.
+		 * Moreover, we assume that we're only ever dealing
+		 * with addresses from all_ips so we can identify an
+		 * address via a pointer rather than doing a more
+		 * expensive address comparison. */
+		if (&(t->addr) == ip) {
+			continue;
+		}
+
+		d = ip_distance(ip, &(t->addr));
+		sum += d * d;  /* Cheaper than pulling in math.h :-) */
+	}
+
+	return sum;
+}
+
+/* Return the LCP2 imbalance metric for addresses currently assigned
+   to the given node.
+ */
+static uint32_t lcp2_imbalance(struct public_ip_list * all_ips, int pnn)
+{
+	struct public_ip_list *t;
+
+	uint32_t imbalance = 0;
+
+	for (t = all_ips; t != NULL; t = t->next) {
+		if (t->pnn != pnn) {
+			continue;
+		}
+		/* Pass the rest of the IPs rather than the whole
+		   all_ips input list.
+		*/
+		imbalance += ip_distance_2_sum(&(t->addr), t->next, pnn);
+	}
+
+	return imbalance;
+}
+
+static bool lcp2_init(struct ipalloc_state *ipalloc_state,
+		      uint32_t **lcp2_imbalances,
+		      bool **rebalance_candidates)
+{
+	int i, numnodes;
+	struct public_ip_list *t;
+
+	numnodes = ipalloc_state->num;
+
+	*rebalance_candidates = talloc_array(ipalloc_state, bool, numnodes);
+	if (*rebalance_candidates == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
+		return false;
+	}
+	*lcp2_imbalances = talloc_array(ipalloc_state, uint32_t, numnodes);
+	if (*lcp2_imbalances == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
+		return false;
+	}
+
+	for (i=0; i<numnodes; i++) {
+		(*lcp2_imbalances)[i] =
+			lcp2_imbalance(ipalloc_state->all_ips, i);
+		/* First step: assume all nodes are candidates */
+		(*rebalance_candidates)[i] = true;
+	}
+
+	/* 2nd step: if a node has IPs assigned then it must have been
+	 * healthy before, so we remove it from consideration.  This
+	 * is overkill but is all we have because we don't maintain
+	 * state between takeover runs.  An alternative would be to
+	 * keep state and invalidate it every time the recovery master
+	 * changes.
+	 */
+	for (t = ipalloc_state->all_ips; t != NULL; t = t->next) {
+		if (t->pnn != -1) {
+			(*rebalance_candidates)[t->pnn] = false;
+		}
+	}
+
+	/* 3rd step: if a node is forced to re-balance then
+	   we allow failback onto the node */
+	if (ipalloc_state->force_rebalance_nodes == NULL) {
+		return true;
+	}
+	for (i = 0;
+	     i < talloc_array_length(ipalloc_state->force_rebalance_nodes);
+	     i++) {
+		uint32_t pnn = ipalloc_state->force_rebalance_nodes[i];
+		if (pnn >= numnodes) {
+			DEBUG(DEBUG_ERR,
+			      (__location__ "unknown node %u\n", pnn));
+			continue;
+		}
+
+		DEBUG(DEBUG_NOTICE,
+		      ("Forcing rebalancing of IPs to node %u\n", pnn));
+		(*rebalance_candidates)[pnn] = true;
+	}
+
+	return true;
+}
+
+/* Allocate any unassigned addresses using the LCP2 algorithm to find
+ * the IP/node combination that will cost the least.
+ */
+static void lcp2_allocate_unassigned(struct ipalloc_state *ipalloc_state,
+				     uint32_t *lcp2_imbalances)
+{
+	struct public_ip_list *t;
+	int dstnode, numnodes;
+
+	int minnode;
+	uint32_t mindsum, dstdsum, dstimbl, minimbl;
+	struct public_ip_list *minip;
+
+	bool should_loop = true;
+	bool have_unassigned = true;
+
+	numnodes = ipalloc_state->num;
+
+	while (have_unassigned && should_loop) {
+		should_loop = false;
+
+		DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
+		DEBUG(DEBUG_DEBUG,(" CONSIDERING MOVES (UNASSIGNED)\n"));
+
+		minnode = -1;
+		mindsum = 0;
+		minip = NULL;
+
+		/* loop over each unassigned ip. */
+		for (t = ipalloc_state->all_ips; t != NULL ; t = t->next) {
+			if (t->pnn != -1) {
+				continue;
+			}
+
+			for (dstnode = 0; dstnode < numnodes; dstnode++) {
+				/* only check nodes that can actually takeover this ip */
+				if (!can_node_takeover_ip(ipalloc_state,
+							  dstnode,
+							  t)) {
+					/* no it couldnt   so skip to the next node */
+					continue;
+				}
+
+				dstdsum = ip_distance_2_sum(&(t->addr),
+							    ipalloc_state->all_ips,
+							    dstnode);
+				dstimbl = lcp2_imbalances[dstnode] + dstdsum;
+				DEBUG(DEBUG_DEBUG,
+				      (" %s -> %d [+%d]\n",
+				       ctdb_sock_addr_to_string(ipalloc_state,
+								&(t->addr)),
+				       dstnode,
+				       dstimbl - lcp2_imbalances[dstnode]));
+
+
+				if ((minnode == -1) || (dstdsum < mindsum)) {
+					minnode = dstnode;
+					minimbl = dstimbl;
+					mindsum = dstdsum;
+					minip = t;
+					should_loop = true;
+				}
+			}
+		}
+
+		DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
+
+		/* If we found one then assign it to the given node. */
+		if (minnode != -1) {
+			minip->pnn = minnode;
+			lcp2_imbalances[minnode] = minimbl;
+			DEBUG(DEBUG_INFO,(" %s -> %d [+%d]\n",
+					  ctdb_sock_addr_to_string(
+						  ipalloc_state,
+						  &(minip->addr)),
+					  minnode,
+					  mindsum));
+		}
+
+		/* There might be a better way but at least this is clear. */
+		have_unassigned = false;
+		for (t = ipalloc_state->all_ips; t != NULL; t = t->next) {
+			if (t->pnn == -1) {
+				have_unassigned = true;
+			}
+		}
+	}
+
+	/* We know if we have an unassigned addresses so we might as
+	 * well optimise.
+	 */
+	if (have_unassigned) {
+		for (t = ipalloc_state->all_ips; t != NULL; t = t->next) {
+			if (t->pnn == -1) {
+				DEBUG(DEBUG_WARNING,
+				      ("Failed to find node to cover ip %s\n",
+				       ctdb_sock_addr_to_string(ipalloc_state,
+								&t->addr)));
+			}
+		}
+	}
+}
+
+/* LCP2 algorithm for rebalancing the cluster.  Given a candidate node
+ * to move IPs from, determines the best IP/destination node
+ * combination to move from the source node.
+ */
+static bool lcp2_failback_candidate(struct ipalloc_state *ipalloc_state,
+				    int srcnode,
+				    uint32_t *lcp2_imbalances,
+				    bool *rebalance_candidates)
+{
+	int dstnode, mindstnode, numnodes;
+	uint32_t srcimbl, srcdsum, dstimbl, dstdsum;
+	uint32_t minsrcimbl, mindstimbl;
+	struct public_ip_list *minip;
+	struct public_ip_list *t;
+
+	/* Find an IP and destination node that best reduces imbalance. */
+	srcimbl = 0;
+	minip = NULL;
+	minsrcimbl = 0;
+	mindstnode = -1;
+	mindstimbl = 0;
+
+	numnodes = ipalloc_state->num;
+
+	DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
+	DEBUG(DEBUG_DEBUG,(" CONSIDERING MOVES FROM %d [%d]\n",
+			   srcnode, lcp2_imbalances[srcnode]));
+
+	for (t = ipalloc_state->all_ips; t != NULL; t = t->next) {
+		/* Only consider addresses on srcnode. */
+		if (t->pnn != srcnode) {
+			continue;
+		}
+
+		/* What is this IP address costing the source node? */
+		srcdsum = ip_distance_2_sum(&(t->addr),
+					    ipalloc_state->all_ips,
+					    srcnode);
+		srcimbl = lcp2_imbalances[srcnode] - srcdsum;
+
+		/* Consider this IP address would cost each potential
+		 * destination node.  Destination nodes are limited to
+		 * those that are newly healthy, since we don't want
+		 * to do gratuitous failover of IPs just to make minor
+		 * balance improvements.
+		 */
+		for (dstnode = 0; dstnode < numnodes; dstnode++) {
+			if (!rebalance_candidates[dstnode]) {
+				continue;
+			}
+
+			/* only check nodes that can actually takeover this ip */
+			if (!can_node_takeover_ip(ipalloc_state, dstnode,
+						  t)) {
+				/* no it couldnt   so skip to the next node */
+				continue;
+			}
+
+			dstdsum = ip_distance_2_sum(&(t->addr),
+						    ipalloc_state->all_ips,
+						    dstnode);
+			dstimbl = lcp2_imbalances[dstnode] + dstdsum;
+			DEBUG(DEBUG_DEBUG,(" %d [%d] -> %s -> %d [+%d]\n",
+					   srcnode, -srcdsum,
+					   ctdb_sock_addr_to_string(
+						   ipalloc_state, &(t->addr)),
+					   dstnode, dstdsum));
+
+			if ((dstimbl < lcp2_imbalances[srcnode]) &&
+			    (dstdsum < srcdsum) &&			\
+			    ((mindstnode == -1) ||				\
+			     ((srcimbl + dstimbl) < (minsrcimbl + mindstimbl)))) {
+
+				minip = t;
+				minsrcimbl = srcimbl;
+				mindstnode = dstnode;
+				mindstimbl = dstimbl;
+			}
+		}
+	}
+	DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
+
+        if (mindstnode != -1) {
+		/* We found a move that makes things better... */
+		DEBUG(DEBUG_INFO,
+		      ("%d [%d] -> %s -> %d [+%d]\n",
+		       srcnode, minsrcimbl - lcp2_imbalances[srcnode],
+		       ctdb_sock_addr_to_string(ipalloc_state, &(minip->addr)),
+		       mindstnode, mindstimbl - lcp2_imbalances[mindstnode]));
+
+
+		lcp2_imbalances[srcnode] = minsrcimbl;
+		lcp2_imbalances[mindstnode] = mindstimbl;
+		minip->pnn = mindstnode;
+
+		return true;
+	}
+
+        return false;
+}
+
+struct lcp2_imbalance_pnn {
+	uint32_t imbalance;
+	int pnn;
+};
+
+static int lcp2_cmp_imbalance_pnn(const void * a, const void * b)
+{
+	const struct lcp2_imbalance_pnn * lipa = (const struct lcp2_imbalance_pnn *) a;
+	const struct lcp2_imbalance_pnn * lipb = (const struct lcp2_imbalance_pnn *) b;
+
+	if (lipa->imbalance > lipb->imbalance) {
+		return -1;
+	} else if (lipa->imbalance == lipb->imbalance) {
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+/* LCP2 algorithm for rebalancing the cluster.  This finds the source
+ * node with the highest LCP2 imbalance, and then determines the best
+ * IP/destination node combination to move from the source node.
+ */
+static void lcp2_failback(struct ipalloc_state *ipalloc_state,
+			  uint32_t *lcp2_imbalances,
+			  bool *rebalance_candidates)
+{
+	int i, numnodes;
+	struct lcp2_imbalance_pnn * lips;
+	bool again;
+
+	numnodes = ipalloc_state->num;
+
+try_again:
+	/* Put the imbalances and nodes into an array, sort them and
+	 * iterate through candidates.  Usually the 1st one will be
+	 * used, so this doesn't cost much...
+	 */
+	DEBUG(DEBUG_DEBUG,("+++++++++++++++++++++++++++++++++++++++++\n"));
+	DEBUG(DEBUG_DEBUG,("Selecting most imbalanced node from:\n"));
+	lips = talloc_array(ipalloc_state, struct lcp2_imbalance_pnn, numnodes);
+	for (i = 0; i < numnodes; i++) {
+		lips[i].imbalance = lcp2_imbalances[i];
+		lips[i].pnn = i;
+		DEBUG(DEBUG_DEBUG,(" %d [%d]\n", i, lcp2_imbalances[i]));
+	}
+	qsort(lips, numnodes, sizeof(struct lcp2_imbalance_pnn),
+	      lcp2_cmp_imbalance_pnn);
+
+	again = false;
+	for (i = 0; i < numnodes; i++) {
+		/* This means that all nodes had 0 or 1 addresses, so
+		 * can't be imbalanced.
+		 */
+		if (lips[i].imbalance == 0) {
+			break;
+		}
+
+		if (lcp2_failback_candidate(ipalloc_state,
+					    lips[i].pnn,
+					    lcp2_imbalances,
+					    rebalance_candidates)) {
+			again = true;
+			break;
+		}
+	}
+
+	talloc_free(lips);
+	if (again) {
+		goto try_again;
+	}
+}
+
+bool ipalloc_lcp2(struct ipalloc_state *ipalloc_state)
+{
+	uint32_t *lcp2_imbalances;
+	bool *rebalance_candidates;
+	int numnodes, num_rebalance_candidates, i;
+	bool ret = true;
+
+	unassign_unsuitable_ips(ipalloc_state);
+
+	if (!lcp2_init(ipalloc_state,
+		       &lcp2_imbalances, &rebalance_candidates)) {
+		ret = false;
+		goto finished;
+	}
+
+	lcp2_allocate_unassigned(ipalloc_state, lcp2_imbalances);
+
+	/* If we don't want IPs to fail back then don't rebalance IPs. */
+	if (1 == ipalloc_state->no_ip_failback) {
+		goto finished;
+	}
+
+	/* It is only worth continuing if we have suitable target
+	 * nodes to transfer IPs to.  This check is much cheaper than
+	 * continuing on...
+	 */
+	numnodes = ipalloc_state->num;
+	num_rebalance_candidates = 0;
+	for (i=0; i<numnodes; i++) {
+		if (rebalance_candidates[i]) {
+			num_rebalance_candidates++;
+		}
+	}
+	if (num_rebalance_candidates == 0) {
+		goto finished;
+	}
+
+	/* Now, try to make sure the ip adresses are evenly distributed
+	   across the nodes.
+	*/
+	lcp2_failback(ipalloc_state, lcp2_imbalances, rebalance_candidates);
+
+finished:
+	return ret;
+}
diff --git a/ctdb/server/ipalloc_nondeterministic.c b/ctdb/server/ipalloc_nondeterministic.c
new file mode 100644
index 0000000..300d8f1
--- /dev/null
+++ b/ctdb/server/ipalloc_nondeterministic.c
@@ -0,0 +1,147 @@
+/*
+   ctdb ip takeover code
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Martin Schwenke  2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include "ctdb_private.h"
+
+#include "lib/util/debug.h"
+#include "common/logging.h"
+#include "common/common.h"
+
+#include "server/ipalloc_private.h"
+
+/* Basic non-deterministic rebalancing algorithm.
+ */
+static void basic_failback(struct ipalloc_state *ipalloc_state,
+			   int num_ips)
+{
+	int i, numnodes;
+	int maxnode, maxnum, minnode, minnum, num, retries;
+	struct public_ip_list *t;
+
+	numnodes = ipalloc_state->num;
+	retries = 0;
+
+try_again:
+	maxnum=0;
+	minnum=0;
+
+	/* for each ip address, loop over all nodes that can serve
+	   this ip and make sure that the difference between the node
+	   serving the most and the node serving the least ip's are
+	   not greater than 1.
+	*/
+	for (t = ipalloc_state->all_ips; t != NULL; t = t->next) {
+		if (t->pnn == -1) {
+			continue;
+		}
+
+		/* Get the highest and lowest number of ips's served by any 
+		   valid node which can serve this ip.
+		*/
+		maxnode = -1;
+		minnode = -1;
+		for (i=0; i<numnodes; i++) {
+			/* only check nodes that can actually serve this ip */
+			if (!can_node_takeover_ip(ipalloc_state, i,
+						  t)) {
+				/* no it couldnt   so skip to the next node */
+				continue;
+			}
+
+			num = node_ip_coverage(i, ipalloc_state->all_ips);
+			if (maxnode == -1) {
+				maxnode = i;
+				maxnum  = num;
+			} else {
+				if (num > maxnum) {
+					maxnode = i;
+					maxnum  = num;
+				}
+			}
+			if (minnode == -1) {
+				minnode = i;
+				minnum  = num;
+			} else {
+				if (num < minnum) {
+					minnode = i;
+					minnum  = num;
+				}
+			}
+		}
+		if (maxnode == -1) {
+			DEBUG(DEBUG_WARNING,
+			      (__location__ " Could not find maxnode. May not be able to serve ip '%s'\n",
+			       ctdb_addr_to_str(&t->addr)));
+
+			continue;
+		}
+
+		/* if the spread between the smallest and largest coverage by
+		   a node is >=2 we steal one of the ips from the node with
+		   most coverage to even things out a bit.
+		   try to do this a limited number of times since we dont
+		   want to spend too much time balancing the ip coverage.
+		*/
+		if ((maxnum > minnum+1) &&
+		    (retries < (num_ips + 5))){
+			struct public_ip_list *tt;
+
+			/* Reassign one of maxnode's VNNs */
+			for (tt = ipalloc_state->all_ips; tt != NULL; tt = tt->next) {
+				if (tt->pnn == maxnode) {
+					(void)find_takeover_node(ipalloc_state,
+								 tt);
+					retries++;
+					goto try_again;;
+				}
+			}
+		}
+	}
+}
+
+bool ipalloc_nondeterministic(struct ipalloc_state *ipalloc_state)
+{
+	/* This should be pushed down into basic_failback. */
+	struct public_ip_list *t;
+	int num_ips = 0;
+	for (t = ipalloc_state->all_ips; t != NULL; t = t->next) {
+		num_ips++;
+	}
+
+	unassign_unsuitable_ips(ipalloc_state);
+
+	basic_allocate_unassigned(ipalloc_state);
+
+	/* If we don't want IPs to fail back then don't rebalance IPs. */
+	if (1 == ipalloc_state->no_ip_failback) {
+		return true;
+	}
+
+	/* Now, try to make sure the ip adresses are evenly distributed
+	   across the nodes.
+	*/
+	basic_failback(ipalloc_state, num_ips);
+
+	return true;
+}
diff --git a/ctdb/server/ipalloc_private.h b/ctdb/server/ipalloc_private.h
new file mode 100644
index 0000000..3ffdeba
--- /dev/null
+++ b/ctdb/server/ipalloc_private.h
@@ -0,0 +1,43 @@
+/*
+   CTDB IP takeover code
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Martin Schwenke  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_IPALLOC_PRIVATE_H__
+#define __CTDB_IPALLOC_PRIVATE_H__
+
+#include "protocol/protocol.h"
+
+#include "server/ipalloc.h"
+
+bool can_node_takeover_ip(struct ipalloc_state *ipalloc_state,
+			  int32_t pnn,
+			  struct public_ip_list *ip);
+int node_ip_coverage(int32_t pnn, struct public_ip_list *ips);
+int find_takeover_node(struct ipalloc_state *ipalloc_state,
+		       struct public_ip_list *ip);
+
+void unassign_unsuitable_ips(struct ipalloc_state *ipalloc_state);
+void basic_allocate_unassigned(struct ipalloc_state *ipalloc_state);
+
+bool ipalloc_nondeterministic(struct ipalloc_state *ipalloc_state);
+bool ipalloc_deterministic(struct ipalloc_state *ipalloc_state);
+bool ipalloc_lcp2(struct ipalloc_state *ipalloc_state);
+
+#endif /* __CTDB_IPALLOC_PRIVATE_H__ */
diff --git a/ctdb/tcp/ctdb_tcp.h b/ctdb/tcp/ctdb_tcp.h
index 5b6b651..0a998c9 100644
--- a/ctdb/tcp/ctdb_tcp.h
+++ b/ctdb/tcp/ctdb_tcp.h
@@ -41,15 +41,15 @@ struct ctdb_incoming {
 struct ctdb_tcp_node {
 	int fd;
 	struct ctdb_queue *out_queue;
-	struct fd_event *connect_fde;
-	struct timed_event *connect_te;
+	struct tevent_fd *connect_fde;
+	struct tevent_timer *connect_te;
 };
 
 
 /* prototypes internal to tcp transport */
 int ctdb_tcp_queue_pkt(struct ctdb_node *node, uint8_t *data, uint32_t length);
 int ctdb_tcp_listen(struct ctdb_context *ctdb);
-void ctdb_tcp_node_connect(struct event_context *ev, struct timed_event *te, 
+void ctdb_tcp_node_connect(struct tevent_context *ev, struct tevent_timer *te,
 			   struct timeval t, void *private_data);
 void ctdb_tcp_read_cb(uint8_t *data, size_t cnt, void *args);
 void ctdb_tcp_tnode_cb(uint8_t *data, size_t cnt, void *private_data);
diff --git a/ctdb/tcp/tcp_connect.c b/ctdb/tcp/tcp_connect.c
index b106f22..fbb17c8 100644
--- a/ctdb/tcp/tcp_connect.c
+++ b/ctdb/tcp/tcp_connect.c
@@ -18,11 +18,22 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
-#include "../include/ctdb_private.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
+
 #include "ctdb_tcp.h"
 
 /*
@@ -60,15 +71,16 @@ void ctdb_tcp_tnode_cb(uint8_t *data, size_t cnt, void *private_data)
 	}
 
 	ctdb_tcp_stop_connection(node);
-	tnode->connect_te = event_add_timed(node->ctdb->ev, tnode,
-					    timeval_current_ofs(3, 0),
-					    ctdb_tcp_node_connect, node);
+	tnode->connect_te = tevent_add_timer(node->ctdb->ev, tnode,
+					     timeval_current_ofs(3, 0),
+					     ctdb_tcp_node_connect, node);
 }
 
 /*
   called when socket becomes writeable on connect
 */
-static void ctdb_node_connect_write(struct event_context *ev, struct fd_event *fde, 
+static void ctdb_node_connect_write(struct tevent_context *ev,
+				    struct tevent_fd *fde,
 				    uint16_t flags, void *private_data)
 {
 	struct ctdb_node *node = talloc_get_type(private_data,
@@ -86,7 +98,7 @@ static void ctdb_node_connect_write(struct event_context *ev, struct fd_event *f
 	if (getsockopt(tnode->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0 ||
 	    error != 0) {
 		ctdb_tcp_stop_connection(node);
-		tnode->connect_te = event_add_timed(ctdb->ev, tnode, 
+		tnode->connect_te = tevent_add_timer(ctdb->ev, tnode,
 						    timeval_current_ofs(1, 0),
 						    ctdb_tcp_node_connect, node);
 		return;
@@ -114,7 +126,7 @@ static void ctdb_node_connect_write(struct event_context *ev, struct fd_event *f
 /*
   called when we should try and establish a tcp connection to a node
 */
-void ctdb_tcp_node_connect(struct event_context *ev, struct timed_event *te, 
+void ctdb_tcp_node_connect(struct tevent_context *ev, struct tevent_timer *te,
 			   struct timeval t, void *private_data)
 {
 	struct ctdb_node *node = talloc_get_type(private_data,
@@ -182,22 +194,23 @@ void ctdb_tcp_node_connect(struct event_context *ev, struct timed_event *te,
 	if (connect(tnode->fd, (struct sockaddr *)&sock_out, sockout_size) != 0 &&
 	    errno != EINPROGRESS) {
 		ctdb_tcp_stop_connection(node);
-		tnode->connect_te = event_add_timed(ctdb->ev, tnode, 
-						    timeval_current_ofs(1, 0),
-						    ctdb_tcp_node_connect, node);
+		tnode->connect_te = tevent_add_timer(ctdb->ev, tnode,
+						     timeval_current_ofs(1, 0),
+						     ctdb_tcp_node_connect, node);
 		return;
 	}
 
 	/* non-blocking connect - wait for write event */
-	tnode->connect_fde = event_add_fd(node->ctdb->ev, tnode, tnode->fd, 
-					  EVENT_FD_WRITE|EVENT_FD_READ, 
-					  ctdb_node_connect_write, node);
+	tnode->connect_fde = tevent_add_fd(node->ctdb->ev, tnode, tnode->fd,
+					   TEVENT_FD_WRITE|TEVENT_FD_READ,
+					   ctdb_node_connect_write, node);
 
 	/* don't give it long to connect - retry in one second. This ensures
 	   that we find a node is up quickly (tcp normally backs off a syn reply
 	   delay by quite a lot) */
-	tnode->connect_te = event_add_timed(ctdb->ev, tnode, timeval_current_ofs(1, 0), 
-					    ctdb_tcp_node_connect, node);
+	tnode->connect_te = tevent_add_timer(ctdb->ev, tnode,
+					     timeval_current_ofs(1, 0),
+					     ctdb_tcp_node_connect, node);
 }
 
 /*
@@ -205,7 +218,7 @@ void ctdb_tcp_node_connect(struct event_context *ev, struct timed_event *te,
   currently makes no attempt to check if the connection is really from a ctdb
   node in our cluster
 */
-static void ctdb_listen_event(struct event_context *ev, struct fd_event *fde, 
+static void ctdb_listen_event(struct tevent_context *ev, struct tevent_fd *fde,
 			      uint16_t flags, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
@@ -338,6 +351,9 @@ static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb)
 			DEBUG(DEBUG_ERR,(__location__ " Failed to bind() to socket. %s(%d)\n",
 					strerror(errno), errno));
 		}
+
+		close(ctcp->listen_fd);
+		ctcp->listen_fd = -1;
 	}
 
 	if (i == ctdb->num_nodes) {
@@ -367,8 +383,8 @@ static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb)
 		goto failed;
 	}
 
-	fde = event_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, EVENT_FD_READ,
-			   ctdb_listen_event, ctdb);
+	fde = tevent_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, TEVENT_FD_READ,
+			    ctdb_listen_event, ctdb);
 	tevent_fd_set_auto_close(fde);
 
 	close(lock_fd);
@@ -440,8 +456,8 @@ int ctdb_tcp_listen(struct ctdb_context *ctdb)
 		goto failed;
 	}
 
-	fde = event_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, EVENT_FD_READ,
-		     ctdb_listen_event, ctdb);	
+	fde = tevent_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, TEVENT_FD_READ,
+			    ctdb_listen_event, ctdb);
 	tevent_fd_set_auto_close(fde);
 
 	return 0;
diff --git a/ctdb/tcp/tcp_init.c b/ctdb/tcp/tcp_init.c
index dba3be3..b608366 100644
--- a/ctdb/tcp/tcp_init.c
+++ b/ctdb/tcp/tcp_init.c
@@ -17,11 +17,21 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
-#include "../include/ctdb_private.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/time.h"
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+
+#include "common/common.h"
+#include "common/logging.h"
+
 #include "ctdb_tcp.h"
 
 static int tnode_destructor(struct ctdb_tcp_node *tnode)
@@ -93,9 +103,10 @@ static int ctdb_tcp_connect_node(struct ctdb_node *node)
 	/* startup connection to the other server - will happen on
 	   next event loop */
 	if (!ctdb_same_address(ctdb->address, &node->address)) {
-		tnode->connect_te = event_add_timed(ctdb->ev, tnode, 
-						    timeval_zero(), 
-						    ctdb_tcp_node_connect, node);
+		tnode->connect_te = tevent_add_timer(ctdb->ev, tnode,
+						    timeval_zero(),
+						    ctdb_tcp_node_connect,
+						    node);
 	}
 
 	return 0;
@@ -114,8 +125,9 @@ static void ctdb_tcp_restart(struct ctdb_node *node)
 
 	ctdb_tcp_stop_connection(node);
 
-	tnode->connect_te = event_add_timed(node->ctdb->ev, tnode, timeval_zero(), 
-					    ctdb_tcp_node_connect, node);
+	tnode->connect_te = tevent_add_timer(node->ctdb->ev, tnode,
+					     timeval_zero(),
+					     ctdb_tcp_node_connect, node);
 }
 
 
diff --git a/ctdb/tcp/tcp_io.c b/ctdb/tcp/tcp_io.c
index a951320..5bb4b5b 100644
--- a/ctdb/tcp/tcp_io.c
+++ b/ctdb/tcp/tcp_io.c
@@ -17,12 +17,18 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "lib/util/dlinklist.h"
-#include "tdb.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
-#include "../include/ctdb_private.h"
+
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+
+#include "common/common.h"
+#include "common/logging.h"
+
 #include "ctdb_tcp.h"
 
 
diff --git a/ctdb/tests/complex/18_ctdb_reloadips.sh b/ctdb/tests/complex/18_ctdb_reloadips.sh
index 71f997c..9a40835 100755
--- a/ctdb/tests/complex/18_ctdb_reloadips.sh
+++ b/ctdb/tests/complex/18_ctdb_reloadips.sh
@@ -46,11 +46,11 @@ select_test_node_and_ips
 # The initial search is for a 10.B.0.0/16 network since some
 # configurations may use a whole class B for the private network.
 # Check that there are no public IP addresses (as reported by "ctdb ip
-# -n -all") or other IP addresses (as reported by "ip addr show") with
+# all") or other IP addresses (as reported by "ip addr show") with
 # the provided prefix.  Note that this is an IPv4-specific test.
 
 echo "Getting public IP information from CTDB..."
-try_command_on_node any "$CTDB ip -X -v -n all"
+try_command_on_node any "$CTDB ip -X -v all"
 ctdb_ip_info=$(echo "$out" | awk -F'|' 'NR > 1 { print $2, $3, $5 }')
 
 echo "Getting IP information from interfaces..."
@@ -70,7 +70,7 @@ for b in $(seq 0 255) ; do
 	fi
     done <<<"$ip_addr_info"
 
-    # Does the prefix match any public IP address "ctdb ip -n all"?
+    # Does the prefix match any public IP address "ctdb ip all"?
     while read ip pnn iface ; do
 	if [ "${ip#${prefix}.}" != "$ip" ] ; then
 	    prefix=""
diff --git a/ctdb/tests/cunit/comm_test_001.sh b/ctdb/tests/cunit/comm_test_001.sh
new file mode 100755
index 0000000..5d20db2
--- /dev/null
+++ b/ctdb/tests/cunit/comm_test_001.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+ok "100 2048 500 4096 1024 8192 200 16384 300 32768 400 65536 1048576 "
+
+unit_test comm_test
diff --git a/ctdb/tests/cunit/comm_test_002.sh b/ctdb/tests/cunit/comm_test_002.sh
new file mode 100755
index 0000000..76ee62d
--- /dev/null
+++ b/ctdb/tests/cunit/comm_test_002.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+socket="${TEST_VAR_DIR}/test_sock.$$"
+num_clients=10
+
+remove_socket ()
+{
+    rm -f "$socket"
+}
+
+test_cleanup remove_socket
+
+ok_null
+
+unit_test comm_server_test "$socket" $num_clients &
+pid=$!
+
+for i in $(seq 1 $num_clients) ; do
+    unit_test comm_client_test "$socket"
+done
+
+wait $pid
diff --git a/ctdb/tests/cunit/db_hash_test_001.sh b/ctdb/tests/cunit/db_hash_test_001.sh
new file mode 100755
index 0000000..76c38fe
--- /dev/null
+++ b/ctdb/tests/cunit/db_hash_test_001.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+ok_null
+
+unit_test db_hash_test
diff --git a/ctdb/tests/cunit/pkt_read_001.sh b/ctdb/tests/cunit/pkt_read_001.sh
new file mode 100755
index 0000000..c951f39
--- /dev/null
+++ b/ctdb/tests/cunit/pkt_read_001.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+ok_null
+
+unit_test pkt_read_test
diff --git a/ctdb/tests/cunit/pkt_write_001.sh b/ctdb/tests/cunit/pkt_write_001.sh
new file mode 100755
index 0000000..131af05
--- /dev/null
+++ b/ctdb/tests/cunit/pkt_write_001.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+ok_null
+
+unit_test pkt_write_test
diff --git a/ctdb/tests/cunit/protocol_test_001.sh b/ctdb/tests/cunit/protocol_test_001.sh
new file mode 100755
index 0000000..41afda5
--- /dev/null
+++ b/ctdb/tests/cunit/protocol_test_001.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+ok_null
+
+for i in $(seq 1 1000) ; do
+    unit_test protocol_types_test $i
+done
diff --git a/ctdb/tests/cunit/protocol_test_002.sh b/ctdb/tests/cunit/protocol_test_002.sh
new file mode 100755
index 0000000..a654f74
--- /dev/null
+++ b/ctdb/tests/cunit/protocol_test_002.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+last_control=145
+
+control_output=$(
+    for i in $(seq 0 $last_control) ; do
+	echo -n "$i.. "
+    done
+    echo
+)
+
+output=$(
+    echo "ctdb_req_header"
+    echo "ctdb_req_call"
+    echo "ctdb_reply_call"
+    echo "ctdb_reply_error"
+    echo "ctdb_req_dmaster"
+    echo "ctdb_reply_dmaster"
+    echo "ctdb_req_control_data"
+    echo "$control_output"
+    echo "ctdb_reply_control_data"
+    echo "$control_output"
+    echo "ctdb_req_control"
+    echo "$control_output"
+    echo "ctdb_reply_control"
+    echo "$control_output"
+    echo "ctdb_req_message"
+)
+
+ok "$output"
+
+for i in $(seq 1 100) ; do
+    unit_test protocol_client_test $i
+done
diff --git a/ctdb/tests/cunit/reqid_test_001.sh b/ctdb/tests/cunit/reqid_test_001.sh
new file mode 100755
index 0000000..06259ba
--- /dev/null
+++ b/ctdb/tests/cunit/reqid_test_001.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+output=$(
+for i in $(seq 0 1023) ; do
+    echo "WARNING: attempt to remove unset id $i in idtree"
+done
+)
+
+ok "$output"
+
+unit_test reqid_test
diff --git a/ctdb/tests/cunit/srvid_test_001.sh b/ctdb/tests/cunit/srvid_test_001.sh
new file mode 100755
index 0000000..ed09535
--- /dev/null
+++ b/ctdb/tests/cunit/srvid_test_001.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+ok_null
+
+unit_test srvid_test
diff --git a/ctdb/tests/eventscripts/00.ctdb.monitor.001.sh b/ctdb/tests/eventscripts/00.ctdb.monitor.001.sh
deleted file mode 100755
index 4290d13..0000000
--- a/ctdb/tests/eventscripts/00.ctdb.monitor.001.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "Memory check, bad situation, no checks enabled"
-
-setup_memcheck "bad"
-
-CTDB_MONITOR_FREE_MEMORY=""
-CTDB_MONITOR_FREE_MEMORY_WARN=""
-CTDB_CHECK_SWAP_IS_NOT_USED="no"
-
-ok_null
-
-simple_test
diff --git a/ctdb/tests/eventscripts/00.ctdb.monitor.002.sh b/ctdb/tests/eventscripts/00.ctdb.monitor.002.sh
deleted file mode 100755
index 6e94012..0000000
--- a/ctdb/tests/eventscripts/00.ctdb.monitor.002.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "Memory check, good situation, all enabled"
-
-setup_memcheck
-
-CTDB_MONITOR_FREE_MEMORY="500"
-CTDB_MONITOR_FREE_MEMORY_WARN="1000"
-CTDB_CHECK_SWAP_IS_NOT_USED="yes"
-
-ok_null
-
-simple_test
diff --git a/ctdb/tests/eventscripts/00.ctdb.monitor.003.sh b/ctdb/tests/eventscripts/00.ctdb.monitor.003.sh
deleted file mode 100755
index 9e63ab5..0000000
--- a/ctdb/tests/eventscripts/00.ctdb.monitor.003.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "Memory check, bad situation, only swap check"
-
-setup_memcheck "bad"
-
-CTDB_MONITOR_FREE_MEMORY=""
-CTDB_MONITOR_FREE_MEMORY_WARN=""
-CTDB_CHECK_SWAP_IS_NOT_USED="yes"
-
-ok <<EOF
-We are swapping:
-$FAKE_PROC_MEMINFO
-$(ps foobar)
-EOF
-
-simple_test
diff --git a/ctdb/tests/eventscripts/00.ctdb.monitor.004.sh b/ctdb/tests/eventscripts/00.ctdb.monitor.004.sh
deleted file mode 100755
index fdf2032..0000000
--- a/ctdb/tests/eventscripts/00.ctdb.monitor.004.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "Memory check, bad situation, only memory warning"
-
-setup_memcheck "bad"
-
-CTDB_MONITOR_FREE_MEMORY=""
-CTDB_MONITOR_FREE_MEMORY_WARN="500"
-CTDB_CHECK_SWAP_IS_NOT_USED="no"
-
-ok <<EOF
-WARNING: free memory is low - 468MB free <=  ${CTDB_MONITOR_FREE_MEMORY_WARN}MB (CTDB threshold)
-EOF
-
-simple_test
diff --git a/ctdb/tests/eventscripts/00.ctdb.monitor.005.sh b/ctdb/tests/eventscripts/00.ctdb.monitor.005.sh
deleted file mode 100755
index a46851a..0000000
--- a/ctdb/tests/eventscripts/00.ctdb.monitor.005.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "Memory check, bad situation, only memory critical"
-
-setup_memcheck "bad"
-
-CTDB_MONITOR_FREE_MEMORY="500"
-CTDB_MONITOR_FREE_MEMORY_WARN=""
-CTDB_CHECK_SWAP_IS_NOT_USED="no"
-
-ok <<EOF
-CRITICAL: OOM - 468MB free <= ${CTDB_MONITOR_FREE_MEMORY}MB (CTDB threshold)
-CRITICAL: Shutting down CTDB!!!
-$FAKE_PROC_MEMINFO
-$(ps foobar)
-CTDB says BYE!
-EOF
-
-simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.001.sh b/ctdb/tests/eventscripts/05.system.monitor.001.sh
new file mode 100755
index 0000000..d88d0e3
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.001.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Filesystem use check, error situation, no checks enabled"
+
+setup_memcheck
+
+CTDB_MONITOR_FILESYSTEM_USAGE=""
+setup_fscheck 100
+ok <<EOF
+WARNING: Filesystem ${CTDB_DBDIR} utilization 100% >= threshold 90%
+EOF
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.002.sh b/ctdb/tests/eventscripts/05.system.monitor.002.sh
new file mode 100755
index 0000000..3a73489
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.002.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Filesystem use check, good situation, 1 error check enabled"
+
+setup_memcheck
+
+CTDB_MONITOR_FILESYSTEM_USAGE="/var::80"
+setup_fscheck
+ok_null
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.003.sh b/ctdb/tests/eventscripts/05.system.monitor.003.sh
new file mode 100755
index 0000000..8576e72
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.003.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Filesystem use check, error situation, 1 error check enabled"
+
+setup_memcheck
+
+CTDB_MONITOR_FILESYSTEM_USAGE="/var::80"
+setup_fscheck 90
+required_result 1 <<EOF
+ERROR: Filesystem /var utilization 90% >= threshold 80%
+EOF
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.004.sh b/ctdb/tests/eventscripts/05.system.monitor.004.sh
new file mode 100755
index 0000000..d2f4f53
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.004.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Filesystem use check, warn situation, only error check enabled"
+
+setup_memcheck
+
+CTDB_MONITOR_FILESYSTEM_USAGE="/var::80"
+setup_fscheck 70
+ok_null
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.005.sh b/ctdb/tests/eventscripts/05.system.monitor.005.sh
new file mode 100755
index 0000000..9b45be3
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.005.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Filesystem use check, warn situation, both checks enabled"
+
+setup_memcheck
+
+CTDB_MONITOR_FILESYSTEM_USAGE="/var:80:90"
+setup_fscheck 85
+ok <<EOF
+WARNING: Filesystem /var utilization 85% >= threshold 80%
+EOF
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.006.sh b/ctdb/tests/eventscripts/05.system.monitor.006.sh
new file mode 100755
index 0000000..f4a661b
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.006.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Filesystem use check, error situation, both checks enabled"
+
+setup_memcheck
+
+CTDB_MONITOR_FILESYSTEM_USAGE="/var:80:90"
+setup_fscheck 95
+required_result 1 <<EOF
+ERROR: Filesystem /var utilization 95% >= threshold 90%
+EOF
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.007.sh b/ctdb/tests/eventscripts/05.system.monitor.007.sh
new file mode 100755
index 0000000..2ebcffb
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.007.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Filesystem use check, good situation, both checks enabled, multiple filesystems"
+
+setup_memcheck
+
+CTDB_MONITOR_FILESYSTEM_USAGE="/var:80:90 /:90:95"
+setup_fscheck
+ok_null
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.011.sh b/ctdb/tests/eventscripts/05.system.monitor.011.sh
new file mode 100755
index 0000000..57b16d4
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.011.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Memory check, bad situation, default checks enabled"
+
+setup_memcheck 100 100
+
+CTDB_MONITOR_MEMORY_USAGE=""
+CTDB_MONITOR_SWAP_USAGE=""
+
+ok <<EOF
+WARNING: System memory utilization 100% >= threshold 80%
+WARNING: System swap utilization 100% >= threshold 25%
+EOF
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.012.sh b/ctdb/tests/eventscripts/05.system.monitor.012.sh
new file mode 100755
index 0000000..aad789b
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.012.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Memory check, good situation, all memory checks enabled"
+
+setup_memcheck
+
+CTDB_MONITOR_MEMORY_USAGE="80:90"
+CTDB_MONITOR_SWAP_USAGE="1:50"
+
+ok_null
+
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.013.sh b/ctdb/tests/eventscripts/05.system.monitor.013.sh
new file mode 100755
index 0000000..4bf9f7b
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.013.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Memory check, bad situation, custom swap critical"
+
+setup_memcheck 100 90
+
+CTDB_MONITOR_MEMORY_USAGE=""
+CTDB_MONITOR_SWAP_USAGE=":50"
+
+required_result 1 <<EOF
+WARNING: System memory utilization 100% >= threshold 80%
+ERROR: System swap utilization 90% >= threshold 50%
+$FAKE_PROC_MEMINFO
+$(ps foobar)
+EOF
+
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.014.sh b/ctdb/tests/eventscripts/05.system.monitor.014.sh
new file mode 100755
index 0000000..48630c4
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.014.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Memory check, bad memory situation, custom memory warning"
+
+setup_memcheck 90 10
+
+CTDB_MONITOR_MEMORY_USAGE="85:"
+CTDB_MONITOR_SWAP_USAGE=""
+
+ok <<EOF
+WARNING: System memory utilization 90% >= threshold 85%
+EOF
+
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.015.sh b/ctdb/tests/eventscripts/05.system.monitor.015.sh
new file mode 100755
index 0000000..7d73bcf
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.015.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Memory check, bad situation, custom memory critical"
+
+setup_memcheck 90 0
+
+CTDB_MONITOR_MEMORY_USAGE=":85"
+CTDB_MONITOR_SWAP_USAGE=""
+
+required_result 1 <<EOF
+ERROR: System memory utilization 90% >= threshold 85%
+$FAKE_PROC_MEMINFO
+$(ps foobar)
+EOF
+
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.016.sh b/ctdb/tests/eventscripts/05.system.monitor.016.sh
new file mode 100755
index 0000000..44dddc6
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.016.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Memory check, bad situation, both memory checks, causes warning"
+
+setup_memcheck 87 0
+
+CTDB_MONITOR_MEMORY_USAGE="80:90"
+CTDB_MONITOR_SWAP_USAGE=""
+
+ok <<EOF
+WARNING: System memory utilization 87% >= threshold 80%
+EOF
+
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.017.sh b/ctdb/tests/eventscripts/05.system.monitor.017.sh
new file mode 100755
index 0000000..b976dba
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.017.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Memory check, bad situation, both custom memory checks, causes unhealthy"
+
+setup_memcheck 87 0
+
+CTDB_MONITOR_MEMORY_USAGE="70:80"
+CTDB_MONITOR_SWAP_USAGE=""
+
+required_result 1 <<EOF
+ERROR: System memory utilization 87% >= threshold 80%
+MemTotal:        3940712 kB
+MemFree:          225268 kB
+Buffers:          146120 kB
+Cached:          140904 kB
+SwapCached:        56016 kB
+Active:          2422104 kB
+Inactive:        1019928 kB
+Active(anon):    1917580 kB
+Inactive(anon):   523080 kB
+Active(file):     504524 kB
+Inactive(file):   496848 kB
+Unevictable:        4844 kB
+Mlocked:            4844 kB
+SwapTotal:       5857276 kB
+SwapFree:        5857276 kB
+...
+USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
+root         2  0.0  0.0      0     0 ?        S    Aug28   0:00 [kthreadd]
+root         3  0.0  0.0      0     0 ?        S    Aug28   0:43  \_ [ksoftirqd/0]
+...
+root         1  0.0  0.0   2976   624 ?        Ss   Aug28   0:07 init [2]
+root       495  0.0  0.0   3888  1640 ?        Ss   Aug28   0:00 udevd --daemon
+...
+[MORE FAKE ps OUTPUT]
+EOF
+
+simple_test
diff --git a/ctdb/tests/eventscripts/05.system.monitor.018.sh b/ctdb/tests/eventscripts/05.system.monitor.018.sh
new file mode 100755
index 0000000..6ed3ee9
--- /dev/null
+++ b/ctdb/tests/eventscripts/05.system.monitor.018.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Check throttling of warnings"
+
+CTDB_MONITOR_MEMORY_USAGE="70:80"
+CTDB_MONITOR_SWAP_USAGE=""
+
+# Below threshold, nothing logged
+setup_memcheck 67 0
+ok_null
+simple_test
+
+setup_memcheck 71 0
+ok "WARNING: System memory utilization 71% >= threshold 70%"
+simple_test
+
+# 2nd time at same level, nothing logged
+setup_memcheck 71 0
+ok_null
+simple_test
+
+setup_memcheck 73 0
+ok "WARNING: System memory utilization 73% >= threshold 70%"
+simple_test
+
+# 2nd time at same level, nothing logged
+setup_memcheck 73 0
+ok_null
+simple_test
+
+setup_memcheck 79 0
+ok "WARNING: System memory utilization 79% >= threshold 70%"
+simple_test
+
+setup_memcheck 80 0
+required_result 1 <<EOF
+ERROR: System memory utilization 80% >= threshold 80%
+MemTotal:        3940712 kB
+MemFree:          225268 kB
+Buffers:          146120 kB
+Cached:          416754 kB
+SwapCached:        56016 kB
+Active:          2422104 kB
+Inactive:        1019928 kB
+Active(anon):    1917580 kB
+Inactive(anon):   523080 kB
+Active(file):     504524 kB
+Inactive(file):   496848 kB
+Unevictable:        4844 kB
+Mlocked:            4844 kB
+SwapTotal:       5857276 kB
+SwapFree:        5857276 kB
+...
+USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
+root         2  0.0  0.0      0     0 ?        S    Aug28   0:00 [kthreadd]
+root         3  0.0  0.0      0     0 ?        S    Aug28   0:43  \_ [ksoftirqd/0]
+...
+root         1  0.0  0.0   2976   624 ?        Ss   Aug28   0:07 init [2]
+root       495  0.0  0.0   3888  1640 ?        Ss   Aug28   0:00 udevd --daemon
+...
+[MORE FAKE ps OUTPUT]
+EOF
+simple_test
+
+# Fall back into warning at same level as last warning... should log
+setup_memcheck 79 0
+ok "WARNING: System memory utilization 79% >= threshold 70%"
+simple_test
+
+# Below threshold, notice
+setup_memcheck 69 0
+ok <<EOF
+NOTICE: System memory utilization 69% < threshold 70%
+EOF
+simple_test
+
+# Further reduction, nothing logged
+setup_memcheck 68 0
+ok_null
+simple_test
+
+# Back up into warning at same level as last warning... should log
+setup_memcheck 79 0
+ok "WARNING: System memory utilization 79% >= threshold 70%"
+simple_test
+
+# Back up above critical threshold... unhealthy
+setup_memcheck 81 0
+required_result 1 <<EOF
+ERROR: System memory utilization 81% >= threshold 80%
+MemTotal:        3940712 kB
+MemFree:          225268 kB
+Buffers:          146120 kB
+Cached:          377347 kB
+SwapCached:        56016 kB
+Active:          2422104 kB
+Inactive:        1019928 kB
+Active(anon):    1917580 kB
+Inactive(anon):   523080 kB
+Active(file):     504524 kB
+Inactive(file):   496848 kB
+Unevictable:        4844 kB
+Mlocked:            4844 kB
+SwapTotal:       5857276 kB
+SwapFree:        5857276 kB
+...
+USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
+root         2  0.0  0.0      0     0 ?        S    Aug28   0:00 [kthreadd]
+root         3  0.0  0.0      0     0 ?        S    Aug28   0:43  \_ [ksoftirqd/0]
+...
+root         1  0.0  0.0   2976   624 ?        Ss   Aug28   0:07 init [2]
+root       495  0.0  0.0   3888  1640 ?        Ss   Aug28   0:00 udevd --daemon
+...
+[MORE FAKE ps OUTPUT]
+EOF
+simple_test
+
+# Straight back down to a good level... notice
+setup_memcheck 65 0
+ok "NOTICE: System memory utilization 65% < threshold 70%"
+simple_test
diff --git a/ctdb/tests/eventscripts/10.interface.monitor.015.sh b/ctdb/tests/eventscripts/10.interface.monitor.015.sh
index 1090cb9..01bd184 100755
--- a/ctdb/tests/eventscripts/10.interface.monitor.015.sh
+++ b/ctdb/tests/eventscripts/10.interface.monitor.015.sh
@@ -10,7 +10,7 @@ iface=$(ctdb_get_1_interface)
 ip link delete "$iface"
 
 required_result 1 <<EOF
-ERROR: Interface dev123 does not exist but it is used by public addresses.
+ERROR: Monitored interface dev123 does not exist
 EOF
 
 simple_test
diff --git a/ctdb/tests/eventscripts/10.interface.monitor.016.sh b/ctdb/tests/eventscripts/10.interface.monitor.016.sh
index 6fd698a..e511958 100755
--- a/ctdb/tests/eventscripts/10.interface.monitor.016.sh
+++ b/ctdb/tests/eventscripts/10.interface.monitor.016.sh
@@ -12,7 +12,7 @@ iface=$(ctdb_get_1_interface)
 ip link delete "$iface"
 
 ok <<EOF
-ERROR: Interface dev123 does not exist but it is used by public addresses.
+ERROR: Monitored interface dev123 does not exist
 EOF
 
 simple_test
diff --git a/ctdb/tests/eventscripts/11.natgw.005.sh b/ctdb/tests/eventscripts/11.natgw.005.sh
deleted file mode 100755
index 074fcda..0000000
--- a/ctdb/tests/eventscripts/11.natgw.005.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "Inconsistent test setup: slave-only but current node is master"
-
-setup_ctdb
-setup_ctdb_natgw <<EOF
-192.168.1.21 master
-192.168.1.22
-192.168.1.23
-192.168.1.24
-EOF
-
-CTDB_NATGW_SLAVE_ONLY="yes"
-
-required_result 1 <<EOF
-Inconsistent test configuration - master node is slave-only
-There is no NATGW master node
-EOF
-
-for i in "ipreallocated" ; do
-    simple_test_event "$i"
-done
diff --git a/ctdb/tests/eventscripts/11.natgw.041.sh b/ctdb/tests/eventscripts/11.natgw.041.sh
index 22dd392..e8126e1 100755
--- a/ctdb/tests/eventscripts/11.natgw.041.sh
+++ b/ctdb/tests/eventscripts/11.natgw.041.sh
@@ -2,18 +2,17 @@
 
 . "${TEST_SCRIPTS_DIR}/unit.sh"
 
-define_test "CTDB_NATGW_SLAVE_ONLY=yes, CTDB_NATGW_PUBLIC_IFACE unset"
+define_test "slave-only, CTDB_NATGW_PUBLIC_IFACE unset"
 
 setup_ctdb
 setup_ctdb_natgw <<EOF
-192.168.1.21
+192.168.1.21 slave-only
 192.168.1.22 master
 192.168.1.23
 192.168.1.24
 EOF
 
 CTDB_NATGW_PUBLIC_IFACE=""
-CTDB_NATGW_SLAVE_ONLY="yes"
 
 ok_null
 simple_test_event "ipreallocated"
diff --git a/ctdb/tests/eventscripts/11.natgw.042.sh b/ctdb/tests/eventscripts/11.natgw.042.sh
index 9019d4a..001698c 100755
--- a/ctdb/tests/eventscripts/11.natgw.042.sh
+++ b/ctdb/tests/eventscripts/11.natgw.042.sh
@@ -2,11 +2,11 @@
 
 . "${TEST_SCRIPTS_DIR}/unit.sh"
 
-define_test "CTDB_NATGW_SLAVE_ONLY=yes, CTDB_NATGW_PUBLIC_IP unset"
+define_test "slave-only, CTDB_NATGW_PUBLIC_IP unset"
 
 setup_ctdb
 setup_ctdb_natgw <<EOF
-192.168.1.21
+192.168.1.21 slave-only
 192.168.1.22 master
 192.168.1.23
 192.168.1.24
@@ -14,7 +14,6 @@ EOF
 
 CTDB_NATGW_PUBLIC_IFACE=""
 CTDB_NATGW_PUBLIC_IP=""
-CTDB_NATGW_SLAVE_ONLY="yes"
 
 ok_null
 simple_test_event "ipreallocated"
diff --git a/ctdb/tests/eventscripts/11.natgw.051.sh b/ctdb/tests/eventscripts/11.natgw.051.sh
new file mode 100755
index 0000000..8a385b6
--- /dev/null
+++ b/ctdb/tests/eventscripts/11.natgw.051.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Monitor CTDB_NATGW_PUBLIC_IFACE, slave, up"
+
+setup_ctdb
+setup_ctdb_natgw <<EOF
+192.168.1.21
+192.168.1.22 master
+192.168.1.23
+192.168.1.24
+EOF
+
+ok_null
+simple_test_event "monitor"
diff --git a/ctdb/tests/eventscripts/11.natgw.052.sh b/ctdb/tests/eventscripts/11.natgw.052.sh
new file mode 100755
index 0000000..091b6f6
--- /dev/null
+++ b/ctdb/tests/eventscripts/11.natgw.052.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Monitor CTDB_NATGW_PUBLIC_IFACE, slave, down"
+
+setup_ctdb
+setup_ctdb_natgw <<EOF
+192.168.1.21
+192.168.1.22 master
+192.168.1.23
+192.168.1.24
+EOF
+
+ethtool_interfaces_down "$CTDB_NATGW_PUBLIC_IFACE"
+
+required_result 1 <<EOF
+ERROR: No link on the public network interface ${CTDB_NATGW_PUBLIC_IFACE}
+EOF
+simple_test_event "monitor"
diff --git a/ctdb/tests/eventscripts/11.natgw.053.sh b/ctdb/tests/eventscripts/11.natgw.053.sh
new file mode 100755
index 0000000..7c51ec1
--- /dev/null
+++ b/ctdb/tests/eventscripts/11.natgw.053.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Monitor CTDB_NATGW_PUBLIC_IFACE, master, up"
+
+setup_ctdb
+setup_ctdb_natgw <<EOF
+192.168.1.21 master
+192.168.1.22
+192.168.1.23
+192.168.1.24
+EOF
+
+ok_null
+simple_test_event "monitor"
diff --git a/ctdb/tests/eventscripts/11.natgw.054.sh b/ctdb/tests/eventscripts/11.natgw.054.sh
new file mode 100755
index 0000000..08b4b77
--- /dev/null
+++ b/ctdb/tests/eventscripts/11.natgw.054.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Monitor CTDB_NATGW_PUBLIC_IFACE, master, down"
+
+setup_ctdb
+setup_ctdb_natgw <<EOF
+192.168.1.21 master
+192.168.1.22
+192.168.1.23
+192.168.1.24
+EOF
+
+ethtool_interfaces_down "$CTDB_NATGW_PUBLIC_IFACE"
+
+required_result 1 <<EOF
+ERROR: No link on the public network interface ${CTDB_NATGW_PUBLIC_IFACE}
+EOF
+simple_test_event "monitor"
diff --git a/ctdb/tests/eventscripts/13.per_ip_routing.023.sh b/ctdb/tests/eventscripts/13.per_ip_routing.023.sh
new file mode 100755
index 0000000..336e129
--- /dev/null
+++ b/ctdb/tests/eventscripts/13.per_ip_routing.023.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "1 IP configured, broken configuration, takeip"
+
+setup_ctdb
+setup_ctdb_policy_routing
+
+# Configuration for 1 IP
+create_policy_routing_config 1 default
+
+# takeip should add routes for the given address
+ctdb_get_1_public_address |
+while read dev ip bits ; do
+    # Now add configuration breakage by changing default route into a
+    # link local route with a gateway
+    net=$(ipv4_host_addr_to_net "$ip" "$bits")
+    sed -i -e "s at 0\.0\.0\.0/0@${net}@" "$CTDB_PER_IP_ROUTING_CONF"
+
+    ok <<EOF
+RTNETLINK answers: File exists
+add_routing_for_ip: failed to add route: ${net} via ${net%.*}.254 dev ${dev} table ctdb.${ip}
+EOF
+    simple_test_event "takeip" $dev $ip $bits
+done
diff --git a/ctdb/tests/eventscripts/50.samba.monitor.110.sh b/ctdb/tests/eventscripts/50.samba.monitor.110.sh
new file mode 100755
index 0000000..83a2271
--- /dev/null
+++ b/ctdb/tests/eventscripts/50.samba.monitor.110.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "testparm fails"
+
+setup_samba
+
+export FAKE_TESTPARM_FAIL="yes"
+required_result 1 <<EOF
+ERROR: smb.conf cache create failed - testparm failed with:
+Load smb config files from ${CTDB_SYS_ETCDIR}/samba/smb.conf
+rlimit_max: increasing rlimit_max (2048) to minimum Windows limit (16384)
+Processing section "[1_existing]"
+Processing section "[2_existing]"
+Processing section "[3_existing]"
+Loaded services file OK.
+WARNING: 'workgroup' and 'netbios name' must differ.
+EOF
+simple_test
diff --git a/ctdb/tests/eventscripts/50.samba.monitor.111.sh b/ctdb/tests/eventscripts/50.samba.monitor.111.sh
new file mode 100755
index 0000000..034e012
--- /dev/null
+++ b/ctdb/tests/eventscripts/50.samba.monitor.111.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "testparm fails on 2nd time through"
+
+setup_samba
+
+ok_null
+simple_test
+
+export FAKE_TESTPARM_FAIL="yes"
+required_result 1 <<EOF
+WARNING: smb.conf cache update failed - using old cache file
+Load smb config files from ${CTDB_SYS_ETCDIR}/samba/smb.conf
+rlimit_max: increasing rlimit_max (2048) to minimum Windows limit (16384)
+Processing section "[1_existing]"
+Processing section "[2_existing]"
+Processing section "[3_existing]"
+Loaded services file OK.
+WARNING: 'workgroup' and 'netbios name' must differ.
+
+Failed to set smb ports
+EOF
+simple_test
diff --git a/ctdb/tests/eventscripts/50.samba.monitor.112.sh b/ctdb/tests/eventscripts/50.samba.monitor.112.sh
new file mode 100755
index 0000000..a7a487f
--- /dev/null
+++ b/ctdb/tests/eventscripts/50.samba.monitor.112.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "testparm times out"
+
+setup_samba
+
+export FAKE_TIMEOUT="yes"
+required_result 1 <<EOF
+ERROR: smb.conf cache create failed - testparm command timed out
+EOF
+simple_test
diff --git a/ctdb/tests/eventscripts/50.samba.monitor.113.sh b/ctdb/tests/eventscripts/50.samba.monitor.113.sh
new file mode 100755
index 0000000..56bd86d
--- /dev/null
+++ b/ctdb/tests/eventscripts/50.samba.monitor.113.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "testparm times out on 2nd time through"
+
+setup_samba
+
+ok_null
+simple_test
+
+export FAKE_TIMEOUT="yes"
+ok <<EOF
+WARNING: smb.conf cache update timed out - using old cache file
+EOF
+simple_test
diff --git a/ctdb/tests/eventscripts/scripts/local.sh b/ctdb/tests/eventscripts/scripts/local.sh
index 46a5281..fcb7519 100644
--- a/ctdb/tests/eventscripts/scripts/local.sh
+++ b/ctdb/tests/eventscripts/scripts/local.sh
@@ -13,6 +13,7 @@ if [ -d "${TEST_SUBDIR}/stubs" ] ; then
 	/*) : ;;
 	*) EVENTSCRIPTS_PATH="${PWD}/${EVENTSCRIPTS_PATH}" ;;
     esac
+    export CTDB_HELPER_BINDIR="$EVENTSCRIPTS_PATH"
 fi
 
 export EVENTSCRIPTS_PATH
@@ -25,17 +26,17 @@ if [ -d "$EVENTSCRIPTS_TESTS_VAR_DIR" -a \
     rm -r "$EVENTSCRIPTS_TESTS_VAR_DIR"
 fi
 mkdir -p "$EVENTSCRIPTS_TESTS_VAR_DIR"
-export CTDB_VARDIR="$EVENTSCRIPTS_TESTS_VAR_DIR/ctdb"
+export CTDB_SCRIPT_VARDIR="$EVENTSCRIPTS_TESTS_VAR_DIR/script-state"
 
 export CTDB_LOGGING="file:${EVENTSCRIPTS_TESTS_VAR_DIR}/log.ctdb"
 touch "${CTDB_LOGGING#file:}" || \
     die "Unable to setup logging for \"$CTDB_LOGGING\""
 
-if [ -d "${TEST_SUBDIR}/etc" ] ; then    
+if [ -d "${TEST_SUBDIR}/etc" ] ; then
     cp -a "${TEST_SUBDIR}/etc" "$EVENTSCRIPTS_TESTS_VAR_DIR"
-    export CTDB_ETCDIR="${EVENTSCRIPTS_TESTS_VAR_DIR}/etc"
+    export CTDB_SYS_ETCDIR="${EVENTSCRIPTS_TESTS_VAR_DIR}/etc"
 else
-    die "Unable to setup \$CTDB_ETCDIR"
+    die "Unable to setup \$CTDB_SYS_ETCDIR"
 fi
 
 if [ -d "${TEST_SUBDIR}/etc-ctdb" ] ; then
@@ -112,7 +113,10 @@ setup_generic ()
 
 
     export CTDB_DBDIR="${EVENTSCRIPTS_TESTS_VAR_DIR}/db"
-    mkdir -p "${CTDB_DBDIR}/persistent"
+    export CTDB_DBDIR_PERSISTENT="${CTDB_DBDIR}/persistent"
+    export CTDB_DBDIR_STATE="${CTDB_DBDIR}/state"
+    mkdir -p "$CTDB_DBDIR_PERSISTENT"
+    mkdir -p "$CTDB_DBDIR_STATE"
 
     export FAKE_TDBTOOL_SUPPORTS_CHECK="yes"
     export FAKE_TDB_IS_OK
@@ -288,8 +292,8 @@ ctdb_set_pnn ()
     export FAKE_CTDB_PNN="$1"
     echo "Setting up PNN ${FAKE_CTDB_PNN}"
 
-    export CTDB_VARDIR="$EVENTSCRIPTS_TESTS_VAR_DIR/ctdb/${FAKE_CTDB_PNN}"
-    mkdir -p "$CTDB_VARDIR"
+    export CTDB_SCRIPT_VARDIR="$EVENTSCRIPTS_TESTS_VAR_DIR/script-state/${FAKE_CTDB_PNN}"
+    mkdir -p "$CTDB_SCRIPT_VARDIR"
 }
 
 setup_ctdb ()
@@ -327,27 +331,35 @@ setup_config ()
     cat >"$FAKE_CTDB_EXTRA_CONFIG"
 }
 
+validate_percentage ()
+{
+    case "$1" in
+	[0-9]|[0-9][0-9]|100) return 0 ;;
+	*) echo "WARNING: ${1} is an invalid percentage${2:+\" in }${2}${2:+\"}"
+	   return 1
+    esac
+}
+
 setup_memcheck ()
 {
+    _mem_usage="${1:-10}" # Default is 10%
+    _swap_usage="${2:-0}" # Default is  0%
+
     setup_ctdb
 
-    _swap_total="5857276"
+    _swap_total=5857276
+    _swap_free=$(( (100 - $_swap_usage) * $_swap_total / 100 ))
 
-    if [ "$1" = "bad" ] ; then
-	_swap_free="   4352"
-	_mem_cached=" 112"
-	_mem_free=" 468"
-    else
-	_swap_free="$_swap_total"
-	_mem_cached="1112"
-	_mem_free="1468"
-    fi
+    _mem_total=3940712
+    _mem_free=225268
+    _mem_buffers=146120
+    _mem_cached=$(( $_mem_total * (100 - $_mem_usage) / 100 - $_mem_free - $_mem_buffers ))
 
     export FAKE_PROC_MEMINFO="\
-MemTotal:        3940712 kB
-MemFree:          225268 kB
-Buffers:          146120 kB
-Cached:          1139348 kB
+MemTotal:        ${_mem_total} kB
+MemFree:          ${_mem_free} kB
+Buffers:          ${_mem_buffers} kB
+Cached:          ${_mem_cached} kB
 SwapCached:        56016 kB
 Active:          2422104 kB
 Inactive:        1019928 kB
@@ -361,15 +373,18 @@ SwapTotal:       ${_swap_total} kB
 SwapFree:        ${_swap_free} kB
 ..."
 
-    export FAKE_FREE_M="\
-             total       used       free     shared    buffers     cached
-Mem:          3848       3634        213          0        142       ${_mem_cached}
--/+ buffers/cache:       2379       ${_mem_free}
-Swap:         5719        246       5473"
+    export CTDB_MONITOR_MEMORY_USAGE
+    export CTDB_MONITOR_SWAP_USAGE
+}
+
+setup_fscheck ()
+{
+    export FAKE_FS_USE="${1:-10}"  # Default is 10% usage
 
-    export CTDB_MONITOR_FREE_MEMORY
-    export CTDB_MONITOR_FREE_MEMORY_WARN
-    export CTDB_CHECK_SWAP_IS_NOT_USED
+    # Causes some variables to be exported
+    setup_ctdb
+
+    export CTDB_MONITOR_FILESYSTEM_USAGE
 }
 
 ctdb_get_interfaces ()
@@ -470,7 +485,7 @@ create_policy_routing_config ()
     fi |
     while read _dev _ip _bits ; do
 	_net=$(ipv4_host_addr_to_net "$_ip" "$_bits")
-	_gw="${_net%.*}.1" # a dumb, calculated default
+	_gw="${_net%.*}.254" # a dumb, calculated default
 
 	echo "$_ip $_net"
 
@@ -499,7 +514,7 @@ check_routes ()
     fi | {
 	while read _dev _ip _bits ; do
 	    _net=$(ipv4_host_addr_to_net "$_ip" "$_bits")
-	    _gw="${_net%.*}.1" # a dumb, calculated default
+	    _gw="${_net%.*}.254" # a dumb, calculated default
 
 	    _policy_rules="${_policy_rules}
 ${CTDB_PER_IP_ROUTING_RULE_PREF}:	from $_ip lookup ctdb.$_ip "
@@ -587,35 +602,43 @@ EOF
 
 setup_ctdb_natgw ()
 {
-    debug "Setting up NAT gateway"
-
-    natgw_config_dir="${TEST_VAR_DIR}/natgw_config"
-    mkdir -p "$natgw_config_dir"
-
-    # These will accumulate, 1 per test... but will be cleaned up at
-    # the end.
-    export CTDB_NATGW_NODES=$(mktemp --tmpdir="$natgw_config_dir")
-
-    # Read from stdin
-    while read _ip _master _dev ; do
-	echo "$_ip"
-	if [ "$_master" = "master" ] ; then
-	    export FAKE_CTDB_NATGW_MASTER="$_ip"
-	fi
-    done >"$CTDB_NATGW_NODES"
-
-    # Assume all of the nodes are on a /24 network and have IPv4
-    # addresses:
-    read _ip <"$CTDB_NATGW_NODES"
-    export CTDB_NATGW_PRIVATE_NETWORK="${_ip%.*}.0/24"
-
-    # These are fixed.  Probably don't use the same network for the
-    # private node IPs.  To unset the default gateway just set it to
-    # "".  :-)
-    export CTDB_NATGW_PUBLIC_IP="10.1.1.121/24"
-    export CTDB_NATGW_PUBLIC_IFACE="eth1"
-    export CTDB_NATGW_DEFAULT_GATEWAY="10.1.1.254"
-    export CTDB_NATGW_SLAVE_ONLY=""
+	debug "Setting up NAT gateway"
+
+	natgw_config_dir="${TEST_VAR_DIR}/natgw_config"
+	mkdir -p "$natgw_config_dir"
+
+	# These will accumulate, 1 per test... but will be cleaned up at
+	# the end.
+	export CTDB_NATGW_NODES=$(mktemp --tmpdir="$natgw_config_dir")
+
+	# Read from stdin
+	while read _ip _opts ; do
+		case "$_opts" in
+		master)
+			export FAKE_CTDB_NATGW_MASTER="$_ip"
+			echo "$_ip"
+			;;
+		slave-only)
+			printf "%s\tslave-only\n" "$_ip"
+			;;
+		*)
+			echo "$_ip"
+			;;
+		esac
+	done >"$CTDB_NATGW_NODES"
+
+	# Assume all of the nodes are on a /24 network and have IPv4
+	# addresses:
+	read _ip <"$CTDB_NATGW_NODES"
+	export CTDB_NATGW_PRIVATE_NETWORK="${_ip%.*}.0/24"
+
+	# These are fixed.  Probably don't use the same network for the
+	# private node IPs.  To unset the default gateway just set it to
+	# "".  :-)
+	export CTDB_NATGW_PUBLIC_IP="10.1.1.121/24"
+	export CTDB_NATGW_PUBLIC_IFACE="eth1"
+	export CTDB_NATGW_DEFAULT_GATEWAY="10.1.1.254"
+	export CTDB_NATGW_SLAVE_ONLY=""
 }
 
 ok_natgw_master_ip_addr_show ()
@@ -791,6 +814,9 @@ setup_nfs ()
 
     export RPCNFSDCOUNT
 
+    # This doesn't even need to exist
+    export CTDB_NFS_EXPORTS_FILE="$EVENTSCRIPTS_TESTS_VAR_DIR/etc-exports"
+
     # Reset the failcounts for nfs services.
     eventscript_call eval rm -f '$ctdb_fail_dir/nfs_*'
 
@@ -867,7 +893,7 @@ rpc_services_up ()
 
 nfs_load_config ()
 {
-    _etc="$CTDB_ETCDIR" # shortcut for readability
+    _etc="$CTDB_SYS_ETCDIR" # shortcut for readability
     for _c in "$_etc/sysconfig/nfs" "$_etc/default/nfs" "$_etc/ctdb/sysconfig/nfs" ; do
 	if [ -r "$_c" ] ; then
 	    . "$_c"
@@ -1152,7 +1178,7 @@ simple_test ()
 
 ##################################################
 CTDB_BASE="$CTDB_BASE"
-CTDB_ETCDIR="$CTDB_ETCDIR"
+CTDB_SYS_ETCDIR="$CTDB_SYS_ETCDIR"
 ctdb client is "$(which ctdb)"
 ip command is "$(which ip)"
 EOF
diff --git a/ctdb/tests/eventscripts/stubs/ctdb b/ctdb/tests/eventscripts/stubs/ctdb
index aa3ac73..825cd04 100755
--- a/ctdb/tests/eventscripts/stubs/ctdb
+++ b/ctdb/tests/eventscripts/stubs/ctdb
@@ -135,7 +135,7 @@ ip_reallocate ()
 	done
 	CTDB_TEST_LOGLEVEL=2 \
 	    "ctdb_takeover_tests" \
-	    "ctdb_takeover_run_core" "$_flags" <"$FAKE_CTDB_IP_LAYOUT" |
+	    "ipalloc" "$_flags" <"$FAKE_CTDB_IP_LAYOUT" |
 	    sort >"$_t"
 	mv "$_t" "$FAKE_CTDB_IP_LAYOUT"
     ) <"$FAKE_CTDB_IP_LAYOUT"
@@ -243,69 +243,17 @@ ctdb_shutdown ()
 
 ######################################################################
 
-FAKE_CTDB_NATGW_STATE="${FAKE_CTDB_STATE}/natgw_state"
-
-ctdb_setnatgwstate ()
+# This is only used by the NAT gateway code at the moment, so use a
+# hack.  Assume that $CTDB_NATGW_NODES contains all nodes in the
+# cluster (which is what current tests assume).  Use the PNN to find
+# the address from this file.  The NAT gateway code only used the
+# address, so just mark the node healthy.
+ctdb_nodestatus ()
 {
-    echo "$2" >"$FAKE_CTDB_NATGW_STATE"
-}
-
-ctdb_natgwlist ()
-{
-    [ -r "$CTDB_NATGW_NODES" ] || \
-	die "error: missing CTDB_NATGW_NODES=${CTDB_NATGW_NODES}"
-
-    # Determine if the current node has the (fake) NAT gateway
-    # capability.  This is only used to make sure tests are sane and
-    # don't try to use inconsistent setup.
-    if [ -r "$FAKE_CTDB_NATGW_STATE" ] ; then
-	read _state <"$FAKE_CTDB_NATGW_STATE"
-    else
-	_state="off"
-    fi
-
-    # Determine the master node
-    _master="-1 0.0.0.0"
-    _pnn=0
-    while read _ip ; do
-	if [ "$FAKE_CTDB_NATGW_MASTER" = "$_ip" ] ; then
-	    _master="${_pnn} ${_ip}"
-	    if [ "$_pnn" =  "$FAKE_CTDB_PNN" -a "$_state" = "off" ] ; then
-		die "Inconsistent test configuration - master node is slave-only"
-	    fi
-	    break
-	fi
-	_pnn=$(($_pnn + 1))
-    done <"$CTDB_NATGW_NODES"
-    echo "$_master"
-
-    # Now print the node information - it is clearer to do this in a
-    # second pass.  Any nodes before the master that have state not
-    # "off" are tagged as unhealthy, just so the output makes some
-    # sense.
-    _pnn=0
-    _found_master=false
-    while read _ip ; do
-	if [ "$FAKE_CTDB_NATGW_MASTER" = "$_ip" ] ; then
-	    _found_master=true
-	fi
-	if $_found_master ; then
-	    _outstate="HEALTHY"
-	else
-	    if [ $FAKE_CTDB_PNN -eq $_pnn -a "$_state" = "off" ] ; then
-		_outstate="HEALTHY"
-	    else
-		_outstate="UNHEALTHY"
-	    fi
-	fi
-	if [ $FAKE_CTDB_PNN -eq $_pnn ] ; then
-	    _outstate="${_outstate} (THIS NODE)"
-	fi
-	printf "pnn:%d %-16s ${_outstate}\n" $_pnn "$_ip"
-
-	_pnn=$(($_pnn + 1))
-    done <"$CTDB_NATGW_NODES"
-
+    echo '|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|'
+    _line=$(( $FAKE_CTDB_PNN + 1 ))
+    _ip=$(sed -e "${_line}p" "$CTDB_NATGW_NODES")
+    echo "|${FAKE_CTDB_PNN}|${_ip}|0|0|0|0|0|0|0|Y|"
 }
 
 ######################################################################
@@ -513,8 +461,7 @@ case "$1" in
     disable)       ctdb_disable "$@";;
     moveip)        ctdb_moveip "$@";;
     shutdown)      ctdb_shutdown "$@";;
-    setnatgwstate) ctdb_setnatgwstate "$@" ;;
-    natgwlist)     ctdb_natgwlist "$@" ;;
     setvar)	   ctdb_setvar "$@" ;;
+    nodestatus)	   ctdb_nodestatus "$@" ;;
     *) not_implemented "$1" ;;
 esac
diff --git a/ctdb/tests/eventscripts/stubs/ctdb_natgw b/ctdb/tests/eventscripts/stubs/ctdb_natgw
new file mode 100755
index 0000000..96ba7ef
--- /dev/null
+++ b/ctdb/tests/eventscripts/stubs/ctdb_natgw
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+prog="ctdb_natgw"
+
+not_implemented_exit_code=1
+
+not_implemented ()
+{
+    echo "${prog}: command \"$1\" not implemented in stub" >&2
+    exit $not_implemented_exit_code
+}
+
+ctdb_natgw_master ()
+{
+    [ -r "$CTDB_NATGW_NODES" ] || \
+	die "error: missing CTDB_NATGW_NODES=${CTDB_NATGW_NODES}"
+
+    # Determine the master node
+    _master="-1 0.0.0.0"
+    _pnn=0
+    while read _ip ; do
+	if [ "$FAKE_CTDB_NATGW_MASTER" = "$_ip" ] ; then
+	    _master="${_pnn} ${_ip}"
+	    break
+	fi
+	_pnn=$(($_pnn + 1))
+    done <"$CTDB_NATGW_NODES"
+    echo "$_master"
+}
+
+case "$1" in
+    master) ctdb_natgw_master "$@" ;;
+    *) not_implemented "$1" ;;
+esac
diff --git a/ctdb/tests/eventscripts/stubs/df b/ctdb/tests/eventscripts/stubs/df
new file mode 100755
index 0000000..eb91a4c
--- /dev/null
+++ b/ctdb/tests/eventscripts/stubs/df
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+usage ()
+{
+    echo "usage: df -kP <mount-point>"
+    exit 1
+}
+
+if [ "$1" != "-kP" ] ; then
+    usage
+fi
+
+shift
+if [ -z "$1" ] ; then
+    usage
+fi
+
+fs="$1"
+
+# Anything starting with CTDB_DBDIR gets canonicalised to CTDB_DBDIR.
+# This helps with the setting of defaults for the filesystem checks.
+if [ "${fs#${CTDB_DBDIR}}" != "$fs" ] ; then
+    fs="$CTDB_DBDIR"
+fi
+
+# A default, for tests that don't initialise this...
+if [ -z "$FAKE_FS_USE" ] ; then
+    FAKE_FS_USE=10
+fi
+
+echo "Filesystem             1024-blocks      Used Available Capacity Mounted on"
+
+blocks="1000000"
+used=$(($blocks * $FAKE_FS_USE / 100))
+available=$(($blocks - $used))
+
+printf "%-36s %10d %10d %10d %10d%% %s\n" \
+       "/dev/sda1" "$blocks" "$used" "$available" "$FAKE_FS_USE" "$fs"
diff --git a/ctdb/tests/eventscripts/stubs/free b/ctdb/tests/eventscripts/stubs/free
deleted file mode 100755
index 6453509..0000000
--- a/ctdb/tests/eventscripts/stubs/free
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-
-if [ "$1" = "-m" ] ; then
-    echo "$FAKE_FREE_M"
-    exit 0
-else
-    echo "free: not implemented - $*"
-    exit 1
-fi
diff --git a/ctdb/tests/eventscripts/stubs/ip b/ctdb/tests/eventscripts/stubs/ip
index 59219d2..325c892 100755
--- a/ctdb/tests/eventscripts/stubs/ip
+++ b/ctdb/tests/eventscripts/stubs/ip
@@ -573,6 +573,16 @@ ip_route_add ()
     mkdir -p "$FAKE_IP_STATE/routes"
     touch "$_f"
 
+    # Check for duplicate
+    _prefix_regexp=$(echo "^${_prefix}" | sed -e 's@\.@\\. at g')
+    if [ -n "$_metric" ] ; then
+	_prefix_regexp="${_prefix_regexp} .*metric ${_metric} "
+    fi
+    if grep -q "$_prefix_regexp" "$_f" ; then
+	echo "RTNETLINK answers: File exists" >&2
+	exit 1
+    fi
+
     (
 	flock 0
 
diff --git a/ctdb/tests/eventscripts/stubs/ps b/ctdb/tests/eventscripts/stubs/ps
index 5abeaf9..f8e0ae0 100755
--- a/ctdb/tests/eventscripts/stubs/ps
+++ b/ctdb/tests/eventscripts/stubs/ps
@@ -5,7 +5,7 @@ USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
 root         2  0.0  0.0      0     0 ?        S    Aug28   0:00 [kthreadd]
 root         3  0.0  0.0      0     0 ?        S    Aug28   0:43  \_ [ksoftirqd/0]
 ...
-root         1  0.0  0.0   2976   624 ?        Ss   Aug28   0:07 init [2]  
+root         1  0.0  0.0   2976   624 ?        Ss   Aug28   0:07 init [2]
 root       495  0.0  0.0   3888  1640 ?        Ss   Aug28   0:00 udevd --daemon
 ...
 [MORE FAKE ps OUTPUT]
diff --git a/ctdb/tests/eventscripts/stubs/testparm b/ctdb/tests/eventscripts/stubs/testparm
index aac5b18..0473bbf 100755
--- a/ctdb/tests/eventscripts/stubs/testparm
+++ b/ctdb/tests/eventscripts/stubs/testparm
@@ -6,8 +6,42 @@ not_implemented ()
     exit 2
 }
 
+error ()
+{
+    cat >&2 <<EOF
+Load smb config files from ${CTDB_SYS_ETCDIR}/samba/smb.conf
+rlimit_max: increasing rlimit_max (2048) to minimum Windows limit (16384)
+EOF
+
+    for i in $FAKE_SHARES ; do
+	bi=$(basename "$i")
+	echo "Processing section \"[${bi}]\""
+    done >&2
+
+    cat >&2 <<EOF
+Loaded services file OK.
+WARNING: 'workgroup' and 'netbios name' must differ.
+
+EOF
+
+    exit 1
+}
+
+timeout ()
+{
+    echo "$0: INTERNAL ERROR - timeout stub should avoid this" >&2
+}
+
+if [ -n "$FAKE_TESTPARM_FAIL" ] ; then
+    error
+fi
+
+if [ -n "$FAKE_TIMEOUT" ] ; then
+    timeout
+fi
+
 # Ensure that testparm always uses our canned configuration instead of
-# the global one, unless some other file is specified. 
+# the global one, unless some other file is specified.
 
 file=""
 parameter=""
@@ -34,7 +68,7 @@ if [ -n "$file" ] ; then
     cat "$file"
 else
     # We force our own smb.conf and add the shares.
-    cat "${CTDB_ETCDIR}/samba/smb.conf"
+    cat "${CTDB_SYS_ETCDIR}/samba/smb.conf"
 
     for i in $FAKE_SHARES ; do
 	bi=$(basename "$i")
diff --git a/ctdb/tests/eventscripts/stubs/timeout b/ctdb/tests/eventscripts/stubs/timeout
new file mode 100755
index 0000000..1ddce53
--- /dev/null
+++ b/ctdb/tests/eventscripts/stubs/timeout
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ -n "$FAKE_TIMEOUT" ] ; then
+    exit 124
+else
+    shift 1
+    exec "$@"
+fi
diff --git a/ctdb/tests/onnode/functions b/ctdb/tests/onnode/functions
new file mode 120000
index 0000000..ff10411
--- /dev/null
+++ b/ctdb/tests/onnode/functions
@@ -0,0 +1 @@
+../../config/functions
\ No newline at end of file
diff --git a/ctdb/tests/run_tests.sh b/ctdb/tests/run_tests.sh
index d705ac1..2af2daf 100755
--- a/ctdb/tests/run_tests.sh
+++ b/ctdb/tests/run_tests.sh
@@ -255,7 +255,7 @@ export TEST_SCRIPTS_DIR="${test_dir}/scripts"
 # If no tests specified then run some defaults
 if [ -z "$1" ] ; then
     if [ -n "$TEST_LOCAL_DAEMONS" ] ; then
-	set -- onnode takeover tool eventscripts simple
+	set -- onnode takeover tool eventscripts cunit simple
     else
 	set -- simple complex
     fi
diff --git a/ctdb/tests/scripts/integration.bash b/ctdb/tests/scripts/integration.bash
index 139a9a2..e3fb3d4 100644
--- a/ctdb/tests/scripts/integration.bash
+++ b/ctdb/tests/scripts/integration.bash
@@ -169,7 +169,7 @@ all_ips_on_node()
 _select_test_node_and_ips ()
 {
     try_command_on_node any \
-	"$CTDB ip -X -n all | awk -F'|' 'NR > 1 { print \$2, \$3 }'"
+	"$CTDB ip -X all | awk -F'|' 'NR > 1 { print \$2, \$3 }'"
 
     test_node=""  # this matches no PNN
     test_node_ips=""
@@ -229,6 +229,34 @@ get_test_ip_mask_and_iface ()
     echo "$test_ip/$mask is on $iface"
 }
 
+ctdb_get_all_pnns ()
+{
+    try_command_on_node -q all "$CTDB pnn | sed -e 's at PNN:@@'"
+    all_pnns="$out"
+}
+
+# The subtlety is that "ctdb delip" will fail if the IP address isn't
+# configured on a node...
+delete_ip_from_all_nodes ()
+{
+    _ip="$1"
+
+    ctdb_get_all_pnns
+
+    _nodes=""
+
+    for _pnn in $all_pnns ; do
+	all_ips_on_node $_pnn
+	while read _i _n ; do
+	    if [ "$_ip" = "$_i" ] ; then
+		_nodes="${_nodes}${_nodes:+,}${_pnn}"
+	    fi
+	done <<<"$out" # bashism
+    done
+
+    try_command_on_node -pq "$_nodes" "$CTDB delip $_ip"
+}
+
 #######################################
 
 # Wait until either timeout expires or command succeeds.  The command
diff --git a/ctdb/tests/simple/06_ctdb_getpid.sh b/ctdb/tests/simple/06_ctdb_getpid.sh
index 7152ad4..3013734 100755
--- a/ctdb/tests/simple/06_ctdb_getpid.sh
+++ b/ctdb/tests/simple/06_ctdb_getpid.sh
@@ -15,8 +15,6 @@ Steps:
 2. Run 'ctdb getpid -n <number>' on the nodes to check the PID of the
    ctdbd process.
 3. Verify that the output is valid.
-4. Verify that with the '-n all' option the command shows the PIDs on
-   all the nodes
 
 Expected results:
 
@@ -32,8 +30,6 @@ set -e
 
 cluster_is_healthy
 
-# This is an attempt at being independent of the number of nodes
-# reported by "ctdb getpid -n all".
 try_command_on_node 0 "$CTDB listnodes | wc -l"
 num_nodes="$out"
 echo "There are $num_nodes nodes..."
@@ -43,9 +39,6 @@ echo "There are $num_nodes nodes..."
 try_command_on_node -v 0 "onnode -q all $CTDB getpid"
 pids_onnode="$out"
 
-try_command_on_node -v 0 "$CTDB getpid -n all"
-pids_getpid_all="$out"
-
 cmd=""
 n=0
 while [ $n -lt $num_nodes ] ; do
@@ -55,8 +48,7 @@ done
 try_command_on_node -v 0 "( $cmd )"
 pids_getpid_n="$out"
 
-if [ "$pids_onnode" = "$pids_getpid_all" -a \
-    "$pids_getpid_all" = "$pids_getpid_n" ] ; then
+if [ "$pids_onnode" = "$pids_getpid_n" ] ; then
     echo "They're the same... cool!"
 else
     echo "Error: they differ."
diff --git a/ctdb/tests/simple/11_ctdb_ip.sh b/ctdb/tests/simple/11_ctdb_ip.sh
index 0e02b5e..8bca2c6 100755
--- a/ctdb/tests/simple/11_ctdb_ip.sh
+++ b/ctdb/tests/simple/11_ctdb_ip.sh
@@ -32,7 +32,7 @@ set -e
 cluster_is_healthy
 
 echo "Getting list of public IPs..."
-try_command_on_node -v 1 "$CTDB ip -n all | tail -n +2"
+try_command_on_node -v 1 "$CTDB ip all | tail -n +2"
 ips=$(echo "$out" | sed \
 	-e 's@ node\[@ @' \
 	-e 's@\].*$@@')
@@ -55,7 +55,7 @@ fi
 
 [ "$testfailures" != 1 ] && echo "Looks good!"
 
-cmd="$CTDB -X ip -n all | tail -n +2"
+cmd="$CTDB -X ip all | tail -n +2"
 echo "Checking that \"$cmd\" produces expected output..."
 
 try_command_on_node 1 "$cmd"
diff --git a/ctdb/tests/simple/12_ctdb_getdebug.sh b/ctdb/tests/simple/12_ctdb_getdebug.sh
index cdd9e34..39028ac 100755
--- a/ctdb/tests/simple/12_ctdb_getdebug.sh
+++ b/ctdb/tests/simple/12_ctdb_getdebug.sh
@@ -13,8 +13,6 @@ Steps:
 
 1. Verify that the status on all of the ctdb nodes is 'OK'.
 2. Get the current debug level on a node, using 'ctdb getdebug -n <node>'.
-3. Verify that pipe-separated output is generated with the -X option.
-4. Verify that the '-n all' option shows the debug level on all nodes.
 
 Expected results:
 
@@ -41,9 +39,6 @@ sanity_check_output \
     '^Node [[:digit:]]+ is at debug level [[:alpha:]]+ \([[:digit:]]+\)$' \
     "$out"
 
-try_command_on_node -v 1 "$CTDB getdebug -n all"
-getdebug_all="$out"
-
 cmd=""
 n=0
 while [ $n -lt $num_nodes ] ; do
@@ -53,8 +48,7 @@ done
 try_command_on_node -v 1 "$cmd"
 getdebug_n="$out"
 
-if [ "$getdebug_onnode" = "$getdebug_all" -a \
-    "$getdebug_all" = "$getdebug_n" ] ; then
+if [ "$getdebug_onnode" = "$getdebug_n" ] ; then
     echo "They're the same... cool!"
 else
     echo "Error: they differ."
@@ -69,7 +63,7 @@ while read line ; do
     seps="${seps}${seps:+${nl}}|Name|Level|${nl}${t}"
 done <<<"$getdebug_onnode"
 
-cmd="$CTDB -X getdebug -n all"
+cmd="onnode -q all $CTDB -X getdebug"
 echo "Checking that \"$cmd\" produces expected output..."
 
 try_command_on_node 1 "$cmd"
diff --git a/ctdb/tests/simple/13_ctdb_setdebug.sh b/ctdb/tests/simple/13_ctdb_setdebug.sh
index ef8b3ee..ad6f453 100755
--- a/ctdb/tests/simple/13_ctdb_setdebug.sh
+++ b/ctdb/tests/simple/13_ctdb_setdebug.sh
@@ -37,6 +37,7 @@ set_and_check_debug ()
 {
     local node="$1"
     local level="$2"
+    local levelstr="${3:-$level}"
 
     echo "Setting debug level on node ${node} to ${level}."
     try_command_on_node $node "$CTDB setdebug ${level}"
@@ -44,8 +45,8 @@ set_and_check_debug ()
     local check_debug
     get_debug $node
 
-    if [ "$level" != "$check_debug" ] ; then
-	echo "BAD: Debug level should have changed to \"$level\" but it is \"$check_debug\"."
+    if [ "$levelstr" != "$check_debug" ] ; then
+	echo "BAD: Debug level should have changed to \"$levelstr\" but it is \"$check_debug\"."
 	testfailures=1
     fi
 }
@@ -53,7 +54,7 @@ set_and_check_debug ()
 get_debug $test_node
 initial_debug="$check_debug"
 
-levels="ERR WARNING NOTICE INFO DEBUG"
+levels="ERROR WARNING NOTICE INFO DEBUG"
 
 for new_debug in $levels ; do
     [ "$initial_debug" != "$new_debug" ] || continue
@@ -62,6 +63,15 @@ for new_debug in $levels ; do
     set_and_check_debug $test_node "$new_debug"
 done
 
+i=0
+for new_debug in $levels ; do
+    [ "$initial_debug" != "$i" ] || continue
+
+    echo
+    set_and_check_debug $test_node "$i" "$new_debug"
+    i=$[ $i + 1 ]
+done
+
 if [ "$testfailures" != 1 ] ; then
     echo
     echo "Returning the debug level to its initial value..."
diff --git a/ctdb/tests/simple/14_ctdb_statistics.sh b/ctdb/tests/simple/14_ctdb_statistics.sh
index 9cc5ac1..3dd55e0 100755
--- a/ctdb/tests/simple/14_ctdb_statistics.sh
+++ b/ctdb/tests/simple/14_ctdb_statistics.sh
@@ -1,3 +1,4 @@
+
 #!/bin/bash
 
 test_info()
@@ -16,8 +17,6 @@ Steps:
 1. Verify that the status on all of the ctdb nodes is 'OK'.
 2. Run 'ctdb statistics' on a node, and verify that the output is
    valid.
-3. Repeat the command with the '-n all' option and verify that the
-   output is valid.
 
 Expected results:
 
@@ -38,7 +37,3 @@ pattern='^(CTDB version 1|Current time of statistics[[:space:]]*:.*|Statistics c
 try_command_on_node -v 1 "$CTDB statistics"
 
 sanity_check_output 40 "$pattern" "$out"
-
-try_command_on_node -v 1 "$CTDB statistics -n all"
-
-sanity_check_output 40 "$pattern" "$out"
diff --git a/ctdb/tests/simple/16_ctdb_config_add_ip.sh b/ctdb/tests/simple/16_ctdb_config_add_ip.sh
index b5d76ea..55527ad 100755
--- a/ctdb/tests/simple/16_ctdb_config_add_ip.sh
+++ b/ctdb/tests/simple/16_ctdb_config_add_ip.sh
@@ -25,7 +25,7 @@ select_test_node_and_ips
 get_test_ip_mask_and_iface
 
 echo "Deleting IP $test_ip from all nodes"
-try_command_on_node $test_node $CTDB delip -n all $test_ip
+delete_ip_from_all_nodes $test_ip
 wait_until_ips_are_on_node '!' $test_node $test_ip
 
 # Debugging...
diff --git a/ctdb/tests/simple/20_delip_iface_gc.sh b/ctdb/tests/simple/20_delip_iface_gc.sh
index 83de495..23d1d6b 100755
--- a/ctdb/tests/simple/20_delip_iface_gc.sh
+++ b/ctdb/tests/simple/20_delip_iface_gc.sh
@@ -19,7 +19,7 @@ cluster_is_healthy
 ctdb_restart_when_done
 
 echo "Getting public IPs information..."
-try_command_on_node -v any "$CTDB ip -v -n all -X | tail -n +2"
+try_command_on_node -v any "$CTDB ip -v all -X | tail -n +2"
 ip_info="$out"
 
 # Select the first node and find out its interfaces
diff --git a/ctdb/tests/simple/23_ctdb_moveip.sh b/ctdb/tests/simple/23_ctdb_moveip.sh
index f6e9027..f92d7f7 100755
--- a/ctdb/tests/simple/23_ctdb_moveip.sh
+++ b/ctdb/tests/simple/23_ctdb_moveip.sh
@@ -50,10 +50,10 @@ fi
 echo "Target node is ${to_node}"
 
 echo "Turning off DeterministicIPs..."
-try_command_on_node 0 $CTDB setvar DeterministicIPs 0 -n all
+try_command_on_node -q all $CTDB setvar DeterministicIPs 0
 
 echo "Turning on NoIPFailback..."
-try_command_on_node 0 $CTDB setvar NoIPFailback 1 -n all
+try_command_on_node -q all $CTDB setvar NoIPFailback 1
 
 echo "Attempting to move ${test_ip} from node ${test_node} to node ${to_node}"
 try_command_on_node $test_node $CTDB moveip $test_ip $to_node
diff --git a/ctdb/tests/simple/25_dumpmemory.sh b/ctdb/tests/simple/25_dumpmemory.sh
index 4082da1..4d6cc83 100755
--- a/ctdb/tests/simple/25_dumpmemory.sh
+++ b/ctdb/tests/simple/25_dumpmemory.sh
@@ -13,8 +13,6 @@ Steps:
 
 1. Verify that the status on all of the ctdb nodes is 'OK'.
 2. Run 'ctdb dumpmemory' and verify that it shows expected output
-3. Verify that the command takes the '-n all' option and that it
-   causes output for all nodes to be displayed.
 
 Expected results:
 
@@ -35,18 +33,3 @@ try_command_on_node -v 0 "$CTDB dumpmemory"
 pat='^([[:space:]].+[[:space:]]+contains[[:space:]]+[[:digit:]]+ bytes in[[:space:]]+[[:digit:]]+ blocks \(ref [[:digit:]]+\)[[:space:]]+0x[[:xdigit:]]+|[[:space:]]+reference to: .+|full talloc report on .+ \(total[[:space:]]+[[:digit:]]+ bytes in [[:digit:]]+ blocks\))$'
 
 sanity_check_output 10 "$pat" "$out"
-
-echo "Checking output using '-n all'..."
-
-try_command_on_node 0 "$CTDB listnodes"
-num_nodes=$(echo "$out" | wc -l)
-
-try_command_on_node 0 "$CTDB dumpmemory" -n all
-sanity_check_output 10 "$pat" "$out"
-
-if [ $(fgrep -c 'full talloc report on' <<<"$out") -eq  $num_nodes ] ; then
-    echo "OK: there looks to be output for all $num_nodes nodes"
-else
-    echo "BAD: there not look to be output for all $num_nodes nodes"
-    exit 1
-fi    
diff --git a/ctdb/tests/simple/35_set_reclock.sh b/ctdb/tests/simple/35_set_reclock.sh
new file mode 100755
index 0000000..07e3185
--- /dev/null
+++ b/ctdb/tests/simple/35_set_reclock.sh
@@ -0,0 +1,124 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that "ctdb setreclock" sets the recovery lock correctly.
+
+This test only does something when there is a recovery lock
+configured.
+EOF
+}
+
+. "${TEST_SCRIPTS_DIR}/integration.bash"
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+get_generation ()
+{
+    local out
+    try_command_on_node any $CTDB status
+    generation=$(sed -n -e 's@^Generation:@@p' <<<"$out")
+}
+
+generation_has_changed ()
+{
+    local old_generation="$generation"
+    get_generation
+    [ "$old_generation" != "$generation" ]
+}
+
+wait_until_generation_has_changed ()
+{
+    echo
+    echo "Wait until generation has changed..."
+    wait_until 60 generation_has_changed
+}
+
+wait_until_recovered ()
+{
+    wait_until_generation_has_changed
+    wait_until_node_has_status all recovered
+}
+
+echo "Check that recovery lock is set the same on all nodes..."
+try_command_on_node -v -q all $CTDB getreclock
+n=$(echo "$out" | sort -u | wc -l)
+if [ "$n" = 1 ] ; then
+    echo "GOOD: All nodes have the same recovery lock setting"
+else
+    echo "BAD: Recovery lock setting differs across nodes"
+    exit 1
+fi
+
+echo
+echo "Check that recovery lock is actually enabled..."
+t=$(echo "$out" | sed -e 's@^Reclock file:@@' | sort -u)
+if [ "$t" != "No reclock file used." ] ; then
+    echo "OK: Recovery lock is set"
+else
+    echo "OOPS: Recovery lock is unset. Skipping remainder of test"
+    exit 0
+fi
+
+echo
+orig_reclock=$(sed -n -e '1s@^Reclock file:@@p' <<<"$out")
+echo "Remember original recovery lock file: \"${orig_reclock}\""
+
+echo
+echo "Unset and test the recovery lock on all nodes..."
+try_command_on_node -pq all $CTDB setreclock
+wait_until_recovered
+try_command_on_node -v -q all $CTDB getreclock
+t=$(sort -u <<<"$out")
+if [ "$t" = "No reclock file used." ] ; then
+    echo "GOOD: Recovery lock unset on all nodes"
+else
+    echo "BAD: Recovery lock not unset on all nodes"
+    exit 1
+fi
+
+echo
+get_generation
+echo "Current generation is ${generation}"
+
+alt="${orig_reclock}.test"
+echo
+echo "Set alternative recovery lock (${alt}) and test on all nodes..."
+try_command_on_node -pq all $CTDB setreclock "$alt"
+wait_until_recovered
+try_command_on_node -v -q all $CTDB getreclock
+t=$(echo "$out" | sed -e 's@^Reclock file:@@' | sort -u)
+if [ "$t" = "$alt" ] ; then
+    echo "GOOD: Recovery lock set on all nodes"
+else
+    echo "BAD: Recovery lock not set on all nodes"
+    try_command_on_node -vf all rm -v "$alt" || true
+    exit 1
+fi
+
+# Setting or updating the recovery lock file must cause a recovery
+echo "Current generation is ${generation}"
+
+echo
+echo "Restore and test the recovery lock on all nodes..."
+try_command_on_node -pq all $CTDB setreclock "$orig_reclock"
+wait_until_recovered
+try_command_on_node -v all rm -vf "$alt"
+try_command_on_node -v -q all $CTDB getreclock
+t=$(echo "$out" | sed -e 's@^Reclock file:@@' | sort -u)
+if [ "$t" = "$orig_reclock" ] ; then
+    echo "GOOD: Recovery lock restored on all nodes"
+else
+    echo "BAD: Recovery lock not restored on all nodes"
+    exit 1
+fi
+
+echo "Current generation is ${generation}"
diff --git a/ctdb/tests/simple/35_set_recmaster.sh b/ctdb/tests/simple/35_set_recmaster.sh
deleted file mode 100755
index 7c745e4..0000000
--- a/ctdb/tests/simple/35_set_recmaster.sh
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/bin/bash
-
-test_info()
-{
-    cat <<EOF
-Verify that "ctdb setrecmaster" sets the recovery lock correctly.
-
-This test only does something when there is a recovery lock
-configured.
-EOF
-}
-
-. "${TEST_SCRIPTS_DIR}/integration.bash"
-
-ctdb_test_init "$@"
-
-set -e
-
-cluster_is_healthy
-
-# Reset configuration
-ctdb_restart_when_done
-
-get_generation ()
-{
-    local out
-    try_command_on_node any $CTDB status
-    generation=$(sed -n -e 's@^Generation:@@p' <<<"$out")
-}
-
-generation_has_changed ()
-{
-    local old_generation="$generation"
-    get_generation
-    [ "$old_generation" != "$generation" ]
-}
-
-wait_until_generation_has_changed ()
-{
-    echo
-    echo "Wait until generation has changed..."
-    wait_until 60 generation_has_changed
-}
-
-echo "Check that recovery lock is set the same on all nodes..."
-try_command_on_node -v any $CTDB -n all getreclock
-n=$(echo "$out" | sort -u | wc -l)
-if [ "$n" = 1 ] ; then
-    echo "GOOD: All nodes have the same recovery lock setting"
-else
-    echo "BAD: Recovery lock setting differs across nodes"
-    exit 1
-fi
-
-echo
-echo "Check that recovery lock is actually enabled..."
-t=$(echo "$out" | sed -e 's@^Reclock file:@@' | sort -u)
-if [ "$t" != "No reclock file used." ] ; then
-    echo "OK: Recovery lock is set"
-else
-    echo "OOPS: Recovery lock is unset. Skipping remainder of test"
-    exit 0
-fi
-
-echo
-orig_reclock=$(sed -n -e '1s@^Reclock file:@@p' <<<"$out")
-echo "Remember original recovery lock file: \"${orig_reclock}\""
-
-echo
-echo "Unset and test the recovery lock on all nodes..."
-try_command_on_node any $CTDB -n all setreclock
-try_command_on_node -v any $CTDB -n all getreclock
-t=$(sort -u <<<"$out")
-if [ "$t" = "No reclock file used." ] ; then
-    echo "GOOD: Recovery lock unset on all nodes"
-else
-    echo "BAD: Recovery lock not unset on all nodes"
-    exit 1
-fi
-
-echo
-get_generation
-echo "Current generation is ${generation}"
-
-alt="${orig_reclock}.test"
-echo
-echo "Set alternative recovery lock (${alt}) and test on all nodes..."
-try_command_on_node any $CTDB -n all setreclock "$alt"
-try_command_on_node -v any $CTDB -n all getreclock
-t=$(echo "$out" | sed -e 's@^Reclock file:@@' | sort -u)
-if [ "$t" = "$alt" ] ; then
-    echo "GOOD: Recovery lock set on all nodes"
-else
-    echo "BAD: Recovery lock not set on all nodes"
-    try_command_on_node -v any rm -v "$alt" || true
-    exit 1
-fi
-
-# Setting or updating the recovery lock file must cause a recovery
-wait_until_generation_has_changed
-echo "Current generation is ${generation}"
-
-echo
-echo "Restore and test the recovery lock on all nodes..."
-try_command_on_node any $CTDB -n all setreclock "$orig_reclock"
-try_command_on_node -v any rm -v "$alt"
-try_command_on_node -v any $CTDB -n all getreclock
-t=$(echo "$out" | sed -e 's@^Reclock file:@@' | sort -u)
-if [ "$t" = "$orig_reclock" ] ; then
-    echo "GOOD: Recovery lock restored on all nodes"
-else
-    echo "BAD: Recovery lock not restored on all nodes"
-    exit 1
-fi
-
-wait_until_generation_has_changed
-echo "Current generation is ${generation}"
diff --git a/ctdb/tests/simple/60_recoverd_missing_ip.sh b/ctdb/tests/simple/60_recoverd_missing_ip.sh
index 9ad7b69..36271d1 100755
--- a/ctdb/tests/simple/60_recoverd_missing_ip.sh
+++ b/ctdb/tests/simple/60_recoverd_missing_ip.sh
@@ -30,7 +30,7 @@ echo "Running test against node $test_node and IP $test_ip"
 get_test_ip_mask_and_iface
 
 echo "Deleting IP $test_ip from all nodes"
-try_command_on_node $test_node $CTDB delip -n all $test_ip
+delete_ip_from_all_nodes $test_ip
 wait_until_ips_are_on_node ! $test_node $test_ip
 
 try_command_on_node -v all $CTDB ip
diff --git a/ctdb/tests/simple/functions b/ctdb/tests/simple/functions
new file mode 120000
index 0000000..ff10411
--- /dev/null
+++ b/ctdb/tests/simple/functions
@@ -0,0 +1 @@
+../../config/functions
\ No newline at end of file
diff --git a/ctdb/tests/simple/scripts/local.bash b/ctdb/tests/simple/scripts/local.bash
index 81fc0f0..1ccbb23 100644
--- a/ctdb/tests/simple/scripts/local.bash
+++ b/ctdb/tests/simple/scripts/local.bash
@@ -1,3 +1,8 @@
+# onnode needs CTDB_BASE to be set when run in-tree
+if [ -z "$CTDB_BASE" ] ; then
+    export CTDB_BASE="$TEST_SUBDIR"
+fi
+
 if [ -n "$TEST_LOCAL_DAEMONS" ] ; then
     . "${TEST_SUBDIR}/scripts/local_daemons.bash"
 fi
diff --git a/ctdb/tests/simple/scripts/local_daemons.bash b/ctdb/tests/simple/scripts/local_daemons.bash
index 6015dd5..92ec391 100644
--- a/ctdb/tests/simple/scripts/local_daemons.bash
+++ b/ctdb/tests/simple/scripts/local_daemons.bash
@@ -12,6 +12,7 @@ if [ -n "$ctdb_dir" -a -d "${ctdb_dir}/bin" ] ; then
     PATH="${ctdb_dir}/bin:${PATH}"
     export CTDB_LOCK_HELPER="${ctdb_dir}/bin/ctdb_lock_helper"
     export CTDB_EVENT_HELPER="${ctdb_dir}/bin/ctdb_event_helper"
+    export CTDB_RECOVERY_HELPER="${ctdb_dir}/bin/ctdb_recovery_helper"
 fi
 
 export CTDB_NODES="${TEST_VAR_DIR}/nodes.txt"
@@ -21,7 +22,7 @@ export CTDB_NODES="${TEST_VAR_DIR}/nodes.txt"
 daemons_stop ()
 {
     echo "Attempting to politely shutdown daemons..."
-    onnode 1 $CTDB shutdown -n all || true
+    onnode -q all $CTDB shutdown || true
 
     echo "Sleeping for a while..."
     sleep_for 1
diff --git a/ctdb/tests/src/comm_client_test.c b/ctdb/tests/src/comm_client_test.c
new file mode 100644
index 0000000..8db219e
--- /dev/null
+++ b/ctdb/tests/src/comm_client_test.c
@@ -0,0 +1,216 @@
+/*
+   comm tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+
+#include <assert.h>
+
+#include "common/pkt_read.c"
+#include "common/pkt_write.c"
+#include "common/comm.c"
+
+
+struct writer_state {
+	struct tevent_context *ev;
+	struct comm_context *comm;
+	uint8_t *buf;
+	size_t *pkt_size;
+	int count, id;
+};
+
+static void writer_done(struct tevent_req *subreq);
+static void read_handler(uint8_t *buf, size_t buflen, void *private_data);
+static void dead_handler(void *private_data);
+
+static struct tevent_req *writer_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      int fd, size_t *pkt_size,
+				      int count)
+{
+	struct tevent_req *req, *subreq;
+	struct writer_state *state;
+	size_t max_size = 0, buflen;
+	int i, ret;
+
+	for (i=0; i<count; i++) {
+		if (pkt_size[i] > max_size) {
+			max_size = pkt_size[i];
+		}
+	}
+
+	req = tevent_req_create(mem_ctx, &state, struct writer_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->pkt_size = pkt_size;
+	state->count = count;
+	state->id = 0;
+
+	ret = comm_setup(state, ev, fd, read_handler, req,
+			 dead_handler, req, &state->comm);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return tevent_req_post(req, ev);
+	}
+
+	state->buf = talloc_array(state, uint8_t, max_size);
+	if (state->buf == NULL) {
+		talloc_free(req);
+		return NULL;
+	}
+	for (i=0; i<max_size; i++) {
+		state->buf[i] = i%256;
+	}
+
+	buflen = state->pkt_size[state->id];
+	*(uint32_t *)state->buf = buflen;
+	subreq = comm_write_send(state, state->ev, state->comm,
+					 state->buf, buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, writer_done, req);
+
+	return req;
+}
+
+static void writer_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	bool ret;
+	int err;
+
+	ret = comm_write_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_error(req, err);
+		return;
+	}
+}
+
+static void read_handler(uint8_t *buf, size_t buflen, void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	struct writer_state *state = tevent_req_data(
+		req, struct writer_state);
+	struct tevent_req *subreq;
+
+	if (buflen != state->pkt_size[state->id]) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	state->id++;
+	if (state->id >= state->count) {
+		tevent_req_done(req);
+		return;
+	}
+
+	buflen = state->pkt_size[state->id];
+	*(uint32_t *)state->buf = buflen;
+	subreq = comm_write_send(state, state->ev, state->comm,
+				 state->buf, buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, writer_done, req);
+}
+
+static void dead_handler(void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+
+	tevent_req_error(req, EPIPE);
+}
+
+static void writer_recv(struct tevent_req *req, int *perr)
+{
+	if (tevent_req_is_unix_error(req, perr)) {
+		return;
+	}
+	*perr = 0;
+}
+
+static int socket_init(char *sockpath)
+{
+	struct sockaddr_un addr;
+	int fd, ret, i;
+	size_t len;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+
+	len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
+	assert(len < sizeof(addr.sun_path));
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	assert(fd != -1);
+
+	for (i=0; i<5; i++) {
+		ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+		if (ret == 0) {
+			break;
+		}
+		sleep(1);
+	}
+	assert(ret != -1);
+
+	return fd;
+}
+
+int main(int argc, char *argv[])
+{
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	int fd;
+	size_t pkt_size[13] = { 100, 2048, 500, 4096, 1024, 8192,
+				200, 16384, 300, 32768, 400, 65536,
+				1024*1024 };
+	int err;
+
+	if (argc != 2) {
+		printf("Usage: %s <sockpath>\n", argv[0]);
+		exit(1);
+	}
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ev = tevent_context_init(mem_ctx);
+	assert(ev != NULL);
+
+	fd = socket_init(argv[1]);
+
+	req = writer_send(mem_ctx, ev, fd, pkt_size, 13);
+	assert(req != NULL);
+
+	tevent_req_poll(req, ev);
+
+	writer_recv(req, &err);
+	assert(err == 0);
+
+	exit(0);
+}
diff --git a/ctdb/tests/src/comm_server_test.c b/ctdb/tests/src/comm_server_test.c
new file mode 100644
index 0000000..036baac
--- /dev/null
+++ b/ctdb/tests/src/comm_server_test.c
@@ -0,0 +1,367 @@
+/*
+   comm tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+
+#include <assert.h>
+
+#include "common/pkt_read.c"
+#include "common/pkt_write.c"
+#include "common/comm.c"
+
+
+struct accept_state {
+	int listen_fd;
+	struct tevent_fd *fde;
+	int client_fd;
+};
+
+static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
+			   uint16_t flags, void *private_data);
+
+static struct tevent_req *accept_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      int listen_fd)
+{
+	struct tevent_req *req;
+	struct accept_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct accept_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->listen_fd = listen_fd;
+
+	state->fde = tevent_add_fd(ev, state, listen_fd, TEVENT_FD_READ,
+				   accept_handler, req);
+	if (tevent_req_nomem(state->fde, req)) {
+		return tevent_req_post(req, ev);
+	}
+	return req;
+}
+
+static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
+			   uint16_t flags, void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	struct accept_state *state = tevent_req_data(
+		req, struct accept_state);
+	struct sockaddr addr;
+	socklen_t addrlen = sizeof(addr);
+	int ret;
+
+	TALLOC_FREE(state->fde);
+
+	if ((flags & TEVENT_FD_READ) == 0) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	ret = accept(state->listen_fd, &addr, &addrlen);
+	if (ret == -1) {
+		tevent_req_error(req, errno);
+		return;
+	}
+
+	state->client_fd = ret;
+	tevent_req_done(req);
+}
+
+static int accept_recv(struct tevent_req *req, int *perr)
+{
+	struct accept_state *state = tevent_req_data(
+		req, struct accept_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return -1;
+	}
+
+	return state->client_fd;
+}
+
+
+struct echo_state {
+	struct tevent_context *ev;
+	int fd;
+	struct comm_context *comm;
+	uint8_t *data;
+};
+
+static void read_handler(uint8_t *buf, size_t buflen, void *private_data);
+static void read_failed(void *private_data);
+static void write_done(struct tevent_req *subreq);
+
+static struct tevent_req *echo_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev, int fd)
+{
+	struct tevent_req *req;
+	struct echo_state *state;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state, struct echo_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->fd = fd;
+
+	ret = comm_setup(state, ev, fd, read_handler, req,
+			 read_failed, req, &state->comm);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
+		return tevent_req_post(req, ev);
+	}
+
+	return req;
+}
+
+static void read_handler(uint8_t *buf, size_t buflen, void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	struct echo_state *state = tevent_req_data(
+		req, struct echo_state);
+	struct tevent_req *subreq;
+
+	state->data = talloc_memdup(state, buf, buflen);
+	if (tevent_req_nomem(state->data, req)) {
+		return;
+	}
+
+	subreq = comm_write_send(state, state->ev, state->comm,
+				 state->data, buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, write_done, req);
+}
+
+static void read_failed(void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+
+	tevent_req_done(req);
+}
+
+static void write_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct echo_state *state = tevent_req_data(
+		req, struct echo_state);
+	bool ret;
+	int err;
+
+	TALLOC_FREE(state->data);
+
+	ret = comm_write_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_error(req, err);
+		return;
+	}
+}
+
+static bool echo_recv(struct tevent_req *req, int *perr)
+{
+	struct echo_state *state = tevent_req_data(
+		req, struct echo_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return false;
+	}
+
+	close(state->fd);
+	return true;
+}
+
+
+struct socket_process_state {
+	struct tevent_context *ev;
+	int fd;
+	int max_clients;
+	int num_clients;
+};
+
+static void socket_process_client(struct tevent_req *subreq);
+static void socket_process_client_done(struct tevent_req *subreq);
+
+static struct tevent_req *socket_process_send(TALLOC_CTX *mem_ctx,
+					      struct tevent_context *ev,
+					      int fd, int max_clients)
+{
+	struct tevent_req *req, *subreq;
+	struct socket_process_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct socket_process_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->fd = fd;
+	state->max_clients = max_clients;
+	state->num_clients = 0;
+
+	subreq = accept_send(state, ev, fd);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, socket_process_client, req);
+
+	return req;
+}
+
+static void socket_process_client(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct socket_process_state *state = tevent_req_data(
+		req, struct socket_process_state);
+	int client_fd;
+	int err = 0;
+
+	client_fd = accept_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+
+	state->num_clients++;
+
+	if (client_fd == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	subreq = echo_send(state, state->ev, client_fd);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, socket_process_client_done, req);
+
+	if (state->num_clients == state->max_clients) {
+		/* Stop accepting any more clients */
+		return;
+	}
+
+	subreq = accept_send(state, state->ev, state->fd);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, socket_process_client, req);
+}
+
+static void socket_process_client_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct socket_process_state *state = tevent_req_data(
+		req, struct socket_process_state);
+	bool ret;
+	int err = 0;
+
+	ret = echo_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	if (state->num_clients == state->max_clients) {
+		tevent_req_done(req);
+	}
+}
+
+static void socket_process_recv(struct tevent_req *req, int *perr)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+	}
+}
+
+static int socket_init(char *sockpath)
+{
+	struct sockaddr_un addr;
+	int fd, ret;
+	size_t len;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+
+	len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
+	assert(len < sizeof(addr.sun_path));
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	assert(fd != -1);
+
+	ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+	assert(ret != -1);
+
+	ret = listen(fd, 10);
+	assert(ret != -1);
+
+	return fd;
+}
+
+int main(int argc, char *argv[])
+{
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	int fd, err = 0;
+	int num_clients;
+
+	if (argc != 3) {
+		printf("Usage: %s <sockpath> <num_clients>\n", argv[0]);
+		exit(1);
+	}
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ev = tevent_context_init(mem_ctx);
+	assert(ev != NULL);
+
+	fd = socket_init(argv[1]);
+	num_clients = atoi(argv[2]);
+	assert(num_clients > 0);
+
+	req = socket_process_send(mem_ctx, ev, fd, num_clients);
+	assert(req != NULL);
+
+	tevent_req_poll(req, ev);
+
+	socket_process_recv(req, &err);
+	return err;
+}
diff --git a/ctdb/tests/src/comm_test.c b/ctdb/tests/src/comm_test.c
new file mode 100644
index 0000000..2189435
--- /dev/null
+++ b/ctdb/tests/src/comm_test.c
@@ -0,0 +1,260 @@
+/*
+   comm tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+
+#include <assert.h>
+
+#include "common/pkt_read.c"
+#include "common/pkt_write.c"
+#include "common/comm.c"
+
+static void dead_handler(void *private_data)
+{
+	int dead_data = *(int *)private_data;
+
+	assert(dead_data == 1 || dead_data == 2);
+
+	if (dead_data == 1) {
+		/* reader */
+		printf("writer closed pipe\n");
+	} else {
+		/* writer */
+		printf("reader closed pipe\n");
+	}
+}
+
+struct writer_state {
+	struct tevent_context *ev;
+	struct comm_context *comm;
+	uint8_t *buf;
+	size_t *pkt_size;
+	int count, id;
+};
+
+static void writer_next(struct tevent_req *subreq);
+
+static struct tevent_req *writer_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      struct comm_context *comm,
+				      size_t *pkt_size, int count)
+{
+	struct tevent_req *req, *subreq;
+	struct writer_state *state;
+	size_t max_size = 0, buflen;
+	int i;
+
+	for (i=0; i<count; i++) {
+		if (pkt_size[i] > max_size) {
+			max_size = pkt_size[i];
+		}
+	}
+
+	req = tevent_req_create(mem_ctx, &state, struct writer_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->comm = comm;
+	state->pkt_size = pkt_size;
+	state->count = count;
+	state->id = 0;
+
+	state->buf = talloc_array(state, uint8_t, max_size);
+	if (state->buf == NULL) {
+		talloc_free(req);
+		return NULL;
+	}
+	for (i=0; i<max_size; i++) {
+		state->buf[i] = i%256;
+	}
+
+	buflen = state->pkt_size[state->id];
+	*(uint32_t *)state->buf = buflen;
+	subreq = comm_write_send(state, state->ev, state->comm,
+					 state->buf, buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	tevent_req_set_callback(subreq, writer_next, req);
+	return req;
+}
+
+static void writer_next(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct writer_state *state = tevent_req_data(
+		req, struct writer_state);
+	bool ret;
+	int err;
+	size_t buflen;
+
+	ret = comm_write_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	state->id++;
+	if (state->id >= state->count) {
+		tevent_req_done(req);
+		return;
+	}
+
+	buflen = state->pkt_size[state->id];
+	*(uint32_t *)state->buf = buflen;
+	subreq = comm_write_send(state, state->ev, state->comm,
+					 state->buf, buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+
+	tevent_req_set_callback(subreq, writer_next, req);
+}
+
+static void writer_recv(struct tevent_req *req, int *perr)
+{
+	if (tevent_req_is_unix_error(req, perr)) {
+		return;
+	}
+	*perr = 0;
+}
+
+static void writer(int fd, size_t *pkt_size, int count)
+{
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *ev;
+	struct comm_context *comm;
+	struct tevent_req *req;
+	int dead_data = 2;
+	int err;
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ev = tevent_context_init(mem_ctx);
+	assert(ev != NULL);
+
+	err = comm_setup(mem_ctx, ev, fd, NULL, NULL,
+			 dead_handler, &dead_data, &comm);
+	assert(err == 0);
+	assert(comm != NULL);
+
+	req = writer_send(mem_ctx, ev, comm, pkt_size, count);
+	assert(req != NULL);
+
+	tevent_req_poll(req, ev);
+
+	writer_recv(req, &err);
+	assert(err == 0);
+
+	talloc_free(mem_ctx);
+}
+
+struct reader_state {
+	size_t *pkt_size;
+	int count, received;
+	bool done;
+};
+
+static void reader_handler(uint8_t *buf, size_t buflen, void *private_data)
+{
+	struct reader_state *state = talloc_get_type_abort(
+		private_data, struct reader_state);
+
+	assert(buflen == state->pkt_size[state->received]);
+	printf("%zi ", buflen);
+	state->received++;
+
+	if (state->received == state->count) {
+		printf("\n");
+		state->done = true;
+	}
+}
+
+static void reader(int fd, size_t *pkt_size, int count)
+{
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *ev;
+	struct comm_context *comm;
+	struct reader_state *state;
+	int dead_data = 1;
+	int err;
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ev = tevent_context_init(mem_ctx);
+	assert(ev != NULL);
+
+	state = talloc_zero(mem_ctx, struct reader_state);
+	assert(state != NULL);
+
+	state->pkt_size = pkt_size;
+	state->count = count;
+	state->received = 0;
+	state->done = false;
+
+	err = comm_setup(mem_ctx, ev, fd, reader_handler, state,
+			 dead_handler, &dead_data, &comm);
+	assert(err == 0);
+	assert(comm != NULL);
+
+	while (!state->done) {
+		tevent_loop_once(ev);
+	}
+
+	talloc_free(mem_ctx);
+}
+
+int main(void)
+{
+	int fd[2];
+	int ret;
+	pid_t pid;
+	size_t pkt_size[13] = { 100, 2048, 500, 4096, 1024, 8192,
+			      200, 16384, 300, 32768, 400, 65536,
+			      1024*1024 };
+
+
+	ret = pipe(fd);
+	assert(ret == 0);
+
+	pid = fork();
+	assert(pid != -1);
+
+	if (pid == 0) {
+		/* Child process */
+		close(fd[0]);
+		writer(fd[1], pkt_size, 13);
+		close(fd[1]);
+		exit(0);
+	}
+
+	close(fd[1]);
+	reader(fd[0], pkt_size, 13);
+	close(fd[0]);
+
+	return 0;
+}
diff --git a/ctdb/tests/src/ctdb_bench.c b/ctdb/tests/src/ctdb_bench.c
index 3323589..32438f5 100644
--- a/ctdb/tests/src/ctdb_bench.c
+++ b/ctdb/tests/src/ctdb_bench.c
@@ -17,15 +17,23 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
-#include "ctdb_client.h"
+#include "system/network.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/time.h"
+#include "lib/util/debug.h"
+
 #include "ctdb_private.h"
+#include "ctdb_client.h"
 
-#include <sys/time.h>
-#include <time.h>
+#include "common/cmdline.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 static struct timeval tp1,tp2;
 
@@ -56,7 +64,7 @@ static int incr_func(struct ctdb_call_info *call)
 	if (call->record_data.dsize == 0) {
 		call->new_data = talloc(call, TDB_DATA);
 		if (call->new_data == NULL) {
-			return CTDB_ERR_NOMEM;
+			return ENOMEM;
 		}
 		call->new_data->dptr = talloc_size(call, 4);
 		call->new_data->dsize = 4;
@@ -78,26 +86,31 @@ static int fetch_func(struct ctdb_call_info *call)
 }
 
 
-static int msg_count;
-static int msg_plus, msg_minus;
+struct bench_data {
+	struct ctdb_context *ctdb;
+	struct tevent_context *ev;
+	int msg_count;
+	int msg_plus, msg_minus;
+};
 
 /*
   handler for messages in bench_ring()
 */
-static void ring_message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-				 TDB_DATA data, void *private_data)
+static void ring_message_handler(uint64_t srvid, TDB_DATA data,
+				 void *private_data)
 {
+	struct bench_data *bdata = talloc_get_type_abort(
+		private_data, struct bench_data);
 	int incr = *(int *)data.dptr;
-	int *count = (int *)private_data;
 	int dest;
 
-	(*count)++;
-	dest = (ctdb_get_pnn(ctdb) + num_nodes + incr) % num_nodes;
-	ctdb_client_send_message(ctdb, dest, srvid, data);
+	bdata->msg_count++;
+	dest = (ctdb_get_pnn(bdata->ctdb) + num_nodes + incr) % num_nodes;
+	ctdb_client_send_message(bdata->ctdb, dest, srvid, data);
 	if (incr == 1) {
-		msg_plus++;
+		bdata->msg_plus++;
 	} else {
-		msg_minus++;
+		bdata->msg_minus++;
 	}
 }
 
@@ -116,10 +129,11 @@ static void send_start_messages(struct ctdb_context *ctdb, int incr)
 	ctdb_client_send_message(ctdb, dest, 0, data);
 }
 
-static void each_second(struct event_context *ev, struct timed_event *te, 
-					 struct timeval t, void *private_data)
+static void each_second(struct tevent_context *ev, struct tevent_timer *te,
+			struct timeval t, void *private_data)
 {
-	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	struct bench_data *bdata = talloc_get_type_abort(
+		private_data, struct bench_data);
 
 	/* we kickstart the ring into action by inserting messages from node
 	   with pnn 0.
@@ -127,49 +141,57 @@ static void each_second(struct event_context *ev, struct timed_event *te,
 	   running in which case the ring is broken and the messages are lost.
 	   if so, once every second try again to restart the ring
 	*/
-	if (msg_plus == 0) {
+	if (bdata->msg_plus == 0) {
 //		printf("no messages recevied, try again to kickstart the ring in forward direction...\n");
-		send_start_messages(ctdb, 1);
+		send_start_messages(bdata->ctdb, 1);
 	}
-	if (msg_minus == 0) {
+	if (bdata->msg_minus == 0) {
 //		printf("no messages recevied, try again to kickstart the ring in reverse direction...\n");
-		send_start_messages(ctdb, -1);
+		send_start_messages(bdata->ctdb, -1);
 	}
-	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+	tevent_add_timer(bdata->ev, bdata, timeval_current_ofs(1, 0),
+			 each_second, bdata);
 }
 
-static void dummy_event(struct event_context *ev, struct timed_event *te, 
-					 struct timeval t, void *private_data)
+static void dummy_event(struct tevent_context *ev, struct tevent_timer *te,
+			struct timeval t, void *private_data)
 {
-	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
-	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), dummy_event, ctdb);
+	struct bench_data *bdata = talloc_get_type_abort(
+		private_data, struct bench_data);
+
+	tevent_add_timer(bdata->ev, bdata, timeval_current_ofs(1, 0),
+			 dummy_event, bdata);
 }
 
 /*
   benchmark sending messages in a ring around the nodes
 */
-static void bench_ring(struct ctdb_context *ctdb, struct event_context *ev)
+static void bench_ring(struct bench_data *bdata)
 {
-	int pnn=ctdb_get_pnn(ctdb);
+	int pnn = ctdb_get_pnn(bdata->ctdb);
 
 	if (pnn == 0) {
-		event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+		tevent_add_timer(bdata->ev, bdata, timeval_current_ofs(1, 0),
+				 each_second, bdata);
 	} else {
-		event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), dummy_event, ctdb);
+		tevent_add_timer(bdata->ev, bdata, timeval_current_ofs(1, 0),
+				 dummy_event, bdata);
 	}
 
 	start_timer();
 	while (end_timer() < timelimit) {
-		if (pnn == 0 && msg_count % 10000 == 0 && end_timer() > 0) {
-			printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\r", 
-			       msg_count/end_timer(), msg_plus, msg_minus);
+		if (pnn == 0 && bdata->msg_count % 10000 == 0 && end_timer() > 0) {
+			printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\r",
+			       bdata->msg_count/end_timer(),
+			       bdata->msg_plus, bdata->msg_minus);
 			fflush(stdout);
 		}
-		event_loop_once(ev);
+		tevent_loop_once(bdata->ev);
 	}
 
-	printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\n", 
-	       msg_count/end_timer(), msg_plus, msg_minus);
+	printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\n",
+	       bdata->msg_count/end_timer(),
+	       bdata->msg_plus, bdata->msg_minus);
 }
 
 /*
@@ -193,7 +215,8 @@ int main(int argc, const char *argv[])
 	int extra_argc = 0;
 	int ret;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
+	struct bench_data *bdata;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
 
@@ -218,7 +241,7 @@ int main(int argc, const char *argv[])
 		exit(1);
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	/* initialise ctdb */
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
@@ -244,7 +267,14 @@ int main(int argc, const char *argv[])
 		DEBUG(DEBUG_DEBUG,("ctdb_set_call() failed, ignoring return code %d\n", ret));
 	}
 
-	if (ctdb_client_set_message_handler(ctdb, 0, ring_message_handler,&msg_count))
+	bdata = talloc_zero(ctdb, struct bench_data);
+	if (bdata == NULL) {
+		goto error;
+	}
+	bdata->ctdb = ctdb;
+	bdata->ev = ev;
+
+	if (ctdb_client_set_message_handler(ctdb, 0, ring_message_handler, bdata))
 		goto error;
 
 	printf("Waiting for cluster\n");
@@ -252,11 +282,11 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
-	bench_ring(ctdb, ev);
-       
+	bench_ring(bdata);
+
 error:
 	return 0;
 }
diff --git a/ctdb/tests/src/ctdb_fetch.c b/ctdb/tests/src/ctdb_fetch.c
index b900efa..600504b 100644
--- a/ctdb/tests/src/ctdb_fetch.c
+++ b/ctdb/tests/src/ctdb_fetch.c
@@ -17,13 +17,25 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
+
+#include <popt.h>
+#include <talloc.h>
+/* Allow use of deprecated function tevent_loop_allow_nesting() */
+#define TEVENT_DEPRECATED
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
 
-#include <sys/time.h>
-#include <time.h>
 
 static struct timeval tp1,tp2;
 
@@ -43,7 +55,12 @@ static double end_timer(void)
 static int timelimit = 10;
 static int num_records = 10;
 static int num_nodes;
-static int msg_count;
+
+struct bench_data {
+	struct ctdb_context *ctdb;
+	struct tevent_context *ev;
+	int msg_count;
+};
 
 #define TESTKEY "testkey"
 
@@ -52,8 +69,9 @@ static int msg_count;
   store a expanded record
   send a message to next node to tell it to do the same
 */
-static void bench_fetch_1node(struct ctdb_context *ctdb)
+static void bench_fetch_1node(struct bench_data *bdata)
 {
+	struct ctdb_context *ctdb = bdata->ctdb;
 	TDB_DATA key, data, nulldata;
 	struct ctdb_db_context *ctdb_db;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
@@ -80,9 +98,10 @@ static void bench_fetch_1node(struct ctdb_context *ctdb)
 	if (data.dsize == 0) {
 		data.dptr = (uint8_t *)talloc_asprintf(tmp_ctx, "Test data\n");
 	}
-	data.dptr = (uint8_t *)talloc_asprintf_append((char *)data.dptr, 
+	data.dptr = (uint8_t *)talloc_asprintf_append((char *)data.dptr,
 						      "msg_count=%d on node %d\n",
-						      msg_count, ctdb_get_pnn(ctdb));
+						      bdata->msg_count,
+						      ctdb_get_pnn(ctdb));
 	if (data.dptr == NULL) {
 		printf("Failed to create record\n");
 		talloc_free(tmp_ctx);
@@ -109,18 +128,21 @@ static void bench_fetch_1node(struct ctdb_context *ctdb)
 /*
   handler for messages in bench_ring()
 */
-static void message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			    TDB_DATA data, void *private_data)
+static void message_handler(uint64_t srvid, TDB_DATA data, void *private_data)
 {
-	msg_count++;
-	bench_fetch_1node(ctdb);
+	struct bench_data *bdata = talloc_get_type_abort(
+		private_data, struct bench_data);
+
+	bdata->msg_count++;
+	bench_fetch_1node(bdata);
 }
 
 
 /*
  * timeout handler - noop
  */
-static void timeout_handler(struct event_context *ev, struct timed_event *timer,
+static void timeout_handler(struct tevent_context *ev,
+			    struct tevent_timer *timer,
 			    struct timeval curtime, void *private_data)
 {
 	return;
@@ -134,36 +156,38 @@ static void timeout_handler(struct event_context *ev, struct timed_event *timer,
   send a message to next node to tell it to do the same
 
 */
-static void bench_fetch(struct ctdb_context *ctdb, struct event_context *ev)
+static void bench_fetch(struct bench_data *bdata)
 {
+	struct ctdb_context *ctdb = bdata->ctdb;
 	int pnn=ctdb_get_pnn(ctdb);
 
 	if (pnn == num_nodes - 1) {
-		bench_fetch_1node(ctdb);
+		bench_fetch_1node(bdata);
 	}
-	
+
 	start_timer();
-	event_add_timed(ev, ctdb, timeval_current_ofs(timelimit,0), timeout_handler, NULL);
+	tevent_add_timer(bdata->ev, bdata, timeval_current_ofs(timelimit,0),
+			 timeout_handler, NULL);
 
 	while (end_timer() < timelimit) {
-		if (pnn == 0 && msg_count % 100 == 0 && end_timer() > 0) {
-			printf("Fetch: %.2f msgs/sec\r", msg_count/end_timer());
+		if (pnn == 0 && bdata->msg_count % 100 == 0 && end_timer() > 0) {
+			printf("Fetch: %.2f msgs/sec\r", bdata->msg_count/end_timer());
 			fflush(stdout);
 		}
-		if (event_loop_once(ev) != 0) {
+		if (tevent_loop_once(bdata->ev) != 0) {
 			printf("Event loop failed!\n");
 			break;
 		}
 	}
 
-	printf("Fetch: %.2f msgs/sec\n", msg_count/end_timer());
+	printf("Fetch: %.2f msgs/sec\n", bdata->msg_count/end_timer());
 }
 
 /*
   handler for reconfigure message
 */
-static void reconfigure_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-				TDB_DATA data, void *private_data)
+static void reconfigure_handler(uint64_t srvid, TDB_DATA data,
+				void *private_data)
 {
 	int *ready = (int *)private_data;
 	*ready = 1;
@@ -189,10 +213,11 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 	TDB_DATA key, data;
 	struct ctdb_record_handle *h;
 	int cluster_ready=0;
+	struct bench_data *bdata;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
 
@@ -219,7 +244,7 @@ int main(int argc, const char *argv[])
 		exit(1);
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 	tevent_loop_allow_nesting(ev);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
@@ -229,8 +254,8 @@ int main(int argc, const char *argv[])
 		exit(1);
 	}
 
-	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_RECONFIGURE, reconfigure_handler, 
-				 &cluster_ready);
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_RECONFIGURE,
+					reconfigure_handler, &cluster_ready);
 
 	/* attach to a specific database */
 	ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0), "test.tdb",
@@ -240,14 +265,23 @@ int main(int argc, const char *argv[])
 		exit(1);
 	}
 
-	ctdb_client_set_message_handler(ctdb, 0, message_handler, &msg_count);
+	bdata = talloc_zero(ctdb, struct bench_data);
+	if (bdata == NULL) {
+		printf("memory allocation error\n");
+		exit(1);
+	}
+
+	bdata->ctdb = ctdb;
+	bdata->ev = ev;
+
+	ctdb_client_set_message_handler(ctdb, 0, message_handler, bdata);
 
 	printf("Waiting for cluster\n");
 	while (1) {
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 	/* This test has a race condition. If CTDB receives the message from previous
@@ -257,7 +291,7 @@ int main(int argc, const char *argv[])
 	 */
 	printf("Sleeping for %d seconds\n", num_nodes);
 	sleep(num_nodes);
-	bench_fetch(ctdb, ev);
+	bench_fetch(bdata);
 
 	key.dptr = discard_const(TESTKEY);
 	key.dsize = strlen(TESTKEY);
diff --git a/ctdb/tests/src/ctdb_fetch_one.c b/ctdb/tests/src/ctdb_fetch_one.c
index ba0e183..e24684f 100644
--- a/ctdb/tests/src/ctdb_fetch_one.c
+++ b/ctdb/tests/src/ctdb_fetch_one.c
@@ -18,13 +18,22 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
 
-#include <sys/time.h>
-#include <time.h>
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
 
 static int timelimit = 10;
 static int lock_count = 0;
@@ -49,7 +58,8 @@ static void alarm_handler(int sig)
 /*
 	Just try locking/unlocking the same record over and over
 */
-static void bench_fetch_one_loop(struct ctdb_context *ctdb, struct event_context *ev)
+static void bench_fetch_one_loop(struct ctdb_context *ctdb,
+				 struct tevent_context *ev)
 {
 	TDB_DATA key, data;
 
@@ -91,7 +101,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
 
@@ -111,7 +121,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
 
@@ -133,7 +143,7 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 	signal(SIGALRM, alarm_handler);
diff --git a/ctdb/tests/src/ctdb_fetch_readonly_loop.c b/ctdb/tests/src/ctdb_fetch_readonly_loop.c
index bd171f5..3e4cc03 100644
--- a/ctdb/tests/src/ctdb_fetch_readonly_loop.c
+++ b/ctdb/tests/src/ctdb_fetch_readonly_loop.c
@@ -18,12 +18,23 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
 #include "system/time.h"
-#include "popt.h"
-#include "cmdline.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/time.h"
+
 #include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
 
 static struct ctdb_db_context *ctdb_db;
 
@@ -33,7 +44,8 @@ static int count;
 /*
 	Just try locking/unlocking a single record once
 */
-static void fetch_lock_once(struct ctdb_context *ctdb, struct event_context *ev)
+static void fetch_lock_once(struct ctdb_context *ctdb,
+			    struct tevent_context *ev)
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	TDB_DATA key, data;
@@ -84,7 +96,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
 
@@ -104,7 +116,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(5, 0));
 	if (ctdb == NULL) {
@@ -134,7 +146,7 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 	while (1) {
diff --git a/ctdb/tests/src/ctdb_fetch_readonly_once.c b/ctdb/tests/src/ctdb_fetch_readonly_once.c
index 5dc64e0..2119273 100644
--- a/ctdb/tests/src/ctdb_fetch_readonly_once.c
+++ b/ctdb/tests/src/ctdb_fetch_readonly_once.c
@@ -18,10 +18,22 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include <poll.h>
+#include "system/network.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/common.h"
+#include "common/cmdline.h"
 
 const char *TESTKEY = "testkey";
 
@@ -52,7 +64,7 @@ int main(int argc, const char *argv[])
 {
 	struct ctdb_context *ctdb;
 	struct ctdb_db_context *ctdb_db;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	TDB_DATA key;
 
@@ -84,7 +96,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
 	if (ctdb == NULL) {
@@ -108,7 +120,7 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 	fetch_readonly_once(ctdb, ctdb_db, key);
diff --git a/ctdb/tests/src/ctdb_lock_tdb.c b/ctdb/tests/src/ctdb_lock_tdb.c
index a53ffa1..df313c6 100644
--- a/ctdb/tests/src/ctdb_lock_tdb.c
+++ b/ctdb/tests/src/ctdb_lock_tdb.c
@@ -1,7 +1,7 @@
-#include <stdio.h>
-#include <fcntl.h>
+#include "replace.h"
+#include "system/filesys.h"
 
-#include "includes.h"
+#include <tdb.h>
 
 const char *tdb_file;
 TDB_CONTEXT *tdb;
diff --git a/ctdb/tests/src/ctdb_persistent.c b/ctdb/tests/src/ctdb_persistent.c
index 0bf92b3..74eefa9 100644
--- a/ctdb/tests/src/ctdb_persistent.c
+++ b/ctdb/tests/src/ctdb_persistent.c
@@ -18,13 +18,24 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
 
-#include <sys/time.h>
-#include <time.h>
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 static struct timeval tp1,tp2;
 
@@ -48,8 +59,8 @@ static TDB_DATA old_data;
 
 static int success = true;
 
-static void each_second(struct event_context *ev, struct timed_event *te, 
-					 struct timeval t, void *private_data)
+static void each_second(struct tevent_context *ev, struct tevent_timer *te,
+			struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
 	int i;
@@ -63,7 +74,7 @@ static void each_second(struct event_context *ev, struct timed_event *te,
 	}
 	printf("\n"); 
 
-	event_add_timed(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+	tevent_add_timer(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
 }
 
 static void check_counters(struct ctdb_context *ctdb, TDB_DATA data)
@@ -101,7 +112,8 @@ static void check_counters(struct ctdb_context *ctdb, TDB_DATA data)
 
 
 
-static void test_store_records(struct ctdb_context *ctdb, struct event_context *ev)
+static void test_store_records(struct ctdb_context *ctdb,
+			       struct tevent_context *ev)
 {
 	TDB_DATA key;
 	struct ctdb_db_context *ctdb_db;
@@ -195,7 +207,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	setlinebuf(stdout);
 
@@ -217,7 +229,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
 	if (ctdb == NULL) {
@@ -244,14 +256,15 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 	pnn = ctdb_get_pnn(ctdb);
 	printf("Starting test on node %u. running for %u seconds\n", pnn, timelimit);
 
 	if (pnn == 0) {
-		event_add_timed(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+		tevent_add_timer(ev, ctdb, timeval_current_ofs(1, 0),
+				 each_second, ctdb);
 	}
 
 	test_store_records(ctdb, ev);
diff --git a/ctdb/tests/src/ctdb_porting_tests.c b/ctdb/tests/src/ctdb_porting_tests.c
index e95c25d..d281e67 100644
--- a/ctdb/tests/src/ctdb_porting_tests.c
+++ b/ctdb/tests/src/ctdb_porting_tests.c
@@ -17,11 +17,25 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "include/ctdb_private.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
+
 
 static struct {
 	const char *socketname;
@@ -233,22 +247,6 @@ static int test_ctdb_get_peer_pid(void)
 	return 0;
 }
 
-static int test_ctdb_get_process_name(void)
-{
-	char *process_name = NULL;
-	globals.testcount++;
-	process_name = ctdb_get_process_name(globals.helper_pid);
-	if ((process_name == NULL) || !strcmp(process_name, "unknown")) {
-		DEBUG(DEBUG_CRIT,("Test failed: Invalid process name of %d: %s\n", globals.helper_pid, process_name));
-		free(process_name);
-		return -1;
-	}
-	DEBUG(DEBUG_INFO,("Test OK: Name of PID=%d: %s\n", globals.helper_pid, process_name));
-	globals.successcount++;
-	free(process_name);
-	return 0;
-}
-
 /*
   main program
 */
@@ -301,8 +299,6 @@ int main(int argc, const char *argv[])
 	/* FIXME: Test ctdb_sys_{open,close}_capture_socket, ctdb_sys_read_tcp_packet */
 	test_ctdb_sys_check_iface_exists();
 	test_ctdb_get_peer_pid();
-	test_ctdb_get_process_name();
-	/* FIXME: Test ctdb_get_lock_info, ctdb_get_blocker_pid*/
 
 	socket_server_close();
 
diff --git a/ctdb/tests/src/ctdb_randrec.c b/ctdb/tests/src/ctdb_randrec.c
index 60d233b..3541a91 100644
--- a/ctdb/tests/src/ctdb_randrec.c
+++ b/ctdb/tests/src/ctdb_randrec.c
@@ -18,14 +18,24 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
+#include "system/time.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/time.h"
+
 #include "ctdb_private.h"
+#include "ctdb_client.h"
 
-#include <sys/time.h>
-#include <time.h>
+#include "common/cmdline.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 static struct timeval tp1,tp2;
 
@@ -45,7 +55,7 @@ static int num_records = 10;
 static int delete_pct = 75;
 static int base_rec;
 
-static void store_records(struct ctdb_context *ctdb, struct event_context *ev)
+static void store_records(struct ctdb_context *ctdb, struct tevent_context *ev)
 {
 	TDB_DATA key, data;
 	struct ctdb_db_context *ctdb_db;
@@ -158,7 +168,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
 
@@ -178,7 +188,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
 
diff --git a/ctdb/tests/src/ctdb_store.c b/ctdb/tests/src/ctdb_store.c
index 6920343..0405e83 100644
--- a/ctdb/tests/src/ctdb_store.c
+++ b/ctdb/tests/src/ctdb_store.c
@@ -18,18 +18,27 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
 
-#include <sys/time.h>
-#include <time.h>
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
 
 static int num_records = 10;
 static int base_rec;
 
-static void store_records(struct ctdb_context *ctdb, struct event_context *ev)
+static void store_records(struct ctdb_context *ctdb, struct tevent_context *ev)
 {
 	TDB_DATA key, data;
 	struct ctdb_db_context *ctdb_db;
@@ -37,7 +46,7 @@ static void store_records(struct ctdb_context *ctdb, struct event_context *ev)
 	int ret;
 	struct ctdb_record_handle *h;
 	uint32_t i;
-	
+
 	ctdb_db = ctdb_db_handle(ctdb, "test.tdb");
 
 	printf("creating %d records\n", num_records);
@@ -111,7 +120,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
 
@@ -133,7 +142,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
 
@@ -154,7 +163,7 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 	store_records(ctdb, ev);
diff --git a/ctdb/tests/src/ctdb_takeover_tests.c b/ctdb/tests/src/ctdb_takeover_tests.c
index 7ff8755..bbd004e 100644
--- a/ctdb/tests/src/ctdb_takeover_tests.c
+++ b/ctdb/tests/src/ctdb_takeover_tests.c
@@ -26,16 +26,16 @@
 /* Format of each line is "IP pnn" - the separator has to be at least
  * 1 space (not a tab or whatever - a space!).
  */
-static struct ctdb_public_ip_list *
+static struct public_ip_list *
 read_ctdb_public_ip_list(TALLOC_CTX *ctx)
 {
 	char line[1024];
 	ctdb_sock_addr addr;
 	char *t;
 	int pnn;
-	struct ctdb_public_ip_list *last = NULL;
+	struct public_ip_list *last = NULL;
 
-	struct ctdb_public_ip_list *ret = NULL;
+	struct public_ip_list *ret = NULL;
 
 	while (fgets(line, sizeof(line), stdin) != NULL) {
 		
@@ -55,9 +55,9 @@ read_ctdb_public_ip_list(TALLOC_CTX *ctx)
 	       
 		if (parse_ip(line, NULL, 0, &addr)) {
 			if (last == NULL) {
-				last = talloc(ctx, struct ctdb_public_ip_list);
+				last = talloc(ctx, struct public_ip_list);
 			} else {
-				last->next = talloc(ctx, struct ctdb_public_ip_list);
+				last->next = talloc(ctx, struct public_ip_list);
 				last = last->next;
 			}
 			last->next = NULL;
@@ -74,7 +74,7 @@ read_ctdb_public_ip_list(TALLOC_CTX *ctx)
 	return ret;
 }
 
-static void print_ctdb_public_ip_list(struct ctdb_public_ip_list * ips)
+static void print_ctdb_public_ip_list(struct public_ip_list * ips)
 {
 	while (ips) {
 		printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn);
@@ -86,7 +86,7 @@ static void print_ctdb_public_ip_list(struct ctdb_public_ip_list * ips)
  * them back out. */
 static void ctdb_test_read_ctdb_public_ip_list(void)
 {
-	struct ctdb_public_ip_list *l;
+	struct public_ip_list *l;
 
 	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
 
@@ -97,26 +97,41 @@ static void ctdb_test_read_ctdb_public_ip_list(void)
 	talloc_free(tmp_ctx);
 }
 
+static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
+				    int numnodes,
+				    const char *tunable);
+static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
+					int numnodes);
+
 /* Format of each line is "IP CURRENT_PNN ALLOWED_PNN,...".
  */
 static bool
-read_ctdb_public_ip_info(TALLOC_CTX *ctx,
+read_ctdb_public_ip_info(TALLOC_CTX *ctx  ,
 			 int numnodes,
-			 struct ctdb_public_ip_list ** all_ips,
-			 struct ctdb_all_public_ips *** avail)
+			 struct public_ip_list ** all_ips,
+			 struct ctdb_public_ip_list_old *** known,
+			 struct ctdb_public_ip_list_old *** avail)
 {
 	char line[1024];
 	ctdb_sock_addr addr;
 	char *t, *tok;
-	struct ctdb_public_ip_list * ta;
+	struct public_ip_list * ta;
 	int pnn, numips, curr, n, i;
-	struct ctdb_all_public_ips * a;
+	struct ctdb_public_ip_list_old * a;
 
-	struct ctdb_public_ip_list *last = NULL;
+	struct public_ip_list *last = NULL;
+	enum ctdb_runstate *runstate;
+
+	runstate = get_runstate(ctx, numnodes);
 
-	*avail = talloc_array_size(ctx, sizeof(struct ctdb_all_public_ips *), CTDB_TEST_MAX_NODES);
+	*known = talloc_array_size(ctx, sizeof(struct ctdb_public_ip_list_old *), CTDB_TEST_MAX_NODES);
+	memset(*known, 0,
+	       sizeof(struct ctdb_public_ip_list_old *) * CTDB_TEST_MAX_NODES);
+
+	*avail = talloc_array_size(ctx, sizeof(struct ctdb_public_ip_list_old *),
+				   CTDB_TEST_MAX_NODES);
 	memset(*avail, 0,
-	       sizeof(struct ctdb_all_public_ips *) * CTDB_TEST_MAX_NODES);
+	       sizeof(struct ctdb_public_ip_list_old *) * CTDB_TEST_MAX_NODES);
 
 	numips = 0;
 	*all_ips = NULL;
@@ -159,9 +174,9 @@ read_ctdb_public_ip_info(TALLOC_CTX *ctx,
 
 		/* Add address + pnn to all_ips */
 		if (last == NULL) {
-			last = talloc(ctx, struct ctdb_public_ip_list);
+			last = talloc(ctx, struct public_ip_list);
 		} else {
-			last->next = talloc(ctx, struct ctdb_public_ip_list);
+			last->next = talloc(ctx, struct public_ip_list);
 			last = last->next;
 		}
 		last->next = NULL;
@@ -180,22 +195,29 @@ read_ctdb_public_ip_info(TALLOC_CTX *ctx,
 		t = strtok(tok, ",");
 		while (t != NULL) {
 			n = (int) strtol(t, (char **) NULL, 10);
-			if ((*avail)[n] == NULL) {
-				(*avail)[n] = talloc_array(ctx, struct ctdb_all_public_ips, CTDB_TEST_MAX_IPS);
-				(*avail)[n]->num = 0;
+			if ((*known)[n] == NULL) {
+				/* Array size here has to be
+				 * CTDB_TEST_MAX_IPS because total
+				 * number of IPs isn't yet known */
+				(*known)[n] = talloc_size(ctx,
+							  offsetof(struct ctdb_public_ip_list_old, ips) +
+							  CTDB_TEST_MAX_IPS * sizeof(struct ctdb_public_ip));
+				(*known)[n]->num = 0;
 			}
-			curr = (*avail)[n]->num;
-			(*avail)[n]->ips[curr].pnn = pnn;
-			memcpy(&((*avail)[n]->ips[curr].addr),
+			curr = (*known)[n]->num;
+			(*known)[n]->ips[curr].pnn = pnn;
+			memcpy(&((*known)[n]->ips[curr].addr),
 			       &addr, sizeof(addr));
-			(*avail)[n]->num++;
+			(*known)[n]->num++;
 			t = strtok(NULL, ",");
 		}
 
 	}
 
 	/* Build list of all allowed IPs */
-	a = talloc_array(ctx, struct ctdb_all_public_ips, CTDB_TEST_MAX_IPS);
+	a = talloc_size(ctx,
+			offsetof(struct ctdb_public_ip_list_old, ips) +
+			numips * sizeof(struct ctdb_public_ip));
 	a->num = numips;
 	for (ta = *all_ips, i=0; ta != NULL && i < numips ; ta = ta->next, i++) {
 		a->ips[i].pnn = ta->pnn;
@@ -204,8 +226,11 @@ read_ctdb_public_ip_info(TALLOC_CTX *ctx,
 
 	/* Assign it to any nodes that don't have a list assigned */
 	for (n = 0; n < numnodes; n++) {
-		if ((*avail)[n] == NULL) {
-			(*avail)[n] = a;
+		if ((*known)[n] == NULL) {
+			(*known)[n] = a;
+		}
+		if (runstate[n] == CTDB_RUNSTATE_RUNNING) {
+			(*avail)[n] = (*known)[n];
 		}
 	}
 
@@ -213,7 +238,7 @@ read_ctdb_public_ip_info(TALLOC_CTX *ctx,
 }
 
 static void print_ctdb_available_ips(int numnodes,
-				     struct ctdb_all_public_ips **avail)
+				     struct ctdb_public_ip_list_old **avail)
 {
 	int n, i;
 
@@ -233,8 +258,9 @@ static void print_ctdb_available_ips(int numnodes,
 static void ctdb_test_read_ctdb_public_ip_info(const char nodestates[])
 {
 	int numnodes;
-	struct ctdb_public_ip_list *l;
-	struct ctdb_all_public_ips **avail;
+	struct public_ip_list *l;
+	struct ctdb_public_ip_list_old **known;
+	struct ctdb_public_ip_list_old **avail;
 	char *tok, *ns;
 
 	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
@@ -253,7 +279,7 @@ static void ctdb_test_read_ctdb_public_ip_info(const char nodestates[])
 		tok = strtok(NULL, ",");
 	}
 	
-	read_ctdb_public_ip_info(tmp_ctx, numnodes, &l, &avail);
+	read_ctdb_public_ip_info(tmp_ctx, numnodes, &l, &known, &avail);
 
 	print_ctdb_public_ip_list(l);
 	print_ctdb_available_ips(numnodes, avail);
@@ -264,7 +290,7 @@ static void ctdb_test_read_ctdb_public_ip_info(const char nodestates[])
 /* Read 2 IPs from stdin, calculate the IP distance and print it. */
 static void ctdb_test_ip_distance(void)
 {
-	struct ctdb_public_ip_list *l;
+	struct public_ip_list *l;
 	uint32_t distance;
 
 	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
@@ -284,8 +310,8 @@ static void ctdb_test_ip_distance(void)
  * the given node. The given IP must one of the ones in the list.  */
 static void ctdb_test_ip_distance_2_sum(const char ip[], int pnn)
 {
-	struct ctdb_public_ip_list *l;
-	struct ctdb_public_ip_list *t;
+	struct public_ip_list *l;
+	struct public_ip_list *t;
 	ctdb_sock_addr addr;
 	uint32_t distance;
 
@@ -317,11 +343,11 @@ static void ctdb_test_ip_distance_2_sum(const char ip[], int pnn)
 	talloc_free(tmp_ctx);
 }
 
-/* Read some IPs from stdin, calculate the sume of the squares of the
+/* Read some IPs from stdin, calculate the sum of the squares of the
  * IP distances between the first and the rest, and print it. */
 static void ctdb_test_lcp2_imbalance(int pnn)
 {
-	struct ctdb_public_ip_list *l;
+	struct public_ip_list *l;
 	uint32_t imbalance;
 
 	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
@@ -404,22 +430,22 @@ static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
  * by a blank line.  This mode is for testing weird behaviours where
  * the IP layouts differs across nodes and we want to improve
  * create_merged_ip_list(), so should only be used in tests of
- * ctdb_takeover_run_core().  Yes, it is a hack...  :-)
+ * ipalloc().  Yes, it is a hack...  :-)
  */
 static void ctdb_test_init(const char nodestates[],
 			   struct ctdb_context **ctdb,
-			   struct ctdb_public_ip_list **all_ips,
-			   struct ctdb_ipflags **ipflags,
+			   struct ipalloc_state **ipalloc_state,
 			   bool read_ips_for_multiple_nodes)
 {
-	struct ctdb_all_public_ips **avail;
+	struct ctdb_public_ip_list_old **known;
+	struct ctdb_public_ip_list_old **avail;
 	int i, numnodes;
 	uint32_t nodeflags[CTDB_TEST_MAX_NODES];
 	char *tok, *ns, *t;
-	struct ctdb_node_map *nodemap;
+	struct ctdb_node_map_old *nodemap;
 	uint32_t *tval_noiptakeover;
 	uint32_t *tval_noiptakeoverondisabled;
-	enum ctdb_runstate *runstate;
+	struct public_ip_list *all_ips;
 
 	*ctdb = talloc_zero(NULL, struct ctdb_context);
 
@@ -467,17 +493,18 @@ static void ctdb_test_init(const char nodestates[],
 		get_tunable_values(*ctdb, numnodes,
 				   "CTDB_SET_NoIPHostOnAllDisabled");
 
-	runstate = get_runstate(*ctdb, numnodes);
-
-	nodemap =  talloc_array(*ctdb, struct ctdb_node_map, numnodes);
+	nodemap =  talloc_array(*ctdb, struct ctdb_node_map_old, numnodes);
 	nodemap->num = numnodes;
 
 	if (!read_ips_for_multiple_nodes) {
-		read_ctdb_public_ip_info(*ctdb, numnodes, all_ips, &avail);
+		read_ctdb_public_ip_info(*ctdb, numnodes,
+					 &all_ips, &known, &avail);
 	}
 
 	(*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
 
+	*ipalloc_state = ipalloc_state_init(*ctdb, *ctdb);
+
 	for (i=0; i < numnodes; i++) {
 		nodemap->nodes[i].pnn = i;
 		nodemap->nodes[i].flags = nodeflags[i];
@@ -485,41 +512,43 @@ static void ctdb_test_init(const char nodestates[],
 
 		if (read_ips_for_multiple_nodes) {
 			read_ctdb_public_ip_info(*ctdb, numnodes,
-						 all_ips, &avail);
+						 &all_ips, &known, &avail);
 		}
 
 		(*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
 		(*ctdb)->nodes[i]->pnn = i;
 		(*ctdb)->nodes[i]->flags = nodeflags[i];
-		(*ctdb)->nodes[i]->available_public_ips = avail[i];
-		(*ctdb)->nodes[i]->known_public_ips = avail[i];
+
+		(*ipalloc_state)->available_public_ips[i] = avail[i];
+		(*ipalloc_state)->known_public_ips[i] = known[i];
 	}
 
-	*ipflags = set_ipflags_internal(*ctdb, *ctdb, nodemap,
-					tval_noiptakeover,
-					tval_noiptakeoverondisabled,
-					runstate);
+	set_ipflags_internal(*ipalloc_state, nodemap,
+			     tval_noiptakeover,
+			     tval_noiptakeoverondisabled);
+
+	(*ipalloc_state)->all_ips = create_merged_ip_list(*ctdb,
+							  *ipalloc_state);
+
+	(*ipalloc_state)->force_rebalance_nodes = NULL;
 }
 
 /* IP layout is read from stdin. */
 static void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
 {
 	struct ctdb_context *ctdb;
-	struct ctdb_public_ip_list *all_ips;
-	struct ctdb_ipflags *ipflags;
+	struct ipalloc_state *ipalloc_state;
 
 	uint32_t *lcp2_imbalances;
 	bool *newly_healthy;
 
-	ctdb_test_init(nodestates, &ctdb, &all_ips, &ipflags, false);
+	ctdb_test_init(nodestates, &ctdb, &ipalloc_state, false);
 
-	lcp2_init(ctdb, ipflags, all_ips, NULL,
-		  &lcp2_imbalances, &newly_healthy);
+	lcp2_init(ipalloc_state, &lcp2_imbalances, &newly_healthy);
 
-	lcp2_allocate_unassigned(ctdb, ipflags,
-				 all_ips, lcp2_imbalances);
+	lcp2_allocate_unassigned(ipalloc_state, lcp2_imbalances);
 
-	print_ctdb_public_ip_list(all_ips);
+	print_ctdb_public_ip_list(ipalloc_state->all_ips);
 
 	talloc_free(ctdb);
 }
@@ -528,21 +557,18 @@ static void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
 static void ctdb_test_lcp2_failback(const char nodestates[])
 {
 	struct ctdb_context *ctdb;
-	struct ctdb_public_ip_list *all_ips;
-	struct ctdb_ipflags *ipflags;
+	struct ipalloc_state *ipalloc_state;
 
 	uint32_t *lcp2_imbalances;
 	bool *newly_healthy;
 
-	ctdb_test_init(nodestates, &ctdb, &all_ips, &ipflags, false);
+	ctdb_test_init(nodestates, &ctdb, &ipalloc_state, false);
 
-	lcp2_init(ctdb, ipflags, all_ips, NULL,
-		  &lcp2_imbalances, &newly_healthy);
+	lcp2_init(ipalloc_state, &lcp2_imbalances, &newly_healthy);
 
-	lcp2_failback(ctdb, ipflags,
-		      all_ips, lcp2_imbalances, newly_healthy);
+	lcp2_failback(ipalloc_state, lcp2_imbalances, newly_healthy);
 
-	print_ctdb_public_ip_list(all_ips);
+	print_ctdb_public_ip_list(ipalloc_state->all_ips);
 
 	talloc_free(ctdb);
 }
@@ -551,21 +577,18 @@ static void ctdb_test_lcp2_failback(const char nodestates[])
 static void ctdb_test_lcp2_failback_loop(const char nodestates[])
 {
 	struct ctdb_context *ctdb;
-	struct ctdb_public_ip_list *all_ips;
-	struct ctdb_ipflags *ipflags;
+	struct ipalloc_state *ipalloc_state;
 
 	uint32_t *lcp2_imbalances;
 	bool *newly_healthy;
 
-	ctdb_test_init(nodestates, &ctdb, &all_ips, &ipflags, false);
+	ctdb_test_init(nodestates, &ctdb, &ipalloc_state, false);
 
-	lcp2_init(ctdb, ipflags, all_ips, NULL,
-		  &lcp2_imbalances, &newly_healthy);
+	lcp2_init(ipalloc_state, &lcp2_imbalances, &newly_healthy);
 
-	lcp2_failback(ctdb, ipflags,
-		      all_ips, lcp2_imbalances, newly_healthy);
+	lcp2_failback(ipalloc_state, lcp2_imbalances, newly_healthy);
 
-	print_ctdb_public_ip_list(all_ips);
+	print_ctdb_public_ip_list(ipalloc_state->all_ips);
 
 	talloc_free(ctdb);
 }
@@ -573,19 +596,18 @@ static void ctdb_test_lcp2_failback_loop(const char nodestates[])
 /* IP layout is read from stdin.  See comment for ctdb_test_init() for
  * explanation of read_ips_for_multiple_nodes.
  */
-static void ctdb_test_ctdb_takeover_run_core(const char nodestates[],
-					     bool read_ips_for_multiple_nodes)
+static void ctdb_test_ipalloc(const char nodestates[],
+			      bool read_ips_for_multiple_nodes)
 {
 	struct ctdb_context *ctdb;
-	struct ctdb_public_ip_list *all_ips;
-	struct ctdb_ipflags *ipflags;
+	struct ipalloc_state *ipalloc_state;
 
-	ctdb_test_init(nodestates, &ctdb, &all_ips, &ipflags,
+	ctdb_test_init(nodestates, &ctdb, &ipalloc_state,
 		       read_ips_for_multiple_nodes);
 
-	ctdb_takeover_run_core(ctdb, ipflags, &all_ips, NULL);
+	ipalloc(ipalloc_state);
 
-	print_ctdb_public_ip_list(all_ips);
+	print_ctdb_public_ip_list(ipalloc_state->all_ips);
 
 	talloc_free(ctdb);
 }
@@ -624,12 +646,12 @@ int main(int argc, const char *argv[])
 	} else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) {
 		ctdb_test_lcp2_failback_loop(argv[2]);
 	} else if (argc == 3 &&
-		   strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
-		ctdb_test_ctdb_takeover_run_core(argv[2], false);
+		   strcmp(argv[1], "ipalloc") == 0) {
+		ctdb_test_ipalloc(argv[2], false);
 	} else if (argc == 4 &&
-		   strcmp(argv[1], "ctdb_takeover_run_core") == 0 &&
+		   strcmp(argv[1], "ipalloc") == 0 &&
 		   strcmp(argv[3], "multi") == 0) {
-		ctdb_test_ctdb_takeover_run_core(argv[2], true);
+		ctdb_test_ipalloc(argv[2], true);
 	} else {
 		usage();
 	}
diff --git a/ctdb/tests/src/ctdb_test.c b/ctdb/tests/src/ctdb_test.c
index 38f5a06..310a4c7 100644
--- a/ctdb/tests/src/ctdb_test.c
+++ b/ctdb/tests/src/ctdb_test.c
@@ -106,15 +106,15 @@ struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx);
 
 int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb,
 		    struct timeval timeout, uint32_t destnode,
-		    TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap);
+		    TALLOC_CTX *mem_ctx, struct ctdb_node_map_old **nodemap);
 int ctdb_ctrl_getnodesfile(struct ctdb_context *ctdb,
 			   struct timeval timeout, uint32_t destnode,
 			   TALLOC_CTX *mem_ctx,
-			   struct ctdb_node_map **nodemap);
+			   struct ctdb_node_map_old **nodemap);
 int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
 			 struct timeval timeout, uint32_t destnode,
 			 TALLOC_CTX *mem_ctx,
-			 struct ctdb_control_get_ifaces **ifaces);
+			 struct ctdb_iface_list_old **ifaces);
 int ctdb_ctrl_getpnn(struct ctdb_context *ctdb, struct timeval timeout,
 		     uint32_t destnode);
 int ctdb_ctrl_getrecmode(struct ctdb_context *ctdb,
@@ -132,7 +132,7 @@ int ctdb_ctrl_getdbseqnum(struct ctdb_context *ctdb, struct timeval timeout,
 			  uint32_t destnode, uint32_t dbid, uint64_t *seqnum);
 int ctdb_client_set_message_handler(struct ctdb_context *ctdb,
 				    uint64_t srvid,
-				    ctdb_msg_fn_t handler,
+				    srvid_handler_fn handler,
 				    void *private_data);
 int ctdb_client_remove_message_handler(struct ctdb_context *ctdb,
 				       uint64_t srvid,
@@ -164,21 +164,19 @@ struct ctdb_node_capabilities *
 ctdb_get_capabilities(struct ctdb_context *ctdb,
 		      TALLOC_CTX *mem_ctx,
 		      struct timeval timeout,
-		      struct ctdb_node_map *nodemap);
+		      struct ctdb_node_map_old *nodemap);
 
 #undef TIMELIMIT
-#include "tools/ctdb_vacuum.c"
 
 /* CTDB_COMMON_OBJ */
 #include "common/ctdb_io.c"
 #include "common/ctdb_util.c"
 #include "common/ctdb_ltdb.c"
-#include "common/ctdb_message.c"
+#include "common/db_hash.c"
+#include "common/srvid.c"
 #include "common/rb_tree.c"
-#include "common/system_common.c"
-#include "common/ctdb_logging.c"
-#include "common/ctdb_fork.c"
-#include "common/system_util.c"
+#include "common/reqid.c"
+#include "common/logging.c"
 
 /* CTDB_CLIENT_OBJ */
 #include "client/ctdb_client.c"
diff --git a/ctdb/tests/src/ctdb_test_stubs.c b/ctdb/tests/src/ctdb_test_stubs.c
index 93516fd..83ba398 100644
--- a/ctdb/tests/src/ctdb_test_stubs.c
+++ b/ctdb/tests/src/ctdb_test_stubs.c
@@ -27,7 +27,7 @@ static struct ctdb_node_capabilities *global_caps = NULL;
  * EOF or a blank line terminates input.
  *
  * By default, capablities for each node are
- * CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER|CTDB_CAP_NATGW.  These 3
+ * CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER.  These 2
  * capabilities can be faked off by adding, for example,
  * -CTDB_CAP_RECMASTER.  LVS can be faked on by adding
  * CTDB_CAP_LVS.
@@ -90,7 +90,7 @@ static void ctdb_test_stubs_read_nodemap(struct ctdb_context *ctdb)
 			talloc_free(ip);
 			ip = talloc_strdup(ctdb, "0.0.0.0");
 		}
-		capabilities = CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER|CTDB_CAP_NATGW;
+		capabilities = CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER;
 
 		tok = strtok(NULL, " \t");
 		while (tok != NULL) {
@@ -102,8 +102,6 @@ static void ctdb_test_stubs_read_nodemap(struct ctdb_context *ctdb)
 				capabilities &= ~CTDB_CAP_RECMASTER;
 			} else if (strcmp(tok, "-CTDB_CAP_LMASTER") == 0) {
 				capabilities &= ~CTDB_CAP_LMASTER;
-			} else if (strcmp(tok, "-CTDB_CAP_NATGW") == 0) {
-				capabilities &= ~CTDB_CAP_NATGW;
 			} else if (strcmp(tok, "CTDB_CAP_LVS") == 0) {
 				capabilities |= CTDB_CAP_LVS;
 			} else if (strcmp(tok, "TIMEOUT") == 0) {
@@ -175,8 +173,8 @@ static void ctdb_test_stubs_print_nodemap(struct ctdb_context *ctdb)
  *   :eth1:1:4294967292
  */
 
-struct ctdb_iface {
-	struct ctdb_iface *prev, *next;
+struct ctdb_interface {
+	struct ctdb_interface *prev, *next;
 	const char *name;
 	bool link_up;
 	uint32_t references;
@@ -185,7 +183,7 @@ struct ctdb_iface {
 static void ctdb_test_stubs_read_ifaces(struct ctdb_context *ctdb)
 {
 	char line[1024];
-	struct ctdb_iface *iface;
+	struct ctdb_interface *iface;
 
 	while ((fgets(line, sizeof(line), stdin) != NULL) &&
 	       (line[0] != '\n')) {
@@ -227,7 +225,7 @@ static void ctdb_test_stubs_read_ifaces(struct ctdb_context *ctdb)
 		}
 		references = (uint32_t)strtoul(tok, NULL, 0);
 
-		iface = talloc_zero(ctdb, struct ctdb_iface);
+		iface = talloc_zero(ctdb, struct ctdb_interface);
 
 		if (iface == NULL) {
 			DEBUG(DEBUG_ERR, ("OOM allocating iface\n"));
@@ -253,7 +251,7 @@ static void assert_ifaces_set(struct ctdb_context *ctdb)
 #ifdef CTDB_TEST_OVERRIDE_MAIN
 static void ctdb_test_stubs_print_ifaces(struct ctdb_context *ctdb)
 {
-	struct ctdb_iface *iface;
+	struct ctdb_interface *iface;
 
 	assert_ifaces_set(ctdb);
 
@@ -433,7 +431,7 @@ int
 ctdb_ctrl_getnodemap_stub(struct ctdb_context *ctdb,
 			  struct timeval timeout, uint32_t destnode,
 			  TALLOC_CTX *mem_ctx,
-			  struct ctdb_node_map **nodemap)
+			  struct ctdb_node_map_old **nodemap)
 {
 	assert_nodes_set(ctdb);
 
@@ -450,7 +448,7 @@ ctdb_ctrl_getnodemap_stub(struct ctdb_context *ctdb,
 int
 ctdb_ctrl_getnodesfile_stub(struct ctdb_context *ctdb,
 			    struct timeval timeout, uint32_t destnode,
-			    TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap)
+			    TALLOC_CTX *mem_ctx, struct ctdb_node_map_old **nodemap)
 {
 	char *v, *f;
 
@@ -540,12 +538,12 @@ ctdb_ctrl_getpnn_stub(struct ctdb_context *ctdb, struct timeval timeout,
 
 /* From ctdb_takeover.c */
 int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
-				struct ctdb_req_control *c,
+				struct ctdb_req_control_old *c,
 				TDB_DATA *outdata)
 {
 	int i, num, len;
-	struct ctdb_control_get_ifaces *ifaces;
-	struct ctdb_iface *cur;
+	struct ctdb_iface_list_old *ifaces;
+	struct ctdb_interface *cur;
 
 	assert_ifaces_set(ctdb);
 
@@ -555,8 +553,8 @@ int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
 		num++;
 	}
 
-	len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
-		num*sizeof(struct ctdb_control_iface_info);
+	len = offsetof(struct ctdb_iface_list_old, ifaces) +
+		num*sizeof(struct ctdb_iface);
 	ifaces = talloc_zero_size(outdata, len);
 	CTDB_NO_MEMORY(ctdb, ifaces);
 
@@ -573,8 +571,8 @@ int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
 		i++;
 	}
 	ifaces->num = i;
-	len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
-		i*sizeof(struct ctdb_control_iface_info);
+	len = offsetof(struct ctdb_iface_list_old, ifaces) +
+		i*sizeof(struct ctdb_iface);
 
 	outdata->dsize = len;
 	outdata->dptr  = (uint8_t *)ifaces;
@@ -586,7 +584,7 @@ int
 ctdb_ctrl_get_ifaces_stub(struct ctdb_context *ctdb,
 			  struct timeval timeout, uint32_t destnode,
 			  TALLOC_CTX *mem_ctx,
-			  struct ctdb_control_get_ifaces **ifaces)
+			  struct ctdb_iface_list_old **ifaces)
 {
 	TDB_DATA *outdata;
 	int ret;
@@ -600,7 +598,7 @@ ctdb_ctrl_get_ifaces_stub(struct ctdb_context *ctdb,
 	ret = ctdb_control_get_ifaces(ctdb, NULL, outdata);
 
 	if (ret == 0) {
-		*ifaces = (struct ctdb_control_get_ifaces *)outdata->dptr;
+		*ifaces = (struct ctdb_iface_list_old *)outdata->dptr;
 	}
 
 	return ret;
@@ -610,7 +608,7 @@ ctdb_ctrl_get_ifaces_stub(struct ctdb_context *ctdb,
  * the ctdb tool only registers one at a time so keep this simple. */
 static struct {
 	uint64_t srvid;
-	ctdb_msg_fn_t message_handler;
+	srvid_handler_fn message_handler;
 	void *message_private;
 } ctdb_message_list_fake = {
 	.srvid = 0,
@@ -620,7 +618,7 @@ static struct {
 
 int ctdb_client_set_message_handler_stub(struct ctdb_context *ctdb,
 					 uint64_t srvid,
-					 ctdb_msg_fn_t handler,
+					 srvid_handler_fn handler,
 					 void *private_data)
 {
 	ctdb_message_list_fake.srvid = srvid;
@@ -649,7 +647,6 @@ static void ctdb_fake_handler_pnn_reply(struct ctdb_context *ctdb,
 	reply_data.dsize = sizeof(pnn);
 	reply_data.dptr = (uint8_t *)&pnn;
 	ctdb_message_list_fake.message_handler(
-		ctdb,
 		ctdb_message_list_fake.srvid,
 		reply_data,
 		ctdb_message_list_fake.message_private);
@@ -825,7 +822,7 @@ ctdb_client_async_control_stub(struct ctdb_context *ctdb,
 			res = 0;
 			break;
 		case CTDB_CONTROL_GET_NODES_FILE: {
-			struct ctdb_node_map *nodemap;
+			struct ctdb_node_map_old *nodemap;
 			res = ctdb_ctrl_getnodesfile_stub(ctdb, timeout, pnn,
 							  tmp_ctx, &nodemap);
 			if (res == 0) {
@@ -861,7 +858,7 @@ struct ctdb_node_capabilities *
 ctdb_get_capabilities_stub(struct ctdb_context *ctdb,
 			   TALLOC_CTX *mem_ctx,
 			   struct timeval timeout,
-			   struct ctdb_node_map *nodemap)
+			   struct ctdb_node_map_old *nodemap)
 {
 	return global_caps;
 }
diff --git a/ctdb/tests/src/ctdb_trackingdb_test.c b/ctdb/tests/src/ctdb_trackingdb_test.c
index 18bc174..0e0471c 100644
--- a/ctdb/tests/src/ctdb_trackingdb_test.c
+++ b/ctdb/tests/src/ctdb_trackingdb_test.c
@@ -22,13 +22,22 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
 #include "system/time.h"
-#include "popt.h"
-#include "cmdline.h"
-#include "ctdb_private.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
 
 #define MAXINDEX 64
 char indices[MAXINDEX];
@@ -102,7 +111,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
 
@@ -122,7 +131,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(5, 0));
 	if (ctdb == NULL) {
diff --git a/ctdb/tests/src/ctdb_transaction.c b/ctdb/tests/src/ctdb_transaction.c
index 78a63f1..4cc48f5 100644
--- a/ctdb/tests/src/ctdb_transaction.c
+++ b/ctdb/tests/src/ctdb_transaction.c
@@ -19,13 +19,23 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
 
-#include <sys/time.h>
-#include <time.h>
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 static struct timeval tp1,tp2;
 
@@ -64,14 +74,14 @@ static void print_counters(void)
 	printf("\n");
 }
 
-static void each_second(struct event_context *ev, struct timed_event *te,
-					 struct timeval t, void *private_data)
+static void each_second(struct tevent_context *ev, struct tevent_timer *te,
+			struct timeval t, void *private_data)
 {
 	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
 
 	print_counters();
 
-	event_add_timed(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+	tevent_add_timer(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
 }
 
 static void check_counters(struct ctdb_context *ctdb, TDB_DATA data)
@@ -114,7 +124,8 @@ static void do_sleep(unsigned int sec)
 	if (verbose) printf("\n");
 }
 
-static void test_store_records(struct ctdb_context *ctdb, struct event_context *ev)
+static void test_store_records(struct ctdb_context *ctdb,
+			       struct tevent_context *ev)
 {
 	TDB_DATA key;
 	struct ctdb_db_context *ctdb_db;
@@ -223,7 +234,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	if (verbose) {
 		setbuf(stdout, (char *)NULL); /* don't buffer */
@@ -249,7 +260,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
 	if (ctdb == NULL) {
@@ -276,14 +287,15 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 	pnn = ctdb_get_pnn(ctdb);
 	printf("Starting test on node %u. running for %u seconds. sleep delay: %u seconds.\n", pnn, timelimit, delay);
 
 	if (!verbose && (pnn == 0)) {
-		event_add_timed(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+		tevent_add_timer(ev, ctdb, timeval_current_ofs(1, 0),
+				 each_second, ctdb);
 	}
 
 	test_store_records(ctdb, ev);
diff --git a/ctdb/tests/src/ctdb_traverse.c b/ctdb/tests/src/ctdb_traverse.c
index 5b37ed9..d69c8e0 100644
--- a/ctdb/tests/src/ctdb_traverse.c
+++ b/ctdb/tests/src/ctdb_traverse.c
@@ -18,25 +18,36 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
 
-#include <sys/time.h>
-#include <time.h>
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
 
 static const char *dbname = "test.tdb";
 
-static int traverse_callback(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *private_data)
+static int traverse_callback(TDB_DATA key, TDB_DATA data, void *private_data)
 {
 	uint32_t *count = private_data;
-	
+
 	(*count)++;
 	return 0;
 }
 
-static void traverse_loop(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, struct event_context *ev)
+static void traverse_loop(struct ctdb_context *ctdb,
+			  struct ctdb_db_context *ctdb_db,
+			  struct tevent_context *ev)
 {
 	uint32_t count;
 
@@ -64,7 +75,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
 
@@ -86,7 +97,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
 	if (ctdb == NULL) {
@@ -105,7 +116,7 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 	while (1) {
diff --git a/ctdb/tests/src/ctdb_update_record.c b/ctdb/tests/src/ctdb_update_record.c
index 78d983b..7b5b544 100644
--- a/ctdb/tests/src/ctdb_update_record.c
+++ b/ctdb/tests/src/ctdb_update_record.c
@@ -18,11 +18,21 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/time.h"
+
 #include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
 
 static struct ctdb_db_context *ctdb_db;
 
@@ -32,7 +42,8 @@ static struct ctdb_db_context *ctdb_db;
 /*
 	Just try locking/unlocking a single record once
 */
-static void fetch_lock_once(struct ctdb_context *ctdb, struct event_context *ev, uint32_t generation)
+static void fetch_lock_once(struct ctdb_context *ctdb,
+			    struct tevent_context *ev, uint32_t generation)
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	TDB_DATA key, data;
@@ -104,7 +115,7 @@ int main(int argc, const char *argv[])
 	const char **extra_argv;
 	int extra_argc = 0;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 	struct ctdb_vnn_map *vnnmap=NULL;
 
 	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
@@ -125,7 +136,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(5, 0));
 	if (ctdb == NULL) {
@@ -144,7 +155,7 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 
diff --git a/ctdb/tests/src/ctdb_update_record_persistent.c b/ctdb/tests/src/ctdb_update_record_persistent.c
index d73636e..10dc54b 100644
--- a/ctdb/tests/src/ctdb_update_record_persistent.c
+++ b/ctdb/tests/src/ctdb_update_record_persistent.c
@@ -18,15 +18,27 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "lib/tdb_wrap/tdb_wrap.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/time.h"
+
 #include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/common.h"
 
 
-static void update_once(struct ctdb_context *ctdb, struct event_context *ev, struct ctdb_db_context *ctdb_db, char *record, char *value)
+static void update_once(struct ctdb_context *ctdb, struct tevent_context *ev,
+			struct ctdb_db_context *ctdb_db, char *record,
+			char *value)
 {
 	TDB_DATA key, data, olddata;
 	struct ctdb_ltdb_header header;
@@ -61,7 +73,7 @@ int main(int argc, const char *argv[])
 	char *record = NULL;
 	char *value = NULL;
 	struct ctdb_db_context *ctdb_db;
-	struct event_context *ev;
+	struct tevent_context *ev;
 
 	struct poptOption popt_options[] = {
 		POPT_AUTOHELP
@@ -95,7 +107,7 @@ int main(int argc, const char *argv[])
 		while (extra_argv[extra_argc]) extra_argc++;
 	}
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 
 	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(5, 0));
 	if (ctdb == NULL) {
@@ -129,7 +141,7 @@ int main(int argc, const char *argv[])
 		uint32_t recmode=1;
 		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
 		if (recmode == 0) break;
-		event_loop_once(ev);
+		tevent_loop_once(ev);
 	}
 
 	update_once(ctdb, ev, ctdb_db, record, value);
diff --git a/ctdb/tests/src/ctdbd_test.c b/ctdb/tests/src/ctdbd_test.c
index b62429e..018aa2a 100644
--- a/ctdb/tests/src/ctdbd_test.c
+++ b/ctdb/tests/src/ctdbd_test.c
@@ -20,8 +20,14 @@
 #ifndef _CTDBD_TEST_C
 #define _CTDBD_TEST_C
 
-#include "includes.h"
-#include "tdb.h"
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+/* Allow use of deprecated function tevent_loop_allow_nesting() */
+#define TEVENT_DEPRECATED
+#include <tevent.h>
+
 #include "ctdb_private.h"
 
 /*
@@ -35,13 +41,12 @@ bool fast_start;
 #include "common/ctdb_io.c"
 #include "common/ctdb_util.c"
 #include "common/ctdb_ltdb.c"
-#include "common/ctdb_message.c"
+#include "common/db_hash.c"
+#include "common/srvid.c"
 #include "common/cmdline.c"
 #include "common/rb_tree.c"
-#include "common/system_common.c"
-#include "common/ctdb_logging.c"
-#include "common/ctdb_fork.c"
-#include "common/system_util.c"
+#include "common/reqid.c"
+#include "common/logging.c"
 
 /* CTDB_SERVER_OBJ */
 #include "server/ctdb_daemon.c"
@@ -56,6 +61,11 @@ bool fast_start;
 #include "server/ctdb_ltdb_server.c"
 #include "server/ctdb_traverse.c"
 #include "server/eventscript.c"
+#include "server/ipalloc_common.c"
+#include "server/ipalloc_deterministic.c"
+#include "server/ipalloc_nondeterministic.c"
+#include "server/ipalloc_lcp2.c"
+#include "server/ipalloc.c"
 #include "server/ctdb_takeover.c"
 #include "server/ctdb_serverids.c"
 #include "server/ctdb_persistent.c"
@@ -69,6 +79,7 @@ bool fast_start;
 #include "server/ctdb_statistics.c"
 #include "server/ctdb_update_record.c"
 #include "server/ctdb_lock.c"
+#include "server/ctdb_fork.c"
 
 /* CTDB_CLIENT_OBJ */
 #include "client/ctdb_client.c"
diff --git a/ctdb/tests/src/db_hash_test.c b/ctdb/tests/src/db_hash_test.c
new file mode 100644
index 0000000..cc8a689
--- /dev/null
+++ b/ctdb/tests/src/db_hash_test.c
@@ -0,0 +1,101 @@
+/*
+   db_hash tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include <assert.h>
+
+#include "common/db_hash.c"
+
+static void do_test(enum db_hash_type type)
+{
+	struct db_hash_context *dh;
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	uint8_t key[] = "This is a long key";
+	uint8_t value[] = "This is a long value";
+	int ret;
+
+	ret = db_hash_init(mem_ctx, "foobar", 1024, type, &dh);
+	assert(ret == 0);
+
+	ret = db_hash_insert(dh, key, sizeof(key), value, sizeof(value));
+	assert(ret == 0);
+
+	ret = db_hash_exists(dh, key, sizeof(key));
+	assert(ret == 0);
+
+	ret = db_hash_insert(dh, key, sizeof(key), value, sizeof(value));
+	assert(ret == EEXIST);
+
+	ret = db_hash_delete(dh, key, sizeof(key));
+	assert(ret == 0);
+
+	ret = db_hash_exists(dh, key, sizeof(key));
+	assert(ret == ENOENT);
+
+	ret = db_hash_delete(dh, key, sizeof(key));
+	assert(ret == ENOENT);
+
+	ret = db_hash_add(dh, key, sizeof(key), key, sizeof(key));
+	assert(ret == 0);
+
+	ret = db_hash_add(dh, key, sizeof(key), value, sizeof(value));
+	assert(ret == 0);
+
+	talloc_free(dh);
+	ret = talloc_get_size(mem_ctx);
+	assert(ret == 0);
+
+	talloc_free(mem_ctx);
+}
+
+static void do_traverse_test(enum db_hash_type type)
+{
+	struct db_hash_context *dh;
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	char key[] = "keyXXXX";
+	char value[] = "This is some test value";
+	int count, ret, i;
+
+	ret = db_hash_init(mem_ctx, "foobar", 1024, type, &dh);
+	assert(ret == 0);
+
+	for (i=0; i<2000; i++) {
+		sprintf(key, "key%04d", i);
+		ret = db_hash_insert(dh, (uint8_t *)key, sizeof(key),
+				     (uint8_t *)value, sizeof(value));
+		assert(ret == 0);
+	}
+
+	ret = db_hash_traverse(dh, NULL, NULL, &count);
+	assert(ret == 0);
+	assert(count == 2000);
+
+	talloc_free(dh);
+	talloc_free(mem_ctx);
+}
+
+int main(void)
+{
+	do_test(DB_HASH_SIMPLE);
+	do_test(DB_HASH_COMPLEX);
+	do_traverse_test(DB_HASH_SIMPLE);
+	do_traverse_test(DB_HASH_COMPLEX);
+	return 0;
+}
diff --git a/ctdb/tests/src/pkt_read_test.c b/ctdb/tests/src/pkt_read_test.c
new file mode 100644
index 0000000..7e089ec
--- /dev/null
+++ b/ctdb/tests/src/pkt_read_test.c
@@ -0,0 +1,242 @@
+/*
+   packet read tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+
+#include <assert.h>
+
+#include "common/pkt_read.c"
+
+static void writer(int fd)
+{
+	uint8_t buf[1024*1024];
+	size_t buflen;
+	size_t pkt_size[4] = { 100, 500, 1024, 1024*1024 };
+	int i, j;
+	int ret;
+
+	for (i=0; i<1024*1024; i++) {
+		buf[i] = i%256;
+	}
+
+	for (i=0; i<1000; i++) {
+		for (j=0; j<4; j++) {
+			buflen = pkt_size[j];
+			memcpy(buf, &buflen, sizeof(buflen));
+
+			ret = write(fd, buf, buflen);
+			if (ret < 0) {
+				printf("write error: %s\n", strerror(errno));
+				assert(ret > 0);
+			}
+		}
+	}
+
+	close(fd);
+}
+
+struct reader_state {
+	struct tevent_context *ev;
+	int fd;
+	uint8_t buf[1024];
+	struct tevent_req *subreq;
+};
+
+static ssize_t reader_more(uint8_t *buf, size_t buflen, void *private_data);
+static void reader_done(struct tevent_req *subreq);
+
+static struct tevent_req *reader_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      int fd)
+{
+	struct tevent_req *req, *subreq;
+	struct reader_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct reader_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->fd = fd;
+
+	subreq = pkt_read_send(state, state->ev, state->fd, 4,
+			       state->buf, 1024, reader_more, NULL);
+	if (tevent_req_nomem(subreq, req)) {
+		tevent_req_post(req, ev);
+	}
+
+	state->subreq = subreq;
+	tevent_req_set_callback(subreq, reader_done, req);
+	return req;
+}
+
+static ssize_t reader_more(uint8_t *buf, size_t buflen, void *private_data)
+{
+	uint32_t pkt_len;
+
+	if (buflen < sizeof(pkt_len)) {
+		return sizeof(pkt_len) - buflen;
+	}
+
+	pkt_len = *(uint32_t *)buf;
+	return pkt_len - buflen;
+}
+
+static void reader_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct reader_state *state = tevent_req_data(
+		req, struct reader_state);
+	ssize_t nread;
+	uint8_t *buf;
+	bool free_buf;
+	int err;
+
+	nread = pkt_read_recv(subreq, state, &buf, &free_buf, &err);
+	TALLOC_FREE(subreq);
+	state->subreq = NULL;
+	if (nread == -1) {
+		if (err == EPIPE) {
+			tevent_req_done(req);
+		} else {
+			tevent_req_error(req, err);
+		}
+		return;
+	}
+
+	if (free_buf) {
+		talloc_free(buf);
+	}
+
+	subreq = pkt_read_send(state, state->ev, state->fd, 4,
+			       state->buf, 1024, reader_more, NULL);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+
+	state->subreq = subreq;
+	tevent_req_set_callback(subreq, reader_done, req);
+}
+
+static void reader_recv(struct tevent_req *req, int *perr)
+{
+	struct reader_state *state = tevent_req_data(
+		req, struct reader_state);
+	int err = 0;
+
+	if (state->subreq != NULL) {
+		*perr = -1;
+	}
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		*perr = err;
+		return;
+	}
+
+	*perr = 0;
+}
+
+static void reader_handler(struct tevent_context *ev, struct tevent_fd *fde,
+			   uint16_t flags, void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	struct reader_state *state = tevent_req_data(
+		req, struct reader_state);
+
+	assert(state->subreq != NULL);
+	pkt_read_handler(ev, fde, flags, state->subreq);
+}
+
+static void reader(int fd)
+{
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *ev;
+	struct tevent_fd *fde;
+	struct tevent_req *req;
+	int err;
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ev = tevent_context_init(mem_ctx);
+	assert(ev != NULL);
+
+	req = reader_send(mem_ctx, ev, fd);
+	assert(req != NULL);
+
+	fde = tevent_add_fd(ev, mem_ctx, fd, TEVENT_FD_READ,
+			    reader_handler, req);
+	assert(fde != NULL);
+
+	tevent_req_poll(req, ev);
+
+	reader_recv(req, &err);
+	assert(err == 0);
+
+	close(fd);
+
+	talloc_free(mem_ctx);
+}
+
+static bool set_nonblocking(int fd)
+{
+	int v;
+
+	v = fcntl(fd, F_GETFL, 0);
+	if (v == -1) {
+		return false;
+	}
+        if (fcntl(fd, F_SETFL, v | O_NONBLOCK) == -1) {
+		return false;
+	}
+	return true;
+}
+
+int main(void)
+{
+	int fd[2];
+	int ret;
+	pid_t pid;
+
+	ret = pipe(fd);
+	assert(ret == 0);
+
+	pid = fork();
+	assert(pid != -1);
+
+	if (pid == 0) {
+		/* Child process */
+		close(fd[0]);
+		writer(fd[1]);
+		exit(0);
+	}
+
+	close(fd[1]);
+	if (!set_nonblocking(fd[0])) {
+		exit(1);
+	}
+
+	reader(fd[0]);
+
+	return 0;
+}
diff --git a/ctdb/tests/src/pkt_write_test.c b/ctdb/tests/src/pkt_write_test.c
new file mode 100644
index 0000000..191e8b3
--- /dev/null
+++ b/ctdb/tests/src/pkt_write_test.c
@@ -0,0 +1,370 @@
+/*
+   packet write tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+
+#include <assert.h>
+
+#include "common/pkt_read.c"
+#include "common/pkt_write.c"
+
+struct writer_state {
+	struct tevent_context *ev;
+	int fd;
+	uint8_t *buf;
+	size_t buflen;
+	int  count;
+	struct tevent_req *subreq;
+};
+
+static void writer_next(struct tevent_req *subreq);
+
+static struct tevent_req *writer_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      int fd, uint8_t *buf, size_t buflen)
+{
+	struct tevent_req *req, *subreq;
+	struct writer_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct writer_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->fd = fd;
+	state->buf = buf;
+	state->buflen = buflen;
+	state->count = 0;
+
+	subreq = pkt_write_send(state, state->ev, state->fd,
+				state->buf, state->buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	state->subreq = subreq;
+	tevent_req_set_callback(subreq, writer_next, req);
+	return req;
+}
+
+static void writer_next(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct writer_state *state = tevent_req_data(
+		req, struct writer_state);
+	ssize_t nwritten;
+	int err = 0;
+
+	nwritten = pkt_write_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	state->subreq = NULL;
+	if (nwritten == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	if (nwritten != state->buflen) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	state->count++;
+	if (state->count >= 1000) {
+		tevent_req_done(req);
+		return;
+	}
+
+	subreq = pkt_write_send(state, state->ev, state->fd,
+				state->buf, state->buflen);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+
+	state->subreq = subreq;
+	tevent_req_set_callback(subreq, writer_next, req);
+}
+
+static void writer_recv(struct tevent_req *req, int *perr)
+{
+	struct writer_state *state = tevent_req_data(
+		req, struct writer_state);
+	int err = 0;
+
+	if (state->subreq != NULL) {
+		*perr = -1;
+		return;
+	}
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		*perr = err;
+		return;
+	}
+
+	*perr = 0;
+}
+
+static void writer_handler(struct tevent_context *ev, struct tevent_fd *fde,
+			   uint16_t flags, void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	struct writer_state *state = tevent_req_data(
+		req, struct writer_state);
+
+	assert(state->subreq != NULL);
+	pkt_write_handler(ev, fde, flags, state->subreq);
+}
+
+static void writer(int fd)
+{
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *ev;
+	struct tevent_fd *fde;
+	struct tevent_req *req;
+	uint8_t buf[1024*1024];
+	size_t buflen;
+	size_t pkt_size[4] = { 100, 500, 1024, 1024*1024 };
+	int i, err;
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ev = tevent_context_init(mem_ctx);
+	assert(ev != NULL);
+
+	for (i=0; i<1024*1024; i++) {
+		buf[i] = i%256;
+	}
+
+	for (i=0; i<4; i++) {
+		buflen = pkt_size[i];
+		memcpy(buf, &buflen, sizeof(buflen));
+
+		req = writer_send(mem_ctx, ev, fd, buf, buflen);
+		assert(req != NULL);
+
+		fde = tevent_add_fd(ev, mem_ctx, fd, TEVENT_FD_WRITE,
+				    writer_handler, req);
+		assert(fde != NULL);
+
+		tevent_req_poll(req, ev);
+
+		writer_recv(req, &err);
+		assert(err == 0);
+
+		talloc_free(fde);
+		talloc_free(req);
+	}
+
+	close(fd);
+
+	talloc_free(mem_ctx);
+}
+
+struct reader_state {
+	struct tevent_context *ev;
+	int fd;
+	uint8_t buf[1024];
+	struct tevent_req *subreq;
+};
+
+static ssize_t reader_more(uint8_t *buf, size_t buflen, void *private_data);
+static void reader_done(struct tevent_req *subreq);
+
+static struct tevent_req *reader_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      int fd)
+{
+	struct tevent_req *req, *subreq;
+	struct reader_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct reader_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->fd = fd;
+
+	subreq = pkt_read_send(state, state->ev, state->fd, 4,
+			       state->buf, 1024, reader_more, NULL);
+	if (tevent_req_nomem(subreq, req)) {
+		tevent_req_post(req, ev);
+	}
+
+	state->subreq = subreq;
+	tevent_req_set_callback(subreq, reader_done, req);
+	return req;
+}
+
+static ssize_t reader_more(uint8_t *buf, size_t buflen, void *private_data)
+{
+	uint32_t pkt_len;
+
+	if (buflen < sizeof(pkt_len)) {
+		return sizeof(pkt_len) - buflen;
+	}
+
+	pkt_len = *(uint32_t *)buf;
+	return pkt_len - buflen;
+}
+
+static void reader_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct reader_state *state = tevent_req_data(
+		req, struct reader_state);
+	ssize_t nread;
+	uint8_t *buf;
+	bool free_buf;
+	int err = 0;
+
+	nread = pkt_read_recv(subreq, state, &buf, &free_buf, &err);
+	TALLOC_FREE(subreq);
+	state->subreq = NULL;
+	if (nread == -1) {
+		if (err == EPIPE) {
+			tevent_req_done(req);
+		} else {
+			tevent_req_error(req, err);
+		}
+		return;
+	}
+
+	if (free_buf) {
+		talloc_free(buf);
+	}
+
+	subreq = pkt_read_send(state, state->ev, state->fd, 4,
+			       state->buf, 1024, reader_more, NULL);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+
+	state->subreq = subreq;
+	tevent_req_set_callback(subreq, reader_done, req);
+}
+
+static void reader_recv(struct tevent_req *req, int *perr)
+{
+	struct reader_state *state = tevent_req_data(
+		req, struct reader_state);
+	int err = 0;
+
+	if (state->subreq != NULL) {
+		*perr = -1;
+	}
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		*perr = err;
+		return;
+	}
+
+	*perr = 0;
+}
+
+static void reader_handler(struct tevent_context *ev, struct tevent_fd *fde,
+			   uint16_t flags, void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	struct reader_state *state = tevent_req_data(
+		req, struct reader_state);
+
+	assert(state->subreq != NULL);
+	pkt_read_handler(ev, fde, flags, state->subreq);
+}
+
+static void reader(int fd)
+{
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *ev;
+	struct tevent_fd *fde;
+	struct tevent_req *req;
+	int err;
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ev = tevent_context_init(mem_ctx);
+	assert(ev != NULL);
+
+	req = reader_send(mem_ctx, ev, fd);
+	assert(req != NULL);
+
+	fde = tevent_add_fd(ev, mem_ctx, fd, TEVENT_FD_READ,
+			    reader_handler, req);
+	assert(fde != NULL);
+
+	tevent_req_poll(req, ev);
+
+	reader_recv(req, &err);
+	assert(err == 0);
+
+	close(fd);
+
+	talloc_free(mem_ctx);
+}
+
+static bool set_nonblocking(int fd)
+{
+	int v;
+
+	v = fcntl(fd, F_GETFL, 0);
+	if (v == -1) {
+		return false;
+	}
+        if (fcntl(fd, F_SETFL, v | O_NONBLOCK) == -1) {
+		return false;
+	}
+	return true;
+}
+
+int main(void)
+{
+	int fd[2];
+	int ret;
+	pid_t pid;
+
+	ret = pipe(fd);
+	assert(ret == 0);
+
+	pid = fork();
+	assert(pid != -1);
+
+	if (pid == 0) {
+		/* Child process */
+		close(fd[0]);
+		writer(fd[1]);
+		exit(0);
+	}
+
+	close(fd[1]);
+	if (!set_nonblocking(fd[0])) {
+		exit(1);
+	}
+
+	reader(fd[0]);
+
+	return 0;
+}
diff --git a/ctdb/tests/src/protocol_client_test.c b/ctdb/tests/src/protocol_client_test.c
new file mode 100644
index 0000000..f5a3c35
--- /dev/null
+++ b/ctdb/tests/src/protocol_client_test.c
@@ -0,0 +1,2353 @@
+/*
+   protocol tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <assert.h>
+
+#define PROTOCOL_TEST
+
+#include "protocol_types_test.c"
+
+
+#define GENERATION	0xabcdef12
+#define OPERATION	CTDB_REQ_KEEPALIVE
+#define REQID		0x34567890
+#define SRCNODE		7
+#define DESTNODE	13
+
+/*
+ * Functions to fill and verify protocol structures
+ */
+
+static void verify_ctdb_req_header(struct ctdb_req_header *h,
+				   struct ctdb_req_header *h2)
+{
+	verify_buffer(h, h2, sizeof(struct ctdb_req_header));
+}
+
+static void fill_ctdb_req_call(TALLOC_CTX *mem_ctx,
+			       struct ctdb_req_call *c)
+{
+	c->flags = rand32();
+	c->db_id = rand32();
+	c->callid = rand32();
+	c->hopcount = rand32();
+	fill_tdb_data(mem_ctx, &c->key);
+	fill_tdb_data(mem_ctx, &c->calldata);
+}
+
+static void verify_ctdb_req_call(struct ctdb_req_call *c,
+				 struct ctdb_req_call *c2)
+{
+	assert(c->flags == c2->flags);
+	assert(c->db_id == c2->db_id);
+	assert(c->callid == c2->callid);
+	assert(c->hopcount == c2->hopcount);
+	verify_tdb_data(&c->key, &c2->key);
+	verify_tdb_data(&c->calldata, &c2->calldata);
+}
+
+static void fill_ctdb_reply_call(TALLOC_CTX *mem_ctx,
+				 struct ctdb_reply_call *c)
+{
+	c->status = rand32();
+	fill_tdb_data(mem_ctx, &c->data);
+}
+
+static void verify_ctdb_reply_call(struct ctdb_reply_call *c,
+				   struct ctdb_reply_call *c2)
+{
+	assert(c->status == c2->status);
+	verify_tdb_data(&c->data, &c2->data);
+}
+
+static void fill_ctdb_reply_error(TALLOC_CTX *mem_ctx,
+				  struct ctdb_reply_error *c)
+{
+	c->status = rand32();
+	fill_tdb_data(mem_ctx, &c->msg);
+}
+
+static void verify_ctdb_reply_error(struct ctdb_reply_error *c,
+				    struct ctdb_reply_error *c2)
+{
+	assert(c->status == c2->status);
+	verify_tdb_data(&c->msg, &c2->msg);
+}
+
+static void fill_ctdb_req_dmaster(TALLOC_CTX *mem_ctx,
+				  struct ctdb_req_dmaster *c)
+{
+	c->db_id = rand32();
+	c->rsn = rand64();
+	c->dmaster = rand32();
+	fill_tdb_data(mem_ctx, &c->key);
+	fill_tdb_data(mem_ctx, &c->data);
+}
+
+static void verify_ctdb_req_dmaster(struct ctdb_req_dmaster *c,
+				    struct ctdb_req_dmaster *c2)
+{
+	assert(c->db_id == c2->db_id);
+	assert(c->rsn == c2->rsn);
+	assert(c->dmaster == c2->dmaster);
+	verify_tdb_data(&c->key, &c2->key);
+	verify_tdb_data(&c->data, &c2->data);
+}
+
+static void fill_ctdb_reply_dmaster(TALLOC_CTX *mem_ctx,
+				    struct ctdb_reply_dmaster *c)
+{
+	c->db_id = rand32();
+	c->rsn = rand64();
+	fill_tdb_data(mem_ctx, &c->key);
+	fill_tdb_data(mem_ctx, &c->data);
+}
+
+static void verify_ctdb_reply_dmaster(struct ctdb_reply_dmaster *c,
+				      struct ctdb_reply_dmaster *c2)
+{
+	assert(c->db_id == c2->db_id);
+	assert(c->rsn == c2->rsn);
+	verify_tdb_data(&c->key, &c2->key);
+	verify_tdb_data(&c->data, &c2->data);
+}
+
+static void fill_ctdb_req_control_data(TALLOC_CTX *mem_ctx,
+				       struct ctdb_req_control_data *cd,
+				       uint32_t opcode)
+{
+	cd->opcode = opcode;
+	switch (opcode) {
+	case CTDB_CONTROL_PROCESS_EXISTS:
+		cd->data.pid = rand32();
+		break;
+
+	case CTDB_CONTROL_STATISTICS:
+		break;
+
+	case CTDB_CONTROL_PING:
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_GETVNNMAP:
+		break;
+
+	case CTDB_CONTROL_SETVNNMAP:
+		cd->data.vnnmap = talloc(mem_ctx, struct ctdb_vnn_map);
+		assert(cd->data.vnnmap != NULL);
+		fill_ctdb_vnn_map(mem_ctx, cd->data.vnnmap);
+		break;
+
+	case CTDB_CONTROL_GET_DEBUG:
+		break;
+
+	case CTDB_CONTROL_SET_DEBUG:
+		cd->data.loglevel = rand_int(5);
+		break;
+
+	case CTDB_CONTROL_GET_DBMAP:
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		cd->data.pulldb = talloc(mem_ctx, struct ctdb_pulldb);
+		assert(cd->data.pulldb != NULL);
+		fill_ctdb_pulldb(mem_ctx, cd->data.pulldb);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+		assert(cd->data.recbuf != NULL);
+		fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_GET_RECMODE:
+		break;
+
+	case CTDB_CONTROL_SET_RECMODE:
+		cd->data.recmode = rand_int(2);
+		break;
+
+	case CTDB_CONTROL_STATISTICS_RESET:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		fill_ctdb_string(mem_ctx, &cd->data.db_name);
+		assert(cd->data.db_name != NULL);
+		break;
+
+	case CTDB_CONTROL_SET_CALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START:
+		cd->data.traverse_start = talloc(mem_ctx, struct ctdb_traverse_start);
+		assert(cd->data.traverse_start != NULL);
+		fill_ctdb_traverse_start(mem_ctx, cd->data.traverse_start);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL:
+		cd->data.traverse_all = talloc(mem_ctx, struct ctdb_traverse_all);
+		assert(cd->data.traverse_all != NULL);
+		fill_ctdb_traverse_all(mem_ctx, cd->data.traverse_all);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_DATA:
+		cd->data.rec_data = talloc(mem_ctx, struct ctdb_rec_data);
+		assert(cd->data.rec_data != NULL);
+		fill_ctdb_rec_data(mem_ctx, cd->data.rec_data);
+		break;
+
+	case CTDB_CONTROL_REGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_ENABLE_SEQNUM:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_UPDATE_SEQNUM:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_DUMP_MEMORY:
+		break;
+
+	case CTDB_CONTROL_GET_PID:
+		break;
+
+	case CTDB_CONTROL_GET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTER:
+		cd->data.recmaster = rand_int(32);
+		break;
+
+	case CTDB_CONTROL_FREEZE:
+		break;
+
+	case CTDB_CONTROL_THAW:
+		break;
+
+	case CTDB_CONTROL_GET_PNN:
+		break;
+
+	case CTDB_CONTROL_SHUTDOWN:
+		break;
+
+	case CTDB_CONTROL_GET_MONMODE:
+		break;
+
+	case CTDB_CONTROL_TCP_CLIENT:
+		cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+		assert(cd->data.conn != NULL);
+		fill_ctdb_connection(mem_ctx, cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD:
+		cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+		assert(cd->data.conn != NULL);
+		fill_ctdb_connection(mem_ctx, cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_TCP_REMOVE:
+		cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+		assert(cd->data.conn != NULL);
+		fill_ctdb_connection(mem_ctx, cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_STARTUP:
+		break;
+
+	case CTDB_CONTROL_SET_TUNABLE:
+		cd->data.tunable = talloc(mem_ctx, struct ctdb_tunable);
+		assert(cd->data.tunable != NULL);
+		fill_ctdb_tunable(mem_ctx, cd->data.tunable);
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		fill_ctdb_string(mem_ctx, &cd->data.tun_var);
+		assert(cd->data.tun_var != NULL);
+		break;
+
+	case CTDB_CONTROL_LIST_TUNABLES:
+		break;
+
+	case CTDB_CONTROL_MODIFY_FLAGS:
+		cd->data.flag_change = talloc(mem_ctx, struct ctdb_node_flag_change);
+		assert(cd->data.flag_change != NULL);
+		fill_ctdb_node_flag_change(mem_ctx, cd->data.flag_change);
+		break;
+
+	case CTDB_CONTROL_GET_ALL_TUNABLES:
+		break;
+
+	case CTDB_CONTROL_KILL_TCP:
+		cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+		assert(cd->data.conn != NULL);
+		fill_ctdb_connection(mem_ctx, cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		cd->data.addr = talloc(mem_ctx, ctdb_sock_addr);
+		assert(cd->data.addr != NULL);
+		fill_ctdb_sock_addr(mem_ctx, cd->data.addr);
+		break;
+
+	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+		cd->data.tickles = talloc(mem_ctx, struct ctdb_tickle_list);
+		assert(cd->data.tickles != NULL);
+		fill_ctdb_tickle_list(mem_ctx, cd->data.tickles);
+		break;
+
+	case CTDB_CONTROL_REGISTER_SERVER_ID:
+		cd->data.cid = talloc(mem_ctx, struct ctdb_client_id);
+		assert(cd->data.cid != NULL);
+		fill_ctdb_client_id(mem_ctx, cd->data.cid);
+		break;
+
+	case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+		cd->data.cid = talloc(mem_ctx, struct ctdb_client_id);
+		assert(cd->data.cid != NULL);
+		fill_ctdb_client_id(mem_ctx, cd->data.cid);
+		break;
+
+	case CTDB_CONTROL_CHECK_SERVER_ID:
+		cd->data.cid = talloc(mem_ctx, struct ctdb_client_id);
+		assert(cd->data.cid != NULL);
+		fill_ctdb_client_id(mem_ctx, cd->data.cid);
+		break;
+
+	case CTDB_CONTROL_GET_SERVER_ID_LIST:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		fill_ctdb_string(mem_ctx, &cd->data.db_name);
+		assert(cd->data.db_name != NULL);
+		break;
+
+	case CTDB_CONTROL_UPDATE_RECORD:
+		cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+		assert(cd->data.recbuf != NULL);
+		fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+		cd->data.addr_info = talloc(mem_ctx, struct ctdb_addr_info);
+		assert(cd->data.addr_info != NULL);
+		fill_ctdb_addr_info(mem_ctx, cd->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_START:
+		cd->data.tid = rand32();
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_COMMIT:
+		cd->data.tid = rand32();
+		break;
+
+	case CTDB_CONTROL_WIPE_DATABASE:
+		cd->data.transdb = talloc(mem_ctx, struct ctdb_transdb);
+		assert(cd->data.transdb != NULL);
+		fill_ctdb_transdb(mem_ctx, cd->data.transdb);
+		break;
+
+	case CTDB_CONTROL_UPTIME:
+		break;
+
+	case CTDB_CONTROL_START_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_END_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_RELOAD_NODES_FILE:
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+		assert(cd->data.recbuf != NULL);
+		fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_ENABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_DISABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_ADD_PUBLIC_IP:
+		cd->data.addr_info = talloc(mem_ctx, struct ctdb_addr_info);
+		assert(cd->data.addr_info != NULL);
+		fill_ctdb_addr_info(mem_ctx, cd->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_DEL_PUBLIC_IP:
+		cd->data.addr_info = talloc(mem_ctx, struct ctdb_addr_info);
+		assert(cd->data.addr_info != NULL);
+		fill_ctdb_addr_info(mem_ctx, cd->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+		fill_ctdb_string(mem_ctx, &cd->data.event_str);
+		assert(cd->data.event_str != NULL);
+		break;
+
+	case CTDB_CONTROL_GET_CAPABILITIES:
+		break;
+
+	case CTDB_CONTROL_START_PERSISTENT_UPDATE:
+		break;
+
+	case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
+		break;
+
+	case CTDB_CONTROL_RECD_PING:
+		break;
+
+	case CTDB_CONTROL_RELEASE_IP:
+		cd->data.pubip = talloc(mem_ctx, struct ctdb_public_ip);
+		assert(cd->data.pubip != NULL);
+		fill_ctdb_public_ip(mem_ctx, cd->data.pubip);
+		break;
+
+	case CTDB_CONTROL_TAKEOVER_IP:
+		cd->data.pubip = talloc(mem_ctx, struct ctdb_public_ip);
+		assert(cd->data.pubip != NULL);
+		fill_ctdb_public_ip(mem_ctx, cd->data.pubip);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IPS:
+		break;
+
+	case CTDB_CONTROL_GET_NODEMAP:
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		cd->data.event = rand_int(CTDB_EVENT_MAX);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_KILL:
+		cd->data.traverse_start = talloc(mem_ctx, struct ctdb_traverse_start);
+		assert(cd->data.traverse_start != NULL);
+		fill_ctdb_traverse_start(mem_ctx, cd->data.traverse_start);
+		break;
+
+	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+		cd->data.reclock_latency = rand_double();
+		break;
+
+	case CTDB_CONTROL_GET_RECLOCK_FILE:
+		break;
+
+	case CTDB_CONTROL_SET_RECLOCK_FILE:
+		fill_ctdb_string(mem_ctx, &cd->data.reclock_file);
+		assert(cd->data.reclock_file != NULL);
+		break;
+
+	case CTDB_CONTROL_STOP_NODE:
+		break;
+
+	case CTDB_CONTROL_CONTINUE_NODE:
+		break;
+
+	case CTDB_CONTROL_SET_NATGWSTATE:
+		cd->data.role = rand_int(2);
+		break;
+
+	case CTDB_CONTROL_SET_LMASTERROLE:
+		cd->data.role = rand_int(2);
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTERROLE:
+		cd->data.role = rand_int(2);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SCRIPT:
+		fill_ctdb_string(mem_ctx, &cd->data.script);
+		assert(cd->data.script != NULL);
+		break;
+
+	case CTDB_CONTROL_DISABLE_SCRIPT:
+		fill_ctdb_string(mem_ctx, &cd->data.script);
+		assert(cd->data.script != NULL);
+		break;
+
+	case CTDB_CONTROL_SET_BAN_STATE:
+		cd->data.ban_state = talloc(mem_ctx, struct ctdb_ban_state);
+		assert(cd->data.ban_state != NULL);
+		fill_ctdb_ban_state(mem_ctx, cd->data.ban_state);
+		break;
+
+	case CTDB_CONTROL_GET_BAN_STATE:
+		break;
+
+	case CTDB_CONTROL_SET_DB_PRIORITY:
+		cd->data.db_prio = talloc(mem_ctx, struct ctdb_db_priority);
+		assert(cd->data.db_prio != NULL);
+		fill_ctdb_db_priority(mem_ctx, cd->data.db_prio);
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		cd->data.db_prio = talloc(mem_ctx, struct ctdb_db_priority);
+		assert(cd->data.db_prio != NULL);
+		fill_ctdb_db_priority(mem_ctx, cd->data.db_prio);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_CANCEL:
+		break;
+
+	case CTDB_CONTROL_REGISTER_NOTIFY:
+		cd->data.notify = talloc(mem_ctx, struct ctdb_notify_data);
+		assert(cd->data.notify != NULL);
+		fill_ctdb_notify_data(mem_ctx, cd->data.notify);
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_NOTIFY:
+		cd->data.srvid = rand64();
+		break;
+
+	case CTDB_CONTROL_TRANS3_COMMIT:
+		cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+		assert(cd->data.recbuf != NULL);
+		fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_DB_SET_HEALTHY:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		cd->data.addr = talloc(mem_ctx, ctdb_sock_addr);
+		assert(cd->data.addr != NULL);
+		fill_ctdb_sock_addr(mem_ctx, cd->data.addr);
+		break;
+
+	case CTDB_CONTROL_GET_IFACES:
+		break;
+
+	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+		cd->data.iface = talloc(mem_ctx, struct ctdb_iface);
+		assert(cd->data.iface != NULL);
+		fill_ctdb_iface(mem_ctx, cd->data.iface);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+		cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+		assert(cd->data.conn != NULL);
+		fill_ctdb_connection(mem_ctx, cd->data.conn);
+		break;
+
+	case CTDB_CONTROL_GET_STAT_HISTORY:
+		break;
+
+	case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+		cd->data.key = talloc(mem_ctx, struct ctdb_key_data);
+		assert(cd->data.key != NULL);
+		fill_ctdb_key_data(mem_ctx, cd->data.key);
+		break;
+
+	case CTDB_CONTROL_SET_DB_READONLY:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		cd->data.u64_array = talloc(mem_ctx, struct ctdb_uint64_array);
+		assert(cd->data.u64_array != NULL);
+		fill_ctdb_uint64_array(mem_ctx, cd->data.u64_array);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START_EXT:
+		cd->data.traverse_start_ext = talloc(mem_ctx, struct ctdb_traverse_start_ext);
+		assert(cd->data.traverse_start_ext != NULL);
+		fill_ctdb_traverse_start_ext(mem_ctx, cd->data.traverse_start_ext);
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_SET_DB_STICKY:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+		cd->data.traverse_all_ext = talloc(mem_ctx, struct ctdb_traverse_all_ext);
+		assert(cd->data.traverse_all_ext != NULL);
+		fill_ctdb_traverse_all_ext(mem_ctx, cd->data.traverse_all_ext);
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+		assert(cd->data.recbuf != NULL);
+		fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_IPREALLOCATED:
+		break;
+
+	case CTDB_CONTROL_GET_RUNSTATE:
+		break;
+
+	case CTDB_CONTROL_DB_DETACH:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_GET_NODES_FILE:
+		break;
+
+	case CTDB_CONTROL_DB_FREEZE:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_DB_THAW:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_START:
+		cd->data.transdb = talloc(mem_ctx, struct ctdb_transdb);
+		assert(cd->data.transdb != NULL);
+		fill_ctdb_transdb(mem_ctx, cd->data.transdb);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_COMMIT:
+		cd->data.transdb = talloc(mem_ctx, struct ctdb_transdb);
+		assert(cd->data.transdb != NULL);
+		fill_ctdb_transdb(mem_ctx, cd->data.transdb);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_CANCEL:
+		cd->data.db_id = rand32();
+		break;
+	}
+}
+
+static void verify_ctdb_req_control_data(struct ctdb_req_control_data *cd,
+					 struct ctdb_req_control_data *cd2)
+{
+	assert(cd->opcode == cd2->opcode);
+
+	switch (cd->opcode) {
+	case CTDB_CONTROL_PROCESS_EXISTS:
+		assert(cd->data.pid == cd2->data.pid);
+		break;
+
+	case CTDB_CONTROL_STATISTICS:
+		break;
+
+	case CTDB_CONTROL_PING:
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_GETVNNMAP:
+		break;
+
+	case CTDB_CONTROL_SETVNNMAP:
+		verify_ctdb_vnn_map(cd->data.vnnmap, cd2->data.vnnmap);
+		break;
+
+	case CTDB_CONTROL_GET_DEBUG:
+		break;
+
+	case CTDB_CONTROL_SET_DEBUG:
+		assert(cd->data.loglevel == cd2->data.loglevel);
+		break;
+
+	case CTDB_CONTROL_GET_DBMAP:
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		verify_ctdb_pulldb(cd->data.pulldb, cd2->data.pulldb);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_GET_RECMODE:
+		break;
+
+	case CTDB_CONTROL_SET_RECMODE:
+		assert(cd->data.recmode == cd2->data.recmode);
+		break;
+
+	case CTDB_CONTROL_STATISTICS_RESET:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		verify_ctdb_string(cd->data.db_name, cd2->data.db_name);
+		break;
+
+	case CTDB_CONTROL_SET_CALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START:
+		verify_ctdb_traverse_start(cd->data.traverse_start,
+					   cd2->data.traverse_start);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL:
+		verify_ctdb_traverse_all(cd->data.traverse_all,
+					 cd2->data.traverse_all);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_DATA:
+		verify_ctdb_rec_data(cd->data.rec_data, cd2->data.rec_data);
+		break;
+
+	case CTDB_CONTROL_REGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SEQNUM:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_UPDATE_SEQNUM:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DUMP_MEMORY:
+		break;
+
+	case CTDB_CONTROL_GET_PID:
+		break;
+
+	case CTDB_CONTROL_GET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTER:
+		assert(cd->data.recmaster == cd2->data.recmaster);
+		break;
+
+	case CTDB_CONTROL_FREEZE:
+		break;
+
+	case CTDB_CONTROL_THAW:
+		break;
+
+	case CTDB_CONTROL_GET_PNN:
+		break;
+
+	case CTDB_CONTROL_SHUTDOWN:
+		break;
+
+	case CTDB_CONTROL_GET_MONMODE:
+		break;
+
+	case CTDB_CONTROL_TCP_CLIENT:
+		verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD:
+		verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+		break;
+
+	case CTDB_CONTROL_TCP_REMOVE:
+		verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+		break;
+
+	case CTDB_CONTROL_STARTUP:
+		break;
+
+	case CTDB_CONTROL_SET_TUNABLE:
+		verify_ctdb_tunable(cd->data.tunable, cd2->data.tunable);
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		verify_ctdb_string(cd->data.tun_var, cd2->data.tun_var);
+		break;
+
+	case CTDB_CONTROL_LIST_TUNABLES:
+		break;
+
+	case CTDB_CONTROL_MODIFY_FLAGS:
+		verify_ctdb_node_flag_change(cd->data.flag_change,
+					     cd2->data.flag_change);
+		break;
+
+	case CTDB_CONTROL_GET_ALL_TUNABLES:
+		break;
+
+	case CTDB_CONTROL_KILL_TCP:
+		verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		verify_ctdb_sock_addr(cd->data.addr, cd2->data.addr);
+		break;
+
+	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+		verify_ctdb_tickle_list(cd->data.tickles, cd2->data.tickles);
+		break;
+
+	case CTDB_CONTROL_REGISTER_SERVER_ID:
+		verify_ctdb_client_id(cd->data.cid, cd2->data.cid);
+		break;
+
+	case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+		verify_ctdb_client_id(cd->data.cid, cd2->data.cid);
+		break;
+
+	case CTDB_CONTROL_CHECK_SERVER_ID:
+		verify_ctdb_client_id(cd->data.cid, cd2->data.cid);
+		break;
+
+	case CTDB_CONTROL_GET_SERVER_ID_LIST:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		verify_ctdb_string(cd->data.db_name, cd2->data.db_name);
+		break;
+
+	case CTDB_CONTROL_UPDATE_RECORD:
+		verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+		verify_ctdb_addr_info(cd->data.addr_info, cd2->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_START:
+		assert(cd->data.tid == cd2->data.tid);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_COMMIT:
+		assert(cd->data.tid == cd2->data.tid);
+		break;
+
+	case CTDB_CONTROL_WIPE_DATABASE:
+		verify_ctdb_transdb(cd->data.transdb, cd2->data.transdb);
+		break;
+
+	case CTDB_CONTROL_UPTIME:
+		break;
+
+	case CTDB_CONTROL_START_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_END_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_RELOAD_NODES_FILE:
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_ENABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_DISABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_ADD_PUBLIC_IP:
+		verify_ctdb_addr_info(cd->data.addr_info, cd2->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_DEL_PUBLIC_IP:
+		verify_ctdb_addr_info(cd->data.addr_info, cd2->data.addr_info);
+		break;
+
+	case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+		verify_ctdb_string(cd->data.event_str, cd2->data.event_str);
+		break;
+
+	case CTDB_CONTROL_GET_CAPABILITIES:
+		break;
+
+	case CTDB_CONTROL_START_PERSISTENT_UPDATE:
+		break;
+
+	case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
+		break;
+
+	case CTDB_CONTROL_RECD_PING:
+		break;
+
+	case CTDB_CONTROL_RELEASE_IP:
+		verify_ctdb_public_ip(cd->data.pubip, cd2->data.pubip);
+		break;
+
+	case CTDB_CONTROL_TAKEOVER_IP:
+		verify_ctdb_public_ip(cd->data.pubip, cd2->data.pubip);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IPS:
+		break;
+
+	case CTDB_CONTROL_GET_NODEMAP:
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		assert(cd->data.event == cd2->data.event);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_KILL:
+		verify_ctdb_traverse_start(cd->data.traverse_start,
+					   cd2->data.traverse_start);
+		break;
+
+	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+		assert(cd->data.reclock_latency == cd2->data.reclock_latency);
+		break;
+
+	case CTDB_CONTROL_GET_RECLOCK_FILE:
+		break;
+
+	case CTDB_CONTROL_SET_RECLOCK_FILE:
+		verify_ctdb_string(cd->data.reclock_file,
+				   cd2->data.reclock_file);
+		break;
+
+	case CTDB_CONTROL_STOP_NODE:
+		break;
+
+	case CTDB_CONTROL_CONTINUE_NODE:
+		break;
+
+	case CTDB_CONTROL_SET_NATGWSTATE:
+		assert(cd->data.role == cd2->data.role);
+		break;
+
+	case CTDB_CONTROL_SET_LMASTERROLE:
+		assert(cd->data.role == cd2->data.role);
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTERROLE:
+		assert(cd->data.role == cd2->data.role);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SCRIPT:
+		verify_ctdb_string(cd->data.script, cd2->data.script);
+		break;
+
+	case CTDB_CONTROL_DISABLE_SCRIPT:
+		verify_ctdb_string(cd->data.script, cd2->data.script);
+		break;
+
+	case CTDB_CONTROL_SET_BAN_STATE:
+		verify_ctdb_ban_state(cd->data.ban_state, cd2->data.ban_state);
+		break;
+
+	case CTDB_CONTROL_GET_BAN_STATE:
+		break;
+
+	case CTDB_CONTROL_SET_DB_PRIORITY:
+		verify_ctdb_db_priority(cd->data.db_prio, cd2->data.db_prio);
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_CANCEL:
+		break;
+
+	case CTDB_CONTROL_REGISTER_NOTIFY:
+		verify_ctdb_notify_data(cd->data.notify, cd2->data.notify);
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_NOTIFY:
+		assert(cd->data.srvid == cd2->data.srvid);
+		break;
+
+	case CTDB_CONTROL_TRANS3_COMMIT:
+		verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_SET_HEALTHY:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		verify_ctdb_sock_addr(cd->data.addr, cd2->data.addr);
+		break;
+
+	case CTDB_CONTROL_GET_IFACES:
+		break;
+
+	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+		verify_ctdb_iface(cd->data.iface, cd2->data.iface);
+		break;
+
+	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+		verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+		break;
+
+	case CTDB_CONTROL_GET_STAT_HISTORY:
+		break;
+
+	case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+		verify_ctdb_key_data(cd->data.key, cd2->data.key);
+		break;
+
+	case CTDB_CONTROL_SET_DB_READONLY:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		verify_ctdb_uint64_array(cd->data.u64_array,
+					 cd2->data.u64_array);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START_EXT:
+		verify_ctdb_traverse_start_ext(cd->data.traverse_start_ext,
+					       cd2->data.traverse_start_ext);
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_SET_DB_STICKY:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+		verify_ctdb_traverse_all_ext(cd->data.traverse_all_ext,
+					     cd2->data.traverse_all_ext);
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_IPREALLOCATED:
+		break;
+
+	case CTDB_CONTROL_GET_RUNSTATE:
+		break;
+
+	case CTDB_CONTROL_DB_DETACH:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_GET_NODES_FILE:
+		break;
+
+	case CTDB_CONTROL_DB_FREEZE:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_THAW:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_START:
+		verify_ctdb_transdb(cd->data.transdb, cd2->data.transdb);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_COMMIT:
+		verify_ctdb_transdb(cd->data.transdb, cd2->data.transdb);
+		break;
+
+	case CTDB_CONTROL_DB_TRANSACTION_CANCEL:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+	}
+}
+
+static void fill_ctdb_req_control(TALLOC_CTX *mem_ctx,
+				  struct ctdb_req_control *c,
+				  uint32_t opcode)
+{
+	c->opcode = opcode;
+	c->pad = rand32();
+	c->srvid = rand64();
+	c->client_id = rand32();
+	c->flags = rand32();
+
+	fill_ctdb_req_control_data(mem_ctx, &c->rdata, opcode);
+}
+
+static void verify_ctdb_req_control(struct ctdb_req_control *c,
+				    struct ctdb_req_control *c2)
+{
+	assert(c->opcode == c2->opcode);
+	assert(c->pad == c2->pad);
+	assert(c->srvid == c2->srvid);
+	assert(c->client_id == c2->client_id);
+	assert(c->flags == c2->flags);
+
+	verify_ctdb_req_control_data(&c->rdata, &c2->rdata);
+}
+
+static void fill_ctdb_reply_control_data(TALLOC_CTX *mem_ctx,
+					 struct ctdb_reply_control_data *cd,
+					 uint32_t opcode)
+{
+	cd->opcode = opcode;
+
+	switch (opcode) {
+	case CTDB_CONTROL_PROCESS_EXISTS:
+		break;
+
+	case CTDB_CONTROL_STATISTICS:
+		cd->data.stats = talloc(mem_ctx, struct ctdb_statistics);
+		assert(cd->data.stats != NULL);
+		fill_ctdb_statistics(mem_ctx, cd->data.stats);
+		break;
+
+	case CTDB_CONTROL_PING:
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		fill_ctdb_string(mem_ctx, &cd->data.db_path);
+		assert(cd->data.db_path != NULL);
+		break;
+
+	case CTDB_CONTROL_GETVNNMAP:
+		cd->data.vnnmap = talloc(mem_ctx, struct ctdb_vnn_map);
+		assert(cd->data.vnnmap != NULL);
+		fill_ctdb_vnn_map(mem_ctx, cd->data.vnnmap);
+		break;
+
+	case CTDB_CONTROL_SETVNNMAP:
+		break;
+
+	case CTDB_CONTROL_GET_DEBUG:
+		cd->data.loglevel = rand_int(5);
+		break;
+
+	case CTDB_CONTROL_SET_DEBUG:
+		break;
+
+	case CTDB_CONTROL_GET_DBMAP:
+		cd->data.dbmap = talloc(mem_ctx, struct ctdb_dbid_map);
+		assert(cd->data.dbmap != NULL);
+		fill_ctdb_dbid_map(mem_ctx, cd->data.dbmap);
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+		assert(cd->data.recbuf != NULL);
+		fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		break;
+
+	case CTDB_CONTROL_GET_RECMODE:
+		break;
+
+	case CTDB_CONTROL_SET_RECMODE:
+		break;
+
+	case CTDB_CONTROL_STATISTICS_RESET:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		cd->data.db_id = rand32();
+		break;
+
+	case CTDB_CONTROL_SET_CALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_DATA:
+		break;
+
+	case CTDB_CONTROL_REGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		fill_ctdb_string(mem_ctx, &cd->data.db_name);
+		assert(cd->data.db_name);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SEQNUM:
+		break;
+
+	case CTDB_CONTROL_UPDATE_SEQNUM:
+		break;
+
+	case CTDB_CONTROL_DUMP_MEMORY:
+		fill_ctdb_string(mem_ctx, &cd->data.mem_str);
+		assert(cd->data.mem_str);
+		break;
+
+	case CTDB_CONTROL_GET_PID:
+		break;
+
+	case CTDB_CONTROL_GET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_FREEZE:
+		break;
+
+	case CTDB_CONTROL_THAW:
+		break;
+
+	case CTDB_CONTROL_GET_PNN:
+		break;
+
+	case CTDB_CONTROL_SHUTDOWN:
+		break;
+
+	case CTDB_CONTROL_GET_MONMODE:
+		break;
+
+	case CTDB_CONTROL_TCP_CLIENT:
+		break;
+
+	case CTDB_CONTROL_TCP_ADD:
+		break;
+
+	case CTDB_CONTROL_TCP_REMOVE:
+		break;
+
+	case CTDB_CONTROL_STARTUP:
+		break;
+
+	case CTDB_CONTROL_SET_TUNABLE:
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		cd->data.tun_value = rand32();
+		break;
+
+	case CTDB_CONTROL_LIST_TUNABLES:
+		cd->data.tun_var_list = talloc(mem_ctx, struct ctdb_var_list);
+		assert(cd->data.tun_var_list != NULL);
+		fill_ctdb_var_list(mem_ctx, cd->data.tun_var_list);
+		break;
+
+	case CTDB_CONTROL_MODIFY_FLAGS:
+		break;
+
+	case CTDB_CONTROL_GET_ALL_TUNABLES:
+		cd->data.tun_list = talloc(mem_ctx, struct ctdb_tunable_list);
+		assert(cd->data.tun_list != NULL);
+		fill_ctdb_tunable_list(mem_ctx, cd->data.tun_list);
+		break;
+
+	case CTDB_CONTROL_KILL_TCP:
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		cd->data.tickles = talloc(mem_ctx, struct ctdb_tickle_list);
+		assert(cd->data.tickles != NULL);
+		fill_ctdb_tickle_list(mem_ctx, cd->data.tickles);
+		break;
+
+	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+		break;
+
+	case CTDB_CONTROL_REGISTER_SERVER_ID:
+		break;
+
+	case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+		break;
+
+	case CTDB_CONTROL_CHECK_SERVER_ID:
+		break;
+
+	case CTDB_CONTROL_GET_SERVER_ID_LIST:
+		cd->data.cid_map = talloc(mem_ctx, struct ctdb_client_id_map);
+		assert(cd->data.cid_map != NULL);
+		fill_ctdb_client_id_map(mem_ctx, cd->data.cid_map);
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		break;
+
+	case CTDB_CONTROL_UPDATE_RECORD:
+		break;
+
+	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_START:
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_COMMIT:
+		break;
+
+	case CTDB_CONTROL_WIPE_DATABASE:
+		break;
+
+	case CTDB_CONTROL_UPTIME:
+		cd->data.uptime = talloc(mem_ctx, struct ctdb_uptime);
+		assert(cd->data.uptime != NULL);
+		fill_ctdb_uptime(mem_ctx, cd->data.uptime);
+		break;
+
+	case CTDB_CONTROL_START_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_END_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_RELOAD_NODES_FILE:
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+		assert(cd->data.recbuf != NULL);
+		fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_ENABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_DISABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_ADD_PUBLIC_IP:
+		break;
+
+	case CTDB_CONTROL_DEL_PUBLIC_IP:
+		break;
+
+	case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+		break;
+
+	case CTDB_CONTROL_GET_CAPABILITIES:
+		cd->data.caps = rand32();
+		break;
+
+	case CTDB_CONTROL_START_PERSISTENT_UPDATE:
+		break;
+
+	case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
+		break;
+
+	case CTDB_CONTROL_RECD_PING:
+		break;
+
+	case CTDB_CONTROL_RELEASE_IP:
+		break;
+
+	case CTDB_CONTROL_TAKEOVER_IP:
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IPS:
+		cd->data.pubip_list = talloc(mem_ctx, struct ctdb_public_ip_list);
+		assert(cd->data.pubip_list != NULL);
+		fill_ctdb_public_ip_list(mem_ctx, cd->data.pubip_list);
+		break;
+
+	case CTDB_CONTROL_GET_NODEMAP:
+		cd->data.nodemap = talloc(mem_ctx, struct ctdb_node_map);
+		assert(cd->data.nodemap != NULL);
+		fill_ctdb_node_map(mem_ctx, cd->data.nodemap);
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		cd->data.script_list = talloc(mem_ctx, struct ctdb_script_list);
+		assert(cd->data.script_list != NULL);
+		fill_ctdb_script_list(mem_ctx, cd->data.script_list);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_KILL:
+		break;
+
+	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+		break;
+
+	case CTDB_CONTROL_GET_RECLOCK_FILE:
+		fill_ctdb_string(mem_ctx, &cd->data.reclock_file);
+		assert(cd->data.reclock_file != NULL);
+		break;
+
+	case CTDB_CONTROL_SET_RECLOCK_FILE:
+		break;
+
+	case CTDB_CONTROL_STOP_NODE:
+		break;
+
+	case CTDB_CONTROL_CONTINUE_NODE:
+		break;
+
+	case CTDB_CONTROL_SET_NATGWSTATE:
+		break;
+
+	case CTDB_CONTROL_SET_LMASTERROLE:
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTERROLE:
+		break;
+
+	case CTDB_CONTROL_ENABLE_SCRIPT:
+		break;
+
+	case CTDB_CONTROL_DISABLE_SCRIPT:
+		break;
+
+	case CTDB_CONTROL_SET_BAN_STATE:
+		break;
+
+	case CTDB_CONTROL_GET_BAN_STATE:
+		cd->data.ban_state = talloc(mem_ctx, struct ctdb_ban_state);
+		assert(cd->data.ban_state != NULL);
+		fill_ctdb_ban_state(mem_ctx, cd->data.ban_state);
+		break;
+
+	case CTDB_CONTROL_SET_DB_PRIORITY:
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_CANCEL:
+		break;
+
+	case CTDB_CONTROL_REGISTER_NOTIFY:
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_NOTIFY:
+		break;
+
+	case CTDB_CONTROL_TRANS3_COMMIT:
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		cd->data.seqnum = rand64();
+		break;
+
+	case CTDB_CONTROL_DB_SET_HEALTHY:
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		fill_ctdb_string(mem_ctx, &cd->data.reason);
+		assert(cd->data.reason != NULL);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		cd->data.ipinfo = talloc(mem_ctx, struct ctdb_public_ip_info);
+		assert(cd->data.ipinfo != NULL);
+		fill_ctdb_public_ip_info(mem_ctx, cd->data.ipinfo);
+		break;
+
+	case CTDB_CONTROL_GET_IFACES:
+		cd->data.iface_list = talloc(mem_ctx, struct ctdb_iface_list);
+		assert(cd->data.iface_list != NULL);
+		fill_ctdb_iface_list(mem_ctx, cd->data.iface_list);
+		break;
+
+	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+		break;
+
+	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+		break;
+
+	case CTDB_CONTROL_GET_STAT_HISTORY:
+		cd->data.stats_list = talloc(mem_ctx, struct ctdb_statistics_list);
+		assert(cd->data.stats_list != NULL);
+		fill_ctdb_statistics_list(mem_ctx, cd->data.stats_list);
+		break;
+
+	case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+		break;
+
+	case CTDB_CONTROL_SET_DB_READONLY:
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		cd->data.u8_array = talloc(mem_ctx, struct ctdb_uint8_array);
+		assert(cd->data.u8_array != NULL);
+		fill_ctdb_uint8_array(mem_ctx, cd->data.u8_array);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START_EXT:
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		cd->data.dbstats = talloc(mem_ctx, struct ctdb_db_statistics);
+		assert(cd->data.dbstats != NULL);
+		fill_ctdb_db_statistics(mem_ctx, cd->data.dbstats);
+		break;
+
+	case CTDB_CONTROL_SET_DB_STICKY:
+		break;
+
+	case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+		assert(cd->data.recbuf != NULL);
+		fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_IPREALLOCATED:
+		break;
+
+	case CTDB_CONTROL_GET_RUNSTATE:
+		cd->data.runstate = rand32();
+		break;
+
+	case CTDB_CONTROL_DB_DETACH:
+		break;
+
+	case CTDB_CONTROL_GET_NODES_FILE:
+		cd->data.nodemap = talloc(mem_ctx, struct ctdb_node_map);
+		assert(cd->data.nodemap != NULL);
+		fill_ctdb_node_map(mem_ctx, cd->data.nodemap);
+		break;
+
+	}
+}
+
+static void verify_ctdb_reply_control_data(struct ctdb_reply_control_data *cd,
+					   struct ctdb_reply_control_data *cd2)
+{
+	assert(cd->opcode == cd2->opcode);
+
+	switch (cd->opcode) {
+	case CTDB_CONTROL_PROCESS_EXISTS:
+		break;
+
+	case CTDB_CONTROL_STATISTICS:
+		verify_ctdb_statistics(cd->data.stats, cd2->data.stats);
+		break;
+
+	case CTDB_CONTROL_PING:
+		break;
+
+	case CTDB_CONTROL_GETDBPATH:
+		verify_ctdb_string(cd->data.db_path, cd2->data.db_path);
+		break;
+
+	case CTDB_CONTROL_GETVNNMAP:
+		verify_ctdb_vnn_map(cd->data.vnnmap, cd2->data.vnnmap);
+		break;
+
+	case CTDB_CONTROL_SETVNNMAP:
+		break;
+
+	case CTDB_CONTROL_GET_DEBUG:
+		assert(cd->data.loglevel == cd2->data.loglevel);
+		break;
+
+	case CTDB_CONTROL_SET_DEBUG:
+		break;
+
+	case CTDB_CONTROL_GET_DBMAP:
+		verify_ctdb_dbid_map(cd->data.dbmap, cd2->data.dbmap);
+		break;
+
+	case CTDB_CONTROL_PULL_DB:
+		verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_PUSH_DB:
+		break;
+
+	case CTDB_CONTROL_GET_RECMODE:
+		break;
+
+	case CTDB_CONTROL_SET_RECMODE:
+		break;
+
+	case CTDB_CONTROL_STATISTICS_RESET:
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH:
+		assert(cd->data.db_id == cd2->data.db_id);
+		break;
+
+	case CTDB_CONTROL_SET_CALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_DATA:
+		break;
+
+	case CTDB_CONTROL_REGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_SRVID:
+		break;
+
+	case CTDB_CONTROL_GET_DBNAME:
+		verify_ctdb_string(cd->data.db_name, cd2->data.db_name);
+		break;
+
+	case CTDB_CONTROL_ENABLE_SEQNUM:
+		break;
+
+	case CTDB_CONTROL_UPDATE_SEQNUM:
+		break;
+
+	case CTDB_CONTROL_DUMP_MEMORY:
+		verify_ctdb_string(cd->data.mem_str, cd2->data.mem_str);
+		break;
+
+	case CTDB_CONTROL_GET_PID:
+		break;
+
+	case CTDB_CONTROL_GET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTER:
+		break;
+
+	case CTDB_CONTROL_FREEZE:
+		break;
+
+	case CTDB_CONTROL_THAW:
+		break;
+
+	case CTDB_CONTROL_GET_PNN:
+		break;
+
+	case CTDB_CONTROL_SHUTDOWN:
+		break;
+
+	case CTDB_CONTROL_GET_MONMODE:
+		break;
+
+	case CTDB_CONTROL_TCP_CLIENT:
+		break;
+
+	case CTDB_CONTROL_TCP_ADD:
+		break;
+
+	case CTDB_CONTROL_TCP_REMOVE:
+		break;
+
+	case CTDB_CONTROL_STARTUP:
+		break;
+
+	case CTDB_CONTROL_SET_TUNABLE:
+		break;
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		assert(cd->data.tun_value == cd2->data.tun_value);
+		break;
+
+	case CTDB_CONTROL_LIST_TUNABLES:
+		verify_ctdb_var_list(cd->data.tun_var_list,
+				     cd2->data.tun_var_list);
+		break;
+
+	case CTDB_CONTROL_MODIFY_FLAGS:
+		break;
+
+	case CTDB_CONTROL_GET_ALL_TUNABLES:
+		verify_ctdb_tunable_list(cd->data.tun_list, cd2->data.tun_list);
+		break;
+
+	case CTDB_CONTROL_KILL_TCP:
+		break;
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		verify_ctdb_tickle_list(cd->data.tickles, cd2->data.tickles);
+		break;
+
+	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+		break;
+
+	case CTDB_CONTROL_REGISTER_SERVER_ID:
+		break;
+
+	case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+		break;
+
+	case CTDB_CONTROL_CHECK_SERVER_ID:
+		break;
+
+	case CTDB_CONTROL_GET_SERVER_ID_LIST:
+		verify_ctdb_client_id_map(cd->data.cid_map, cd2->data.cid_map);
+		break;
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+		break;
+
+	case CTDB_CONTROL_UPDATE_RECORD:
+		break;
+
+	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_START:
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_COMMIT:
+		break;
+
+	case CTDB_CONTROL_WIPE_DATABASE:
+		break;
+
+	case CTDB_CONTROL_UPTIME:
+		verify_ctdb_uptime(cd->data.uptime, cd2->data.uptime);
+		break;
+
+	case CTDB_CONTROL_START_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_END_RECOVERY:
+		break;
+
+	case CTDB_CONTROL_RELOAD_NODES_FILE:
+		break;
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_ENABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_DISABLE_MONITOR:
+		break;
+
+	case CTDB_CONTROL_ADD_PUBLIC_IP:
+		break;
+
+	case CTDB_CONTROL_DEL_PUBLIC_IP:
+		break;
+
+	case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+		break;
+
+	case CTDB_CONTROL_GET_CAPABILITIES:
+		assert(cd->data.caps == cd2->data.caps);
+		break;
+
+	case CTDB_CONTROL_RECD_PING:
+		break;
+
+	case CTDB_CONTROL_RELEASE_IP:
+		break;
+
+	case CTDB_CONTROL_TAKEOVER_IP:
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IPS:
+		verify_ctdb_public_ip_list(cd->data.pubip_list,
+					   cd2->data.pubip_list);
+		break;
+
+	case CTDB_CONTROL_GET_NODEMAP:
+		verify_ctdb_node_map(cd->data.nodemap, cd2->data.nodemap);
+		break;
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		verify_ctdb_script_list(cd->data.script_list,
+					cd2->data.script_list);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_KILL:
+		break;
+
+	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+		break;
+
+	case CTDB_CONTROL_GET_RECLOCK_FILE:
+		verify_ctdb_string(cd->data.reclock_file,
+				   cd2->data.reclock_file);
+		break;
+
+	case CTDB_CONTROL_SET_RECLOCK_FILE:
+		break;
+
+	case CTDB_CONTROL_STOP_NODE:
+		break;
+
+	case CTDB_CONTROL_CONTINUE_NODE:
+		break;
+
+	case CTDB_CONTROL_SET_NATGWSTATE:
+		break;
+
+	case CTDB_CONTROL_SET_LMASTERROLE:
+		break;
+
+	case CTDB_CONTROL_SET_RECMASTERROLE:
+		break;
+
+	case CTDB_CONTROL_ENABLE_SCRIPT:
+		break;
+
+	case CTDB_CONTROL_DISABLE_SCRIPT:
+		break;
+
+	case CTDB_CONTROL_SET_BAN_STATE:
+		break;
+
+	case CTDB_CONTROL_GET_BAN_STATE:
+		verify_ctdb_ban_state(cd->data.ban_state, cd2->data.ban_state);
+		break;
+
+	case CTDB_CONTROL_SET_DB_PRIORITY:
+		break;
+
+	case CTDB_CONTROL_GET_DB_PRIORITY:
+		break;
+
+	case CTDB_CONTROL_TRANSACTION_CANCEL:
+		break;
+
+	case CTDB_CONTROL_REGISTER_NOTIFY:
+		break;
+
+	case CTDB_CONTROL_DEREGISTER_NOTIFY:
+		break;
+
+	case CTDB_CONTROL_TRANS3_COMMIT:
+		break;
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		assert(cd->data.seqnum == cd2->data.seqnum);
+		break;
+
+	case CTDB_CONTROL_DB_SET_HEALTHY:
+		break;
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		verify_ctdb_string(cd->data.reason, cd2->data.reason);
+		break;
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		verify_ctdb_public_ip_info(cd->data.ipinfo, cd2->data.ipinfo);
+		break;
+
+	case CTDB_CONTROL_GET_IFACES:
+		verify_ctdb_iface_list(cd->data.iface_list,
+				       cd2->data.iface_list);
+		break;
+
+	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+		break;
+
+	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+		break;
+
+	case CTDB_CONTROL_GET_STAT_HISTORY:
+		verify_ctdb_statistics_list(cd->data.stats_list,
+					    cd2->data.stats_list);
+		break;
+
+	case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+		break;
+
+	case CTDB_CONTROL_SET_DB_READONLY:
+		break;
+
+	case CTDB_CONTROL_CHECK_SRVIDS:
+		verify_ctdb_uint8_array(cd->data.u8_array, cd2->data.u8_array);
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_START_EXT:
+		break;
+
+	case CTDB_CONTROL_GET_DB_STATISTICS:
+		verify_ctdb_db_statistics(cd->data.dbstats, cd2->data.dbstats);
+		break;
+
+	case CTDB_CONTROL_SET_DB_STICKY:
+		break;
+
+	case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+		break;
+
+	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+		break;
+
+	case CTDB_CONTROL_RECEIVE_RECORDS:
+		verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+		break;
+
+	case CTDB_CONTROL_IPREALLOCATED:
+		break;
+
+	case CTDB_CONTROL_GET_RUNSTATE:
+		assert(cd->data.runstate == cd2->data.runstate);
+		break;
+
+	case CTDB_CONTROL_DB_DETACH:
+		break;
+
+	case CTDB_CONTROL_GET_NODES_FILE:
+		verify_ctdb_node_map(cd->data.nodemap, cd2->data.nodemap);
+		break;
+
+	}
+}
+
+static void fill_ctdb_reply_control(TALLOC_CTX *mem_ctx,
+				    struct ctdb_reply_control *c,
+				    uint32_t opcode)
+{
+	c->status = -rand_int(2);
+	if (c->status == 0) {
+		c->errmsg = NULL;
+		fill_ctdb_reply_control_data(mem_ctx, &c->rdata, opcode);
+	} else {
+		fill_ctdb_string(mem_ctx, &c->errmsg);
+	}
+}
+
+static void verify_ctdb_reply_control(struct ctdb_reply_control *c,
+				      struct ctdb_reply_control *c2)
+{
+	assert(c->status == c2->status);
+	verify_ctdb_string(c->errmsg, c2->errmsg);
+	if (c->status == 0) {
+		verify_ctdb_reply_control_data(&c->rdata, &c2->rdata);
+	}
+}
+
+static void fill_ctdb_req_message_data(TALLOC_CTX *mem_ctx,
+				       struct ctdb_req_message_data *c)
+{
+	c->srvid = rand64();
+	fill_tdb_data(mem_ctx, &c->data);
+}
+
+static void verify_ctdb_req_message_data(struct ctdb_req_message_data *c,
+					 struct ctdb_req_message_data *c2)
+{
+	assert(c->srvid == c2->srvid);
+	verify_tdb_data(&c->data, &c2->data);
+}
+
+/*
+ * Functions to test marshalling
+ */
+
+static void test_ctdb_req_header(void)
+{
+	TALLOC_CTX *mem_ctx;
+	uint8_t *pkt;
+	size_t pkt_len;
+	struct ctdb_req_header *h, h2;
+	int ret;
+
+	printf("ctdb_req_header\n");
+	fflush(stdout);
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ret = allocate_pkt(mem_ctx, sizeof(struct ctdb_req_header),
+			   &pkt, &pkt_len);
+	assert(ret == 0);
+
+	h = (struct ctdb_req_header *)pkt;
+	ctdb_req_header_fill(h, GENERATION, OPERATION, DESTNODE, SRCNODE,
+			     REQID);
+
+	ret = ctdb_req_header_pull(pkt, pkt_len, &h2);
+	assert(ret == 0);
+
+	verify_ctdb_req_header(h, &h2);
+
+	talloc_free(mem_ctx);
+}
+
+static void test_req_call_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	uint8_t *pkt;
+	size_t pkt_len;
+	int ret;
+	struct ctdb_req_header h, h2;
+	struct ctdb_req_call c, c2;
+
+	printf("ctdb_req_call\n");
+	fflush(stdout);
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_CALL,
+			     DESTNODE, SRCNODE, REQID);
+
+	fill_ctdb_req_call(mem_ctx, &c);
+	ret = ctdb_req_call_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+	assert(ret == 0);
+	ret = ctdb_req_call_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+	assert(ret == 0);
+	verify_ctdb_req_header(&h, &h2);
+	verify_ctdb_req_call(&c, &c2);
+
+	talloc_free(mem_ctx);
+}
+
+static void test_reply_call_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	uint8_t *pkt;
+	size_t pkt_len;
+	int ret;
+	struct ctdb_req_header h, h2;
+	struct ctdb_reply_call c, c2;
+
+	printf("ctdb_reply_call\n");
+	fflush(stdout);
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_CALL,
+			     DESTNODE, SRCNODE, REQID);
+
+	fill_ctdb_reply_call(mem_ctx, &c);
+	ret = ctdb_reply_call_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+	assert(ret == 0);
+	ret = ctdb_reply_call_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+	assert(ret == 0);
+	verify_ctdb_req_header(&h, &h2);
+	verify_ctdb_reply_call(&c, &c2);
+
+	talloc_free(mem_ctx);
+}
+
+static void test_reply_error_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	uint8_t *pkt;
+	size_t pkt_len;
+	int ret;
+	struct ctdb_req_header h, h2;
+	struct ctdb_reply_error c, c2;
+
+	printf("ctdb_reply_error\n");
+	fflush(stdout);
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_ERROR,
+			     DESTNODE, SRCNODE, REQID);
+
+	fill_ctdb_reply_error(mem_ctx, &c);
+	ret = ctdb_reply_error_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+	assert(ret == 0);
+	ret = ctdb_reply_error_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+	assert(ret == 0);
+	verify_ctdb_req_header(&h, &h2);
+	verify_ctdb_reply_error(&c, &c2);
+
+	talloc_free(mem_ctx);
+}
+
+static void test_req_dmaster_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	uint8_t *pkt;
+	size_t pkt_len;
+	int ret;
+	struct ctdb_req_header h, h2;
+	struct ctdb_req_dmaster c, c2;
+
+	printf("ctdb_req_dmaster\n");
+	fflush(stdout);
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_DMASTER,
+			     DESTNODE, SRCNODE, REQID);
+
+	fill_ctdb_req_dmaster(mem_ctx, &c);
+	ret = ctdb_req_dmaster_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+	assert(ret == 0);
+	ret = ctdb_req_dmaster_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+	assert(ret == 0);
+	verify_ctdb_req_header(&h, &h2);
+	verify_ctdb_req_dmaster(&c, &c2);
+
+	talloc_free(mem_ctx);
+}
+
+static void test_reply_dmaster_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	uint8_t *pkt;
+	size_t pkt_len;
+	int ret;
+	struct ctdb_req_header h, h2;
+	struct ctdb_reply_dmaster c, c2;
+
+	printf("ctdb_reply_dmaster\n");
+	fflush(stdout);
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_DMASTER,
+			     DESTNODE, SRCNODE, REQID);
+
+	fill_ctdb_reply_dmaster(mem_ctx, &c);
+	ret = ctdb_reply_dmaster_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+	assert(ret == 0);
+	ret = ctdb_reply_dmaster_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+	assert(ret == 0);
+	verify_ctdb_req_header(&h, &h2);
+	verify_ctdb_reply_dmaster(&c, &c2);
+
+	talloc_free(mem_ctx);
+}
+
+#define NUM_CONTROLS	146
+
+static void test_req_control_data_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	size_t buflen;
+	int ret;
+	struct ctdb_req_control_data cd, cd2;
+	uint32_t opcode;
+
+	printf("ctdb_req_control_data\n");
+	fflush(stdout);
+
+	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
+		mem_ctx = talloc_new(NULL);
+		assert(mem_ctx != NULL);
+
+		printf("%u.. ", opcode);
+		fflush(stdout);
+		fill_ctdb_req_control_data(mem_ctx, &cd, opcode);
+		buflen = ctdb_req_control_data_len(&cd);
+		ctdb_req_control_data_push(&cd, BUFFER);
+		ret = ctdb_req_control_data_pull(BUFFER, buflen, opcode, mem_ctx, &cd2);
+		assert(ret == 0);
+		verify_ctdb_req_control_data(&cd, &cd2);
+		talloc_free(mem_ctx);
+	}
+
+	printf("\n");
+	fflush(stdout);
+}
+
+static void test_reply_control_data_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	size_t buflen;
+	int ret;
+	struct ctdb_reply_control_data cd, cd2;
+	uint32_t opcode;
+
+	printf("ctdb_reply_control_data\n");
+	fflush(stdout);
+
+	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
+		mem_ctx = talloc_new(NULL);
+		assert(mem_ctx != NULL);
+
+		printf("%u.. ", opcode);
+		fflush(stdout);
+		fill_ctdb_reply_control_data(mem_ctx, &cd, opcode);
+		buflen = ctdb_reply_control_data_len(&cd);
+		ctdb_reply_control_data_push(&cd, BUFFER);
+		ret = ctdb_reply_control_data_pull(BUFFER, buflen, opcode, mem_ctx, &cd2);
+		assert(ret == 0);
+		verify_ctdb_reply_control_data(&cd, &cd2);
+		talloc_free(mem_ctx);
+	}
+
+	printf("\n");
+	fflush(stdout);
+}
+
+static void test_req_control_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	uint8_t *pkt;
+	size_t pkt_len;
+	int ret;
+	struct ctdb_req_header h, h2;
+	struct ctdb_req_control c, c2;
+	uint32_t opcode;
+
+	printf("ctdb_req_control\n");
+	fflush(stdout);
+
+	ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_CONTROL,
+			     DESTNODE, SRCNODE, REQID);
+
+	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
+		mem_ctx = talloc_new(NULL);
+		assert(mem_ctx != NULL);
+
+		printf("%u.. ", opcode);
+		fflush(stdout);
+		fill_ctdb_req_control(mem_ctx, &c, opcode);
+		ret = ctdb_req_control_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+		assert(ret == 0);
+		ret = ctdb_req_control_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+		assert(ret == 0);
+		verify_ctdb_req_header(&h, &h2);
+		verify_ctdb_req_control(&c, &c2);
+
+		talloc_free(mem_ctx);
+	}
+
+	printf("\n");
+	fflush(stdout);
+}
+
+static void test_reply_control_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	uint8_t *pkt;
+	size_t pkt_len;
+	int ret;
+	struct ctdb_req_header h, h2;
+	struct ctdb_reply_control c, c2;
+	uint32_t opcode;
+
+	printf("ctdb_reply_control\n");
+	fflush(stdout);
+
+	ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_CONTROL,
+			     DESTNODE, SRCNODE, REQID);
+
+	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
+		mem_ctx = talloc_new(NULL);
+		assert(mem_ctx != NULL);
+
+		printf("%u.. ", opcode);
+		fflush(stdout);
+		fill_ctdb_reply_control(mem_ctx, &c, opcode);
+		ret = ctdb_reply_control_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+		assert(ret == 0);
+		ret = ctdb_reply_control_pull(pkt, pkt_len, opcode, &h2, mem_ctx, &c2);
+		assert(ret == 0);
+		verify_ctdb_req_header(&h, &h2);
+		verify_ctdb_reply_control(&c, &c2);
+
+		talloc_free(mem_ctx);
+	}
+
+	printf("\n");
+	fflush(stdout);
+}
+
+static void test_req_message_test(void)
+{
+	TALLOC_CTX *mem_ctx;
+	uint8_t *pkt;
+	size_t pkt_len;
+	int ret;
+	struct ctdb_req_header h, h2;
+	struct ctdb_req_message_data c, c2;
+
+	printf("ctdb_req_message\n");
+	fflush(stdout);
+
+	mem_ctx = talloc_new(NULL);
+	assert(mem_ctx != NULL);
+
+	ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_MESSAGE,
+			     DESTNODE, SRCNODE, REQID);
+
+	fill_ctdb_req_message_data(mem_ctx, &c);
+	ret = ctdb_req_message_data_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+	assert(ret == 0);
+	ret = ctdb_req_message_data_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+	assert(ret == 0);
+	verify_ctdb_req_header(&h, &h2);
+	verify_ctdb_req_message_data(&c, &c2);
+
+	talloc_free(mem_ctx);
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc == 2) {
+		int seed = atoi(argv[1]);
+		srandom(seed);
+	}
+
+	test_ctdb_req_header();
+
+	test_req_call_test();
+	test_reply_call_test();
+	test_reply_error_test();
+	test_req_dmaster_test();
+	test_reply_dmaster_test();
+
+	test_req_control_data_test();
+	test_reply_control_data_test();
+
+	test_req_control_test();
+	test_reply_control_test();
+
+	test_req_message_test();
+
+	return 0;
+}
diff --git a/ctdb/tests/src/protocol_types_test.c b/ctdb/tests/src/protocol_types_test.c
new file mode 100644
index 0000000..bab104c
--- /dev/null
+++ b/ctdb/tests/src/protocol_types_test.c
@@ -0,0 +1,1287 @@
+/*
+   protocol types tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <assert.h>
+
+#include "protocol/protocol_types.c"
+#include "protocol/protocol_header.c"
+#include "protocol/protocol_call.c"
+#include "protocol/protocol_control.c"
+#include "protocol/protocol_message.c"
+#include "protocol/protocol_packet.c"
+
+uint8_t BUFFER[1024*1024];
+
+/*
+ * Functions to generation random data
+ */
+
+static int rand_int(int max)
+{
+	return random() % max;
+}
+
+static uint8_t rand8(void)
+{
+	uint8_t val = rand_int(256) & 0xff;
+	return val;
+}
+
+static uint32_t rand32(void)
+{
+	return random();
+}
+
+static uint64_t rand64(void)
+{
+	uint64_t t = random();
+	t = (t << 32) | random();
+	return t;
+}
+
+static double rand_double(void)
+{
+	return 1.0 / rand64();
+}
+
+static void fill_buffer(void *p, size_t len)
+{
+	int i;
+	uint8_t *ptr = p;
+
+	for (i=0; i<len; i++) {
+		ptr[i] = rand8();
+	}
+}
+
+static void verify_buffer(void *p1, void *p2, size_t len)
+{
+	if (len > 0) {
+		assert(memcmp(p1, p2, len) == 0);
+	}
+}
+
+/*
+ * Functions to fill and verify data types
+ */
+
+static void fill_tdb_data(TALLOC_CTX *mem_ctx, TDB_DATA *p)
+{
+	p->dsize = rand_int(1024) + 1;
+	p->dptr = talloc_array(mem_ctx, uint8_t, p->dsize);
+	assert(p->dptr != NULL);
+	fill_buffer(p->dptr, p->dsize);
+}
+
+static void verify_tdb_data(TDB_DATA *p1, TDB_DATA *p2)
+{
+	assert(p1->dsize == p2->dsize);
+	verify_buffer(p1->dptr, p2->dptr, p1->dsize);
+}
+
+static void fill_ctdb_statistics(TALLOC_CTX *mem_ctx, struct ctdb_statistics *p)
+{
+	fill_buffer((uint8_t *)p, sizeof(struct ctdb_statistics));
+}
+
+static void verify_ctdb_statistics(struct ctdb_statistics *p1,
+				   struct ctdb_statistics *p2)
+{
+	verify_buffer(p1, p2, sizeof(struct ctdb_statistics));
+}
+
+static void fill_ctdb_vnn_map(TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *p)
+{
+	int i;
+
+	p->generation = rand32();
+	p->size = rand_int(20) + 1;
+	p->map = talloc_array(mem_ctx, uint32_t, p->size);
+	assert(p->map != NULL);
+
+	for (i=0; i<p->size; i++) {
+		p->map[i] = rand32();
+	}
+}
+
+static void verify_ctdb_vnn_map(struct ctdb_vnn_map *p1,
+				struct ctdb_vnn_map *p2)
+{
+	int i;
+
+	assert(p1->generation == p2->generation);
+	assert(p1->size == p2->size);
+	for (i=0; i<p1->size; i++) {
+		assert(p1->map[i] == p2->map[i]);
+	}
+}
+
+static void fill_ctdb_dbid(TALLOC_CTX *mem_ctx, struct ctdb_dbid *p)
+{
+	p->db_id = rand32();
+	p->flags = rand8();
+}
+
+static void verify_ctdb_dbid(struct ctdb_dbid *p1, struct ctdb_dbid *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	assert(p1->flags == p2->flags);
+}
+
+static void fill_ctdb_dbid_map(TALLOC_CTX *mem_ctx, struct ctdb_dbid_map *p)
+{
+	int i;
+
+	p->num = rand_int(40) + 1;
+	p->dbs = talloc_array(mem_ctx, struct ctdb_dbid, p->num);
+	assert(p->dbs != NULL);
+	for (i=0; i<p->num; i++) {
+		fill_ctdb_dbid(mem_ctx, &p->dbs[i]);
+	}
+}
+
+static void verify_ctdb_dbid_map(struct ctdb_dbid_map *p1,
+				 struct ctdb_dbid_map *p2)
+{
+	int i;
+
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		verify_ctdb_dbid(&p1->dbs[i], &p2->dbs[i]);
+	}
+}
+
+static void fill_ctdb_pulldb(TALLOC_CTX *mem_ctx, struct ctdb_pulldb *p)
+{
+	p->db_id = rand32();
+	p->lmaster = rand32();
+}
+
+static void verify_ctdb_pulldb(struct ctdb_pulldb *p1, struct ctdb_pulldb *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	assert(p1->lmaster == p2->lmaster);
+}
+
+static void fill_ctdb_ltdb_header(TALLOC_CTX *mem_ctx,
+				  struct ctdb_ltdb_header *p)
+{
+	p->rsn = rand64();
+	p->dmaster = rand32();
+	p->flags = rand32();
+}
+
+static void verify_ctdb_ltdb_header(struct ctdb_ltdb_header *p1,
+				    struct ctdb_ltdb_header *p2)
+{
+	assert(p1->rsn == p2->rsn);
+	assert(p1->dmaster == p2->dmaster);
+	assert(p1->flags == p2->flags);
+}
+
+static void fill_ctdb_rec_data(TALLOC_CTX *mem_ctx, struct ctdb_rec_data *p)
+{
+	p->reqid = rand32();
+	if (p->reqid % 5 == 0) {
+		p->header = talloc(mem_ctx, struct ctdb_ltdb_header);
+		assert(p->header != NULL);
+		fill_ctdb_ltdb_header(mem_ctx, p->header);
+	} else {
+		p->header = NULL;
+	}
+	fill_tdb_data(mem_ctx, &p->key);
+	fill_tdb_data(mem_ctx, &p->data);
+}
+
+static void verify_ctdb_rec_data(struct ctdb_rec_data *p1,
+				 struct ctdb_rec_data *p2)
+{
+	struct ctdb_ltdb_header header;
+
+	assert(p1->reqid == p2->reqid);
+	if (p1->header != NULL) {
+		assert(ctdb_ltdb_header_extract(&p2->data, &header) == 0);
+		verify_ctdb_ltdb_header(p1->header, &header);
+	}
+	verify_tdb_data(&p1->key, &p2->key);
+	verify_tdb_data(&p1->data, &p2->data);
+}
+
+static void fill_ctdb_rec_buffer(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *p)
+{
+	struct ctdb_rec_data rec;
+	int ret, i;
+	int count;
+
+	p->db_id = rand32();
+	p->count = 0;
+	p->buf = NULL;
+	p->buflen = 0;
+
+	count = rand_int(100) + 1;
+	for (i=0; i<count; i++) {
+		fill_ctdb_rec_data(mem_ctx, &rec);
+		ret = ctdb_rec_buffer_add(mem_ctx, p, rec.reqid, rec.header,
+					  rec.key, rec.data);
+		assert(ret == 0);
+	}
+}
+
+static void verify_ctdb_rec_buffer(struct ctdb_rec_buffer *p1,
+				   struct ctdb_rec_buffer *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	assert(p1->count == p2->count);
+	assert(p1->buflen == p2->buflen);
+	verify_buffer(p1->buf, p2->buf, p1->buflen);
+}
+
+static void fill_ctdb_traverse_start(TALLOC_CTX *mem_ctx,
+				     struct ctdb_traverse_start *p)
+{
+	p->db_id = rand32();
+	p->reqid = rand32();
+	p->srvid = rand64();
+}
+
+static void verify_ctdb_traverse_start(struct ctdb_traverse_start *p1,
+				       struct ctdb_traverse_start *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	assert(p1->reqid == p2->reqid);
+	assert(p1->srvid == p2->srvid);
+}
+
+static void fill_ctdb_traverse_all(TALLOC_CTX *mem_ctx,
+				   struct ctdb_traverse_all *p)
+{
+	p->db_id = rand32();
+	p->reqid = rand32();
+	p->pnn = rand32();
+	p->client_reqid = rand32();
+	p->srvid = rand64();
+}
+
+static void verify_ctdb_traverse_all(struct ctdb_traverse_all *p1,
+				     struct ctdb_traverse_all *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	assert(p1->reqid == p2->reqid);
+	assert(p1->pnn == p2->pnn);
+	assert(p1->client_reqid == p2->client_reqid);
+	assert(p1->srvid == p2->srvid);
+}
+
+static void fill_ctdb_traverse_start_ext(TALLOC_CTX *mem_ctx,
+					 struct ctdb_traverse_start_ext *p)
+{
+	p->db_id = rand32();
+	p->reqid = rand32();
+	p->srvid = rand64();
+	p->withemptyrecords = rand_int(2);
+}
+
+static void verify_ctdb_traverse_start_ext(struct ctdb_traverse_start_ext *p1,
+					   struct ctdb_traverse_start_ext *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	assert(p1->reqid == p2->reqid);
+	assert(p1->srvid == p2->srvid);
+	assert(p1->withemptyrecords == p2->withemptyrecords);
+}
+
+static void fill_ctdb_traverse_all_ext(TALLOC_CTX *mem_ctx,
+				       struct ctdb_traverse_all_ext *p)
+{
+	p->db_id = rand32();
+	p->reqid = rand32();
+	p->pnn = rand32();
+	p->client_reqid = rand32();
+	p->srvid = rand64();
+	p->withemptyrecords = rand_int(2);
+}
+
+static void verify_ctdb_traverse_all_ext(struct ctdb_traverse_all_ext *p1,
+					 struct ctdb_traverse_all_ext *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	assert(p1->reqid == p2->reqid);
+	assert(p1->pnn == p2->pnn);
+	assert(p1->client_reqid == p2->client_reqid);
+	assert(p1->srvid == p2->srvid);
+	assert(p1->withemptyrecords == p2->withemptyrecords);
+}
+
+static void fill_ctdb_sock_addr(TALLOC_CTX *mem_ctx, ctdb_sock_addr *p)
+{
+	if (rand_int(2) == 0) {
+		p->ip.sin_family = AF_INET;
+		p->ip.sin_port = rand_int(65535);
+		fill_buffer(&p->ip.sin_addr, sizeof(struct in_addr));
+	} else {
+		p->ip6.sin6_family = AF_INET6;
+		p->ip6.sin6_port = rand_int(65535);
+		fill_buffer(&p->ip6.sin6_addr, sizeof(struct in6_addr));
+	}
+}
+
+static void verify_ctdb_sock_addr(ctdb_sock_addr *p1, ctdb_sock_addr *p2)
+{
+	assert(p1->sa.sa_family == p2->sa.sa_family);
+	if (p1->sa.sa_family == AF_INET) {
+		assert(p1->ip.sin_port == p2->ip.sin_port);
+		verify_buffer(&p1->ip.sin_addr, &p2->ip.sin_addr,
+				   sizeof(struct in_addr));
+	} else {
+		assert(p1->ip6.sin6_port == p2->ip6.sin6_port);
+		verify_buffer(&p1->ip6.sin6_addr, &p2->ip6.sin6_addr,
+				   sizeof(struct in6_addr));
+	}
+}
+
+static void fill_ctdb_connection(TALLOC_CTX *mem_ctx,
+				 struct ctdb_connection *p)
+{
+	fill_ctdb_sock_addr(mem_ctx, &p->src);
+	fill_ctdb_sock_addr(mem_ctx, &p->dst);
+}
+
+static void verify_ctdb_connection(struct ctdb_connection *p1,
+				   struct ctdb_connection *p2)
+{
+	verify_ctdb_sock_addr(&p1->src, &p2->src);
+	verify_ctdb_sock_addr(&p1->dst, &p2->dst);
+}
+
+static void fill_ctdb_string(TALLOC_CTX *mem_ctx, const char **out)
+{
+	char *p;
+	int len, i;
+
+	len = rand_int(1024) + 1;
+	p = talloc_size(mem_ctx, len+1);
+	assert(p != NULL);
+
+	for (i=0; i<len; i++) {
+		p[i] = 'A' + rand_int(26);
+	}
+	p[len] = '\0';
+	*out = p;
+}
+
+static void verify_ctdb_string(const char *p1, const char *p2)
+{
+	if (p1 == NULL || p2 == NULL) {
+		assert(p1 == p2);
+	} else {
+		assert(strlen(p1) == strlen(p2));
+		assert(strcmp(p1, p2) == 0);
+	}
+}
+
+static void fill_ctdb_tunable(TALLOC_CTX *mem_ctx, struct ctdb_tunable *p)
+{
+	fill_ctdb_string(mem_ctx, discard_const(&p->name));
+	p->value = rand32();
+}
+
+static void verify_ctdb_tunable(struct ctdb_tunable *p1,
+				struct ctdb_tunable *p2)
+{
+	verify_ctdb_string(discard_const(p1->name), discard_const(p2->name));
+	assert(p1->value == p2->value);
+}
+
+static void fill_ctdb_node_flag_change(TALLOC_CTX *mem_ctx,
+				       struct ctdb_node_flag_change *p)
+{
+	p->pnn = rand32();
+	p->new_flags = rand32();
+	p->old_flags = rand32();
+}
+
+static void verify_ctdb_node_flag_change(struct ctdb_node_flag_change *p1,
+					 struct ctdb_node_flag_change *p2)
+{
+	assert(p1->pnn == p2->pnn);
+	assert(p1->new_flags == p2->new_flags);
+	assert(p1->old_flags == p2->old_flags);
+}
+
+static void fill_ctdb_var_list(TALLOC_CTX *mem_ctx,
+			       struct ctdb_var_list *p)
+{
+	int i;
+
+	p->count = rand_int(100) + 1;
+	p->var = talloc_array(mem_ctx, const char *, p->count);
+	for (i=0; i<p->count; i++) {
+		fill_ctdb_string(p->var, discard_const(&p->var[i]));
+	}
+}
+
+static void verify_ctdb_var_list(struct ctdb_var_list *p1,
+				 struct ctdb_var_list *p2)
+{
+	int i;
+
+	assert(p1->count == p2->count);
+	for (i=0; i<p1->count; i++) {
+		verify_ctdb_string(discard_const(p1->var[i]),
+				   discard_const(p2->var[i]));
+	}
+}
+
+static void fill_ctdb_tunable_list(TALLOC_CTX *mem_ctx,
+				   struct ctdb_tunable_list *p)
+{
+	fill_buffer(p, sizeof(struct ctdb_tunable_list));
+}
+
+static void verify_ctdb_tunable_list(struct ctdb_tunable_list *p1,
+				     struct ctdb_tunable_list *p2)
+{
+	verify_buffer(p1, p2, sizeof(struct ctdb_tunable_list));
+}
+
+static void fill_ctdb_tickle_list(TALLOC_CTX *mem_ctx,
+				  struct ctdb_tickle_list *p)
+{
+	int i;
+
+	fill_ctdb_sock_addr(mem_ctx, &p->addr);
+	p->num = rand_int(1000) + 1;
+	p->conn = talloc_array(mem_ctx, struct ctdb_connection, p->num);
+	assert(p->conn != NULL);
+	for (i=0; i<p->num; i++) {
+		fill_ctdb_connection(mem_ctx, &p->conn[i]);
+	}
+}
+
+static void verify_ctdb_tickle_list(struct ctdb_tickle_list *p1,
+				    struct ctdb_tickle_list *p2)
+{
+	int i;
+
+	verify_ctdb_sock_addr(&p1->addr, &p2->addr);
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		verify_ctdb_connection(&p1->conn[i], &p2->conn[i]);
+	}
+}
+
+static void fill_ctdb_client_id(TALLOC_CTX *mem_ctx,
+				struct ctdb_client_id *p)
+{
+	p->type = rand8();
+	p->pnn = rand32();
+	p->server_id = rand32();
+}
+
+static void verify_ctdb_client_id(struct ctdb_client_id *p1,
+				  struct ctdb_client_id *p2)
+{
+	assert(p1->type == p2->type);
+	assert(p1->pnn == p2->pnn);
+	assert(p1->server_id == p2->server_id);
+}
+
+static void fill_ctdb_client_id_list(TALLOC_CTX *mem_ctx,
+				     struct ctdb_client_id_list *p)
+{
+	int i;
+
+	p->num = rand_int(1000) + 1;
+	p->cid = talloc_array(mem_ctx, struct ctdb_client_id, p->num);
+	assert(p->cid != NULL);
+	for (i=0; i<p->num; i++) {
+		fill_ctdb_client_id(mem_ctx, &p->cid[i]);
+	}
+}
+
+static void verify_ctdb_client_id_list(struct ctdb_client_id_list *p1,
+				       struct ctdb_client_id_list *p2)
+{
+	int i;
+
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		verify_ctdb_client_id(&p1->cid[i], &p2->cid[i]);
+	}
+}
+
+static void fill_ctdb_client_id_map(TALLOC_CTX *mem_ctx,
+				    struct ctdb_client_id_map *p)
+{
+	int i;
+
+	p->count = rand_int(10) + 1;
+	p->list = talloc_array(mem_ctx, struct ctdb_client_id_list, p->count);
+	assert(p->list != NULL);
+	for (i=0; i<p->count; i++) {
+		fill_ctdb_client_id_list(mem_ctx, &p->list[i]);
+	}
+}
+
+static void verify_ctdb_client_id_map(struct ctdb_client_id_map *p1,
+				      struct ctdb_client_id_map *p2)
+{
+	int i;
+
+	assert(p1->count == p2->count);
+	for (i=0; i<p1->count; i++) {
+		verify_ctdb_client_id_list(&p1->list[i], &p2->list[i]);
+	}
+}
+
+static void fill_ctdb_addr_info(TALLOC_CTX *mem_ctx, struct ctdb_addr_info *p)
+{
+	fill_ctdb_sock_addr(mem_ctx, &p->addr);
+	p->mask = rand_int(33);
+	if (rand_int(2) == 0) {
+		p->iface = NULL;
+	} else {
+		fill_ctdb_string(mem_ctx, &p->iface);
+	}
+}
+
+static void verify_ctdb_addr_info(struct ctdb_addr_info *p1,
+				  struct ctdb_addr_info *p2)
+{
+	verify_ctdb_sock_addr(&p1->addr, &p2->addr);
+	assert(p1->mask == p2->mask);
+	verify_ctdb_string(p1->iface, p2->iface);
+}
+
+static void fill_ctdb_transdb(TALLOC_CTX *mem_ctx, struct ctdb_transdb *p)
+{
+	p->db_id = rand32();
+	p->tid = rand32();
+}
+
+static void verify_ctdb_transdb(struct ctdb_transdb *p1, struct ctdb_transdb *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	assert(p1->tid == p2->tid);
+}
+
+static void fill_ctdb_uptime(TALLOC_CTX *mem_ctx, struct ctdb_uptime *p)
+{
+	fill_buffer(p, sizeof(struct ctdb_uptime));
+}
+
+static void verify_ctdb_uptime(struct ctdb_uptime *p1, struct ctdb_uptime *p2)
+{
+	verify_buffer(p1, p2, sizeof(struct ctdb_uptime));
+}
+
+static void fill_ctdb_public_ip(TALLOC_CTX *mem_ctx, struct ctdb_public_ip *p)
+{
+	p->pnn = rand32();
+	fill_ctdb_sock_addr(mem_ctx, &p->addr);
+}
+
+static void verify_ctdb_public_ip(struct ctdb_public_ip *p1,
+				  struct ctdb_public_ip *p2)
+{
+	assert(p1->pnn == p2->pnn);
+	verify_ctdb_sock_addr(&p1->addr, &p2->addr);
+}
+
+static void fill_ctdb_public_ip_list(TALLOC_CTX *mem_ctx,
+				     struct ctdb_public_ip_list *p)
+{
+	int i;
+
+	p->num = rand_int(32);
+	if (p->num == 0) {
+		p->ip = NULL;
+		return;
+	}
+	p->ip = talloc_array(mem_ctx, struct ctdb_public_ip, p->num);
+	assert(p->ip != NULL);
+	for (i=0; i<p->num; i++) {
+		fill_ctdb_public_ip(mem_ctx, &p->ip[i]);
+	}
+}
+
+static void verify_ctdb_public_ip_list(struct ctdb_public_ip_list *p1,
+				       struct ctdb_public_ip_list *p2)
+{
+	int i;
+
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		verify_ctdb_public_ip(&p1->ip[i], &p2->ip[i]);
+	}
+}
+
+static void fill_ctdb_node_and_flags(TALLOC_CTX *mem_ctx,
+				     struct ctdb_node_and_flags *p)
+{
+	p->pnn = rand32();
+	p->flags = rand32();
+	fill_ctdb_sock_addr(mem_ctx, &p->addr);
+}
+
+static void verify_ctdb_node_and_flags(struct ctdb_node_and_flags *p1,
+				       struct ctdb_node_and_flags *p2)
+{
+	assert(p1->pnn == p2->pnn);
+	assert(p1->flags == p2->flags);
+	verify_ctdb_sock_addr(&p1->addr, &p2->addr);
+}
+
+static void fill_ctdb_node_map(TALLOC_CTX *mem_ctx, struct ctdb_node_map *p)
+{
+	int i;
+
+	p->num = rand_int(32) + 1;
+	p->node = talloc_array(mem_ctx, struct ctdb_node_and_flags, p->num);
+	assert(p->node != NULL);
+	for (i=0; i<p->num; i++) {
+		fill_ctdb_node_and_flags(mem_ctx, &p->node[i]);
+	}
+}
+
+static void verify_ctdb_node_map(struct ctdb_node_map *p1,
+				 struct ctdb_node_map *p2)
+{
+	int i;
+
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		verify_ctdb_node_and_flags(&p1->node[i], &p2->node[i]);
+	}
+}
+
+static void fill_ctdb_script(TALLOC_CTX *mem_ctx, struct ctdb_script *p)
+{
+	fill_buffer(p, sizeof(struct ctdb_script));
+}
+
+static void verify_ctdb_script(struct ctdb_script *p1, struct ctdb_script *p2)
+{
+	verify_buffer(p1, p2, sizeof(struct ctdb_script));
+}
+
+static void fill_ctdb_script_list(TALLOC_CTX *mem_ctx,
+				  struct ctdb_script_list *p)
+{
+	int i;
+
+	p->num_scripts = rand_int(32) + 1;
+	p->script = talloc_array(mem_ctx, struct ctdb_script, p->num_scripts);
+	assert(p->script != NULL);
+	for (i=0; i<p->num_scripts; i++) {
+		fill_ctdb_script(mem_ctx, &p->script[i]);
+	}
+}
+
+static void verify_ctdb_script_list(struct ctdb_script_list *p1,
+				    struct ctdb_script_list *p2)
+{
+	int i;
+
+	assert(p1->num_scripts == p2->num_scripts);
+	for (i=0; i<p1->num_scripts; i++) {
+		verify_ctdb_script(&p1->script[i], &p2->script[i]);
+	}
+}
+
+static void fill_ctdb_ban_state(TALLOC_CTX *mem_ctx, struct ctdb_ban_state *p)
+{
+	p->pnn = rand32();
+	p->time = rand32();
+}
+
+static void verify_ctdb_ban_state(struct ctdb_ban_state *p1,
+				  struct ctdb_ban_state *p2)
+{
+	assert(p1->pnn == p2->pnn);
+	assert(p1->time == p2->time);
+}
+
+static void fill_ctdb_db_priority(TALLOC_CTX *mem_ctx,
+				  struct ctdb_db_priority *p)
+{
+	p->db_id = rand32();
+	p->priority = rand32();
+}
+
+static void verify_ctdb_db_priority(struct ctdb_db_priority *p1,
+				    struct ctdb_db_priority *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	assert(p1->priority == p2->priority);
+}
+
+static void fill_ctdb_notify_data(TALLOC_CTX *mem_ctx,
+				  struct ctdb_notify_data *p)
+{
+	p->srvid = rand64();
+	fill_tdb_data(mem_ctx, &p->data);
+}
+
+static void verify_ctdb_notify_data(struct ctdb_notify_data *p1,
+				    struct ctdb_notify_data *p2)
+{
+	assert(p1->srvid == p2->srvid);
+	verify_tdb_data(&p1->data, &p2->data);
+}
+
+static void fill_ctdb_iface(TALLOC_CTX *mem_ctx, struct ctdb_iface *p)
+{
+	fill_buffer(p, sizeof(struct ctdb_iface));
+}
+
+static void verify_ctdb_iface(struct ctdb_iface *p1, struct ctdb_iface *p2)
+{
+	verify_buffer(p1, p2, sizeof(struct ctdb_iface));
+}
+
+static void fill_ctdb_iface_list(TALLOC_CTX *mem_ctx,
+				 struct ctdb_iface_list *p)
+{
+	int i;
+
+	p->num = rand_int(32) + 1;
+	p->iface = talloc_array(mem_ctx, struct ctdb_iface, p->num);
+	assert(p->iface != NULL);
+	for (i=0; i<p->num; i++) {
+		fill_ctdb_iface(mem_ctx, &p->iface[i]);
+	}
+}
+
+static void verify_ctdb_iface_list(struct ctdb_iface_list *p1,
+				   struct ctdb_iface_list *p2)
+{
+	int i;
+
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		verify_ctdb_iface(&p1->iface[i], &p2->iface[i]);
+	}
+}
+
+static void fill_ctdb_public_ip_info(TALLOC_CTX *mem_ctx,
+				     struct ctdb_public_ip_info *p)
+{
+	fill_ctdb_public_ip(mem_ctx, &p->ip);
+	p->active_idx = rand_int(32) + 1;
+	p->ifaces = talloc(mem_ctx, struct ctdb_iface_list);
+	assert(p->ifaces != NULL);
+	fill_ctdb_iface_list(mem_ctx, p->ifaces);
+}
+
+static void verify_ctdb_public_ip_info(struct ctdb_public_ip_info *p1,
+				       struct ctdb_public_ip_info *p2)
+{
+	verify_ctdb_public_ip(&p1->ip, &p2->ip);
+	assert(p1->active_idx == p2->active_idx);
+	verify_ctdb_iface_list(p1->ifaces, p2->ifaces);
+}
+
+static void fill_ctdb_statistics_list(TALLOC_CTX *mem_ctx,
+				      struct ctdb_statistics_list *p)
+{
+	int i;
+
+	p->num = rand_int(10) + 1;
+	p->stats = talloc_array(mem_ctx, struct ctdb_statistics, p->num);
+	assert(p->stats != NULL);
+
+	for (i=0; i<p->num; i++) {
+		fill_ctdb_statistics(mem_ctx, &p->stats[i]);
+	}
+}
+
+static void verify_ctdb_statistics_list(struct ctdb_statistics_list *p1,
+					struct ctdb_statistics_list *p2)
+{
+	int i;
+
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		verify_ctdb_statistics(&p1->stats[i], &p2->stats[i]);
+	}
+}
+
+static void fill_ctdb_key_data(TALLOC_CTX *mem_ctx, struct ctdb_key_data *p)
+{
+	p->db_id = rand32();
+	fill_ctdb_ltdb_header(mem_ctx, &p->header);
+	fill_tdb_data(mem_ctx, &p->key);
+}
+
+static void verify_ctdb_key_data(struct ctdb_key_data *p1,
+				 struct ctdb_key_data *p2)
+{
+	assert(p1->db_id == p2->db_id);
+	verify_ctdb_ltdb_header(&p1->header, &p2->header);
+	verify_tdb_data(&p1->key, &p2->key);
+}
+
+static void fill_ctdb_uint8_array(TALLOC_CTX *mem_ctx,
+				  struct ctdb_uint8_array *p)
+{
+	int i;
+
+	p->num = rand_int(1024) + 1;
+	p->val = talloc_array(mem_ctx, uint8_t, p->num);
+	assert(p->val != NULL);
+
+	for (i=0; i<p->num; i++) {
+		p->val[i] = rand8();
+	}
+}
+
+static void verify_ctdb_uint8_array(struct ctdb_uint8_array *p1,
+				    struct ctdb_uint8_array *p2)
+{
+	int i;
+
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		assert(p1->val[i] == p2->val[i]);
+	}
+}
+
+static void fill_ctdb_uint64_array(TALLOC_CTX *mem_ctx,
+				   struct ctdb_uint64_array *p)
+{
+	int i;
+
+	p->num = rand_int(1024) + 1;
+	p->val = talloc_array(mem_ctx, uint64_t, p->num);
+	assert(p->val != NULL);
+
+	for (i=0; i<p->num; i++) {
+		p->val[i] = rand64();
+	}
+}
+
+static void verify_ctdb_uint64_array(struct ctdb_uint64_array *p1,
+				     struct ctdb_uint64_array *p2)
+{
+	int i;
+
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		assert(p1->val[i] == p2->val[i]);
+	}
+}
+
+static void fill_ctdb_db_statistics(TALLOC_CTX *mem_ctx,
+				   struct ctdb_db_statistics *p)
+{
+	int i;
+
+	fill_buffer(p, offsetof(struct ctdb_db_statistics, num_hot_keys));
+	p->num_hot_keys = 10;
+	for (i=0; i<p->num_hot_keys; i++) {
+		p->hot_keys[i].count = rand32();
+		fill_tdb_data(mem_ctx, &p->hot_keys[i].key);
+	}
+}
+
+static void verify_ctdb_db_statistics(struct ctdb_db_statistics *p1,
+				      struct ctdb_db_statistics *p2)
+{
+	int i;
+
+	verify_buffer(p1, p2, offsetof(struct ctdb_db_statistics,
+					    num_hot_keys));
+	assert(p1->num_hot_keys == p2->num_hot_keys);
+	for (i=0; i<p1->num_hot_keys; i++) {
+		assert(p1->hot_keys[i].count == p2->hot_keys[i].count);
+		verify_tdb_data(&p1->hot_keys[i].key, &p2->hot_keys[i].key);
+	}
+}
+
+#ifndef PROTOCOL_TEST
+
+static void fill_ctdb_election_message(TALLOC_CTX *mem_ctx,
+				       struct ctdb_election_message *p)
+{
+	p->num_connected = rand_int(32);
+	fill_buffer(&p->priority_time, sizeof(struct timeval));
+	p->pnn = rand_int(32);
+	p->node_flags = rand32();
+}
+
+static void verify_ctdb_election_message(struct ctdb_election_message *p1,
+					 struct ctdb_election_message *p2)
+{
+	assert(p1->num_connected == p2->num_connected);
+	verify_buffer(p1, p2, sizeof(struct timeval));
+	assert(p1->pnn == p2->pnn);
+	assert(p1->node_flags == p2->node_flags);
+}
+
+static void fill_ctdb_srvid_message(TALLOC_CTX *mem_ctx,
+				    struct ctdb_srvid_message *p)
+{
+	p->pnn = rand_int(32);
+	p->srvid = rand64();
+}
+
+static void verify_ctdb_srvid_message(struct ctdb_srvid_message *p1,
+				      struct ctdb_srvid_message *p2)
+{
+	assert(p1->pnn == p2->pnn);
+	assert(p1->srvid == p2->srvid);
+}
+
+static void fill_ctdb_disable_message(TALLOC_CTX *mem_ctx,
+				      struct ctdb_disable_message *p)
+{
+	p->pnn = rand_int(32);
+	p->srvid = rand64();
+	p->timeout = rand32();
+}
+
+static void verify_ctdb_disable_message(struct ctdb_disable_message *p1,
+					struct ctdb_disable_message *p2)
+{
+	assert(p1->pnn == p2->pnn);
+	assert(p1->srvid == p2->srvid);
+	assert(p1->timeout == p2->timeout);
+}
+
+static void fill_ctdb_server_id(TALLOC_CTX *mem_ctx,
+				struct ctdb_server_id *p)
+{
+	p->pid = rand64();
+	p->task_id = rand32();
+	p->vnn = rand_int(32);
+	p->unique_id = rand64();
+}
+
+static void verify_ctdb_server_id(struct ctdb_server_id *p1,
+				  struct ctdb_server_id *p2)
+{
+	assert(p1->pid == p2->pid);
+	assert(p1->task_id == p2->task_id);
+	assert(p1->vnn == p2->vnn);
+	assert(p1->unique_id == p2->unique_id);
+}
+
+static void fill_ctdb_g_lock(TALLOC_CTX *mem_ctx, struct ctdb_g_lock *p)
+{
+	p->type = rand_int(2);
+	fill_ctdb_server_id(mem_ctx, &p->sid);
+}
+
+static void verify_ctdb_g_lock(struct ctdb_g_lock *p1, struct ctdb_g_lock *p2)
+{
+	assert(p1->type == p2->type);
+	verify_ctdb_server_id(&p1->sid, &p2->sid);
+}
+
+static void fill_ctdb_g_lock_list(TALLOC_CTX *mem_ctx,
+				  struct ctdb_g_lock_list *p)
+{
+	int i;
+
+	p->num = rand_int(20) + 1;
+	p->lock = talloc_array(mem_ctx, struct ctdb_g_lock, p->num);
+	assert(p->lock != NULL);
+	for (i=0; i<p->num; i++) {
+		fill_ctdb_g_lock(mem_ctx, &p->lock[i]);
+	}
+}
+
+static void verify_ctdb_g_lock_list(struct ctdb_g_lock_list *p1,
+				    struct ctdb_g_lock_list *p2)
+{
+	int i;
+
+	assert(p1->num == p2->num);
+	for (i=0; i<p1->num; i++) {
+		verify_ctdb_g_lock(&p1->lock[i], &p2->lock[i]);
+	}
+}
+
+/*
+ * Functions to test marshalling routines
+ */
+
+static void test_ctdb_uint32(void)
+{
+	uint32_t p1, p2;
+	size_t buflen;
+	int ret;
+
+	p1 = rand32();
+	buflen = ctdb_uint32_len(p1);
+	ctdb_uint32_push(p1, BUFFER);
+	ret = ctdb_uint32_pull(BUFFER, buflen, NULL, &p2);
+	assert(ret == 0);
+	assert(p1 == p2);
+}
+
+static void test_ctdb_uint64(void)
+{
+	uint64_t p1, p2;
+	size_t buflen;
+	int ret;
+
+	p1 = rand64();
+	buflen = ctdb_uint64_len(p1);
+	ctdb_uint64_push(p1, BUFFER);
+	ret = ctdb_uint64_pull(BUFFER, buflen, NULL, &p2);
+	assert(ret == 0);
+	assert(p1 == p2);
+}
+
+static void test_ctdb_double(void)
+{
+	double p1, p2;
+	size_t buflen;
+	int ret;
+
+	p1 = rand_double();
+	buflen = ctdb_double_len(p1);
+	ctdb_double_push(p1, BUFFER);
+	ret = ctdb_double_pull(BUFFER, buflen, NULL, &p2);
+	assert(ret == 0);
+	assert(p1 == p2);
+}
+
+static void test_ctdb_pid(void)
+{
+	pid_t p1, p2;
+	size_t buflen;
+	int ret;
+
+	p1 = rand32();
+	buflen = ctdb_pid_len(p1);
+	ctdb_pid_push(p1, BUFFER);
+	ret = ctdb_pid_pull(BUFFER, buflen, NULL, &p2);
+	assert(ret == 0);
+	assert(p1 == p2);
+}
+
+#define TEST_FUNC(NAME)		test_ ##NAME
+#define FILL_FUNC(NAME)		fill_ ##NAME
+#define VERIFY_FUNC(NAME)	verify_ ##NAME
+#define LEN_FUNC(NAME)		NAME## _len
+#define PUSH_FUNC(NAME)		NAME## _push
+#define PULL_FUNC(NAME)		NAME## _pull
+
+#define DEFINE_TEST(TYPE, NAME)	\
+static void TEST_FUNC(NAME)(void) \
+{ \
+	TALLOC_CTX *mem_ctx = talloc_new(NULL); \
+	TYPE *p1, *p2; \
+	size_t buflen; \
+	int ret; \
+\
+	p1 = talloc_zero(mem_ctx, TYPE); \
+	assert(p1 != NULL); \
+	FILL_FUNC(NAME)(p1, p1); \
+	buflen = LEN_FUNC(NAME)(p1); \
+	PUSH_FUNC(NAME)(p1, BUFFER); \
+	ret = PULL_FUNC(NAME)(BUFFER, buflen, mem_ctx, &p2); \
+	assert(ret == 0); \
+	VERIFY_FUNC(NAME)(p1, p2); \
+	talloc_free(mem_ctx); \
+}
+
+
+static void test_ctdb_string(void)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	const char *p1, *p2;
+	size_t buflen;
+	int ret;
+
+	fill_ctdb_string(mem_ctx, &p1);
+	buflen = ctdb_string_len(p1);
+	ctdb_string_push(p1, BUFFER);
+	ret = ctdb_string_pull(BUFFER, buflen, mem_ctx, &p2);
+	assert(ret == 0);
+	verify_ctdb_string(p1, p2);
+	talloc_free(mem_ctx);
+}
+
+static void test_ctdb_stringn(void)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	const char *p1, *p2;
+	size_t buflen;
+	int ret;
+
+	fill_ctdb_string(mem_ctx, &p1);
+	buflen = ctdb_stringn_len(p1);
+	ctdb_stringn_push(p1, BUFFER);
+	ret = ctdb_stringn_pull(BUFFER, buflen, mem_ctx, &p2);
+	assert(ret == 0);
+	verify_ctdb_string(p1, p2);
+	talloc_free(mem_ctx);
+}
+
+static void test_ctdb_ltdb_header(void)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	struct ctdb_ltdb_header p1, p2;
+	size_t buflen;
+	int ret;
+
+	fill_ctdb_ltdb_header(mem_ctx, &p1);
+	buflen = ctdb_ltdb_header_len(&p1);
+	ctdb_ltdb_header_push(&p1, BUFFER);
+	ret = ctdb_ltdb_header_pull(BUFFER, buflen, &p2);
+	assert(ret == 0);
+	verify_ctdb_ltdb_header(&p1, &p2);
+	talloc_free(mem_ctx);
+}
+
+static void test_ctdb_g_lock(void)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	struct ctdb_g_lock p1, p2;
+	size_t buflen;
+	int ret;
+
+	fill_ctdb_g_lock(mem_ctx, &p1);
+	buflen = ctdb_g_lock_len(&p1);
+	ctdb_g_lock_push(&p1, BUFFER);
+	ret = ctdb_g_lock_pull(BUFFER, buflen, &p2);
+	assert(ret == 0);
+	verify_ctdb_g_lock(&p1, &p2);
+	talloc_free(mem_ctx);
+}
+
+DEFINE_TEST(struct ctdb_statistics, ctdb_statistics);
+DEFINE_TEST(struct ctdb_vnn_map, ctdb_vnn_map);
+DEFINE_TEST(struct ctdb_dbid_map, ctdb_dbid_map);
+DEFINE_TEST(struct ctdb_pulldb, ctdb_pulldb);
+DEFINE_TEST(struct ctdb_rec_data, ctdb_rec_data);
+DEFINE_TEST(struct ctdb_rec_buffer, ctdb_rec_buffer);
+DEFINE_TEST(struct ctdb_traverse_start, ctdb_traverse_start);
+DEFINE_TEST(struct ctdb_traverse_all, ctdb_traverse_all);
+DEFINE_TEST(struct ctdb_traverse_start_ext, ctdb_traverse_start_ext);
+DEFINE_TEST(struct ctdb_traverse_all_ext, ctdb_traverse_all_ext);
+DEFINE_TEST(ctdb_sock_addr, ctdb_sock_addr);
+DEFINE_TEST(struct ctdb_connection, ctdb_connection);
+DEFINE_TEST(struct ctdb_tunable, ctdb_tunable);
+DEFINE_TEST(struct ctdb_node_flag_change, ctdb_node_flag_change);
+DEFINE_TEST(struct ctdb_var_list, ctdb_var_list);
+DEFINE_TEST(struct ctdb_tunable_list, ctdb_tunable_list);
+DEFINE_TEST(struct ctdb_tickle_list, ctdb_tickle_list);
+DEFINE_TEST(struct ctdb_client_id, ctdb_client_id);
+DEFINE_TEST(struct ctdb_client_id_list, ctdb_client_id_list);
+DEFINE_TEST(struct ctdb_client_id_map, ctdb_client_id_map);
+DEFINE_TEST(struct ctdb_addr_info, ctdb_addr_info);
+DEFINE_TEST(struct ctdb_transdb, ctdb_transdb);
+DEFINE_TEST(struct ctdb_uptime, ctdb_uptime);
+DEFINE_TEST(struct ctdb_public_ip, ctdb_public_ip);
+DEFINE_TEST(struct ctdb_public_ip_list, ctdb_public_ip_list);
+DEFINE_TEST(struct ctdb_node_and_flags, ctdb_node_and_flags);
+DEFINE_TEST(struct ctdb_node_map, ctdb_node_map);
+DEFINE_TEST(struct ctdb_script, ctdb_script);
+DEFINE_TEST(struct ctdb_script_list, ctdb_script_list);
+DEFINE_TEST(struct ctdb_ban_state, ctdb_ban_state);
+DEFINE_TEST(struct ctdb_db_priority, ctdb_db_priority);
+DEFINE_TEST(struct ctdb_notify_data, ctdb_notify_data);
+DEFINE_TEST(struct ctdb_iface, ctdb_iface);
+DEFINE_TEST(struct ctdb_iface_list, ctdb_iface_list);
+DEFINE_TEST(struct ctdb_public_ip_info, ctdb_public_ip_info);
+DEFINE_TEST(struct ctdb_statistics_list, ctdb_statistics_list);
+DEFINE_TEST(struct ctdb_key_data, ctdb_key_data);
+DEFINE_TEST(struct ctdb_uint8_array, ctdb_uint8_array);
+DEFINE_TEST(struct ctdb_uint64_array, ctdb_uint64_array);
+DEFINE_TEST(struct ctdb_db_statistics, ctdb_db_statistics);
+DEFINE_TEST(struct ctdb_election_message, ctdb_election_message);
+DEFINE_TEST(struct ctdb_srvid_message, ctdb_srvid_message);
+DEFINE_TEST(struct ctdb_disable_message, ctdb_disable_message);
+DEFINE_TEST(struct ctdb_g_lock_list, ctdb_g_lock_list);
+
+int main(int argc, char *argv[])
+{
+	if (argc == 2) {
+		int seed = atoi(argv[1]);
+		srandom(seed);
+	}
+
+	test_ctdb_uint32();
+	test_ctdb_uint64();
+	test_ctdb_double();
+	test_ctdb_pid();
+
+	test_ctdb_string();
+	test_ctdb_stringn();
+
+	test_ctdb_ltdb_header();
+	test_ctdb_g_lock();
+
+	TEST_FUNC(ctdb_statistics)();
+	TEST_FUNC(ctdb_vnn_map)();
+	TEST_FUNC(ctdb_dbid_map)();
+	TEST_FUNC(ctdb_pulldb)();
+	TEST_FUNC(ctdb_rec_data)();
+	TEST_FUNC(ctdb_rec_buffer)();
+	TEST_FUNC(ctdb_traverse_start)();
+	TEST_FUNC(ctdb_traverse_all)();
+	TEST_FUNC(ctdb_traverse_start_ext)();
+	TEST_FUNC(ctdb_traverse_all_ext)();
+	TEST_FUNC(ctdb_sock_addr)();
+	TEST_FUNC(ctdb_connection)();
+	TEST_FUNC(ctdb_tunable)();
+	TEST_FUNC(ctdb_node_flag_change)();
+	TEST_FUNC(ctdb_var_list)();
+	TEST_FUNC(ctdb_tunable_list)();
+	TEST_FUNC(ctdb_tickle_list)();
+	TEST_FUNC(ctdb_client_id)();
+	TEST_FUNC(ctdb_client_id_list)();
+	TEST_FUNC(ctdb_client_id_map)();
+	TEST_FUNC(ctdb_addr_info)();
+	TEST_FUNC(ctdb_transdb)();
+	TEST_FUNC(ctdb_uptime)();
+	TEST_FUNC(ctdb_public_ip)();
+	TEST_FUNC(ctdb_public_ip_list)();
+	TEST_FUNC(ctdb_node_and_flags)();
+	TEST_FUNC(ctdb_node_map)();
+	TEST_FUNC(ctdb_script)();
+	TEST_FUNC(ctdb_script_list)();
+	TEST_FUNC(ctdb_ban_state)();
+	TEST_FUNC(ctdb_db_priority)();
+	TEST_FUNC(ctdb_notify_data)();
+	TEST_FUNC(ctdb_iface)();
+	TEST_FUNC(ctdb_iface_list)();
+	TEST_FUNC(ctdb_public_ip_info)();
+	TEST_FUNC(ctdb_statistics_list)();
+	TEST_FUNC(ctdb_key_data)();
+	TEST_FUNC(ctdb_uint8_array)();
+	TEST_FUNC(ctdb_uint64_array)();
+	TEST_FUNC(ctdb_db_statistics)();
+	TEST_FUNC(ctdb_election_message)();
+	TEST_FUNC(ctdb_srvid_message)();
+	TEST_FUNC(ctdb_disable_message)();
+	TEST_FUNC(ctdb_g_lock_list)();
+
+	return 0;
+}
+
+#endif
diff --git a/ctdb/tests/src/rb_test.c b/ctdb/tests/src/rb_test.c
index 44842e6..1f94fd1 100644
--- a/ctdb/tests/src/rb_test.c
+++ b/ctdb/tests/src/rb_test.c
@@ -17,15 +17,22 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "lib/util/dlinklist.h"
+#include "replace.h"
 #include "system/filesys.h"
-#include "popt.h"
-#include "cmdline.h"
+#include "system/network.h"
+#include "system/time.h"
+
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/dlinklist.h"
+
+#include "ctdb_private.h"
 
-#include <sys/time.h>
-#include <time.h>
 #include "common/rb_tree.h"
+#include "common/cmdline.h"
+#include "common/common.h"
 
 static struct timeval tp1,tp2;
 
diff --git a/ctdb/tests/src/reqid_test.c b/ctdb/tests/src/reqid_test.c
new file mode 100644
index 0000000..ec0c4a5
--- /dev/null
+++ b/ctdb/tests/src/reqid_test.c
@@ -0,0 +1,72 @@
+/*
+   reqid tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include <assert.h>
+
+#include "common/reqid.c"
+
+
+int main(void)
+{
+	struct reqid_context *reqid_ctx;
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	int i, ret;
+	uint32_t reqid;
+	int *data, *tmp;
+
+	ret = reqid_init(mem_ctx, INT_MAX-200, &reqid_ctx);
+	assert(ret == 0);
+
+	data = talloc_zero(mem_ctx, int);
+	assert(data != 0);
+
+	for (i=0; i<1024*1024; i++) {
+		reqid = reqid_new(reqid_ctx, data);
+		assert(reqid != -1);
+	}
+
+	for (i=0; i<1024; i++) {
+		tmp = reqid_find(reqid_ctx, i, int);
+		assert(tmp == data);
+	}
+
+	for (i=0; i<1024; i++) {
+		ret = reqid_remove(reqid_ctx, i);
+		assert(ret == 0);
+	}
+
+	for (i=0; i<1024; i++) {
+		tmp = reqid_find(reqid_ctx, i, int);
+		assert(tmp == NULL);
+	}
+
+	for (i=0; i<1024; i++) {
+		ret = reqid_remove(reqid_ctx, i);
+		assert(ret == ENOENT);
+	}
+
+	talloc_free(reqid_ctx);
+	assert(talloc_get_size(mem_ctx) == 0);
+
+	talloc_free(mem_ctx);
+
+	return 0;
+}
diff --git a/ctdb/tests/src/srvid_test.c b/ctdb/tests/src/srvid_test.c
new file mode 100644
index 0000000..f5e94ac
--- /dev/null
+++ b/ctdb/tests/src/srvid_test.c
@@ -0,0 +1,78 @@
+/*
+   srvid tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include <assert.h>
+
+#include "common/db_hash.c"
+#include "common/srvid.c"
+
+#define TEST_SRVID	0xFE11223344556677
+
+static void test_handler(uint64_t srvid, TDB_DATA data, void *private_data)
+{
+	int *count = (int *)private_data;
+	(*count)++;
+}
+
+int main(void)
+{
+	struct srvid_context *srv;
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	int ret;
+	int count = 0;
+
+	ret = srvid_init(mem_ctx, &srv);
+	assert(ret == 0);
+
+	ret = srvid_register(srv, tmp_ctx, TEST_SRVID, test_handler, &count);
+	assert(ret == 0);
+
+	ret = srvid_exists(srv, TEST_SRVID);
+	assert(ret == 0);
+
+	ret = srvid_dispatch(srv, TEST_SRVID, 0, tdb_null);
+	assert(ret == 0);
+	assert(count == 1);
+
+	ret = srvid_deregister(srv, TEST_SRVID, NULL);
+	assert(ret == ENOENT);
+
+	ret = srvid_deregister(srv, TEST_SRVID, &count);
+	assert(ret == 0);
+
+	ret = srvid_register(srv, tmp_ctx, TEST_SRVID, test_handler, &count);
+	assert(ret == 0);
+
+	talloc_free(tmp_ctx);
+	ret = srvid_exists(srv, TEST_SRVID);
+	assert(ret == ENOENT);
+
+	ret = srvid_dispatch(srv, TEST_SRVID, 0, tdb_null);
+	assert(ret == ENOENT);
+
+	talloc_free(srv);
+	assert(talloc_get_size(mem_ctx) == 0);
+
+	talloc_free(mem_ctx);
+
+	return 0;
+}
diff --git a/ctdb/tests/takeover/scripts/local.sh b/ctdb/tests/takeover/scripts/local.sh
index a84f58b..60375f0 100644
--- a/ctdb/tests/takeover/scripts/local.sh
+++ b/ctdb/tests/takeover/scripts/local.sh
@@ -1,6 +1,6 @@
 # Hey Emacs, this is a -*- shell-script -*- !!!  :-)
 
-test_prog="ctdb_takeover_tests ctdb_takeover_run_core"
+test_prog="ctdb_takeover_tests ipalloc"
 
 define_test ()
 {
diff --git a/ctdb/tests/takeover/simulation/ctdb_takeover.py b/ctdb/tests/takeover/simulation/ctdb_takeover.py
index 4b7ceef..1aeeaca 100755
--- a/ctdb/tests/takeover/simulation/ctdb_takeover.py
+++ b/ctdb/tests/takeover/simulation/ctdb_takeover.py
@@ -761,7 +761,7 @@ class Cluster(object):
         # Written while asleep...
 
         # Convert the cluster state to something that be fed to
-        # ctdb_takeover_tests ctdb_takeover_run_core ...
+        # ctdb_takeover_tests ipalloc ...
 
         in_lines = []
         for ip in sorted(list(self.all_public_ips)):
@@ -786,7 +786,7 @@ class Cluster(object):
         else:
             os.environ["CTDB_TEST_LOGLEVEL"] = "0"
 
-        p = subprocess.Popen("../../bin/ctdb_takeover_tests ctdb_takeover_run_core %s 2>&1" % nodestates,
+        p = subprocess.Popen("../../bin/ctdb_takeover_tests ipalloc %s 2>&1" % nodestates,
                              shell=True,
                              stdin=subprocess.PIPE, stdout=subprocess.PIPE)
         p.stdin.write("\n".join(in_lines))
diff --git a/ctdb/tests/test_check_tcp_ports.sh b/ctdb/tests/test_check_tcp_ports.sh
index e439b6d..1272d88 100755
--- a/ctdb/tests/test_check_tcp_ports.sh
+++ b/ctdb/tests/test_check_tcp_ports.sh
@@ -2,7 +2,8 @@
 
 DIRNAME=$(dirname $0)
 
-. ${DIRNAME}/../config/functions
+CTDB_BASE="${DIRNAME}/../config"
+. "${CTDB_BASE}/functions"
 
 SERVICE="test-service"
 
diff --git a/ctdb/tests/tool/scripts/local.sh b/ctdb/tests/tool/scripts/local.sh
index 737cb71..f85262b 100644
--- a/ctdb/tests/tool/scripts/local.sh
+++ b/ctdb/tests/tool/scripts/local.sh
@@ -1,5 +1,11 @@
 # Hey Emacs, this is a -*- shell-script -*- !!!  :-)
 
+# Augment PATH with stubs/ directory.
+
+if [ -d "${TEST_SUBDIR}/stubs" ] ; then
+    PATH="${TEST_SUBDIR}/stubs:$PATH"
+fi
+
 if "$TEST_VERBOSE" ; then
     debug () { echo "$@" ; }
 else
@@ -14,12 +20,14 @@ define_test ()
 	func.*)
 	    _func="${_f#func.}"
 	    _func="${_func%.*}" # Strip test number
-	    test_prog="ctdb_functest ${_func}"
+	    export CTDB_TEST_PROG="ctdb_functest"
+	    test_args="$_func"
 	    ;;
 	stubby.*)
 	    _cmd="${_f#stubby.}"
 	    _cmd="${_cmd%.*}" # Strip test number
-	    test_prog="ctdb_stubtest ${_cmd}"
+	    export CTDB_TEST_PROG="ctdb_stubtest"
+	    test_args="$_cmd"
 	    ;;
 	*)
 	    die "Unknown pattern for testcase \"$_f\""
@@ -30,16 +38,26 @@ define_test ()
 
 setup_natgw ()
 {
-    debug "Setting up NAT gateway"
+	debug "Setting up NAT gateway"
 
-    natgw_config_dir="${TEST_VAR_DIR}/natgw_config"
-    mkdir -p "$natgw_config_dir"
+	# Use in-tree binaries if running against local daemons.
+	# Otherwise CTDB need to be installed on all nodes.
+	if [ -n "$ctdb_dir" -a -d "${ctdb_dir}/bin" ] ; then
+		if [ -z "$CTDB_NATGW_HELPER" ] ; then
+			export CTDB_NATGW_HELPER="${ctdb_dir}/tools/ctdb_natgw"
+		fi
+		# Only want to find functions file, so this is OK
+		export CTDB_BASE="${ctdb_dir}/config"
+	fi
 
-    # These will accumulate, 1 per test... but will be cleaned up at
-    # the end.
-    export CTDB_NATGW_NODES=$(mktemp --tmpdir="$natgw_config_dir")
+	natgw_config_dir="${TEST_VAR_DIR}/natgw_config"
+	mkdir -p "$natgw_config_dir"
+
+	# These will accumulate, 1 per test... but will be cleaned up
+	# at the end.
+	export CTDB_NATGW_NODES=$(mktemp --tmpdir="$natgw_config_dir")
 
-    cat >"$CTDB_NATGW_NODES"
+	cat >"$CTDB_NATGW_NODES"
 }
 
 setup_nodes ()
@@ -71,5 +89,5 @@ simple_test ()
     : ${CTDB_DEBUGLEVEL:=3}
     export CTDB_DEBUGLEVEL
 
-    unit_test $test_prog "$@"
+    unit_test ctdb $test_args "$@"
 }
diff --git a/ctdb/tests/tool/stubby.getcapabilities.001.sh b/ctdb/tests/tool/stubby.getcapabilities.001.sh
index df4a659..e89f7a0 100755
--- a/ctdb/tests/tool/stubby.getcapabilities.001.sh
+++ b/ctdb/tests/tool/stubby.getcapabilities.001.sh
@@ -8,7 +8,6 @@ required_result 0 <<EOF
 RECMASTER: YES
 LMASTER: YES
 LVS: NO
-NATGW: YES
 EOF
 
 simple_test <<EOF
diff --git a/ctdb/tests/tool/stubby.getcapabilities.002.sh b/ctdb/tests/tool/stubby.getcapabilities.002.sh
index 9a37c4a..112a912 100755
--- a/ctdb/tests/tool/stubby.getcapabilities.002.sh
+++ b/ctdb/tests/tool/stubby.getcapabilities.002.sh
@@ -8,7 +8,6 @@ required_result 0 <<EOF
 RECMASTER: YES
 LMASTER: YES
 LVS: NO
-NATGW: YES
 EOF
 
 simple_test <<EOF
diff --git a/ctdb/tests/tool/stubby.getcapabilities.004.sh b/ctdb/tests/tool/stubby.getcapabilities.004.sh
index d3e24b4..4412883 100755
--- a/ctdb/tests/tool/stubby.getcapabilities.004.sh
+++ b/ctdb/tests/tool/stubby.getcapabilities.004.sh
@@ -10,7 +10,7 @@ input="\
 NODEMAP
 0       192.168.20.41   0x0     CURRENT RECMASTER CTDB_CAP_LVS
 1       192.168.20.42   0x0	-CTDB_CAP_LMASTER
-2       192.168.20.43   0x0	-CTDB_CAP_RECMASTER -CTDB_CAP_NATGW
+2       192.168.20.43   0x0	-CTDB_CAP_RECMASTER
 
 IFACES
 :Name:LinkStatus:References:
@@ -27,7 +27,6 @@ required_result 0 <<EOF
 RECMASTER: YES
 LMASTER: YES
 LVS: YES
-NATGW: YES
 EOF
 
 simple_test -n 0 <<EOF
@@ -38,7 +37,6 @@ required_result 0 <<EOF
 RECMASTER: YES
 LMASTER: NO
 LVS: NO
-NATGW: YES
 EOF
 
 simple_test -n 1 <<EOF
@@ -49,7 +47,6 @@ required_result 0 <<EOF
 RECMASTER: NO
 LMASTER: YES
 LVS: NO
-NATGW: NO
 EOF
 
 simple_test -n 2 <<EOF
diff --git a/ctdb/tests/tool/stubby.natgwlist.006.sh b/ctdb/tests/tool/stubby.natgwlist.006.sh
index 4ed95ca..6de8e12 100755
--- a/ctdb/tests/tool/stubby.natgwlist.006.sh
+++ b/ctdb/tests/tool/stubby.natgwlist.006.sh
@@ -2,10 +2,10 @@
 
 . "${TEST_SCRIPTS_DIR}/unit.sh"
 
-define_test "3 nodes, node 0 missing NATGW capability, all stopped"
+define_test "3 nodes, node 0 is slave-only, all stopped"
 
 setup_natgw <<EOF
-192.168.20.41
+192.168.20.41	slave-only
 192.168.20.42
 192.168.20.43
 EOF
@@ -20,7 +20,7 @@ EOF
 
 simple_test <<EOF
 NODEMAP
-0       192.168.20.41   0x20	-CTDB_CAP_NATGW
+0       192.168.20.41   0x20
 1       192.168.20.42   0x20    CURRENT RECMASTER
 2       192.168.20.43   0x20
 
diff --git a/ctdb/tests/tool/stubby.natgwlist.007.sh b/ctdb/tests/tool/stubby.natgwlist.007.sh
index 855dcc6..563d867 100755
--- a/ctdb/tests/tool/stubby.natgwlist.007.sh
+++ b/ctdb/tests/tool/stubby.natgwlist.007.sh
@@ -2,12 +2,12 @@
 
 . "${TEST_SCRIPTS_DIR}/unit.sh"
 
-define_test "3 nodes, node 0 missing NATGW capability, all stopped"
+define_test "3 nodes, all nodes are slave-only, all stopped"
 
 setup_natgw <<EOF
-192.168.20.41
-192.168.20.42
-192.168.20.43
+192.168.20.41	slave-only
+192.168.20.42	slave-only
+192.168.20.43	slave-only
 EOF
 
 required_result 2 <<EOF
@@ -20,9 +20,9 @@ EOF
 
 simple_test <<EOF
 NODEMAP
-0       192.168.20.41   0x20	-CTDB_CAP_NATGW
-1       192.168.20.42   0x20    CURRENT RECMASTER -CTDB_CAP_NATGW
-2       192.168.20.43   0x20	-CTDB_CAP_NATGW
+0       192.168.20.41   0x20
+1       192.168.20.42   0x20    CURRENT RECMASTER
+2       192.168.20.43   0x20
 
 VNNMAP
 654321
diff --git a/ctdb/tests/tool/stubby.natgwlist.009.sh b/ctdb/tests/tool/stubby.natgwlist.009.sh
deleted file mode 100755
index d802971..0000000
--- a/ctdb/tests/tool/stubby.natgwlist.009.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "3 nodes, all in natgw group, 1 actual time-out"
-
-setup_natgw <<EOF
-192.168.20.41
-192.168.20.42
-192.168.20.43
-EOF
-
-required_result 255 <<EOF
-${TEST_DATE_STAMP}__LOCATION__ control timed out. reqid:1234567890 opcode:80 dstnode:0
-${TEST_DATE_STAMP}__LOCATION__ ctdb_control_recv failed
-${TEST_DATE_STAMP}__LOCATION__ ctdb_ctrl_getcapabilities_recv failed
-${TEST_DATE_STAMP}Unable to get capabilities from node 0
-EOF
-
-simple_test <<EOF
-NODEMAP
-0       192.168.20.41   0x0     TIMEOUT
-1       192.168.20.42   0x0     CURRENT RECMASTER
-2       192.168.20.43   0x0
-
-VNNMAP
-654321
-0
-1
-2
-
-IFACES
-:Name:LinkStatus:References:
-:eth2:1:2:
-:eth1:1:4:
-EOF
diff --git a/ctdb/tests/tool/stubby.natgwlist.010.sh b/ctdb/tests/tool/stubby.natgwlist.010.sh
deleted file mode 100755
index aaa3161..0000000
--- a/ctdb/tests/tool/stubby.natgwlist.010.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "3 nodes, all in natgw group, 1 potential time-out"
-
-setup_natgw <<EOF
-192.168.20.41
-192.168.20.42
-192.168.20.43
-EOF
-
-required_result 0 <<EOF
-0 192.168.20.41
-Number of nodes:3
-pnn:0 192.168.20.41    OK (THIS NODE)
-pnn:1 192.168.20.42    OK
-pnn:2 192.168.20.43    OK
-EOF
-
-simple_test <<EOF
-NODEMAP
-0       192.168.20.41   0x0     CURRENT RECMASTER
-1       192.168.20.42   0x0
-2       192.168.20.43   0x0     TIMEOUT
-
-VNNMAP
-654321
-0
-1
-2
-
-IFACES
-:Name:LinkStatus:References:
-:eth2:1:2:
-:eth1:1:4:
-EOF
diff --git a/ctdb/tests/tool/stubby.nodestatus.002.sh b/ctdb/tests/tool/stubby.nodestatus.002.sh
index f5b1909..a3a7a42 100755
--- a/ctdb/tests/tool/stubby.nodestatus.002.sh
+++ b/ctdb/tests/tool/stubby.nodestatus.002.sh
@@ -2,19 +2,19 @@
 
 . "${TEST_SCRIPTS_DIR}/unit.sh"
 
-define_test "-n all, 3 nodes, all OK"
+define_test "all, 3 nodes, 1 disconnected"
 
-required_result 0 <<EOF
+required_result 1 <<EOF
 Number of nodes:3
 pnn:0 192.168.20.41    OK
-pnn:1 192.168.20.42    OK
+pnn:1 192.168.20.42    DISCONNECTED|INACTIVE
 pnn:2 192.168.20.43    OK (THIS NODE)
 EOF
 
 simple_test all <<EOF
 NODEMAP
 0       192.168.20.41   0x0
-1       192.168.20.42   0x0
+1       192.168.20.42   0x1
 2       192.168.20.43   0x0     CURRENT RECMASTER
 
 IFACES
diff --git a/ctdb/tests/tool/stubby.nodestatus.003.sh b/ctdb/tests/tool/stubby.nodestatus.003.sh
deleted file mode 100755
index a3a7a42..0000000
--- a/ctdb/tests/tool/stubby.nodestatus.003.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "all, 3 nodes, 1 disconnected"
-
-required_result 1 <<EOF
-Number of nodes:3
-pnn:0 192.168.20.41    OK
-pnn:1 192.168.20.42    DISCONNECTED|INACTIVE
-pnn:2 192.168.20.43    OK (THIS NODE)
-EOF
-
-simple_test all <<EOF
-NODEMAP
-0       192.168.20.41   0x0
-1       192.168.20.42   0x1
-2       192.168.20.43   0x0     CURRENT RECMASTER
-
-IFACES
-:Name:LinkStatus:References:
-:eth2:1:2:
-:eth1:1:4:
-
-VNNMAP
-654321
-0
-1
-2
-EOF
diff --git a/ctdb/tests/tool/stubby.nodestatus.004.sh b/ctdb/tests/tool/stubby.nodestatus.004.sh
deleted file mode 100755
index bc98905..0000000
--- a/ctdb/tests/tool/stubby.nodestatus.004.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "-n all, 3 nodes, 1 disconnected"
-
-# -n all asks each node for the node status and 
-#        thus reports THIS NODE for each node
-
-required_result 0 <<EOF
-pnn:0 192.168.20.41    OK (THIS NODE)
-pnn:2 192.168.20.43    OK (THIS NODE)
-EOF
-
-simple_test -n all <<EOF
-NODEMAP
-0       192.168.20.41   0x0
-1       192.168.20.42   0x1
-2       192.168.20.43   0x0     CURRENT RECMASTER
-
-IFACES
-:Name:LinkStatus:References:
-:eth2:1:2:
-:eth1:1:4:
-
-VNNMAP
-654321
-0
-1
-2
-EOF
diff --git a/ctdb/tests/tool/stubby.nodestatus.005.sh b/ctdb/tests/tool/stubby.nodestatus.005.sh
deleted file mode 100755
index cb532e7..0000000
--- a/ctdb/tests/tool/stubby.nodestatus.005.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/sh
-
-. "${TEST_SCRIPTS_DIR}/unit.sh"
-
-define_test "-n all all, 3 nodes, 1 disconnected"
-
-required_result 1 <<EOF
-Number of nodes:3
-pnn:0 192.168.20.41    OK (THIS NODE)
-pnn:1 192.168.20.42    DISCONNECTED|INACTIVE
-pnn:2 192.168.20.43    OK
-Number of nodes:3
-pnn:0 192.168.20.41    OK
-pnn:1 192.168.20.42    DISCONNECTED|INACTIVE
-pnn:2 192.168.20.43    OK (THIS NODE)
-EOF
-
-simple_test -n all all <<EOF
-NODEMAP
-0       192.168.20.41   0x0
-1       192.168.20.42   0x1
-2       192.168.20.43   0x0     CURRENT RECMASTER
-
-IFACES
-:Name:LinkStatus:References:
-:eth2:1:2:
-:eth1:1:4:
-
-VNNMAP
-654321
-0
-1
-2
-EOF
diff --git a/ctdb/tests/tool/stubs/ctdb b/ctdb/tests/tool/stubs/ctdb
new file mode 100755
index 0000000..c6e1e70
--- /dev/null
+++ b/ctdb/tests/tool/stubs/ctdb
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# If "ctdb" is called several time in a test then it must always get
+# the same input.  So, it is read here the first time and then fed to
+# all future instances.
+if [ -z "$_CTDB_TOOL_STUB_INPUT" ] ; then
+    if ! tty -s ; then
+	_CTDB_TOOL_STUB_INPUT=$(cat)
+    else
+	_CTDB_TOOL_STUB_INPUT=""
+    fi
+    # Let's not try being subtle about whether this variable is unset
+    # or empty.  If we've been here then it is set, even if input was
+    # empty.
+    if [ -z "$_CTDB_TOOL_STUB_INPUT" ] ; then
+	_CTDB_TOOL_STUB_INPUT="@@@EMPTY@@@"
+    fi
+    export _CTDB_TOOL_STUB_INPUT
+fi
+
+if [ "$_CTDB_TOOL_STUB_INPUT" != "@@@EMPTY@@@" ] ; then
+    exec "$CTDB_TEST_PROG" "$@" <<EOF
+$_CTDB_TOOL_STUB_INPUT
+EOF
+else
+    exec "$CTDB_TEST_PROG" "$@" </dev/null
+fi
diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c
index c5689c2..9061642 100644
--- a/ctdb/tools/ctdb.c
+++ b/ctdb/tools/ctdb.c
@@ -18,19 +18,34 @@
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/time.h"
 #include "system/filesys.h"
 #include "system/network.h"
 #include "system/locale.h"
-#include "popt.h"
-#include "cmdline.h"
-#include "../include/ctdb_version.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
+
+#include <popt.h>
+#include <talloc.h>
+/* Allow use of deprecated function tevent_loop_allow_nesting() */
+#define TEVENT_DEPRECATED
+#include <tevent.h>
+#include <tdb.h>
+
 #include "lib/tdb_wrap/tdb_wrap.h"
 #include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/substitute.h"
+#include "lib/util/time.h"
+
+#include "ctdb_version.h"
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/rb_tree.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
 
 #define ERR_TIMEOUT	20	/* timed out trying to reach node */
 #define ERR_NONODE	21	/* node does not exist */
@@ -230,7 +245,7 @@ static bool parse_nodestring(struct ctdb_context *ctdb,
 	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
 	int n;
 	uint32_t i;
-	struct ctdb_node_map *nodemap;
+	struct ctdb_node_map_old *nodemap;
 	int ret;
 
 	*nodes = NULL;
@@ -349,7 +364,7 @@ static bool db_exists(struct ctdb_context *ctdb, const char *dbarg,
 		      uint32_t *dbid, const char **dbname, uint8_t *flags)
 {
 	int i, ret;
-	struct ctdb_dbid_map *dbmap=NULL;
+	struct ctdb_dbid_map_old *dbmap=NULL;
 	bool dbid_given = false, found = false;
 	uint32_t id;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
@@ -368,19 +383,19 @@ static bool db_exists(struct ctdb_context *ctdb, const char *dbarg,
 
 	for(i=0; i<dbmap->num; i++) {
 		if (dbid_given) {
-			if (id == dbmap->dbs[i].dbid) {
+			if (id == dbmap->dbs[i].db_id) {
 				found = true;
 				break;
 			}
 		} else {
-			ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, tmp_ctx, &name);
+			ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, tmp_ctx, &name);
 			if (ret != 0) {
-				DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].dbid));
+				DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].db_id));
 				goto fail;
 			}
 
 			if (strcmp(name, dbarg) == 0) {
-				id = dbmap->dbs[i].dbid;
+				id = dbmap->dbs[i].db_id;
 				found = true;
 				break;
 			}
@@ -388,9 +403,9 @@ static bool db_exists(struct ctdb_context *ctdb, const char *dbarg,
 	}
 
 	if (found && dbid_given && dbname != NULL) {
-		ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, tmp_ctx, &name);
+		ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, tmp_ctx, &name);
 		if (ret != 0) {
-			DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].dbid));
+			DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].db_id));
 			found = false;
 			goto fail;
 		}
@@ -685,7 +700,7 @@ static int control_statistics_reset(struct ctdb_context *ctdb, int argc, const c
 static int control_stats(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int ret;
-	struct ctdb_statistics_wire *stats;
+	struct ctdb_statistics_list_old *stats;
 	int i, num_records = -1;
 
 	assert_single_node_only();
@@ -718,7 +733,7 @@ static int control_stats(struct ctdb_context *ctdb, int argc, const char **argv)
 static int control_dbstatistics(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_db_statistics *dbstat;
+	struct ctdb_db_statistics_old *dbstat;
 	int i;
 	uint32_t db_id;
 	int num_hot_keys;
@@ -871,7 +886,7 @@ static int control_pnn(struct ctdb_context *ctdb, int argc, const char **argv)
 }
 
 
-static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx)
+static struct ctdb_node_map_old *read_nodes_file(TALLOC_CTX *mem_ctx)
 {
 	const char *nodes_list;
 
@@ -897,7 +912,7 @@ static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx)
 static int find_node_xpnn(void)
 {
 	TALLOC_CTX *mem_ctx = talloc_new(NULL);
-	struct ctdb_node_map *node_map;
+	struct ctdb_node_map_old *node_map;
 	int i, pnn;
 
 	node_map = read_nodes_file(mem_ctx);
@@ -946,7 +961,7 @@ static bool is_partially_online(struct ctdb_context *ctdb, struct ctdb_node_and_
 	bool ret = false;
 
 	if (node->flags == 0) {
-		struct ctdb_control_get_ifaces *ifaces;
+		struct ctdb_iface_list_old *ifaces;
 
 		if (ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(), node->pnn,
 					 tmp_ctx, &ifaces) == 0) {
@@ -1006,7 +1021,7 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	int i;
 	struct ctdb_vnn_map *vnnmap=NULL;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	uint32_t recmode, recmaster, mypnn;
 	int num_deleted_nodes = 0;
 	int ret;
@@ -1091,7 +1106,7 @@ static int control_nodestatus(struct ctdb_context *ctdb, int argc, const char **
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	int i, ret;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	uint32_t * nodes;
 	uint32_t pnn_mode, mypnn;
 
@@ -1135,79 +1150,23 @@ static int control_nodestatus(struct ctdb_context *ctdb, int argc, const char **
 	return ret;
 }
 
-static struct ctdb_node_map *read_natgw_nodes_file(struct ctdb_context *ctdb,
-						   TALLOC_CTX *mem_ctx)
-{
-	const char *natgw_list;
-	struct ctdb_node_map *natgw_nodes = NULL;
-
-	natgw_list = getenv("CTDB_NATGW_NODES");
-	if (natgw_list == NULL) {
-		natgw_list = talloc_asprintf(mem_ctx, "%s/natgw_nodes",
-					     getenv("CTDB_BASE"));
-		if (natgw_list == NULL) {
-			DEBUG(DEBUG_ALERT,(__location__ " Out of memory\n"));
-			exit(1);
-		}
-	}
-	/* The PNNs/flags will be junk but they're not used */
-	natgw_nodes = ctdb_read_nodes_file(mem_ctx, natgw_list);
-	if (natgw_nodes == NULL) {
-		DEBUG(DEBUG_ERR,
-		      ("Failed to load natgw node list '%s'\n", natgw_list));
-	}
-	return natgw_nodes;
-}
-
-
 /* talloc off the existing nodemap... */
-static struct ctdb_node_map *talloc_nodemap(struct ctdb_node_map *nodemap)
+static struct ctdb_node_map_old *talloc_nodemap(struct ctdb_node_map_old *nodemap)
 {
 	return talloc_zero_size(nodemap,
-				offsetof(struct ctdb_node_map, nodes) +
+				offsetof(struct ctdb_node_map_old, nodes) +
 				nodemap->num * sizeof(struct ctdb_node_and_flags));
 }
 
-static struct ctdb_node_map *
-filter_nodemap_by_addrs(struct ctdb_context *ctdb,
-			struct ctdb_node_map *nodemap,
-			struct ctdb_node_map *natgw_nodes)
-{
-	int i, j;
-	struct ctdb_node_map *ret;
-
-	ret = talloc_nodemap(nodemap);
-	CTDB_NO_MEMORY_NULL(ctdb, ret);
-
-	ret->num = 0;
-
-	for (i = 0; i < nodemap->num; i++) {
-		for(j = 0; j < natgw_nodes->num ; j++) {
-			if (nodemap->nodes[j].flags & NODE_FLAGS_DELETED) {
-				continue;
-			}
-			if (ctdb_same_ip(&natgw_nodes->nodes[j].addr,
-					 &nodemap->nodes[i].addr)) {
-
-				ret->nodes[ret->num] = nodemap->nodes[i];
-				ret->num++;
-				break;
-			}
-		}
-	}
-
-	return ret;
-}
-
-static struct ctdb_node_map *
+static struct ctdb_node_map_old *
 filter_nodemap_by_capabilities(struct ctdb_context *ctdb,
-			       struct ctdb_node_map *nodemap,
+			       struct ctdb_node_map_old *nodemap,
 			       uint32_t required_capabilities,
 			       bool first_only)
 {
 	int i;
 	uint32_t capabilities;
-	struct ctdb_node_map *ret;
+	struct ctdb_node_map_old *ret;
 
 	ret = talloc_nodemap(nodemap);
 	CTDB_NO_MEMORY_NULL(ctdb, ret);
@@ -1245,13 +1204,13 @@ filter_nodemap_by_capabilities(struct ctdb_context *ctdb,
 	return ret;
 }
 
-static struct ctdb_node_map *
+static struct ctdb_node_map_old *
 filter_nodemap_by_flags(struct ctdb_context *ctdb,
-			struct ctdb_node_map *nodemap,
+			struct ctdb_node_map_old *nodemap,
 			uint32_t flags_mask)
 {
 	int i;
-	struct ctdb_node_map *ret;
+	struct ctdb_node_map_old *ret;
 
 	ret = talloc_nodemap(nodemap);
 	CTDB_NO_MEMORY_NULL(ctdb, ret);
@@ -1275,125 +1234,33 @@ filter_nodemap_by_flags(struct ctdb_context *ctdb,
  */
 static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	int i, ret;
-	struct ctdb_node_map *natgw_nodes = NULL;
-	struct ctdb_node_map *orig_nodemap=NULL;
-	struct ctdb_node_map *nodemap;
-	uint32_t mypnn, pnn;
-	const char *ip;
-
-	/* When we have some nodes that could be the NATGW, make a
-	 * series of attempts to find the first node that doesn't have
-	 * certain status flags set.
-	 */
-	uint32_t exclude_flags[] = {
-		/* Look for a nice healthy node */
-		NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_UNHEALTHY,
-		/* If not found, an UNHEALTHY/BANNED node will do */
-		NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED,
-		/* If not found, a STOPPED node will do */
-		NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED,
-		0,
-	};
-
-	/* read the natgw nodes file into a linked list */
-	natgw_nodes = read_natgw_nodes_file(ctdb, tmp_ctx);
-	if (natgw_nodes == NULL) {
-		ret = -1;
-		goto done;
-	}
-
-	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE,
-				   tmp_ctx, &orig_nodemap);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node.\n"));
-		talloc_free(tmp_ctx);
-		return -1;
-	}
-
-	/* Get a nodemap that includes only the nodes in the NATGW
-	 * group */
-	nodemap = filter_nodemap_by_addrs(ctdb, orig_nodemap, natgw_nodes);
-	if (nodemap == NULL) {
-		ret = -1;
-		goto done;
-	}
+	static char prog[PATH_MAX+1] = "";
 
-	ret = 2; /* matches ENOENT */
-	pnn = -1;
-	ip = "0.0.0.0";
-	/* For each flag mask... */
-	for (i = 0; exclude_flags[i] != 0; i++) {
-		/* ... get a nodemap that excludes nodes with with
-		 * masked flags... */
-		struct ctdb_node_map *t =
-			filter_nodemap_by_flags(ctdb, nodemap,
-						exclude_flags[i]);
-		if (t == NULL) {
-			/* No memory */
-			ret = -1;
-			goto done;
-		}
-		if (t->num > 0) {
-			/* ... and find the first node with the NATGW
-			 * capability */
-			struct ctdb_node_map *n;
-			n = filter_nodemap_by_capabilities(ctdb, t,
-							   CTDB_CAP_NATGW,
-							   true);
-			if (n == NULL) {
-				/* No memory */
-				ret = -1;
-				goto done;
-			}
-			if (n->num > 0) {
-				ret = 0;
-				pnn = n->nodes[0].pnn;
-				ip = ctdb_addr_to_str(&n->nodes[0].addr);
-				break;
-			}
-		}
-		talloc_free(t);
+	if (argc != 0) {
+		usage();
 	}
 
-	if (options.machinereadable) {
-		printm(":Node:IP:\n");
-		printm(":%d:%s:\n", pnn, ip);
-	} else {
-		printf("%d %s\n", pnn, ip);
+	if (!ctdb_set_helper("NAT gateway helper", prog, sizeof(prog),
+			     "CTDB_NATGW_HELPER", CTDB_HELPER_BINDIR,
+			     "ctdb_natgw")) {
+		DEBUG(DEBUG_ERR, ("Unable to set NAT gateway helper\n"));
+		exit(1);
 	}
 
-	/* print the pruned list of nodes belonging to this natgw list */
-	mypnn = getpnn(ctdb);
-	if (options.machinereadable) {
-		control_status_header_machine();
-	} else {
-		printf("Number of nodes:%d\n", nodemap->num);
-	}
-	for(i=0;i<nodemap->num;i++){
-		if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
-			continue;
-		}
-		if (options.machinereadable) {
-			control_status_1_machine(ctdb, mypnn, &(nodemap->nodes[i]));
-		} else {
-			control_status_1_human(ctdb, mypnn, &(nodemap->nodes[i]));
-		}
-	}
+	execl(prog, prog, "natgwlist", NULL);
 
-done:
-	talloc_free(tmp_ctx);
-	return ret;
+	DEBUG(DEBUG_ERR,
+	      ("Unable to run NAT gateway helper %s\n", strerror(errno)));
+	exit(1);
 }
 
 /*
   display the status of the scripts for monitoring (or other events)
  */
 static int control_one_scriptstatus(struct ctdb_context *ctdb,
-				    enum ctdb_eventscript_call type)
+				    enum ctdb_event type)
 {
-	struct ctdb_scripts_wire *script_status;
+	struct ctdb_script_list_old *script_status;
 	int ret, i;
 
 	ret = ctdb_ctrl_getscriptstatus(ctdb, TIMELIMIT(), options.pnn, ctdb, type, &script_status);
@@ -1493,7 +1360,7 @@ static int control_scriptstatus(struct ctdb_context *ctdb,
 				int argc, const char **argv)
 {
 	int ret;
-	enum ctdb_eventscript_call type, min, max;
+	enum ctdb_event type, min, max;
 	const char *arg;
 
 	if (argc > 1) {
@@ -1600,7 +1467,7 @@ static int control_recmaster(struct ctdb_context *ctdb, int argc, const char **a
  */
 static int control_add_tickle(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-	struct ctdb_tcp_connection t;
+	struct ctdb_connection t;
 	TDB_DATA data;
 	int ret;
 
@@ -1610,11 +1477,11 @@ static int control_add_tickle(struct ctdb_context *ctdb, int argc, const char **
 		usage();
 	}
 
-	if (parse_ip_port(argv[0], &t.src_addr) == 0) {
+	if (parse_ip_port(argv[0], &t.src) == 0) {
 		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
 		return -1;
 	}
-	if (parse_ip_port(argv[1], &t.dst_addr) == 0) {
+	if (parse_ip_port(argv[1], &t.dst) == 0) {
 		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[1]));
 		return -1;
 	}
@@ -1639,7 +1506,7 @@ static int control_add_tickle(struct ctdb_context *ctdb, int argc, const char **
  */
 static int control_del_tickle(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-	struct ctdb_tcp_connection t;
+	struct ctdb_connection t;
 	TDB_DATA data;
 	int ret;
 
@@ -1649,11 +1516,11 @@ static int control_del_tickle(struct ctdb_context *ctdb, int argc, const char **
 		usage();
 	}
 
-	if (parse_ip_port(argv[0], &t.src_addr) == 0) {
+	if (parse_ip_port(argv[0], &t.src) == 0) {
 		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
 		return -1;
 	}
-	if (parse_ip_port(argv[1], &t.dst_addr) == 0) {
+	if (parse_ip_port(argv[1], &t.dst) == 0) {
 		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[1]));
 		return -1;
 	}
@@ -1678,7 +1545,7 @@ static int control_del_tickle(struct ctdb_context *ctdb, int argc, const char **
  */
 static int control_get_tickles(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-	struct ctdb_control_tcp_tickle_list *list;
+	struct ctdb_tickle_list_old *list;
 	ctdb_sock_addr addr;
 	int i, ret;
 	unsigned port = 0;
@@ -1706,22 +1573,22 @@ static int control_get_tickles(struct ctdb_context *ctdb, int argc, const char *
 
 	if (options.machinereadable){
 		printm(":source ip:port:destination ip:port:\n");
-		for (i=0;i<list->tickles.num;i++) {
-			if (port && port != ntohs(list->tickles.connections[i].dst_addr.ip.sin_port)) {
+		for (i=0;i<list->num;i++) {
+			if (port && port != ntohs(list->connections[i].dst.ip.sin_port)) {
 				continue;
 			}
-			printm(":%s:%u", ctdb_addr_to_str(&list->tickles.connections[i].src_addr), ntohs(list->tickles.connections[i].src_addr.ip.sin_port));
-			printm(":%s:%u:\n", ctdb_addr_to_str(&list->tickles.connections[i].dst_addr), ntohs(list->tickles.connections[i].dst_addr.ip.sin_port));
+			printm(":%s:%u", ctdb_addr_to_str(&list->connections[i].src), ntohs(list->connections[i].src.ip.sin_port));
+			printm(":%s:%u:\n", ctdb_addr_to_str(&list->connections[i].dst), ntohs(list->connections[i].dst.ip.sin_port));
 		}
 	} else {
 		printf("Tickles for ip:%s\n", ctdb_addr_to_str(&list->addr));
-		printf("Num tickles:%u\n", list->tickles.num);
-		for (i=0;i<list->tickles.num;i++) {
-			if (port && port != ntohs(list->tickles.connections[i].dst_addr.ip.sin_port)) {
+		printf("Num tickles:%u\n", list->num);
+		for (i=0;i<list->num;i++) {
+			if (port && port != ntohs(list->connections[i].dst.ip.sin_port)) {
 				continue;
 			}
-			printf("SRC: %s:%u   ", ctdb_addr_to_str(&list->tickles.connections[i].src_addr), ntohs(list->tickles.connections[i].src_addr.ip.sin_port));
-			printf("DST: %s:%u\n", ctdb_addr_to_str(&list->tickles.connections[i].dst_addr), ntohs(list->tickles.connections[i].dst_addr.ip.sin_port));
+			printf("SRC: %s:%u   ", ctdb_addr_to_str(&list->connections[i].src), ntohs(list->connections[i].src.ip.sin_port));
+			printf("DST: %s:%u\n", ctdb_addr_to_str(&list->connections[i].dst), ntohs(list->connections[i].dst.ip.sin_port));
 		}
 	}
 
@@ -1733,13 +1600,13 @@ static int control_get_tickles(struct ctdb_context *ctdb, int argc, const char *
 
 static int move_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr, uint32_t pnn)
 {
-	struct ctdb_all_public_ips *ips;
+	struct ctdb_public_ip_list_old *ips;
 	struct ctdb_public_ip ip;
 	int i, ret;
 	uint32_t *nodes;
 	uint32_t disable_time;
 	TDB_DATA data;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 
 	disable_time = 30;
@@ -1828,8 +1695,8 @@ static int
 find_other_host_for_public_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr)
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_all_public_ips *ips;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_public_ip_list_old *ips;
+	struct ctdb_node_map_old *nodemap=NULL;
 	int i, j, ret;
 	int pnn;
 
@@ -1990,7 +1857,7 @@ static int rebalance_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr)
 	uint32_t *nodes;
 	uint32_t disable_time;
 	TDB_DATA data;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 
 	disable_time = 30;
@@ -2062,7 +1929,7 @@ static int control_rebalanceip(struct ctdb_context *ctdb, int argc, const char *
 static int getips_store_callback(void *param, void *data)
 {
 	struct ctdb_public_ip *node_ip = (struct ctdb_public_ip *)data;
-	struct ctdb_all_public_ips *ips = param;
+	struct ctdb_public_ip_list_old *ips = param;
 	int i;
 
 	i = ips->num++;
@@ -2112,10 +1979,10 @@ static void *add_ip_callback(void *parm, void *data)
 }
 
 static int
-control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struct ctdb_all_public_ips **ips)
+control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struct ctdb_public_ip_list_old **ips)
 {
-	struct ctdb_all_public_ips *tmp_ips;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_public_ip_list_old *tmp_ips;
+	struct ctdb_node_map_old *nodemap=NULL;
 	trbt_tree_t *ip_tree;
 	int i, j, len, ret;
 	uint32_t count;
@@ -2162,7 +2029,7 @@ control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struc
 	count = 0;
 	trbt_traversearray32(ip_tree, IP_KEYLEN, getips_count_callback, &count);
 
-	len = offsetof(struct ctdb_all_public_ips, ips) + 
+	len = offsetof(struct ctdb_public_ip_list_old, ips) +
 		count*sizeof(struct ctdb_public_ip);
 	tmp_ips = talloc_zero_size(tmp_ctx, len);
 	trbt_traversearray32(ip_tree, IP_KEYLEN, getips_store_callback, tmp_ips);
@@ -2173,13 +2040,14 @@ control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struc
 }
 
 
-static void ctdb_every_second(struct event_context *ev, struct timed_event *te, struct timeval t, void *p)
+static void ctdb_every_second(struct tevent_context *ev,
+			      struct tevent_timer *te,
+			      struct timeval t, void *p)
 {
 	struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
 
-	event_add_timed(ctdb->ev, ctdb, 
-				timeval_current_ofs(1, 0),
-				ctdb_every_second, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb, timeval_current_ofs(1, 0),
+			 ctdb_every_second, ctdb);
 }
 
 struct srvid_reply_handler_data {
@@ -2189,9 +2057,7 @@ struct srvid_reply_handler_data {
 	const char *srvid_str;
 };
 
-static void srvid_broadcast_reply_handler(struct ctdb_context *ctdb,
-					 uint64_t srvid,
-					 TDB_DATA data,
+static void srvid_broadcast_reply_handler(uint64_t srvid, TDB_DATA data,
 					 void *private_data)
 {
 	struct srvid_reply_handler_data *d =
@@ -2245,17 +2111,16 @@ static int srvid_broadcast(struct ctdb_context *ctdb,
 	TDB_DATA data;
 	uint32_t pnn;
 	uint64_t reply_srvid;
-	struct srvid_request request;
-	struct srvid_request_data request_data;
+	struct ctdb_srvid_message request;
+	struct ctdb_disable_message request_data;
 	struct srvid_reply_handler_data reply_data;
 	struct timeval tv;
 
 	ZERO_STRUCT(request);
 
 	/* Time ticks to enable timeouts to be processed */
-	event_add_timed(ctdb->ev, ctdb, 
-				timeval_current_ofs(1, 0),
-				ctdb_every_second, ctdb);
+	tevent_add_timer(ctdb->ev, ctdb, timeval_current_ofs(1, 0),
+			 ctdb_every_second, ctdb);
 
 	pnn = ctdb_get_pnn(ctdb);
 	reply_srvid = getpid();
@@ -2269,7 +2134,7 @@ static int srvid_broadcast(struct ctdb_context *ctdb,
 	} else {
 		request_data.pnn = pnn;
 		request_data.srvid = reply_srvid;
-		request_data.data = *arg;
+		request_data.timeout = *arg;
 
 		data.dptr = (uint8_t *)&request_data;
 		data.dsize = sizeof(request_data);
@@ -2288,7 +2153,7 @@ again:
 	reply_data.done = false;
 
 	if (wait_for_all) {
-		struct ctdb_node_map *nodemap;
+		struct ctdb_node_map_old *nodemap;
 
 		ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(),
 					   CTDB_CURRENT_NODE, ctdb, &nodemap);
@@ -2325,7 +2190,7 @@ again:
 	tv = timeval_current();
 	/* This loop terminates the reply is received */
 	while (timeval_elapsed(&tv) < 5.0 && !reply_data.done) {
-		event_loop_once(ctdb->ev);
+		tevent_loop_once(ctdb->ev);
 	}
 
 	if (!reply_data.done) {
@@ -2363,9 +2228,9 @@ static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
 	int len, retries = 0;
 	unsigned mask;
 	ctdb_sock_addr addr;
-	struct ctdb_control_ip_iface *pub;
+	struct ctdb_addr_info_old *pub;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_all_public_ips *ips;
+	struct ctdb_public_ip_list_old *ips;
 
 
 	if (argc != 2) {
@@ -2401,7 +2266,7 @@ static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
 	*/
 	alarm(0);
 
-	len = offsetof(struct ctdb_control_ip_iface, iface) + strlen(argv[1]) + 1;
+	len = offsetof(struct ctdb_addr_info_old, iface) + strlen(argv[1]) + 1;
 	pub = talloc_size(tmp_ctx, len); 
 	CTDB_NO_MEMORY(ctdb, pub);
 
@@ -2468,8 +2333,8 @@ static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv)
 static int control_delip_all(struct ctdb_context *ctdb, int argc, const char **argv, ctdb_sock_addr *addr)
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_node_map *nodemap=NULL;
-	struct ctdb_all_public_ips *ips;
+	struct ctdb_node_map_old *nodemap=NULL;
+	struct ctdb_public_ip_list_old *ips;
 	int ret, i, j;
 
 	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
@@ -2542,9 +2407,9 @@ static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int i, ret;
 	ctdb_sock_addr addr;
-	struct ctdb_control_ip_iface pub;
+	struct ctdb_addr_info_old pub;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_all_public_ips *ips;
+	struct ctdb_public_ip_list_old *ips;
 
 	if (argc != 1) {
 		talloc_free(tmp_ctx);
@@ -2606,7 +2471,7 @@ static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv)
 static int kill_tcp_from_file(struct ctdb_context *ctdb,
 			      int argc, const char **argv)
 {
-	struct ctdb_control_killtcp *killtcp;
+	struct ctdb_connection *killtcp;
 	int max_entries, current, i;
 	struct timeval timeout;
 	char line[128], src[128], dst[128];
@@ -2643,19 +2508,19 @@ static int kill_tcp_from_file(struct ctdb_context *ctdb,
 		if (current >= max_entries) {
 			max_entries += 1024;
 			killtcp = talloc_realloc(ctdb, killtcp,
-						 struct ctdb_control_killtcp,
+						 struct ctdb_connection,
 						 max_entries);
 			CTDB_NO_MEMORY(ctdb, killtcp);
 		}
 
-		if (!parse_ip_port(src, &killtcp[current].src_addr)) {
+		if (!parse_ip_port(src, &killtcp[current].src)) {
 			DEBUG(DEBUG_ERR, ("Bad IP:port on line [%d]: '%s'\n",
 					  linenum, src));
 			talloc_free(killtcp);
 			return -1;
 		}
 
-		if (!parse_ip_port(dst, &killtcp[current].dst_addr)) {
+		if (!parse_ip_port(dst, &killtcp[current].dst)) {
 			DEBUG(DEBUG_ERR, ("Bad IP:port on line [%d]: '%s'\n",
 					  linenum, dst));
 			talloc_free(killtcp);
@@ -2673,7 +2538,7 @@ static int kill_tcp_from_file(struct ctdb_context *ctdb,
 
 	for (i = 0; i < current; i++) {
 
-		data.dsize = sizeof(struct ctdb_control_killtcp);
+		data.dsize = sizeof(struct ctdb_connection);
 		data.dptr  = (unsigned char *)&killtcp[i];
 
 		timeout = TIMELIMIT();
@@ -2709,7 +2574,7 @@ static int kill_tcp_from_file(struct ctdb_context *ctdb,
 static int kill_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int ret;
-	struct ctdb_control_killtcp killtcp;
+	struct ctdb_connection killtcp;
 
 	assert_single_node_only();
 
@@ -2721,12 +2586,12 @@ static int kill_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
 		usage();
 	}
 
-	if (!parse_ip_port(argv[0], &killtcp.src_addr)) {
+	if (!parse_ip_port(argv[0], &killtcp.src)) {
 		DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[0]));
 		return -1;
 	}
 
-	if (!parse_ip_port(argv[1], &killtcp.dst_addr)) {
+	if (!parse_ip_port(argv[1], &killtcp.dst)) {
 		DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[1]));
 		return -1;
 	}
@@ -2775,7 +2640,7 @@ static int control_gratious_arp(struct ctdb_context *ctdb, int argc, const char
 static int regsrvid(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int ret;
-	struct ctdb_server_id server_id;
+	struct ctdb_client_id server_id;
 
 	if (argc < 3) {
 		usage();
@@ -2801,7 +2666,7 @@ static int regsrvid(struct ctdb_context *ctdb, int argc, const char **argv)
 static int unregsrvid(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int ret;
-	struct ctdb_server_id server_id;
+	struct ctdb_client_id server_id;
 
 	if (argc < 3) {
 		usage();
@@ -2826,7 +2691,7 @@ static int chksrvid(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	uint32_t status = 0;
 	int ret;
-	struct ctdb_server_id server_id;
+	struct ctdb_client_id server_id;
 
 	if (argc < 3) {
 		usage();
@@ -2856,7 +2721,7 @@ static int chksrvid(struct ctdb_context *ctdb, int argc, const char **argv)
 static int getsrvids(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int i, ret;
-	struct ctdb_server_id_list *server_ids;
+	struct ctdb_client_id_list_old *server_ids;
 
 	ret = ctdb_ctrl_get_server_id_list(ctdb, ctdb, TIMELIMIT(), options.pnn, &server_ids);
 	if (ret != 0) {
@@ -2951,7 +2816,11 @@ static int control_ip(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int i, ret;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_all_public_ips *ips;
+	struct ctdb_public_ip_list_old *ips;
+
+	if (argc == 1 && strcmp(argv[0], "all") == 0) {
+		options.pnn = CTDB_BROADCAST_ALL;
+	}
 
 	if (options.pnn == CTDB_BROADCAST_ALL) {
 		/* read the list of public ips from all nodes */
@@ -2981,7 +2850,7 @@ static int control_ip(struct ctdb_context *ctdb, int argc, const char **argv)
 	}
 
 	for (i=1;i<=ips->num;i++) {
-		struct ctdb_control_public_ip_info *info = NULL;
+		struct ctdb_public_ip_info_old *info = NULL;
 		int32_t pnn;
 		char *aciface = NULL;
 		char *avifaces = NULL;
@@ -3070,7 +2939,7 @@ static int control_ipinfo(struct ctdb_context *ctdb, int argc, const char **argv
 	int i, ret;
 	ctdb_sock_addr addr;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_control_public_ip_info *info;
+	struct ctdb_public_ip_info_old *info;
 
 	if (argc != 1) {
 		talloc_free(tmp_ctx);
@@ -3121,7 +2990,7 @@ static int control_ifaces(struct ctdb_context *ctdb, int argc, const char **argv
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	int i;
-	struct ctdb_control_get_ifaces *ifaces;
+	struct ctdb_iface_list_old *ifaces;
 	int ret;
 
 	/* read the public ip list from this node */
@@ -3165,7 +3034,7 @@ static int control_setifacelink(struct ctdb_context *ctdb, int argc, const char
 {
 	int ret;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_control_iface_info info;
+	struct ctdb_iface info;
 
 	ZERO_STRUCT(info);
 
@@ -3233,7 +3102,7 @@ static int update_flags_and_ipreallocate(struct ctdb_context *ctdb,
 					      const char *desc,
 					      bool set_flag)
 {
-	struct ctdb_node_map *nodemap = NULL;
+	struct ctdb_node_map_old *nodemap = NULL;
 	bool flag_is_set;
 	int ret;
 
@@ -3403,7 +3272,7 @@ static uint32_t get_generation(struct ctdb_context *ctdb)
 /* Ban a node */
 static bool update_state_banned(struct ctdb_context *ctdb, void *data)
 {
-	struct ctdb_ban_time *bantime = (struct ctdb_ban_time *)data;
+	struct ctdb_ban_state *bantime = (struct ctdb_ban_state *)data;
 	int ret;
 
 	ret = ctdb_ctrl_set_ban(ctdb, TIMELIMIT(), options.pnn, bantime);
@@ -3413,7 +3282,7 @@ static bool update_state_banned(struct ctdb_context *ctdb, void *data)
 
 static int control_ban(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-	struct ctdb_ban_time bantime;
+	struct ctdb_ban_state bantime;
 
 	if (argc < 1) {
 		usage();
@@ -3438,7 +3307,7 @@ static int control_ban(struct ctdb_context *ctdb, int argc, const char **argv)
 /* Unban a node */
 static int control_unban(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-	struct ctdb_ban_time bantime;
+	struct ctdb_ban_state bantime;
 
 	bantime.pnn  = options.pnn;
 	bantime.time = 0;
@@ -3456,8 +3325,8 @@ static int control_unban(struct ctdb_context *ctdb, int argc, const char **argv)
 static int control_showban(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int ret;
-	struct ctdb_node_map *nodemap=NULL;
-	struct ctdb_ban_time *bantime;
+	struct ctdb_node_map_old *nodemap=NULL;
+	struct ctdb_ban_state *bantime;
 
 	/* verify the node exists */
 	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
@@ -3564,19 +3433,17 @@ static int control_getcapabilities(struct ctdb_context *ctdb, int argc, const ch
 		DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", options.pnn));
 		return -1;
 	}
-	
+
 	if (!options.machinereadable){
 		printf("RECMASTER: %s\n", (capabilities&CTDB_CAP_RECMASTER)?"YES":"NO");
 		printf("LMASTER: %s\n", (capabilities&CTDB_CAP_LMASTER)?"YES":"NO");
 		printf("LVS: %s\n", (capabilities&CTDB_CAP_LVS)?"YES":"NO");
-		printf("NATGW: %s\n", (capabilities&CTDB_CAP_NATGW)?"YES":"NO");
 	} else {
-		printm(":RECMASTER:LMASTER:LVS:NATGW:\n");
-		printm(":%d:%d:%d:%d:\n",
+		printm(":RECMASTER:LMASTER:LVS:\n");
+		printm(":%d:%d:%d:\n",
 			!!(capabilities&CTDB_CAP_RECMASTER),
 			!!(capabilities&CTDB_CAP_LMASTER),
-			!!(capabilities&CTDB_CAP_LVS),
-			!!(capabilities&CTDB_CAP_NATGW));
+			!!(capabilities&CTDB_CAP_LVS));
 	}
 	return 0;
 }
@@ -3596,8 +3463,8 @@ static uint32_t lvs_exclude_flags[] = {
 static int control_lvs(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_node_map *orig_nodemap=NULL;
-	struct ctdb_node_map *nodemap;
+	struct ctdb_node_map_old *orig_nodemap=NULL;
+	struct ctdb_node_map_old *nodemap;
 	int i, ret;
 
 	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn,
@@ -3619,7 +3486,7 @@ static int control_lvs(struct ctdb_context *ctdb, int argc, const char **argv)
 	ret = 0;
 
 	for (i = 0; lvs_exclude_flags[i] != 0; i++) {
-		struct ctdb_node_map *t =
+		struct ctdb_node_map_old *t =
 			filter_nodemap_by_flags(ctdb, nodemap,
 						lvs_exclude_flags[i]);
 		if (t == NULL) {
@@ -3649,7 +3516,7 @@ done:
 static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	int i, ret;
 
 	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn,
@@ -3661,7 +3528,7 @@ static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **a
 	}
 
 	for (i = 0; lvs_exclude_flags[i] != 0; i++) {
-		struct ctdb_node_map *t =
+		struct ctdb_node_map_old *t =
 			filter_nodemap_by_flags(ctdb, nodemap,
 						lvs_exclude_flags[i]);
 		if (t == NULL) {
@@ -3670,7 +3537,7 @@ static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **a
 			goto done;
 		}
 		if (t->num > 0) {
-			struct ctdb_node_map *n;
+			struct ctdb_node_map_old *n;
 			n = filter_nodemap_by_capabilities(ctdb,
 							   t,
 							   CTDB_CAP_LVS,
@@ -3772,6 +3639,7 @@ static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv)
 	}
 
 	ZERO_STRUCT(c);
+	c.ctdb = ctdb;
 	c.f = stdout;
 	c.printemptyrecords = (bool)options.printemptyrecords;
 	c.printdatasize = (bool)options.printdatasize;
@@ -3807,6 +3675,7 @@ static int cattdb_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
 	d->count++;
 
 	ZERO_STRUCT(c);
+	c.ctdb = d->ctdb;
 	c.f = stdout;
 	c.printemptyrecords = (bool)options.printemptyrecords;
 	c.printdatasize = (bool)options.printdatasize;
@@ -3814,7 +3683,7 @@ static int cattdb_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
 	c.printhash = (bool)options.printhash;
 	c.printrecordflags = true;
 
-	return ctdb_dumpdb_record(d->ctdb, key, data, &c);
+	return ctdb_dumpdb_record(key, data, &c);
 }
 
 /*
@@ -4591,7 +4460,7 @@ done:
 static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int i, ret;
-	struct ctdb_dbid_map *dbmap=NULL;
+	struct ctdb_dbid_map_old *dbmap=NULL;
 
 	ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &dbmap);
 	if (ret != 0) {
@@ -4610,16 +4479,16 @@ static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **ar
 			bool sticky;
 
 			ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn,
-					    dbmap->dbs[i].dbid, ctdb, &path);
+					    dbmap->dbs[i].db_id, ctdb, &path);
 			ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn,
-					    dbmap->dbs[i].dbid, ctdb, &name);
+					    dbmap->dbs[i].db_id, ctdb, &name);
 			ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn,
-					      dbmap->dbs[i].dbid, ctdb, &health);
+					      dbmap->dbs[i].db_id, ctdb, &health);
 			persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
 			readonly   = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
 			sticky     = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
 			printm(":0x%08X:%s:%s:%d:%d:%d:%d:\n",
-			       dbmap->dbs[i].dbid, name, path,
+			       dbmap->dbs[i].db_id, name, path,
 			       !!(persistent), !!(sticky),
 			       !!(health), !!(readonly));
 		}
@@ -4635,14 +4504,14 @@ static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **ar
 		bool readonly;
 		bool sticky;
 
-		ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &path);
-		ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name);
-		ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &health);
+		ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, ctdb, &path);
+		ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, ctdb, &name);
+		ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, ctdb, &health);
 		persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
 		readonly   = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
 		sticky     = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
 		printf("dbid:0x%08x name:%s path:%s%s%s%s%s\n",
-		       dbmap->dbs[i].dbid, name, path,
+		       dbmap->dbs[i].db_id, name, path,
 		       persistent?" PERSISTENT":"",
 		       sticky?" STICKY":"",
 		       readonly?" READONLY":"",
@@ -4864,7 +4733,8 @@ static int control_getdebug(struct ctdb_context *ctdb, int argc, const char **ar
 		DEBUG(DEBUG_ERR, ("Unable to get debuglevel response from node %u\n", options.pnn));
 		return ret;
 	} else {
-		const char *desc = get_debug_by_level(level);
+		enum debug_level log_level = debug_level_from_int(level);
+		const char *desc = debug_level_to_string(log_level);
 		if (desc == NULL) {
 			/* This should never happen */
 			desc = "Unknown";
@@ -4914,7 +4784,7 @@ static int control_getreclock(struct ctdb_context *ctdb, int argc, const char **
 static int control_setreclock(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int ret;
-	const char *reclock;
+	const char *reclock = NULL;
 
 	if (argc == 0) {
 		reclock = NULL;
@@ -4933,41 +4803,12 @@ static int control_setreclock(struct ctdb_context *ctdb, int argc, const char **
 }
 
 /*
-  set the natgw state on/off
- */
-static int control_setnatgwstate(struct ctdb_context *ctdb, int argc, const char **argv)
-{
-	int ret;
-	uint32_t natgwstate;
-
-	if (argc == 0) {
-		usage();
-	}
-
-	if (!strcmp(argv[0], "on")) {
-		natgwstate = 1;
-	} else if (!strcmp(argv[0], "off")) {
-		natgwstate = 0;
-	} else {
-		usage();
-	}
-
-	ret = ctdb_ctrl_setnatgwstate(ctdb, TIMELIMIT(), options.pnn, natgwstate);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, ("Unable to set the natgw state for node %u\n", options.pnn));
-		return ret;
-	}
-
-	return 0;
-}
-
-/*
   set the lmaster role on/off
  */
 static int control_setlmasterrole(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int ret;
-	uint32_t lmasterrole;
+	uint32_t lmasterrole = 0;
 
 	if (argc == 0) {
 		usage();
@@ -4996,7 +4837,7 @@ static int control_setlmasterrole(struct ctdb_context *ctdb, int argc, const cha
 static int control_setrecmasterrole(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int ret;
-	uint32_t recmasterrole;
+	uint32_t recmasterrole = 0;
 
 	if (argc == 0) {
 		usage();
@@ -5026,19 +4867,22 @@ static int control_setdebug(struct ctdb_context *ctdb, int argc, const char **ar
 {
 	int ret;
 	int32_t level;
+	enum debug_level log_level;
 
 	if (argc == 0) {
 		printf("You must specify the debug level. Valid levels are:\n");
-		print_debug_levels(stdout);
+		printf("\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
 		return 0;
 	}
 
-	if (!parse_debug(argv[0], &level)) {
+	if (!debug_level_parse(argv[0], &log_level)) {
 		printf("Invalid debug level, must be one of\n");
-		print_debug_levels(stdout);
+		printf("\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
 		return -1;
 	}
 
+	level = debug_level_to_int(log_level);
+
 	ret = ctdb_ctrl_set_debuglevel(ctdb, options.pnn, level);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR, ("Unable to set debug level on node %u\n", options.pnn));
@@ -5111,7 +4955,7 @@ static int control_detach(struct ctdb_context *ctdb, int argc,
 	uint32_t db_id;
 	uint8_t flags;
 	int ret, i, status = 0;
-	struct ctdb_node_map *nodemap = NULL;
+	struct ctdb_node_map_old *nodemap = NULL;
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	uint32_t recmode;
 
@@ -5397,7 +5241,7 @@ struct backup_data {
 static int backup_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
 {
 	struct backup_data *bd = talloc_get_type(private, struct backup_data);
-	struct ctdb_rec_data *rec;
+	struct ctdb_rec_data_old *rec;
 
 	/* add the record */
 	rec = ctdb_marshall_record(bd->records, 0, key, NULL, data);
@@ -5578,10 +5422,10 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
 	TDB_DATA data;
 	struct db_file_header dbhdr;
 	struct ctdb_db_context *ctdb_db;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	struct ctdb_vnn_map *vnnmap=NULL;
 	int i, fh;
-	struct ctdb_control_wipe_database w;
+	struct ctdb_transdb w;
 	uint32_t *nodes;
 	uint32_t generation;
 	struct tm *tm;
@@ -5687,7 +5531,7 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
 
 
 	w.db_id = ctdb_db->db_id;
-	w.transaction_id = generation;
+	w.tid = generation;
 
 	data.dptr = (void *)&w;
 	data.dsize = sizeof(w);
@@ -5780,7 +5624,7 @@ static int control_dumpdbbackup(struct ctdb_context *ctdb, int argc, const char
 	int i, fh;
 	struct tm *tm;
 	char tbuf[100];
-	struct ctdb_rec_data *rec = NULL;
+	struct ctdb_rec_data_old *rec = NULL;
 	struct ctdb_marshall_buffer *m;
 	struct ctdb_dump_db_context c;
 
@@ -5824,6 +5668,7 @@ static int control_dumpdbbackup(struct ctdb_context *ctdb, int argc, const char
 		dbhdr.name, m->db_id, tbuf);
 
 	ZERO_STRUCT(c);
+	c.ctdb = ctdb;
 	c.f = stdout;
 	c.printemptyrecords = (bool)options.printemptyrecords;
 	c.printdatasize = (bool)options.printdatasize;
@@ -5839,7 +5684,7 @@ static int control_dumpdbbackup(struct ctdb_context *ctdb, int argc, const char
 		rec = ctdb_marshall_loop_next(m, rec, &reqid,
 					      NULL, &key, &data);
 
-		ctdb_dumpdb_record(ctdb, key, data, &c);
+		ctdb_dumpdb_record(key, data, &c);
 	}
 
 	printf("Dumped %d records\n", i);
@@ -5858,10 +5703,10 @@ static int control_wipedb(struct ctdb_context *ctdb, int argc,
 	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	TDB_DATA data;
 	struct ctdb_db_context *ctdb_db;
-	struct ctdb_node_map *nodemap = NULL;
+	struct ctdb_node_map_old *nodemap = NULL;
 	struct ctdb_vnn_map *vnnmap = NULL;
 	int i;
-	struct ctdb_control_wipe_database w;
+	struct ctdb_transdb w;
 	uint32_t *nodes;
 	uint32_t generation;
 	uint8_t flags;
@@ -5939,7 +5784,7 @@ static int control_wipedb(struct ctdb_context *ctdb, int argc,
 	}
 
 	w.db_id = ctdb_db->db_id;
-	w.transaction_id = generation;
+	w.tid = generation;
 
 	data.dptr = (void *)&w;
 	data.dsize = sizeof(w);
@@ -6033,8 +5878,7 @@ static int control_dumpmemory(struct ctdb_context *ctdb, int argc, const char **
 /*
   handler for memory dumps
 */
-static void mem_dump_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			     TDB_DATA data, void *private_data)
+static void mem_dump_handler(uint64_t srvid, TDB_DATA data, void *private_data)
 {
 	sys_write(1, data.dptr, data.dsize);
 	exit(0);
@@ -6047,7 +5891,7 @@ static int control_rddumpmemory(struct ctdb_context *ctdb, int argc, const char
 {
 	int ret;
 	TDB_DATA data;
-	struct srvid_request rd;
+	struct ctdb_srvid_message rd;
 
 	rd.pnn = ctdb_get_pnn(ctdb);
 	rd.srvid = getpid();
@@ -6068,8 +5912,8 @@ static int control_rddumpmemory(struct ctdb_context *ctdb, int argc, const char
 	}
 
 	/* this loop will terminate when we have received the reply */
-	while (1) {	
-		event_loop_once(ctdb->ev);
+	while (1) {
+		tevent_loop_once(ctdb->ev);
 	}
 
 	return 0;
@@ -6105,8 +5949,8 @@ static int control_msgsend(struct ctdb_context *ctdb, int argc, const char **arg
 /*
   handler for msglisten
 */
-static void msglisten_handler(struct ctdb_context *ctdb, uint64_t srvid, 
-			     TDB_DATA data, void *private_data)
+static void msglisten_handler(uint64_t srvid, TDB_DATA data,
+			      void *private_data)
 {
 	int i;
 
@@ -6131,8 +5975,8 @@ static int control_msglisten(struct ctdb_context *ctdb, int argc, const char **a
 	ctdb_client_set_message_handler(ctdb, srvid, msglisten_handler, NULL);
 	printf("Listening for messages on srvid:%d\n", (int)srvid);
 
-	while (1) {	
-		event_loop_once(ctdb->ev);
+	while (1) {
+		tevent_loop_once(ctdb->ev);
 	}
 
 	return 0;
@@ -6145,7 +5989,7 @@ static int control_msglisten(struct ctdb_context *ctdb, int argc, const char **a
 static int control_listnodes(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	TALLOC_CTX *mem_ctx = talloc_new(NULL);
-	struct ctdb_node_map *node_map;
+	struct ctdb_node_map_old *node_map;
 	int i;
 
 	assert_single_node_only();
@@ -6181,10 +6025,10 @@ static void get_nodes_files_callback(struct ctdb_context *ctdb,
 				     uint32_t node_pnn, int32_t res,
 				     TDB_DATA outdata, void *callback_data)
 {
-	struct ctdb_node_map **maps =
-		talloc_get_type(callback_data, struct ctdb_node_map *);
+	struct ctdb_node_map_old **maps =
+		talloc_get_type(callback_data, struct ctdb_node_map_old *);
 
-	if (outdata.dsize < offsetof(struct ctdb_node_map, nodes) ||
+	if (outdata.dsize < offsetof(struct ctdb_node_map_old, nodes) ||
 	    outdata.dptr == NULL) {
 		DEBUG(DEBUG_ERR,
 		      (__location__ " Invalid return data: %u %p\n",
@@ -6209,17 +6053,17 @@ static void get_nodes_files_fail_callback(struct ctdb_context *ctdb,
 	      ("ERROR: Failed to get nodes file from node %u\n", node_pnn));
 }
 
-static struct ctdb_node_map **
+static struct ctdb_node_map_old **
 ctdb_get_nodes_files(struct ctdb_context *ctdb,
 		     TALLOC_CTX *mem_ctx,
 		     struct timeval timeout,
-		     struct ctdb_node_map *nodemap)
+		     struct ctdb_node_map_old *nodemap)
 {
 	uint32_t *nodes;
 	int ret;
-	struct ctdb_node_map **maps;
+	struct ctdb_node_map_old **maps;
 
-	maps = talloc_zero_array(mem_ctx, struct ctdb_node_map *, nodemap->num);
+	maps = talloc_zero_array(mem_ctx, struct ctdb_node_map_old *, nodemap->num);
 	CTDB_NO_MEMORY_NULL(ctdb, maps);
 
 	nodes = list_of_connected_nodes(ctdb, nodemap, mem_ctx, true);
@@ -6238,8 +6082,8 @@ ctdb_get_nodes_files(struct ctdb_context *ctdb,
 	return maps;
 }
 
-static bool node_files_are_identical(struct ctdb_node_map *nm1,
-				     struct ctdb_node_map *nm2)
+static bool node_files_are_identical(struct ctdb_node_map_old *nm1,
+				     struct ctdb_node_map_old *nm2)
 {
 	int i;
 
@@ -6259,10 +6103,10 @@ static bool node_files_are_identical(struct ctdb_node_map *nm1,
 static bool check_all_node_files_are_identical(struct ctdb_context *ctdb,
 					       TALLOC_CTX *mem_ctx,
 					       struct timeval timeout,
-					       struct ctdb_node_map *nodemap,
-					       struct ctdb_node_map *file_nodemap)
+					       struct ctdb_node_map_old *nodemap,
+					       struct ctdb_node_map_old *file_nodemap)
 {
-	static struct ctdb_node_map **maps;
+	static struct ctdb_node_map_old **maps;
 	int i;
 	bool ret = true;
 
@@ -6290,8 +6134,8 @@ static bool check_all_node_files_are_identical(struct ctdb_context *ctdb,
   reload the nodes file on the local node
  */
 static bool sanity_check_nodes_file_changes(TALLOC_CTX *mem_ctx,
-					    struct ctdb_node_map *nodemap,
-					    struct ctdb_node_map *file_nodemap)
+					    struct ctdb_node_map_old *nodemap,
+					    struct ctdb_node_map_old *file_nodemap)
 {
 	int i;
 	bool should_abort = false;
@@ -6384,9 +6228,9 @@ static void reload_nodes_fail_callback(struct ctdb_context *ctdb,
 static int control_reload_nodes_file(struct ctdb_context *ctdb, int argc, const char **argv)
 {
 	int i, ret;
-	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map_old *nodemap=NULL;
 	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
-	struct ctdb_node_map *file_nodemap;
+	struct ctdb_node_map_old *file_nodemap;
 	uint32_t *conn;
 	uint32_t timeout;
 
@@ -6520,7 +6364,6 @@ static const struct {
 	{ "chksrvid",        chksrvid,			false,	false, "check if a server id exists", "<pnn> <type> <id>" },
 	{ "getsrvids",       getsrvids,			false,	false, "get a list of all server ids"},
 	{ "check_srvids",    check_srvids,		false,	false, "check if a srvid exists", "<id>+" },
-	{ "repack",          ctdb_repack,		false,	false, "repack all databases", "[max_freelist]"},
 	{ "listnodes",       control_listnodes,		false,	true, "list all nodes in the cluster"},
 	{ "reloadnodes",     control_reload_nodes_file,	false,	false, "reload the nodes file and restart the transport on all nodes"},
 	{ "moveip",          control_moveip,		false,	false, "move/failover an ip address to another node", "<ip> <node>"},
@@ -6536,11 +6379,10 @@ static const struct {
 	{ "scriptstatus",     control_scriptstatus,     true,	false, "show the status of the monitoring scripts (or all scripts)", "[all]"},
 	{ "enablescript",     control_enablescript,  true,	false, "enable an eventscript", "<script>"},
 	{ "disablescript",    control_disablescript,  true,	false, "disable an eventscript", "<script>"},
-	{ "natgwlist",        control_natgwlist,        true,	false, "show the nodes belonging to this natgw configuration"},
+	{ "natgwlist",        control_natgwlist,	false,	true, "show the nodes belonging to this natgw configuration"},
 	{ "xpnn",             control_xpnn,             false,	true,  "find the pnn of the local node without talking to the daemon (unreliable)" },
 	{ "getreclock",       control_getreclock,	true,	false, "Show the reclock file of a node"},
 	{ "setreclock",       control_setreclock,	true,	false, "Set/clear the reclock file of a node", "[filename]"},
-	{ "setnatgwstate",    control_setnatgwstate,	false,	false, "Set NATGW state to on/off", "{on|off}"},
 	{ "setlmasterrole",   control_setlmasterrole,	false,	false, "Set LMASTER role to on/off", "{on|off}"},
 	{ "setrecmasterrole", control_setrecmasterrole,	false,	false, "Set RECMASTER role to on/off", "{on|off}"},
 	{ "setdbprio",        control_setdbprio,	false,	false, "Set DB priority", "<dbname|dbid> <prio:1-3>"},
@@ -6627,7 +6469,7 @@ int main(int argc, const char *argv[])
 	int extra_argc = 0;
 	int ret=-1, i;
 	poptContext pc;
-	struct event_context *ev;
+	struct tevent_context *ev;
 	const char *control;
 
 	setlinebuf(stdout);
@@ -6695,7 +6537,7 @@ int main(int argc, const char *argv[])
 	/* Default value for CTDB_BASE - don't override */
 	setenv("CTDB_BASE", CTDB_ETCDIR, 0);
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 	if (!ev) {
 		DEBUG(DEBUG_ERR, ("Failed to initialize event system\n"));
 		exit(1);
diff --git a/ctdb/tools/ctdb_diagnostics b/ctdb/tools/ctdb_diagnostics
index 3f2fa63..a8c8c42 100755
--- a/ctdb/tools/ctdb_diagnostics
+++ b/ctdb/tools/ctdb_diagnostics
@@ -72,14 +72,14 @@ PATH="$PATH:/sbin:/usr/sbin:/usr/lpp/mmfs/bin"
 # list of config files that must exist and that we check are the same 
 # on the nodes
 if [ -d /etc/sysconfig ] ; then
-    CONFIG_FILES_MUST="/etc/krb5.conf /etc/hosts /etc/ctdb/nodes /etc/sysconfig/ctdb /etc/resolv.conf /etc/nsswitch.conf /etc/sysctl.conf /etc/samba/smb.conf /etc/fstab /etc/multipath.conf /etc/pam.d/system-auth /etc/sysconfig/nfs /etc/exports /etc/vsftpd/vsftpd.conf"
+    CONFIG_FILES_MUST="/etc/krb5.conf /etc/hosts /usr/local/etc/ctdb/nodes /etc/sysconfig/ctdb /etc/resolv.conf /etc/nsswitch.conf /etc/sysctl.conf /etc/samba/smb.conf /etc/fstab /etc/multipath.conf /etc/pam.d/system-auth /etc/sysconfig/nfs /etc/exports /etc/vsftpd/vsftpd.conf"
 else
-    CONFIG_FILES_MUST="/etc/krb5.conf /etc/hosts /etc/ctdb/nodes /etc/default/ctdb /etc/resolv.conf /etc/nsswitch.conf /etc/sysctl.conf /etc/samba/smb.conf /etc/fstab /etc/multipath.conf /etc/pam.d/system-auth /etc/default/nfs /etc/exports /etc/vsftpd/vsftpd.conf"
+    CONFIG_FILES_MUST="/etc/krb5.conf /etc/hosts /usr/local/etc/ctdb/nodes /etc/default/ctdb /etc/resolv.conf /etc/nsswitch.conf /etc/sysctl.conf /etc/samba/smb.conf /etc/fstab /etc/multipath.conf /etc/pam.d/system-auth /etc/default/nfs /etc/exports /etc/vsftpd/vsftpd.conf"
 fi
 
 # list of config files that may exist and should be checked that they
 # are the same on the nodes
-CONFIG_FILES_MAY="/etc/ctdb/public_addresses /etc/ctdb/static-routes"
+CONFIG_FILES_MAY="/usr/local/etc/ctdb/public_addresses /usr/local/etc/ctdb/static-routes"
 
 2>&1
 
@@ -181,7 +181,7 @@ cat <<EOF
 For reference, here is the nodes file on the current node...
 EOF
 
-show_file /etc/ctdb/nodes
+show_file /usr/local/etc/ctdb/nodes
 
 cat <<EOF
 --------------------------------------------------------------------
@@ -233,17 +233,17 @@ show_all "ctdb statistics"
 show_all "ctdb uptime"
 show_all "ctdb listvars"
 show_all "ctdb getdbmap"
+show_all "ctdb -X getdbmap | awk -F'|' 'NR > 1 {print \$3}' | sort | xargs -n 1 ctdb dbstatistics"
 
 echo "Showing log.ctdb"
-show_all "test -f /var/log/log.ctdb && tail -100 /var/log/log.ctdb"
+show_all "test -f /usr/local/var/log/log.ctdb && tail -100 /usr/local/var/log/log.ctdb"
 
 echo "Showing log.ctdb"
-show_all "test -f /var/log/log.ctdb && tail -100 /var/log/log.ctdb"
+show_all "test -f /usr/local/var/log/log.ctdb && tail -100 /usr/local/var/log/log.ctdb"
 
 show_all "tail -200 /var/log/messages"
-show_all "tail -200 /etc/ctdb/state/vacuum.log"
-show_all "ls -lRs /var/ctdb"
-show_all "ls -lRs /etc/ctdb"
+show_all "ls -lRs /usr/local/var/lib/ctdb"
+show_all "ls -lRs /usr/local/etc/ctdb"
 
 
 cat <<EOF
diff --git a/ctdb/tools/ctdb_natgw b/ctdb/tools/ctdb_natgw
new file mode 100755
index 0000000..d778c2d
--- /dev/null
+++ b/ctdb/tools/ctdb_natgw
@@ -0,0 +1,199 @@
+#!/bin/sh
+
+if [ -z "$CTDB_BASE" ] ; then
+    export CTDB_BASE="/usr/local/etc/ctdb"
+fi
+
+. "${CTDB_BASE}/functions"
+loadconfig "ctdb"
+
+# Default NAT gateway nodes file location
+[ -n "$CTDB_NATGW_NODES" ] || CTDB_NATGW_NODES="${CTDB_BASE}/natgw_nodes"
+
+[ -n "$CTDB_SOCKET" ] && export CTDB_SOCKET
+
+############################################################
+
+usage ()
+{
+cat <<EOF
+$0 <option>
+
+<option> is one of:
+  master     Display node number and private IP address of master node
+  list       List private IP addresses of nodes in group, annotate master
+  status     Show status of nodes in NAT gateway group
+  natgwlist  Combination of "master" and "status", for backward compatiblity
+EOF
+    exit 1
+}
+
+nodestatus_X=""
+# Fields are:
+# Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode
+get_nodestatus_X ()
+{
+    # Result is cached in global variable nodestatus_X
+    [ -n "$nodestatus_X" ] || \
+	nodestatus_X=$(ctdb -X nodestatus all |
+			      sed -e '1d' -e 's@^|@@' -e 's@|$@@')
+}
+
+get_nodestatus ()
+{
+    # Result is cached in global variable nodestatus
+    [ -n "$nodestatus" ] || nodestatus=$(ctdb nodestatus all)
+    [ $? -ne 255 ] # ctdb nodestatus returns 255 on failure
+}
+
+get_natgw_nodes ()
+{
+    # Result is cached in global variable natgw_nodes
+    if [ -n "$natgw_nodes" ] ; then
+	return
+    fi
+
+    if [ ! -r "$CTDB_NATGW_NODES" ] ; then
+	return 1
+    fi
+
+    natgw_nodes=$(cat "$CTDB_NATGW_NODES") || return 1
+
+    # Sanity check file contents here
+    while read _ip _options ; do
+	# Skip comments
+	case "$_ip" in
+	    \#*) continue ;;
+	esac
+	case "$_options" in
+	    slave-only|"") : ;;
+	    *) die "${prog}: Invalid options \"${_options}\" in  \"$CTDB_NATGW_NODES\""
+	esac
+    done <<EOF
+$natgw_nodes
+EOF
+
+    return 0
+}
+
+# Print the PNN and IP address of the NAT gateway master node
+find_master ()
+{
+    get_natgw_nodes || \
+	die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
+    get_nodestatus_X  || \
+	die "${prog}: Unable to get status of nodes"
+
+    # $_ms is an @-delimited list of nodes that are allowed to be the master
+    _ms="@"
+    while read _ip _options ; do
+	case "$_options" in
+	    "") _ms="${_ms}${_ip}@" ;;
+	esac
+    done <<EOF
+$natgw_nodes
+EOF
+
+    # Now filter by $ms and by status of nodes...
+
+    # Note that the 3 awk invocations below have "||" between them, so
+    # the first to succeed will select the master node.
+
+    # First try for a fully active and healthy node, so must not be
+    # DISABLED, UNHEALTHY or INACTIVE (last covers DISCONNECTED,
+    # BANNED or STOPPED)
+    awk -F '|' -v ms="$_ms" \
+	'BEGIN { ret = 2 }
+	 ms ~ "@" $2 "@" && \
+	     $5 == 0 && $6 == 0 && $8 == 0 { print $1, $2 ; ret=0 ; exit }
+	 END { exit ret }' <<EOF ||
+$nodestatus_X
+EOF
+    # Not found?  UNHEALTHY/BANNED will do, so node must not be
+    # DISCONNECTED, DISABLED or STOPPED
+    awk -F '|' -v ms="$_ms" \
+	'BEGIN { ret = 2 }
+	 ms ~ "@" $2 "@" && \
+	     $3 == 0 && $5 == 0 && $7 == 0 { print $1, $2 ; ret=0 ; exit }
+	 END { exit ret }' <<EOF ||
+$nodestatus_X
+EOF
+    # Not found?  STOPPED will do, so node must not be DISCONNECTED or
+    # DISABLED
+    awk -F '|' -v ms="$_ms" \
+	'BEGIN { ret = 2 }
+	 ms ~ "@" $2 "@" && \
+	     $3 == 0 && $5 == 0 { print $1, $2 ; ret=0 ; exit }
+	 END { exit ret }' <<EOF
+$nodestatus_X
+EOF
+}
+
+# List all nodes in the NAT gateway group, annotating the master node
+nodes_list ()
+{
+    get_natgw_nodes || \
+	die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
+    set -- $(find_master)  || \
+	die "${prog}: Unable to determine NAT gateway master node"
+    _master_ip="$2"
+
+    # Annotate the master node
+    while read _ip _options ; do
+	if [ "$_ip" = "$_master_ip" ] ; then
+	    _options="MASTER${_options:+,}${_options}"
+	fi
+	printf "${_ip}\t${_options}\n"
+    done <<EOF
+$natgw_nodes
+EOF
+}
+
+# Print the status of all nodes in the NAT gateway group, along with a count
+nodes_status ()
+{
+    get_natgw_nodes || \
+	die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
+    get_nodestatus || \
+	die "${prog}: Unable to get status of nodes"
+
+    # $_ns is a @-delimited list of nodes in the NAT gateway group
+    _ns="@"
+    while read _ip _options ; do
+	_ns="${_ns}${_ip}@"
+    done <<EOF
+$natgw_nodes
+EOF
+
+    # Print status of nodes in $_ns, along with node count
+    awk -v ns="$_ns" \
+	'BEGIN { out = "" ; count = 0 } \
+         ns ~ "@" $2 "@" { out =  out "\n" $0 ; count += 1 } \
+         END { print "Number of nodes:" count out }' <<EOF
+$nodestatus
+EOF
+}
+
+# For backward compatibility
+natgwlist ()
+{
+    ret=0
+    find_master
+    if [ $? -eq 2 ] ; then
+	echo "-1 0.0.0.0"
+	ret=2
+    fi
+    nodes_status || return $?
+    return $ret
+}
+
+prog=$(basename "$0")
+cmd="$1"
+
+case "$cmd" in
+    master)    find_master ;;
+    list)      nodes_list ;;
+    status)    nodes_status ;;
+    natgwlist) natgwlist ;;
+    *)         usage ;;
+esac
diff --git a/ctdb/tools/ctdb_vacuum.c b/ctdb/tools/ctdb_vacuum.c
deleted file mode 100644
index ae93682..0000000
--- a/ctdb/tools/ctdb_vacuum.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/* 
-   ctdb control tool - database vacuum 
-
-   Copyright (C) Andrew Tridgell  2008
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "system/filesys.h"
-#include "system/network.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
-#include "lib/tdb_wrap/tdb_wrap.h"
-
-/* should be tunable */
-#define TIMELIMIT() timeval_current_ofs(10, 0)
-
-
-struct vacuum_traverse_state {
-	bool error;
-	struct tdb_context *dest_db;
-};
-
-/*
-  traverse function for repacking
- */
-static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
-{
-	struct vacuum_traverse_state *state = (struct vacuum_traverse_state *)private;
-	if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
-		state->error = true;
-		return -1;
-	}
-	return 0;
-}
-
-/*
-  repack a tdb
- */
-static int ctdb_repack_tdb(struct tdb_context *tdb)
-{
-	struct tdb_context *tmp_db;
-	struct vacuum_traverse_state state;
-
-	if (tdb_transaction_start(tdb) != 0) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction\n"));
-		return -1;
-	}
-
-	tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb),
-			  TDB_INTERNAL|TDB_DISALLOW_NESTING,
-			  O_RDWR|O_CREAT, 0);
-	if (tmp_db == NULL) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to create tmp_db\n"));
-		tdb_transaction_cancel(tdb);
-		return -1;
-	}
-
-	state.error = false;
-	state.dest_db = tmp_db;
-
-	if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying out\n"));
-		tdb_transaction_cancel(tdb);
-		tdb_close(tmp_db);
-		return -1;		
-	}
-
-	if (state.error) {
-		DEBUG(DEBUG_ERR,(__location__ " Error during traversal\n"));
-		tdb_transaction_cancel(tdb);
-		tdb_close(tmp_db);
-		return -1;
-	}
-
-	if (tdb_wipe_all(tdb) != 0) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to wipe database\n"));
-		tdb_transaction_cancel(tdb);
-		tdb_close(tmp_db);
-		return -1;
-	}
-
-	state.error = false;
-	state.dest_db = tdb;
-
-	if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying back\n"));
-		tdb_transaction_cancel(tdb);
-		tdb_close(tmp_db);
-		return -1;		
-	}
-
-	if (state.error) {
-		DEBUG(DEBUG_ERR,(__location__ " Error during second traversal\n"));
-		tdb_transaction_cancel(tdb);
-		tdb_close(tmp_db);
-		return -1;
-	}
-
-	tdb_close(tmp_db);
-
-	if (tdb_transaction_commit(tdb) != 0) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to commit\n"));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/* repack one database */
-static int ctdb_repack_db(struct ctdb_context *ctdb, uint32_t db_id, 
-			  bool persistent, uint32_t repack_limit)
-{
-	struct ctdb_db_context *ctdb_db;
-	const char *name;
-	int size;
-
-	if (ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, db_id, ctdb, &name) != 0) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to get name of db 0x%x\n", db_id));
-		return -1;
-	}
-
-	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), name, persistent, 0);
-	if (ctdb_db == NULL) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to attach to database '%s'\n", name));
-		return -1;
-	}
-
-	size = tdb_freelist_size(ctdb_db->ltdb->tdb);
-	if (size == -1) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to get freelist size for '%s'\n", name));
-		return -1;
-	}
-
-	if (size <= repack_limit) {
-		return 0;
-	}
-
-	printf("Repacking %s with %u freelist entries\n", name, size);
-
-	if (ctdb_repack_tdb(ctdb_db->ltdb->tdb) != 0) {
-		DEBUG(DEBUG_ERR,(__location__ " Failed to repack '%s'\n", name));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/*
-  repack all our databases
- */
-int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv)
-{
-	struct ctdb_dbid_map *dbmap=NULL;
-	int ret, i;
-	/* a reasonable default limit to prevent us using too much memory */
-	uint32_t repack_limit = 10000; 
-
-	if (argc > 0) {
-		repack_limit = atoi(argv[0]);
-	}
-
-	ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &dbmap);
-	if (ret != 0) {
-		DEBUG(DEBUG_ERR, ("Unable to get dbids from local node\n"));
-		return ret;
-	}
-
-	for (i=0;i<dbmap->num;i++) {
-		if (ctdb_repack_db(ctdb, dbmap->dbs[i].dbid, 
-				   dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, repack_limit) != 0) {
-			DEBUG(DEBUG_ERR,("Failed to repack db 0x%x\n", dbmap->dbs[i].dbid));
-			return -1;
-		}
-	}
-
-	return 0;
-}
diff --git a/ctdb/tools/ltdbtool.c b/ctdb/tools/ltdbtool.c
index 13fd7f9..7ac70e2 100644
--- a/ctdb/tools/ltdbtool.c
+++ b/ctdb/tools/ltdbtool.c
@@ -18,23 +18,14 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdio.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <ctype.h> /* isprint */
-#include <string.h> /* strstr */
-#include <fcntl.h> /* mode_t */
-#include <sys/stat.h> /* S_IRUSR */
-#include <stdint.h> /* uint32_t */
-#include <netinet/in.h> /* struct sockaddr_in */
-#include <sys/socket.h> /* struct sockaddr */
-#include <sys/param.h>  /* MIN */
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "system/locale.h"
+
 #include <tdb.h>
-#include <unistd.h> /* getopt */
-#include <errno.h>
 
-#include "ctdb_protocol.h"
+#include "protocol/protocol.h"
 
 enum {
 	MAX_HEADER_SIZE=24,
diff --git a/ctdb/tools/onnode b/ctdb/tools/onnode
index 2ca3113..104295e 100755
--- a/ctdb/tools/onnode
+++ b/ctdb/tools/onnode
@@ -67,7 +67,12 @@ names_ok=false
 push=false
 stdin=false
 
-ctdb_base="${CTDB_BASE:-/etc/ctdb}"
+if [ -z "$CTDB_BASE" ] ; then
+    CTDB_BASE="/usr/local/etc/ctdb"
+fi
+
+. "${CTDB_BASE}/functions"
+loadconfig "ctdb"
 
 parse_options ()
 {
@@ -258,13 +263,15 @@ get_nodes ()
     if [ -n "$CTDB_NODES_SOCKETS" ] ; then 
 	all_nodes="$CTDB_NODES_SOCKETS"
     else
-	local f="${ctdb_base}/nodes"
+	local f="${CTDB_BASE}/nodes"
 	if [ -n "$CTDB_NODES_FILE" ] ; then
 	    f="$CTDB_NODES_FILE"
 	    if [ ! -e "$f" -a "${f#/}" = "$f" ] ; then
-		# $f is relative, try in $ctdb_base
-		f="${ctdb_base}/${f}"
+		# $f is relative, try in $CTDB_BASE
+		f="${CTDB_BASE}/${f}"
 	    fi
+	elif [ -n "$CTDB_NODES" ] ; then
+	    f="$CTDB_NODES"
 	fi
 
 	if [ ! -r "$f" ] ; then
@@ -367,7 +374,7 @@ else
 	EXTRA_SSH_OPTS=""
     else 
 	# Could "2>/dev/null || true" but want to see errors from typos in file.
-	[ -r "${ctdb_base}/onnode.conf" ] && . "${ctdb_base}/onnode.conf"
+	[ -r "${CTDB_BASE}/onnode.conf" ] && . "${CTDB_BASE}/onnode.conf"
 	[ -n "$SSH" ] || SSH=ssh
 	if [ "$SSH" = "ssh" ] ; then
 	    if $parallel || ! $stdin ; then
diff --git a/ctdb/utils/ping_pong/ping_pong.c b/ctdb/utils/ping_pong/ping_pong.c
index fdb575d..be43a1d 100644
--- a/ctdb/utils/ping_pong/ping_pong.c
+++ b/ctdb/utils/ping_pong/ping_pong.c
@@ -39,10 +39,11 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/mman.h>
+#include <stdbool.h>
 
 static struct timeval tp1,tp2;
 
-static int do_reads, do_writes, use_mmap, do_check;
+static int do_reads, do_writes, use_mmap, do_check, do_brl_test;
 
 static void start_timer(void)
 {
@@ -57,7 +58,7 @@ static double end_timer(void)
 }
 
 /* lock a byte range in a open file */
-static int lock_range(int fd, int offset, int len)
+static int lock_range(int fd, int offset, int len, bool wait)
 {
 	struct flock lock;
 
@@ -67,7 +68,7 @@ static int lock_range(int fd, int offset, int len)
 	lock.l_len = len;
 	lock.l_pid = 0;
 	
-	return fcntl(fd,F_SETLKW,&lock);
+	return fcntl(fd, wait ? F_SETLKW : F_SETLK, &lock);
 }
 
 /* check whether we could place a lock */
@@ -147,11 +148,11 @@ static void ping_pong(int fd, int num_locks)
 
 	start_timer();
 
-	lock_range(fd, 0, 1);
+	lock_range(fd, 0, 1, true);
 	i = 0;
 
 	while (1) {
-		if (lock_range(fd, (i+1) % num_locks, 1) != 0) {
+		if (lock_range(fd, (i+1) % num_locks, 1, true) != 0) {
 			printf("lock at %d failed! - %s\n",
 			       (i+1) % num_locks, strerror(errno));
 		}
@@ -198,13 +199,25 @@ static void ping_pong(int fd, int num_locks)
 	}
 }
 
+static void usage(void)
+{
+	printf("ping_pong -rwmc <file> <num_locks>\n");
+	printf("ping_pong -l <file>\n\n");
+	printf("Options\n");
+	printf(" -r    do reads\n");
+	printf(" -w    do writes\n");
+	printf(" -m    use mmap\n");
+	printf(" -c    check locks\n");
+	printf(" -l    test for working byte range locks\n");
+}
+
 int main(int argc, char *argv[])
 {
 	char *fname;
 	int fd, num_locks;
 	int c;
 
-	while ((c = getopt(argc, argv, "rwmc")) != -1) {
+	while ((c = getopt(argc, argv, "rwmcl")) != -1) {
 		switch (c){
 		case 'w':
 			do_writes = 1;
@@ -218,6 +231,9 @@ int main(int argc, char *argv[])
 		case 'c':
 			do_check = 1;
 			break;
+		case 'l':
+			do_brl_test = 1;
+			break;
 		default:
 			fprintf(stderr, "Unknown option '%c'\n", c);
 			exit(1);
@@ -227,25 +243,44 @@ int main(int argc, char *argv[])
 	argv += optind;
 	argc -= optind;
 
-	if (argc < 2) {
-		printf("ping_pong [options] <file> <num_locks>\n");
-		printf("           -r    do reads\n");
-		printf("           -w    do writes\n");
-		printf("           -m    use mmap\n");
-		printf("           -c    check locks\n");
+	if (argc < 1) {
+		usage();
 		exit(1);
 	}
 
 	fname = argv[0];
+
+	fd = open(fname, O_CREAT|O_RDWR, 0600);
+	if (fd == -1) {
+		exit(1);
+	}
+
+	if (do_brl_test) {
+		if (lock_range(fd, 0, 0, false) != 0) {
+			printf("file already locked, calling check_lock to tell us who has it locked:\n");
+			(void)check_lock(fd, 0, 0);
+			printf("Working POSIX byte range locks\n");
+			exit(0);
+		}
+
+		printf("Holding lock, press any key to continue...\n");
+		printf("You should run the same command on another node now.\n");
+		getchar();
+		printf("Good bye.\n");
+		exit(0);
+	}
+
+	if (argc < 2) {
+		usage();
+		exit(1);
+	}
+
 	num_locks = atoi(argv[1]);
 	if (num_locks <= 0) {
 		printf("num_locks should be > 0\n");
 		exit(1);
 	}
 
-	fd = open(fname, O_CREAT|O_RDWR, 0600);
-	if (fd == -1) exit(1);
-
 	ping_pong(fd, num_locks);
 
 	return 0;
diff --git a/ctdb/utils/pmda/pmda_ctdb.c b/ctdb/utils/pmda/pmda_ctdb.c
index 1145844..b4105a6 100644
--- a/ctdb/utils/pmda/pmda_ctdb.c
+++ b/ctdb/utils/pmda/pmda_ctdb.c
@@ -19,12 +19,24 @@
  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/time.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/system.h"
+#include "common/common.h"
+
 #include <pcp/pmapi.h>
 #include <pcp/impl.h>
 #include <pcp/pmda.h>
-#include "includes.h"
-#include "ctdb_private.h"
-#include "ctdb_protocol.h"
+
 #include "domain.h"
 
 /*
@@ -158,7 +170,7 @@ static pmdaMetric metrictab[] = {
 		PMDA_PMUNITS(0,0,0,0,0,0) }, },
 };
 
-static struct event_context *ev;
+static struct tevent_context *ev;
 static struct ctdb_context *ctdb;
 static struct ctdb_statistics *stats;
 
@@ -182,7 +194,7 @@ pmda_ctdb_daemon_connect(void)
 	int ret;
 	struct sockaddr_un addr;
 
-	ev = event_context_init(NULL);
+	ev = tevent_context_init(NULL);
 	if (ev == NULL) {
 		fprintf(stderr, "Failed to init event ctx\n");
 		return -1;
diff --git a/ctdb/utils/smnotify/smnotify.c b/ctdb/utils/smnotify/smnotify.c
index d5c5a4c..0cd61c7 100644
--- a/ctdb/utils/smnotify/smnotify.c
+++ b/ctdb/utils/smnotify/smnotify.c
@@ -137,7 +137,7 @@ int main(int argc, const char *argv[])
 		exit(10);
 	}
 
-	/* we dont want to wait for any reply */
+	/* we don't want to wait for any reply */
 	w.tv_sec = 0;
 	w.tv_usec = 0;
 	clnt_control(clnt, CLSET_TIMEOUT, (char *)&w);
diff --git a/ctdb/web/iscsi.html b/ctdb/web/iscsi.html
index 1385e18..2926eaa 100644
--- a/ctdb/web/iscsi.html
+++ b/ctdb/web/iscsi.html
@@ -10,7 +10,7 @@ You can use CTDB to create a HA iSCSI Target.
 <p>
 Since the iSCSI Target is not
 clusterized nor integrated with CTDB in the same sense Samba is, this
-implementation will only create a HA solution for iSCSI where each public address is assinged its own iscsi target name and the LUNs that are created are only accessible through one specific target (i.e. one public address at a time).
+implementation will only create a HA solution for iSCSI where each public address is assigned its own iscsi target name and the LUNs that are created are only accessible through one specific target (i.e. one public address at a time).
 
 </p>
 
diff --git a/ctdb/web/testing.html b/ctdb/web/testing.html
index d0d39a3..92182dd 100644
--- a/ctdb/web/testing.html
+++ b/ctdb/web/testing.html
@@ -99,9 +99,9 @@ Number of nodes:4
 </pre>
 
 <h3>ctdb ping</h3>
-this command tries to "ping" each of the CTDB daemons in the cluster.
+this command tries to "ping" the local CTDB daemon.
 <pre>
-  ctdb ping -n all
+  onnode -q all ctdb ping
 
   response from 0 time=0.000050 sec  (13 clients)
   response from 1 time=0.000154 sec  (27 clients)
diff --git a/ctdb/wscript b/ctdb/wscript
index 06f86a3..5739269 100755
--- a/ctdb/wscript
+++ b/ctdb/wscript
@@ -26,7 +26,7 @@ else:
 version = samba_version.samba_version_file('%s/VERSION' % vdir, vdir, env)
 VERSION = version.STRING.replace('-', '.')
 
-Options.default_prefix = '/usr/local'
+default_prefix = Options.default_prefix = '/usr/local'
 
 samba_dist.DIST_DIRS('''ctdb:. lib/replace:lib/replace lib/talloc:lib/talloc
                         lib/tevent:lib/tevent lib/tdb:lib/tdb
@@ -36,6 +36,19 @@ samba_dist.DIST_DIRS('''ctdb:. lib/replace:lib/replace lib/talloc:lib/talloc
                         lib/ccan:lib/ccan libcli/util:libcli/util
                         buildtools:buildtools third_party/waf:third_party/waf''')
 
+manpages = [
+    'ctdb.1',
+    'ctdb.7',
+    'ctdbd.1',
+    'ctdbd.conf.5',
+    'ctdbd_wrapper.1',
+    'ctdb-statistics.7',
+    'ctdb-tunables.7',
+    'ltdbtool.1',
+    'onnode.1',
+    'ping_pong.1'
+]
+
 
 def set_options(opt):
     opt.PRIVATE_EXTENSION_DEFAULT('ctdb')
@@ -94,7 +107,8 @@ def configure(conf):
     conf.RECURSE('lib/talloc')
     conf.RECURSE('lib/tevent')
     conf.RECURSE('lib/tdb')
-    conf.RECURSE('lib/socket_wrapper')
+    if conf.env.standalone_ctdb or conf.CONFIG_GET('ENABLE_SELFTEST'):
+        conf.RECURSE('lib/socket_wrapper')
 
     conf.CHECK_HEADERS('sched.h')
     conf.CHECK_HEADERS('procinfo.h')
@@ -167,6 +181,7 @@ def configure(conf):
     conf.env.CTDB_ETCDIR = os.path.join(conf.env.SYSCONFDIR, 'ctdb')
     conf.env.CTDB_VARDIR = os.path.join(conf.env.LOCALSTATEDIR, 'lib/ctdb')
     conf.env.CTDB_RUNDIR = os.path.join(conf.env.LOCALSTATEDIR, 'run/ctdb')
+    conf.env.CTDB_HELPER_BINDIR = os.path.join(conf.env.LIBEXECDIR, 'ctdb')
 
     if Options.options.ctdb_logdir:
         conf.env.CTDB_LOGDIR = Options.options.ctdb_logdir
@@ -178,16 +193,15 @@ def configure(conf):
     else:
         conf.env.CTDB_SOCKPATH = os.path.join(conf.env.CTDB_RUNDIR,
                                               'ctdbd.socket')
+    conf.define('CTDB_SOCKET', conf.env.CTDB_SOCKPATH)
 
     conf.ADD_CFLAGS('''-DCTDB_HELPER_BINDIR=\"%s\"
                        -DLOGDIR=\"%s\"
-                       -DSOCKPATH=\"%s\"
                        -DCTDB_ETCDIR=\"%s\"
                        -DCTDB_VARDIR=\"%s\"
                        -DCTDB_RUNDIR=\"%s\"''' % (
-                    conf.env.CTDB_BINDIR,
+                    conf.env.CTDB_HELPER_BINDIR,
                     conf.env.CTDB_LOGDIR,
-                    conf.env.CTDB_SOCKPATH,
                     conf.env.CTDB_ETCDIR,
                     conf.env.CTDB_VARDIR,
                     conf.env.CTDB_RUNDIR))
@@ -199,16 +213,14 @@ def configure(conf):
     # Allow unified compilation and separate compilation of utilities
     # to find includes
     if not conf.env.standalone_ctdb:
-        conf.ADD_EXTRA_INCLUDES('#ctdb/include')
+        conf.ADD_EXTRA_INCLUDES('#include/public #ctdb/include #ctdb')
     else:
         if srcdir == '.':
             # Building from tarball
             conf.ADD_EXTRA_INCLUDES('#include')
-            conf.ADD_EXTRA_INCLUDES('#include/internal')
         else:
             # Building standalone CTDB from within Samba tree
             conf.ADD_EXTRA_INCLUDES('#ctdb/include')
-            conf.ADD_EXTRA_INCLUDES('#ctdb/include/internal')
             conf.ADD_EXTRA_INCLUDES('#ctdb')
         conf.ADD_EXTRA_INCLUDES('#lib #lib/replace')
 
@@ -216,6 +228,19 @@ def configure(conf):
         conf.DEFINE('SAMBA_UTIL_CORE_ONLY', 1, add_to_cflags=True)
         conf.SAMBA_CONFIG_H()
 
+    if 'XSLTPROC_MANPAGES' in conf.env and conf.env['XSLTPROC_MANPAGES']:
+        conf.env.ctdb_generate_manpages = True
+    else:
+        conf.env.ctdb_generate_manpages = False
+
+        Logs.info("xsltproc unavailable, checking for pre-built manpages")
+        conf.env.ctdb_prebuilt_manpages = []
+        for m in manpages:
+            if os.path.exists(os.path.join("doc", m)):
+                Logs.info("  %s: yes" % (m))
+                conf.env.ctdb_prebuilt_manpages.append(m)
+            else:
+                Logs.info("  %s: no" % (m))
 
 def build(bld):
     if bld.env.standalone_ctdb:
@@ -246,6 +271,8 @@ def build(bld):
                                 dep_vars=['VERSION'])
         t.env.VERSION = VERSION
 
+    bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
+
     bld.RECURSE('lib/replace')
     if bld.CHECK_FOR_THIRD_PARTY():
         bld.RECURSE('third_party/popt')
@@ -256,10 +283,11 @@ def build(bld):
     bld.RECURSE('lib/talloc')
     bld.RECURSE('lib/tevent')
     bld.RECURSE('lib/tdb')
-    bld.RECURSE('lib/socket_wrapper')
+    if bld.env.standalone_ctdb or bld.CONFIG_GET('SOCKET_WRAPPER'):
+        bld.RECURSE('lib/socket_wrapper')
 
     if bld.env.standalone_ctdb:
-        # In a combined build is implemented, CTDB will wanted to
+        # If a combined build is implemented, CTDB will want to
         # build against samba-util rather than samba-util-core.
         # Similarly, other Samba subsystems expect samba-util.  So,
         # for a standalone build, just define a fake samba-util
@@ -271,7 +299,7 @@ def build(bld):
     bld.SAMBA_SUBSYSTEM('ctdb-tcp',
                         source=bld.SUBDIR('tcp',
                                           'tcp_connect.c tcp_init.c tcp_io.c'),
-                        includes='include include/internal',
+                        includes='include',
                         deps='replace tdb talloc tevent')
 
     ib_deps = ''
@@ -280,24 +308,10 @@ def build(bld):
                             source=bld.SUBDIR('ib',
                                               '''ibwrapper.c ibw_ctdb.c
                                                  ibw_ctdb_init.c'''),
-                            includes='include include/internal',
-                            deps='replace')
+                            includes='include',
+                            deps='replace talloc tevent')
         ib_deps = ' ctdb-ib rdmacm ibverbs'
 
-    bld.SAMBA_SUBSYSTEM('ctdb-common',
-                        source=bld.SUBDIR('common',
-                                          '''ctdb_io.c ctdb_util.c ctdb_ltdb.c
-                                             ctdb_message.c cmdline.c rb_tree.c
-                                             system_common.c ctdb_fork.c'''),
-                        includes='include include/internal common .',
-                        deps='replace popt talloc tevent tdb popt')
-
-    bld.SAMBA_SUBSYSTEM('ctdb-common-util',
-                        source=bld.SUBDIR('common',
-                                          'system_util.c ctdb_logging.c'),
-                        includes='include include/internal',
-                        deps='replace tevent tdb')
-
     if sys.platform.startswith('linux'):
         CTDB_SYSTEM_SRC = bld.SUBDIR('common', 'system_linux.c')
     elif sys.platform.startswith('aix'):
@@ -312,16 +326,64 @@ def build(bld):
         Logs.error("Platform %s not supported" % sys.platform)
 
     bld.SAMBA_SUBSYSTEM('ctdb-system',
-                        source=CTDB_SYSTEM_SRC,
-                        includes='include include/internal',
+                        source=bld.SUBDIR('common',
+                                          'system_common.c system_util.c') +
+                               CTDB_SYSTEM_SRC,
+                        includes='include',
                         deps='replace talloc tevent tdb pcap')
 
+    bld.SAMBA_SUBSYSTEM('ctdb-common',
+                        source=bld.SUBDIR('common',
+                                          '''ctdb_io.c ctdb_util.c ctdb_ltdb.c
+                                             cmdline.c rb_tree.c'''),
+                        includes='include',
+                        deps='replace popt talloc tevent tdb popt ctdb-system')
+
+    bld.SAMBA_SUBSYSTEM('ctdb-util',
+                        source=bld.SUBDIR('common',
+                                          '''db_hash.c srvid.c reqid.c
+                                             pkt_read.c pkt_write.c comm.c
+                                             logging.c'''),
+                        deps='replace talloc tevent tdb tevent-unix-util')
+
+    bld.SAMBA_SUBSYSTEM('ctdb-protocol',
+                        source=bld.SUBDIR('protocol',
+                                          '''protocol_header.c protocol_packet.c
+                                             protocol_types.c protocol_call.c
+                                             protocol_message.c
+                                             protocol_control.c
+                                             protocol_client.c
+                                             protocol_util.c'''),
+                        includes='include',
+                        deps='replace talloc tdb')
+
     bld.SAMBA_SUBSYSTEM('ctdb-client',
                         source=bld.SUBDIR('client', 'ctdb_client.c'),
-                        includes='include include/internal',
-                        public_headers='include/ctdb_client.h',
+                        includes='include',
                         deps='''replace popt talloc tevent tdb
-                                samba-util tdb-wrap''')
+                                samba-util tdb-wrap ctdb-util''')
+
+    bld.SAMBA_SUBSYSTEM('ctdb-client2',
+                        source=bld.SUBDIR('client',
+                                          '''client_connect.c client_call.c
+                                             client_message.c client_control.c
+                                             client_message_sync.c
+                                             client_control_sync.c
+                                             client_db.c client_util.c
+                                          '''),
+                        includes='include',
+                        deps='replace talloc tevent tdb tdb-wrap')
+
+    bld.SAMBA_SUBSYSTEM('ctdb-ipalloc',
+                        source=bld.SUBDIR('server',
+                                          '''ipalloc_deterministic.c
+                                             ipalloc_nondeterministic.c
+                                             ipalloc_lcp2.c
+                                             ipalloc_common.c
+                                             ipalloc.c
+                                          '''),
+                        includes='include',
+                        deps='ctdb-protocol replace talloc tevent')
 
     bld.SAMBA_SUBSYSTEM('ctdb-server',
                         source='server/ctdbd.c ' +
@@ -341,49 +403,49 @@ def build(bld):
                                              ctdb_vacuum.c ctdb_banning.c
                                              ctdb_statistics.c
                                              ctdb_update_record.c
-                                             ctdb_lock.c'''),
-                        includes='include include/internal',
-                        public_headers='''include/ctdb_version.h
-                                          include/ctdb.h
-                                          include/ctdb_private.h
-                                          include/ctdb_protocol.h
-                                          include/ctdb_typesafe_cb.h''',
-                        deps='replace popt talloc tevent tdb')
+                                             ctdb_lock.c ctdb_fork.c'''),
+                        includes='include',
+                        deps='ctdb-ipalloc replace popt talloc tevent tdb talloc_report')
 
     bld.SAMBA_BINARY('ctdbd',
                      source='',
                      deps='''ctdb-server ctdb-client ctdb-common
-                             ctdb-common-util ctdb-system ctdb-tcp''' +
+                             ctdb-system ctdb-tcp ctdb-util''' +
                           ib_deps,
                      install_path='${SBINDIR}',
-                     manpages='doc/ctdbd.1')
+                     manpages='ctdbd.1')
 
     bld.SAMBA_BINARY('ctdb',
-                     source='tools/ctdb.c tools/ctdb_vacuum.c',
-                     deps='''ctdb-client ctdb-common ctdb-common-util
-                             ctdb-system''',
-                     includes='include include/internal',
+                     source='tools/ctdb.c',
+                     deps='ctdb-client ctdb-common ctdb-system ctdb-util',
+                     includes='include',
                      install_path='${BINDIR}',
-                     manpages='doc/ctdb.1')
+                     manpages='ctdb.1')
 
     bld.SAMBA_BINARY('ltdbtool',
                      source='tools/ltdbtool.c',
                      includes='include',
                      deps='tdb',
                      install_path='${BINDIR}',
-                     manpages='doc/ltdbtool.1')
+                     manpages='ltdbtool.1')
 
     bld.SAMBA_BINARY('ctdb_lock_helper',
                      source='server/ctdb_lock_helper.c',
-                     deps='samba-util ctdb-common-util talloc tdb',
-                     includes='include include/internal',
-                     install_path='${BINDIR}')
+                     deps='samba-util ctdb-system talloc tdb',
+                     includes='include',
+                     install_path='${CTDB_HELPER_BINDIR}')
 
     bld.SAMBA_BINARY('ctdb_event_helper',
                      source='server/ctdb_event_helper.c',
-                     includes='include include/internal',
-                     deps='samba-util ctdb-common-util replace tdb',
-                     install_path='${BINDIR}')
+                     includes='include',
+                     deps='samba-util ctdb-system replace tdb',
+                     install_path='${CTDB_HELPER_BINDIR}')
+
+    bld.SAMBA_BINARY('ctdb_recovery_helper',
+                     source='server/ctdb_recovery_helper.c',
+                     deps='''ctdb-client2 ctdb-protocol ctdb-util
+                             samba-util replace tdb''',
+                     install_path='${CTDB_HELPER_BINDIR}')
 
     bld.SAMBA_GENERATOR('ctdb-smnotify-h',
                         source='utils/smnotify/smnotify.x',
@@ -407,20 +469,19 @@ def build(bld):
                                        'smnotify.c gen_smnotify.c gen_xdr.c'),
                      deps='ctdb-smnotify-h ctdb-smnotify-c ctdb-smnotify-x popt',
                      includes='utils utils/smnotify',
-                     install_path='${BINDIR}')
+                     install_path='${CTDB_HELPER_BINDIR}')
 
     bld.SAMBA_BINARY('ping_pong',
                      source='utils/ping_pong/ping_pong.c',
                      deps='',
                      install_path='${BINDIR}',
-                     manpages='doc/ping_pong.1')
+                     manpages='ping_pong.1')
 
     if bld.env.HAVE_PMDA:
         bld.SAMBA_BINARY('pmdactdb',
                          source='utils/pmda/pmda_ctdb.c',
-                         includes='include include/internal',
-                         deps='''ctdb-client ctdb-common ctdb-system
-                                 ctdb-common-util pcp_pmda pcp''',
+                         includes='include',
+                         deps='ctdb-client ctdb-common pcp_pmda pcp',
                          install_path='${CTDB_PMDADIR}')
         bld.INSTALL_FILES('${CTDB_PMDADIR}', 'utils/pmda/Install',
                           destname='Install')
@@ -435,16 +496,61 @@ def build(bld):
         bld.INSTALL_FILES('${CTDB_PMDADIR}', 'utils/pmda/README',
                           destname='README')
 
-    if 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
-        bld.MANPAGES('''doc/onnode.1 doc/ctdbd_wrapper.1 doc/ctdbd.conf.5
-                        doc/ctdb.7 doc/ctdb-statistics.7 doc/ctdb-tunables.7''',
-                     True)
-
-    bld.INSTALL_FILES('${BINDIR}', 'tools/onnode',
+    sed_expr1 = 's|/usr/local/var/lib/ctdb|%s|g'  % (bld.env.CTDB_VARDIR)
+    sed_expr2 = 's|/usr/local/etc/ctdb|%s|g'      % (bld.env.CTDB_ETCDIR)
+    sed_expr3 = 's|/usr/local/var/log|%s|g'       % (bld.env.CTDB_LOGDIR)
+    sed_expr4 = 's|/usr/local/var/run/ctdb|%s|g'  % (bld.env.CTDB_RUNDIR)
+    sed_expr5 = 's|/usr/local/sbin|%s|g'          % (bld.env.SBINDIR)
+    sed_expr6 = 's|/usr/local/libexec/ctdb|%s|g'  % (bld.env.CTDB_HELPER_BINDIR)
+    sed_cmdline = '-e "%s" -e "%s" -e "%s" -e "%s" -e "%s" -e "%s"' % \
+                       (sed_expr1, sed_expr2, sed_expr3, sed_expr4, sed_expr5,
+                        sed_expr6)
+
+    for f in manpages:
+        x = '%s.xml' % (f)
+        bld.SAMBA_GENERATOR(x,
+                            source=os.path.join('doc', x),
+                            target=x,
+                            rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+
+    if bld.env.ctdb_generate_manpages:
+        bld.MANPAGES('''onnode.1 ctdbd_wrapper.1 ctdbd.conf.5
+                        ctdb.7 ctdb-statistics.7 ctdb-tunables.7''',
+                      True)
+    else:
+        for m in bld.env.ctdb_prebuilt_manpages:
+            bld.SAMBA_GENERATOR(m,
+                                source=os.path.join("doc", m),
+                                target=m,
+                                rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+            bld.INSTALL_FILES('${MANDIR}/man%s' % m[-1], m)
+
+    bld.SAMBA_GENERATOR('ctdb-onnode',
+                        source='tools/onnode',
+                        target='onnode',
+                        rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+    bld.INSTALL_FILES('${BINDIR}', 'onnode',
                       destname='onnode', chmod=0755)
-    bld.INSTALL_FILES('${BINDIR}', 'tools/ctdb_diagnostics',
+
+    bld.SAMBA_GENERATOR('ctdb-diagnostics',
+                        source='tools/ctdb_diagnostics',
+                        target='ctdb_diagnostics',
+                        rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+    bld.INSTALL_FILES('${BINDIR}', 'ctdb_diagnostics',
                       destname='ctdb_diagnostics', chmod=0755)
-    bld.INSTALL_FILES('${SBINDIR}', 'config/ctdbd_wrapper',
+
+    bld.SAMBA_GENERATOR('ctdb-natgw',
+                        source='tools/ctdb_natgw',
+                        target='ctdb_natgw',
+                        rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+    bld.INSTALL_FILES('${CTDB_HELPER_BINDIR}', 'ctdb_natgw',
+                      destname='ctdb_natgw', chmod=0755)
+
+    bld.SAMBA_GENERATOR('ctdbd-wrapper',
+                        source='config/ctdbd_wrapper',
+                        target='ctdbd_wrapper',
+                        rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+    bld.INSTALL_FILES('${SBINDIR}', 'ctdbd_wrapper',
                       destname='ctdbd_wrapper', chmod=0755)
 
     def SUBDIR_MODE_callback(arg, dirname, fnames):
@@ -478,8 +584,11 @@ def build(bld):
             bld.INSTALL_FILES(bld.env.CTDB_ETCDIR, 'config/%s' % fmode[0],
                               destname=fmode[0], chmod=fmode[1])
 
-    bld.INSTALL_FILES(bld.env.CTDB_ETCDIR, 'config/functions',
-                      destname='functions')
+    bld.SAMBA_GENERATOR('ctdb-functions',
+                        source='config/functions',
+                        target='functions',
+                        rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+    bld.INSTALL_FILES(bld.env.CTDB_ETCDIR, 'functions', destname='functions')
 
     etc_scripts = [
         'ctdb-crash-cleanup.sh',
@@ -495,7 +604,11 @@ def build(bld):
         bld.INSTALL_FILES(bld.env.CTDB_ETCDIR, 'config/%s' % t,
                           destname=t, chmod=0755)
 
-    bld.INSTALL_FILES('${SYSCONFDIR}/sudoers.d', 'config/ctdb.sudoers',
+    bld.SAMBA_GENERATOR('ctdb-sudoers',
+                        source='config/ctdb.sudoers',
+                        target='ctdb.sudoers',
+                        rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+    bld.INSTALL_FILES('${SYSCONFDIR}/sudoers.d', 'ctdb.sudoers',
                       destname='ctdb')
 
     bld.INSTALL_FILES('${CTDB_ETCDIR}/notify.d', 'config/notify.d.README',
@@ -505,14 +618,31 @@ def build(bld):
     bld.install_dir(bld.env.CTDB_RUNDIR)
     bld.install_dir(bld.env.CTDB_VARDIR)
 
-    sed_expr = 's/@PACKAGE_VERSION@/%s/g' % VERSION
-    t = bld.SAMBA_GENERATOR('ctdb-pc',
-                            source='ctdb.pc.in',
-                            target='ctdb.pc',
-                            rule='sed -e "%s" ${SRC} > ${TGT}' % sed_expr,
-                            dep_vars=['VERSION'])
-    t.env.VERSION = VERSION
-    bld.INSTALL_FILES('${LIBDIR}/pkgconfig', 'ctdb.pc')
+    # Unit tests
+    ctdb_unit_tests = [
+        'db_hash_test',
+        'srvid_test',
+        'pkt_read_test',
+        'pkt_write_test',
+        'comm_test',
+        'comm_server_test',
+        'comm_client_test',
+        'protocol_types_test',
+        'protocol_client_test',
+    ]
+
+    for target in ctdb_unit_tests:
+        src = 'tests/src/' + target + '.c'
+
+        bld.SAMBA_BINARY(target,
+                         source=src,
+                         deps='talloc tevent tdb tevent-unix-util',
+                         install_path='${CTDB_TEST_LIBDIR}')
+
+    bld.SAMBA_BINARY('reqid_test',
+                     source='tests/src/reqid_test.c',
+                     deps='samba-util',
+                     install_path='${CTDB_TEST_LIBDIR}')
 
     # Test binaries
     ctdb_tests = [
@@ -539,44 +669,44 @@ def build(bld):
 
         bld.SAMBA_BINARY(target,
                          source=src,
-                         includes='include include/internal',
-                         deps='''ctdb-client ctdb-common ctdb-common-util
-                                 ctdb-system''',
+                         includes='include',
+                         deps='ctdb-client ctdb-common ctdb-util',
                          install_path='${CTDB_TEST_LIBDIR}')
 
     bld.SAMBA_BINARY('ctdb_takeover_tests',
                      source='tests/src/ctdb_takeover_tests.c',
                      deps='''replace popt tdb tevent talloc ctdb-system
-                             samba-util tdb-wrap''' +
+                             samba-util tdb-wrap talloc_report
+                             ctdb-protocol''' +
                           ib_deps,
-                     includes='include include/internal',
+                     includes='include',
                      install_path='${CTDB_TEST_LIBDIR}')
 
     bld.SAMBA_BINARY('ctdb_functest',
                      source='tests/src/ctdb_functest.c',
                      deps='''replace tdb tevent talloc popt ctdb-system
                              samba-util tdb-wrap''',
-                     includes='include include/internal',
+                     includes='include',
                      install_path='${CTDB_TEST_LIBDIR}')
 
     bld.SAMBA_BINARY('ctdb_stubtest',
                      source='tests/src/ctdb_test.c',
                      deps='''replace tdb tevent talloc popt ctdb-system
                              samba-util tdb-wrap''',
-                     includes='include include/internal',
+                     includes='include',
                      install_path='${CTDB_TEST_LIBDIR}')
 
     if bld.env.HAVE_INFINIBAND:
         bld.SAMBA_BINARY('ibwrapper_test',
                          source='ib/ibwrapper_test.c',
-                         includes='include include/internal',
-                         deps='''replace talloc ctdb-client ctdb-common
-                                 ctdb-system''' +
+                         includes='include',
+                         deps='replace talloc ctdb-client ctdb-common' +
                               ib_deps,
                          install_path='${CTDB_TEST_LIBDIR}')
 
     test_subdirs = [
         'complex',
+        'cunit',
         'events.d',
         'eventscripts',
         'onnode',
@@ -639,6 +769,17 @@ def build(bld):
         bld.symlink_as(os.path.join(test_link_dir, t),
                        os.path.join(bld.env.CTDB_ETCDIR, t))
 
+    # Tests that use onnode need to overwrite link to in-tree
+    # functions file when installed
+    bld.symlink_as(os.path.join(bld.env.CTDB_TEST_DATADIR, 'onnode/functions'),
+                   os.path.join(bld.env.CTDB_ETCDIR, 'functions'))
+    bld.symlink_as(os.path.join(bld.env.CTDB_TEST_DATADIR, 'simple/functions'),
+                   os.path.join(bld.env.CTDB_ETCDIR, 'functions'))
+
+    # Need a link to nodes file because $CTDB_BASE is overridden
+    bld.symlink_as(os.path.join(bld.env.CTDB_TEST_DATADIR, 'simple/nodes'),
+                   os.path.join(bld.env.CTDB_ETCDIR, 'nodes'))
+
 
 def testonly(ctx):
     cmd = 'tests/run_tests.sh -V tests/var'
@@ -689,17 +830,6 @@ def dist():
         sys.exit(ret)
     samba_dist.DIST_FILES('ctdb/%s:%s' % (t, t), extend=True)
 
-    manpages = [
-        'ctdb.1',
-        'ctdb.7',
-        'ctdbd.1',
-        'ctdbd.conf.5',
-        'ctdbd_wrapper.1',
-        'ctdb-statistics.7',
-        'ctdb-tunables.7',
-        'ltdbtool.1'
-    ]
-
     cmd = 'make -C doc'
     ret = samba_utils.RUN_COMMAND(cmd)
     if ret != 0:
diff --git a/dfs_server/dfs_server_ad.c b/dfs_server/dfs_server_ad.c
index 3a25dff..04aa7e0 100644
--- a/dfs_server/dfs_server_ad.c
+++ b/dfs_server/dfs_server_ad.c
@@ -27,6 +27,7 @@
 #include "lib/tsocket/tsocket.h"
 #include "dfs_server/dfs_server_ad.h"
 #include "lib/util/util_net.h"
+#include "libds/common/roles.h"
 
 #define MAX_DFS_RESPONSE 56*1024 /* 56 Kb */
 
diff --git a/docs-xml/Samba3-HOWTO/TOSHARG-Passdb.xml b/docs-xml/Samba3-HOWTO/TOSHARG-Passdb.xml
index e301489..9335f51 100644
--- a/docs-xml/Samba3-HOWTO/TOSHARG-Passdb.xml
+++ b/docs-xml/Samba3-HOWTO/TOSHARG-Passdb.xml
@@ -1566,7 +1566,7 @@ refuse machine password change
 			<listitem><para>maximum password age = 90 days.</para></listitem>
 			<listitem><para>minimum password age = 7 days.</para></listitem>
 			<listitem><para>bad lockout attempt = 8 bad logon attempts.</para></listitem>
-			<listitem><para>lockout duration = forever, account must be manually reenabled.</para></listitem>
+			<listitem><para>lockout duration = forever, account must be manually re-enabled.</para></listitem>
 		</orderedlist>
 
 		<para>
diff --git a/docs-xml/archives/THANKS b/docs-xml/archives/THANKS
index 37ecc99..991cb6d 100644
--- a/docs-xml/archives/THANKS
+++ b/docs-xml/archives/THANKS
@@ -112,7 +112,7 @@ John Terpstra (jht at aquasoft.com.au)
         of Samba.
 
         The donation of the new PC will make it possible to more fully
-        diagnose and observe the behaviour of Samba in conjuction with
+        diagnose and observe the behaviour of Samba in conjunction with
         other SMB protocol utilising systems.
 
 
diff --git a/docs-xml/build/DTD/samba-doc b/docs-xml/build/DTD/samba-doc
index 06aa02a..afde348 100644
--- a/docs-xml/build/DTD/samba-doc
+++ b/docs-xml/build/DTD/samba-doc
@@ -42,6 +42,10 @@
 	name CDATA #REQUIRED
 	type CDATA #REQUIRED
 	context CDATA #REQUIRED
+	synonym CDATA #IMPLIED
+	handler CDATA #IMPLIED
+	deprecated CDATA #IMPLIED
+	enumlist CDATA #IMPLIED
 >
 <!ELEMENT description ANY>
 <!ELEMENT synonym (#PCDATA)>
diff --git a/docs-xml/manpages/cifsdd.8.xml b/docs-xml/manpages/cifsdd.8.xml
new file mode 100644
index 0000000..572ed7b
--- /dev/null
+++ b/docs-xml/manpages/cifsdd.8.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="smbspool.8">
+
+<refmeta>
+	<refentrytitle>cifsdd</refentrytitle>
+	<manvolnum>8</manvolnum>
+	<refmiscinfo class="source">Samba</refmiscinfo>
+	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+	<refname>cifsdd</refname>
+	<refpurpose>convert and copy a file over SMB</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+	<cmdsynopsis>
+		<command>cifsdd</command>
+		<arg choice="opt">OPERAND</arg>...
+	</cmdsynopsis>
+	<cmdsynopsis>
+		<command>cifsdd</command>
+		<arg choice="plain">OPTION</arg>
+	</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+	<title>DESCRIPTION</title>
+
+	<para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
+	<manvolnum>7</manvolnum></citerefentry> suite.</para>
+
+	<para>Copy a file, converting and formatting according to the operands.</para>
+
+	<variablelist>
+		<varlistentry>
+			<term>bs=BYTES</term>
+			<listitem><para>read and write up to BYTES bytes at a time (default: 4096)</para></listitem>
+		</varlistentry>
+		<varlistentry>
+			<term>ibs=BYTES</term>
+			<listitem><para>read up to BYTES bytes at a time (default: 4096)</para></listitem>
+		</varlistentry>
+		<varlistentry>
+			<term>obs=BYTES</term>
+			<listitem><para>write BYTES bytes at a time (default: 4096)</para></listitem>
+		</varlistentry>
+
+		<varlistentry>
+			<term>if=FILE</term>
+			<listitem><para>read from FILE instead of stdin</para></listitem>
+		</varlistentry>
+		<varlistentry>
+			<term>of=FILE</term>
+			<listitem><para>write to FILE instead of stdout</para></listitem>
+		</varlistentry>
+
+		<varlistentry>
+			<term>count=N</term>
+			<listitem><para>copy only N input blocks</para></listitem>
+		</varlistentry>
+		<varlistentry>
+			<term>seek=N</term>
+			<listitem><para>skip N obs-sized blocks at start of output</para></listitem>
+		</varlistentry>
+		<varlistentry>
+			<term>skip=N</term>
+			<listitem><para>skip N ibs-sized blocks at start of input</para></listitem>
+		</varlistentry>
+
+		<varlistentry>
+			<term>direct</term>
+			<listitem><para>use direct I/O for data</para></listitem>
+		</varlistentry>
+		<varlistentry>
+			<term>sync</term>
+			<listitem><para>use synchronous writes</para></listitem>
+		</varlistentry>
+		<varlistentry>
+			<term>oplock</term>
+			<listitem><para>take oplocks on the input and output files</para></listitem>
+		</varlistentry>
+	</variablelist>
+</refsect1>
+
+<refsect1>
+	<title>AUTHOR</title>
+
+	<para>The original Samba software and related utilities
+	were created by Andrew Tridgell. Samba is now developed
+	by the Samba Team as an Open Source project similar
+	to the way the Linux kernel is developed.</para>
+
+	<para>The cifsdd manpage was written by Andreas
+		Schneider.</para>
+</refsect1>
+
+</refentry>
diff --git a/docs-xml/manpages/dbwrap_tool.1.xml b/docs-xml/manpages/dbwrap_tool.1.xml
index 229dca2..d5219cb 100644
--- a/docs-xml/manpages/dbwrap_tool.1.xml
+++ b/docs-xml/manpages/dbwrap_tool.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/eventlogadm.8.xml b/docs-xml/manpages/eventlogadm.8.xml
index 517eb41..82939c6 100644
--- a/docs-xml/manpages/eventlogadm.8.xml
+++ b/docs-xml/manpages/eventlogadm.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/findsmb.1.xml b/docs-xml/manpages/findsmb.1.xml
index d228aee..81b9440 100644
--- a/docs-xml/manpages/findsmb.1.xml
+++ b/docs-xml/manpages/findsmb.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/idmap_ad.8.xml b/docs-xml/manpages/idmap_ad.8.xml
index 1699a9a..06a89ac 100644
--- a/docs-xml/manpages/idmap_ad.8.xml
+++ b/docs-xml/manpages/idmap_ad.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/idmap_autorid.8.xml b/docs-xml/manpages/idmap_autorid.8.xml
index be80dcb..4ae61e7 100644
--- a/docs-xml/manpages/idmap_autorid.8.xml
+++ b/docs-xml/manpages/idmap_autorid.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -38,6 +38,21 @@
 
 	<variablelist>
 		<varlistentry>
+		<term>range = low - high</term>
+		<listitem><para>
+			Defines the available matching uid and gid
+			range for which the backend is
+			authoritative. Note that the range acts as a
+			filter.  If algorithmically determined UID or
+			GID fall outside the range, they are ignored
+			and the corresponding map is discarded.  It is
+			intended as a way to avoid accidental UID/GID
+			overlaps between local and remotely defined
+			IDs.
+		</para></listitem>
+		</varlistentry>
+
+		<varlistentry>
 		<term>rangesize = numberofidsperdomain</term>
 		<listitem><para>
 			Defines the number of uids/gids available per
diff --git a/docs-xml/manpages/idmap_hash.8.xml b/docs-xml/manpages/idmap_hash.8.xml
index bf7af5b..6191183 100644
--- a/docs-xml/manpages/idmap_hash.8.xml
+++ b/docs-xml/manpages/idmap_hash.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/idmap_ldap.8.xml b/docs-xml/manpages/idmap_ldap.8.xml
index 89b17e2..e8bda4f 100644
--- a/docs-xml/manpages/idmap_ldap.8.xml
+++ b/docs-xml/manpages/idmap_ldap.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/idmap_nss.8.xml b/docs-xml/manpages/idmap_nss.8.xml
index 1187ece..a769b33 100644
--- a/docs-xml/manpages/idmap_nss.8.xml
+++ b/docs-xml/manpages/idmap_nss.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/idmap_rfc2307.8.xml b/docs-xml/manpages/idmap_rfc2307.8.xml
index a502db2..b8ab097 100644
--- a/docs-xml/manpages/idmap_rfc2307.8.xml
+++ b/docs-xml/manpages/idmap_rfc2307.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 <refnamediv>
@@ -88,16 +88,16 @@
 			no.</para></listitem>
 		</varlistentry>
 		<varlistentry>
-			<term>cn_realm = <yes | no></term>
+			<term>realm</term>
 			<listitem><para>Append @realm to cn for groups
 			(and users if user_cn is set) in
-			LDAP. This option is not required, the default
-			is no.</para></listitem>
+			LDAP queries. This option is not required, the default
+			is not to append the realm.</para></listitem>
 		</varlistentry>
 		<varlistentry>
 			<term>ldap_domain</term>
 			<listitem><para>When using the LDAP server in
-			the Active Directory server, this allows to
+			the Active Directory server, this allows one to
 			specify the domain where to access the Active
 			Directory server. This allows using trust
 			relationships while keeping all RFC 2307
@@ -124,13 +124,6 @@
 			absent, an anonymous bind will be
 			performed.</para></listitem>
 		</varlistentry>
-		<varlistentry>
-			<term>ldap_realm</term>
-			<listitem><para>Defines the realm to use in
-			the user and group names. This is only
-			required when using cn_realm together with a
-			stand-alone ldap server.</para></listitem>
-		</varlistentry>
 	</variablelist>
 </refsect1>
 
diff --git a/docs-xml/manpages/idmap_rid.8.xml b/docs-xml/manpages/idmap_rid.8.xml
index a93031a..a4b8d0c 100644
--- a/docs-xml/manpages/idmap_rid.8.xml
+++ b/docs-xml/manpages/idmap_rid.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/idmap_script.8.xml b/docs-xml/manpages/idmap_script.8.xml
index 7a86b1b..a378e7b 100644
--- a/docs-xml/manpages/idmap_script.8.xml
+++ b/docs-xml/manpages/idmap_script.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/idmap_tdb.8.xml b/docs-xml/manpages/idmap_tdb.8.xml
index 20fd661..3a7f7c2 100644
--- a/docs-xml/manpages/idmap_tdb.8.xml
+++ b/docs-xml/manpages/idmap_tdb.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/idmap_tdb2.8.xml b/docs-xml/manpages/idmap_tdb2.8.xml
index 1a21059..866464d 100644
--- a/docs-xml/manpages/idmap_tdb2.8.xml
+++ b/docs-xml/manpages/idmap_tdb2.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/libsmbclient.7.xml b/docs-xml/manpages/libsmbclient.7.xml
index cf22dc5..b21eeee 100644
--- a/docs-xml/manpages/libsmbclient.7.xml
+++ b/docs-xml/manpages/libsmbclient.7.xml
@@ -7,7 +7,7 @@
 	<manvolnum>7</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">7</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/lmhosts.5.xml b/docs-xml/manpages/lmhosts.5.xml
index e3ee025..b5e2ef8 100644
--- a/docs-xml/manpages/lmhosts.5.xml
+++ b/docs-xml/manpages/lmhosts.5.xml
@@ -7,7 +7,7 @@
 	<manvolnum>5</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">File Formats and Conventions</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/log2pcap.1.xml b/docs-xml/manpages/log2pcap.1.xml
index 2135d58..1d6c7c8 100644
--- a/docs-xml/manpages/log2pcap.1.xml
+++ b/docs-xml/manpages/log2pcap.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/net.8.xml b/docs-xml/manpages/net.8.xml
index a2bca95..6612191 100644
--- a/docs-xml/manpages/net.8.xml
+++ b/docs-xml/manpages/net.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -239,7 +239,7 @@
 		<term>--single-obj-repl</term>
 		<listitem><para>
 				When calling "net rpc vampire keytab" this option
-				allows to replicate just a single object to the generated keytab file.
+				allows one to replicate just a single object to the generated keytab file.
 		</para></listitem>
 		</varlistentry>
 
@@ -247,7 +247,7 @@
 		<term>--clean-old-entries</term>
 		<listitem><para>
 				When calling "net rpc vampire keytab" this option
-				allows to cleanup old entries from the generated keytab file.
+				allows one to cleanup old entries from the generated keytab file.
 		</para></listitem>
 		</varlistentry>
 
@@ -299,7 +299,7 @@
 
 		<varlistentry>
 		<term>-X|--exclude DIRECTORY</term>
-		<listitem><para>Allows to exclude directories when copying with "net rpc share migrate".
+		<listitem><para>Allows one to exclude directories when copying with "net rpc share migrate".
 		</para></listitem>
 		</varlistentry>
 
@@ -371,6 +371,13 @@
 		</para></listitem>
 		</varlistentry>
 
+		<varlistentry>
+		<term>--no-dns-updates</term>
+		<listitem><para>Do not perform DNS updates as part of
+		"net ads join".
+		</para></listitem>
+		</varlistentry>
+
 		&stdarg.encrypt;
 		&popt.common.samba.client;
 
@@ -439,8 +446,9 @@ The remote server must be specified with the -S option.
 </refsect2>
 
 <refsect2>
-<title>[RPC|ADS] JOIN [TYPE] [-U username[%password]] [createupn=UPN]
-[createcomputer=OU] [machinepass=PASS] [osName=string osVer=string] [options]</title>
+<title>[RPC|ADS] JOIN [TYPE] [--no-dns-updates] [-U username[%password]]
+[createupn=UPN] [createcomputer=OU] [machinepass=PASS]
+[osName=string osVer=string] [options]</title>
 
 <para>
 Join a domain.  If the account already exists on the server, and 
@@ -1346,7 +1354,7 @@ to show in the result.
 </para>
 
 <para>
-	This attribute allows to control which Kerberos encryption types are used for the generation of initial and service tickets. The value consists of an integer bitmask with the following values:
+	This attribute allows one to control which Kerberos encryption types are used for the generation of initial and service tickets. The value consists of an integer bitmask with the following values:
 </para>
 
 <para>0x00000001 DES-CBC-CRC</para>
@@ -1372,7 +1380,7 @@ to show in the result.
 	<title>ADS ENCTYPES SET <replaceable><ACCOUNTNAME></replaceable> <replaceable>[enctypes]</replaceable></title>
 
 <para>
-	Set the value of the "msDS-SupportedEncryptionTypes" attribute of the LDAP object of ACCOUNTNAME to a given value. If the value is ommitted, the value is set to 31 which enables all the currently supported encryption types.
+	Set the value of the "msDS-SupportedEncryptionTypes" attribute of the LDAP object of ACCOUNTNAME to a given value. If the value is omitted, the value is set to 31 which enables all the currently supported encryption types.
 </para>
 
 <para>Example: <userinput>net ads enctypes set Computername 24</userinput></para>
diff --git a/docs-xml/manpages/nmbd.8.xml b/docs-xml/manpages/nmbd.8.xml
index c41807a..f07643e 100644
--- a/docs-xml/manpages/nmbd.8.xml
+++ b/docs-xml/manpages/nmbd.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/nmblookup.1.xml b/docs-xml/manpages/nmblookup.1.xml
index 589fd10..65fb3c6 100644
--- a/docs-xml/manpages/nmblookup.1.xml
+++ b/docs-xml/manpages/nmblookup.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/ntlm_auth.1.xml b/docs-xml/manpages/ntlm_auth.1.xml
index 97477af..042893a 100644
--- a/docs-xml/manpages/ntlm_auth.1.xml
+++ b/docs-xml/manpages/ntlm_auth.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -381,6 +381,12 @@
 	</varlistentry>
 
 	<varlistentry>
+	<term>--offline-logon</term>
+	<listitem><para>Allow offline logons for plain text auth.
+	</para></listitem>
+	</varlistentry>
+
+	<varlistentry>
 	<term>--configfile=<configuration file></term>
 	<listitem><para>The file specified contains the
 	configuration details required by the server.  The
diff --git a/docs-xml/manpages/pam_winbind.8.xml b/docs-xml/manpages/pam_winbind.8.xml
index 9bab9ca..34ece9c 100644
--- a/docs-xml/manpages/pam_winbind.8.xml
+++ b/docs-xml/manpages/pam_winbind.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">8</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -160,7 +160,7 @@
 		<varlistentry>
 		<term>cached_login</term>
 		<listitem><para>
-		Winbind allows to logon using cached credentials when <parameter>winbind offline logon</parameter> is enabled. To use this feature from the PAM module this option must be set.
+		Winbind allows one to logon using cached credentials when <parameter>winbind offline logon</parameter> is enabled. To use this feature from the PAM module this option must be set.
 		</para></listitem>
 		</varlistentry>
 
diff --git a/docs-xml/manpages/pam_winbind.conf.5.xml b/docs-xml/manpages/pam_winbind.conf.5.xml
index da681e7..c3cfbb3 100644
--- a/docs-xml/manpages/pam_winbind.conf.5.xml
+++ b/docs-xml/manpages/pam_winbind.conf.5.xml
@@ -7,7 +7,7 @@
 	<manvolnum>5</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">5</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -152,7 +152,7 @@
 		<varlistentry>
 		<term>cached_login = yes|no</term>
 		<listitem><para>
-		Winbind allows to logon using cached credentials when <parameter>winbind offline logon</parameter> is enabled. To use this feature from the PAM module this option must be set. Defaults to "no".
+		Winbind allows one to logon using cached credentials when <parameter>winbind offline logon</parameter> is enabled. To use this feature from the PAM module this option must be set. Defaults to "no".
 		</para></listitem>
 		</varlistentry>
 
diff --git a/docs-xml/manpages/pdbedit.8.xml b/docs-xml/manpages/pdbedit.8.xml
index 6ed0399..9622c72 100644
--- a/docs-xml/manpages/pdbedit.8.xml
+++ b/docs-xml/manpages/pdbedit.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -43,6 +43,7 @@
 		<arg choice="opt">-r</arg>
 		<arg choice="opt">-s configfile</arg>
 		<arg choice="opt">-S script</arg>
+		<arg choice="opt">--set-nt-hash</arg>
 		<arg choice="opt">-t</arg>
 		<arg choice="opt">--time-format</arg>
 		<arg choice="opt">-u username</arg>
@@ -99,7 +100,8 @@ samba:45:Test User
 		<term>-v|--verbose</term>
 		<listitem><para>This option enables the verbose listing format.
 		It causes pdbedit to list the users in the database, printing
-		out the account fields in a descriptive format.</para>
+		out the account fields in a descriptive format. Used together
+		with -w also shows passwords hashes.</para>
 
 		<para>Example: <command>pdbedit -L -v</command></para>
 		<para><programlisting>
@@ -134,7 +136,9 @@ Profile Path:   \\BERSERKER\profile
 		out the account fields in a format compatible with the
 		<filename>smbpasswd</filename> file format. (see the
 		<citerefentry><refentrytitle>smbpasswd</refentrytitle>
-		<manvolnum>5</manvolnum></citerefentry> for details)</para>
+		<manvolnum>5</manvolnum></citerefentry> for details).
+		Instead used together with (-v) displays the passwords
+		hashes in verbose output.</para>
 
 		<para>Example: <command>pdbedit -L -w</command></para>
 		<programlisting>
@@ -205,6 +209,18 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE:
 		
 		
 		<varlistentry>
+		<term>--set-nt-hash</term>
+		<listitem><para>This option can be used while modifying
+		a user account. It will set the user's password using
+		the nt-hash value given as hexadecimal string.
+		Useful to synchronize passwords.</para>
+       
+		<para>Example: <command>--set-nt-hash 8846F7EAEE8FB117AD06BDD830B7586C</command>
+		</para>
+		</listitem>
+		</varlistentry>
+
+		<varlistentry>
 		<term>-p|--profile profile</term>
 		<listitem><para>This option can be used while adding or
 		modifying a user account. It will specify the user's profile
@@ -428,7 +444,7 @@ account policy value for bad lockout attempt is now 3
 		then <parameter>-i in-backend -e out-backend</parameter>
 		applies to the account policies instead of the user database.</para>
 
-		<para>This option will allow to migrate account policies from their default
+		<para>This option will allow one to migrate account policies from their default
 		tdb-store into a passdb backend, e.g. an LDAP directory server.</para>
 
 		<para>Example: <command>pdbedit -y -i tdbsam: -e ldapsam:ldap://my.ldap.host</command></para>
diff --git a/docs-xml/manpages/profiles.1.xml b/docs-xml/manpages/profiles.1.xml
index adcc0a8..f921958 100644
--- a/docs-xml/manpages/profiles.1.xml
+++ b/docs-xml/manpages/profiles.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/rpcclient.1.xml b/docs-xml/manpages/rpcclient.1.xml
index aec8ef1..fcdd0c6 100644
--- a/docs-xml/manpages/rpcclient.1.xml
+++ b/docs-xml/manpages/rpcclient.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/samba-regedit.8.xml b/docs-xml/manpages/samba-regedit.8.xml
index a218807..8b72fa2 100644
--- a/docs-xml/manpages/samba-regedit.8.xml
+++ b/docs-xml/manpages/samba-regedit.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/samba-tool.8.xml b/docs-xml/manpages/samba-tool.8.xml
index a575a20..3416ecf 100644
--- a/docs-xml/manpages/samba-tool.8.xml
+++ b/docs-xml/manpages/samba-tool.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/samba.7.xml b/docs-xml/manpages/samba.7.xml
index 5a772a1..006dfc0 100644
--- a/docs-xml/manpages/samba.7.xml
+++ b/docs-xml/manpages/samba.7.xml
@@ -7,7 +7,7 @@
 	<manvolnum>7</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">Miscellanea</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/samba.8.xml b/docs-xml/manpages/samba.8.xml
index 81f17b9..da9762e 100644
--- a/docs-xml/manpages/samba.8.xml
+++ b/docs-xml/manpages/samba.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/sharesec.1.xml b/docs-xml/manpages/sharesec.1.xml
index 88c2742..8c467ef 100644
--- a/docs-xml/manpages/sharesec.1.xml
+++ b/docs-xml/manpages/sharesec.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smb.conf.5.xml b/docs-xml/manpages/smb.conf.5.xml
index 4d444b1..cc77958 100644
--- a/docs-xml/manpages/smb.conf.5.xml
+++ b/docs-xml/manpages/smb.conf.5.xml
@@ -6,7 +6,7 @@
 	<manvolnum>5</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">File Formats and Conventions</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smbcacls.1.xml b/docs-xml/manpages/smbcacls.1.xml
index ce38b1d..de57b86 100644
--- a/docs-xml/manpages/smbcacls.1.xml
+++ b/docs-xml/manpages/smbcacls.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml
index 50c7ff6..faf1ca1 100644
--- a/docs-xml/manpages/smbclient.1.xml
+++ b/docs-xml/manpages/smbclient.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smbcontrol.1.xml b/docs-xml/manpages/smbcontrol.1.xml
index 713c146..9afdfa4 100644
--- a/docs-xml/manpages/smbcontrol.1.xml
+++ b/docs-xml/manpages/smbcontrol.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smbcquotas.1.xml b/docs-xml/manpages/smbcquotas.1.xml
index 3e7e55f..fb7475d 100644
--- a/docs-xml/manpages/smbcquotas.1.xml
+++ b/docs-xml/manpages/smbcquotas.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smbd.8.xml b/docs-xml/manpages/smbd.8.xml
index 7cf7d51..af6a77b 100644
--- a/docs-xml/manpages/smbd.8.xml
+++ b/docs-xml/manpages/smbd.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -120,12 +120,12 @@
 		server to run "interactively", not as a daemon, even if the
 		server is executed on the command line of a shell. Setting this
 		parameter negates the implicit daemon mode when run from the
-		command line. <command>smbd</command> also logs to standard
-		output, as if the <command>-S</command> parameter had been
-		given.
+		command line. <command>smbd</command> will only accept one
+		connection and terminate. It will also log to standard output,
+		as if the <command>-S</command> parameter had been given.
 		</para></listitem>
 		</varlistentry>
-		
+
 		&stdarg.server.debug;
 		&popt.common.samba;
 		&popt.autohelp;
diff --git a/docs-xml/manpages/smbget.1.xml b/docs-xml/manpages/smbget.1.xml
index 81670d9..d77cb8e 100644
--- a/docs-xml/manpages/smbget.1.xml
+++ b/docs-xml/manpages/smbget.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -22,20 +22,18 @@
 		<arg choice="opt">-a, --guest</arg>
 		<arg choice="opt">-r, --resume</arg>
 		<arg choice="opt">-R, --recursive</arg>
-		<arg choice="opt">-u, --username=STRING</arg>
-		<arg choice="opt">-p, --password=STRING</arg>
+		<arg choice="opt">-U, --username=STRING</arg>
 		<arg choice="opt">-w, --workgroup=STRING</arg>
 		<arg choice="opt">-n, --nonprompt</arg>
 		<arg choice="opt">-d, --debuglevel=INT</arg>
 		<arg choice="opt">-D, --dots</arg>
-		<arg choice="opt">-P, --keep-permissions</arg>
 		<arg choice="opt">-o, --outputfile</arg>
 		<arg choice="opt">-f, --rcfile</arg>
 		<arg choice="opt">-q, --quiet</arg>
 		<arg choice="opt">-v, --verbose</arg>
 		<arg choice="opt">-b, --blocksize</arg>
 		<arg choice="opt">-O, --stdout</arg>
-		<arg choice="opt">-U, --update</arg>
+		<arg choice="opt">-u, --update</arg>
 		<arg choice="opt">-?, --help</arg>
 		<arg choice="opt">--usage</arg>
 		<arg choice="req">smb://host/share/path/to/file</arg>
@@ -78,13 +76,8 @@
 	</varlistentry>
 
 	<varlistentry>
-		<term>-u, --username=STRING</term>
-		<listitem><para>Username to use</para></listitem>
-	</varlistentry>
-
-	<varlistentry>
-		<term>-p, --password=STRING</term>
-		<listitem><para>Password to use</para></listitem>
+		<term> -U, --username=<replaceable>username[%password]</replaceable></term>
+		<listitem><para>Username (and password) to use</para></listitem>
 	</varlistentry>
 
 	<varlistentry>
@@ -108,11 +101,6 @@
 	</varlistentry>
 
 	<varlistentry>
-		<term>-P, --keep-permissions</term>
-		<listitem><para>Set same permissions on local file as are set on remote file.</para></listitem>
-	</varlistentry>
-
-	<varlistentry>
 		<term>-o, --outputfile</term>
 		<listitem><para>Write the file that is being downloaded to the specified file. Can not be used together with -R.</para></listitem>
 	</varlistentry>
@@ -153,7 +141,7 @@
 	</varlistentry>
 
 	<varlistentry>
-		<term>-U, --update</term>
+		<term>-u, --update</term>
 		<listitem><para>Download only when remote file is newer than local file or local file is missing.</para></listitem>
 	</varlistentry>
 
diff --git a/docs-xml/manpages/smbgetrc.5.xml b/docs-xml/manpages/smbgetrc.5.xml
index 630875b..f1bb8b5 100644
--- a/docs-xml/manpages/smbgetrc.5.xml
+++ b/docs-xml/manpages/smbgetrc.5.xml
@@ -7,7 +7,7 @@
 	<manvolnum>5</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">File Formats and Conventions</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -53,15 +53,11 @@
 			<listitem><para>Whether directories should be downloaded recursively</para></listitem>
 		</varlistentry>
 
-		<varlistentry><term>username <replaceable>name</replaceable></term>
-			<listitem><para>Username to use when logging in to the remote server. Use an empty string for anonymous access.
+		<varlistentry><term>user <replaceable>name[%password]</replaceable></term>
+			<listitem><para>Username (and password) to use when logging in to the remote server. Use an empty string for anonymous access.
 			</para></listitem>
 		</varlistentry>
 
-		<varlistentry><term>password <replaceable>pass</replaceable></term>
-			<listitem><para>Password to use when logging in.</para></listitem>
-		</varlistentry>
-
 		<varlistentry><term>workgroup <replaceable>wg</replaceable></term>
 			<listitem><para>Workgroup to use when logging in</para></listitem>
 		</varlistentry>
diff --git a/docs-xml/manpages/smbpasswd.5.xml b/docs-xml/manpages/smbpasswd.5.xml
index 5bfe488..a97e3be 100644
--- a/docs-xml/manpages/smbpasswd.5.xml
+++ b/docs-xml/manpages/smbpasswd.5.xml
@@ -7,7 +7,7 @@
 	<manvolnum>5</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">File Formats and Conventions</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smbpasswd.8.xml b/docs-xml/manpages/smbpasswd.8.xml
index 7c04657..5a57475 100644
--- a/docs-xml/manpages/smbpasswd.8.xml
+++ b/docs-xml/manpages/smbpasswd.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smbspool.8.xml b/docs-xml/manpages/smbspool.8.xml
index 2f2de08..56aa5d3 100644
--- a/docs-xml/manpages/smbspool.8.xml
+++ b/docs-xml/manpages/smbspool.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -50,6 +50,7 @@
 		<listitem><para>smb://server[:port]/printer</para></listitem>
 		<listitem><para>smb://workgroup/server[:port]/printer</para></listitem>
 		<listitem><para>smb://username:password@server[:port]/printer</para></listitem>
+		<listitem><para>smb://domain\username:password@server[:port]/printer</para></listitem>
 		<listitem><para>smb://username:password@workgroup/server[:port]/printer</para></listitem>
 	</itemizedlist>
 
@@ -62,6 +63,10 @@
 	pass the URI in argv[0], while shell scripts must set the 
 	<envar>DEVICE_URI</envar> environment variable prior to
 	running smbspool.</para>
+
+	<para>smbspool will accept URI escaped characters.  This allows setting
+	a domain in the username, or space in the printer name. For example
+	smb://domain%5Cusername/printer%20name</para>
 </refsect1>
 
 <refsect1>
diff --git a/docs-xml/manpages/smbstatus.1.xml b/docs-xml/manpages/smbstatus.1.xml
index 84d7b41..84bf0fb 100644
--- a/docs-xml/manpages/smbstatus.1.xml
+++ b/docs-xml/manpages/smbstatus.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smbta-util.8.xml b/docs-xml/manpages/smbta-util.8.xml
deleted file mode 100644
index 83abfe9..0000000
--- a/docs-xml/manpages/smbta-util.8.xml
+++ /dev/null
@@ -1,115 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<refentry id="smbta-util.8">
-
-<refmeta>
-	<refentrytitle>smbta-util</refentrytitle>
-	<manvolnum>8</manvolnum>
-	<refmiscinfo class="source">Samba</refmiscinfo>
-	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
-</refmeta>
-
-
-<refnamediv>
-	<refname>smbta-util</refname>
-	<refpurpose>control encryption in VFS smb_traffic_analyzer</refpurpose>
-</refnamediv>
-
-<refsynopsisdiv>
-
-	<cmdsynopsis>
-		<command>smbta-util</command>
-		<arg rep="repeat" choice="opt">
-		<replaceable>COMMANDS</replaceable>
-		</arg>
-	</cmdsynopsis>
-
-</refsynopsisdiv>
-
-<refsect1>
-	<title>DESCRIPTION</title>
-
-	<para>This tool is part of the
-	<citerefentry><refentrytitle>samba</refentrytitle>
-	<manvolnum>1</manvolnum></citerefentry> suite.</para>
-
-	<para><command>smbta-util</command> is a tool to ease the
-	configuration of the vfs_smb_traffic_analyzer module regarding
-	data encryption.</para>
-	<para>The user can generate a key, install a key (activating
-	encryption), or uninstall a key (deactivating encryption).
-	Any operation that installs a key will create a File containing
-	the key. This file can be used by smbta-tool on other machines
-	to install the same key from the file.</para>
-	
-
-</refsect1>
-
-
-<refsect1>
-	<title>COMMANDS</title>
-
-	<variablelist>
-
-		<varlistentry>
-		<term><option>-h</option></term>
-		<listitem><para>Show a short help text on the command line.
-		</para></listitem>
-		</varlistentry>
-
-		<varlistentry>
-		<term><option>-f</option>
-		<replaceable>KEYFILE</replaceable></term>
-		<listitem><para>Open an existing keyfile, read the key from
-		the file, and install the key, activating encryption.
-		</para></listitem>
-		</varlistentry>
-
-		<varlistentry>
-		<term><option>-g</option>
-		<replaceable>KEYFILE</replaceable></term>
-		<listitem><para>Generate a new random key, install the key,
-		activate encryption, and store the key into the file KEYFILE.
-		</para></listitem>
-		</varlistentry>
-
-		<varlistentry>
-		<term><option>-u</option></term>
-		<listitem><para>Uninstall the key, deactivating encryption.
-		</para></listitem>
-		</varlistentry>
-
-		<varlistentry>
-		<term><option>-s</option></term>
-		<listitem><para>Check if a key is installed.
-		</para></listitem>
-		</varlistentry>
-
-		<varlistentry>
-		<term><option>-c</option>
-		<replaceable>KEYFILE</replaceable></term>
-		<listitem><para>Create a KEYFILE from an installed key.
-		</para></listitem>
-		</varlistentry>
-
-
-	</variablelist>
-</refsect1>
-
-<refsect1>
-	<title>VERSION</title>
-	<para>This man page is correct for version 3.4 of the Samba suite.</para>
-</refsect1>
-
-<refsect1>
-	<title>AUTHOR</title>
-	<para> The original version of smbta-util was created by Holger Hetterich.
-	</para>
-	<para> The original Samba software and related utilities were
-	created by Andrew Tridgell.  Samba is now developed by the
-	Samba Team as an Open Source project similar to the way the
-	Linux kernel is developed.</para>
-</refsect1>
-
-</refentry>
diff --git a/docs-xml/manpages/smbtar.1.xml b/docs-xml/manpages/smbtar.1.xml
index 23cb8ad..bf1045a 100644
--- a/docs-xml/manpages/smbtar.1.xml
+++ b/docs-xml/manpages/smbtar.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/smbtree.1.xml b/docs-xml/manpages/smbtree.1.xml
index 69477fe..8470c26 100644
--- a/docs-xml/manpages/smbtree.1.xml
+++ b/docs-xml/manpages/smbtree.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/testparm.1.xml b/docs-xml/manpages/testparm.1.xml
index 8bb2aa9..9a4541b 100644
--- a/docs-xml/manpages/testparm.1.xml
+++ b/docs-xml/manpages/testparm.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_acl_tdb.8.xml b/docs-xml/manpages/vfs_acl_tdb.8.xml
index becbc55..460c844 100644
--- a/docs-xml/manpages/vfs_acl_tdb.8.xml
+++ b/docs-xml/manpages/vfs_acl_tdb.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_acl_xattr.8.xml b/docs-xml/manpages/vfs_acl_xattr.8.xml
index 82a919a..b6f8c03 100644
--- a/docs-xml/manpages/vfs_acl_xattr.8.xml
+++ b/docs-xml/manpages/vfs_acl_xattr.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_aio_fork.8.xml b/docs-xml/manpages/vfs_aio_fork.8.xml
index 07f61fd..55dbb69 100644
--- a/docs-xml/manpages/vfs_aio_fork.8.xml
+++ b/docs-xml/manpages/vfs_aio_fork.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_aio_linux.8.xml b/docs-xml/manpages/vfs_aio_linux.8.xml
index 92672ce..d6c2b06 100644
--- a/docs-xml/manpages/vfs_aio_linux.8.xml
+++ b/docs-xml/manpages/vfs_aio_linux.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_aio_pthread.8.xml b/docs-xml/manpages/vfs_aio_pthread.8.xml
index b3c2713..1f8161f 100644
--- a/docs-xml/manpages/vfs_aio_pthread.8.xml
+++ b/docs-xml/manpages/vfs_aio_pthread.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_audit.8.xml b/docs-xml/manpages/vfs_audit.8.xml
index c427f3f..102d24b 100644
--- a/docs-xml/manpages/vfs_audit.8.xml
+++ b/docs-xml/manpages/vfs_audit.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_btrfs.8.xml b/docs-xml/manpages/vfs_btrfs.8.xml
index 0a51e6f..d5d47c04 100644
--- a/docs-xml/manpages/vfs_btrfs.8.xml
+++ b/docs-xml/manpages/vfs_btrfs.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_cacheprime.8.xml b/docs-xml/manpages/vfs_cacheprime.8.xml
index b3ddcc9..5559f34 100644
--- a/docs-xml/manpages/vfs_cacheprime.8.xml
+++ b/docs-xml/manpages/vfs_cacheprime.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_cap.8.xml b/docs-xml/manpages/vfs_cap.8.xml
index af1f91d..334a805 100644
--- a/docs-xml/manpages/vfs_cap.8.xml
+++ b/docs-xml/manpages/vfs_cap.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_catia.8.xml b/docs-xml/manpages/vfs_catia.8.xml
index 0300730..c408023 100644
--- a/docs-xml/manpages/vfs_catia.8.xml
+++ b/docs-xml/manpages/vfs_catia.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_ceph.8.xml b/docs-xml/manpages/vfs_ceph.8.xml
index d250509..f6b4fe6 100644
--- a/docs-xml/manpages/vfs_ceph.8.xml
+++ b/docs-xml/manpages/vfs_ceph.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -74,7 +74,7 @@
 		<term>ceph:config_file = path</term>
 		<listitem>
 		<para>
-			Allows to define a ceph configfile to use. Empty by default.
+			Allows one to define a ceph configfile to use. Empty by default.
 		</para>
 		<para>
 			Example: ceph:config_file =
diff --git a/docs-xml/manpages/vfs_commit.8.xml b/docs-xml/manpages/vfs_commit.8.xml
index 6f0dcc9..27d070c 100644
--- a/docs-xml/manpages/vfs_commit.8.xml
+++ b/docs-xml/manpages/vfs_commit.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_crossrename.8.xml b/docs-xml/manpages/vfs_crossrename.8.xml
index 523b60b..583f336 100644
--- a/docs-xml/manpages/vfs_crossrename.8.xml
+++ b/docs-xml/manpages/vfs_crossrename.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_default_quota.8.xml b/docs-xml/manpages/vfs_default_quota.8.xml
index ce541ed..07b9d8d 100644
--- a/docs-xml/manpages/vfs_default_quota.8.xml
+++ b/docs-xml/manpages/vfs_default_quota.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_dirsort.8.xml b/docs-xml/manpages/vfs_dirsort.8.xml
index 7f26cf4..30a4d4a 100644
--- a/docs-xml/manpages/vfs_dirsort.8.xml
+++ b/docs-xml/manpages/vfs_dirsort.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_extd_audit.8.xml b/docs-xml/manpages/vfs_extd_audit.8.xml
index dc74201..5823a66 100644
--- a/docs-xml/manpages/vfs_extd_audit.8.xml
+++ b/docs-xml/manpages/vfs_extd_audit.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_fake_perms.8.xml b/docs-xml/manpages/vfs_fake_perms.8.xml
index facc8b0..58a5bb9 100644
--- a/docs-xml/manpages/vfs_fake_perms.8.xml
+++ b/docs-xml/manpages/vfs_fake_perms.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_fileid.8.xml b/docs-xml/manpages/vfs_fileid.8.xml
index 0482203..7eae2bc 100644
--- a/docs-xml/manpages/vfs_fileid.8.xml
+++ b/docs-xml/manpages/vfs_fileid.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_fruit.8.xml b/docs-xml/manpages/vfs_fruit.8.xml
index 80c565c..2ac5db7 100644
--- a/docs-xml/manpages/vfs_fruit.8.xml
+++ b/docs-xml/manpages/vfs_fruit.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_full_audit.8.xml b/docs-xml/manpages/vfs_full_audit.8.xml
index 653fdbf..f07db96 100644
--- a/docs-xml/manpages/vfs_full_audit.8.xml
+++ b/docs-xml/manpages/vfs_full_audit.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_glusterfs.8.xml b/docs-xml/manpages/vfs_glusterfs.8.xml
index 7368e1f..5693080 100644
--- a/docs-xml/manpages/vfs_glusterfs.8.xml
+++ b/docs-xml/manpages/vfs_glusterfs.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_gpfs.8.xml b/docs-xml/manpages/vfs_gpfs.8.xml
index e0c5951..d5552eb 100644
--- a/docs-xml/manpages/vfs_gpfs.8.xml
+++ b/docs-xml/manpages/vfs_gpfs.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_linux_xfs_sgid.8.xml b/docs-xml/manpages/vfs_linux_xfs_sgid.8.xml
index 637d2c9..e1c5e0f 100644
--- a/docs-xml/manpages/vfs_linux_xfs_sgid.8.xml
+++ b/docs-xml/manpages/vfs_linux_xfs_sgid.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_media_harmony.8.xml b/docs-xml/manpages/vfs_media_harmony.8.xml
index 5927dc6..b939c2a 100644
--- a/docs-xml/manpages/vfs_media_harmony.8.xml
+++ b/docs-xml/manpages/vfs_media_harmony.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_netatalk.8.xml b/docs-xml/manpages/vfs_netatalk.8.xml
index 68bc220..ad3569d 100644
--- a/docs-xml/manpages/vfs_netatalk.8.xml
+++ b/docs-xml/manpages/vfs_netatalk.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_offline.8.xml b/docs-xml/manpages/vfs_offline.8.xml
new file mode 100644
index 0000000..5a702b6
--- /dev/null
+++ b/docs-xml/manpages/vfs_offline.8.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="vfs_offline.8">
+
+<refmeta>
+	<refentrytitle>vfs_offline</refentrytitle>
+	<manvolnum>8</manvolnum>
+	<refmiscinfo class="source">Samba</refmiscinfo>
+	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+	<refname>vfs_offline</refname>
+	<refpurpose>Mark all files as offline</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+	<cmdsynopsis>
+		<command>vfs objects = offline</command>
+	</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+	<title>DESCRIPTION</title>
+
+	<para>This VFS module is part of the
+	<citerefentry><refentrytitle>samba</refentrytitle>
+	<manvolnum>7</manvolnum></citerefentry> suite.</para>
+
+	<para>The <command>vfs_offline</command> module marks all files
+	in the share as having the offline DOS attribute.</para>
+
+	<para>Files with the offline DOS attribute are handled differently
+	by the Windows SMB client, as well as by Windows Explorer. In
+	particular, Windows Explorer does not read those files for the sole
+	purpose of drawing a thumbnail, as it normally does. This can
+	improve user experience with some remote file systems.</para>
+
+</refsect1>
+
+<refsect1>
+	<title>EXAMPLES</title>
+
+	<para>Mark all files in a share as offline:</para>
+
+<programlisting>
+        <smbconfsection name="[remote]"/>
+	<smbconfoption name="vfs objects">offline</smbconfoption>
+</programlisting>
+
+</refsect1>
+
+<refsect1>
+	<title>VERSION</title>
+
+	<para>This man page is correct for version 4.4 of the Samba suite.
+	</para>
+</refsect1>
+
+<refsect1>
+	<title>AUTHOR</title>
+
+	<para>The original Samba software and related utilities
+	were created by Andrew Tridgell. Samba is now developed
+	by the Samba Team as an Open Source project similar
+	to the way the Linux kernel is developed.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/docs-xml/manpages/vfs_prealloc.8.xml b/docs-xml/manpages/vfs_prealloc.8.xml
index c3c1fb1..140bf96 100644
--- a/docs-xml/manpages/vfs_prealloc.8.xml
+++ b/docs-xml/manpages/vfs_prealloc.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_preopen.8.xml b/docs-xml/manpages/vfs_preopen.8.xml
index 5ef19a2..83ffdf0 100644
--- a/docs-xml/manpages/vfs_preopen.8.xml
+++ b/docs-xml/manpages/vfs_preopen.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 <refnamediv>
diff --git a/docs-xml/manpages/vfs_readahead.8.xml b/docs-xml/manpages/vfs_readahead.8.xml
index 10f553e..1c62f1b 100644
--- a/docs-xml/manpages/vfs_readahead.8.xml
+++ b/docs-xml/manpages/vfs_readahead.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_readonly.8.xml b/docs-xml/manpages/vfs_readonly.8.xml
index 4e9872f..1dce729 100644
--- a/docs-xml/manpages/vfs_readonly.8.xml
+++ b/docs-xml/manpages/vfs_readonly.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_recycle.8.xml b/docs-xml/manpages/vfs_recycle.8.xml
index 70d7e66..7b1701e 100644
--- a/docs-xml/manpages/vfs_recycle.8.xml
+++ b/docs-xml/manpages/vfs_recycle.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_scannedonly.8.xml b/docs-xml/manpages/vfs_scannedonly.8.xml
deleted file mode 100644
index 5f569b7..0000000
--- a/docs-xml/manpages/vfs_scannedonly.8.xml
+++ /dev/null
@@ -1,243 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
-<refentry id="vfs_scannedonly.8">
-
-<refmeta>
-	<refentrytitle>vfs_scannedonly</refentrytitle>
-	<manvolnum>8</manvolnum>
-	<refmiscinfo class="source">Samba</refmiscinfo>
-	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
-</refmeta>
-
-
-<refnamediv>
-	<refname>vfs_scannedonly</refname>
-	<refpurpose>Ensures that only files that have been scanned for viruses are
-	visible and accessible to the end user.</refpurpose>
-</refnamediv>
-
-<refsynopsisdiv>
-	<cmdsynopsis>
-		<command>vfs objects = scannedonly</command>
-	</cmdsynopsis>
-</refsynopsisdiv>
-
-<refsect1>
-	<title>DESCRIPTION</title>
-
-	<para>This VFS module is part of the
-	<citerefentry><refentrytitle>samba</refentrytitle>
-	<manvolnum>8</manvolnum></citerefentry> suite.</para>
-
-	<para>The <command>vfs_scannedonly</command> VFS module ensures that
-	only files that have been scanned for viruses are visible and accessible
-	to the end user. If non-scanned files are found an anti-virus scanning
-	daemon is notified. The anti-virus scanning daemon is not part of the
-	Samba suite.
-	</para>
-
-	<para>Scannedonly comes in two parts: a samba vfs module and (one or
-	more) daemons. The daemon scans files. If a certain file is clean,
-	a second file is created with prefix <filename>.scanned:</filename>.
-	The Samba module simply looks if such a <filename>.scanned:</filename>
-	file exists, and is newer than the pertinent file. If this is the case,
-	the file is shown to the user. If this is not the case, the file is not
-	returned in a directory listing (configurable), and cannot be opened
-	(configurable). The Samba vfs module will notify the daemon to scan
-	this file.
-	</para>
-
-	<para>So what happens for the user in the default configuration. The
-	first time a directory is listed, it shows files as 'file is being
-	scanned for viruses, but after the first time all files are shown.
-	There is a utility scannedonly_prescan that can help you to prescan
-	all directories. When new files are written the daemon is notified
-	immediately after the file is complete.
-	</para>
-
-	<para>If a virus is found by the daemon, a file with a warning message
-	is created in the directory of the user, a warning is sent to the logs,
-	and the file is renamed to have prefix <filename>.virus:</filename>.
-	Files with the <filename>.virus:</filename> prefix are never shown to
-	the user and all access is denied.
-	</para>
-
-	<para>This module is stackable.</para>
-
-</refsect1>
-
-<refsect1>
-	<title>CONFIGURATION</title>
-
-	<para><command>vfs_scannedonly</command> relies on a anti-virus scanning
-	daemon that listens on the scannedonly socket (unix domain socket or UDP
-	socket).
-	</para>
-</refsect1>
-
-<refsect1>
-        <title>OPTIONS</title>
-
-        <variablelist>
-		<varlistentry>
-		<term>scannedonly:domain_socket = True </term>
-		<listitem>
-		<para>Whether to use a unix domain socket or not (false reverts
-		to use udp)
-		</para>
-		</listitem>
-	</varlistentry>
-
-	<varlistentry>
-		<term>scannedonly:socketname = /var/lib/scannedonly/scan</term>
-		<listitem>
-		<para>The location of the unix domain socket to connect to</para>
-		</listitem>
-	</varlistentry>
-
-	<varlistentry>
-		<term>scannedonly:portnum = 2020</term>
-		<listitem>
-		<para>The udp port number to connect to
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:scanhost = localhost</term>
-		<listitem>
-		<para>
-		When using UDP the host that runs the scanning daemon (this host
-		needs access to the files!)
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:show_special_files = True</term>
-		<listitem>
-		<para>
-		Whether sockets, devices and fifo's (all not scanned for
-		viruses) should be visible to the user
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:rm_hidden_files_on_rmdir = True</term>
-		<listitem>
-		<para>
-		Whether files that are not visible (<filename>.scanned:</filename>
-		files, <filename>.failed:</filename> files and <filename>.virus:
-		</filename> files) should be deleted if the user tries to remove
-		the directory. If false, the user will get the "directory is not
-		empty" error.
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:hide_nonscanned_files = True</term>
-		<listitem>
-		<para>
-		If false, all non-scanned files are visible in directory listings.
-		If such files are found in a directory listing the scanning daemon
-		is notified that scanning is required. Access to non-scanned files
-		is still denied (see scannedonly:allow_nonscanned_files).
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:scanning_message = is being scanned for
-	viruses</term>
-		<listitem>
-		<para>
-		If non-scanned files are hidden
-		(if scannedonly:hide_nonscanned_files = True), a fake 0 byte file
-		is shown. The filename is the original filename with the message
-		as suffix.
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:recheck_time_open = 50</term>
-		<listitem>
-		<para>
-		If a non-scanned file is opened, the vfs module will wait
-		recheck_tries_open times for recheck_time_open milliseconds for
-		the scanning daemon to create a <filename>.scanned:</filename>
-		file. For small files that are scanned by the daemon within the
-		time (tries * time) the behavior will be just like on-access
-		scanning.
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:recheck_tries_open = 100</term>
-		<listitem>
-		<para>
-		See recheck_time_open.
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:recheck_time_readdir = 50</term>
-		<listitem>
-		<para>
-		If a non-scanned file is in a directory listing the vfs module
-		notifies the daemon (once for all files that need scanning in
-		that directory), and waits recheck_tries_readdir times for
-		recheck_time_readdir milliseconds. Only used when
-		hide_nonscanned_files is false.
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:recheck_tries_readdir = 20</term>
-		<listitem>
-		<para>
-		See recheck_time_readdir.
-		</para>
-		</listitem>
-	</varlistentry>
-	<varlistentry><term>scannedonly:allow_nonscanned_files = False</term>
-		<listitem>
-		<para>
-		Allow access to non-scanned files. The daemon is notified,
-		however, and special files such as <filename>.scanned:</filename>
-		files. <filename>.virus:</filename> files and
-		<filename>.failed:</filename> files are not listed.
-		</para>
-		</listitem>
-	</varlistentry>
-
-	</variablelist>
-</refsect1>
-
-<refsect1>
-	<title>EXAMPLES</title>
-
-	<para>Enable anti-virus scanning:</para>
-<programlisting>
-        <smbconfsection name="[homes]"/>
-	<smbconfoption name="vfs objects">scannedonly</smbconfoption>
-	<smbconfoption name="scannedonly:hide_nonscanned_files">False</smbconfoption>
-</programlisting>
-
-</refsect1>
-
-<refsect1>
-	<title>CAVEATS</title>
-
-	<para>This is not true on-access scanning. However, it is very fast
-	for files that have been scanned already.
-	</para>
-</refsect1>
-
-<refsect1>
-	<title>VERSION</title>
-
-	<para>This man page is correct for version 4.0.0 of the Samba suite.
-	</para>
-</refsect1>
-
-<refsect1>
-	<title>AUTHOR</title>
-
-	<para>The original Samba software and related utilities
-	were created by Andrew Tridgell. Scannedonly was
-	developed for Samba by Olivier Sessink. Samba is now developed
-	by the Samba Team as an Open Source project similar
-	to the way the Linux kernel is developed.</para>
-
-</refsect1>
-
-</refentry>
diff --git a/docs-xml/manpages/vfs_shadow_copy.8.xml b/docs-xml/manpages/vfs_shadow_copy.8.xml
index be7de83..c4aabe5 100644
--- a/docs-xml/manpages/vfs_shadow_copy.8.xml
+++ b/docs-xml/manpages/vfs_shadow_copy.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_shadow_copy2.8.xml b/docs-xml/manpages/vfs_shadow_copy2.8.xml
index 0cf1e54..fbc0651 100644
--- a/docs-xml/manpages/vfs_shadow_copy2.8.xml
+++ b/docs-xml/manpages/vfs_shadow_copy2.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -182,7 +182,7 @@
 		</term>
                 <listitem>
 		<para>
-		The basedir option allows to specify a directory
+		The basedir option allows one to specify a directory
 		between the share's mount point and the share root,
 		relative to which the file system's snapshots are taken.
 		</para>
@@ -226,6 +226,46 @@
                 </varlistentry>
 
 		<varlistentry>
+		<term>shadow:snapsharepath = SNAPSHAREPATH
+		</term>
+		<listitem>
+		<para>
+		With this parameter, one can specify the path of the share's
+		root directory in snapshots, relative to the snapshot's
+		root directory. It is an alternative method to
+		<command>shadow:basedir</command>, allowing greater control.
+		</para>
+		<para>
+		For example, if within each
+		snapshot the files of the share have a
+		<command>path/to/share/</command> prefix, then
+		<command>shadow:snapsharepath</command> can be
+		set to <command>path/to/share</command>.
+		</para>
+		<para>
+		With this parameter, it is no longer assumed that a
+		snapshot represents an image of the original file system or
+		a portion of it. For example, a system could perform
+		backups of only files contained in shares, and then
+		expose the backup files in a logical structure:
+		</para>
+		<itemizedlist>
+		<listitem><para>share1/</para></listitem>
+		<listitem><para>share2/</para></listitem>
+		<listitem><para>.../</para></listitem>
+		</itemizedlist>
+		<para>
+		Note that the <command>shadow:snapdirseverywhere</command>
+		and the <command>shadow:basedir</command> options
+		are incompatible with <command>shadow:snapsharepath</command>
+		and disable <command>shadow:snapsharepath</command> setting.
+		</para>
+		<para>Example: shadow:snapsharepath = path/to/share</para>
+		<para>Default: shadow:snapsharepath = NOT SPECIFIED</para>
+                </listitem>
+		</varlistentry>
+
+		<varlistentry>
                 <term>shadow:sort = asc/desc
                 </term>
                 <listitem>
@@ -272,7 +312,7 @@
 		<term>shadow:sscanf = yes/no</term>
 		<listitem>
 		<para>
-		This paramter can be used to specify that the time in
+		This parameter can be used to specify that the time in
 		format string is given as an unsigned long integer (%lu)
 		rather than a time strptime() can parse.
 		The result must be a unix time_t time.
@@ -351,10 +391,10 @@
 		only particular subtrees of the filesystem as well.
 		</para>
 		<para>
-		Note that <command>shadow:snapdirseverywhere</command>
+		Note that <command>shadow:crossmountpoints</command>
 		depends on <command>shadow:snapdir</command> and needs it to be
 		a relative path. Setting an absolute snapdir path disables
-		<command>shadow:snapdirseverywhere</command>.
+		<command>shadow:crossmountpoints</command>.
 		</para>
 		<para>
 		Note that this option is incompatible with the
diff --git a/docs-xml/manpages/vfs_shell_snap.8.xml b/docs-xml/manpages/vfs_shell_snap.8.xml
index dc6eb064..6207cd0 100644
--- a/docs-xml/manpages/vfs_shell_snap.8.xml
+++ b/docs-xml/manpages/vfs_shell_snap.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_smb_traffic_analyzer.8.xml b/docs-xml/manpages/vfs_smb_traffic_analyzer.8.xml
deleted file mode 100644
index 3cdc813..0000000
--- a/docs-xml/manpages/vfs_smb_traffic_analyzer.8.xml
+++ /dev/null
@@ -1,299 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
-<refentry id="vfs_smb_traffic_analyzer.8">
-
-<refmeta>
-	<refentrytitle>smb_traffic_analyzer</refentrytitle>
-	<manvolnum>8</manvolnum>
-	<refmiscinfo class="source">Samba</refmiscinfo>
-	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
-</refmeta>
-
-
-<refnamediv>
-	<refname>vfs_smb_traffic_analyzer</refname>
-	<refpurpose>log Samba VFS read and write operations through a socket
-	to a helper application</refpurpose>
-</refnamediv>
-
-<refsynopsisdiv>
-	<cmdsynopsis>
-		<command>vfs objects = smb_traffic_analyzer</command>
-	</cmdsynopsis>
-</refsynopsisdiv>
-
-<refsect1>
-	<title>DESCRIPTION</title>
-
-	<para>This VFS module is part of the
-	<citerefentry><refentrytitle>samba</refentrytitle>
-	<manvolnum>7</manvolnum></citerefentry> suite.</para>
-
-	<para>The <command>vfs_smb_traffic_analyzer</command> VFS module logs
-	client file operations on a Samba server and sends this data
-	over a socket to a helper program (in the following the "Receiver"),
-	which feeds a SQL database. More
-	information on the helper programs can be obtained from the
-	homepage of the project at:
-	http://holger123.wordpress.com/smb-traffic-analyzer/
-	Since the VFS module depends on a receiver that is doing something with
-	the data, it is evolving in it's development. Therefore, the module
-	works with different protocol versions, and the receiver has to be able
-	to decode the protocol that is used. The protocol version 1 was
-	introduced to Samba at September 25, 2008. It was a very simple
-	protocol, supporting only a small list of VFS operations, and had
-	several drawbacks. The protocol version 2 is a try to solve the
-	problems version 1 had while at the same time adding new features.
-	With the release of Samba 4.0.0, the module will run protocol version 2
-	by default.
-	</para>
-</refsect1>
-
-<refsect1>
-	<title>Protocol version 1 documentation</title>
-	<para><command>vfs_smb_traffic_analyzer</command> protocol version 1 is aware
-		of the following VFS operations:</para>
-
-	<simplelist>
-        <member>write</member>
-        <member>pwrite</member>
-	<member>read</member>
-	<member>pread</member>
-	</simplelist>
-
-	<para><command>vfs_smb_traffic_analyzer</command> sends the following data
-	in a fixed format separated by a comma through either an internet or a
-	unix domain socket:</para>
-	<programlisting>
-	BYTES|USER|DOMAIN|READ/WRITE|SHARE|FILENAME|TIMESTAMP
-	</programlisting>
-
-	<para>Description of the records:
-
-	<itemizedlist>
-	<listitem><para><command>BYTES</command> - the length in bytes of the VFS operation</para></listitem>
-	<listitem><para><command>USER</command> - the user who initiated the operation</para></listitem>
-	<listitem><para><command>DOMAIN</command> - the domain of the user</para></listitem>
-	<listitem><para><command>READ/WRITE</command> - either "W" for a write operation or "R" for read</para></listitem>
-	<listitem><para><command>SHARE</command> - the name of the share on which the VFS operation occurred</para></listitem>
-	<listitem><para><command>FILENAME</command> - the name of the file that was used by the VFS operation</para></listitem>
-	<listitem><para><command>TIMESTAMP</command> - a timestamp, formatted as "yyyy-mm-dd hh-mm-ss.ms" indicating when the VFS operation occurred</para></listitem>
-	<listitem><para><command>IP</command> - The IP Address (v4 or v6) of the client machine that initiated the VFS operation.</para></listitem>
-	</itemizedlist>
-
-	</para>
-
-	<para>This module is stackable.</para>
-
-</refsect1>
-
-<refsect1>
-	<title>Drawbacks of protocol version 1</title>
-	<para>Several drawbacks have been seen with protocol version 1 over time.</para>
-	<itemizedlist>
-	<listitem>
-		<para>
-			<command>Problematic parsing - </command>
-			Protocol version 1 uses hyphen and comma to separate blocks of data. Once there is a
-			filename with a hyphen, you will run into problems because the receiver decodes the
-			data in a wrong way.
-		</para>
-	</listitem>
-	<listitem>
-		<para>
-			<command>Insecure network transfer - </command>
-			Protocol version 1 sends all it's data as plaintext over the network.
-		</para>
-	</listitem>
-	<listitem>
-		<para>
-			<command>Limited set of supported VFS operations - </command>
-			Protocol version 1 supports only four VFS operations.
-		</para>
-	</listitem>
-	<listitem>
-		<para>
-			<command>No subreleases of the protocol - </command>
-			Protocol version 1 is fixed on it's version, making it unable to introduce new
-			features or bugfixes through compatible sub-releases.
-		</para>
-	</listitem>
-	</itemizedlist>
-</refsect1>
-<refsect1>
-	<title>Version 2 of the protocol</title>
-	<para>Protocol version 2 is an approach to solve the problems introduced with protcol v1.
-	From the users perspective, the following changes are most prominent among other enhancements:
-	</para>
-	<itemizedlist>
-		<listitem>
-		<para>
-		The data from the module may be send encrypted, with a key stored in secrets.tdb. The
-		Receiver then has to use the same key. The module does AES block encryption over the
-		data to send.
-		</para>
-		</listitem>
-		<listitem>
-		<para>
-		The module now can identify itself against the receiver with a sub-release number, where
-		the receiver may run with a different sub-release number than the module. However, as
-		long as both run on the V2.x protocol, the receiver will not crash, even if the module
-		uses features only implemented in the newer subrelease. Ultimately, if the module uses
-		a new feature from a newer subrelease, and the receiver runs an older protocol, it is just
-		ignoring the functionality. Of course it is best to have both the receiver and the module
-		running the same subrelease of the protocol.
-		</para>
-		</listitem>
-		<listitem>
-		<para>
-		The parsing problems of protocol V1 can no longer happen, because V2 is marshalling the
-		data packages in a proper way.
-		</para>
-		</listitem>
-		<listitem>
-		<para>
-		The module now potentially has the ability to create data on every VFS function. As of
-		protocol V2.0, there is support for 8 VFS functions, namely write,read,pread,pwrite,
-		rename,chdir,mkdir and rmdir. Supporting more VFS functions is one of the targets for the
-		upcoming sub-releases.
-		</para>
-		</listitem>
-	</itemizedlist>
-	<para>
-		To enable protocol V2, the protocol_version vfs option has to be used (see OPTIONS).
-	</para>
-		
-</refsect1>		
-
-<refsect1>
-	<title>OPTIONS with protocol V1 and V2.x</title>
-
-	<variablelist>
-
-		<varlistentry>
-                <term>smb_traffic_analyzer:mode = STRING</term>
-                <listitem>
-                <para>If STRING matches to "unix_domain_socket", the module will
-		use a unix domain socket located at /var/tmp/stadsocket, if
-		STRING contains an different string or is not defined, the module will
-		use an internet domain socket for data transfer.</para>
-
-                </listitem>
-                </varlistentry>
-
-
-		<varlistentry>
-		<term>smb_traffic_analyzer:host = STRING</term>
-		<listitem>
-		<para>The module will send the data to the system named with
-		the hostname STRING.</para>
-
-		</listitem>
-		</varlistentry>
-
-		<varlistentry>
-		<term>smb_traffic_analyzer:port = STRING</term>
-		<listitem>
-		<para>The module will send the data using the TCP port given
-		in STRING.
-		</para>
-		</listitem>
-		</varlistentry>
-		<varlistentry>
-		<term>smb_traffic_analyzer:anonymize_prefix = STRING</term>
-		<listitem>
-		<para>The module will replace the user names with a prefix
-		given by STRING and a simple hash number. In version 2.x
-		of the protocol, the users SID will also be anonymized.
-		</para>
-
-		</listitem>
-		</varlistentry>
-
-		<varlistentry>
-		<term>smb_traffic_analyzer:total_anonymization = STRING</term>
-		<listitem>
-		<para>If STRING matches to 'yes', the module will replace
-		any user name with the string given by the option 
-		smb_traffic_analyzer:anonymize_prefix, without generating
-		an additional hash number. This means that any transfer data
-		will be mapped to a single user, leading to a total 
-		anonymization of user related data. In version 2.x of the
-		protocol, the users SID will also be anonymized.</para>
-		</listitem>
-		</varlistentry>
-
-		<varlistentry>
-		<term>smb_traffic_analyzer:protocol_version = STRING</term>
-		<listitem>
-		<para>If STRING matches to V1, the module will use version 1 of the
-		protocol. If STRING is not given, the module will use version 2 of the
-		protocol, which is the default.
-		</para>
-		</listitem>
-		</varlistentry>
-
-	</variablelist>
-</refsect1>
-
-<refsect1>
-	<title>EXAMPLES</title>
-	<para>Running protocol V2 on share "example_share", using an internet socket.</para>
-	<programlisting>
-	<smbconfsection name="[example_share]"/>
-	<smbconfoption name="path">/data/example</smbconfoption>
-	<smbconfoption name="vfs_objects">smb_traffic_analyzer</smbconfoption>
-	<smbconfoption name="smb_traffic_analyzer:host">examplehost</smbconfoption>
-	<smbconfoption name="smb_traffic_analyzer:port">3491</smbconfoption>
-	</programlisting>
-
-	<para>The module running on share "example_share", using a unix domain socket</para>
-	<programlisting>
-	<smbconfsection name="[example_share]"/>
-	<smbconfoption name="path">/data/example</smbconfoption>
-	<smbconfoption name="vfs objects">smb_traffic_analyzer</smbconfoption>
-	<smbconfoption name="smb_traffic_analyzer:mode">unix_domain_socket</smbconfoption>
-	</programlisting>
-
-	<para>The module running on share "example_share", using an internet socket,
-	connecting to host "examplehost" on port 3491.</para>
-	<programlisting>
-	<smbconfsection name="[example_share]"/>
-	<smbconfoption name="path">/data/example</smbconfoption>
-	<smbconfoption name="vfs objects">smb_traffic_analyzer</smbconfoption>
-	<smbconfoption name="smb_traffic_analyzer:host">examplehost</smbconfoption>
-	<smbconfoption name="smb_traffic_analyzer:port">3491</smbconfoption>
-	</programlisting>
-
-	<para>The module running on share "example_share", using an internet socket,
-	connecting to host "examplehost" on port 3491, anonymizing user names with
-	the prefix "User".</para>
-	<programlisting>
-	<smbconfsection name="[example_share]"/>
-	<smbconfoption name="path">/data/example</smbconfoption>
-	<smbconfoption name="vfs objects">smb_traffic_analyzer</smbconfoption>
-	<smbconfoption name="smb_traffic_analyzer:host">examplehost</smbconfoption>
-	<smbconfoption name="smb_traffic_analyzer:port">3491</smbconfoption>
-	<smbconfoption name="smb_traffic_analyzer:anonymize_prefix">User</smbconfoption>
-	</programlisting>
-</refsect1>
-
-<refsect1>
-	<title>VERSION</title>
-	<para>This man page is correct for version 3.3 of the Samba suite.
-	</para>
-</refsect1>
-
-<refsect1>
-	<title>AUTHOR</title>
-
-	<para>The original Samba software and related utilities
-	were created by Andrew Tridgell. Samba is now developed
-	by the Samba Team as an Open Source project similar
-	to the way the Linux kernel is developed.</para>
-
-	<para>The original version of the VFS module and the
-	helper tools were created by Holger Hetterich.</para>
-</refsect1>
-</refentry>
diff --git a/docs-xml/manpages/vfs_snapper.8.xml b/docs-xml/manpages/vfs_snapper.8.xml
index 3e27aea..e0cdc72 100644
--- a/docs-xml/manpages/vfs_snapper.8.xml
+++ b/docs-xml/manpages/vfs_snapper.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_streams_depot.8.xml b/docs-xml/manpages/vfs_streams_depot.8.xml
index 8dd4316..3f453c4 100644
--- a/docs-xml/manpages/vfs_streams_depot.8.xml
+++ b/docs-xml/manpages/vfs_streams_depot.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_streams_xattr.8.xml b/docs-xml/manpages/vfs_streams_xattr.8.xml
index 8f5cd72..eeecebd 100644
--- a/docs-xml/manpages/vfs_streams_xattr.8.xml
+++ b/docs-xml/manpages/vfs_streams_xattr.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_syncops.8.xml b/docs-xml/manpages/vfs_syncops.8.xml
index fdbe92b..5883113 100644
--- a/docs-xml/manpages/vfs_syncops.8.xml
+++ b/docs-xml/manpages/vfs_syncops.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_time_audit.8.xml b/docs-xml/manpages/vfs_time_audit.8.xml
index 6df4005..40d3659 100644
--- a/docs-xml/manpages/vfs_time_audit.8.xml
+++ b/docs-xml/manpages/vfs_time_audit.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_tsmsm.8.xml b/docs-xml/manpages/vfs_tsmsm.8.xml
index 68ddab9..ffa0e30 100644
--- a/docs-xml/manpages/vfs_tsmsm.8.xml
+++ b/docs-xml/manpages/vfs_tsmsm.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_unityed_media.8.xml b/docs-xml/manpages/vfs_unityed_media.8.xml
index cca26cf..cef7e22 100644
--- a/docs-xml/manpages/vfs_unityed_media.8.xml
+++ b/docs-xml/manpages/vfs_unityed_media.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_worm.8.xml b/docs-xml/manpages/vfs_worm.8.xml
index 4bf3ca1..1a20bdb 100644
--- a/docs-xml/manpages/vfs_worm.8.xml
+++ b/docs-xml/manpages/vfs_worm.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_xattr_tdb.8.xml b/docs-xml/manpages/vfs_xattr_tdb.8.xml
index 35bc4d7..96942fe 100644
--- a/docs-xml/manpages/vfs_xattr_tdb.8.xml
+++ b/docs-xml/manpages/vfs_xattr_tdb.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfs_zfsacl.8.xml b/docs-xml/manpages/vfs_zfsacl.8.xml
index bb4d3b8..7f2629b 100644
--- a/docs-xml/manpages/vfs_zfsacl.8.xml
+++ b/docs-xml/manpages/vfs_zfsacl.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/vfstest.1.xml b/docs-xml/manpages/vfstest.1.xml
index 3b464b2..4dec4f2 100644
--- a/docs-xml/manpages/vfstest.1.xml
+++ b/docs-xml/manpages/vfstest.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/wbinfo.1.xml b/docs-xml/manpages/wbinfo.1.xml
index ee1d993..4c3edab 100644
--- a/docs-xml/manpages/wbinfo.1.xml
+++ b/docs-xml/manpages/wbinfo.1.xml
@@ -7,7 +7,7 @@
 	<manvolnum>1</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">User Commands</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
@@ -259,7 +259,7 @@
 
 		<varlistentry>
 		<term>--krb5ccname <replaceable>KRB5CCNAME</replaceable></term>
-		<listitem><para>Allows to request a sepcific kerberos credential
+		<listitem><para>Allows one to request a sepcific kerberos credential
 				cache type used for authentication.
 		</para></listitem>
 		</varlistentry>
diff --git a/docs-xml/manpages/winbind_krb5_locator.7.xml b/docs-xml/manpages/winbind_krb5_locator.7.xml
index cda71dc..a92c2db 100644
--- a/docs-xml/manpages/winbind_krb5_locator.7.xml
+++ b/docs-xml/manpages/winbind_krb5_locator.7.xml
@@ -7,7 +7,7 @@
 	<manvolnum>7</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">7</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/manpages/winbindd.8.xml b/docs-xml/manpages/winbindd.8.xml
index b29193b..5e9b5c8 100644
--- a/docs-xml/manpages/winbindd.8.xml
+++ b/docs-xml/manpages/winbindd.8.xml
@@ -7,7 +7,7 @@
 	<manvolnum>8</manvolnum>
 	<refmiscinfo class="source">Samba</refmiscinfo>
 	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
-	<refmiscinfo class="version">4.3</refmiscinfo>
+	<refmiscinfo class="version">4.4</refmiscinfo>
 </refmeta>
 
 
diff --git a/docs-xml/smbdotconf/base/bindinterfacesonly.xml b/docs-xml/smbdotconf/base/bindinterfacesonly.xml
index 31b462c..9a148f3 100644
--- a/docs-xml/smbdotconf/base/bindinterfacesonly.xml
+++ b/docs-xml/smbdotconf/base/bindinterfacesonly.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="bind interfaces only"
-				type="boolean"
+                 type="boolean"
                  context="G"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/base/comment.xml b/docs-xml/smbdotconf/base/comment.xml
index 3c2c3b1..b0dd91c 100644
--- a/docs-xml/smbdotconf/base/comment.xml
+++ b/docs-xml/smbdotconf/base/comment.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="comment"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This is a text field that is seen next to a share 
diff --git a/docs-xml/smbdotconf/base/configbackend.xml b/docs-xml/smbdotconf/base/configbackend.xml
index 864ec3c..2237569 100644
--- a/docs-xml/smbdotconf/base/configbackend.xml
+++ b/docs-xml/smbdotconf/base/configbackend.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="config backend"
                  context="G"
-				 type="enum"
+                 type="enum"
+                 enumlist="enum_config_backend"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/base/doscharset.xml b/docs-xml/smbdotconf/base/doscharset.xml
index 8a18c93..c99b840 100644
--- a/docs-xml/smbdotconf/base/doscharset.xml
+++ b/docs-xml/smbdotconf/base/doscharset.xml
@@ -1,8 +1,9 @@
 <samba:parameter name="dos charset"
-				 type="string"
+                 type="string"
                  context="G"
                  constant="1"
-				 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 handler="handle_dos_charset"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
         <para>DOS SMB clients assume the server has 
 	the same charset as they do. This option specifies which 
diff --git a/docs-xml/smbdotconf/base/interfaces.xml b/docs-xml/smbdotconf/base/interfaces.xml
index 39c90b9..b804e64 100644
--- a/docs-xml/smbdotconf/base/interfaces.xml
+++ b/docs-xml/smbdotconf/base/interfaces.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="interfaces"
                  context="G"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
         <para>This option allows you to override the default 
@@ -38,7 +38,28 @@
 	By default Samba enables all active interfaces that are broadcast capable
 	except the loopback adaptor (IP address 127.0.0.1).
 	</para>
-	
+
+	<para>
+	In order to support SMB3 multi-channel configurations, smbd understands
+	some extra data that can be appended after the actual interface with
+	this extended syntax:
+	</para>
+
+	<para>
+	interface[;key1=value1[,key2=value2[...]]]
+	</para>
+
+	<para>
+	Known keys are speed, capability, and if_index. Speed is specified in
+	bits per second. Known capabilities are RSS and RDMA. The
+	if_index should be used with care: the values must not coincide with
+	indexes used by the kernel.
+	Note that these options are mainly intended for testing and
+	development rather than for production use. At least on Linux systems,
+	these values should be auto-detected, but the settings can serve
+	as last a resort when autodetection is not working or is not available.
+	</para>
+
 	<para>
 	The example below configures three network interfaces corresponding 
 	to the eth0 device and IP addresses 192.168.2.10 and 192.168.3.10. 
diff --git a/docs-xml/smbdotconf/base/multicastdnsregister.xml b/docs-xml/smbdotconf/base/multicastdnsregister.xml
index 87559e5..2c330ab 100644
--- a/docs-xml/smbdotconf/base/multicastdnsregister.xml
+++ b/docs-xml/smbdotconf/base/multicastdnsregister.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="multicast dns register"
-				type="boolean"
+                 type="boolean"
                  context="G"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/base/netbiosaliases.xml b/docs-xml/smbdotconf/base/netbiosaliases.xml
index 46f97e2..0304ab0 100644
--- a/docs-xml/smbdotconf/base/netbiosaliases.xml
+++ b/docs-xml/smbdotconf/base/netbiosaliases.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="netbios aliases"
                  context="G"
-				 type="list"
+                 type="cmdlist"
+                 handler="handle_netbios_aliases"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
         <para>This is a list of NetBIOS names that nmbd will 
diff --git a/docs-xml/smbdotconf/base/netbiosname.xml b/docs-xml/smbdotconf/base/netbiosname.xml
index ed7dd5e..a7d9e2c 100644
--- a/docs-xml/smbdotconf/base/netbiosname.xml
+++ b/docs-xml/smbdotconf/base/netbiosname.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="netbios name"
                  context="G"
-                 type="string"
+                 type="ustring"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/base/netbiosscope.xml b/docs-xml/smbdotconf/base/netbiosscope.xml
index 811e1c6..c5be028 100644
--- a/docs-xml/smbdotconf/base/netbiosscope.xml
+++ b/docs-xml/smbdotconf/base/netbiosscope.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="netbios scope"
                  context="G"
-				 type="string"
+                 type="ustring"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/base/realm.xml b/docs-xml/smbdotconf/base/realm.xml
index ab56ec5..8499c78 100644
--- a/docs-xml/smbdotconf/base/realm.xml
+++ b/docs-xml/smbdotconf/base/realm.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="realm"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
+                 handler="handle_realm"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
         <para>This option specifies the kerberos realm to use. The realm is 
diff --git a/docs-xml/smbdotconf/base/sharebackend.xml b/docs-xml/smbdotconf/base/sharebackend.xml
index fc8b6d4..08124cd 100644
--- a/docs-xml/smbdotconf/base/sharebackend.xml
+++ b/docs-xml/smbdotconf/base/sharebackend.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="share backend"
                  context="G"
                  type="string"
-		 constant="1"
+                 constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/base/unixcharset.xml b/docs-xml/smbdotconf/base/unixcharset.xml
index ff8f6bb..06754a4 100644
--- a/docs-xml/smbdotconf/base/unixcharset.xml
+++ b/docs-xml/smbdotconf/base/unixcharset.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="unix charset"
-	context="G"
-	type="string"
+                 context="G"
+                 type="string"
                  constant="1"
+                 handler="handle_charset"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
         <para>Specifies the charset the unix machine 
diff --git a/docs-xml/smbdotconf/base/workgroup.xml b/docs-xml/smbdotconf/base/workgroup.xml
index 49aec41..eb8ca18 100644
--- a/docs-xml/smbdotconf/base/workgroup.xml
+++ b/docs-xml/smbdotconf/base/workgroup.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="workgroup"
                  context="G"
-				 type="string"
+                 type="ustring"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/browse/browseable.xml b/docs-xml/smbdotconf/browse/browseable.xml
index c56d3fc..64dfcf0 100644
--- a/docs-xml/smbdotconf/browse/browseable.xml
+++ b/docs-xml/smbdotconf/browse/browseable.xml
@@ -1,4 +1,6 @@
-<samba:parameter name="browseable" context="S" type="boolean"
+<samba:parameter name="browseable"
+                 context="S"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>browsable</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/browse/browselist.xml b/docs-xml/smbdotconf/browse/browselist.xml
index adf7454..f053e81 100644
--- a/docs-xml/smbdotconf/browse/browselist.xml
+++ b/docs-xml/smbdotconf/browse/browselist.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="browse list"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This controls whether <citerefentry><refentrytitle>smbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/browse/domainmaster.xml b/docs-xml/smbdotconf/browse/domainmaster.xml
index a47800b..8817f2b 100644
--- a/docs-xml/smbdotconf/browse/domainmaster.xml
+++ b/docs-xml/smbdotconf/browse/domainmaster.xml
@@ -1,5 +1,6 @@
 <samba:parameter name="domain master"
-				 type="enum"
+                 type="enum"
+                 enumlist="enum_bool_auto"
                  context="G"
                  function="_domain_master"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
diff --git a/docs-xml/smbdotconf/browse/enhancedbrowsing.xml b/docs-xml/smbdotconf/browse/enhancedbrowsing.xml
index 8b1b531..7ad8930 100644
--- a/docs-xml/smbdotconf/browse/enhancedbrowsing.xml
+++ b/docs-xml/smbdotconf/browse/enhancedbrowsing.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="enhanced browsing"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option enables a couple of enhancements to 
diff --git a/docs-xml/smbdotconf/browse/lmannounce.xml b/docs-xml/smbdotconf/browse/lmannounce.xml
index 6d712c4..1ec5052 100644
--- a/docs-xml/smbdotconf/browse/lmannounce.xml
+++ b/docs-xml/smbdotconf/browse/lmannounce.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="lm announce"
                  context="G"
-				 type="enum"
+                 type="enum"
+                 enumlist="enum_bool_auto"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter determines if <citerefentry><refentrytitle>nmbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/browse/lminterval.xml b/docs-xml/smbdotconf/browse/lminterval.xml
index 8a68e09..da33658 100644
--- a/docs-xml/smbdotconf/browse/lminterval.xml
+++ b/docs-xml/smbdotconf/browse/lminterval.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="lm interval"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>If Samba is set to produce Lanman announce 
diff --git a/docs-xml/smbdotconf/browse/oslevel.xml b/docs-xml/smbdotconf/browse/oslevel.xml
index fc386d2..43ba861 100644
--- a/docs-xml/smbdotconf/browse/oslevel.xml
+++ b/docs-xml/smbdotconf/browse/oslevel.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="os level"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/browse/preferredmaster.xml b/docs-xml/smbdotconf/browse/preferredmaster.xml
index e32ca52..15ebd24 100644
--- a/docs-xml/smbdotconf/browse/preferredmaster.xml
+++ b/docs-xml/smbdotconf/browse/preferredmaster.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="preferred master"
                  context="G"
-				 type="boolean-auto"
-                 generated_function="0"
+                 type="enum"
+                 enumlist="enum_bool_auto"
+                 function="_preferred_master"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>prefered master</synonym>
  <description>
diff --git a/docs-xml/smbdotconf/domain/allowdnsupdates.xml b/docs-xml/smbdotconf/domain/allowdnsupdates.xml
index 1563d29..6c0a0d0 100644
--- a/docs-xml/smbdotconf/domain/allowdnsupdates.xml
+++ b/docs-xml/smbdotconf/domain/allowdnsupdates.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="allow dns updates"
                  context="G"
                  type="enum"
+                 enumlist="enum_dns_update_settings"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option determines what kind of updates to the DNS are allowed.
diff --git a/docs-xml/smbdotconf/domain/dnsupdatecommand.xml b/docs-xml/smbdotconf/domain/dnsupdatecommand.xml
index 70c311e..40cbc5b 100644
--- a/docs-xml/smbdotconf/domain/dnsupdatecommand.xml
+++ b/docs-xml/smbdotconf/domain/dnsupdatecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="dns update command"
                  context="G"
-                 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option sets the command that is called when there are
diff --git a/docs-xml/smbdotconf/domain/machinepasswordtimeout.xml b/docs-xml/smbdotconf/domain/machinepasswordtimeout.xml
index b53ee3c..be4e0e9 100644
--- a/docs-xml/smbdotconf/domain/machinepasswordtimeout.xml
+++ b/docs-xml/smbdotconf/domain/machinepasswordtimeout.xml
@@ -1,20 +1,23 @@
 <samba:parameter name="machine password timeout"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 	 <description>
 
 	<para>
-	If a Samba server is a member of a Windows NT Domain (see the <smbconfoption
-	name="security">domain</smbconfoption> parameter) then periodically a running smbd process will try and change
-	the MACHINE ACCOUNT PASSWORD stored in the TDB called <filename moreinfo="none">private/secrets.tdb
+	If a Samba server is a member of a Windows NT or Active Directory Domain (see the <smbconfoption
+	name="security">domain</smbconfoption> and
+	<smbconfoption name="security">ads</smbconfoption> parameters),
+	then periodically a running winbindd process will try and change
+	the MACHINE ACCOUNT PASSWORD stored in the TDB called <filename moreinfo="none">secrets.tdb
 	</filename>.  This parameter specifies how often this password will be changed, in seconds. The default is one
 	week (expressed in seconds), the same as a Windows NT Domain member server.
 	</para>
 
 	<para>
 	See also <citerefentry><refentrytitle>smbpasswd</refentrytitle> <manvolnum>8</manvolnum></citerefentry>,
-	and the <smbconfoption name="security">domain</smbconfoption> parameter.
+	and the <smbconfoption name="security">domain</smbconfoption>
+	and <smbconfoption name="security">ads</smbconfoption> parameters.
 	</para>
 
 </description>
diff --git a/docs-xml/smbdotconf/domain/nsupdatecommand.xml b/docs-xml/smbdotconf/domain/nsupdatecommand.xml
index 9481058..8978ade 100644
--- a/docs-xml/smbdotconf/domain/nsupdatecommand.xml
+++ b/docs-xml/smbdotconf/domain/nsupdatecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="nsupdate command"
                  context="G"
-                 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option sets the path to the <filename>nsupdate</filename>
diff --git a/docs-xml/smbdotconf/domain/rndccommand.xml b/docs-xml/smbdotconf/domain/rndccommand.xml
index 72df82f..d9ac4ea 100644
--- a/docs-xml/smbdotconf/domain/rndccommand.xml
+++ b/docs-xml/smbdotconf/domain/rndccommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="rndc command"
                  context="G"
-                 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option specifies the path to the name server control utility.
diff --git a/docs-xml/smbdotconf/domain/spnupdatecommand.xml b/docs-xml/smbdotconf/domain/spnupdatecommand.xml
index cbeb657..9dcce13 100644
--- a/docs-xml/smbdotconf/domain/spnupdatecommand.xml
+++ b/docs-xml/smbdotconf/domain/spnupdatecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="spn update command"
                  context="G"
-                 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option sets the command that for updating
diff --git a/docs-xml/smbdotconf/filename/casesensitive.xml b/docs-xml/smbdotconf/filename/casesensitive.xml
index 8c0995c..f0e53be 100644
--- a/docs-xml/smbdotconf/filename/casesensitive.xml
+++ b/docs-xml/smbdotconf/filename/casesensitive.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="case sensitive"
                  context="S"
-		 type="enum"
+                 type="enum"
+                 enumlist="enum_bool_auto"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>casesignames</synonym>
 
diff --git a/docs-xml/smbdotconf/filename/defaultcase.xml b/docs-xml/smbdotconf/filename/defaultcase.xml
index d167ae3..988bad9 100644
--- a/docs-xml/smbdotconf/filename/defaultcase.xml
+++ b/docs-xml/smbdotconf/filename/defaultcase.xml
@@ -1,6 +1,8 @@
 <samba:parameter name="default case"
-	context="S"
-	type="enum" xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="enum"
+                 enumlist="enum_case"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>See the section on <smbconfoption name="name mangling"/>.
 	Also note the <smbconfoption name="short preserve case"/> parameter.</para>
diff --git a/docs-xml/smbdotconf/filename/deletevetofiles.xml b/docs-xml/smbdotconf/filename/deletevetofiles.xml
index 31138aa..581dc05 100644
--- a/docs-xml/smbdotconf/filename/deletevetofiles.xml
+++ b/docs-xml/smbdotconf/filename/deletevetofiles.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="delete veto files"
-				 type="boolean"
+                 type="boolean"
                  context="S"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/filename/hidedotfiles.xml b/docs-xml/smbdotconf/filename/hidedotfiles.xml
index 9f31f2c..54e0b0a 100644
--- a/docs-xml/smbdotconf/filename/hidedotfiles.xml
+++ b/docs-xml/smbdotconf/filename/hidedotfiles.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="hide dot files"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This is a boolean parameter that controls whether 
diff --git a/docs-xml/smbdotconf/filename/hidespecialfiles.xml b/docs-xml/smbdotconf/filename/hidespecialfiles.xml
index ea2b68a..904fd3a 100644
--- a/docs-xml/smbdotconf/filename/hidespecialfiles.xml
+++ b/docs-xml/smbdotconf/filename/hidespecialfiles.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="hide special files"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/docs-xml/smbdotconf/filename/hideunreadable.xml b/docs-xml/smbdotconf/filename/hideunreadable.xml
index 992f135..361320c 100644
--- a/docs-xml/smbdotconf/filename/hideunreadable.xml
+++ b/docs-xml/smbdotconf/filename/hideunreadable.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="hide unreadable"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
 	<para>This parameter prevents clients from seeing the
diff --git a/docs-xml/smbdotconf/filename/hideunwriteablefiles.xml b/docs-xml/smbdotconf/filename/hideunwriteablefiles.xml
index 6665860..97a44f0 100644
--- a/docs-xml/smbdotconf/filename/hideunwriteablefiles.xml
+++ b/docs-xml/smbdotconf/filename/hideunwriteablefiles.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="hide unwriteable files"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/filename/manglednames.xml b/docs-xml/smbdotconf/filename/manglednames.xml
index dfd85c4..bd5d97f 100644
--- a/docs-xml/smbdotconf/filename/manglednames.xml
+++ b/docs-xml/smbdotconf/filename/manglednames.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="mangled names"
-				 type="boolean"
+                 type="boolean"
                  context="S"
                  parm="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
diff --git a/docs-xml/smbdotconf/filename/mangleprefix.xml b/docs-xml/smbdotconf/filename/mangleprefix.xml
index 96ff963..8cb7dea 100644
--- a/docs-xml/smbdotconf/filename/mangleprefix.xml
+++ b/docs-xml/smbdotconf/filename/mangleprefix.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="mangle prefix"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para> controls the number of prefix
diff --git a/docs-xml/smbdotconf/filename/manglingchar.xml b/docs-xml/smbdotconf/filename/manglingchar.xml
index e40a12e..374d1ee 100644
--- a/docs-xml/smbdotconf/filename/manglingchar.xml
+++ b/docs-xml/smbdotconf/filename/manglingchar.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="mangling char"
                  context="S"
-		 type="char"
+                 type="char"
                  parm="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
diff --git a/docs-xml/smbdotconf/filename/manglingmethod.xml b/docs-xml/smbdotconf/filename/manglingmethod.xml
index 4b68067..559ed6c 100644
--- a/docs-xml/smbdotconf/filename/manglingmethod.xml
+++ b/docs-xml/smbdotconf/filename/manglingmethod.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="mangling method"
-			 context="G"
-				 type="string"
+                 context="G"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para> controls the algorithm used for the generating
diff --git a/docs-xml/smbdotconf/filename/maparchive.xml b/docs-xml/smbdotconf/filename/maparchive.xml
index 33ff876..44f49cd 100644
--- a/docs-xml/smbdotconf/filename/maparchive.xml
+++ b/docs-xml/smbdotconf/filename/maparchive.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="map archive"
                  context="S"
-				 type="boolean"
-				 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This controls whether the DOS archive attribute 
diff --git a/docs-xml/smbdotconf/filename/maphidden.xml b/docs-xml/smbdotconf/filename/maphidden.xml
index cbf9c10..3ad05a6 100644
--- a/docs-xml/smbdotconf/filename/maphidden.xml
+++ b/docs-xml/smbdotconf/filename/maphidden.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="map hidden"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/filename/mapreadonly.xml b/docs-xml/smbdotconf/filename/mapreadonly.xml
index f4ac7c8..54a5e01 100644
--- a/docs-xml/smbdotconf/filename/mapreadonly.xml
+++ b/docs-xml/smbdotconf/filename/mapreadonly.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="map readonly"
                  context="S"
-		 type="enum"
+                 type="enum"
+                 enumlist="enum_map_readonly"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/filename/mapsystem.xml b/docs-xml/smbdotconf/filename/mapsystem.xml
index 5605d88..53c11bd 100644
--- a/docs-xml/smbdotconf/filename/mapsystem.xml
+++ b/docs-xml/smbdotconf/filename/mapsystem.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="map system"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/filename/maxstatcachesize.xml b/docs-xml/smbdotconf/filename/maxstatcachesize.xml
index 40790df..63f91e7 100644
--- a/docs-xml/smbdotconf/filename/maxstatcachesize.xml
+++ b/docs-xml/smbdotconf/filename/maxstatcachesize.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="max stat cache size"
                  context="G"
-		 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter limits the size in memory of any 
diff --git a/docs-xml/smbdotconf/filename/preservecase.xml b/docs-xml/smbdotconf/filename/preservecase.xml
index 875900d..a7eae26 100644
--- a/docs-xml/smbdotconf/filename/preservecase.xml
+++ b/docs-xml/smbdotconf/filename/preservecase.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="preserve case"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/filename/shortpreservecase.xml b/docs-xml/smbdotconf/filename/shortpreservecase.xml
index 90188a0..ecb5652 100644
--- a/docs-xml/smbdotconf/filename/shortpreservecase.xml
+++ b/docs-xml/smbdotconf/filename/shortpreservecase.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="short preserve case"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/filename/statcache.xml b/docs-xml/smbdotconf/filename/statcache.xml
index ec1ee25..2b19777 100644
--- a/docs-xml/smbdotconf/filename/statcache.xml
+++ b/docs-xml/smbdotconf/filename/statcache.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="stat cache"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter determines if <citerefentry><refentrytitle>smbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/filename/storedosattributes.xml b/docs-xml/smbdotconf/filename/storedosattributes.xml
index acd78b0..30665eb 100644
--- a/docs-xml/smbdotconf/filename/storedosattributes.xml
+++ b/docs-xml/smbdotconf/filename/storedosattributes.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="store dos attributes"
                  context="S"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/filename/vetofiles.xml b/docs-xml/smbdotconf/filename/vetofiles.xml
index 8065dcf..acbc3dc 100644
--- a/docs-xml/smbdotconf/filename/vetofiles.xml
+++ b/docs-xml/smbdotconf/filename/vetofiles.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="veto files"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
 	<para>
diff --git a/docs-xml/smbdotconf/filename/vetooplockfiles.xml b/docs-xml/smbdotconf/filename/vetooplockfiles.xml
index b99ab00..dde3705 100644
--- a/docs-xml/smbdotconf/filename/vetooplockfiles.xml
+++ b/docs-xml/smbdotconf/filename/vetooplockfiles.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="veto oplock files"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
 	<para>
diff --git a/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml b/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml
index 92ea541..3152f06 100644
--- a/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml
+++ b/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="client ldap sasl wrapping"
                  context="G"
-		 type="enum"
+                 type="enum"
+                 enumlist="enum_ldap_sasl_wrapping"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/ldap/ldapadmindn.xml b/docs-xml/smbdotconf/ldap/ldapadmindn.xml
index 3f50799..f993742 100644
--- a/docs-xml/smbdotconf/ldap/ldapadmindn.xml
+++ b/docs-xml/smbdotconf/ldap/ldapadmindn.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="ldap admin dn"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
-				 <description>
+<description>
 
 	 <para>
 	The <smbconfoption name="ldap admin dn"/> defines the Distinguished  Name (DN) name used by Samba to contact
diff --git a/docs-xml/smbdotconf/ldap/ldapconnectiontimeout.xml b/docs-xml/smbdotconf/ldap/ldapconnectiontimeout.xml
index 7c77fe3..b176897 100644
--- a/docs-xml/smbdotconf/ldap/ldapconnectiontimeout.xml
+++ b/docs-xml/smbdotconf/ldap/ldapconnectiontimeout.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="ldap connection timeout"
-		 context="G"
-			type="integer"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="integer"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This parameter tells the LDAP library calls which timeout in seconds
diff --git a/docs-xml/smbdotconf/ldap/ldapdeletedn.xml b/docs-xml/smbdotconf/ldap/ldapdeletedn.xml
index a9518d1..47ffad8 100644
--- a/docs-xml/smbdotconf/ldap/ldapdeletedn.xml
+++ b/docs-xml/smbdotconf/ldap/ldapdeletedn.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ldap delete dn"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para> This parameter specifies whether a delete
diff --git a/docs-xml/smbdotconf/ldap/ldapderef.xml b/docs-xml/smbdotconf/ldap/ldapderef.xml
index 23ad3e7..920d1ae 100644
--- a/docs-xml/smbdotconf/ldap/ldapderef.xml
+++ b/docs-xml/smbdotconf/ldap/ldapderef.xml
@@ -1,5 +1,8 @@
-<samba:parameter name="ldap deref" context="G" type="enum"
-	xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<samba:parameter name="ldap deref"
+                 context="G"
+                 type="enum"
+                 enumlist="enum_ldap_deref"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 
 <description>
 
diff --git a/docs-xml/smbdotconf/ldap/ldapfollowreferral.xml b/docs-xml/smbdotconf/ldap/ldapfollowreferral.xml
index ebdfb89..3130a7b 100644
--- a/docs-xml/smbdotconf/ldap/ldapfollowreferral.xml
+++ b/docs-xml/smbdotconf/ldap/ldapfollowreferral.xml
@@ -1,5 +1,8 @@
-<samba:parameter name="ldap follow referral" context="G" type="enum"
-	xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<samba:parameter name="ldap follow referral"
+                 context="G"
+                 type="enum"
+                 enumlist="enum_bool_auto"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 
 <description>
 
diff --git a/docs-xml/smbdotconf/ldap/ldapgroupsuffix.xml b/docs-xml/smbdotconf/ldap/ldapgroupsuffix.xml
index bb18832..7de0fac 100644
--- a/docs-xml/smbdotconf/ldap/ldapgroupsuffix.xml
+++ b/docs-xml/smbdotconf/ldap/ldapgroupsuffix.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="ldap group suffix"
                  context="G"
-				 type="string"
-                 generated_function="0"
+                 type="string"
+                 function="_ldap_group_suffix"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the suffix that is 
diff --git a/docs-xml/smbdotconf/ldap/ldapidmapsuffix.xml b/docs-xml/smbdotconf/ldap/ldapidmapsuffix.xml
index aac09df..1fe7e8a 100644
--- a/docs-xml/smbdotconf/ldap/ldapidmapsuffix.xml
+++ b/docs-xml/smbdotconf/ldap/ldapidmapsuffix.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="ldap idmap suffix"
                  context="G"
-		 type="string"
-                 generated_function="0"
+                 type="string"
+                 function="_ldap_idmap_suffix"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/ldap/ldapmachinesuffix.xml b/docs-xml/smbdotconf/ldap/ldapmachinesuffix.xml
index 2572246..e82675b 100644
--- a/docs-xml/smbdotconf/ldap/ldapmachinesuffix.xml
+++ b/docs-xml/smbdotconf/ldap/ldapmachinesuffix.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="ldap machine suffix"
-		context="G"
-		type="string"
-                 generated_function="0"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 function="_ldap_machine_suffix"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/ldap/ldappagesize.xml b/docs-xml/smbdotconf/ldap/ldappagesize.xml
index 311eba1..577ea2a 100644
--- a/docs-xml/smbdotconf/ldap/ldappagesize.xml
+++ b/docs-xml/smbdotconf/ldap/ldappagesize.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="ldap page size"
-	context="G"
-	type="integer"
-        xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="integer"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This parameter specifies the number of entries per page.
@@ -12,6 +12,6 @@
 	This parameter specifies the size of these pages.
 	</para>
 </description>
-<value type="default">1024</value>
+<value type="default">1000</value>
 <value type="example">512</value>
 </samba:parameter>
diff --git a/docs-xml/smbdotconf/ldap/ldappasswdsync.xml b/docs-xml/smbdotconf/ldap/ldappasswdsync.xml
index 7166e9b..42bc916 100644
--- a/docs-xml/smbdotconf/ldap/ldappasswdsync.xml
+++ b/docs-xml/smbdotconf/ldap/ldappasswdsync.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="ldap passwd sync"
-			context="G"
-			type="enum"
-			xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="enum"
+                 enumlist="enum_ldap_passwd_sync"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 
 <synonym>ldap password sync</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/ldap/ldapreplicationsleep.xml b/docs-xml/smbdotconf/ldap/ldapreplicationsleep.xml
index a8236d8..059c77e 100644
--- a/docs-xml/smbdotconf/ldap/ldapreplicationsleep.xml
+++ b/docs-xml/smbdotconf/ldap/ldapreplicationsleep.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ldap replication sleep"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/ldap/ldapsameditposix.xml b/docs-xml/smbdotconf/ldap/ldapsameditposix.xml
index 6496bfb..e7f36e6 100644
--- a/docs-xml/smbdotconf/ldap/ldapsameditposix.xml
+++ b/docs-xml/smbdotconf/ldap/ldapsameditposix.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ldapsam:editposix"
-	context="G"
-	type="string"
+                 context="G"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/docs-xml/smbdotconf/ldap/ldapsamtrusted.xml b/docs-xml/smbdotconf/ldap/ldapsamtrusted.xml
index 4556679..1d593e6 100644
--- a/docs-xml/smbdotconf/ldap/ldapsamtrusted.xml
+++ b/docs-xml/smbdotconf/ldap/ldapsamtrusted.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ldapsam:trusted"
-	context="G"
-	type="string"
+                 context="G"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/docs-xml/smbdotconf/ldap/ldapssl.xml b/docs-xml/smbdotconf/ldap/ldapssl.xml
index eade027..a50c88e 100644
--- a/docs-xml/smbdotconf/ldap/ldapssl.xml
+++ b/docs-xml/smbdotconf/ldap/ldapssl.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="ldap ssl"
                  context="G"
-				 type="enum"
+                 type="enum"
+                 enumlist="enum_ldap_ssl"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option is used to define whether or not Samba should
diff --git a/docs-xml/smbdotconf/ldap/ldapsslads.xml b/docs-xml/smbdotconf/ldap/ldapsslads.xml
index 4f1771a..4fdf4dc 100644
--- a/docs-xml/smbdotconf/ldap/ldapsslads.xml
+++ b/docs-xml/smbdotconf/ldap/ldapsslads.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="ldap ssl ads"
-		 context="G"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option is used to define whether or not Samba should
 	use SSL when connecting to the ldap server using
diff --git a/docs-xml/smbdotconf/ldap/ldapsuffix.xml b/docs-xml/smbdotconf/ldap/ldapsuffix.xml
index 7db13c2..aeff0dd 100644
--- a/docs-xml/smbdotconf/ldap/ldapsuffix.xml
+++ b/docs-xml/smbdotconf/ldap/ldapsuffix.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ldap suffix"
                  context="G"
-		 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies the base for all ldap suffixes and for storing the sambaDomain object.</para>
diff --git a/docs-xml/smbdotconf/ldap/ldaptimeout.xml b/docs-xml/smbdotconf/ldap/ldaptimeout.xml
index e920ddc..f421eeb 100644
--- a/docs-xml/smbdotconf/ldap/ldaptimeout.xml
+++ b/docs-xml/smbdotconf/ldap/ldaptimeout.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ldap timeout"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/ldap/ldapusersuffix.xml b/docs-xml/smbdotconf/ldap/ldapusersuffix.xml
index 71fdc9e..8e6b8a3 100644
--- a/docs-xml/smbdotconf/ldap/ldapusersuffix.xml
+++ b/docs-xml/smbdotconf/ldap/ldapusersuffix.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="ldap user suffix"
-	context="G"
-	type="string"
-                 generated_function="0"
-        xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 function="_ldap_user_suffix"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This parameter specifies where users are added to the tree. If this parameter is unset, 
diff --git a/docs-xml/smbdotconf/locking/blockinglocks.xml b/docs-xml/smbdotconf/locking/blockinglocks.xml
index 493f281..2794124 100644
--- a/docs-xml/smbdotconf/locking/blockinglocks.xml
+++ b/docs-xml/smbdotconf/locking/blockinglocks.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="blocking locks"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter controls the behavior 
diff --git a/docs-xml/smbdotconf/locking/cscpolicy.xml b/docs-xml/smbdotconf/locking/cscpolicy.xml
index 6131e12..511639e 100644
--- a/docs-xml/smbdotconf/locking/cscpolicy.xml
+++ b/docs-xml/smbdotconf/locking/cscpolicy.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="csc policy"
                  context="S"
-				 type="enum"
+                 type="enum"
+                 enumlist="enum_csc_policy"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/locking/fakeoplocks.xml b/docs-xml/smbdotconf/locking/fakeoplocks.xml
index fa004d7..c5622ae 100644
--- a/docs-xml/smbdotconf/locking/fakeoplocks.xml
+++ b/docs-xml/smbdotconf/locking/fakeoplocks.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="fake oplocks"
-				 type="boolean"
+                 type="boolean"
                  context="S"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/locking/kerneloplocks.xml b/docs-xml/smbdotconf/locking/kerneloplocks.xml
index d8fe223..a22cdf2 100644
--- a/docs-xml/smbdotconf/locking/kerneloplocks.xml
+++ b/docs-xml/smbdotconf/locking/kerneloplocks.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="kernel oplocks"
-				 type="boolean"
-		 context="S"
+                 type="boolean"
+                 context="S"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>For UNIXes that support kernel based <smbconfoption name="oplocks"/>
diff --git a/docs-xml/smbdotconf/locking/kernelsharemodes.xml b/docs-xml/smbdotconf/locking/kernelsharemodes.xml
index 5b64b77..134fffc 100644
--- a/docs-xml/smbdotconf/locking/kernelsharemodes.xml
+++ b/docs-xml/smbdotconf/locking/kernelsharemodes.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="kernel share modes"
-		 type="boolean"
-		 context="S"
+                 type="boolean"
+                 context="S"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/locking/level2oplocks.xml b/docs-xml/smbdotconf/locking/level2oplocks.xml
index 496701b..f411449 100644
--- a/docs-xml/smbdotconf/locking/level2oplocks.xml
+++ b/docs-xml/smbdotconf/locking/level2oplocks.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="level2 oplocks"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter controls whether Samba supports
diff --git a/docs-xml/smbdotconf/locking/locking.xml b/docs-xml/smbdotconf/locking/locking.xml
index 0021c50..15bc98d 100644
--- a/docs-xml/smbdotconf/locking/locking.xml
+++ b/docs-xml/smbdotconf/locking/locking.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="locking"
-				 type="boolean"
+                 type="boolean"
                  context="S"
                  parm="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
diff --git a/docs-xml/smbdotconf/locking/lockspintime.xml b/docs-xml/smbdotconf/locking/lockspintime.xml
index 8e40877b..689d7dd 100644
--- a/docs-xml/smbdotconf/locking/lockspintime.xml
+++ b/docs-xml/smbdotconf/locking/lockspintime.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="lock spin time"
-				 type="integer"
+                 type="integer"
                  context="G"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/locking/oplockbreakwaittime.xml b/docs-xml/smbdotconf/locking/oplockbreakwaittime.xml
index bede040..f07b6c9 100644
--- a/docs-xml/smbdotconf/locking/oplockbreakwaittime.xml
+++ b/docs-xml/smbdotconf/locking/oplockbreakwaittime.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="oplock break wait time"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
 	<para>
diff --git a/docs-xml/smbdotconf/locking/oplockcontentionlimit.xml b/docs-xml/smbdotconf/locking/oplockcontentionlimit.xml
index 3ee3c45..edaa7d7 100644
--- a/docs-xml/smbdotconf/locking/oplockcontentionlimit.xml
+++ b/docs-xml/smbdotconf/locking/oplockcontentionlimit.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="oplock contention limit"
                  context="S"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/locking/oplocks.xml b/docs-xml/smbdotconf/locking/oplocks.xml
index a5e163b..1d72649 100644
--- a/docs-xml/smbdotconf/locking/oplocks.xml
+++ b/docs-xml/smbdotconf/locking/oplocks.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="oplocks"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/locking/posixlocking.xml b/docs-xml/smbdotconf/locking/posixlocking.xml
index 2136047..f38b2bd 100644
--- a/docs-xml/smbdotconf/locking/posixlocking.xml
+++ b/docs-xml/smbdotconf/locking/posixlocking.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="posix locking"
-				 type="boolean"
+                 type="boolean"
                  context="S"
                  parm="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
diff --git a/docs-xml/smbdotconf/locking/smb2leases.xml b/docs-xml/smbdotconf/locking/smb2leases.xml
index 9241bc8..5ca13d2 100644
--- a/docs-xml/smbdotconf/locking/smb2leases.xml
+++ b/docs-xml/smbdotconf/locking/smb2leases.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="smb2 leases"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/locking/strictlocking.xml b/docs-xml/smbdotconf/locking/strictlocking.xml
index 29ace66..89a1bf7 100644
--- a/docs-xml/smbdotconf/locking/strictlocking.xml
+++ b/docs-xml/smbdotconf/locking/strictlocking.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="strict locking"
                  context="S"
-				 type="enum"
+                 type="enum"
+                 enumlist="enum_bool_auto"
                  parm="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/logging/debugclass.xml b/docs-xml/smbdotconf/logging/debugclass.xml
index b9ffbe3..eee3cc5 100644
--- a/docs-xml/smbdotconf/logging/debugclass.xml
+++ b/docs-xml/smbdotconf/logging/debugclass.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="debug class"
                  context="G"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/logging/debughirestimestamp.xml b/docs-xml/smbdotconf/logging/debughirestimestamp.xml
index 5c9e468..72598d7 100644
--- a/docs-xml/smbdotconf/logging/debughirestimestamp.xml
+++ b/docs-xml/smbdotconf/logging/debughirestimestamp.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="debug hires timestamp"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/logging/debugpid.xml b/docs-xml/smbdotconf/logging/debugpid.xml
index 5c81625..8e6436c 100644
--- a/docs-xml/smbdotconf/logging/debugpid.xml
+++ b/docs-xml/smbdotconf/logging/debugpid.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="debug pid"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/logging/debugprefixtimestamp.xml b/docs-xml/smbdotconf/logging/debugprefixtimestamp.xml
index e894142..0a004d4 100644
--- a/docs-xml/smbdotconf/logging/debugprefixtimestamp.xml
+++ b/docs-xml/smbdotconf/logging/debugprefixtimestamp.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="debug prefix timestamp"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/logging/debugtimestamp.xml b/docs-xml/smbdotconf/logging/debugtimestamp.xml
deleted file mode 100644
index 205eac8..0000000
--- a/docs-xml/smbdotconf/logging/debugtimestamp.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<samba:parameter name="debug timestamp"
-                 context="G"
-				 type="boolean"
-                 function="timestamp_logs"
-                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
-<synonym>timestamp logs</synonym>
-<description>
-    <para>
-    Samba debug log messages are timestamped by default. If you are running at a high 
-    <smbconfoption name="debug level"/> these timestamps can be distracting. This 
-    boolean parameter allows timestamping to be turned off.
-	</para>
-</description>
-<value type="default">yes</value>
-</samba:parameter>
diff --git a/docs-xml/smbdotconf/logging/debuguid.xml b/docs-xml/smbdotconf/logging/debuguid.xml
index cc715ec..1dd1dbf 100644
--- a/docs-xml/smbdotconf/logging/debuguid.xml
+++ b/docs-xml/smbdotconf/logging/debuguid.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="debug uid"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/logging/ldapdebuglevel.xml b/docs-xml/smbdotconf/logging/ldapdebuglevel.xml
index 1b51767..2092b7d 100644
--- a/docs-xml/smbdotconf/logging/ldapdebuglevel.xml
+++ b/docs-xml/smbdotconf/logging/ldapdebuglevel.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="ldap debug level"
-		 type="integer"
-		context="G"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="integer"
+                 context="G"
+                 handler="handle_ldap_debug_level"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 		This parameter controls the debug level of the LDAP library
diff --git a/docs-xml/smbdotconf/logging/ldapdebugthreshold.xml b/docs-xml/smbdotconf/logging/ldapdebugthreshold.xml
index ab69cc5..2783ac9 100644
--- a/docs-xml/smbdotconf/logging/ldapdebugthreshold.xml
+++ b/docs-xml/smbdotconf/logging/ldapdebugthreshold.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="ldap debug threshold"
-		type="integer"
-		context="G"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="integer"
+                 context="G"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 		This parameter controls the Samba debug level at which
diff --git a/docs-xml/smbdotconf/logging/logfile.xml b/docs-xml/smbdotconf/logging/logfile.xml
index 4a7be66..eb751cb 100644
--- a/docs-xml/smbdotconf/logging/logfile.xml
+++ b/docs-xml/smbdotconf/logging/logfile.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="log file"
                  context="G"
-				 type="string"
+                 type="string"
                  function="logfile"
+                 handler="handle_logfile"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/logging/logging.xml b/docs-xml/smbdotconf/logging/logging.xml
index f779d8f..8524884 100644
--- a/docs-xml/smbdotconf/logging/logging.xml
+++ b/docs-xml/smbdotconf/logging/logging.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="logging"
-		 type="string"
-		 context="G"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="string"
+                 context="G"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
   <para>This parameter configures logging backends. Multiple
diff --git a/docs-xml/smbdotconf/logging/loglevel.xml b/docs-xml/smbdotconf/logging/loglevel.xml
index 6a22554..f4e2adb 100644
--- a/docs-xml/smbdotconf/logging/loglevel.xml
+++ b/docs-xml/smbdotconf/logging/loglevel.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="log level"
-				 type="string"
+                 type="string"
                  context="G"
+                 handler="handle_debug_list"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>debuglevel</synonym>
 <description>
@@ -10,7 +11,7 @@
     </para>
 
     <para>This parameter has been extended since the 2.2.x 
-    series, now it allows to specify the debug level for multiple 
+    series, now it allows one to specify the debug level for multiple 
     debug classes. This is to give greater flexibility in the configuration 
     of the system. The following debug classes are currently implemented:
     </para>
diff --git a/docs-xml/smbdotconf/logging/maxlogsize.xml b/docs-xml/smbdotconf/logging/maxlogsize.xml
index 3373f16..8a1979d 100644
--- a/docs-xml/smbdotconf/logging/maxlogsize.xml
+++ b/docs-xml/smbdotconf/logging/maxlogsize.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="max log size"
-				 type="integer"
+                 type="bytes"
                  context="G"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/logging/syslog.xml b/docs-xml/smbdotconf/logging/syslog.xml
index 23ca499..78e694e 100644
--- a/docs-xml/smbdotconf/logging/syslog.xml
+++ b/docs-xml/smbdotconf/logging/syslog.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="syslog"
                  context="G"
-				 type="integer"
+                 type="integer"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/logging/syslogonly.xml b/docs-xml/smbdotconf/logging/syslogonly.xml
index 9847f0c..b9aea2d 100644
--- a/docs-xml/smbdotconf/logging/syslogonly.xml
+++ b/docs-xml/smbdotconf/logging/syslogonly.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="syslog only"
                  context="G"
-				 type="boolean"
+                 type="boolean"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/logging/timestamplogs.xml b/docs-xml/smbdotconf/logging/timestamplogs.xml
new file mode 100644
index 0000000..28003c3
--- /dev/null
+++ b/docs-xml/smbdotconf/logging/timestamplogs.xml
@@ -0,0 +1,14 @@
+<samba:parameter name="timestamp logs"
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<synonym>debug timestamp</synonym>
+<description>
+    <para>
+    Samba debug log messages are timestamped by default. If you are running at a high
+    <smbconfoption name="debug level"/> these timestamps can be distracting. This
+    boolean parameter allows timestamping to be turned off.
+	</para>
+</description>
+<value type="default">yes</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/logon/domainlogons.xml b/docs-xml/smbdotconf/logon/domainlogons.xml
index 0a1d11d..7ee419e 100644
--- a/docs-xml/smbdotconf/logon/domainlogons.xml
+++ b/docs-xml/smbdotconf/logon/domainlogons.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="domain logons"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  function="_domain_logons"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/logon/enableprivileges.xml b/docs-xml/smbdotconf/logon/enableprivileges.xml
index be9b5f7..9e28457 100644
--- a/docs-xml/smbdotconf/logon/enableprivileges.xml
+++ b/docs-xml/smbdotconf/logon/enableprivileges.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="enable privileges"
                  context="G"
-		 type="boolean"
+                 type="boolean"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/logon/initlogondelayedhosts.xml b/docs-xml/smbdotconf/logon/initlogondelayedhosts.xml
index 12d91cc..83d1ebd 100644
--- a/docs-xml/smbdotconf/logon/initlogondelayedhosts.xml
+++ b/docs-xml/smbdotconf/logon/initlogondelayedhosts.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="init logon delayed hosts"
                  context="G"
-		 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/logon/logondrive.xml b/docs-xml/smbdotconf/logon/logondrive.xml
index dc12080..9f61598 100644
--- a/docs-xml/smbdotconf/logon/logondrive.xml
+++ b/docs-xml/smbdotconf/logon/logondrive.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="logon drive"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/logon/logonhome.xml b/docs-xml/smbdotconf/logon/logonhome.xml
index 3e9d150..d211674 100644
--- a/docs-xml/smbdotconf/logon/logonhome.xml
+++ b/docs-xml/smbdotconf/logon/logonhome.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="logon home"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/logon/logonpath.xml b/docs-xml/smbdotconf/logon/logonpath.xml
index d9ffbcb..106bb59 100644
--- a/docs-xml/smbdotconf/logon/logonpath.xml
+++ b/docs-xml/smbdotconf/logon/logonpath.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="logon path"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/logon/logonscript.xml b/docs-xml/smbdotconf/logon/logonscript.xml
index b6d7580..0a8d69d 100644
--- a/docs-xml/smbdotconf/logon/logonscript.xml
+++ b/docs-xml/smbdotconf/logon/logonscript.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="logon script"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/misc/addsharecommand.xml b/docs-xml/smbdotconf/misc/addsharecommand.xml
index 3beb8de..6bbdef6 100644
--- a/docs-xml/smbdotconf/misc/addsharecommand.xml
+++ b/docs-xml/smbdotconf/misc/addsharecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="add share command"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/misc/afsshare.xml b/docs-xml/smbdotconf/misc/afsshare.xml
index d2c3d1e..fe97b58 100644
--- a/docs-xml/smbdotconf/misc/afsshare.xml
+++ b/docs-xml/smbdotconf/misc/afsshare.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="afs share"
-	         context="S"
-			 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter controls whether special AFS features are enabled
 	for this share. If enabled, it assumes that the directory exported via
diff --git a/docs-xml/smbdotconf/misc/afsusernamemap.xml b/docs-xml/smbdotconf/misc/afsusernamemap.xml
index 94f0cee..4dc3d46 100644
--- a/docs-xml/smbdotconf/misc/afsusernamemap.xml
+++ b/docs-xml/smbdotconf/misc/afsusernamemap.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="afs username map"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
diff --git a/docs-xml/smbdotconf/misc/allowinsecurewidelinks.xml b/docs-xml/smbdotconf/misc/allowinsecurewidelinks.xml
index a8a0991..6b60108 100644
--- a/docs-xml/smbdotconf/misc/allowinsecurewidelinks.xml
+++ b/docs-xml/smbdotconf/misc/allowinsecurewidelinks.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="allow insecure wide links"
-		context="G"
-		type="boolean"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	In normal operation the option <smbconfoption name="wide links"/>
diff --git a/docs-xml/smbdotconf/misc/asyncsmbechohandler.xml b/docs-xml/smbdotconf/misc/asyncsmbechohandler.xml
index 84e2f1a..2b6eeb3 100644
--- a/docs-xml/smbdotconf/misc/asyncsmbechohandler.xml
+++ b/docs-xml/smbdotconf/misc/asyncsmbechohandler.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="async smb echo handler"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies whether Samba should fork the
diff --git a/docs-xml/smbdotconf/misc/auto_services.xml b/docs-xml/smbdotconf/misc/auto_services.xml
new file mode 100644
index 0000000..a7d7f13
--- /dev/null
+++ b/docs-xml/smbdotconf/misc/auto_services.xml
@@ -0,0 +1,21 @@
+<samba:parameter name="auto services"
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<synonym>preload</synonym>
+<description>
+	<para>This is a list of services that you want to be
+	automatically added to the browse lists. This is most useful
+	for homes and printers services that would otherwise not be
+	visible.</para>
+
+	<para>
+	Note that if you just want all printers in your
+	printcap file loaded then the <smbconfoption name="load printers"/>
+	 option is easier.
+	</para>
+</description>
+
+<value type="default"></value>
+<value type="example">fred lp colorlp</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/misc/available.xml b/docs-xml/smbdotconf/misc/available.xml
index 343c6fd..6e3b70c 100644
--- a/docs-xml/smbdotconf/misc/available.xml
+++ b/docs-xml/smbdotconf/misc/available.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="available"
-	         context="S"
-		 type="boolean"
+                 context="S"
+                 type="boolean"
                  generated_function="0"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter lets you "turn off" a service. If 
 	<parameter moreinfo="none">available = no</parameter>, then <emphasis>ALL</emphasis> 
diff --git a/docs-xml/smbdotconf/misc/cachedirectory.xml b/docs-xml/smbdotconf/misc/cachedirectory.xml
index b0731f9..6ffda0b 100644
--- a/docs-xml/smbdotconf/misc/cachedirectory.xml
+++ b/docs-xml/smbdotconf/misc/cachedirectory.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="cache directory"
                  context="G"
-		 type="string"
-		 constant="1"
+                 type="string"
+                 constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Usually, most of the TDB files are stored in the <parameter
diff --git a/docs-xml/smbdotconf/misc/changenotify.xml b/docs-xml/smbdotconf/misc/changenotify.xml
index 70793d6..9ded7ec 100644
--- a/docs-xml/smbdotconf/misc/changenotify.xml
+++ b/docs-xml/smbdotconf/misc/changenotify.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="change notify"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies whether Samba should reply
diff --git a/docs-xml/smbdotconf/misc/changesharecommand.xml b/docs-xml/smbdotconf/misc/changesharecommand.xml
index fbfc440..9f805b1 100644
--- a/docs-xml/smbdotconf/misc/changesharecommand.xml
+++ b/docs-xml/smbdotconf/misc/changesharecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="change share command"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/misc/clusteraddresses.xml b/docs-xml/smbdotconf/misc/clusteraddresses.xml
index b489ed4..d01a4f9 100644
--- a/docs-xml/smbdotconf/misc/clusteraddresses.xml
+++ b/docs-xml/smbdotconf/misc/clusteraddresses.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="cluster addresses"
-	         context="G"
-			 type="list"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="cmdlist"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>With this parameter you can add additional addresses
 	nmbd will register with a WINS server. These addresses are not
diff --git a/docs-xml/smbdotconf/misc/clustering.xml b/docs-xml/smbdotconf/misc/clustering.xml
index 3613670..cf426ec 100644
--- a/docs-xml/smbdotconf/misc/clustering.xml
+++ b/docs-xml/smbdotconf/misc/clustering.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="clustering"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies whether Samba should contact
diff --git a/docs-xml/smbdotconf/misc/configfile.xml b/docs-xml/smbdotconf/misc/configfile.xml
index 450be18..566d430 100644
--- a/docs-xml/smbdotconf/misc/configfile.xml
+++ b/docs-xml/smbdotconf/misc/configfile.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="config file"
                  context="G"
-				 type="string"
+                 type="string"
                  function="next_configfile"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/misc/copy.xml b/docs-xml/smbdotconf/misc/copy.xml
index 945f2c9..53e899e 100644
--- a/docs-xml/smbdotconf/misc/copy.xml
+++ b/docs-xml/smbdotconf/misc/copy.xml
@@ -2,6 +2,7 @@
                  type="string"
                  context="S"
                  generated_function="0"
+                 handler="handle_copy"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter allows you to "clone" service 
diff --git a/docs-xml/smbdotconf/misc/ctdblocktimewarnthreshold.xml b/docs-xml/smbdotconf/misc/ctdblocktimewarnthreshold.xml
index 283de6b..f9da01f 100644
--- a/docs-xml/smbdotconf/misc/ctdblocktimewarnthreshold.xml
+++ b/docs-xml/smbdotconf/misc/ctdblocktimewarnthreshold.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ctdb locktime warn threshold"
                  context="G"
-		 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/docs-xml/smbdotconf/misc/ctdbtimeout.xml b/docs-xml/smbdotconf/misc/ctdbtimeout.xml
index 1bff098..b02b2c8 100644
--- a/docs-xml/smbdotconf/misc/ctdbtimeout.xml
+++ b/docs-xml/smbdotconf/misc/ctdbtimeout.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ctdb timeout"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies a timeout in milliseconds for the
diff --git a/docs-xml/smbdotconf/misc/defaultservice.xml b/docs-xml/smbdotconf/misc/defaultservice.xml
index c0942f5..788506f 100644
--- a/docs-xml/smbdotconf/misc/defaultservice.xml
+++ b/docs-xml/smbdotconf/misc/defaultservice.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="default service"
                  context="G"
-				 type="string"
+                 type="string"
                  function="defaultservice"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>default</synonym>
diff --git a/docs-xml/smbdotconf/misc/deletereadonly.xml b/docs-xml/smbdotconf/misc/deletereadonly.xml
index de4f566..84390ed 100644
--- a/docs-xml/smbdotconf/misc/deletereadonly.xml
+++ b/docs-xml/smbdotconf/misc/deletereadonly.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="delete readonly"
-		 context="S"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter allows readonly files to be deleted.  
 	This is not normal DOS semantics, but is allowed by UNIX.</para>
diff --git a/docs-xml/smbdotconf/misc/deletesharecommand.xml b/docs-xml/smbdotconf/misc/deletesharecommand.xml
index 4e20523..b5942b6 100644
--- a/docs-xml/smbdotconf/misc/deletesharecommand.xml
+++ b/docs-xml/smbdotconf/misc/deletesharecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="delete share command"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/misc/dfreecachetime.xml b/docs-xml/smbdotconf/misc/dfreecachetime.xml
index b21535e..9679763 100644
--- a/docs-xml/smbdotconf/misc/dfreecachetime.xml
+++ b/docs-xml/smbdotconf/misc/dfreecachetime.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="dfree cache time"
-	         context="S"
-			 type="integer"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="integer"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
 	<para>
diff --git a/docs-xml/smbdotconf/misc/directorynamecachesize.xml b/docs-xml/smbdotconf/misc/directorynamecachesize.xml
index e9f974b..7a89bf2 100644
--- a/docs-xml/smbdotconf/misc/directorynamecachesize.xml
+++ b/docs-xml/smbdotconf/misc/directorynamecachesize.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="directory name cache size"
-		 context="S"
-		 type="integer"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="integer"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This parameter specifies the size of the directory name cache.
diff --git a/docs-xml/smbdotconf/misc/dmapisupport.xml b/docs-xml/smbdotconf/misc/dmapisupport.xml
index 6ff85dd..de284ee 100644
--- a/docs-xml/smbdotconf/misc/dmapisupport.xml
+++ b/docs-xml/smbdotconf/misc/dmapisupport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="dmapi support"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies whether Samba should use DMAPI to
diff --git a/docs-xml/smbdotconf/misc/dontdescend.xml b/docs-xml/smbdotconf/misc/dontdescend.xml
index d9f41da..fe6686b 100644
--- a/docs-xml/smbdotconf/misc/dontdescend.xml
+++ b/docs-xml/smbdotconf/misc/dontdescend.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="dont descend"
-	         context="S"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>There are certain directories on some systems 
 	(e.g., the <filename moreinfo="none">/proc</filename> tree under Linux) that are either not 
diff --git a/docs-xml/smbdotconf/misc/dosfilemode.xml b/docs-xml/smbdotconf/misc/dosfilemode.xml
index cf53192..353f4bb 100644
--- a/docs-xml/smbdotconf/misc/dosfilemode.xml
+++ b/docs-xml/smbdotconf/misc/dosfilemode.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="dos filemode"
-		 context="S"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para> The default behavior in Samba is to provide
 	UNIX-like behavior where only the owner of a file/directory is
diff --git a/docs-xml/smbdotconf/misc/dosfiletimeresolution.xml b/docs-xml/smbdotconf/misc/dosfiletimeresolution.xml
index 130f0fd..ccdfa6d 100644
--- a/docs-xml/smbdotconf/misc/dosfiletimeresolution.xml
+++ b/docs-xml/smbdotconf/misc/dosfiletimeresolution.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="dos filetime resolution"
-		 context="S"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Under the DOS and Windows FAT filesystem, the finest 
 	granularity on time resolution is two seconds. Setting this parameter 
diff --git a/docs-xml/smbdotconf/misc/dosfiletimes.xml b/docs-xml/smbdotconf/misc/dosfiletimes.xml
index 423b13c..17fadd2 100644
--- a/docs-xml/smbdotconf/misc/dosfiletimes.xml
+++ b/docs-xml/smbdotconf/misc/dosfiletimes.xml
@@ -1,12 +1,12 @@
 <samba:parameter name="dos filetimes"
-		 context="S"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Under DOS and Windows, if a user can write to a 
 	file they can change the timestamp on it. Under POSIX semantics, 
 	only the owner of the file or root may change the timestamp. By 
-	default, Samba emulates the DOS semantics and allows to change the 
+	default, Samba emulates the DOS semantics and allows one to change the 
 	timestamp on a file if the user <command moreinfo="none">smbd</command> is acting 
 	on behalf has write permissions.
 	Due to changes in Microsoft Office 2000 and beyond,
diff --git a/docs-xml/smbdotconf/misc/fakedirectorycreatetimes.xml b/docs-xml/smbdotconf/misc/fakedirectorycreatetimes.xml
index 54e7b87..49f54a9 100644
--- a/docs-xml/smbdotconf/misc/fakedirectorycreatetimes.xml
+++ b/docs-xml/smbdotconf/misc/fakedirectorycreatetimes.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="fake directory create times"
-		 context="S"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>NTFS and Windows VFAT file systems keep a create 
 	time for all files and directories. This is not the same as the 
diff --git a/docs-xml/smbdotconf/misc/followsymlinks.xml b/docs-xml/smbdotconf/misc/followsymlinks.xml
index c0fd920..deca634 100644
--- a/docs-xml/smbdotconf/misc/followsymlinks.xml
+++ b/docs-xml/smbdotconf/misc/followsymlinks.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="follow symlinks"
-	         context="S"
-			 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This parameter allows the Samba administrator to stop <citerefentry><refentrytitle>smbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/misc/fssprunestale.xml b/docs-xml/smbdotconf/misc/fssprunestale.xml
index a8287b0..226a973 100644
--- a/docs-xml/smbdotconf/misc/fssprunestale.xml
+++ b/docs-xml/smbdotconf/misc/fssprunestale.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="fss: prune stale"
                  context="G"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/misc/fsssequencetimeout.xml b/docs-xml/smbdotconf/misc/fsssequencetimeout.xml
index 300ff6c..67afac5 100644
--- a/docs-xml/smbdotconf/misc/fsssequencetimeout.xml
+++ b/docs-xml/smbdotconf/misc/fsssequencetimeout.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="fss: sequence timeout"
                  context="G"
-		 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/misc/fstype.xml b/docs-xml/smbdotconf/misc/fstype.xml
index d210c10..822b451 100644
--- a/docs-xml/smbdotconf/misc/fstype.xml
+++ b/docs-xml/smbdotconf/misc/fstype.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="fstype"
-	         context="S"
-			 type="string"
+                 context="S"
+                 type="string"
                  constant="1"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This parameter allows the administrator to configure the string that specifies the type of filesystem a share 
diff --git a/docs-xml/smbdotconf/misc/homedirmap.xml b/docs-xml/smbdotconf/misc/homedirmap.xml
index e50f64f..279b0b6 100644
--- a/docs-xml/smbdotconf/misc/homedirmap.xml
+++ b/docs-xml/smbdotconf/misc/homedirmap.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="homedir map"
-	         context="G"
-			 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
 	<para>
 	If <smbconfoption name="nis homedir"/> is <constant>yes</constant>, and <citerefentry><refentrytitle>smbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/misc/include.xml b/docs-xml/smbdotconf/misc/include.xml
index bfd7b3f..cbda1ed 100644
--- a/docs-xml/smbdotconf/misc/include.xml
+++ b/docs-xml/smbdotconf/misc/include.xml
@@ -1,8 +1,9 @@
 <samba:parameter name="include"
-	         context="G"
-		 type="string"
+                 context="S"
+                 type="string"
                  generated_function="0"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 handler="handle_include"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This allows you to include one config file inside another.  The file is included literally, as though typed 
diff --git a/docs-xml/smbdotconf/misc/kernelchangenotify.xml b/docs-xml/smbdotconf/misc/kernelchangenotify.xml
index 6a41dcb..d5551a9 100644
--- a/docs-xml/smbdotconf/misc/kernelchangenotify.xml
+++ b/docs-xml/smbdotconf/misc/kernelchangenotify.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="kernel change notify"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies whether Samba should ask the 
diff --git a/docs-xml/smbdotconf/misc/lockdirectory.xml b/docs-xml/smbdotconf/misc/lockdirectory.xml
index 7a9cdf8..738de2e 100644
--- a/docs-xml/smbdotconf/misc/lockdirectory.xml
+++ b/docs-xml/smbdotconf/misc/lockdirectory.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="lock directory"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>lock dir</synonym>
diff --git a/docs-xml/smbdotconf/misc/logwriteablefilesonexit.xml b/docs-xml/smbdotconf/misc/logwriteablefilesonexit.xml
index 320abfc..d95471a 100644
--- a/docs-xml/smbdotconf/misc/logwriteablefilesonexit.xml
+++ b/docs-xml/smbdotconf/misc/logwriteablefilesonexit.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="log writeable files on exit"
-		 context="G"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	When the network connection between a CIFS client and Samba
diff --git a/docs-xml/smbdotconf/misc/magicoutput.xml b/docs-xml/smbdotconf/misc/magicoutput.xml
index ce62099..784d090 100644
--- a/docs-xml/smbdotconf/misc/magicoutput.xml
+++ b/docs-xml/smbdotconf/misc/magicoutput.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="magic output"
-		 context="S"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This parameter specifies the name of a file which will contain output created by a magic script (see the 
diff --git a/docs-xml/smbdotconf/misc/magicscript.xml b/docs-xml/smbdotconf/misc/magicscript.xml
index b621f00..cbc4209 100644
--- a/docs-xml/smbdotconf/misc/magicscript.xml
+++ b/docs-xml/smbdotconf/misc/magicscript.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="magic script"
-		 context="S"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the name of a file which, 
 	if opened, will be executed by the server when the file is closed. 
diff --git a/docs-xml/smbdotconf/misc/messagecommand.xml b/docs-xml/smbdotconf/misc/messagecommand.xml
index ee0db13..1025452 100644
--- a/docs-xml/smbdotconf/misc/messagecommand.xml
+++ b/docs-xml/smbdotconf/misc/messagecommand.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="message command"
-	         context="G"
-			 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This specifies what command to run when the 
 	server receives a WinPopup style message.</para>
diff --git a/docs-xml/smbdotconf/misc/nbtclientsocketaddress.xml b/docs-xml/smbdotconf/misc/nbtclientsocketaddress.xml
index 4651c19..0833c63 100644
--- a/docs-xml/smbdotconf/misc/nbtclientsocketaddress.xml
+++ b/docs-xml/smbdotconf/misc/nbtclientsocketaddress.xml
@@ -1,8 +1,9 @@
 <samba:parameter name="nbt client socket address"
-	         context="G"
-			 type="string"
+                 context="G"
+                 type="string"
                  constant="1"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 deprecated="1"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>socket address</synonym>
 <description>
 	<para>This option allows you to control what address Samba
diff --git a/docs-xml/smbdotconf/misc/ncalrpcdir.xml b/docs-xml/smbdotconf/misc/ncalrpcdir.xml
index 1d84d60..2fa1019 100644
--- a/docs-xml/smbdotconf/misc/ncalrpcdir.xml
+++ b/docs-xml/smbdotconf/misc/ncalrpcdir.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="ncalrpc dir"
-		 context="G"
-		 type="string"
+                 context="G"
+                 type="string"
                  constant="1"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This directory will hold a series of named pipes to allow RPC over inter-process communication.</para>
 	<para>This will allow Samba and other unix processes to interact over DCE/RPC without using TCP/IP. Additionally a sub-directory 'np' has restricted permissions, and allows a trusted communication channel between Samba processes</para>
diff --git a/docs-xml/smbdotconf/misc/nishomedir.xml b/docs-xml/smbdotconf/misc/nishomedir.xml
index 4e66e71..ace8475 100644
--- a/docs-xml/smbdotconf/misc/nishomedir.xml
+++ b/docs-xml/smbdotconf/misc/nishomedir.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="NIS homedir"
-	         context="G"
-			 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Get the home share server from a NIS map. For 
 	UNIX systems that use an automounter, the user's home directory 
diff --git a/docs-xml/smbdotconf/misc/nmbdbindexplicitbroadcast.xml b/docs-xml/smbdotconf/misc/nmbdbindexplicitbroadcast.xml
index 91f69a4..fd72f06 100644
--- a/docs-xml/smbdotconf/misc/nmbdbindexplicitbroadcast.xml
+++ b/docs-xml/smbdotconf/misc/nmbdbindexplicitbroadcast.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="nmbd bind explicit broadcast"
-	         context="G"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This option causes <citerefentry><refentrytitle>nmbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/misc/panicaction.xml b/docs-xml/smbdotconf/misc/panicaction.xml
index ce4c15f..d6e1517 100644
--- a/docs-xml/smbdotconf/misc/panicaction.xml
+++ b/docs-xml/smbdotconf/misc/panicaction.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="panic action"
-		 context="G"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This is a Samba developer option that allows a 
 	system command to be called when either <citerefentry><refentrytitle>smbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/misc/perfcountmodule.xml b/docs-xml/smbdotconf/misc/perfcountmodule.xml
index 50da2c67..e1c0948 100644
--- a/docs-xml/smbdotconf/misc/perfcountmodule.xml
+++ b/docs-xml/smbdotconf/misc/perfcountmodule.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="perfcount module"
-		 context="G"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the perfcount backend to be used when monitoring SMB
 	operations.  Only one perfcount module may be used, and it must implement all of the
diff --git a/docs-xml/smbdotconf/misc/piddirectory.xml b/docs-xml/smbdotconf/misc/piddirectory.xml
index 56206cb..b53730d 100644
--- a/docs-xml/smbdotconf/misc/piddirectory.xml
+++ b/docs-xml/smbdotconf/misc/piddirectory.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="pid directory"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/misc/postexec.xml b/docs-xml/smbdotconf/misc/postexec.xml
index db6d88f..c65ee1b 100644
--- a/docs-xml/smbdotconf/misc/postexec.xml
+++ b/docs-xml/smbdotconf/misc/postexec.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="postexec"
-	         context="S"
-			 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option specifies a command to be run 
 	whenever the service is disconnected. It takes the usual 
diff --git a/docs-xml/smbdotconf/misc/preexec.xml b/docs-xml/smbdotconf/misc/preexec.xml
index bbcee49..e5d07ef 100644
--- a/docs-xml/smbdotconf/misc/preexec.xml
+++ b/docs-xml/smbdotconf/misc/preexec.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="preexec"
-		 context="S"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
- <synonym>exec</synonym>
+                 context="S"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<synonym>exec</synonym>
 <description>
 	<para>This option specifies a command to be run whenever 
 	the service is connected to. It takes the usual substitutions.</para>
diff --git a/docs-xml/smbdotconf/misc/preload.xml b/docs-xml/smbdotconf/misc/preload.xml
deleted file mode 100644
index 70d7ca6..0000000
--- a/docs-xml/smbdotconf/misc/preload.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<samba:parameter name="preload"
-                 context="G"
-				 type="string"
-                 function="auto_services"
-                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
-<synonym>auto services</synonym>
-<description>
-	<para>This is a list of services that you want to be 
-	automatically added to the browse lists. This is most useful 
-	for homes and printers services that would otherwise not be 
-	visible.</para>
-
-	<para>
-	Note that if you just want all printers in your 
-	printcap file loaded then the <smbconfoption name="load printers"/>
-	 option is easier.
-	</para>
-</description>
-
-<value type="default"></value>
-<value type="example">fred lp colorlp</value>
-</samba:parameter>
diff --git a/docs-xml/smbdotconf/misc/registryshares.xml b/docs-xml/smbdotconf/misc/registryshares.xml
index bb25005..0bdb1f6 100644
--- a/docs-xml/smbdotconf/misc/registryshares.xml
+++ b/docs-xml/smbdotconf/misc/registryshares.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="registry shares"
                  context="G"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/misc/remoteannounce.xml b/docs-xml/smbdotconf/misc/remoteannounce.xml
index 5d442ea..ad537c8 100644
--- a/docs-xml/smbdotconf/misc/remoteannounce.xml
+++ b/docs-xml/smbdotconf/misc/remoteannounce.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="remote announce"
-	         context="G"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This option allows you to setup <citerefentry><refentrytitle>nmbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/misc/remotebrowsesync.xml b/docs-xml/smbdotconf/misc/remotebrowsesync.xml
index 2c7547d..91a8c8f 100644
--- a/docs-xml/smbdotconf/misc/remotebrowsesync.xml
+++ b/docs-xml/smbdotconf/misc/remotebrowsesync.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="remote browse sync"
-	         context="G"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This option allows you to setup <citerefentry><refentrytitle>nmbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/misc/resetonzerovc.xml b/docs-xml/smbdotconf/misc/resetonzerovc.xml
index 1fa3023..f2ad85d 100644
--- a/docs-xml/smbdotconf/misc/resetonzerovc.xml
+++ b/docs-xml/smbdotconf/misc/resetonzerovc.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="reset on zero vc"
-		 context="G"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This boolean option controls whether an incoming session setup
diff --git a/docs-xml/smbdotconf/misc/rootpostexec.xml b/docs-xml/smbdotconf/misc/rootpostexec.xml
index 5a9613c..d50ca7f 100644
--- a/docs-xml/smbdotconf/misc/rootpostexec.xml
+++ b/docs-xml/smbdotconf/misc/rootpostexec.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="root postexec"
-		 context="S"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This is the same as the <parameter moreinfo="none">postexec</parameter>
diff --git a/docs-xml/smbdotconf/misc/rootpreexec.xml b/docs-xml/smbdotconf/misc/rootpreexec.xml
index f0fff73..32bfe44 100644
--- a/docs-xml/smbdotconf/misc/rootpreexec.xml
+++ b/docs-xml/smbdotconf/misc/rootpreexec.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="root preexec"
-		 context="S"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This is the same as the <parameter moreinfo="none">preexec</parameter>
diff --git a/docs-xml/smbdotconf/misc/rootpreexecclose.xml b/docs-xml/smbdotconf/misc/rootpreexecclose.xml
index 3bce915..35fd883 100644
--- a/docs-xml/smbdotconf/misc/rootpreexecclose.xml
+++ b/docs-xml/smbdotconf/misc/rootpreexecclose.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="root preexec close"
-		 context="S"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This is the same as the <parameter moreinfo="none">preexec close
 	</parameter> parameter except that the command is run as root.</para>
diff --git a/docs-xml/smbdotconf/misc/rpcdaemon.xml b/docs-xml/smbdotconf/misc/rpcdaemon.xml
index 72f057d..806ddbd 100644
--- a/docs-xml/smbdotconf/misc/rpcdaemon.xml
+++ b/docs-xml/smbdotconf/misc/rpcdaemon.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="rpc_daemon:DAEMON"
                  context="G"
-		 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
@@ -25,7 +25,7 @@
 
 	<para>
 	Choosing the <emphasis>fork</emphasis> option will cause samba to fork
-	a separate proces for each daemon configured this way. Each daemon may
+	a separate process for each daemon configured this way. Each daemon may
 	in turn fork a number of children used to handle requests from multiple
 	smbds and direct tcp/ip connections (if the Endpoint Mapper is
 	enabled). Communication with smbd happens over named pipes and require
diff --git a/docs-xml/smbdotconf/misc/rpcserver.xml b/docs-xml/smbdotconf/misc/rpcserver.xml
index fafedaf..434e5ec 100644
--- a/docs-xml/smbdotconf/misc/rpcserver.xml
+++ b/docs-xml/smbdotconf/misc/rpcserver.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="rpc_server:SERVER"
                  context="G"
-		 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
@@ -49,7 +49,7 @@
 	</para>
 
 	<para>
-		Choosing the <emphasis>external</emphasis> option allows to run
+		Choosing the <emphasis>external</emphasis> option allows one to run
 		a separate daemon or even a completely independent (3rd party)
 		server capable of interfacing with samba via the MS-RPC
 		interface over named pipes.
diff --git a/docs-xml/smbdotconf/misc/smbdprofilinglevel.xml b/docs-xml/smbdotconf/misc/smbdprofilinglevel.xml
index d92e5dc..54dccf0 100644
--- a/docs-xml/smbdotconf/misc/smbdprofilinglevel.xml
+++ b/docs-xml/smbdotconf/misc/smbdprofilinglevel.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="smbd profiling level"
-	         context="G"
-		 type="enum"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="enum"
+                 enumlist="enum_smbd_profiling_level"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	  This parameter allows the administrator to enable profiling support.
diff --git a/docs-xml/smbdotconf/misc/statedirectory.xml b/docs-xml/smbdotconf/misc/statedirectory.xml
index 71200ea..084f145 100644
--- a/docs-xml/smbdotconf/misc/statedirectory.xml
+++ b/docs-xml/smbdotconf/misc/statedirectory.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="state directory"
                  context="G"
-		 type="string"
-		 constant="1"
+                 type="string"
+                 constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Usually, most of the TDB files are stored in the
diff --git a/docs-xml/smbdotconf/misc/usershareallowguests.xml b/docs-xml/smbdotconf/misc/usershareallowguests.xml
index 6fd75d1..be210bf 100644
--- a/docs-xml/smbdotconf/misc/usershareallowguests.xml
+++ b/docs-xml/smbdotconf/misc/usershareallowguests.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="usershare allow guests"
-	         context="G"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter controls whether user defined shares are allowed
 	to be accessed by non-authenticated users or not. It is the equivalent
diff --git a/docs-xml/smbdotconf/misc/usersharemaxshares.xml b/docs-xml/smbdotconf/misc/usersharemaxshares.xml
index 1d2bab7..0d69bb8 100644
--- a/docs-xml/smbdotconf/misc/usersharemaxshares.xml
+++ b/docs-xml/smbdotconf/misc/usersharemaxshares.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="usershare max shares"
-	         context="G"
-		 type="integer"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="integer"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the number of user defined shares
 	that are allowed to be created by users belonging to the group owning the
diff --git a/docs-xml/smbdotconf/misc/usershareowneronly.xml b/docs-xml/smbdotconf/misc/usershareowneronly.xml
index acfb1df..5b33492 100644
--- a/docs-xml/smbdotconf/misc/usershareowneronly.xml
+++ b/docs-xml/smbdotconf/misc/usershareowneronly.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="usershare owner only"
-	         context="G"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter controls whether the pathname exported by
 	a user defined shares must be owned by the user creating the
diff --git a/docs-xml/smbdotconf/misc/usersharepath.xml b/docs-xml/smbdotconf/misc/usersharepath.xml
index a1b2841..446b1fd 100644
--- a/docs-xml/smbdotconf/misc/usersharepath.xml
+++ b/docs-xml/smbdotconf/misc/usersharepath.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="usershare path"
-	         context="G"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the absolute path of the directory on the
 	filesystem used to store the user defined share definition files.
diff --git a/docs-xml/smbdotconf/misc/usershareprefixallowlist.xml b/docs-xml/smbdotconf/misc/usershareprefixallowlist.xml
index 481431e..4c236fe 100644
--- a/docs-xml/smbdotconf/misc/usershareprefixallowlist.xml
+++ b/docs-xml/smbdotconf/misc/usershareprefixallowlist.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="usershare prefix allow list"
-	         context="G"
-		 type="list"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="cmdlist"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies a list of absolute pathnames
 	the root of which are allowed to be exported by user defined share definitions.
diff --git a/docs-xml/smbdotconf/misc/usershareprefixdenylist.xml b/docs-xml/smbdotconf/misc/usershareprefixdenylist.xml
index 396e8c1..c0e18a7 100644
--- a/docs-xml/smbdotconf/misc/usershareprefixdenylist.xml
+++ b/docs-xml/smbdotconf/misc/usershareprefixdenylist.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="usershare prefix deny list"
-	         context="G"
-		 type="list"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="cmdlist"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies a list of absolute pathnames
 	the root of which are NOT allowed to be exported by user defined share definitions.
diff --git a/docs-xml/smbdotconf/misc/usersharetemplateshare.xml b/docs-xml/smbdotconf/misc/usersharetemplateshare.xml
index dd50f43..3a74dcb 100644
--- a/docs-xml/smbdotconf/misc/usersharetemplateshare.xml
+++ b/docs-xml/smbdotconf/misc/usersharetemplateshare.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="usershare template share"
-	         context="G"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>User defined shares only have limited possible parameters
 	such as path, guest ok, etc. This parameter allows usershares to
diff --git a/docs-xml/smbdotconf/misc/utmpdirectory.xml b/docs-xml/smbdotconf/misc/utmpdirectory.xml
index b962ff3..82c8f10 100644
--- a/docs-xml/smbdotconf/misc/utmpdirectory.xml
+++ b/docs-xml/smbdotconf/misc/utmpdirectory.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="utmp directory"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/misc/valid.xml b/docs-xml/smbdotconf/misc/valid.xml
index c8b5d62..8d86f9c 100644
--- a/docs-xml/smbdotconf/misc/valid.xml
+++ b/docs-xml/smbdotconf/misc/valid.xml
@@ -1,8 +1,9 @@
 <samba:parameter name="-valid"
-		 context="S"
-		 type="boolean"
+                 context="S"
+                 type="boolean"
                  generated_function="0"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 function="valid"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para> This parameter indicates whether a share is 
 	valid and thus can be used. When this parameter is set to false, 
diff --git a/docs-xml/smbdotconf/misc/volume.xml b/docs-xml/smbdotconf/misc/volume.xml
index d3385e7..02129f1 100644
--- a/docs-xml/smbdotconf/misc/volume.xml
+++ b/docs-xml/smbdotconf/misc/volume.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="volume"
-		 context="S"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This allows you to override the volume label 
 	returned for a share. Useful for CDROMs with installation programs 
diff --git a/docs-xml/smbdotconf/misc/widelinks.xml b/docs-xml/smbdotconf/misc/widelinks.xml
index b507ae9..09f8aa5 100644
--- a/docs-xml/smbdotconf/misc/widelinks.xml
+++ b/docs-xml/smbdotconf/misc/widelinks.xml
@@ -1,8 +1,7 @@
 <samba:parameter name="wide links"
-		 context="S"
-		 type="boolean"
-                 generated_function="0"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter controls whether or not links 
 	in the UNIX file system may be followed by the server. Links 
diff --git a/docs-xml/smbdotconf/misc/wtmpdirectory.xml b/docs-xml/smbdotconf/misc/wtmpdirectory.xml
index 4652153..eb9d876 100644
--- a/docs-xml/smbdotconf/misc/wtmpdirectory.xml
+++ b/docs-xml/smbdotconf/misc/wtmpdirectory.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="wtmp directory"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/printing/addportcommand.xml b/docs-xml/smbdotconf/printing/addportcommand.xml
index 8a44a97..7a35c52 100644
--- a/docs-xml/smbdotconf/printing/addportcommand.xml
+++ b/docs-xml/smbdotconf/printing/addportcommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="addport command"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>Samba 3.0.23 introduced support for adding printer ports
diff --git a/docs-xml/smbdotconf/printing/addprintercommand.xml b/docs-xml/smbdotconf/printing/addprintercommand.xml
index 36d0f85..c39296d 100644
--- a/docs-xml/smbdotconf/printing/addprintercommand.xml
+++ b/docs-xml/smbdotconf/printing/addprintercommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="addprinter command"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>With the introduction of MS-RPC based printing
diff --git a/docs-xml/smbdotconf/printing/cupsencrypt.xml b/docs-xml/smbdotconf/printing/cupsencrypt.xml
index cba55d2..8094abe 100644
--- a/docs-xml/smbdotconf/printing/cupsencrypt.xml
+++ b/docs-xml/smbdotconf/printing/cupsencrypt.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="cups encrypt"
-	context="G"
-	type="enum"
-                 generated_function="0"
-	xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="enum"
+                 enumlist="enum_bool_auto"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This parameter is only applicable if <smbconfoption name="printing"/>
diff --git a/docs-xml/smbdotconf/printing/cupsoptions.xml b/docs-xml/smbdotconf/printing/cupsoptions.xml
index 6079b19..7e6b07d 100644
--- a/docs-xml/smbdotconf/printing/cupsoptions.xml
+++ b/docs-xml/smbdotconf/printing/cupsoptions.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="cups options"
                  context="S"
-		 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/printing/cupsserver.xml b/docs-xml/smbdotconf/printing/cupsserver.xml
index a301985..19bb769 100644
--- a/docs-xml/smbdotconf/printing/cupsserver.xml
+++ b/docs-xml/smbdotconf/printing/cupsserver.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="cups server"
                  context="G"
-		 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/printing/defaultdevmode.xml b/docs-xml/smbdotconf/printing/defaultdevmode.xml
index c2c7d3e..f86de9b 100644
--- a/docs-xml/smbdotconf/printing/defaultdevmode.xml
+++ b/docs-xml/smbdotconf/printing/defaultdevmode.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="default devmode"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter is only applicable to <smbconfoption name="printable"/> services.
diff --git a/docs-xml/smbdotconf/printing/deleteprintercommand.xml b/docs-xml/smbdotconf/printing/deleteprintercommand.xml
index f26fc00..f9a9a47 100644
--- a/docs-xml/smbdotconf/printing/deleteprintercommand.xml
+++ b/docs-xml/smbdotconf/printing/deleteprintercommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="deleteprinter command"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>With the introduction of MS-RPC based printer
diff --git a/docs-xml/smbdotconf/printing/disablespoolss.xml b/docs-xml/smbdotconf/printing/disablespoolss.xml
index 63c2e19..4710002 100644
--- a/docs-xml/smbdotconf/printing/disablespoolss.xml
+++ b/docs-xml/smbdotconf/printing/disablespoolss.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="disable spoolss"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  function="_disable_spoolss"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/printing/enablespoolss.xml b/docs-xml/smbdotconf/printing/enablespoolss.xml
index f2335d8..68e09bf 100644
--- a/docs-xml/smbdotconf/printing/enablespoolss.xml
+++ b/docs-xml/smbdotconf/printing/enablespoolss.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="enable spoolss"
                  context="G"
-		 type="boolean"
+                 type="boolean-rev"
+                 function="_disable_spoolss"
                  synonym="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/printing/enumportscommand.xml b/docs-xml/smbdotconf/printing/enumportscommand.xml
index 17880c6..cb85cd0 100644
--- a/docs-xml/smbdotconf/printing/enumportscommand.xml
+++ b/docs-xml/smbdotconf/printing/enumportscommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="enumports command"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>The concept of a "port" is fairly foreign
diff --git a/docs-xml/smbdotconf/printing/forceprintername.xml b/docs-xml/smbdotconf/printing/forceprintername.xml
index 7503494..607d176 100644
--- a/docs-xml/smbdotconf/printing/forceprintername.xml
+++ b/docs-xml/smbdotconf/printing/forceprintername.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="force printername"
                  context="S"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>When printing from Windows NT (or later), 
diff --git a/docs-xml/smbdotconf/printing/iprintserver.xml b/docs-xml/smbdotconf/printing/iprintserver.xml
index 55a0594..82bf9e9 100644
--- a/docs-xml/smbdotconf/printing/iprintserver.xml
+++ b/docs-xml/smbdotconf/printing/iprintserver.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="iprint server"
                  context="G"
-		 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/printing/loadprinters.xml b/docs-xml/smbdotconf/printing/loadprinters.xml
index 2072745..83e0f4c 100644
--- a/docs-xml/smbdotconf/printing/loadprinters.xml
+++ b/docs-xml/smbdotconf/printing/loadprinters.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="load printers"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>A boolean variable that controls whether all 
diff --git a/docs-xml/smbdotconf/printing/lppausecommand.xml b/docs-xml/smbdotconf/printing/lppausecommand.xml
index 0ca8f4d..3aa134c 100644
--- a/docs-xml/smbdotconf/printing/lppausecommand.xml
+++ b/docs-xml/smbdotconf/printing/lppausecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="lppause command"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter specifies the command to be 
diff --git a/docs-xml/smbdotconf/printing/lpqcachetime.xml b/docs-xml/smbdotconf/printing/lpqcachetime.xml
index dcced48..0b3670a 100644
--- a/docs-xml/smbdotconf/printing/lpqcachetime.xml
+++ b/docs-xml/smbdotconf/printing/lpqcachetime.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="lpq cache time"
-		 context="G"
-		 type="integer"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="integer"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This controls how long lpq info will be cached 
 	for to prevent the <command moreinfo="none">lpq</command> command being called too 
diff --git a/docs-xml/smbdotconf/printing/lpqcommand.xml b/docs-xml/smbdotconf/printing/lpqcommand.xml
index ee2c3d0..f3c17f2 100644
--- a/docs-xml/smbdotconf/printing/lpqcommand.xml
+++ b/docs-xml/smbdotconf/printing/lpqcommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="lpq command"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
     <para>This parameter specifies the command to be 
diff --git a/docs-xml/smbdotconf/printing/lpresumecommand.xml b/docs-xml/smbdotconf/printing/lpresumecommand.xml
index e769fe3..153ba76 100644
--- a/docs-xml/smbdotconf/printing/lpresumecommand.xml
+++ b/docs-xml/smbdotconf/printing/lpresumecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="lpresume command"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter specifies the command to be 
diff --git a/docs-xml/smbdotconf/printing/lprmcommand.xml b/docs-xml/smbdotconf/printing/lprmcommand.xml
index d542868..4b7f3dd 100644
--- a/docs-xml/smbdotconf/printing/lprmcommand.xml
+++ b/docs-xml/smbdotconf/printing/lprmcommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="lprm command"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter specifies the command to be 
diff --git a/docs-xml/smbdotconf/printing/maxprintjobs.xml b/docs-xml/smbdotconf/printing/maxprintjobs.xml
index 0b3db05..f37ff0a 100644
--- a/docs-xml/smbdotconf/printing/maxprintjobs.xml
+++ b/docs-xml/smbdotconf/printing/maxprintjobs.xml
@@ -1,7 +1,6 @@
 <samba:parameter name="max print jobs"
                  context="S"
-		 type="integer"
-                 generated_function="0"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter limits the maximum number of 
diff --git a/docs-xml/smbdotconf/printing/maxreportedprintjobs.xml b/docs-xml/smbdotconf/printing/maxreportedprintjobs.xml
index e5e9570..5cfd21f 100644
--- a/docs-xml/smbdotconf/printing/maxreportedprintjobs.xml
+++ b/docs-xml/smbdotconf/printing/maxreportedprintjobs.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="max reported print jobs"
                  context="S"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/printing/os2drivermap.xml b/docs-xml/smbdotconf/printing/os2drivermap.xml
index c06002c..166cec2 100644
--- a/docs-xml/smbdotconf/printing/os2drivermap.xml
+++ b/docs-xml/smbdotconf/printing/os2drivermap.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="os2 driver map"
                  context="G"
-		 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>The parameter is used to define the absolute
diff --git a/docs-xml/smbdotconf/printing/printable.xml b/docs-xml/smbdotconf/printing/printable.xml
index ab8b5de..870d888 100644
--- a/docs-xml/smbdotconf/printing/printable.xml
+++ b/docs-xml/smbdotconf/printing/printable.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="printable"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>print ok</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/printing/printcapcachetime.xml b/docs-xml/smbdotconf/printing/printcapcachetime.xml
index 4bbcb2d..d5a4c80 100644
--- a/docs-xml/smbdotconf/printing/printcapcachetime.xml
+++ b/docs-xml/smbdotconf/printing/printcapcachetime.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="printcap cache time"
-	context="G"
-	type="integer"
+                 context="G"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option specifies the number of seconds before the printing
diff --git a/docs-xml/smbdotconf/printing/printcapname.xml b/docs-xml/smbdotconf/printing/printcapname.xml
index edb47d7..64acc26 100644
--- a/docs-xml/smbdotconf/printing/printcapname.xml
+++ b/docs-xml/smbdotconf/printing/printcapname.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="printcap name"
-	context="G"
-	type="string"
-                 generated_function="0"
+                 context="G"
+                 type="string"
+                 constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>printcap</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/printing/printcommand.xml b/docs-xml/smbdotconf/printing/printcommand.xml
index 18881e9..c84e45f 100644
--- a/docs-xml/smbdotconf/printing/printcommand.xml
+++ b/docs-xml/smbdotconf/printing/printcommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="print command"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>After a print job has finished spooling to 
diff --git a/docs-xml/smbdotconf/printing/printername.xml b/docs-xml/smbdotconf/printing/printername.xml
index 1d3f79e..abe2b24 100644
--- a/docs-xml/smbdotconf/printing/printername.xml
+++ b/docs-xml/smbdotconf/printing/printername.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="printer name"
                  context="S"
-		 type="string"
+                 type="string"
                  function="_printername"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <synonym>printer</synonym>
diff --git a/docs-xml/smbdotconf/printing/printing.xml b/docs-xml/smbdotconf/printing/printing.xml
index 14ec2b0..2e25621 100644
--- a/docs-xml/smbdotconf/printing/printing.xml
+++ b/docs-xml/smbdotconf/printing/printing.xml
@@ -1,6 +1,8 @@
 <samba:parameter name="printing"
                  context="S"
-				 type="enum"
+                 type="enum"
+                 enumlist="enum_printing"
+                 handler="handle_printing"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameters controls how printer status  information is
diff --git a/docs-xml/smbdotconf/printing/printjobusername.xml b/docs-xml/smbdotconf/printing/printjobusername.xml
index 71d143c..872a2e5 100644
--- a/docs-xml/smbdotconf/printing/printjobusername.xml
+++ b/docs-xml/smbdotconf/printing/printjobusername.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="printjob username"
                  context="S"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/printing/printnotifybackchannel.xml b/docs-xml/smbdotconf/printing/printnotifybackchannel.xml
index b9d32ec..576bf75 100644
--- a/docs-xml/smbdotconf/printing/printnotifybackchannel.xml
+++ b/docs-xml/smbdotconf/printing/printnotifybackchannel.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="print notify backchannel"
-		 context="S"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 <para>Windows print clients can update print queue status by expecting
 	the server to open a backchannel SMB connection to them. Due to
diff --git a/docs-xml/smbdotconf/printing/queuepausecommand.xml b/docs-xml/smbdotconf/printing/queuepausecommand.xml
index c396a67..5dca456 100644
--- a/docs-xml/smbdotconf/printing/queuepausecommand.xml
+++ b/docs-xml/smbdotconf/printing/queuepausecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="queuepause command"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter specifies the command to be 
diff --git a/docs-xml/smbdotconf/printing/queueresumecommand.xml b/docs-xml/smbdotconf/printing/queueresumecommand.xml
index ec1fb97..4a57333 100644
--- a/docs-xml/smbdotconf/printing/queueresumecommand.xml
+++ b/docs-xml/smbdotconf/printing/queueresumecommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="queueresume command"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter specifies the command to be 
diff --git a/docs-xml/smbdotconf/printing/showaddprinterwizard.xml b/docs-xml/smbdotconf/printing/showaddprinterwizard.xml
index 542ca0b..14687b8 100644
--- a/docs-xml/smbdotconf/printing/showaddprinterwizard.xml
+++ b/docs-xml/smbdotconf/printing/showaddprinterwizard.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="show add printer wizard"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>With the introduction of MS-RPC based printing support
diff --git a/docs-xml/smbdotconf/printing/spoolssarchitecture.xml b/docs-xml/smbdotconf/printing/spoolssarchitecture.xml
index a0739d5..1eccf9f 100644
--- a/docs-xml/smbdotconf/printing/spoolssarchitecture.xml
+++ b/docs-xml/smbdotconf/printing/spoolssarchitecture.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="spoolss: architecture"
-		 context="G"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Windows spoolss print clients only allow association of server-side drivers
 	with printers when the driver architecture matches the advertised print server
diff --git a/docs-xml/smbdotconf/printing/spoolssosversion.xml b/docs-xml/smbdotconf/printing/spoolssosversion.xml
index cd568e7..0ef4489 100644
--- a/docs-xml/smbdotconf/printing/spoolssosversion.xml
+++ b/docs-xml/smbdotconf/printing/spoolssosversion.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="spoolss: os_major"
-		 context="G"
-		 type="integer"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="integer"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Windows might require a new os version number. This option allows
 		to modify the build number. The complete default version number is:
diff --git a/docs-xml/smbdotconf/printing/useclientdriver.xml b/docs-xml/smbdotconf/printing/useclientdriver.xml
index 47fbb3e..4d07604 100644
--- a/docs-xml/smbdotconf/printing/useclientdriver.xml
+++ b/docs-xml/smbdotconf/printing/useclientdriver.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="use client driver"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter applies only to Windows NT/2000
diff --git a/docs-xml/smbdotconf/protocol/aclcheckpermissions.xml b/docs-xml/smbdotconf/protocol/aclcheckpermissions.xml
index 91d2b3f..bfffcc0 100644
--- a/docs-xml/smbdotconf/protocol/aclcheckpermissions.xml
+++ b/docs-xml/smbdotconf/protocol/aclcheckpermissions.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="acl check permissions"
                  context="S"
-		 type="boolean"
+                 type="boolean"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>Please note this parameter is now deprecated in Samba 3.6.2 and will be removed
diff --git a/docs-xml/smbdotconf/protocol/aclmapfullcontrol.xml b/docs-xml/smbdotconf/protocol/aclmapfullcontrol.xml
index 33b6e51..9bb1e7d 100644
--- a/docs-xml/smbdotconf/protocol/aclmapfullcontrol.xml
+++ b/docs-xml/smbdotconf/protocol/aclmapfullcontrol.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="acl map full control"
-		context="S"
-		type="boolean"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
 	This boolean parameter controls whether <citerefentry><refentrytitle>smbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/protocol/cldapport.xml b/docs-xml/smbdotconf/protocol/cldapport.xml
index ed41f11..3fcb2b3 100644
--- a/docs-xml/smbdotconf/protocol/cldapport.xml
+++ b/docs-xml/smbdotconf/protocol/cldapport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="cldap port"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option controls the port used by the CLDAP protocol.
diff --git a/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml b/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml
index e68226f..240ba1a 100644
--- a/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml
+++ b/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml
@@ -1,8 +1,9 @@
 <samba:parameter name="client max protocol"
-		 context="G"
-		 type="enum"
-		 function="_client_max_protocol"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="enum"
+                 function="_client_max_protocol"
+                 enumlist="enum_protocol"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>The value of the parameter (a string) is the highest 
     protocol level that will be supported by the client.</para>
diff --git a/docs-xml/smbdotconf/protocol/clientminprotocol.xml b/docs-xml/smbdotconf/protocol/clientminprotocol.xml
index c906a15..ac0d460 100644
--- a/docs-xml/smbdotconf/protocol/clientminprotocol.xml
+++ b/docs-xml/smbdotconf/protocol/clientminprotocol.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="client min protocol"
-		 context="G"
-		 type="enum"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="enum"
+                 enumlist="enum_protocol"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This setting controls the minimum protocol version that the
 	client will attempt to use.</para>
diff --git a/docs-xml/smbdotconf/protocol/clientusespnego.xml b/docs-xml/smbdotconf/protocol/clientusespnego.xml
index b95ad0e..f5a3512 100644
--- a/docs-xml/smbdotconf/protocol/clientusespnego.xml
+++ b/docs-xml/smbdotconf/protocol/clientusespnego.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="client use spnego"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para> This variable controls whether Samba clients will try 
diff --git a/docs-xml/smbdotconf/protocol/dcerpcendpointservers.xml b/docs-xml/smbdotconf/protocol/dcerpcendpointservers.xml
index 7fc172b..feecf62 100644
--- a/docs-xml/smbdotconf/protocol/dcerpcendpointservers.xml
+++ b/docs-xml/smbdotconf/protocol/dcerpcendpointservers.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="dcerpc endpoint servers"
                  context="G"
-				 type="list"
+                 type="list"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies which DCE/RPC endpoint servers should be run.</para>
diff --git a/docs-xml/smbdotconf/protocol/defersharingviolations.xml b/docs-xml/smbdotconf/protocol/defersharingviolations.xml
index bf3b524..353dd9d 100644
--- a/docs-xml/smbdotconf/protocol/defersharingviolations.xml
+++ b/docs-xml/smbdotconf/protocol/defersharingviolations.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="defer sharing violations"
                  context="G"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/protocol/dgramport.xml b/docs-xml/smbdotconf/protocol/dgramport.xml
index cac7243..b68c81f 100644
--- a/docs-xml/smbdotconf/protocol/dgramport.xml
+++ b/docs-xml/smbdotconf/protocol/dgramport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="dgram port"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies which ports the server should listen on for NetBIOS datagram traffic.</para>
diff --git a/docs-xml/smbdotconf/protocol/disablenetbios.xml b/docs-xml/smbdotconf/protocol/disablenetbios.xml
index a7b5759..ce39834 100644
--- a/docs-xml/smbdotconf/protocol/disablenetbios.xml
+++ b/docs-xml/smbdotconf/protocol/disablenetbios.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="disable netbios"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>Enabling this parameter will disable netbios support
diff --git a/docs-xml/smbdotconf/protocol/easupport.xml b/docs-xml/smbdotconf/protocol/easupport.xml
index fc37f71..4c98267 100644
--- a/docs-xml/smbdotconf/protocol/easupport.xml
+++ b/docs-xml/smbdotconf/protocol/easupport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ea support"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This boolean parameter controls whether <citerefentry><refentrytitle>smbd</refentrytitle>                                       
diff --git a/docs-xml/smbdotconf/protocol/enableasusupport.xml b/docs-xml/smbdotconf/protocol/enableasusupport.xml
index f938ed8..3c60b9b 100644
--- a/docs-xml/smbdotconf/protocol/enableasusupport.xml
+++ b/docs-xml/smbdotconf/protocol/enableasusupport.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="enable asu support"
-		 context="G"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>Hosts running the "Advanced Server for Unix (ASU)" product
     require some special accomodations such as creating a builtin [ADMIN$]
diff --git a/docs-xml/smbdotconf/protocol/eventloglist.xml b/docs-xml/smbdotconf/protocol/eventloglist.xml
index ba90661..6d0b400 100644
--- a/docs-xml/smbdotconf/protocol/eventloglist.xml
+++ b/docs-xml/smbdotconf/protocol/eventloglist.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="eventlog list"
-		 type="list"
+                 type="cmdlist"
                  context="G"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/protocol/largereadwrite.xml b/docs-xml/smbdotconf/protocol/largereadwrite.xml
index 5a34bfd..e7142d1 100644
--- a/docs-xml/smbdotconf/protocol/largereadwrite.xml
+++ b/docs-xml/smbdotconf/protocol/largereadwrite.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="large readwrite"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter determines whether or not
diff --git a/docs-xml/smbdotconf/protocol/mapaclinherit.xml b/docs-xml/smbdotconf/protocol/mapaclinherit.xml
index 5b2de34..3409232 100644
--- a/docs-xml/smbdotconf/protocol/mapaclinherit.xml
+++ b/docs-xml/smbdotconf/protocol/mapaclinherit.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="map acl inherit"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This boolean parameter controls whether <citerefentry><refentrytitle>smbd</refentrytitle>                                       
diff --git a/docs-xml/smbdotconf/protocol/maxmux.xml b/docs-xml/smbdotconf/protocol/maxmux.xml
index 8281722..ab50001 100644
--- a/docs-xml/smbdotconf/protocol/maxmux.xml
+++ b/docs-xml/smbdotconf/protocol/maxmux.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="max mux"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option controls the maximum number of 
diff --git a/docs-xml/smbdotconf/protocol/maxttl.xml b/docs-xml/smbdotconf/protocol/maxttl.xml
index 8813b40..c340ad1 100644
--- a/docs-xml/smbdotconf/protocol/maxttl.xml
+++ b/docs-xml/smbdotconf/protocol/maxttl.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="max ttl"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option tells <citerefentry><refentrytitle>nmbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/protocol/maxwinsttl.xml b/docs-xml/smbdotconf/protocol/maxwinsttl.xml
index 6c37a03..2427eec 100644
--- a/docs-xml/smbdotconf/protocol/maxwinsttl.xml
+++ b/docs-xml/smbdotconf/protocol/maxwinsttl.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="max wins ttl"
-				 type="integer"
+                 type="integer"
                  context="G"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/protocol/maxxmit.xml b/docs-xml/smbdotconf/protocol/maxxmit.xml
index 875efa0..aca98d5 100644
--- a/docs-xml/smbdotconf/protocol/maxxmit.xml
+++ b/docs-xml/smbdotconf/protocol/maxxmit.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="max xmit"
                  context="G"
-				 type="integer"
+                 type="bytes"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option controls the maximum packet size 
diff --git a/docs-xml/smbdotconf/protocol/minreceivefilesize.xml b/docs-xml/smbdotconf/protocol/minreceivefilesize.xml
index 4f40ecf..ce0ea30 100644
--- a/docs-xml/smbdotconf/protocol/minreceivefilesize.xml
+++ b/docs-xml/smbdotconf/protocol/minreceivefilesize.xml
@@ -1,8 +1,7 @@
 <samba:parameter name="min receivefile size"
-		type="integer"
-		context="G"
-                 generated_function="0"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="bytes"
+                 context="G"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 <para>This option changes the behavior of <citerefentry><refentrytitle>smbd</refentrytitle>
 <manvolnum>8</manvolnum></citerefentry> when processing SMBwriteX calls. Any incoming
diff --git a/docs-xml/smbdotconf/protocol/minwinsttl.xml b/docs-xml/smbdotconf/protocol/minwinsttl.xml
index dbeb6d1..8991757 100644
--- a/docs-xml/smbdotconf/protocol/minwinsttl.xml
+++ b/docs-xml/smbdotconf/protocol/minwinsttl.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="min wins ttl"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option tells <citerefentry><refentrytitle>nmbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/protocol/nameresolveorder.xml b/docs-xml/smbdotconf/protocol/nameresolveorder.xml
index 17a4d95..ec3aaf3 100644
--- a/docs-xml/smbdotconf/protocol/nameresolveorder.xml
+++ b/docs-xml/smbdotconf/protocol/nameresolveorder.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="name resolve order"
                  context="G"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> 
 <description>
     <para>This option is used by the programs in the Samba 
diff --git a/docs-xml/smbdotconf/protocol/nbtport.xml b/docs-xml/smbdotconf/protocol/nbtport.xml
index 0c06d7c..7070b98 100644
--- a/docs-xml/smbdotconf/protocol/nbtport.xml
+++ b/docs-xml/smbdotconf/protocol/nbtport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="nbt port"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies which port the server should use for NetBIOS over IP name
diff --git a/docs-xml/smbdotconf/protocol/ntaclsupport.xml b/docs-xml/smbdotconf/protocol/ntaclsupport.xml
index 7938110..1b1f947 100644
--- a/docs-xml/smbdotconf/protocol/ntaclsupport.xml
+++ b/docs-xml/smbdotconf/protocol/ntaclsupport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="nt acl support"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This boolean parameter controls whether <citerefentry><refentrytitle>smbd</refentrytitle>                                       
diff --git a/docs-xml/smbdotconf/protocol/ntpipesupport.xml b/docs-xml/smbdotconf/protocol/ntpipesupport.xml
index 9acfeda..907dee1 100644
--- a/docs-xml/smbdotconf/protocol/ntpipesupport.xml
+++ b/docs-xml/smbdotconf/protocol/ntpipesupport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="nt pipe support"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This boolean parameter controls whether 
diff --git a/docs-xml/smbdotconf/protocol/ntstatussupport.xml b/docs-xml/smbdotconf/protocol/ntstatussupport.xml
index 961e2ae..07d3462 100644
--- a/docs-xml/smbdotconf/protocol/ntstatussupport.xml
+++ b/docs-xml/smbdotconf/protocol/ntstatussupport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="nt status support"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This boolean parameter controls whether <citerefentry><refentrytitle>smbd</refentrytitle>                                       
diff --git a/docs-xml/smbdotconf/protocol/profileacls.xml b/docs-xml/smbdotconf/protocol/profileacls.xml
index 956e41f..ade906c 100644
--- a/docs-xml/smbdotconf/protocol/profileacls.xml
+++ b/docs-xml/smbdotconf/protocol/profileacls.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="profile acls"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/protocol/readraw.xml b/docs-xml/smbdotconf/protocol/readraw.xml
index f660b01..a467f52 100644
--- a/docs-xml/smbdotconf/protocol/readraw.xml
+++ b/docs-xml/smbdotconf/protocol/readraw.xml
@@ -1,9 +1,9 @@
 <samba:parameter name="read raw"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
-    <para>This is ignored if <smbconfoption name="async echo handler"/> is set,
+    <para>This is ignored if <smbconfoption name="async smb echo handler"/> is set,
     because this feature is incompatible with raw read SMB requests</para>
 
     <para>If enabled, raw reads allow reads of 65535 bytes in 
@@ -21,5 +21,5 @@
 <value type="default">yes</value>
 
 <related>write raw</related>
-<related>async echo handler</related>
+<related>async smb echo handler</related>
 </samba:parameter>
diff --git a/docs-xml/smbdotconf/protocol/rpcbigendian.xml b/docs-xml/smbdotconf/protocol/rpcbigendian.xml
index 1933054..5f7c5b6 100644
--- a/docs-xml/smbdotconf/protocol/rpcbigendian.xml
+++ b/docs-xml/smbdotconf/protocol/rpcbigendian.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="rpc big endian"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Setting this option will force the RPC client and server to
diff --git a/docs-xml/smbdotconf/protocol/servermaxprotocol.xml b/docs-xml/smbdotconf/protocol/servermaxprotocol.xml
index 7321d22..1dbe602 100644
--- a/docs-xml/smbdotconf/protocol/servermaxprotocol.xml
+++ b/docs-xml/smbdotconf/protocol/servermaxprotocol.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="server max protocol"
-		 context="G"
-		 type="enum"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="enum"
+                 enumlist="enum_protocol"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>The value of the parameter (a string) is the highest 
     protocol level that will be supported by the server.</para>
diff --git a/docs-xml/smbdotconf/protocol/serverminprotocol.xml b/docs-xml/smbdotconf/protocol/serverminprotocol.xml
index 25457d9..4765f5b 100644
--- a/docs-xml/smbdotconf/protocol/serverminprotocol.xml
+++ b/docs-xml/smbdotconf/protocol/serverminprotocol.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="server min protocol"
-		 context="G"
-		 type="enum"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="enum"
+                 enumlist="enum_protocol"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>min protocol</synonym>
 <description>
 	<para>This setting controls the minimum protocol version that the server
diff --git a/docs-xml/smbdotconf/protocol/servermultichannelsupport.xml b/docs-xml/smbdotconf/protocol/servermultichannelsupport.xml
new file mode 100644
index 0000000..14db171
--- /dev/null
+++ b/docs-xml/smbdotconf/protocol/servermultichannelsupport.xml
@@ -0,0 +1,21 @@
+<samba:parameter name="server multi channel support"
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+    <para>This boolean parameter controls whether
+    <citerefentry><refentrytitle>smbd</refentrytitle>
+    <manvolnum>8</manvolnum></citerefentry> will support
+    SMB3 multi-channel.
+    </para>
+    <para>This parameter has been added with version 4.4.</para>
+    <para>
+    Warning: Note that this feature is considered experimental in Samba 4.4.
+    Use it at your own risk: Even though it may seem to work well in testing,
+    it may result in data corruption under some race conditions.
+    Future 4.4.x release may improve this situation.
+    </para>
+</description>
+
+<value type="default">no</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/protocol/sharefakefscaps.xml b/docs-xml/smbdotconf/protocol/sharefakefscaps.xml
index 8709a28..11f4955 100644
--- a/docs-xml/smbdotconf/protocol/sharefakefscaps.xml
+++ b/docs-xml/smbdotconf/protocol/sharefakefscaps.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="share:fake_fscaps"
-	context="G"
-	type="string"
+                 context="G"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/docs-xml/smbdotconf/protocol/smb2maxcredits.xml b/docs-xml/smbdotconf/protocol/smb2maxcredits.xml
index ef2ad48..90bc622 100644
--- a/docs-xml/smbdotconf/protocol/smb2maxcredits.xml
+++ b/docs-xml/smbdotconf/protocol/smb2maxcredits.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="smb2 max credits"
-		type="integer"
-		context="G"
-                 generated_function="0"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="integer"
+                 context="G"
+                 handler="handle_smb2_max_credits"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 <para>This option controls the maximum number of outstanding simultaneous SMB2 operations
 that Samba tells the client it will allow. This is similar to the <smbconfoption name="max mux"/>
diff --git a/docs-xml/smbdotconf/protocol/smb2maxread.xml b/docs-xml/smbdotconf/protocol/smb2maxread.xml
index 9d05290..01f9583 100644
--- a/docs-xml/smbdotconf/protocol/smb2maxread.xml
+++ b/docs-xml/smbdotconf/protocol/smb2maxread.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="smb2 max read"
-		type="integer"
-		context="G"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="bytes"
+                 context="G"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 <para>This option specifies the protocol value that <citerefentry><refentrytitle>smbd</refentrytitle>
 <manvolnum>8</manvolnum></citerefentry> will return to a client, informing the client of the largest
diff --git a/docs-xml/smbdotconf/protocol/smb2maxtrans.xml b/docs-xml/smbdotconf/protocol/smb2maxtrans.xml
index a1998c9..5586d3f 100644
--- a/docs-xml/smbdotconf/protocol/smb2maxtrans.xml
+++ b/docs-xml/smbdotconf/protocol/smb2maxtrans.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="smb2 max trans"
-		type="integer"
-		context="G"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="bytes"
+                 context="G"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 <para>This option specifies the protocol value that <citerefentry><refentrytitle>smbd</refentrytitle>
 <manvolnum>8</manvolnum></citerefentry> will return to a client, informing the client of the largest
diff --git a/docs-xml/smbdotconf/protocol/smb2maxwrite.xml b/docs-xml/smbdotconf/protocol/smb2maxwrite.xml
index 5048d47..f895a04 100644
--- a/docs-xml/smbdotconf/protocol/smb2maxwrite.xml
+++ b/docs-xml/smbdotconf/protocol/smb2maxwrite.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="smb2 max write"
-		type="integer"
-		context="G"
-		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="bytes"
+                 context="G"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 <para>This option specifies the protocol value that <citerefentry><refentrytitle>smbd</refentrytitle>
 <manvolnum>8</manvolnum></citerefentry> will return to a client, informing the client of the largest
diff --git a/docs-xml/smbdotconf/protocol/smbports.xml b/docs-xml/smbdotconf/protocol/smbports.xml
index f21fe7f..ec1df65 100644
--- a/docs-xml/smbdotconf/protocol/smbports.xml
+++ b/docs-xml/smbdotconf/protocol/smbports.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="smb ports"
                  context="G"
-				 type="list"
+                 type="cmdlist"
+                 handler="handle_smb_ports"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies which ports the server should listen on for SMB traffic.</para>
diff --git a/docs-xml/smbdotconf/protocol/svcctllist.xml b/docs-xml/smbdotconf/protocol/svcctllist.xml
index ecd8184..826bf70 100644
--- a/docs-xml/smbdotconf/protocol/svcctllist.xml
+++ b/docs-xml/smbdotconf/protocol/svcctllist.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="svcctl list"
-		 type="list"
+                 type="cmdlist"
                  context="G"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/protocol/timeserver.xml b/docs-xml/smbdotconf/protocol/timeserver.xml
index f907fba..ceefbd3 100644
--- a/docs-xml/smbdotconf/protocol/timeserver.xml
+++ b/docs-xml/smbdotconf/protocol/timeserver.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="time server"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter determines if <citerefentry><refentrytitle>nmbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/protocol/unicode.xml b/docs-xml/smbdotconf/protocol/unicode.xml
index f7a2350..86fb06c 100644
--- a/docs-xml/smbdotconf/protocol/unicode.xml
+++ b/docs-xml/smbdotconf/protocol/unicode.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="unicode"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies whether the server and client should support unicode.</para>
diff --git a/docs-xml/smbdotconf/protocol/unixextensions.xml b/docs-xml/smbdotconf/protocol/unixextensions.xml
index 9bcf01d..61ae361 100644
--- a/docs-xml/smbdotconf/protocol/unixextensions.xml
+++ b/docs-xml/smbdotconf/protocol/unixextensions.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="unix extensions"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
     <para>This boolean parameter controls whether Samba
diff --git a/docs-xml/smbdotconf/protocol/usespnego.xml b/docs-xml/smbdotconf/protocol/usespnego.xml
index 1bdb4ba..0c9ffbf 100644
--- a/docs-xml/smbdotconf/protocol/usespnego.xml
+++ b/docs-xml/smbdotconf/protocol/usespnego.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="use spnego"
                  context="G"
-				 type="boolean"
+                 type="boolean"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This deprecated variable controls whether samba will try 
diff --git a/docs-xml/smbdotconf/protocol/webport.xml b/docs-xml/smbdotconf/protocol/webport.xml
index 7cc55b0..b9f49ef 100644
--- a/docs-xml/smbdotconf/protocol/webport.xml
+++ b/docs-xml/smbdotconf/protocol/webport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="web port"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies which port the Samba web server should listen on.</para>
diff --git a/docs-xml/smbdotconf/protocol/writeraw.xml b/docs-xml/smbdotconf/protocol/writeraw.xml
index 599104e..9a3d11f 100644
--- a/docs-xml/smbdotconf/protocol/writeraw.xml
+++ b/docs-xml/smbdotconf/protocol/writeraw.xml
@@ -1,9 +1,9 @@
 <samba:parameter name="write raw"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
-    <para>This is ignored if <smbconfoption name="async echo handler"/> is set, 
+    <para>This is ignored if <smbconfoption name="async smb echo handler"/> is set,
     because this feature is incompatible with raw write SMB requests</para>
 
     <para>If enabled, raw writes allow writes of 65535 bytes in 
@@ -21,5 +21,5 @@
 <value type="default">yes</value>
 
 <related>read raw</related>
-<related>async echo handler</related>
+<related>async smb echo handler</related>
 </samba:parameter>
diff --git a/docs-xml/smbdotconf/security/accessbasedshareenum.xml b/docs-xml/smbdotconf/security/accessbasedshareenum.xml
index b33c4a5..4557465 100644
--- a/docs-xml/smbdotconf/security/accessbasedshareenum.xml
+++ b/docs-xml/smbdotconf/security/accessbasedshareenum.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="access based share enum"
-		 type="boolean"
+                 type="boolean"
                  context="S"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
      <para>If this parameter is <constant>yes</constant> for a
     service, then the share hosted by the service will only be visible
diff --git a/docs-xml/smbdotconf/security/aclgroupcontrol.xml b/docs-xml/smbdotconf/security/aclgroupcontrol.xml
index fbc4c7d..eeec434 100644
--- a/docs-xml/smbdotconf/security/aclgroupcontrol.xml
+++ b/docs-xml/smbdotconf/security/aclgroupcontrol.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="acl group control"
                  context="S"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/security/adminusers.xml b/docs-xml/smbdotconf/security/adminusers.xml
index 30adea9..5e0f60c 100644
--- a/docs-xml/smbdotconf/security/adminusers.xml
+++ b/docs-xml/smbdotconf/security/adminusers.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="admin users"
                  context="S"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This is a list of users who will be granted 
diff --git a/docs-xml/smbdotconf/security/algorithmicridbase.xml b/docs-xml/smbdotconf/security/algorithmicridbase.xml
index 4df3c3d..a5eba3c 100644
--- a/docs-xml/smbdotconf/security/algorithmicridbase.xml
+++ b/docs-xml/smbdotconf/security/algorithmicridbase.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="algorithmic rid base"
                  context="G"
-				 type="integer"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="integer"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This determines how Samba will use its
     algorithmic mapping from uids/gid to the RIDs needed to construct
diff --git a/docs-xml/smbdotconf/security/allowtrusteddomains.xml b/docs-xml/smbdotconf/security/allowtrusteddomains.xml
index 806bab7..3617210 100644
--- a/docs-xml/smbdotconf/security/allowtrusteddomains.xml
+++ b/docs-xml/smbdotconf/security/allowtrusteddomains.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="allow trusted domains"
                  context="G"
-				 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
     This option only takes effect when the <smbconfoption name="security"/> option is set to 
diff --git a/docs-xml/smbdotconf/security/authmethods.xml b/docs-xml/smbdotconf/security/authmethods.xml
index 813c4cb..386104d 100644
--- a/docs-xml/smbdotconf/security/authmethods.xml
+++ b/docs-xml/smbdotconf/security/authmethods.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="auth methods"
                  context="G"
-				 type="list"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="cmdlist"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
     <para>
diff --git a/docs-xml/smbdotconf/security/checkpasswordscript.xml b/docs-xml/smbdotconf/security/checkpasswordscript.xml
index 7399744..e2079c2 100644
--- a/docs-xml/smbdotconf/security/checkpasswordscript.xml
+++ b/docs-xml/smbdotconf/security/checkpasswordscript.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="check password script"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>The name of a program that can be used to check password
diff --git a/docs-xml/smbdotconf/security/clientlanmanauth.xml b/docs-xml/smbdotconf/security/clientlanmanauth.xml
index 4147f34..c026b8f 100644
--- a/docs-xml/smbdotconf/security/clientlanmanauth.xml
+++ b/docs-xml/smbdotconf/security/clientlanmanauth.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="client lanman auth"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter determines whether or not <citerefentry><refentrytitle>smbclient</refentrytitle>
diff --git a/docs-xml/smbdotconf/security/clientntlmv2auth.xml b/docs-xml/smbdotconf/security/clientntlmv2auth.xml
index d0f0a37..531c8fc 100644
--- a/docs-xml/smbdotconf/security/clientntlmv2auth.xml
+++ b/docs-xml/smbdotconf/security/clientntlmv2auth.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="client NTLMv2 auth"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter determines whether or not <citerefentry><refentrytitle>smbclient</refentrytitle>
diff --git a/docs-xml/smbdotconf/security/clientplaintextauth.xml b/docs-xml/smbdotconf/security/clientplaintextauth.xml
index f640416..1c4d356 100644
--- a/docs-xml/smbdotconf/security/clientplaintextauth.xml
+++ b/docs-xml/smbdotconf/security/clientplaintextauth.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="client plaintext auth"
                  context="G"
-				 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies whether a client should send a plaintext 
 		password if the server does not support encrypted passwords.</para>
diff --git a/docs-xml/smbdotconf/security/clientschannel.xml b/docs-xml/smbdotconf/security/clientschannel.xml
index 62a47fe..6ab3558 100644
--- a/docs-xml/smbdotconf/security/clientschannel.xml
+++ b/docs-xml/smbdotconf/security/clientschannel.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="client schannel"
                  context="G"
-				 type="enum"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="enum"
+                 enumlist="enum_bool_auto"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
     <para>
diff --git a/docs-xml/smbdotconf/security/clientsigning.xml b/docs-xml/smbdotconf/security/clientsigning.xml
index 60b8ffe..2af5ada 100644
--- a/docs-xml/smbdotconf/security/clientsigning.xml
+++ b/docs-xml/smbdotconf/security/clientsigning.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="client signing"
                  context="G"
-				 type="enum"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="enum"
+                 enumlist="enum_smb_signing_vals"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This controls whether the client is allowed or required to use SMB signing. Possible values 
     are <emphasis>auto</emphasis>, <emphasis>mandatory</emphasis> 
diff --git a/docs-xml/smbdotconf/security/clientusepsnegoprincipal.xml b/docs-xml/smbdotconf/security/clientusepsnegoprincipal.xml
index 1d8214e..8e9edd2 100644
--- a/docs-xml/smbdotconf/security/clientusepsnegoprincipal.xml
+++ b/docs-xml/smbdotconf/security/clientusepsnegoprincipal.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="client use spnego principal"
                  context="G"
-				 type="boolean"
+                 type="boolean"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter determines whether or not
diff --git a/docs-xml/smbdotconf/security/createmask.xml b/docs-xml/smbdotconf/security/createmask.xml
index 22dc5eb..06ee896 100644
--- a/docs-xml/smbdotconf/security/createmask.xml
+++ b/docs-xml/smbdotconf/security/createmask.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="create mask"
                  context="S"
-				 type="integer"
+                 type="octal"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 
 <synonym>create mode</synonym>
diff --git a/docs-xml/smbdotconf/security/dedicatedkeytabfile.xml b/docs-xml/smbdotconf/security/dedicatedkeytabfile.xml
index c8d6c2d..d516315 100644
--- a/docs-xml/smbdotconf/security/dedicatedkeytabfile.xml
+++ b/docs-xml/smbdotconf/security/dedicatedkeytabfile.xml
@@ -1,4 +1,6 @@
-<samba:parameter name="dedicated keytab file" context="G" type="string"
+<samba:parameter name="dedicated keytab file"
+                 context="G"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/security/directorymask.xml b/docs-xml/smbdotconf/security/directorymask.xml
index 6a3d2f7..890092a 100644
--- a/docs-xml/smbdotconf/security/directorymask.xml
+++ b/docs-xml/smbdotconf/security/directorymask.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="directory mask"
-	context="S"
-	type="integer"
+                 context="S"
+                 type="octal"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>directory mode</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/security/directorysecuritymask.xml b/docs-xml/smbdotconf/security/directorysecuritymask.xml
index ad208f4..f02e4ff 100644
--- a/docs-xml/smbdotconf/security/directorysecuritymask.xml
+++ b/docs-xml/smbdotconf/security/directorysecuritymask.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="directory security mask"
-		 context="S"
-		 removed="1"
-		 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 removed="1"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
 	This parameter has been removed for Samba 4.0.0.
diff --git a/docs-xml/smbdotconf/security/encryptpasswords.xml b/docs-xml/smbdotconf/security/encryptpasswords.xml
index 4b7d50e..4bd9780 100644
--- a/docs-xml/smbdotconf/security/encryptpasswords.xml
+++ b/docs-xml/smbdotconf/security/encryptpasswords.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="encrypt passwords"
                  context="G"
-				 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This boolean controls whether encrypted passwords 
     will be negotiated with the client. Note that Windows NT 4.0 SP3 and 
diff --git a/docs-xml/smbdotconf/security/forcecreatemode.xml b/docs-xml/smbdotconf/security/forcecreatemode.xml
index 2b7f1bb..79e6e63 100644
--- a/docs-xml/smbdotconf/security/forcecreatemode.xml
+++ b/docs-xml/smbdotconf/security/forcecreatemode.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="force create mode"
                  context="S"
-                 type="integer"
+                 type="octal"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter specifies a set of UNIX mode bit
diff --git a/docs-xml/smbdotconf/security/forcedirectorymode.xml b/docs-xml/smbdotconf/security/forcedirectorymode.xml
index c28f84a..aa8375a 100644
--- a/docs-xml/smbdotconf/security/forcedirectorymode.xml
+++ b/docs-xml/smbdotconf/security/forcedirectorymode.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="force directory mode"
                  context="S"
-		 type="integer"
+                 type="octal"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter specifies a set of UNIX mode bit 
diff --git a/docs-xml/smbdotconf/security/forcedirectorysecuritymode.xml b/docs-xml/smbdotconf/security/forcedirectorysecuritymode.xml
index a45395d..fbd8e16 100644
--- a/docs-xml/smbdotconf/security/forcedirectorysecuritymode.xml
+++ b/docs-xml/smbdotconf/security/forcedirectorysecuritymode.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="force directory security mode"
-		 context="S"
-		 type="string"
-		 removed="1"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="S"
+                 type="string"
+                 removed="1"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
 	This parameter has been removed for Samba 4.0.0.
diff --git a/docs-xml/smbdotconf/security/forcegroup.xml b/docs-xml/smbdotconf/security/forcegroup.xml
index f6c9974..d101f1c 100644
--- a/docs-xml/smbdotconf/security/forcegroup.xml
+++ b/docs-xml/smbdotconf/security/forcegroup.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="force group"
                  context="S"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>group</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/security/forceunknownacluser.xml b/docs-xml/smbdotconf/security/forceunknownacluser.xml
index 4c0949f..c5aec53 100644
--- a/docs-xml/smbdotconf/security/forceunknownacluser.xml
+++ b/docs-xml/smbdotconf/security/forceunknownacluser.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="force unknown acl user"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 
 <description>
diff --git a/docs-xml/smbdotconf/security/forceuser.xml b/docs-xml/smbdotconf/security/forceuser.xml
index f1ec5d4..ff5c7a2 100644
--- a/docs-xml/smbdotconf/security/forceuser.xml
+++ b/docs-xml/smbdotconf/security/forceuser.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="force user"
-				 type="string"
+                 type="string"
                  context="S"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/security/guestaccount.xml b/docs-xml/smbdotconf/security/guestaccount.xml
index 905e795..c5dbbd9 100644
--- a/docs-xml/smbdotconf/security/guestaccount.xml
+++ b/docs-xml/smbdotconf/security/guestaccount.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="guest account"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This is a username which will be used for access 
     to services which are specified as <smbconfoption name="guest ok"/> (see below). Whatever privileges this 
diff --git a/docs-xml/smbdotconf/security/guestok.xml b/docs-xml/smbdotconf/security/guestok.xml
index 7a07ff1..390f1c3 100644
--- a/docs-xml/smbdotconf/security/guestok.xml
+++ b/docs-xml/smbdotconf/security/guestok.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="guest ok"
-				 type="boolean"
+                 type="boolean"
                  context="S"
-				 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>public</synonym>
 <description>
     <para>If this parameter is <constant>yes</constant> for 
diff --git a/docs-xml/smbdotconf/security/guestonly.xml b/docs-xml/smbdotconf/security/guestonly.xml
index 258eba9..5660162 100644
--- a/docs-xml/smbdotconf/security/guestonly.xml
+++ b/docs-xml/smbdotconf/security/guestonly.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="guest only"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>only guest</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/security/hostsallow.xml b/docs-xml/smbdotconf/security/hostsallow.xml
index 35be404..8b4b622 100644
--- a/docs-xml/smbdotconf/security/hostsallow.xml
+++ b/docs-xml/smbdotconf/security/hostsallow.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="hosts allow"
                  context="S"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>allow hosts</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/security/hostsdeny.xml b/docs-xml/smbdotconf/security/hostsdeny.xml
index 2421a4e..cd2f8de 100644
--- a/docs-xml/smbdotconf/security/hostsdeny.xml
+++ b/docs-xml/smbdotconf/security/hostsdeny.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="hosts deny"
                  context="S"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>deny hosts</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/security/inheritacls.xml b/docs-xml/smbdotconf/security/inheritacls.xml
index e2552e3..4c6caef 100644
--- a/docs-xml/smbdotconf/security/inheritacls.xml
+++ b/docs-xml/smbdotconf/security/inheritacls.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="inherit acls"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter can be used to ensure that if default acls
diff --git a/docs-xml/smbdotconf/security/inheritowner.xml b/docs-xml/smbdotconf/security/inheritowner.xml
index 0ed8285..ab7da57 100644
--- a/docs-xml/smbdotconf/security/inheritowner.xml
+++ b/docs-xml/smbdotconf/security/inheritowner.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="inherit owner"
                  context="S"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>The ownership of new files and directories 
diff --git a/docs-xml/smbdotconf/security/inheritpermissions.xml b/docs-xml/smbdotconf/security/inheritpermissions.xml
index 6e09f4f..9dda734 100644
--- a/docs-xml/smbdotconf/security/inheritpermissions.xml
+++ b/docs-xml/smbdotconf/security/inheritpermissions.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="inherit permissions"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/security/invalidusers.xml b/docs-xml/smbdotconf/security/invalidusers.xml
index f4ed66f..b2fb2b9 100644
--- a/docs-xml/smbdotconf/security/invalidusers.xml
+++ b/docs-xml/smbdotconf/security/invalidusers.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="invalid users"
                  context="S"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This is a list of users that should not be allowed 
diff --git a/docs-xml/smbdotconf/security/kerberosmethod.xml b/docs-xml/smbdotconf/security/kerberosmethod.xml
index a4948f2..b7cd988 100644
--- a/docs-xml/smbdotconf/security/kerberosmethod.xml
+++ b/docs-xml/smbdotconf/security/kerberosmethod.xml
@@ -1,4 +1,7 @@
-<samba:parameter name="kerberos method" context="G" type="enum"
+<samba:parameter name="kerberos method"
+                 context="G"
+                 type="enum"
+                 enumlist="enum_kerberos_method"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/security/kpasswdport.xml b/docs-xml/smbdotconf/security/kpasswdport.xml
index 0555e78..71cd337 100644
--- a/docs-xml/smbdotconf/security/kpasswdport.xml
+++ b/docs-xml/smbdotconf/security/kpasswdport.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="kpasswd port"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies which ports the Kerberos server should listen on for
diff --git a/docs-xml/smbdotconf/security/krb5port.xml b/docs-xml/smbdotconf/security/krb5port.xml
index 6c4f0a8..06c7988 100644
--- a/docs-xml/smbdotconf/security/krb5port.xml
+++ b/docs-xml/smbdotconf/security/krb5port.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="krb5 port"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>Specifies which port the KDC should listen on for Kerberos traffic.</para>
diff --git a/docs-xml/smbdotconf/security/lanmanauth.xml b/docs-xml/smbdotconf/security/lanmanauth.xml
index 44d18c4..138a24f 100644
--- a/docs-xml/smbdotconf/security/lanmanauth.xml
+++ b/docs-xml/smbdotconf/security/lanmanauth.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="lanman auth"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter determines whether or not <citerefentry><refentrytitle>smbd</refentrytitle>
@@ -20,7 +20,7 @@
     will also result in sambaLMPassword in Samba's passdb being
     blanked after the next password change. As a result of that
     lanman clients won't be able to authenticate, even if lanman
-    auth is reenabled later on.
+    auth is re-enabled later on.
     </para>
 		
     <para>Unlike the <command moreinfo="none">encrypt
diff --git a/docs-xml/smbdotconf/security/maptoguest.xml b/docs-xml/smbdotconf/security/maptoguest.xml
index 2e4c634..c98086a 100644
--- a/docs-xml/smbdotconf/security/maptoguest.xml
+++ b/docs-xml/smbdotconf/security/maptoguest.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="map to guest"
-				 type="enum"
+                 type="enum"
                  context="G"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 enumlist="enum_map_to_guest"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter can take four different values, which tell
     <citerefentry><refentrytitle>smbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml b/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml
index 69f4d82..126411a 100644
--- a/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml
+++ b/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="map untrusted to domain"
                  context="G"
-		 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
     If a client connects to smbd using an untrusted domain name, such as
diff --git a/docs-xml/smbdotconf/security/ntlmauth.xml b/docs-xml/smbdotconf/security/ntlmauth.xml
index a39f9e5..6af1908 100644
--- a/docs-xml/smbdotconf/security/ntlmauth.xml
+++ b/docs-xml/smbdotconf/security/ntlmauth.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="ntlm auth"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter determines whether or not <citerefentry><refentrytitle>smbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/security/nullpasswords.xml b/docs-xml/smbdotconf/security/nullpasswords.xml
index 3d7b2ad..49533f6 100644
--- a/docs-xml/smbdotconf/security/nullpasswords.xml
+++ b/docs-xml/smbdotconf/security/nullpasswords.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="null passwords"
                  context="G"
-				 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="boolean"
+                 deprecated="1"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>Allow or disallow client access to accounts that have null passwords. </para>
 
diff --git a/docs-xml/smbdotconf/security/obeypamrestrictions.xml b/docs-xml/smbdotconf/security/obeypamrestrictions.xml
index e4b2b6c..92708ef 100644
--- a/docs-xml/smbdotconf/security/obeypamrestrictions.xml
+++ b/docs-xml/smbdotconf/security/obeypamrestrictions.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="obey pam restrictions"
                  context="G"
-				 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>When Samba 3.0 is configured to enable PAM support
     (i.e. --with-pam), this parameter will control whether or not Samba
diff --git a/docs-xml/smbdotconf/security/oldpasswordallowedperiod.xml b/docs-xml/smbdotconf/security/oldpasswordallowedperiod.xml
index 718cd32..9cb607b 100644
--- a/docs-xml/smbdotconf/security/oldpasswordallowedperiod.xml
+++ b/docs-xml/smbdotconf/security/oldpasswordallowedperiod.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="old password allowed period"
                  context="G"
-				 type="integer"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="integer"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>Number of minutes to permit an NTLM login after a password change or reset using the old password.  This allows the user to re-cache the new password on multiple clients without disrupting a network reconnection in the meantime. </para>
 
diff --git a/docs-xml/smbdotconf/security/onlyuser.xml b/docs-xml/smbdotconf/security/onlyuser.xml
index ed1bbd5..3b62ba6 100644
--- a/docs-xml/smbdotconf/security/onlyuser.xml
+++ b/docs-xml/smbdotconf/security/onlyuser.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="only user"
-					type="boolean"
+                 type="boolean"
                  context="S"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>To restrict a service to a particular set of users you
diff --git a/docs-xml/smbdotconf/security/pampasswordchange.xml b/docs-xml/smbdotconf/security/pampasswordchange.xml
index 973a10b..92ab4ad 100644
--- a/docs-xml/smbdotconf/security/pampasswordchange.xml
+++ b/docs-xml/smbdotconf/security/pampasswordchange.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="pam password change"
                  context="G"
-				 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>With the addition of better PAM support in Samba 2.2, 
     this parameter, it is possible to use PAM's password change control 
diff --git a/docs-xml/smbdotconf/security/passdbbackend.xml b/docs-xml/smbdotconf/security/passdbbackend.xml
index 4f5321d..3e378bd 100644
--- a/docs-xml/smbdotconf/security/passdbbackend.xml
+++ b/docs-xml/smbdotconf/security/passdbbackend.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="passdb backend"
                  context="G"
-		 type="string"
+                 type="string"
                  constant="1"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
     <para>This option allows the administrator to chose which backend
diff --git a/docs-xml/smbdotconf/security/passdbexpandexplicit.xml b/docs-xml/smbdotconf/security/passdbexpandexplicit.xml
index 778a390..41c8ea0 100644
--- a/docs-xml/smbdotconf/security/passdbexpandexplicit.xml
+++ b/docs-xml/smbdotconf/security/passdbexpandexplicit.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="passdb expand explicit"
                  context="G"
-				 type="boolean"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
 	This parameter controls whether Samba substitutes %-macros in the passdb fields if they are explicitly set. We
diff --git a/docs-xml/smbdotconf/security/passwdchatdebug.xml b/docs-xml/smbdotconf/security/passwdchatdebug.xml
index 9046f20..0c3481e 100644
--- a/docs-xml/smbdotconf/security/passwdchatdebug.xml
+++ b/docs-xml/smbdotconf/security/passwdchatdebug.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="passwd chat debug"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This boolean specifies if the passwd chat script 
diff --git a/docs-xml/smbdotconf/security/passwdchattimeout.xml b/docs-xml/smbdotconf/security/passwdchattimeout.xml
index 07374ff..74e8688 100644
--- a/docs-xml/smbdotconf/security/passwdchattimeout.xml
+++ b/docs-xml/smbdotconf/security/passwdchattimeout.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="passwd chat timeout"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This integer specifies the number of seconds smbd will wait for an initial
diff --git a/docs-xml/smbdotconf/security/passwdprogram.xml b/docs-xml/smbdotconf/security/passwdprogram.xml
index 94649e2..8141048 100644
--- a/docs-xml/smbdotconf/security/passwdprogram.xml
+++ b/docs-xml/smbdotconf/security/passwdprogram.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="passwd program"
                  context="G"
-				 type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
     <para>The name of a program that can be used to set 
     UNIX user passwords.  Any occurrences of <parameter moreinfo="none">%u</parameter> 
diff --git a/docs-xml/smbdotconf/security/passwordserver.xml b/docs-xml/smbdotconf/security/passwordserver.xml
index e01adb6..a62494b 100644
--- a/docs-xml/smbdotconf/security/passwordserver.xml
+++ b/docs-xml/smbdotconf/security/passwordserver.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="password server"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>By specifying the name of a domain controller with this option,
     and using <command moreinfo="none">security = [ads|domain]</command>
diff --git a/docs-xml/smbdotconf/security/preloadmodules.xml b/docs-xml/smbdotconf/security/preloadmodules.xml
index 44eb467..7b77674 100644
--- a/docs-xml/smbdotconf/security/preloadmodules.xml
+++ b/docs-xml/smbdotconf/security/preloadmodules.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="preload modules"
-		type="list"
-		 context="G"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="cmdlist"
+                 context="G"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This is a list of paths to modules that should
 	be loaded into smbd before a client connects. This improves
diff --git a/docs-xml/smbdotconf/security/privatedir.xml b/docs-xml/smbdotconf/security/privatedir.xml
index 4189f6b..58be372 100644
--- a/docs-xml/smbdotconf/security/privatedir.xml
+++ b/docs-xml/smbdotconf/security/privatedir.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="private dir"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>private directory</synonym>
 <description>
     <para>This parameters defines the directory
diff --git a/docs-xml/smbdotconf/security/readlist.xml b/docs-xml/smbdotconf/security/readlist.xml
index c874fef..96f3746 100644
--- a/docs-xml/smbdotconf/security/readlist.xml
+++ b/docs-xml/smbdotconf/security/readlist.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="read list"
                  context="S"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/security/readonly.xml b/docs-xml/smbdotconf/security/readonly.xml
index f587f67..834633f 100644
--- a/docs-xml/smbdotconf/security/readonly.xml
+++ b/docs-xml/smbdotconf/security/readonly.xml
@@ -1,8 +1,7 @@
 <samba:parameter name="read only"
                  context="S"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
-<synonym>write ok</synonym>
 <description>
     <para>An inverted synonym is <smbconfoption name="writeable"/>.</para>
 
diff --git a/docs-xml/smbdotconf/security/renameuserscript.xml b/docs-xml/smbdotconf/security/renameuserscript.xml
index 472a4a3..1a15eba 100644
--- a/docs-xml/smbdotconf/security/renameuserscript.xml
+++ b/docs-xml/smbdotconf/security/renameuserscript.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="rename user script"
                  context="G"
-				 type="string"
-				 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
 	This is the full pathname to a script that will be run as root by <citerefentry><refentrytitle>smbd</refentrytitle>
diff --git a/docs-xml/smbdotconf/security/restrictanonymous.xml b/docs-xml/smbdotconf/security/restrictanonymous.xml
index ffea693..78cafd2 100644
--- a/docs-xml/smbdotconf/security/restrictanonymous.xml
+++ b/docs-xml/smbdotconf/security/restrictanonymous.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="restrict anonymous"
-	type="integer"
+                 type="integer"
                  context="G"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/security/rootdirectory.xml b/docs-xml/smbdotconf/security/rootdirectory.xml
index d5a071e..e795af2 100644
--- a/docs-xml/smbdotconf/security/rootdirectory.xml
+++ b/docs-xml/smbdotconf/security/rootdirectory.xml
@@ -1,7 +1,7 @@
 <samba:parameter name="root directory"
-	context="G"
-	type="string"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>root</synonym>
 <synonym>root dir</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/security/sambakcccommand.xml b/docs-xml/smbdotconf/security/sambakcccommand.xml
index cf94480..af8a28a 100644
--- a/docs-xml/smbdotconf/security/sambakcccommand.xml
+++ b/docs-xml/smbdotconf/security/sambakcccommand.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="samba kcc command"
                  context="G"
-                 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option specifies the path to the Samba KCC command.
diff --git a/docs-xml/smbdotconf/security/security.xml b/docs-xml/smbdotconf/security/security.xml
index ac248d0..89e6a45 100644
--- a/docs-xml/smbdotconf/security/security.xml
+++ b/docs-xml/smbdotconf/security/security.xml
@@ -1,11 +1,12 @@
 <samba:parameter name="security"
                  context="G"
-				 type="enum"
+                 type="enum"
                  function="_security"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
-		 <when_value value="security">
-			 <requires option="encrypted passwords">/(yes|true)/</requires>
-		 </when_value>
+                 enumlist="enum_security"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<when_value value="security">
+    <requires option="encrypted passwords">/(yes|true)/</requires>
+</when_value>
 <description>
     <para>This option affects how clients respond to 
     Samba and is one of the most important settings in the <filename moreinfo="none">
diff --git a/docs-xml/smbdotconf/security/serverrole.xml b/docs-xml/smbdotconf/security/serverrole.xml
index e6ff399..9511c61 100644
--- a/docs-xml/smbdotconf/security/serverrole.xml
+++ b/docs-xml/smbdotconf/security/serverrole.xml
@@ -1,8 +1,9 @@
 <samba:parameter name="server role"
                  context="G"
-				 type="enum"
+                 type="enum"
                  function="_server_role"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 enumlist="enum_server_role"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option determines the basic operating mode of a Samba
     server and is one of the most important settings in the <filename
@@ -24,7 +25,7 @@
     <para><anchor id="AUTO"/><emphasis>SERVER ROLE = AUTO</emphasis></para>
 
     <para>This is the default server role in Samba, and causes Samba to consult
-    the <smbconfoption name="security"/> parameter (if set) to determine the server role, giving compatable behaviours to previous Samba versions.</para>
+    the <smbconfoption name="security"/> parameter (if set) to determine the server role, giving compatible behaviours to previous Samba versions.</para>
 
     <para><anchor id="STANDALONE"/><emphasis>SERVER ROLE = STANDALONE</emphasis></para>
 
@@ -60,7 +61,7 @@
     only one PDC per NetBIOS scope (typcially a broadcast network or
     clients served by a single WINS server).</para>
 
-    <para><anchor id="BDC"/><emphasis>SERVER ROLE = NETBIOS BACKUP DOMAIN CONTROLLER</emphasis></para>
+    <para><anchor id="BDC"/><emphasis>SERVER ROLE = CLASSIC BACKUP DOMAIN CONTROLLER</emphasis></para>
 
     <para>This mode of operation runs a classic Samba backup domain
     controller, providing domain logon services to Windows and Samba
@@ -84,5 +85,5 @@
 <related>encrypt passwords</related>
 
 <value type="default">AUTO</value>
-<value type="example">DOMAIN CONTROLLER</value>
+<value type="example">ACTIVE DIRECTORY DOMAIN CONTROLLER</value>
 </samba:parameter>
diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml
index aee63cc..a2dca1b 100644
--- a/docs-xml/smbdotconf/security/serverschannel.xml
+++ b/docs-xml/smbdotconf/security/serverschannel.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="server schannel"
                  context="G"
-				 type="enum"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="enum"
+                 enumlist="enum_bool_auto"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
 	This controls whether the server offers or even demands the use of the netlogon schannel.
diff --git a/docs-xml/smbdotconf/security/serversigning.xml b/docs-xml/smbdotconf/security/serversigning.xml
index 9fdb833..21b79f0 100644
--- a/docs-xml/smbdotconf/security/serversigning.xml
+++ b/docs-xml/smbdotconf/security/serversigning.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="server signing"
                  context="G"
-				 type="enum"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="enum"
+                 enumlist="enum_smb_signing_vals"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
     <para>This controls whether the client is allowed or required to use SMB1 and SMB2 signing. Possible values
diff --git a/docs-xml/smbdotconf/security/smbencrypt.xml b/docs-xml/smbdotconf/security/smbencrypt.xml
index b44ed9a..0f08966 100644
--- a/docs-xml/smbdotconf/security/smbencrypt.xml
+++ b/docs-xml/smbdotconf/security/smbencrypt.xml
@@ -1,7 +1,8 @@
 <samba:parameter name="smb encrypt"
                  context="S"
-				 type="enum"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 type="enum"
+                 enumlist="enum_smb_signing_vals"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
 	This parameter controls whether a remote client is allowed or required
diff --git a/docs-xml/smbdotconf/security/smbpasswdfile.xml b/docs-xml/smbdotconf/security/smbpasswdfile.xml
index 7ca8584..a906403 100644
--- a/docs-xml/smbdotconf/security/smbpasswdfile.xml
+++ b/docs-xml/smbdotconf/security/smbpasswdfile.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="smb passwd file"
-	type="string"
+                 type="string"
                  context="G"
                  constant="1"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option sets the path to the encrypted smbpasswd file. By
     default the path to the smbpasswd file  is compiled into Samba.</para>
diff --git a/docs-xml/smbdotconf/security/tlsdhparamsfile.xml b/docs-xml/smbdotconf/security/tlsdhparamsfile.xml
index 7d454f3..4a5361c 100644
--- a/docs-xml/smbdotconf/security/tlsdhparamsfile.xml
+++ b/docs-xml/smbdotconf/security/tlsdhparamsfile.xml
@@ -6,7 +6,7 @@
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
  <description>
 	 <para>This option can be set to a file with Diffie-Hellman parameters
-		 which will be used with EDH ciphers.
+		 which will be used with DH ciphers.
 	 </para>
 	 <para>This path is relative to <smbconfoption name="private dir"/> if the path
 	 does not start with a /.</para>
diff --git a/docs-xml/smbdotconf/security/unixpasswordsync.xml b/docs-xml/smbdotconf/security/unixpasswordsync.xml
index d88254b..321ece5 100644
--- a/docs-xml/smbdotconf/security/unixpasswordsync.xml
+++ b/docs-xml/smbdotconf/security/unixpasswordsync.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="unix password sync"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This boolean parameter controls whether Samba 
diff --git a/docs-xml/smbdotconf/security/username.xml b/docs-xml/smbdotconf/security/username.xml
index a85076c..a04a997 100644
--- a/docs-xml/smbdotconf/security/username.xml
+++ b/docs-xml/smbdotconf/security/username.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="username"
-	context="S"
-	type="string"
+                 context="S"
+                 type="string"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>user</synonym>
 <synonym>users</synonym>
diff --git a/docs-xml/smbdotconf/security/usernamelevel.xml b/docs-xml/smbdotconf/security/usernamelevel.xml
index d2cdb5b..f5248c0 100644
--- a/docs-xml/smbdotconf/security/usernamelevel.xml
+++ b/docs-xml/smbdotconf/security/usernamelevel.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="username level"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option helps Samba to try and 'guess' at 
diff --git a/docs-xml/smbdotconf/security/usernamemap.xml b/docs-xml/smbdotconf/security/usernamemap.xml
index c5a15d0..8867ea6 100644
--- a/docs-xml/smbdotconf/security/usernamemap.xml
+++ b/docs-xml/smbdotconf/security/usernamemap.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="username map"
                  context="G"
-				 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/security/usernamemapcachetime.xml b/docs-xml/smbdotconf/security/usernamemapcachetime.xml
index 16aaaaf..974026c 100644
--- a/docs-xml/smbdotconf/security/usernamemapcachetime.xml
+++ b/docs-xml/smbdotconf/security/usernamemapcachetime.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="username map cache time"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/security/usernamemapscript.xml b/docs-xml/smbdotconf/security/usernamemapscript.xml
index 2e43a78..0edd4eb 100644
--- a/docs-xml/smbdotconf/security/usernamemapscript.xml
+++ b/docs-xml/smbdotconf/security/usernamemapscript.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="username map script"
                  context="G"
-		 type="string"
+                 type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This script is a mutually exclusive alternative to the 
diff --git a/docs-xml/smbdotconf/security/validusers.xml b/docs-xml/smbdotconf/security/validusers.xml
index ec3e11e..0b681a1 100644
--- a/docs-xml/smbdotconf/security/validusers.xml
+++ b/docs-xml/smbdotconf/security/validusers.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="valid users"
                  context="S"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/security/writeable.xml b/docs-xml/smbdotconf/security/writeable.xml
index 8c0e12e..5433849 100644
--- a/docs-xml/smbdotconf/security/writeable.xml
+++ b/docs-xml/smbdotconf/security/writeable.xml
@@ -1,9 +1,11 @@
 <samba:parameter name="writeable"
                  context="S"
-				 type="boolean"
+                 type="boolean-rev"
+                 function="read_only"
                  synonym="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>writable</synonym>
+<synonym>write ok</synonym>
 <description>
     <para>Inverted synonym for <smbconfoption name="read only"/>.</para>
 </description>
diff --git a/docs-xml/smbdotconf/security/writelist.xml b/docs-xml/smbdotconf/security/writelist.xml
index c17db81..a9b9e8b 100644
--- a/docs-xml/smbdotconf/security/writelist.xml
+++ b/docs-xml/smbdotconf/security/writelist.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="write list"
                  context="S"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/docs-xml/smbdotconf/tuning/aiomaxthreads.xml b/docs-xml/smbdotconf/tuning/aiomaxthreads.xml
new file mode 100644
index 0000000..3afe989
--- /dev/null
+++ b/docs-xml/smbdotconf/tuning/aiomaxthreads.xml
@@ -0,0 +1,19 @@
+<samba:parameter name="aio max threads"
+                 type="integer"
+                 context="G"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+  <para>
+    The integer parameter specifies the maximum number of
+    threads each smbd process will create when doing parallel asynchronous IO
+    calls. If the number of outstanding calls is greater than this
+    number the requests will not be refused but go onto a queue
+    and will be scheduled in turn as outstanding requests complete.
+  </para>
+
+  <related>aio read size</related>
+  <related>aio write size</related>
+</description>
+
+<value type="default">100</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/tuning/aioreadsize.xml b/docs-xml/smbdotconf/tuning/aioreadsize.xml
index 082cf5d..0c9cc52 100644
--- a/docs-xml/smbdotconf/tuning/aioreadsize.xml
+++ b/docs-xml/smbdotconf/tuning/aioreadsize.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="aio read size"
                  context="S"
-		 type="integer"
+                 type="bytes"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
   <para>If Samba has been built with asynchronous I/O support and this
diff --git a/docs-xml/smbdotconf/tuning/aiowritesize.xml b/docs-xml/smbdotconf/tuning/aiowritesize.xml
index e33a60e..c2ad118 100644
--- a/docs-xml/smbdotconf/tuning/aiowritesize.xml
+++ b/docs-xml/smbdotconf/tuning/aiowritesize.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="aio write size"
                  context="S"
-		 type="integer"
+                 type="bytes"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
   <para>If Samba has been built with asynchronous I/O support and this
diff --git a/docs-xml/smbdotconf/tuning/allocationroundupsize.xml b/docs-xml/smbdotconf/tuning/allocationroundupsize.xml
index 5fc013b..eaea467 100644
--- a/docs-xml/smbdotconf/tuning/allocationroundupsize.xml
+++ b/docs-xml/smbdotconf/tuning/allocationroundupsize.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="allocation roundup size"
                  context="S"
-		 type="integer"
+                 type="bytes"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This parameter allows an administrator to tune the 
diff --git a/docs-xml/smbdotconf/tuning/blocksize.xml b/docs-xml/smbdotconf/tuning/blocksize.xml
index 1a0cc54..8d0dd8c 100644
--- a/docs-xml/smbdotconf/tuning/blocksize.xml
+++ b/docs-xml/smbdotconf/tuning/blocksize.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="block size"
-				type="integer"
+                 type="bytes"
                  context="S"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/tuning/maxdisksize.xml b/docs-xml/smbdotconf/tuning/maxdisksize.xml
index 27d74b9..0361358 100644
--- a/docs-xml/smbdotconf/tuning/maxdisksize.xml
+++ b/docs-xml/smbdotconf/tuning/maxdisksize.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="max disk size"
                  context="G"
-				 type="integer"
+                 type="bytes"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option allows you to put an upper limit 
diff --git a/docs-xml/smbdotconf/tuning/strictrename.xml b/docs-xml/smbdotconf/tuning/strictrename.xml
index 5478863..91572f2 100644
--- a/docs-xml/smbdotconf/tuning/strictrename.xml
+++ b/docs-xml/smbdotconf/tuning/strictrename.xml
@@ -15,9 +15,18 @@
     Samba system the cost is even greater than the non-clustered
     case.</para>
 
-    <para>For this reason the default is "no", and it is recommended
-    to be left that way unless a specific Windows application requires
-    it to be changed.</para>
+    <para>When set to "no" smbd only checks the local process
+    the client is attached to for open files below a directory
+    being renamed, instead of checking for open files across all
+    smbd processes.</para>
+
+    <para>Because of the expense in fully searching the database,
+    the default is "no", and it is recommended to be left that way
+    unless a specific Windows application requires it to be changed.</para>
+
+    <para>If the client has requested UNIX extensions (POSIX
+    pathnames) then renames are always allowed and this parameter
+    has no effect.</para>
 
 </description>
 
diff --git a/docs-xml/smbdotconf/tuning/strictsync.xml b/docs-xml/smbdotconf/tuning/strictsync.xml
index 0d33845..5cfd388 100644
--- a/docs-xml/smbdotconf/tuning/strictsync.xml
+++ b/docs-xml/smbdotconf/tuning/strictsync.xml
@@ -5,7 +5,7 @@
  <description>
     <para>Many Windows applications (including the Windows 98 explorer
     shell) seem to confuse flushing buffer contents to disk with doing
-    a sync to disk. Under UNIX, a sync call forces the process to be
+    a sync to disk. Under UNIX, a sync call forces the thread to be
     suspended until the kernel has ensured that all outstanding data in
     kernel disk buffers has been safely stored onto stable storage.
     This is very slow and should only be done rarely. Setting this
@@ -17,6 +17,10 @@
     on crashes, so there is little danger in this default setting. In
     addition, this fixes many performance problems that people have
     reported with the new Windows98 explorer shell file copies.</para>
+    <para>The flush request from SMB2/3 clients is handled
+    asynchronously, so for these clients setting the parameter
+    to <constant>yes</constant> does not block the processing of other
+    requests in the smbd process.</para>
 </description>
 
 <related>sync always</related>
diff --git a/docs-xml/smbdotconf/tuning/writecachesize.xml b/docs-xml/smbdotconf/tuning/writecachesize.xml
index e2fa17f..484b353 100644
--- a/docs-xml/smbdotconf/tuning/writecachesize.xml
+++ b/docs-xml/smbdotconf/tuning/writecachesize.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="write cache size"
                  context="S"
-				 type="integer"
+                 type="bytes"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>If this integer parameter is set to non-zero value,
diff --git a/docs-xml/smbdotconf/vfs/vfsobjects.xml b/docs-xml/smbdotconf/vfs/vfsobjects.xml
index 09d41c7..05903ba 100644
--- a/docs-xml/smbdotconf/vfs/vfsobjects.xml
+++ b/docs-xml/smbdotconf/vfs/vfsobjects.xml
@@ -1,5 +1,5 @@
 <samba:parameter name="vfs objects"
-				type="list"
+                 type="cmdlist"
                  context="S"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>vfs object</synonym>
diff --git a/docs-xml/smbdotconf/winbind/createkrb5conf.xml b/docs-xml/smbdotconf/winbind/createkrb5conf.xml
index bb2d300..4054034 100644
--- a/docs-xml/smbdotconf/winbind/createkrb5conf.xml
+++ b/docs-xml/smbdotconf/winbind/createkrb5conf.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="create krb5 conf"
-	context="G"
-	type="boolean"
+                 context="G"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/docs-xml/smbdotconf/winbind/idmapbackend.xml b/docs-xml/smbdotconf/winbind/idmapbackend.xml
index a554741..864a975 100644
--- a/docs-xml/smbdotconf/winbind/idmapbackend.xml
+++ b/docs-xml/smbdotconf/winbind/idmapbackend.xml
@@ -1,7 +1,9 @@
 <samba:parameter name="idmap backend"
                  context="G"
-		 type="string"
+                 type="string"
                  generated_function="0"
+                 handler="handle_idmap_backend"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/winbind/idmapcachetime.xml b/docs-xml/smbdotconf/winbind/idmapcachetime.xml
index 4fe6536..87c6c56 100644
--- a/docs-xml/smbdotconf/winbind/idmapcachetime.xml
+++ b/docs-xml/smbdotconf/winbind/idmapcachetime.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="idmap cache time"
                  context="G"
-		 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the number of seconds that Winbind's
diff --git a/docs-xml/smbdotconf/winbind/idmapconfig.xml b/docs-xml/smbdotconf/winbind/idmapconfig.xml
index db24784..1374040 100644
--- a/docs-xml/smbdotconf/winbind/idmapconfig.xml
+++ b/docs-xml/smbdotconf/winbind/idmapconfig.xml
@@ -1,4 +1,4 @@
-<samba:parameter name="idmap config:OPTION"
+<samba:parameter name="idmap config DOMAIN : OPTION"
                  context="G"
                  type="string"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
diff --git a/docs-xml/smbdotconf/winbind/idmapgid.xml b/docs-xml/smbdotconf/winbind/idmapgid.xml
index b5652b8..1b576b2 100644
--- a/docs-xml/smbdotconf/winbind/idmapgid.xml
+++ b/docs-xml/smbdotconf/winbind/idmapgid.xml
@@ -1,9 +1,11 @@
 <samba:parameter name="idmap gid"
                  context="G"
-		 type="string"
+                 type="string"
                  generated_function="0"
+                 handler="handle_idmap_gid"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
-		<synonym>winbind gid</synonym>
+<synonym>winbind gid</synonym>
 <description>
 	<para>
 	The idmap gid parameter specifies the range of group ids
diff --git a/docs-xml/smbdotconf/winbind/idmapnegativecachetime.xml b/docs-xml/smbdotconf/winbind/idmapnegativecachetime.xml
index 76f538a..32c4e1f 100644
--- a/docs-xml/smbdotconf/winbind/idmapnegativecachetime.xml
+++ b/docs-xml/smbdotconf/winbind/idmapnegativecachetime.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="idmap negative cache time"
                  context="G"
-		 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the number of seconds that Winbind's
diff --git a/docs-xml/smbdotconf/winbind/idmapuid.xml b/docs-xml/smbdotconf/winbind/idmapuid.xml
index f72929c..f666f61 100644
--- a/docs-xml/smbdotconf/winbind/idmapuid.xml
+++ b/docs-xml/smbdotconf/winbind/idmapuid.xml
@@ -1,7 +1,9 @@
 <samba:parameter name="idmap uid"
-			 type="string"
+                 type="string"
                  context="G"
                  generated_function="0"
+                 handler="handle_idmap_uid"
+                 deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <synonym>winbind uid</synonym>
 <description>
diff --git a/docs-xml/smbdotconf/winbind/templatehomedir.xml b/docs-xml/smbdotconf/winbind/templatehomedir.xml
index 2afa6b3..cbf391c 100644
--- a/docs-xml/smbdotconf/winbind/templatehomedir.xml
+++ b/docs-xml/smbdotconf/winbind/templatehomedir.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="template homedir"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/winbind/templateshell.xml b/docs-xml/smbdotconf/winbind/templateshell.xml
index 0844bdf..21e44e6 100644
--- a/docs-xml/smbdotconf/winbind/templateshell.xml
+++ b/docs-xml/smbdotconf/winbind/templateshell.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="template shell"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/winbind/winbindcachetime.xml b/docs-xml/smbdotconf/winbind/winbindcachetime.xml
index 3ff8089..2f69de3 100644
--- a/docs-xml/smbdotconf/winbind/winbindcachetime.xml
+++ b/docs-xml/smbdotconf/winbind/winbindcachetime.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind cache time"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the number of 
diff --git a/docs-xml/smbdotconf/winbind/winbindenumgroups.xml b/docs-xml/smbdotconf/winbind/winbindenumgroups.xml
index 4d7b5e6..c3339e1 100644
--- a/docs-xml/smbdotconf/winbind/winbindenumgroups.xml
+++ b/docs-xml/smbdotconf/winbind/winbindenumgroups.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind enum groups"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>On large installations using <citerefentry><refentrytitle>winbindd</refentrytitle>
diff --git a/docs-xml/smbdotconf/winbind/winbindexpandgroups.xml b/docs-xml/smbdotconf/winbind/winbindexpandgroups.xml
index 73c1464..941ba04 100644
--- a/docs-xml/smbdotconf/winbind/winbindexpandgroups.xml
+++ b/docs-xml/smbdotconf/winbind/winbindexpandgroups.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind expand groups"
                  context="G"
-		 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This option controls the maximum depth that winbindd
diff --git a/docs-xml/smbdotconf/winbind/winbindmaxclients.xml b/docs-xml/smbdotconf/winbind/winbindmaxclients.xml
index c11d0b6..847a588 100644
--- a/docs-xml/smbdotconf/winbind/winbindmaxclients.xml
+++ b/docs-xml/smbdotconf/winbind/winbindmaxclients.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind max clients"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the maximum number of clients
diff --git a/docs-xml/smbdotconf/winbind/winbindmaxdomainconnections.xml b/docs-xml/smbdotconf/winbind/winbindmaxdomainconnections.xml
index c279244..be39143 100644
--- a/docs-xml/smbdotconf/winbind/winbindmaxdomainconnections.xml
+++ b/docs-xml/smbdotconf/winbind/winbindmaxdomainconnections.xml
@@ -1,8 +1,8 @@
 <samba:parameter name="winbind max domain connections"
-		 context="G"
-		 type="integer"
-                 generated_function="0"
-		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+                 context="G"
+                 type="integer"
+                 function="_winbind_max_domain_connections"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the maximum number of simultaneous
 	connections that the <citerefentry><refentrytitle>winbindd</refentrytitle>
diff --git a/docs-xml/smbdotconf/winbind/winbindnestedgroups.xml b/docs-xml/smbdotconf/winbind/winbindnestedgroups.xml
index 8a8bc54..a4a03eb 100644
--- a/docs-xml/smbdotconf/winbind/winbindnestedgroups.xml
+++ b/docs-xml/smbdotconf/winbind/winbindnestedgroups.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind nested groups"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>If set to yes, this parameter activates the support for nested
diff --git a/docs-xml/smbdotconf/winbind/winbindnormalizenames.xml b/docs-xml/smbdotconf/winbind/winbindnormalizenames.xml
index 8339cbf..362f488 100644
--- a/docs-xml/smbdotconf/winbind/winbindnormalizenames.xml
+++ b/docs-xml/smbdotconf/winbind/winbindnormalizenames.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind normalize names"
                  context="G"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter controls whether winbindd will replace
diff --git a/docs-xml/smbdotconf/winbind/winbindnssinfo.xml b/docs-xml/smbdotconf/winbind/winbindnssinfo.xml
index 6b09be0..d834744 100644
--- a/docs-xml/smbdotconf/winbind/winbindnssinfo.xml
+++ b/docs-xml/smbdotconf/winbind/winbindnssinfo.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind nss info"
                  context="G"
-				 type="list"
+                 type="cmdlist"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/docs-xml/smbdotconf/winbind/winbindofflinelogon.xml b/docs-xml/smbdotconf/winbind/winbindofflinelogon.xml
index 1a5b522..9cf1249 100644
--- a/docs-xml/smbdotconf/winbind/winbindofflinelogon.xml
+++ b/docs-xml/smbdotconf/winbind/winbindofflinelogon.xml
@@ -1,11 +1,11 @@
 <samba:parameter name="winbind offline logon"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
 	<para>This parameter is designed to control whether Winbind should
-	allow to login with the <parameter moreinfo="none">pam_winbind</parameter> 
+	allow one to login with the <parameter moreinfo="none">pam_winbind</parameter> 
 	module using Cached Credentials. If enabled, winbindd will store user credentials
 	from successful logins encrypted in a local cache.
 	</para>
diff --git a/docs-xml/smbdotconf/winbind/winbindreconnectdelay.xml b/docs-xml/smbdotconf/winbind/winbindreconnectdelay.xml
index 11d105c..f26fd5e 100644
--- a/docs-xml/smbdotconf/winbind/winbindreconnectdelay.xml
+++ b/docs-xml/smbdotconf/winbind/winbindreconnectdelay.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind reconnect delay"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the number of
diff --git a/docs-xml/smbdotconf/winbind/winbindrefreshtickets.xml b/docs-xml/smbdotconf/winbind/winbindrefreshtickets.xml
index 00c65df..f6bb738 100644
--- a/docs-xml/smbdotconf/winbind/winbindrefreshtickets.xml
+++ b/docs-xml/smbdotconf/winbind/winbindrefreshtickets.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind refresh tickets"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/docs-xml/smbdotconf/winbind/winbindrequesttimeout.xml b/docs-xml/smbdotconf/winbind/winbindrequesttimeout.xml
index d6c9e08..8c7ec56 100644
--- a/docs-xml/smbdotconf/winbind/winbindrequesttimeout.xml
+++ b/docs-xml/smbdotconf/winbind/winbindrequesttimeout.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind request timeout"
                  context="G"
-				 type="integer"
+                 type="integer"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies the number of
diff --git a/docs-xml/smbdotconf/winbind/winbindrpconly.xml b/docs-xml/smbdotconf/winbind/winbindrpconly.xml
index 3019e71..50795ac 100644
--- a/docs-xml/smbdotconf/winbind/winbindrpconly.xml
+++ b/docs-xml/smbdotconf/winbind/winbindrpconly.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind rpc only"
-	context="G"
-	type="boolean"
+                 context="G"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/docs-xml/smbdotconf/winbind/winbindseparator.xml b/docs-xml/smbdotconf/winbind/winbindseparator.xml
index 8c4a11a..1c1632f 100644
--- a/docs-xml/smbdotconf/winbind/winbindseparator.xml
+++ b/docs-xml/smbdotconf/winbind/winbindseparator.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind separator"
                  context="G"
-				 type="string"
+                 type="string"
                  constant="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/winbind/winbindtrusteddomainsonly.xml b/docs-xml/smbdotconf/winbind/winbindtrusteddomainsonly.xml
index 629832c..3d420c7 100644
--- a/docs-xml/smbdotconf/winbind/winbindtrusteddomainsonly.xml
+++ b/docs-xml/smbdotconf/winbind/winbindtrusteddomainsonly.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind trusted domains only"
                  context="G"
-		 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>
diff --git a/docs-xml/smbdotconf/winbind/winbindusedefaultdomain.xml b/docs-xml/smbdotconf/winbind/winbindusedefaultdomain.xml
index 8278aa5..186398e 100644
--- a/docs-xml/smbdotconf/winbind/winbindusedefaultdomain.xml
+++ b/docs-xml/smbdotconf/winbind/winbindusedefaultdomain.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="winbind use default domain"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>This parameter specifies whether the
diff --git a/docs-xml/smbdotconf/wins/dnsproxy.xml b/docs-xml/smbdotconf/wins/dnsproxy.xml
index 6b3c198..75d4446 100644
--- a/docs-xml/smbdotconf/wins/dnsproxy.xml
+++ b/docs-xml/smbdotconf/wins/dnsproxy.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="dns proxy"
                  context="G"
-				 type="boolean"
+                 type="boolean"
                  function="wins_dns_proxy"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/smbdotconf/wins/winsserver.xml b/docs-xml/smbdotconf/wins/winsserver.xml
index 69146fb..d323b38 100644
--- a/docs-xml/smbdotconf/wins/winsserver.xml
+++ b/docs-xml/smbdotconf/wins/winsserver.xml
@@ -1,6 +1,6 @@
 <samba:parameter name="wins server"
                  context="G"
-				 type="list"
+                 type="cmdlist"
                  function="wins_server_list"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
diff --git a/docs-xml/using_samba/ch02.xml b/docs-xml/using_samba/ch02.xml
index e632a42..e6bb595 100644
--- a/docs-xml/using_samba/ch02.xml
+++ b/docs-xml/using_samba/ch02.xml
@@ -136,7 +136,7 @@ newer.
 <indexterm id="ch02-idx-947333-0"><primary>makefiles</primary></indexterm> that accompanies the binary distribution should list any special requirements.<footnote label="2" id="ch02-pgfId-943622">
 
 
-<para>This is especially true with programs that use <emphasis>glibc-2.1</emphasis> (which comes standard with Red Hat Linux 6). This library caused quite a consternation in the development community when it was released because it was incompatable with previous versions of <emphasis>g</emphasis><filename>libc</filename>.</para>
+<para>This is especially true with programs that use <emphasis>glibc-2.1</emphasis> (which comes standard with Red Hat Linux 6). This library caused quite a consternation in the development community when it was released because it was incompatible with previous versions of <emphasis>g</emphasis><filename>libc</filename>.</para>
 
 
 </footnote></para>
diff --git a/docs-xml/using_samba/ch05.xml b/docs-xml/using_samba/ch05.xml
index 0fbc4c7..c86f7b4 100644
--- a/docs-xml/using_samba/ch05.xml
+++ b/docs-xml/using_samba/ch05.xml
@@ -1007,7 +1007,7 @@ domain master</title>
 <indexterm id="ch05-idx-969711-0"><primary>files</primary><secondary>deleting, option for</secondary></indexterm> <literal>veto</literal> <literal>files</literal> option comes in. If this boolean option is set to <literal>yes</literal>, the user is allowed to delete both the regular files and the vetoed files in the directory, and the directory itself will be removed. If the option is set to <literal>no</literal>, the user will not be able to delete the vetoed files, and consequently the [...]
 
 
-<para>The <literal>dont</literal> <literal>descend</literal> directive specifies a list of <indexterm id="ch05-idx-969715-0"><primary>directories</primary><secondary>barring users from viewing contents</secondary></indexterm>directories whose contents Samba should not allow to be visible. Note that we say <emphasis>contents</emphasis>, not the directory itself. Users will be able to enter a directory marked as such, but they are prohibited from descending the directory tree any farther&m [...]
+<para>The <literal>dont</literal> <literal>descend</literal> directive specifies a list of <indexterm id="ch05-idx-969715-0"><primary>directories</primary><secondary>barring users from viewing contents</secondary></indexterm>directories whose contents Samba should not allow one to be visible. Note that we say <emphasis>contents</emphasis>, not the directory itself. Users will be able to enter a directory marked as such, but they are prohibited from descending the directory tree any farth [...]
 
 
 <programlisting>[data]
diff --git a/docs-xml/wscript_build b/docs-xml/wscript_build
index 8cdd2dd..11b826b 100644
--- a/docs-xml/wscript_build
+++ b/docs-xml/wscript_build
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 from samba_utils import save_file
 manpages='''
+         manpages/cifsdd.8
          manpages/dbwrap_tool.1
          manpages/eventlogadm.8
          manpages/findsmb.1
@@ -40,7 +41,6 @@ manpages='''
          manpages/smbspool.8
          manpages/smbspool_krb5_wrapper.8
          manpages/smbstatus.1
-         manpages/smbta-util.8
          manpages/smbtar.1
          manpages/smbtree.1
          manpages/testparm.1
@@ -69,16 +69,15 @@ manpages='''
          manpages/vfs_linux_xfs_sgid.8
          manpages/vfs_media_harmony.8
          manpages/vfs_netatalk.8
+         manpages/vfs_offline.8
          manpages/vfs_prealloc.8
          manpages/vfs_preopen.8
          manpages/vfs_readahead.8
          manpages/vfs_readonly.8
          manpages/vfs_recycle.8
-         manpages/vfs_scannedonly.8
          manpages/vfs_shadow_copy.8
          manpages/vfs_shadow_copy2.8
 	 manpages/vfs_shell_snap.8
-         manpages/vfs_smb_traffic_analyzer.8
 	 manpages/vfs_snapper.8
          manpages/vfs_streams_depot.8
          manpages/vfs_streams_xattr.8
@@ -113,15 +112,13 @@ def smbdotconf_generate_parameter_list(task):
     t += "]>\n"
     t += "<section>\n"
     for article in articles:
-        f = open(article.abspath(task.env), 'r')
-        t += f.read()
-        f.close()
+        t += article.read()
 
     t += "</section>\n"
     save_file(parameter_all, t , create_dir=True)
     return 0
 
-articles = bld.path.ant_glob("smbdotconf/**/*.xml")
+articles = bld.path.ant_glob("smbdotconf/**/*.xml", flat=True)
 parameter_all = 'smbdotconf/parameters.all.xml'
 bld.SAMBA_GENERATOR(parameter_all,
                     source=articles,
diff --git a/docs/manpages/cifsdd.8 b/docs/manpages/cifsdd.8
new file mode 100644
index 0000000..c73ff28
--- /dev/null
+++ b/docs/manpages/cifsdd.8
@@ -0,0 +1,104 @@
+'\" t
+.\"     Title: cifsdd
+.\"    Author: [see the "AUTHOR" section]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 03/22/2016
+.\"    Manual: System Administration tools
+.\"    Source: Samba 4.4
+.\"  Language: English
+.\"
+.TH "CIFSDD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+cifsdd \- convert and copy a file over SMB
+.SH "SYNOPSIS"
+.HP \w'\ 'u
+cifsdd [OPERAND]\&.\&.\&.
+	
+.HP \w'\ 'u
+cifsdd OPTION
+.SH "DESCRIPTION"
+.PP
+This tool is part of the
+\fBsamba\fR(7)
+suite\&.
+.PP
+Copy a file, converting and formatting according to the operands\&.
+.PP
+bs=BYTES
+.RS 4
+read and write up to BYTES bytes at a time (default: 4096)
+.RE
+.PP
+ibs=BYTES
+.RS 4
+read up to BYTES bytes at a time (default: 4096)
+.RE
+.PP
+obs=BYTES
+.RS 4
+write BYTES bytes at a time (default: 4096)
+.RE
+.PP
+if=FILE
+.RS 4
+read from FILE instead of stdin
+.RE
+.PP
+of=FILE
+.RS 4
+write to FILE instead of stdout
+.RE
+.PP
+count=N
+.RS 4
+copy only N input blocks
+.RE
+.PP
+seek=N
+.RS 4
+skip N obs\-sized blocks at start of output
+.RE
+.PP
+skip=N
+.RS 4
+skip N ibs\-sized blocks at start of input
+.RE
+.PP
+direct
+.RS 4
+use direct I/O for data
+.RE
+.PP
+sync
+.RS 4
+use synchronous writes
+.RE
+.PP
+oplock
+.RS 4
+take oplocks on the input and output files
+.RE
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
+.PP
+The cifsdd manpage was written by Andreas Schneider\&.
diff --git a/docs/manpages/dbwrap_tool.1 b/docs/manpages/dbwrap_tool.1
index 38a088c..1322c44 100644
--- a/docs/manpages/dbwrap_tool.1
+++ b/docs/manpages/dbwrap_tool.1
@@ -2,12 +2,12 @@
 .\"     Title: dbwrap_tool
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "DBWRAP_TOOL" "1" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "DBWRAP_TOOL" "1" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/eventlogadm.8 b/docs/manpages/eventlogadm.8
index 1fdf559..98948e2 100644
--- a/docs/manpages/eventlogadm.8
+++ b/docs/manpages/eventlogadm.8
@@ -2,12 +2,12 @@
 .\"     Title: eventlogadm
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "EVENTLOGADM" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "EVENTLOGADM" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/findsmb.1 b/docs/manpages/findsmb.1
index c0c1ea3..1503981 100644
--- a/docs/manpages/findsmb.1
+++ b/docs/manpages/findsmb.1
@@ -2,12 +2,12 @@
 .\"     Title: findsmb
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "FINDSMB" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "FINDSMB" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_ad.8 b/docs/manpages/idmap_ad.8
index c33d927..65dab87 100644
--- a/docs/manpages/idmap_ad.8
+++ b/docs/manpages/idmap_ad.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_ad
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_AD" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_AD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_autorid.8 b/docs/manpages/idmap_autorid.8
index e06e626..53407e1 100644
--- a/docs/manpages/idmap_autorid.8
+++ b/docs/manpages/idmap_autorid.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_autorid
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_AUTORID" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_AUTORID" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -40,6 +40,11 @@ The mappings of which domain is mapped to which range is stored in autorid\&.tdb
 Due to the algorithm being used, it is the module that is most easy to use as it only requires a minimal configuration\&.
 .SH "IDMAP OPTIONS"
 .PP
+range = low \- high
+.RS 4
+Defines the available matching uid and gid range for which the backend is authoritative\&. Note that the range acts as a filter\&. If algorithmically determined UID or GID fall outside the range, they are ignored and the corresponding map is discarded\&. It is intended as a way to avoid accidental UID/GID overlaps between local and remotely defined IDs\&.
+.RE
+.PP
 rangesize = numberofidsperdomain
 .RS 4
 Defines the number of uids/gids available per domain range\&. The minimum needed value is 2000\&. SIDs with RIDs larger than this value will be mapped into extension ranges depending upon number of available ranges\&. If the autorid backend runs out of available ranges, mapping requests for new domains (or new extension ranges for domains already known) are ignored and the corresponding map is discarded\&.
diff --git a/docs/manpages/idmap_hash.8 b/docs/manpages/idmap_hash.8
index 6b2c3b2..5ab8594 100644
--- a/docs/manpages/idmap_hash.8
+++ b/docs/manpages/idmap_hash.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_hash
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_HASH" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_HASH" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_ldap.8 b/docs/manpages/idmap_ldap.8
index 8383973..18f176f 100644
--- a/docs/manpages/idmap_ldap.8
+++ b/docs/manpages/idmap_ldap.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_ldap
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_LDAP" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_LDAP" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_nss.8 b/docs/manpages/idmap_nss.8
index 5ebfafe..805133d 100644
--- a/docs/manpages/idmap_nss.8
+++ b/docs/manpages/idmap_nss.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_nss
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_NSS" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_NSS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_rfc2307.8 b/docs/manpages/idmap_rfc2307.8
index 0f7532c..7e194bf 100644
--- a/docs/manpages/idmap_rfc2307.8
+++ b/docs/manpages/idmap_rfc2307.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_rfc2307
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_RFC2307" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_RFC2307" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -69,14 +69,14 @@ user_cn = <yes | no>
 Query cn attribute instead of uid attribute for the user name in LDAP\&. This option is not required, the default is no\&.
 .RE
 .PP
-cn_realm = <yes | no>
+realm
 .RS 4
-Append @realm to cn for groups (and users if user_cn is set) in LDAP\&. This option is not required, the default is no\&.
+Append @realm to cn for groups (and users if user_cn is set) in LDAP queries\&. This option is not required, the default is not to append the realm\&.
 .RE
 .PP
 ldap_domain
 .RS 4
-When using the LDAP server in the Active Directory server, this allows to specify the domain where to access the Active Directory server\&. This allows using trust relationships while keeping all RFC 2307 records in one place\&. This parameter is optional, the default is to access the AD server in the current domain to query LDAP records\&.
+When using the LDAP server in the Active Directory server, this allows one to specify the domain where to access the Active Directory server\&. This allows using trust relationships while keeping all RFC 2307 records in one place\&. This parameter is optional, the default is to access the AD server in the current domain to query LDAP records\&.
 .RE
 .PP
 ldap_url
@@ -89,11 +89,6 @@ ldap_user_dn
 Defines the user DN to be used for authentication\&. The secret for authenticating this user should be stored with net idmap secret (see
 \fBnet\fR(8))\&. If absent, an anonymous bind will be performed\&.
 .RE
-.PP
-ldap_realm
-.RS 4
-Defines the realm to use in the user and group names\&. This is only required when using cn_realm together with a stand\-alone ldap server\&.
-.RE
 .SH "EXAMPLES"
 .PP
 The following example shows how to retrieve id mappings from a stand\-alone LDAP server\&. This example also shows how to leave a small non conflicting range for local id allocation that may be used in internal backends like BUILTIN\&.
diff --git a/docs/manpages/idmap_rid.8 b/docs/manpages/idmap_rid.8
index 8a87aff..3768b1d 100644
--- a/docs/manpages/idmap_rid.8
+++ b/docs/manpages/idmap_rid.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_rid
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_RID" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_RID" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_script.8 b/docs/manpages/idmap_script.8
index 85deee2..7d8f152 100644
--- a/docs/manpages/idmap_script.8
+++ b/docs/manpages/idmap_script.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_script
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_SCRIPT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_SCRIPT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_tdb.8 b/docs/manpages/idmap_tdb.8
index dd060f7..bb84117 100644
--- a/docs/manpages/idmap_tdb.8
+++ b/docs/manpages/idmap_tdb.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_tdb
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_TDB" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_TDB" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_tdb2.8 b/docs/manpages/idmap_tdb2.8
index e38f223..11db10c 100644
--- a/docs/manpages/idmap_tdb2.8
+++ b/docs/manpages/idmap_tdb2.8
@@ -2,12 +2,12 @@
 .\"     Title: idmap_tdb2
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "IDMAP_TDB2" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "IDMAP_TDB2" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/libsmbclient.7 b/docs/manpages/libsmbclient.7
index e4b20e3..fc07386 100644
--- a/docs/manpages/libsmbclient.7
+++ b/docs/manpages/libsmbclient.7
@@ -2,12 +2,12 @@
 .\"     Title: libsmbclient
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: 7
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "LIBSMBCLIENT" "7" "02/24/2016" "Samba 4\&.3" "7"
+.TH "LIBSMBCLIENT" "7" "03/22/2016" "Samba 4\&.4" "7"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/lmhosts.5 b/docs/manpages/lmhosts.5
index a8ff381..baf2c5e 100644
--- a/docs/manpages/lmhosts.5
+++ b/docs/manpages/lmhosts.5
@@ -2,12 +2,12 @@
 .\"     Title: lmhosts
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: File Formats and Conventions
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "LMHOSTS" "5" "02/24/2016" "Samba 4\&.3" "File Formats and Conventions"
+.TH "LMHOSTS" "5" "03/22/2016" "Samba 4\&.4" "File Formats and Conventions"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/log2pcap.1 b/docs/manpages/log2pcap.1
index b489e7d..eef069b 100644
--- a/docs/manpages/log2pcap.1
+++ b/docs/manpages/log2pcap.1
@@ -2,12 +2,12 @@
 .\"     Title: log2pcap
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "LOG2PCAP" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "LOG2PCAP" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/net.8 b/docs/manpages/net.8
index b0978a9..2ee68ed 100644
--- a/docs/manpages/net.8
+++ b/docs/manpages/net.8
@@ -2,12 +2,12 @@
 .\"     Title: net
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "NET" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "NET" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -185,12 +185,12 @@ When calling "net rpc vampire keytab" this option enforces a full re\-creation o
 .PP
 \-\-single\-obj\-repl
 .RS 4
-When calling "net rpc vampire keytab" this option allows to replicate just a single object to the generated keytab file\&.
+When calling "net rpc vampire keytab" this option allows one to replicate just a single object to the generated keytab file\&.
 .RE
 .PP
 \-\-clean\-old\-entries
 .RS 4
-When calling "net rpc vampire keytab" this option allows to cleanup old entries from the generated keytab file\&.
+When calling "net rpc vampire keytab" this option allows one to cleanup old entries from the generated keytab file\&.
 .RE
 .PP
 \-\-db
@@ -230,7 +230,7 @@ Includes timestamps to be copied in "net rpc share migrate"\&.
 .PP
 \-X|\-\-exclude DIRECTORY
 .RS 4
-Allows to exclude directories when copying with "net rpc share migrate"\&.
+Allows one to exclude directories when copying with "net rpc share migrate"\&.
 .RE
 .PP
 \-\-destination SERVERNAME
@@ -278,6 +278,11 @@ Create a new database from scratch (used in "net registry check")\&.
 Defines filename for database prechecking (used in "net registry import")\&.
 .RE
 .PP
+\-\-no\-dns\-updates
+.RS 4
+Do not perform DNS updates as part of "net ads join"\&.
+.RE
+.PP
 \-e|\-\-encrypt
 .RS 4
 This command line parameter requires the remote server support the UNIX extensions or that the SMB3 protocol has been selected\&. Requests that the connection be encrypted\&. Negotiates SMB encryption using either SMB3 or POSIX extensions via GSSAPI\&. Uses the given credentials for the encryption negotiation (either kerberos or NTLMv1/v2 if given domain/username/password triple\&. Fails the connection if encryption cannot be negotiated\&.
@@ -349,7 +354,7 @@ Tries to set the date and time of the local server to that on the remote server
 .SS "TIME ZONE"
 .PP
 Displays the timezone in hours from GMT on the remote server\&. The remote server must be specified with the \-S option\&.
-.SS "[RPC|ADS] JOIN [TYPE] [\-U username[%password]] [createupn=UPN] [createcomputer=OU] [machinepass=PASS] [osName=string osVer=string] [options]"
+.SS "[RPC|ADS] JOIN [TYPE] [\-\-no\-dns\-updates] [\-U username[%password]] [createupn=UPN] [createcomputer=OU] [machinepass=PASS] [osName=string osVer=string] [options]"
 .PP
 Join a domain\&. If the account already exists on the server, and [TYPE] is MEMBER, the machine will attempt to join automatically\&. (Assuming that the machine has been created in server manager) Otherwise, a password will be prompted for, and a new account may be created\&.
 .PP
@@ -979,7 +984,7 @@ Print out workgroup name for specified kerberos realm\&.
 .PP
 List, modify or delete the value of the "msDS\-SupportedEncryptionTypes" attribute of an account in AD\&.
 .PP
-This attribute allows to control which Kerberos encryption types are used for the generation of initial and service tickets\&. The value consists of an integer bitmask with the following values:
+This attribute allows one to control which Kerberos encryption types are used for the generation of initial and service tickets\&. The value consists of an integer bitmask with the following values:
 .PP
 0x00000001 DES\-CBC\-CRC
 .PP
@@ -998,7 +1003,7 @@ Example:
 \fBnet ads enctypes list Computername\fR
 .SS "ADS ENCTYPES SET \fI<ACCOUNTNAME>\fR \fI[enctypes]\fR"
 .PP
-Set the value of the "msDS\-SupportedEncryptionTypes" attribute of the LDAP object of ACCOUNTNAME to a given value\&. If the value is ommitted, the value is set to 31 which enables all the currently supported encryption types\&.
+Set the value of the "msDS\-SupportedEncryptionTypes" attribute of the LDAP object of ACCOUNTNAME to a given value\&. If the value is omitted, the value is set to 31 which enables all the currently supported encryption types\&.
 .PP
 Example:
 \fBnet ads enctypes set Computername 24\fR
diff --git a/docs/manpages/nmbd.8 b/docs/manpages/nmbd.8
index bcf774a..6543ee9 100644
--- a/docs/manpages/nmbd.8
+++ b/docs/manpages/nmbd.8
@@ -2,12 +2,12 @@
 .\"     Title: nmbd
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "NMBD" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "NMBD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/nmblookup.1 b/docs/manpages/nmblookup.1
index 6b2677d..12e1d4f 100644
--- a/docs/manpages/nmblookup.1
+++ b/docs/manpages/nmblookup.1
@@ -2,12 +2,12 @@
 .\"     Title: nmblookup
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "NMBLOOKUP" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "NMBLOOKUP" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/ntlm_auth.1 b/docs/manpages/ntlm_auth.1
index 1d0fed8..6d996e0 100644
--- a/docs/manpages/ntlm_auth.1
+++ b/docs/manpages/ntlm_auth.1
@@ -2,12 +2,12 @@
 .\"     Title: ntlm_auth
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "NTLM_AUTH" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "NTLM_AUTH" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -332,6 +332,11 @@ Define the target service\&.
 Whether to use credentials cached by winbindd\&.
 .RE
 .PP
+\-\-offline\-logon
+.RS 4
+Allow offline logons for plain text auth\&.
+.RE
+.PP
 \-\-configfile=<configuration file>
 .RS 4
 The file specified contains the configuration details required by the server\&. The information in this file includes server\-specific information such as what printcap file to use, as well as descriptions of all the services that the server is to provide\&. See
diff --git a/docs/manpages/pam_winbind.8 b/docs/manpages/pam_winbind.8
index dbfca2b..2da1b1f 100644
--- a/docs/manpages/pam_winbind.8
+++ b/docs/manpages/pam_winbind.8
@@ -2,12 +2,12 @@
 .\"     Title: pam_winbind
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: 8
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "PAM_WINBIND" "8" "02/24/2016" "Samba 4\&.3" "8"
+.TH "PAM_WINBIND" "8" "03/22/2016" "Samba 4\&.4" "8"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -122,7 +122,7 @@ option, it can store the retrieved Ticket Granting Ticket (TGT) in a credential
 .PP
 cached_login
 .RS 4
-Winbind allows to logon using cached credentials when
+Winbind allows one to logon using cached credentials when
 \fIwinbind offline logon\fR
 is enabled\&. To use this feature from the PAM module this option must be set\&.
 .RE
diff --git a/docs/manpages/pam_winbind.conf.5 b/docs/manpages/pam_winbind.conf.5
index 9e3d7c8..68b1fe0 100644
--- a/docs/manpages/pam_winbind.conf.5
+++ b/docs/manpages/pam_winbind.conf.5
@@ -2,12 +2,12 @@
 .\"     Title: pam_winbind.conf
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: 5
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "PAM_WINBIND\&.CONF" "5" "02/24/2016" "Samba 4\&.3" "5"
+.TH "PAM_WINBIND\&.CONF" "5" "03/22/2016" "Samba 4\&.4" "5"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -110,7 +110,7 @@ Leave empty to just do kerberos authentication without having a ticket cache aft
 .PP
 cached_login = yes|no
 .RS 4
-Winbind allows to logon using cached credentials when
+Winbind allows one to logon using cached credentials when
 \fIwinbind offline logon\fR
 is enabled\&. To use this feature from the PAM module this option must be set\&. Defaults to "no"\&.
 .RE
diff --git a/docs/manpages/pdbedit.8 b/docs/manpages/pdbedit.8
index 12245f1..edecd5b 100644
--- a/docs/manpages/pdbedit.8
+++ b/docs/manpages/pdbedit.8
@@ -2,12 +2,12 @@
 .\"     Title: pdbedit
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "PDBEDIT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "PDBEDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -31,7 +31,7 @@
 pdbedit \- manage the SAM database (Database of Samba Users)
 .SH "SYNOPSIS"
 .HP \w'\ 'u
-pdbedit [\-a] [\-b\ passdb\-backend] [\-c\ account\-control] [\-C\ value] [\-d\ debuglevel] [\-D\ drive] [\-e\ passdb\-backend] [\-f\ fullname] [\-\-force\-initialized\-passwords] [\-g] [\-h\ homedir] [\-i\ passdb\-backend] [\-I\ domain] [\-K] [\-L] [\-m] [\-M\ SID|RID] [\-N\ description] [\-P\ account\-policy] [\-p\ profile] [\-\-policies\-reset] [\-r] [\-s\ configfile] [\-S\ script] [\-t] [\-\-time\-format] [\-u\ username] [\-U\ SID|RID] [\-v] [\-V] [\-w] [\-x] [\-y] [\-z] [\-Z]
+pdbedit [\-a] [\-b\ passdb\-backend] [\-c\ account\-control] [\-C\ value] [\-d\ debuglevel] [\-D\ drive] [\-e\ passdb\-backend] [\-f\ fullname] [\-\-force\-initialized\-passwords] [\-g] [\-h\ homedir] [\-i\ passdb\-backend] [\-I\ domain] [\-K] [\-L] [\-m] [\-M\ SID|RID] [\-N\ description] [\-P\ account\-policy] [\-p\ profile] [\-\-policies\-reset] [\-r] [\-s\ configfile] [\-S\ script] [\-\-set\-nt\-hash] [\-t] [\-\-time\-format] [\-u\ username] [\-U\ SID|RID] [\-v] [\-V] [\-w] [\-x] [\-y [...]
 .SH "DESCRIPTION"
 .PP
 This tool is part of the
@@ -66,7 +66,7 @@ samba:45:Test User
 .PP
 \-v|\-\-verbose
 .RS 4
-This option enables the verbose listing format\&. It causes pdbedit to list the users in the database, printing out the account fields in a descriptive format\&.
+This option enables the verbose listing format\&. It causes pdbedit to list the users in the database, printing out the account fields in a descriptive format\&. Used together with \-w also shows passwords hashes\&.
 .sp
 Example:
 pdbedit \-L \-v
@@ -105,7 +105,7 @@ This option sets the "smbpasswd" listing format\&. It will make pdbedit list the
 smbpasswd
 file format\&. (see the
 \fBsmbpasswd\fR(5)
-for details)
+for details)\&. Instead used together with (\-v) displays the passwords hashes in verbose output\&.
 .sp
 Example:
 pdbedit \-L \-w
@@ -167,6 +167,14 @@ Example:
 \-S "\e\e\e\eBERSERKER\e\enetlogon\e\esorce\&.bat"
 .RE
 .PP
+\-\-set\-nt\-hash
+.RS 4
+This option can be used while modifying a user account\&. It will set the user\*(Aqs password using the nt\-hash value given as hexadecimal string\&. Useful to synchronize passwords\&.
+.sp
+Example:
+\-\-set\-nt\-hash 8846F7EAEE8FB117AD06BDD830B7586C
+.RE
+.PP
 \-p|\-\-profile profile
 .RS 4
 This option can be used while adding or modifying a user account\&. It will specify the user\*(Aqs profile directory\&.
@@ -497,7 +505,7 @@ If you specify
 \fI\-i in\-backend \-e out\-backend\fR
 applies to the account policies instead of the user database\&.
 .sp
-This option will allow to migrate account policies from their default tdb\-store into a passdb backend, e\&.g\&. an LDAP directory server\&.
+This option will allow one to migrate account policies from their default tdb\-store into a passdb backend, e\&.g\&. an LDAP directory server\&.
 .sp
 Example:
 pdbedit \-y \-i tdbsam: \-e ldapsam:ldap://my\&.ldap\&.host
diff --git a/docs/manpages/profiles.1 b/docs/manpages/profiles.1
index 33296d1..9216459 100644
--- a/docs/manpages/profiles.1
+++ b/docs/manpages/profiles.1
@@ -2,12 +2,12 @@
 .\"     Title: profiles
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "PROFILES" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "PROFILES" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/rpcclient.1 b/docs/manpages/rpcclient.1
index 9e721db..c7394eb 100644
--- a/docs/manpages/rpcclient.1
+++ b/docs/manpages/rpcclient.1
@@ -2,12 +2,12 @@
 .\"     Title: rpcclient
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "RPCCLIENT" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "RPCCLIENT" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/samba-regedit.8 b/docs/manpages/samba-regedit.8
index 3b282b1..b734dd9 100644
--- a/docs/manpages/samba-regedit.8
+++ b/docs/manpages/samba-regedit.8
@@ -2,12 +2,12 @@
 .\"     Title: samba-regedit
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SAMBA\-REGEDIT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "SAMBA\-REGEDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/samba-tool.8 b/docs/manpages/samba-tool.8
index c55158d..31aa073 100644
--- a/docs/manpages/samba-tool.8
+++ b/docs/manpages/samba-tool.8
@@ -2,12 +2,12 @@
 .\"     Title: samba-tool
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SAMBA\-TOOL" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "SAMBA\-TOOL" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/samba.7 b/docs/manpages/samba.7
index 3628bfd..d47ce9e 100644
--- a/docs/manpages/samba.7
+++ b/docs/manpages/samba.7
@@ -2,12 +2,12 @@
 .\"     Title: samba
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: Miscellanea
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SAMBA" "7" "02/24/2016" "Samba 4\&.3" "Miscellanea"
+.TH "SAMBA" "7" "03/22/2016" "Samba 4\&.4" "Miscellanea"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/samba.8 b/docs/manpages/samba.8
index 0bd4e30..d4cf53e 100644
--- a/docs/manpages/samba.8
+++ b/docs/manpages/samba.8
@@ -2,12 +2,12 @@
 .\"     Title: samba
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SAMBA" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "SAMBA" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/sharesec.1 b/docs/manpages/sharesec.1
index e654488..5e86ba3 100644
--- a/docs/manpages/sharesec.1
+++ b/docs/manpages/sharesec.1
@@ -2,12 +2,12 @@
 .\"     Title: sharesec
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SHARESEC" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "SHARESEC" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smb.conf.5 b/docs/manpages/smb.conf.5
index 796aa3a..1705bfe 100644
--- a/docs/manpages/smb.conf.5
+++ b/docs/manpages/smb.conf.5
@@ -2,12 +2,12 @@
 .\"     Title: smb.conf
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: File Formats and Conventions
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMB\&.CONF" "5" "02/24/2016" "Samba 4\&.3" "File Formats and Conventions"
+.TH "SMB\&.CONF" "5" "03/22/2016" "Samba 4\&.4" "File Formats and Conventions"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -1184,6 +1184,22 @@ Example:
 \fI\fIafs username map\fR\fR\fI = \fR\fI%u at afs\&.samba\&.org\fR\fI \fR
 .RE
 
+aio max threads (G)
+.\" aio max threads
+.PP
+.RS 4
+The integer parameter specifies the maximum number of threads each smbd process will create when doing parallel asynchronous IO calls\&. If the number of outstanding calls is greater than this number the requests will not be refused but go onto a queue and will be scheduled in turn as outstanding requests complete\&.
+.sp
+Related command:
+\m[blue]\fBaio read size\fR\m[]
+.sp
+Related command:
+\m[blue]\fBaio write size\fR\m[]
+.sp
+Default:
+\fI\fIaio max threads\fR\fR\fI = \fR\fI100\fR\fI \fR
+.RE
+
 aio read size (S)
 .\" aio read size
 .PP
@@ -1396,6 +1412,31 @@ Example:
 \fI\fIauth methods\fR\fR\fI = \fR\fIguest sam winbind\fR\fI \fR
 .RE
 
+preload
+.\" preload
+.PP
+.RS 4
+This parameter is a synonym for
+auto services\&.
+.RE
+
+auto services (G)
+.\" auto services
+.PP
+.RS 4
+This is a list of services that you want to be automatically added to the browse lists\&. This is most useful for homes and printers services that would otherwise not be visible\&.
+.sp
+Note that if you just want all printers in your printcap file loaded then the
+\m[blue]\fBload printers\fR\m[]
+option is easier\&.
+.sp
+Default:
+\fI\fIauto services\fR\fR\fI = \fR\fI\fR\fI \fR
+.sp
+Example:
+\fI\fIauto services\fR\fR\fI = \fR\fIfred lp colorlp\fR\fI \fR
+.RE
+
 available (S)
 .\" available
 .PP
@@ -2525,26 +2566,6 @@ Default:
 \fI\fIdebug prefix timestamp\fR\fR\fI = \fR\fIno\fR\fI \fR
 .RE
 
-timestamp logs
-.\" timestamp logs
-.PP
-.RS 4
-This parameter is a synonym for
-debug timestamp\&.
-.RE
-
-debug timestamp (G)
-.\" debug timestamp
-.PP
-.RS 4
-Samba debug log messages are timestamped by default\&. If you are running at a high
-\m[blue]\fBdebug level\fR\m[]
-these timestamps can be distracting\&. This boolean parameter allows timestamping to be turned off\&.
-.sp
-Default:
-\fI\fIdebug timestamp\fR\fR\fI = \fR\fIyes\fR\fI \fR
-.RE
-
 debug uid (G)
 .\" debug uid
 .PP
@@ -3188,7 +3209,7 @@ dos filetimes (S)
 .\" dos filetimes
 .PP
 .RS 4
-Under DOS and Windows, if a user can write to a file they can change the timestamp on it\&. Under POSIX semantics, only the owner of the file or root may change the timestamp\&. By default, Samba emulates the DOS semantics and allows to change the timestamp on a file if the user
+Under DOS and Windows, if a user can write to a file they can change the timestamp on it\&. Under POSIX semantics, only the owner of the file or root may change the timestamp\&. By default, Samba emulates the DOS semantics and allows one to change the timestamp on a file if the user
 smbd
 is acting on behalf has write permissions\&. Due to changes in Microsoft Office 2000 and beyond, the default for this parameter has been changed from "no" to "yes" in Samba 3\&.0\&.14 and above\&. Microsoft Excel will display dialog box warnings about the file being changed by another user if this parameter is not set to "yes" and files are being shared between users\&.
 .sp
@@ -4165,8 +4186,8 @@ Default:
 \fI\fIidmap cache time\fR\fR\fI = \fR\fI604800\fR\fI \fR
 .RE
 
-idmap config:OPTION (G)
-.\" idmap config:OPTION
+idmap config DOMAIN : OPTION (G)
+.\" idmap config DOMAIN : OPTION
 .PP
 .RS 4
 ID mapping in Samba is the mapping between Windows SIDs and Unix user and group IDs\&. This is performed by Winbindd with a configurable plugin interface\&. Samba\*(Aqs ID mapping is configured by options starting with the
@@ -4284,7 +4305,7 @@ Example:
 \fI\fIidmap uid\fR\fR\fI = \fR\fI10000\-20000\fR\fI \fR
 .RE
 
-include (G)
+include (S)
 .\" include
 .PP
 .RS 4
@@ -4451,6 +4472,12 @@ The "IP" parameters above can either be a full dotted decimal IP address or a ho
 .sp
 By default Samba enables all active interfaces that are broadcast capable except the loopback adaptor (IP address 127\&.0\&.0\&.1)\&.
 .sp
+In order to support SMB3 multi\-channel configurations, smbd understands some extra data that can be appended after the actual interface with this extended syntax:
+.sp
+interface[;key1=value1[,key2=value2[\&.\&.\&.]]]
+.sp
+Known keys are speed, capability, and if_index\&. Speed is specified in bits per second\&. Known capabilities are RSS and RDMA\&. The if_index should be used with care: the values must not coincide with indexes used by the kernel\&. Note that these options are mainly intended for testing and development rather than for production use\&. At least on Linux systems, these values should be auto\-detected, but the settings can serve as last a resort when autodetection is not working or is not [...]
+.sp
 The example below configures three network interfaces corresponding to the eth0 device and IP addresses 192\&.168\&.2\&.10 and 192\&.168\&.3\&.10\&. The netmasks of the latter two interfaces would be set to 255\&.255\&.255\&.0\&.
 .sp
 Default:
@@ -4676,7 +4703,7 @@ The LANMAN encrypted response is easily broken, due to its case\-insensitive nat
 .sp
 When this parameter is set to
 no
-this will also result in sambaLMPassword in Samba\*(Aqs passdb being blanked after the next password change\&. As a result of that lanman clients won\*(Aqt be able to authenticate, even if lanman auth is reenabled later on\&.
+this will also result in sambaLMPassword in Samba\*(Aqs passdb being blanked after the next password change\&. As a result of that lanman clients won\*(Aqt be able to authenticate, even if lanman auth is re\-enabled later on\&.
 .sp
 Unlike the
 encrypt passwords
@@ -4884,7 +4911,7 @@ This parameter specifies the number of entries per page\&.
 If the LDAP server supports paged results, clients can request subsets of search results (pages) instead of the entire list\&. This parameter specifies the size of these pages\&.
 .sp
 Default:
-\fI\fIldap page size\fR\fR\fI = \fR\fI1024\fR\fI \fR
+\fI\fIldap page size\fR\fR\fI = \fR\fI1000\fR\fI \fR
 .sp
 Example:
 \fI\fIldap page size\fR\fR\fI = \fR\fI512\fR\fI \fR
@@ -5493,7 +5520,7 @@ The value of the parameter (a astring) allows the debug level (logging level) to
 smb\&.conf
 file\&.
 .sp
-This parameter has been extended since the 2\&.2\&.x series, now it allows to specify the debug level for multiple debug classes\&. This is to give greater flexibility in the configuration of the system\&. The following debug classes are currently implemented:
+This parameter has been extended since the 2\&.2\&.x series, now it allows one to specify the debug level for multiple debug classes\&. This is to give greater flexibility in the configuration of the system\&. The following debug classes are currently implemented:
 .sp
 .RS 4
 .ie n \{\
@@ -6105,15 +6132,19 @@ machine password timeout (G)
 .\" machine password timeout
 .PP
 .RS 4
-If a Samba server is a member of a Windows NT Domain (see the
+If a Samba server is a member of a Windows NT or Active Directory Domain (see the
 \m[blue]\fBsecurity = domain\fR\m[]
-parameter) then periodically a running smbd process will try and change the MACHINE ACCOUNT PASSWORD stored in the TDB called
-private/secrets\&.tdb\&. This parameter specifies how often this password will be changed, in seconds\&. The default is one week (expressed in seconds), the same as a Windows NT Domain member server\&.
+and
+\m[blue]\fBsecurity = ads\fR\m[]
+parameters), then periodically a running winbindd process will try and change the MACHINE ACCOUNT PASSWORD stored in the TDB called
+secrets\&.tdb\&. This parameter specifies how often this password will be changed, in seconds\&. The default is one week (expressed in seconds), the same as a Windows NT Domain member server\&.
 .sp
 See also
 \fBsmbpasswd\fR(8), and the
 \m[blue]\fBsecurity = domain\fR\m[]
-parameter\&.
+and
+\m[blue]\fBsecurity = ads\fR\m[]
+parameters\&.
 .sp
 Default:
 \fI\fImachine password timeout\fR\fR\fI = \fR\fI604800\fR\fI \fR
@@ -7916,31 +7947,6 @@ Default:
 \fI\fIpreferred master\fR\fR\fI = \fR\fIauto\fR\fI \fR
 .RE
 
-auto services
-.\" auto services
-.PP
-.RS 4
-This parameter is a synonym for
-preload\&.
-.RE
-
-preload (G)
-.\" preload
-.PP
-.RS 4
-This is a list of services that you want to be automatically added to the browse lists\&. This is most useful for homes and printers services that would otherwise not be visible\&.
-.sp
-Note that if you just want all printers in your printcap file loaded then the
-\m[blue]\fBload printers\fR\m[]
-option is easier\&.
-.sp
-Default:
-\fI\fIpreload\fR\fR\fI = \fR\fI\fR\fI \fR
-.sp
-Example:
-\fI\fIpreload\fR\fR\fI = \fR\fIfred lp colorlp\fR\fI \fR
-.RE
-
 preload modules (G)
 .\" preload modules
 .PP
@@ -8363,14 +8369,6 @@ Example:
 \fI\fIread list\fR\fR\fI = \fR\fImary, @students\fR\fI \fR
 .RE
 
-write ok
-.\" write ok
-.PP
-.RS 4
-This parameter is a synonym for
-read only\&.
-.RE
-
 read only (S)
 .\" read only
 .PP
@@ -8394,7 +8392,7 @@ read raw (G)
 .PP
 .RS 4
 This is ignored if
-\m[blue]\fBasync echo handler\fR\m[]
+\m[blue]\fBasync smb echo handler\fR\m[]
 is set, because this feature is incompatible with raw read SMB requests
 .sp
 If enabled, raw reads allow reads of 65535 bytes in one packet\&. This typically provides a major performance benefit for some very, very old clients\&.
@@ -8796,7 +8794,7 @@ by default\&.
 .sp
 Choosing the
 \fIfork\fR
-option will cause samba to fork a separate proces for each daemon configured this way\&. Each daemon may in turn fork a number of children used to handle requests from multiple smbds and direct tcp/ip connections (if the Endpoint Mapper is enabled)\&. Communication with smbd happens over named pipes and require that said pipes are forward to the external daemon (see
+option will cause samba to fork a separate process for each daemon configured this way\&. Each daemon may in turn fork a number of children used to handle requests from multiple smbds and direct tcp/ip connections (if the Endpoint Mapper is enabled)\&. Communication with smbd happens over named pipes and require that said pipes are forward to the external daemon (see
 \m[blue]\fBrpc_server\fR\m[])\&.
 .sp
 Forked RPC Daemons support dynamically forking children to handle connections\&. The heuristics about how many children to keep around and how fast to allow them to fork and also how many clients each child is allowed to handle concurrently is defined by parametrical options named after the daemon\&. Five options are currently supported:
@@ -9046,7 +9044,7 @@ in smbd\&. The defaults may vary depending on the service\&.
 .sp
 Choosing the
 \fIexternal\fR
-option allows to run a separate daemon or even a completely independent (3rd party) server capable of interfacing with samba via the MS\-RPC interface over named pipes\&.
+option allows one to run a separate daemon or even a completely independent (3rd party) server capable of interfacing with samba via the MS\-RPC interface over named pipes\&.
 .sp
 Currently in Samba3 we support four daemons, spoolssd, epmd, lsasd and mdssd\&. These daemons can be enabled using the
 \fIrpc_daemon\fR
@@ -9448,6 +9446,22 @@ Example:
 \fI\fIserver min protocol\fR\fR\fI = \fR\fINT1\fR\fI \fR
 .RE
 
+server multi channel support (G)
+.\" server multi channel support
+.PP
+.RS 4
+This boolean parameter controls whether
+\fBsmbd\fR(8)
+will support SMB3 multi\-channel\&.
+.sp
+This parameter has been added with version 4\&.4\&.
+.sp
+Warning: Note that this feature is considered experimental in Samba 4\&.4\&. Use it at your own risk: Even though it may seem to work well in testing, it may result in data corruption under some race conditions\&. Future 4\&.4\&.x release may improve this situation\&.
+.sp
+Default:
+\fI\fIserver multi channel support\fR\fR\fI = \fR\fIno\fR\fI \fR
+.RE
+
 server role (G)
 .\" server role
 .PP
@@ -9477,7 +9491,7 @@ if you want to mainly setup shares without a password (guest shares)\&. This is
 .sp
 This is the default server role in Samba, and causes Samba to consult the
 \m[blue]\fBsecurity\fR\m[]
-parameter (if set) to determine the server role, giving compatable behaviours to previous Samba versions\&.
+parameter (if set) to determine the server role, giving compatible behaviours to previous Samba versions\&.
 .sp
 \fISERVER ROLE = STANDALONE\fR
 .sp
@@ -9509,7 +9523,7 @@ that a valid UNIX user must still exist as well as the account on the Domain Con
 .sp
 This mode of operation runs a classic Samba primary domain controller, providing domain logon services to Windows and Samba clients of an NT4\-like domain\&. Clients must be joined to the domain to create a secure, trusted path across the network\&. There must be only one PDC per NetBIOS scope (typcially a broadcast network or clients served by a single WINS server)\&.
 .sp
-\fISERVER ROLE = NETBIOS BACKUP DOMAIN CONTROLLER\fR
+\fISERVER ROLE = CLASSIC BACKUP DOMAIN CONTROLLER\fR
 .sp
 This mode of operation runs a classic Samba backup domain controller, providing domain logon services to Windows and Samba clients of an NT4\-like domain\&. As a BDC, this allows multiple Samba servers to provide redundant logon services to a single NetBIOS scope\&.
 .sp
@@ -9522,7 +9536,7 @@ Default:
 \fI\fIserver role\fR\fR\fI = \fR\fIAUTO\fR\fI \fR
 .sp
 Example:
-\fI\fIserver role\fR\fR\fI = \fR\fIDOMAIN CONTROLLER\fR\fI \fR
+\fI\fIserver role\fR\fR\fI = \fR\fIACTIVE DIRECTORY DOMAIN CONTROLLER\fR\fI \fR
 .RE
 
 server schannel (G)
@@ -10891,7 +10905,11 @@ By default a Windows SMB server prevents directory renames when there are open f
 .sp
 This boolean parameter allows Samba to match the Windows behavior\&. Setting this to "yes" is a very expensive change, as it forces Samba to travers the entire open file handle database on every directory rename request\&. In a clustered Samba system the cost is even greater than the non\-clustered case\&.
 .sp
-For this reason the default is "no", and it is recommended to be left that way unless a specific Windows application requires it to be changed\&.
+When set to "no" smbd only checks the local process the client is attached to for open files below a directory being renamed, instead of checking for open files across all smbd processes\&.
+.sp
+Because of the expense in fully searching the database, the default is "no", and it is recommended to be left that way unless a specific Windows application requires it to be changed\&.
+.sp
+If the client has requested UNIX extensions (POSIX pathnames) then renames are always allowed and this parameter has no effect\&.
 .sp
 Default:
 \fI\fIstrict rename\fR\fR\fI = \fR\fIno\fR\fI \fR
@@ -10901,12 +10919,16 @@ strict sync (S)
 .\" strict sync
 .PP
 .RS 4
-Many Windows applications (including the Windows 98 explorer shell) seem to confuse flushing buffer contents to disk with doing a sync to disk\&. Under UNIX, a sync call forces the process to be suspended until the kernel has ensured that all outstanding data in kernel disk buffers has been safely stored onto stable storage\&. This is very slow and should only be done rarely\&. Setting this parameter to
+Many Windows applications (including the Windows 98 explorer shell) seem to confuse flushing buffer contents to disk with doing a sync to disk\&. Under UNIX, a sync call forces the thread to be suspended until the kernel has ensured that all outstanding data in kernel disk buffers has been safely stored onto stable storage\&. This is very slow and should only be done rarely\&. Setting this parameter to
 \fBno\fR
 (the default) means that
 \fBsmbd\fR(8)
 ignores the Windows applications requests for a sync call\&. There is only a possibility of losing data if the operating system itself that Samba is running on crashes, so there is little danger in this default setting\&. In addition, this fixes many performance problems that people have reported with the new Windows98 explorer shell file copies\&.
 .sp
+The flush request from SMB2/3 clients is handled asynchronously, so for these clients setting the parameter to
+\fByes\fR
+does not block the processing of other requests in the smbd process\&.
+.sp
 Default:
 \fI\fIstrict sync\fR\fR\fI = \fR\fIno\fR\fI \fR
 .RE
@@ -11036,6 +11058,26 @@ Default:
 \fI\fItime server\fR\fR\fI = \fR\fIno\fR\fI \fR
 .RE
 
+debug timestamp
+.\" debug timestamp
+.PP
+.RS 4
+This parameter is a synonym for
+timestamp logs\&.
+.RE
+
+timestamp logs (G)
+.\" timestamp logs
+.PP
+.RS 4
+Samba debug log messages are timestamped by default\&. If you are running at a high
+\m[blue]\fBdebug level\fR\m[]
+these timestamps can be distracting\&. This boolean parameter allows timestamping to be turned off\&.
+.sp
+Default:
+\fI\fItimestamp logs\fR\fR\fI = \fR\fIyes\fR\fI \fR
+.RE
+
 tls cafile (G)
 .\" tls cafile
 .PP
@@ -11082,7 +11124,7 @@ tls dh params file (G)
 .\" tls dh params file
 .PP
 .RS 4
-This option can be set to a file with Diffie\-Hellman parameters which will be used with EDH ciphers\&.
+This option can be set to a file with Diffie\-Hellman parameters which will be used with DH ciphers\&.
 .sp
 This path is relative to
 \m[blue]\fBprivate dir\fR\m[]
@@ -12005,7 +12047,7 @@ winbind offline logon (G)
 .\" winbind offline logon
 .PP
 .RS 4
-This parameter is designed to control whether Winbind should allow to login with the
+This parameter is designed to control whether Winbind should allow one to login with the
 \fIpam_winbind\fR
 module using Cached Credentials\&. If enabled, winbindd will store user credentials from successful logins encrypted in a local cache\&.
 .sp
@@ -12300,6 +12342,14 @@ This parameter is a synonym for
 writeable\&.
 .RE
 
+write ok
+.\" write ok
+.PP
+.RS 4
+This parameter is a synonym for
+writeable\&.
+.RE
+
 writeable (S)
 .\" writeable
 .PP
@@ -12354,7 +12404,7 @@ write raw (G)
 .PP
 .RS 4
 This is ignored if
-\m[blue]\fBasync echo handler\fR\m[]
+\m[blue]\fBasync smb echo handler\fR\m[]
 is set, because this feature is incompatible with raw write SMB requests
 .sp
 If enabled, raw writes allow writes of 65535 bytes in one packet\&. This typically provides a major performance benefit for some very, very old clients\&.
diff --git a/docs/manpages/smbcacls.1 b/docs/manpages/smbcacls.1
index 291ac5e..3a1f3fb 100644
--- a/docs/manpages/smbcacls.1
+++ b/docs/manpages/smbcacls.1
@@ -2,12 +2,12 @@
 .\"     Title: smbcacls
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBCACLS" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "SMBCACLS" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbclient.1 b/docs/manpages/smbclient.1
index 395fbcf..d8964e8 100644
--- a/docs/manpages/smbclient.1
+++ b/docs/manpages/smbclient.1
@@ -2,12 +2,12 @@
 .\"     Title: smbclient
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBCLIENT" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "SMBCLIENT" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbcontrol.1 b/docs/manpages/smbcontrol.1
index c8cf7ff..b42c86f 100644
--- a/docs/manpages/smbcontrol.1
+++ b/docs/manpages/smbcontrol.1
@@ -2,12 +2,12 @@
 .\"     Title: smbcontrol
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBCONTROL" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "SMBCONTROL" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbcquotas.1 b/docs/manpages/smbcquotas.1
index 22365d0..146b110 100644
--- a/docs/manpages/smbcquotas.1
+++ b/docs/manpages/smbcquotas.1
@@ -2,12 +2,12 @@
 .\"     Title: smbcquotas
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBCQUOTAS" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "SMBCQUOTAS" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbd.8 b/docs/manpages/smbd.8
index 0171d72..0f4f1ee 100644
--- a/docs/manpages/smbd.8
+++ b/docs/manpages/smbd.8
@@ -2,12 +2,12 @@
 .\"     Title: smbd
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBD" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "SMBD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -90,7 +90,7 @@ to log to standard output rather than a file\&.
 .RS 4
 If this parameter is specified it causes the server to run "interactively", not as a daemon, even if the server is executed on the command line of a shell\&. Setting this parameter negates the implicit daemon mode when run from the command line\&.
 smbd
-also logs to standard output, as if the
+will only accept one connection and terminate\&. It will also log to standard output, as if the
 \-S
 parameter had been given\&.
 .RE
diff --git a/docs/manpages/smbget.1 b/docs/manpages/smbget.1
index 566a67a..12a0374 100644
--- a/docs/manpages/smbget.1
+++ b/docs/manpages/smbget.1
@@ -2,12 +2,12 @@
 .\"     Title: smbget
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBGET" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "SMBGET" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -31,7 +31,7 @@
 smbget \- wget\-like utility for download files over SMB
 .SH "SYNOPSIS"
 .HP \w'\ 'u
-smbget [\-a,\ \-\-guest] [\-r,\ \-\-resume] [\-R,\ \-\-recursive] [\-u,\ \-\-username=STRING] [\-p,\ \-\-password=STRING] [\-w,\ \-\-workgroup=STRING] [\-n,\ \-\-nonprompt] [\-d,\ \-\-debuglevel=INT] [\-D,\ \-\-dots] [\-P,\ \-\-keep\-permissions] [\-o,\ \-\-outputfile] [\-f,\ \-\-rcfile] [\-q,\ \-\-quiet] [\-v,\ \-\-verbose] [\-b,\ \-\-blocksize] [\-O,\ \-\-stdout] [\-U,\ \-\-update] [\-?,\ \-\-help] [\-\-usage] {smb://host/share/path/to/file} [smb://url2/] [\&.\&.\&.]
+smbget [\-a,\ \-\-guest] [\-r,\ \-\-resume] [\-R,\ \-\-recursive] [\-U,\ \-\-username=STRING] [\-w,\ \-\-workgroup=STRING] [\-n,\ \-\-nonprompt] [\-d,\ \-\-debuglevel=INT] [\-D,\ \-\-dots] [\-o,\ \-\-outputfile] [\-f,\ \-\-rcfile] [\-q,\ \-\-quiet] [\-v,\ \-\-verbose] [\-b,\ \-\-blocksize] [\-O,\ \-\-stdout] [\-u,\ \-\-update] [\-?,\ \-\-help] [\-\-usage] {smb://host/share/path/to/file} [smb://url2/] [\&.\&.\&.]
 .SH "DESCRIPTION"
 .PP
 This tool is part of the
@@ -59,14 +59,9 @@ Automatically resume aborted files
 Recursively download files
 .RE
 .PP
-\-u, \-\-username=STRING
+\-U, \-\-username=\fIusername[%password]\fR
 .RS 4
-Username to use
-.RE
-.PP
-\-p, \-\-password=STRING
-.RS 4
-Password to use
+Username (and password) to use
 .RE
 .PP
 \-w, \-\-workgroup=STRING
@@ -89,11 +84,6 @@ Debuglevel to use
 Show dots as progress indication
 .RE
 .PP
-\-P, \-\-keep\-permissions
-.RS 4
-Set same permissions on local file as are set on remote file\&.
-.RE
-.PP
 \-o, \-\-outputfile
 .RS 4
 Write the file that is being downloaded to the specified file\&. Can not be used together with \-R\&.
@@ -134,7 +124,7 @@ Show help message
 Display brief usage message
 .RE
 .PP
-\-U, \-\-update
+\-u, \-\-update
 .RS 4
 Download only when remote file is newer than local file or local file is missing\&.
 .RE
diff --git a/docs/manpages/smbgetrc.5 b/docs/manpages/smbgetrc.5
index c959419..d1962b2 100644
--- a/docs/manpages/smbgetrc.5
+++ b/docs/manpages/smbgetrc.5
@@ -2,12 +2,12 @@
 .\"     Title: smbgetrc
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: File Formats and Conventions
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBGETRC" "5" "02/24/2016" "Samba 4\&.3" "File Formats and Conventions"
+.TH "SMBGETRC" "5" "03/22/2016" "Samba 4\&.4" "File Formats and Conventions"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -56,14 +56,9 @@ recursive on|off
 Whether directories should be downloaded recursively
 .RE
 .PP
-username \fIname\fR
+user \fIname[%password]\fR
 .RS 4
-Username to use when logging in to the remote server\&. Use an empty string for anonymous access\&.
-.RE
-.PP
-password \fIpass\fR
-.RS 4
-Password to use when logging in\&.
+Username (and password) to use when logging in to the remote server\&. Use an empty string for anonymous access\&.
 .RE
 .PP
 workgroup \fIwg\fR
diff --git a/docs/manpages/smbpasswd.5 b/docs/manpages/smbpasswd.5
index 31b52a9..71740b8 100644
--- a/docs/manpages/smbpasswd.5
+++ b/docs/manpages/smbpasswd.5
@@ -2,12 +2,12 @@
 .\"     Title: smbpasswd
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: File Formats and Conventions
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBPASSWD" "5" "02/24/2016" "Samba 4\&.3" "File Formats and Conventions"
+.TH "SMBPASSWD" "5" "03/22/2016" "Samba 4\&.4" "File Formats and Conventions"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbpasswd.8 b/docs/manpages/smbpasswd.8
index 3d00776..2f233e9 100644
--- a/docs/manpages/smbpasswd.8
+++ b/docs/manpages/smbpasswd.8
@@ -2,12 +2,12 @@
 .\"     Title: smbpasswd
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBPASSWD" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "SMBPASSWD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbspool.8 b/docs/manpages/smbspool.8
index c4bc508..975a6d6 100644
--- a/docs/manpages/smbspool.8
+++ b/docs/manpages/smbspool.8
@@ -2,12 +2,12 @@
 .\"     Title: smbspool
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBSPOOL" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "SMBSPOOL" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -85,6 +85,17 @@ smb://username:password@server[:port]/printer
 .sp -1
 .IP \(bu 2.3
 .\}
+smb://domain\eusername:password@server[:port]/printer
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
 smb://username:password@workgroup/server[:port]/printer
 .RE
 .sp
@@ -102,6 +113,8 @@ exec(2)
 functions can pass the URI in argv[0], while shell scripts must set the
 \fBDEVICE_URI\fR
 environment variable prior to running smbspool\&.
+.PP
+smbspool will accept URI escaped characters\&. This allows setting a domain in the username, or space in the printer name\&. For example smb://domain%5Cusername/printer%20name
 .SH "OPTIONS"
 .sp
 .RS 4
diff --git a/docs/manpages/smbspool_krb5_wrapper.8 b/docs/manpages/smbspool_krb5_wrapper.8
index bd6f2b5..ccd20b9 100644
--- a/docs/manpages/smbspool_krb5_wrapper.8
+++ b/docs/manpages/smbspool_krb5_wrapper.8
@@ -2,12 +2,12 @@
 .\"     Title: smbspool_krb5_wrapper
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
 .\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBSPOOL_KRB5_WRAPPE" "8" "02/24/2016" "Samba 4\&.4" "System Administration tools"
+.TH "SMBSPOOL_KRB5_WRAPPE" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbstatus.1 b/docs/manpages/smbstatus.1
index c2766d5..1dcd876 100644
--- a/docs/manpages/smbstatus.1
+++ b/docs/manpages/smbstatus.1
@@ -2,12 +2,12 @@
 .\"     Title: smbstatus
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBSTATUS" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "SMBSTATUS" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbta-util.8 b/docs/manpages/smbta-util.8
deleted file mode 100644
index f7349c7..0000000
--- a/docs/manpages/smbta-util.8
+++ /dev/null
@@ -1,83 +0,0 @@
-'\" t
-.\"     Title: smbta-util
-.\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
-.\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
-.\"  Language: English
-.\"
-.TH "SMBTA\-UTIL" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-smbta-util \- control encryption in VFS smb_traffic_analyzer
-.SH "SYNOPSIS"
-.HP \w'\ 'u
-smbta\-util [\fICOMMANDS\fR...]
-.SH "DESCRIPTION"
-.PP
-This tool is part of the
-\fBsamba\fR(1)
-suite\&.
-.PP
-smbta\-util
-is a tool to ease the configuration of the vfs_smb_traffic_analyzer module regarding data encryption\&.
-.PP
-The user can generate a key, install a key (activating encryption), or uninstall a key (deactivating encryption)\&. Any operation that installs a key will create a File containing the key\&. This file can be used by smbta\-tool on other machines to install the same key from the file\&.
-.SH "COMMANDS"
-.PP
-\fB\-h\fR
-.RS 4
-Show a short help text on the command line\&.
-.RE
-.PP
-\fB\-f\fR \fIKEYFILE\fR
-.RS 4
-Open an existing keyfile, read the key from the file, and install the key, activating encryption\&.
-.RE
-.PP
-\fB\-g\fR \fIKEYFILE\fR
-.RS 4
-Generate a new random key, install the key, activate encryption, and store the key into the file KEYFILE\&.
-.RE
-.PP
-\fB\-u\fR
-.RS 4
-Uninstall the key, deactivating encryption\&.
-.RE
-.PP
-\fB\-s\fR
-.RS 4
-Check if a key is installed\&.
-.RE
-.PP
-\fB\-c\fR \fIKEYFILE\fR
-.RS 4
-Create a KEYFILE from an installed key\&.
-.RE
-.SH "VERSION"
-.PP
-This man page is correct for version 3\&.4 of the Samba suite\&.
-.SH "AUTHOR"
-.PP
-The original version of smbta\-util was created by Holger Hetterich\&.
-.PP
-The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff --git a/docs/manpages/smbtar.1 b/docs/manpages/smbtar.1
index 130b1a3..8cf2265 100644
--- a/docs/manpages/smbtar.1
+++ b/docs/manpages/smbtar.1
@@ -2,12 +2,12 @@
 .\"     Title: smbtar
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBTAR" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "SMBTAR" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbtree.1 b/docs/manpages/smbtree.1
index e757082..0eea499 100644
--- a/docs/manpages/smbtree.1
+++ b/docs/manpages/smbtree.1
@@ -2,12 +2,12 @@
 .\"     Title: smbtree
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "SMBTREE" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "SMBTREE" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/testparm.1 b/docs/manpages/testparm.1
index 5b42305..dd29266 100644
--- a/docs/manpages/testparm.1
+++ b/docs/manpages/testparm.1
@@ -2,12 +2,12 @@
 .\"     Title: testparm
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "TESTPARM" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "TESTPARM" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_acl_tdb.8 b/docs/manpages/vfs_acl_tdb.8
index 9c69b5f..2903303 100644
--- a/docs/manpages/vfs_acl_tdb.8
+++ b/docs/manpages/vfs_acl_tdb.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_acl_tdb
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_ACL_TDB" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_ACL_TDB" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_acl_xattr.8 b/docs/manpages/vfs_acl_xattr.8
index 9ed7731..0c80ba2 100644
--- a/docs/manpages/vfs_acl_xattr.8
+++ b/docs/manpages/vfs_acl_xattr.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_acl_xattr
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_ACL_XATTR" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_ACL_XATTR" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_aio_fork.8 b/docs/manpages/vfs_aio_fork.8
index a5a8838..43e9d21 100644
--- a/docs/manpages/vfs_aio_fork.8
+++ b/docs/manpages/vfs_aio_fork.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_aio_fork
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_AIO_FORK" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_AIO_FORK" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_aio_linux.8 b/docs/manpages/vfs_aio_linux.8
index 9029985..e962a26 100644
--- a/docs/manpages/vfs_aio_linux.8
+++ b/docs/manpages/vfs_aio_linux.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_aio_linux
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_AIO_LINUX" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_AIO_LINUX" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_aio_pthread.8 b/docs/manpages/vfs_aio_pthread.8
index 0606288..d96564e 100644
--- a/docs/manpages/vfs_aio_pthread.8
+++ b/docs/manpages/vfs_aio_pthread.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_aio_pthread
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_AIO_PTHREAD" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_AIO_PTHREAD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_audit.8 b/docs/manpages/vfs_audit.8
index 0154f99..1316baa 100644
--- a/docs/manpages/vfs_audit.8
+++ b/docs/manpages/vfs_audit.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_audit
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_AUDIT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_AUDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_btrfs.8 b/docs/manpages/vfs_btrfs.8
index aea6e5a..33c2245 100644
--- a/docs/manpages/vfs_btrfs.8
+++ b/docs/manpages/vfs_btrfs.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_btrfs
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_BTRFS" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_BTRFS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_cacheprime.8 b/docs/manpages/vfs_cacheprime.8
index ce1cad4..17ed828 100644
--- a/docs/manpages/vfs_cacheprime.8
+++ b/docs/manpages/vfs_cacheprime.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_cacheprime
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_CACHEPRIME" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_CACHEPRIME" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_cap.8 b/docs/manpages/vfs_cap.8
index 326c412..d278883 100644
--- a/docs/manpages/vfs_cap.8
+++ b/docs/manpages/vfs_cap.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_cap
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_CAP" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_CAP" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_catia.8 b/docs/manpages/vfs_catia.8
index bc68933..f48b650 100644
--- a/docs/manpages/vfs_catia.8
+++ b/docs/manpages/vfs_catia.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_catia
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_CATIA" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_CATIA" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_ceph.8 b/docs/manpages/vfs_ceph.8
index 73b3d61..8c28386 100644
--- a/docs/manpages/vfs_ceph.8
+++ b/docs/manpages/vfs_ceph.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_ceph
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_CEPH" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_CEPH" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -67,7 +67,7 @@ requires that the underlying share path is a Ceph filesystem\&.
 .PP
 ceph:config_file = path
 .RS 4
-Allows to define a ceph configfile to use\&. Empty by default\&.
+Allows one to define a ceph configfile to use\&. Empty by default\&.
 .sp
 Example: ceph:config_file = /etc/ceph/ceph\&.conf
 .RE
diff --git a/docs/manpages/vfs_commit.8 b/docs/manpages/vfs_commit.8
index afbb350..36d357c 100644
--- a/docs/manpages/vfs_commit.8
+++ b/docs/manpages/vfs_commit.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_commit
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_COMMIT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_COMMIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_crossrename.8 b/docs/manpages/vfs_crossrename.8
index 4b037a1..4fab9e7 100644
--- a/docs/manpages/vfs_crossrename.8
+++ b/docs/manpages/vfs_crossrename.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_crossrename
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_CROSSRENAME" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_CROSSRENAME" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_default_quota.8 b/docs/manpages/vfs_default_quota.8
index 9347894..9628808 100644
--- a/docs/manpages/vfs_default_quota.8
+++ b/docs/manpages/vfs_default_quota.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_default_quota
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_DEFAULT_QUOTA" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_DEFAULT_QUOTA" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_dirsort.8 b/docs/manpages/vfs_dirsort.8
index 6455c07..ebc8bde 100644
--- a/docs/manpages/vfs_dirsort.8
+++ b/docs/manpages/vfs_dirsort.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_dirsort
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_DIRSORT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_DIRSORT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_extd_audit.8 b/docs/manpages/vfs_extd_audit.8
index 48f605b..66e5945 100644
--- a/docs/manpages/vfs_extd_audit.8
+++ b/docs/manpages/vfs_extd_audit.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_extd_audit
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_EXTD_AUDIT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_EXTD_AUDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_fake_perms.8 b/docs/manpages/vfs_fake_perms.8
index 68aac1f..d7fbbb8 100644
--- a/docs/manpages/vfs_fake_perms.8
+++ b/docs/manpages/vfs_fake_perms.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_fake_perms
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_FAKE_PERMS" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_FAKE_PERMS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_fileid.8 b/docs/manpages/vfs_fileid.8
index 2121630..aa13ef5 100644
--- a/docs/manpages/vfs_fileid.8
+++ b/docs/manpages/vfs_fileid.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_fileid
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_FILEID" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_FILEID" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_fruit.8 b/docs/manpages/vfs_fruit.8
index 7b8f212..a2ac437 100644
--- a/docs/manpages/vfs_fruit.8
+++ b/docs/manpages/vfs_fruit.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_fruit
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_FRUIT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_FRUIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_full_audit.8 b/docs/manpages/vfs_full_audit.8
index 4ea3f03..8c2f996 100644
--- a/docs/manpages/vfs_full_audit.8
+++ b/docs/manpages/vfs_full_audit.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_full_audit
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_FULL_AUDIT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_FULL_AUDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_glusterfs.8 b/docs/manpages/vfs_glusterfs.8
index e70933f..0de3b97 100644
--- a/docs/manpages/vfs_glusterfs.8
+++ b/docs/manpages/vfs_glusterfs.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_glusterfs
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_GLUSTERFS" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_GLUSTERFS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_gpfs.8 b/docs/manpages/vfs_gpfs.8
index a5b158e..7f0a43d 100644
--- a/docs/manpages/vfs_gpfs.8
+++ b/docs/manpages/vfs_gpfs.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_gpfs
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_GPFS" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_GPFS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_linux_xfs_sgid.8 b/docs/manpages/vfs_linux_xfs_sgid.8
index 0acaee5..7621b0f 100644
--- a/docs/manpages/vfs_linux_xfs_sgid.8
+++ b/docs/manpages/vfs_linux_xfs_sgid.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_syncops
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_SYNCOPS" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_SYNCOPS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_media_harmony.8 b/docs/manpages/vfs_media_harmony.8
index eefadb3..f16553e 100644
--- a/docs/manpages/vfs_media_harmony.8
+++ b/docs/manpages/vfs_media_harmony.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_media_harmony
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_MEDIA_HARMONY" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_MEDIA_HARMONY" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_netatalk.8 b/docs/manpages/vfs_netatalk.8
index 6cbe456..ab74ab6 100644
--- a/docs/manpages/vfs_netatalk.8
+++ b/docs/manpages/vfs_netatalk.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_netatalk
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_NETATALK" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_NETATALK" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_offline.8 b/docs/manpages/vfs_offline.8
new file mode 100644
index 0000000..e9ad9bc
--- /dev/null
+++ b/docs/manpages/vfs_offline.8
@@ -0,0 +1,65 @@
+'\" t
+.\"     Title: vfs_offline
+.\"    Author: [see the "AUTHOR" section]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 03/22/2016
+.\"    Manual: System Administration tools
+.\"    Source: Samba 4.4
+.\"  Language: English
+.\"
+.TH "VFS_OFFLINE" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+vfs_offline \- Mark all files as offline
+.SH "SYNOPSIS"
+.HP \w'\ 'u
+vfs objects = offline
+.SH "DESCRIPTION"
+.PP
+This VFS module is part of the
+\fBsamba\fR(7)
+suite\&.
+.PP
+The
+vfs_offline
+module marks all files in the share as having the offline DOS attribute\&.
+.PP
+Files with the offline DOS attribute are handled differently by the Windows SMB client, as well as by Windows Explorer\&. In particular, Windows Explorer does not read those files for the sole purpose of drawing a thumbnail, as it normally does\&. This can improve user experience with some remote file systems\&.
+.SH "EXAMPLES"
+.PP
+Mark all files in a share as offline:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+        \fI[remote]\fR
+	\m[blue]\fBvfs objects = offline\fR\m[]
+.fi
+.if n \{\
+.RE
+.\}
+.SH "VERSION"
+.PP
+This man page is correct for version 4\&.4 of the Samba suite\&.
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff --git a/docs/manpages/vfs_prealloc.8 b/docs/manpages/vfs_prealloc.8
index 242a7e4..dee51e4 100644
--- a/docs/manpages/vfs_prealloc.8
+++ b/docs/manpages/vfs_prealloc.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_prealloc
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_PREALLOC" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_PREALLOC" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_preopen.8 b/docs/manpages/vfs_preopen.8
index db8e404..79a6c0b 100644
--- a/docs/manpages/vfs_preopen.8
+++ b/docs/manpages/vfs_preopen.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_preopen
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_PREOPEN" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_PREOPEN" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_readahead.8 b/docs/manpages/vfs_readahead.8
index 6c9fec5..8619a55 100644
--- a/docs/manpages/vfs_readahead.8
+++ b/docs/manpages/vfs_readahead.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_readahead
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_READAHEAD" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_READAHEAD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_readonly.8 b/docs/manpages/vfs_readonly.8
index c335680..2f4a306 100644
--- a/docs/manpages/vfs_readonly.8
+++ b/docs/manpages/vfs_readonly.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_readonly
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_READONLY" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_READONLY" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_recycle.8 b/docs/manpages/vfs_recycle.8
index d8e1ae8..414483a 100644
--- a/docs/manpages/vfs_recycle.8
+++ b/docs/manpages/vfs_recycle.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_recycle
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_RECYCLE" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_RECYCLE" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_scannedonly.8 b/docs/manpages/vfs_scannedonly.8
deleted file mode 100644
index a5d9d5d..0000000
--- a/docs/manpages/vfs_scannedonly.8
+++ /dev/null
@@ -1,164 +0,0 @@
-'\" t
-.\"     Title: vfs_scannedonly
-.\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
-.\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
-.\"  Language: English
-.\"
-.TH "VFS_SCANNEDONLY" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-vfs_scannedonly \- Ensures that only files that have been scanned for viruses are visible and accessible to the end user\&.
-.SH "SYNOPSIS"
-.HP \w'\ 'u
-vfs objects = scannedonly
-.SH "DESCRIPTION"
-.PP
-This VFS module is part of the
-\fBsamba\fR(8)
-suite\&.
-.PP
-The
-vfs_scannedonly
-VFS module ensures that only files that have been scanned for viruses are visible and accessible to the end user\&. If non\-scanned files are found an anti\-virus scanning daemon is notified\&. The anti\-virus scanning daemon is not part of the Samba suite\&.
-.PP
-Scannedonly comes in two parts: a samba vfs module and (one or more) daemons\&. The daemon scans files\&. If a certain file is clean, a second file is created with prefix
-\&.scanned:\&. The Samba module simply looks if such a
-\&.scanned:
-file exists, and is newer than the pertinent file\&. If this is the case, the file is shown to the user\&. If this is not the case, the file is not returned in a directory listing (configurable), and cannot be opened (configurable)\&. The Samba vfs module will notify the daemon to scan this file\&.
-.PP
-So what happens for the user in the default configuration\&. The first time a directory is listed, it shows files as \*(Aqfile is being scanned for viruses, but after the first time all files are shown\&. There is a utility scannedonly_prescan that can help you to prescan all directories\&. When new files are written the daemon is notified immediately after the file is complete\&.
-.PP
-If a virus is found by the daemon, a file with a warning message is created in the directory of the user, a warning is sent to the logs, and the file is renamed to have prefix
-\&.virus:\&. Files with the
-\&.virus:
-prefix are never shown to the user and all access is denied\&.
-.PP
-This module is stackable\&.
-.SH "CONFIGURATION"
-.PP
-vfs_scannedonly
-relies on a anti\-virus scanning daemon that listens on the scannedonly socket (unix domain socket or UDP socket)\&.
-.SH "OPTIONS"
-.PP
-scannedonly:domain_socket = True
-.RS 4
-Whether to use a unix domain socket or not (false reverts to use udp)
-.RE
-.PP
-scannedonly:socketname = /var/lib/scannedonly/scan
-.RS 4
-The location of the unix domain socket to connect to
-.RE
-.PP
-scannedonly:portnum = 2020
-.RS 4
-The udp port number to connect to
-.RE
-.PP
-scannedonly:scanhost = localhost
-.RS 4
-When using UDP the host that runs the scanning daemon (this host needs access to the files!)
-.RE
-.PP
-scannedonly:show_special_files = True
-.RS 4
-Whether sockets, devices and fifo\*(Aqs (all not scanned for viruses) should be visible to the user
-.RE
-.PP
-scannedonly:rm_hidden_files_on_rmdir = True
-.RS 4
-Whether files that are not visible (\&.scanned:
-files,
-\&.failed:
-files and
-\&.virus:
-files) should be deleted if the user tries to remove the directory\&. If false, the user will get the "directory is not empty" error\&.
-.RE
-.PP
-scannedonly:hide_nonscanned_files = True
-.RS 4
-If false, all non\-scanned files are visible in directory listings\&. If such files are found in a directory listing the scanning daemon is notified that scanning is required\&. Access to non\-scanned files is still denied (see scannedonly:allow_nonscanned_files)\&.
-.RE
-.PP
-scannedonly:scanning_message = is being scanned for viruses
-.RS 4
-If non\-scanned files are hidden (if scannedonly:hide_nonscanned_files = True), a fake 0 byte file is shown\&. The filename is the original filename with the message as suffix\&.
-.RE
-.PP
-scannedonly:recheck_time_open = 50
-.RS 4
-If a non\-scanned file is opened, the vfs module will wait recheck_tries_open times for recheck_time_open milliseconds for the scanning daemon to create a
-\&.scanned:
-file\&. For small files that are scanned by the daemon within the time (tries * time) the behavior will be just like on\-access scanning\&.
-.RE
-.PP
-scannedonly:recheck_tries_open = 100
-.RS 4
-See recheck_time_open\&.
-.RE
-.PP
-scannedonly:recheck_time_readdir = 50
-.RS 4
-If a non\-scanned file is in a directory listing the vfs module notifies the daemon (once for all files that need scanning in that directory), and waits recheck_tries_readdir times for recheck_time_readdir milliseconds\&. Only used when hide_nonscanned_files is false\&.
-.RE
-.PP
-scannedonly:recheck_tries_readdir = 20
-.RS 4
-See recheck_time_readdir\&.
-.RE
-.PP
-scannedonly:allow_nonscanned_files = False
-.RS 4
-Allow access to non\-scanned files\&. The daemon is notified, however, and special files such as
-\&.scanned:
-files\&.
-\&.virus:
-files and
-\&.failed:
-files are not listed\&.
-.RE
-.SH "EXAMPLES"
-.PP
-Enable anti\-virus scanning:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-        \fI[homes]\fR
-	\m[blue]\fBvfs objects = scannedonly\fR\m[]
-	\m[blue]\fBscannedonly:hide_nonscanned_files = False\fR\m[]
-.fi
-.if n \{\
-.RE
-.\}
-.SH "CAVEATS"
-.PP
-This is not true on\-access scanning\&. However, it is very fast for files that have been scanned already\&.
-.SH "VERSION"
-.PP
-This man page is correct for version 4\&.0\&.0 of the Samba suite\&.
-.SH "AUTHOR"
-.PP
-The original Samba software and related utilities were created by Andrew Tridgell\&. Scannedonly was developed for Samba by Olivier Sessink\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff --git a/docs/manpages/vfs_shadow_copy.8 b/docs/manpages/vfs_shadow_copy.8
index deff1c2..00b2f62 100644
--- a/docs/manpages/vfs_shadow_copy.8
+++ b/docs/manpages/vfs_shadow_copy.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_shadow_copy
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_SHADOW_COPY" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_SHADOW_COPY" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_shadow_copy2.8 b/docs/manpages/vfs_shadow_copy2.8
index f4da715..884f173 100644
--- a/docs/manpages/vfs_shadow_copy2.8
+++ b/docs/manpages/vfs_shadow_copy2.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_shadow_copy2
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_SHADOW_COPY2" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_SHADOW_COPY2" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -250,7 +250,7 @@ Default: shadow:snapdir = \&.snapshots
 .PP
 shadow:basedir = BASEDIR
 .RS 4
-The basedir option allows to specify a directory between the share\*(Aqs mount point and the share root, relative to which the file system\*(Aqs snapshots are taken\&.
+The basedir option allows one to specify a directory between the share\*(Aqs mount point and the share root, relative to which the file system\*(Aqs snapshots are taken\&.
 .sp
 For example, if
 .sp
@@ -310,6 +310,69 @@ shadow:basedir
 and disable the basedir setting\&.
 .RE
 .PP
+shadow:snapsharepath = SNAPSHAREPATH
+.RS 4
+With this parameter, one can specify the path of the share\*(Aqs root directory in snapshots, relative to the snapshot\*(Aqs root directory\&. It is an alternative method to
+shadow:basedir, allowing greater control\&.
+.sp
+For example, if within each snapshot the files of the share have a
+path/to/share/
+prefix, then
+shadow:snapsharepath
+can be set to
+path/to/share\&.
+.sp
+With this parameter, it is no longer assumed that a snapshot represents an image of the original file system or a portion of it\&. For example, a system could perform backups of only files contained in shares, and then expose the backup files in a logical structure:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+share1/
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+share2/
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\&.\&.\&./
+.RE
+.sp
+.RE
+Note that the
+shadow:snapdirseverywhere
+and the
+shadow:basedir
+options are incompatible with
+shadow:snapsharepath
+and disable
+shadow:snapsharepath
+setting\&.
+.sp
+Example: shadow:snapsharepath = path/to/share
+.sp
+Default: shadow:snapsharepath = NOT SPECIFIED
+.RE
+.PP
 shadow:sort = asc/desc
 .RS 4
 By default, this module sorts the shadow copy data alphabetically before sending it to the client\&. With this parameter, one can specify the sort order\&. Possible known values are desc (descending, the default) and asc (ascending)\&. If the file system lists directories alphabetically sorted, one can turn off sorting in this module by specifying any other value\&.
@@ -337,7 +400,7 @@ Default: shadow:format = "@GMT\-%Y\&.%m\&.%d\-%H\&.%M\&.%S"
 .PP
 shadow:sscanf = yes/no
 .RS 4
-This paramter can be used to specify that the time in format string is given as an unsigned long integer (%lu) rather than a time strptime() can parse\&. The result must be a unix time_t time\&.
+This parameter can be used to specify that the time in format string is given as an unsigned long integer (%lu) rather than a time strptime() can parse\&. The result must be a unix time_t time\&.
 .sp
 Default: shadow:sscanf = no
 .RE
@@ -387,11 +450,11 @@ shadow:snapdirseverywhere = yes\&. Setting this option makes the module not stop
 An example where this is needed are independent filesets in IBM\*(Aqs GPFS, but other filesystems might support snapshotting only particular subtrees of the filesystem as well\&.
 .sp
 Note that
-shadow:snapdirseverywhere
+shadow:crossmountpoints
 depends on
 shadow:snapdir
 and needs it to be a relative path\&. Setting an absolute snapdir path disables
-shadow:snapdirseverywhere\&.
+shadow:crossmountpoints\&.
 .sp
 Note that this option is incompatible with the
 shadow:basedir
diff --git a/docs/manpages/vfs_shell_snap.8 b/docs/manpages/vfs_shell_snap.8
index dba4e3f..402d591 100644
--- a/docs/manpages/vfs_shell_snap.8
+++ b/docs/manpages/vfs_shell_snap.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_shell_snap
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_SHELL_SNAP" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_SHELL_SNAP" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_smb_traffic_analyzer.8 b/docs/manpages/vfs_smb_traffic_analyzer.8
deleted file mode 100644
index b506a22..0000000
--- a/docs/manpages/vfs_smb_traffic_analyzer.8
+++ /dev/null
@@ -1,385 +0,0 @@
-'\" t
-.\"     Title: smb_traffic_analyzer
-.\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
-.\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
-.\"  Language: English
-.\"
-.TH "SMB_TRAFFIC_ANALYZER" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-vfs_smb_traffic_analyzer \- log Samba VFS read and write operations through a socket to a helper application
-.SH "SYNOPSIS"
-.HP \w'\ 'u
-vfs objects = smb_traffic_analyzer
-.SH "DESCRIPTION"
-.PP
-This VFS module is part of the
-\fBsamba\fR(7)
-suite\&.
-.PP
-The
-vfs_smb_traffic_analyzer
-VFS module logs client file operations on a Samba server and sends this data over a socket to a helper program (in the following the "Receiver"), which feeds a SQL database\&. More information on the helper programs can be obtained from the homepage of the project at: http://holger123\&.wordpress\&.com/smb\-traffic\-analyzer/ Since the VFS module depends on a receiver that is doing something with the data, it is evolving in it\*(Aqs development\&. Therefore, the module works with differe [...]
-.SH "PROTOCOL VERSION 1 DOCUMENTATION"
-.PP
-vfs_smb_traffic_analyzer
-protocol version 1 is aware of the following VFS operations:
-.RS 4
-write
-.RE
-.RS 4
-pwrite
-.RE
-.RS 4
-read
-.RE
-.RS 4
-pread
-.RE
-.PP
-vfs_smb_traffic_analyzer
-sends the following data in a fixed format separated by a comma through either an internet or a unix domain socket:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-	BYTES|USER|DOMAIN|READ/WRITE|SHARE|FILENAME|TIMESTAMP
-	
-.fi
-.if n \{\
-.RE
-.\}
-.PP
-Description of the records:
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-BYTES
-\- the length in bytes of the VFS operation
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-USER
-\- the user who initiated the operation
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-DOMAIN
-\- the domain of the user
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-READ/WRITE
-\- either "W" for a write operation or "R" for read
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-SHARE
-\- the name of the share on which the VFS operation occurred
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-FILENAME
-\- the name of the file that was used by the VFS operation
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-TIMESTAMP
-\- a timestamp, formatted as "yyyy\-mm\-dd hh\-mm\-ss\&.ms" indicating when the VFS operation occurred
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-IP
-\- The IP Address (v4 or v6) of the client machine that initiated the VFS operation\&.
-.RE
-.sp
-.RE
-.PP
-This module is stackable\&.
-.SH "DRAWBACKS OF PROTOCOL VERSION 1"
-.PP
-Several drawbacks have been seen with protocol version 1 over time\&.
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-Problematic parsing \-
-Protocol version 1 uses hyphen and comma to separate blocks of data\&. Once there is a filename with a hyphen, you will run into problems because the receiver decodes the data in a wrong way\&.
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-Insecure network transfer \-
-Protocol version 1 sends all it\*(Aqs data as plaintext over the network\&.
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-Limited set of supported VFS operations \-
-Protocol version 1 supports only four VFS operations\&.
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-No subreleases of the protocol \-
-Protocol version 1 is fixed on it\*(Aqs version, making it unable to introduce new features or bugfixes through compatible sub\-releases\&.
-.RE
-.SH "VERSION 2 OF THE PROTOCOL"
-.PP
-Protocol version 2 is an approach to solve the problems introduced with protcol v1\&. From the users perspective, the following changes are most prominent among other enhancements:
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-The data from the module may be send encrypted, with a key stored in secrets\&.tdb\&. The Receiver then has to use the same key\&. The module does AES block encryption over the data to send\&.
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-The module now can identify itself against the receiver with a sub\-release number, where the receiver may run with a different sub\-release number than the module\&. However, as long as both run on the V2\&.x protocol, the receiver will not crash, even if the module uses features only implemented in the newer subrelease\&. Ultimately, if the module uses a new feature from a newer subrelease, and the receiver runs an older protocol, it is just ignoring the functionality\&. Of course it i [...]
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-The parsing problems of protocol V1 can no longer happen, because V2 is marshalling the data packages in a proper way\&.
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-The module now potentially has the ability to create data on every VFS function\&. As of protocol V2\&.0, there is support for 8 VFS functions, namely write,read,pread,pwrite, rename,chdir,mkdir and rmdir\&. Supporting more VFS functions is one of the targets for the upcoming sub\-releases\&.
-.RE
-.sp
-.RE
-.PP
-To enable protocol V2, the protocol_version vfs option has to be used (see OPTIONS)\&.
-.SH "OPTIONS WITH PROTOCOL V1 AND V2.X"
-.PP
-smb_traffic_analyzer:mode = STRING
-.RS 4
-If STRING matches to "unix_domain_socket", the module will use a unix domain socket located at /var/tmp/stadsocket, if STRING contains an different string or is not defined, the module will use an internet domain socket for data transfer\&.
-.RE
-.PP
-smb_traffic_analyzer:host = STRING
-.RS 4
-The module will send the data to the system named with the hostname STRING\&.
-.RE
-.PP
-smb_traffic_analyzer:port = STRING
-.RS 4
-The module will send the data using the TCP port given in STRING\&.
-.RE
-.PP
-smb_traffic_analyzer:anonymize_prefix = STRING
-.RS 4
-The module will replace the user names with a prefix given by STRING and a simple hash number\&. In version 2\&.x of the protocol, the users SID will also be anonymized\&.
-.RE
-.PP
-smb_traffic_analyzer:total_anonymization = STRING
-.RS 4
-If STRING matches to \*(Aqyes\*(Aq, the module will replace any user name with the string given by the option smb_traffic_analyzer:anonymize_prefix, without generating an additional hash number\&. This means that any transfer data will be mapped to a single user, leading to a total anonymization of user related data\&. In version 2\&.x of the protocol, the users SID will also be anonymized\&.
-.RE
-.PP
-smb_traffic_analyzer:protocol_version = STRING
-.RS 4
-If STRING matches to V1, the module will use version 1 of the protocol\&. If STRING is not given, the module will use version 2 of the protocol, which is the default\&.
-.RE
-.SH "EXAMPLES"
-.PP
-Running protocol V2 on share "example_share", using an internet socket\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-	\fI[example_share]\fR
-	\m[blue]\fBpath = /data/example\fR\m[]
-	\m[blue]\fBvfs_objects = smb_traffic_analyzer\fR\m[]
-	\m[blue]\fBsmb_traffic_analyzer:host = examplehost\fR\m[]
-	\m[blue]\fBsmb_traffic_analyzer:port = 3491\fR\m[]
-	
-.fi
-.if n \{\
-.RE
-.\}
-.PP
-The module running on share "example_share", using a unix domain socket
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-	\fI[example_share]\fR
-	\m[blue]\fBpath = /data/example\fR\m[]
-	\m[blue]\fBvfs objects = smb_traffic_analyzer\fR\m[]
-	\m[blue]\fBsmb_traffic_analyzer:mode = unix_domain_socket\fR\m[]
-	
-.fi
-.if n \{\
-.RE
-.\}
-.PP
-The module running on share "example_share", using an internet socket, connecting to host "examplehost" on port 3491\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-	\fI[example_share]\fR
-	\m[blue]\fBpath = /data/example\fR\m[]
-	\m[blue]\fBvfs objects = smb_traffic_analyzer\fR\m[]
-	\m[blue]\fBsmb_traffic_analyzer:host = examplehost\fR\m[]
-	\m[blue]\fBsmb_traffic_analyzer:port = 3491\fR\m[]
-	
-.fi
-.if n \{\
-.RE
-.\}
-.PP
-The module running on share "example_share", using an internet socket, connecting to host "examplehost" on port 3491, anonymizing user names with the prefix "User"\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-	\fI[example_share]\fR
-	\m[blue]\fBpath = /data/example\fR\m[]
-	\m[blue]\fBvfs objects = smb_traffic_analyzer\fR\m[]
-	\m[blue]\fBsmb_traffic_analyzer:host = examplehost\fR\m[]
-	\m[blue]\fBsmb_traffic_analyzer:port = 3491\fR\m[]
-	\m[blue]\fBsmb_traffic_analyzer:anonymize_prefix = User\fR\m[]
-	
-.fi
-.if n \{\
-.RE
-.\}
-.SH "VERSION"
-.PP
-This man page is correct for version 3\&.3 of the Samba suite\&.
-.SH "AUTHOR"
-.PP
-The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
-.PP
-The original version of the VFS module and the helper tools were created by Holger Hetterich\&.
diff --git a/docs/manpages/vfs_snapper.8 b/docs/manpages/vfs_snapper.8
index 401a35b..b3352a8 100644
--- a/docs/manpages/vfs_snapper.8
+++ b/docs/manpages/vfs_snapper.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_snapper
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_SNAPPER" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_SNAPPER" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_streams_depot.8 b/docs/manpages/vfs_streams_depot.8
index 30238e2..6e28159 100644
--- a/docs/manpages/vfs_streams_depot.8
+++ b/docs/manpages/vfs_streams_depot.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_streams_depot
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_STREAMS_DEPOT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_STREAMS_DEPOT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_streams_xattr.8 b/docs/manpages/vfs_streams_xattr.8
index 609d39e..d23f971 100644
--- a/docs/manpages/vfs_streams_xattr.8
+++ b/docs/manpages/vfs_streams_xattr.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_streams_xattr
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_STREAMS_XATTR" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_STREAMS_XATTR" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_syncops.8 b/docs/manpages/vfs_syncops.8
index a36ff94..1c532d4 100644
--- a/docs/manpages/vfs_syncops.8
+++ b/docs/manpages/vfs_syncops.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_syncops
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_SYNCOPS" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_SYNCOPS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_time_audit.8 b/docs/manpages/vfs_time_audit.8
index 6e422fd..2e837aa 100644
--- a/docs/manpages/vfs_time_audit.8
+++ b/docs/manpages/vfs_time_audit.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_time_audit
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_TIME_AUDIT" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_TIME_AUDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_tsmsm.8 b/docs/manpages/vfs_tsmsm.8
index 973455e..d4593cc 100644
--- a/docs/manpages/vfs_tsmsm.8
+++ b/docs/manpages/vfs_tsmsm.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_tsmsm
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_TSMSM" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_TSMSM" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_unityed_media.8 b/docs/manpages/vfs_unityed_media.8
index a4263ee..c429ac7 100644
--- a/docs/manpages/vfs_unityed_media.8
+++ b/docs/manpages/vfs_unityed_media.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_unityed_media
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_UNITYED_MEDIA" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_UNITYED_MEDIA" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_worm.8 b/docs/manpages/vfs_worm.8
index 9272ca4..342f43f 100644
--- a/docs/manpages/vfs_worm.8
+++ b/docs/manpages/vfs_worm.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_worm
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_WORM" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_WORM" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_xattr_tdb.8 b/docs/manpages/vfs_xattr_tdb.8
index ab5624a..6bb8d76 100644
--- a/docs/manpages/vfs_xattr_tdb.8
+++ b/docs/manpages/vfs_xattr_tdb.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_xattr_tdb
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_XATTR_TDB" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_XATTR_TDB" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_zfsacl.8 b/docs/manpages/vfs_zfsacl.8
index 49761b9..967d85e 100644
--- a/docs/manpages/vfs_zfsacl.8
+++ b/docs/manpages/vfs_zfsacl.8
@@ -2,12 +2,12 @@
 .\"     Title: vfs_zfsacl
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFS_ZFSACL" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "VFS_ZFSACL" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfstest.1 b/docs/manpages/vfstest.1
index aa5f3d5..918ec7c 100644
--- a/docs/manpages/vfstest.1
+++ b/docs/manpages/vfstest.1
@@ -2,12 +2,12 @@
 .\"     Title: vfstest
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "VFSTEST" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "VFSTEST" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/wbinfo.1 b/docs/manpages/wbinfo.1
index b50f729..470e7b2 100644
--- a/docs/manpages/wbinfo.1
+++ b/docs/manpages/wbinfo.1
@@ -2,12 +2,12 @@
 .\"     Title: wbinfo
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: User Commands
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "WBINFO" "1" "02/24/2016" "Samba 4\&.3" "User Commands"
+.TH "WBINFO" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -191,7 +191,7 @@ Attempt to authenticate a user via Kerberos\&.
 .PP
 \-\-krb5ccname \fIKRB5CCNAME\fR
 .RS 4
-Allows to request a sepcific kerberos credential cache type used for authentication\&.
+Allows one to request a sepcific kerberos credential cache type used for authentication\&.
 .RE
 .PP
 \-\-lanman
diff --git a/docs/manpages/winbind_krb5_locator.7 b/docs/manpages/winbind_krb5_locator.7
index b9a7ed6..49bc3d8 100644
--- a/docs/manpages/winbind_krb5_locator.7
+++ b/docs/manpages/winbind_krb5_locator.7
@@ -2,12 +2,12 @@
 .\"     Title: winbind_krb5_locator
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: 7
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "WINBIND_KRB5_LOCATOR" "7" "02/24/2016" "Samba 4\&.3" "7"
+.TH "WINBIND_KRB5_LOCATOR" "7" "03/22/2016" "Samba 4\&.4" "7"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/docs/manpages/winbindd.8 b/docs/manpages/winbindd.8
index 8f30460..9aef6bb 100644
--- a/docs/manpages/winbindd.8
+++ b/docs/manpages/winbindd.8
@@ -2,12 +2,12 @@
 .\"     Title: winbindd
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/24/2016
+.\"      Date: 03/22/2016
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.3
+.\"    Source: Samba 4.4
 .\"  Language: English
 .\"
-.TH "WINBINDD" "8" "02/24/2016" "Samba 4\&.3" "System Administration tools"
+.TH "WINBINDD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/dynconfig/dynconfig.c b/dynconfig/dynconfig.c
index cf35bdb..9614152 100644
--- a/dynconfig/dynconfig.c
+++ b/dynconfig/dynconfig.c
@@ -18,8 +18,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-
 /**
  * @file dynconfig.c
  *
@@ -40,10 +38,9 @@
  * table?  There's kind of a chicken-and-egg situation there...
  **/
 
+#include "replace.h"
 #include "dynconfig.h"
-#ifdef strdup
-#undef strdup
-#endif
+#include "lib/util/memory.h"
 
 #define DEFINE_DYN_CONFIG_PARAM(name) \
 const char *dyn_##name = name; \
diff --git a/dynconfig/wscript b/dynconfig/wscript
index 6410c38..dba74f6 100755
--- a/dynconfig/wscript
+++ b/dynconfig/wscript
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-import string, Logs, Utils, Options, sys, Build, os, intltool, optparse, textwrap
+import string, Logs, Utils, Options, Build, os, optparse, textwrap
 from samba_utils import EXPAND_VARIABLES, os_path_relpath
 
 class SambaIndentedHelpFormatter (optparse.IndentedHelpFormatter):
@@ -374,7 +374,7 @@ def dynconfig_cflags(bld, list=None):
         if list and not varname in list:
             continue
         value = bld.env[varname]
-        if not Options.is_install:
+        if not bld.is_install:
             override = get_override(bld)
             if varname in override:
                 value = os.path.join(bld.env.srcdir, override[varname])
@@ -399,7 +399,7 @@ def pathconfig_entities(bld, list=None):
         if list and not varname in list:
             continue
         value = bld.env[varname]
-        if not Options.is_install:
+        if not bld.is_install:
             override = get_override(bld)
             if varname in override:
                 value = os.path.join(bld.env.srcdir, override[varname])
@@ -412,7 +412,7 @@ def build(bld):
     version_header = 'version.h'
     bld.SAMBA_SUBSYSTEM('DYNCONFIG',
                         'dynconfig.c',
-                        deps='replace talloc',
+                        deps='replace',
                         public_headers=os_path_relpath(os.path.join(Options.launch_dir, version_header), bld.curdir),
                         header_path='samba',
                         cflags=cflags)
diff --git a/examples/VFS/shadow_copy_test.c b/examples/VFS/shadow_copy_test.c
index b3a99ca..05d6e16 100644
--- a/examples/VFS/shadow_copy_test.c
+++ b/examples/VFS/shadow_copy_test.c
@@ -83,6 +83,7 @@ static struct vfs_fn_pointers vfs_test_shadow_copy_fns = {
 	.get_shadow_copy_data_fn = test_get_shadow_copy_data
 };
 
+static_decl_vfs;
 NTSTATUS vfs_shadow_copy_test_init(void)
 {
 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c
index 7021998..a4309d4 100644
--- a/examples/VFS/skel_opaque.c
+++ b/examples/VFS/skel_opaque.c
@@ -54,8 +54,9 @@ static uint64_t skel_disk_free(vfs_handle_struct *handle, const char *path,
 	return 0;
 }
 
-static int skel_get_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype,
-			  unid_t id, SMB_DISK_QUOTA *dq)
+static int skel_get_quota(vfs_handle_struct *handle, const char *path,
+			  enum SMB_QUOTA_TYPE qtype, unid_t id,
+			  SMB_DISK_QUOTA *dq)
 {
 	errno = ENOSYS;
 	return -1;
@@ -961,6 +962,7 @@ struct vfs_fn_pointers skel_opaque_fns = {
 	.set_offline_fn = skel_set_offline
 };
 
+static_decl_vfs;
 NTSTATUS vfs_skel_opaque_init(void)
 {
 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "skel_opaque",
diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c
index 6c6adea..2d1ed79 100644
--- a/examples/VFS/skel_transparent.c
+++ b/examples/VFS/skel_transparent.c
@@ -55,10 +55,11 @@ static uint64_t skel_disk_free(vfs_handle_struct *handle, const char *path,
 	return SMB_VFS_NEXT_DISK_FREE(handle, path, bsize, dfree, dsize);
 }
 
-static int skel_get_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype,
-			  unid_t id, SMB_DISK_QUOTA *dq)
+static int skel_get_quota(vfs_handle_struct *handle, const char *path,
+			  enum SMB_QUOTA_TYPE qtype, unid_t id,
+			  SMB_DISK_QUOTA *dq)
 {
-	return SMB_VFS_NEXT_GET_QUOTA(handle, qtype, id, dq);
+	return SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, dq);
 }
 
 static int skel_set_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype,
@@ -1070,6 +1071,7 @@ struct vfs_fn_pointers skel_transparent_fns = {
 	.set_offline_fn = skel_set_offline
 };
 
+static_decl_vfs;
 NTSTATUS vfs_skel_transparent_init(void)
 {
 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "skel_transparent",
diff --git a/examples/libsmbclient/get_auth_data_fn.h b/examples/libsmbclient/get_auth_data_fn.h
index 6b91c97..5f2be72 100644
--- a/examples/libsmbclient/get_auth_data_fn.h
+++ b/examples/libsmbclient/get_auth_data_fn.h
@@ -16,6 +16,7 @@ get_auth_data_fn(const char * pServer,
     char            workgroup[256] = { '\0' };
     char            username[256] = { '\0' };
     char            password[256] = { '\0' };
+    char           *ret;
 
     static int krb5_set = 1;
 
@@ -36,7 +37,10 @@ get_auth_data_fn(const char * pServer,
     }
 
     fprintf(stdout, "Workgroup: [%s] ", pWorkgroup);
-    fgets(temp, sizeof(temp), stdin);
+    ret = fgets(temp, sizeof(temp), stdin);
+    if (ret == NULL) {
+	    return;
+    }
     
     if (temp[strlen(temp) - 1] == '\n') /* A new line? */
     {
@@ -49,7 +53,10 @@ get_auth_data_fn(const char * pServer,
     }
     
     fprintf(stdout, "Username: [%s] ", pUsername);
-    fgets(temp, sizeof(temp), stdin);
+    ret = fgets(temp, sizeof(temp), stdin);
+    if (ret == NULL) {
+	    return;
+    }
     
     if (temp[strlen(temp) - 1] == '\n') /* A new line? */
     {
@@ -62,7 +69,10 @@ get_auth_data_fn(const char * pServer,
     }
     
     fprintf(stdout, "Password: ");
-    fgets(temp, sizeof(temp), stdin);
+    ret = fgets(temp, sizeof(temp), stdin);
+    if (ret == NULL) {
+	    return;
+    }
     
     if (temp[strlen(temp) - 1] == '\n') /* A new line? */
     {
diff --git a/examples/libsmbclient/teststat.c b/examples/libsmbclient/teststat.c
index f36639e..4084fd0 100644
--- a/examples/libsmbclient/teststat.c
+++ b/examples/libsmbclient/teststat.c
@@ -47,10 +47,10 @@ int main(int argc, char * argv[])
         return 1;
     }
     
-    printf("\nSAMBA\n mtime:%lu/%s ctime:%lu/%s atime:%lu/%s\n",
-           st.st_mtime, ctime_r(&st.st_mtime, m_time),
-           st.st_ctime, ctime_r(&st.st_ctime, c_time),
-           st.st_atime, ctime_r(&st.st_atime, a_time)); 
+    printf("\nSAMBA\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+           (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+           (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+           (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
     
     if (pLocalPath != NULL)
     {
@@ -60,10 +60,10 @@ int main(int argc, char * argv[])
             return 1;
         }
         
-        printf("LOCAL\n mtime:%lu/%s ctime:%lu/%s atime:%lu/%s\n",
-               st.st_mtime, ctime_r(&st.st_mtime, m_time),
-               st.st_ctime, ctime_r(&st.st_ctime, c_time),
-               st.st_atime, ctime_r(&st.st_atime, a_time)); 
+        printf("LOCAL\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+               (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+               (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+               (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
     }
 
     return 0; 
diff --git a/examples/libsmbclient/teststat2.c b/examples/libsmbclient/teststat2.c
index fcd3e30..963cd27 100644
--- a/examples/libsmbclient/teststat2.c
+++ b/examples/libsmbclient/teststat2.c
@@ -47,10 +47,10 @@ static int gettime(const char * pUrl,
                 return 1;
         }
         
-        printf("SAMBA\n mtime:%lu/%s ctime:%lu/%s atime:%lu/%s\n",
-               st.st_mtime, ctime_r(&st.st_mtime, m_time),
-               st.st_ctime, ctime_r(&st.st_ctime, c_time),
-               st.st_atime, ctime_r(&st.st_atime, a_time)); 
+        printf("SAMBA\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+               (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+               (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+               (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
         
         
         /* check the stat on this file */
@@ -60,10 +60,10 @@ static int gettime(const char * pUrl,
                 return 1;
         }
         
-        printf("LOCAL\n mtime:%lu/%s ctime:%lu/%s atime:%lu/%s\n",
-               st.st_mtime, ctime_r(&st.st_mtime, m_time),
-               st.st_ctime, ctime_r(&st.st_ctime, c_time),
-               st.st_atime, ctime_r(&st.st_atime, a_time));
+        printf("LOCAL\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+               (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+               (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+               (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
         
         
         return 0;
diff --git a/examples/libsmbclient/testutime.c b/examples/libsmbclient/testutime.c
index 2b3c40b..cdbcfec 100644
--- a/examples/libsmbclient/testutime.c
+++ b/examples/libsmbclient/testutime.c
@@ -47,10 +47,10 @@ int main(int argc, char * argv[])
         return 1;
     }
     
-    printf("Before\n mtime:%lu/%s ctime:%lu/%s atime:%lu/%s\n",
-           st.st_mtime, ctime_r(&st.st_mtime, m_time),
-           st.st_ctime, ctime_r(&st.st_ctime, c_time),
-           st.st_atime, ctime_r(&st.st_atime, a_time)); 
+    printf("Before\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+           (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+           (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+           (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
     
     utimbuf.actime = t;         /* unchangable (wont change) */
     utimbuf.modtime = t;        /* this one should succeed */
@@ -66,10 +66,10 @@ int main(int argc, char * argv[])
         return 1;
     }
     
-    printf("After\n mtime:%lu/%s ctime:%lu/%s atime:%lu/%s\n",
-           st.st_mtime, ctime_r(&st.st_mtime, m_time),
-           st.st_ctime, ctime_r(&st.st_ctime, c_time),
-           st.st_atime, ctime_r(&st.st_atime, a_time)); 
+    printf("After\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+           (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+           (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+           (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
     
     return 0; 
 }
diff --git a/examples/pdb/test.c b/examples/pdb/test.c
index 5780130..6d68d87 100644
--- a/examples/pdb/test.c
+++ b/examples/pdb/test.c
@@ -107,8 +107,8 @@ static NTSTATUS testsam_init(struct pdb_methods **pdb_method, const char *locati
 	return NT_STATUS_OK;
 }
 
-NTSTATUS pdb_testsam_init(void);
-NTSTATUS pdb_testsam_init(void)
+static_decl_pdb;
+NTSTATUS pdb_test_init(void)
 {
 	return smb_register_passdb(PASSDB_INTERFACE_VERSION, "testsam",
 				   testsam_init);
diff --git a/install_with_python.sh b/install_with_python.sh
index e545ecc..9335cfe 100755
--- a/install_with_python.sh
+++ b/install_with_python.sh
@@ -18,20 +18,39 @@ export LD_LIBRARY_PATH
 VERSION="Python-2.6.5"
 
 do_install_python() {
-       mkdir -p python_install || exit 1
-       rsync -avz samba.org::ftp/tridge/python/$VERSION.tar python_install || exit 1
-       cd python_install || exit 1;
-       rm -rf $VERSION || exit 1
-       tar -xf $VERSION.tar || exit 1
-       cd $VERSION || exit 1
-       ./configure --prefix=$PREFIX/python --enable-shared --disable-ipv6 || exit 1
-       make || exit 1
-       make install || exit 1
-       cd ../.. || exit 1
-       rm -rf python_install || exit 1
+       set -e
+       mkdir -p python_install
+       rsync -avz samba.org::ftp/tridge/python/$VERSION.tar python_install
+       cd python_install
+       rm -rf $VERSION
+
+       # Verify that the download hasn't been corrupted
+       # This checks Python-2.6.5, while more hashes my be added later.
+       if command -v sha256sum
+       then
+            echo "2f1ec5e52d122bf1864529c1bbac7fe6afc10e3a083217b3a7bff5ded37efcc3  Python-2.6.5.tar" > checksums.sha256
+            sha256sum --status -c checksums.sha256
+       else
+            echo "c83cf77f32463c3949b85c94f661c090  Python-2.6.5.tar" > checksums.md5
+            md5sum --status -c checksums.md5
+       fi
+
+       tar -xf $VERSION.tar
+       cd $VERSION
+       ./configure --prefix=$PREFIX/python --enable-shared --disable-ipv6
+       make
+       make install
+       cd ../..
+       rm -rf python_install
+}
+
+cleanup_install_python() {
+       rm -rf python_install
+       exit 1
 }
 
 if [ ! -d $PREFIX/python ]; then
+   trap "cleanup_install_python" 0
    # needs to be installed
    do_install_python
 fi
diff --git a/lib/crypto/REQUIREMENTS b/lib/crypto/REQUIREMENTS
index 4b1e21a..351c2bb 100644
--- a/lib/crypto/REQUIREMENTS
+++ b/lib/crypto/REQUIREMENTS
@@ -35,9 +35,6 @@ AES CFB8
  - SCHANNEL
  - NETLOGON SamLogon session keys
 
-AES 128
- - SMB VFS traffic analyzer
-
  # NETTLE (AES-NI available)
 
 AES128 CCM
diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
index d75c714..a1b98c3 100644
--- a/lib/dbwrap/dbwrap.c
+++ b/lib/dbwrap/dbwrap.c
@@ -395,11 +395,6 @@ int dbwrap_wipe(struct db_context *db)
 	return db->wipe(db);
 }
 
-int dbwrap_hash_size(struct db_context *db)
-{
-	return db->hash_size;
-}
-
 int dbwrap_check(struct db_context *db)
 {
 	if (db->check == NULL) {
@@ -454,9 +449,9 @@ int dbwrap_transaction_cancel(struct db_context *db)
 	return db->transaction_cancel(db);
 }
 
-void dbwrap_db_id(struct db_context *db, const uint8_t **id, size_t *idlen)
+size_t dbwrap_db_id(struct db_context *db, uint8_t *id, size_t idlen)
 {
-	db->id(db, id, idlen);
+	return db->id(db, id, idlen);
 }
 
 bool dbwrap_is_persistent(struct db_context *db)
diff --git a/lib/dbwrap/dbwrap.h b/lib/dbwrap/dbwrap.h
index e081e18..2eded04 100644
--- a/lib/dbwrap/dbwrap.h
+++ b/lib/dbwrap/dbwrap.h
@@ -24,6 +24,7 @@
 #include <talloc.h>
 #include "libcli/util/ntstatus.h"
 #include "tdb.h"
+#include "lib/param/loadparm.h"
 
 struct db_record;
 struct db_context;
@@ -83,17 +84,18 @@ int dbwrap_wipe(struct db_context *db);
 int dbwrap_check(struct db_context *db);
 int dbwrap_get_seqnum(struct db_context *db);
 /* Returns 0 if unknown. */
-int dbwrap_hash_size(struct db_context *db);
 int dbwrap_transaction_start(struct db_context *db);
 NTSTATUS dbwrap_transaction_start_nonblock(struct db_context *db);
 int dbwrap_transaction_commit(struct db_context *db);
 int dbwrap_transaction_cancel(struct db_context *db);
-void dbwrap_db_id(struct db_context *db, const uint8_t **id, size_t *idlen);
+size_t dbwrap_db_id(struct db_context *db, uint8_t *id, size_t idlen);
 bool dbwrap_is_persistent(struct db_context *db);
 const char *dbwrap_name(struct db_context *db);
 
 /* The following definitions come from lib/dbwrap_util.c  */
 
+NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key);
+NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key);
 NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key);
 NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
 			       TDB_DATA data, int flags);
diff --git a/lib/dbwrap/dbwrap_cache.c b/lib/dbwrap/dbwrap_cache.c
index 724389e..e4cee55 100644
--- a/lib/dbwrap/dbwrap_cache.c
+++ b/lib/dbwrap/dbwrap_cache.c
@@ -179,12 +179,13 @@ static int dbwrap_cache_exists(struct db_context *db, TDB_DATA key)
 	return dbwrap_exists(ctx->backing, key);
 }
 
-static void dbwrap_cache_id(struct db_context *db, const uint8_t **id,
-			    size_t *idlen)
+static size_t dbwrap_cache_id(struct db_context *db, uint8_t *id,
+			      size_t idlen)
 {
 	struct db_cache_ctx *ctx = talloc_get_type_abort(
 		db->private_data, struct db_cache_ctx);
-	dbwrap_db_id(ctx->backing, id, idlen);
+
+	return dbwrap_db_id(ctx->backing, id, idlen);
 }
 
 struct db_context *db_open_cache(TALLOC_CTX *mem_ctx,
@@ -222,6 +223,5 @@ struct db_context *db_open_cache(TALLOC_CTX *mem_ctx,
 	db->exists = dbwrap_cache_exists;
 	db->id = dbwrap_cache_id;
 	db->name = dbwrap_name(ctx->backing);
-	db->hash_size = dbwrap_hash_size(ctx->backing);
 	return db;
 }
diff --git a/lib/dbwrap/dbwrap_local_open.c b/lib/dbwrap/dbwrap_local_open.c
index 6509ff9..c350fd3 100644
--- a/lib/dbwrap/dbwrap_local_open.c
+++ b/lib/dbwrap/dbwrap_local_open.c
@@ -34,8 +34,13 @@ struct db_context *dbwrap_local_open(TALLOC_CTX *mem_ctx,
 {
 	struct db_context *db = NULL;
 
-	db = db_open_tdb(mem_ctx, lp_ctx, name, hash_size,
-			 tdb_flags, open_flags, mode,
+	if (hash_size == 0) {
+		hash_size = lpcfg_tdb_hash_size(lp_ctx, name);
+	}
+
+	db = db_open_tdb(mem_ctx, name, hash_size,
+			 lpcfg_tdb_flags(lp_ctx, tdb_flags),
+			 open_flags, mode,
 			 lock_order, dbwrap_flags);
 
 	return db;
diff --git a/lib/dbwrap/dbwrap_private.h b/lib/dbwrap/dbwrap_private.h
index a6bad04..6a52850 100644
--- a/lib/dbwrap/dbwrap_private.h
+++ b/lib/dbwrap/dbwrap_private.h
@@ -58,9 +58,9 @@ struct db_context {
 	int (*exists)(struct db_context *db,TDB_DATA key);
 	int (*wipe)(struct db_context *db);
 	int (*check)(struct db_context *db);
-	void (*id)(struct db_context *db, const uint8_t **id, size_t *idlen);
+	size_t (*id)(struct db_context *db, uint8_t *id, size_t idlen);
+
 	const char *name;
-	int hash_size;
 	void *private_data;
 	enum dbwrap_lock_order lock_order;
 	bool persistent;
diff --git a/lib/dbwrap/dbwrap_rbt.c b/lib/dbwrap/dbwrap_rbt.c
index a9cc641..3b5e589 100644
--- a/lib/dbwrap/dbwrap_rbt.c
+++ b/lib/dbwrap/dbwrap_rbt.c
@@ -514,10 +514,12 @@ static int db_rbt_trans_dummy(struct db_context *db)
 	return 0;
 }
 
-static void db_rbt_id(struct db_context *db, const uint8_t **id, size_t *idlen)
+static size_t db_rbt_id(struct db_context *db, uint8_t *id, size_t idlen)
 {
-	*id = (uint8_t *)db;
-	*idlen = sizeof(struct db_context *);
+	if (idlen >= sizeof(struct db_context *)) {
+		memcpy(id, &db, sizeof(struct db_context *));
+	}
+	return sizeof(struct db_context *);
 }
 
 struct db_context *db_open_rbt(TALLOC_CTX *mem_ctx)
diff --git a/lib/dbwrap/dbwrap_tdb.c b/lib/dbwrap/dbwrap_tdb.c
index 2bc123e..e12ec44 100644
--- a/lib/dbwrap/dbwrap_tdb.c
+++ b/lib/dbwrap/dbwrap_tdb.c
@@ -136,7 +136,7 @@ static struct db_record *db_tdb_fetch_locked_internal(
 
 	talloc_set_destructor(state.result, db_tdb_record_destr);
 
-	state.result->private_data = talloc_reference(state.result, ctx);
+	state.result->private_data = ctx;
 	state.result->store = db_tdb_store;
 	state.result->delete_rec = db_tdb_delete;
 
@@ -388,21 +388,24 @@ static int db_tdb_transaction_cancel(struct db_context *db)
 	return 0;
 }
 
-static void db_tdb_id(struct db_context *db, const uint8_t **id, size_t *idlen)
+static size_t db_tdb_id(struct db_context *db, uint8_t *id, size_t idlen)
 {
 	struct db_tdb_ctx *db_ctx =
 		talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
-	*id = (uint8_t *)&db_ctx->id;
-	*idlen = sizeof(db_ctx->id);
+
+	if (idlen >= sizeof(db_ctx->id)) {
+		memcpy(id, &db_ctx->id, sizeof(db_ctx->id));
+	}
+
+	return sizeof(db_ctx->id);
 }
 
 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
-			       struct loadparm_context *lp_ctx,
 			       const char *name,
 			       int hash_size, int tdb_flags,
 			       int open_flags, mode_t mode,
 			       enum dbwrap_lock_order lock_order,
-			       uint64_t dbrwap_flags)
+			       uint64_t dbwrap_flags)
 {
 	struct db_context *result = NULL;
 	struct db_tdb_ctx *db_tdb;
@@ -421,12 +424,7 @@ struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
 	}
 	result->lock_order = lock_order;
 
-	if (hash_size == 0) {
-		hash_size = lpcfg_tdb_hash_size(lp_ctx, name);
-	}
-
-	db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size,
-				     lpcfg_tdb_flags(lp_ctx, tdb_flags),
+	db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
 				     open_flags, mode);
 	if (db_tdb->wtdb == NULL) {
 		DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
@@ -458,7 +456,6 @@ struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
 	result->id = db_tdb_id;
 	result->check = db_tdb_check;
 	result->name = tdb_name(db_tdb->wtdb->tdb);
-	result->hash_size = hash_size;
 	return result;
 
  fail:
diff --git a/lib/dbwrap/dbwrap_tdb.h b/lib/dbwrap/dbwrap_tdb.h
index 93ee09c..d5f49c7 100644
--- a/lib/dbwrap/dbwrap_tdb.h
+++ b/lib/dbwrap/dbwrap_tdb.h
@@ -25,7 +25,6 @@
 struct db_context;
 
 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
-			       struct loadparm_context *lp_ctx,
 			       const char *name,
 			       int hash_size, int tdb_flags,
 			       int open_flags, mode_t mode,
diff --git a/lib/dbwrap/dbwrap_util.c b/lib/dbwrap/dbwrap_util.c
index 901ef56..22f910d 100644
--- a/lib/dbwrap/dbwrap_util.c
+++ b/lib/dbwrap/dbwrap_util.c
@@ -412,7 +412,8 @@ static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
 
 	status = dbwrap_record_delete(rec);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
+		DBG_INFO("dbwrap_record_delete returned %s\n",
+			 nt_errstr(status));
 	}
 
 	talloc_free(rec);
@@ -527,6 +528,23 @@ NTSTATUS dbwrap_trans_traverse(struct db_context *db,
 	return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
 }
 
+NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key)
+{
+	NTSTATUS status;
+
+	status = dbwrap_delete(db, key);
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+		status = NT_STATUS_OK;
+	}
+
+	return status;
+}
+
+NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key)
+{
+	return dbwrap_purge(db, string_term_tdb_data(key));
+}
+
 NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
 {
 	return dbwrap_delete(db, string_term_tdb_data(key));
diff --git a/lib/dbwrap/wscript_build b/lib/dbwrap/wscript_build
index 195ad4e..b719a60 100644
--- a/lib/dbwrap/wscript_build
+++ b/lib/dbwrap/wscript_build
@@ -1,6 +1,6 @@
 SRC = '''dbwrap.c dbwrap_util.c dbwrap_rbt.c dbwrap_cache.c dbwrap_tdb.c
          dbwrap_local_open.c'''
-DEPS= '''samba-util util_tdb errors tdb tdb-wrap samba-hostconfig'''
+DEPS= '''samba-util util_tdb samba-errors tdb tdb-wrap samba-hostconfig'''
 
 bld.SAMBA_LIBRARY('dbwrap',
                   source=SRC,
diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c
index 22975c1..13984e9 100644
--- a/lib/krb5_wrap/krb5_samba.c
+++ b/lib/krb5_wrap/krb5_samba.c
@@ -143,7 +143,7 @@ bool setup_kaddr( krb5_address *pkaddr, struct sockaddr_storage *paddr)
 *
 * @param context	The krb5_context
 * @param host_princ	The krb5_principal to use
-* @param salt		The optional salt, if ommitted, salt is calculated with
+* @param salt		The optional salt, if omitted, salt is calculated with
 *			the provided principal.
 * @param password	The krb5_data containing the password
 * @param enctype	The krb5_enctype to use for the keyblock generation
@@ -1276,7 +1276,7 @@ krb5_error_code smb_krb5_enctype_to_string(krb5_context context,
 
 /**********************************************************************
  * Open a krb5 keytab with flags, handles readonly or readwrite access and
- * allows to process non-default keytab names.
+ * allows one to process non-default keytab names.
  * @param context krb5_context
  * @param keytab_name_req string
  * @param write_access bool if writable keytab is required
@@ -1717,6 +1717,14 @@ krb5_error_code kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc,
 		return code;
 	}
 
+#ifndef SAMBA4_USES_HEIMDAL /* MIT */
+	/*
+	 * We need to store the principal as returned from the KDC to the
+	 * credentials cache. If we don't do that the KRB5 library is not
+	 * able to find the tickets it is looking for
+	 */
+	principal = my_creds.client;
+#endif
 	code = krb5_cc_initialize(ctx, cc, principal);
 	if (code) {
 		goto done;
@@ -2135,7 +2143,7 @@ krb5_error_code smb_krb5_make_principal(krb5_context context,
 	va_list ap;
 
 	if (_realm) {
-		realm = _realm;
+		realm = discard_const_p(char, _realm);
 		free_realm = false;
 	} else {
 		code = krb5_get_default_realm(context, &realm);
@@ -2316,7 +2324,8 @@ char *smb_krb5_principal_get_realm(krb5_context context,
 	return strdup(discard_const_p(char, krb5_principal_get_realm(context, principal)));
 #elif defined(krb5_princ_realm) /* MIT */
 	krb5_data *realm;
-	realm = krb5_princ_realm(context, principal);
+	realm = discard_const_p(krb5_data,
+				krb5_princ_realm(context, principal));
 	return strndup(realm->data, realm->length);
 #else
 #error UNKNOWN_GET_PRINC_REALM_FUNCTIONS
diff --git a/lib/ldb-samba/ldb_ildap.c b/lib/ldb-samba/ldb_ildap.c
index 6ec363d..65f11db 100644
--- a/lib/ldb-samba/ldb_ildap.c
+++ b/lib/ldb-samba/ldb_ildap.c
@@ -418,11 +418,13 @@ static int ildb_request_send(struct ildb_context *ac, struct ldap_message *msg)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	talloc_free(req->time_event);
-	req->time_event = NULL;
-	if (ac->req->timeout) {
-		req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac,
-						   timeval_current_ofs(ac->req->timeout, 0),
+	TALLOC_FREE(req->time_event);
+	if (ac->req->timeout > 0) {
+		struct timeval tv = {
+			.tv_sec = ac->req->starttime + ac->req->timeout,
+		};
+
+		req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac, tv,
 						   ildb_request_timeout, ac);
 	}
 
diff --git a/lib/ldb-samba/ldb_matching_rules.c b/lib/ldb-samba/ldb_matching_rules.c
new file mode 100644
index 0000000..1692a73
--- /dev/null
+++ b/lib/ldb-samba/ldb_matching_rules.c
@@ -0,0 +1,342 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   ldb database library - Extended match rules
+
+   Copyright (C) 2014 Samuel Cabrero <samuelcabrero at kernevil.me>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <ldb_module.h>
+#include "dsdb/samdb/samdb.h"
+#include "ldb_matching_rules.h"
+
+static int ldb_eval_transitive_filter_helper(TALLOC_CTX *mem_ctx,
+					     struct ldb_context *ldb,
+					     const char *attr,
+					     const struct dsdb_dn *dn_to_match,
+					     const char *dn_oid,
+					     struct dsdb_dn *to_visit,
+					     struct dsdb_dn ***visited,
+					     unsigned int *visited_count,
+					     bool *matched)
+{
+	TALLOC_CTX *tmp_ctx;
+	int ret, i, j;
+	struct ldb_result *res;
+	struct ldb_message *msg;
+	struct ldb_message_element *el;
+	const char *attrs[] = { attr, NULL };
+
+	tmp_ctx = talloc_new(mem_ctx);
+	if (tmp_ctx == NULL) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	/*
+	 * Fetch the entry to_visit
+	 *
+	 * NOTE: This is a new LDB search from the TOP of the module
+	 * stack.  This means that this search runs the whole stack
+	 * from top to bottom.
+	 *
+	 * This may seem to be in-efficient, but it is also the only
+	 * way to ensure that the ACLs for this search are applied
+	 * correctly.
+	 *
+	 * Note also that we don't have the original request
+	 * here, so we can not apply controls or timeouts here.
+	 */
+	ret = dsdb_search_dn(ldb, tmp_ctx, &res, to_visit->dn, attrs, 0);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+	if (res->count != 1) {
+		talloc_free(tmp_ctx);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	msg = res->msgs[0];
+
+	/* Fetch the attribute to match from the entry being visited */
+	el = ldb_msg_find_element(msg, attr);
+	if (el == NULL) {
+		/* This entry does not have the attribute to match */
+		talloc_free(tmp_ctx);
+		*matched = false;
+		return LDB_SUCCESS;
+	}
+
+	/*
+	 * If the value to match is present in the attribute values of the
+	 * current entry being visited, set matched to true and return OK
+	 */
+	for (i=0; i<el->num_values; i++) {
+		struct dsdb_dn *dn;
+		dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], dn_oid);
+		if (dn == NULL) {
+			talloc_free(tmp_ctx);
+			*matched = false;
+			return LDB_ERR_INVALID_DN_SYNTAX;
+		}
+
+		if (ldb_dn_compare(dn_to_match->dn, dn->dn) == 0) {
+			talloc_free(tmp_ctx);
+			*matched = true;
+			return LDB_SUCCESS;
+		}
+	}
+
+	/*
+	 * If arrived here, the value to match is not in the values of the
+	 * entry being visited. Add the entry being visited (to_visit)
+	 * to the visited array. The array is (re)allocated in the parent
+	 * memory context.
+	 */
+	if (visited == NULL) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	} else if (*visited == NULL) {
+		*visited = talloc_array(mem_ctx, struct dsdb_dn *, 1);
+		if (*visited == NULL) {
+			talloc_free(tmp_ctx);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		(*visited)[0] = to_visit;
+		(*visited_count) = 1;
+	} else {
+		*visited = talloc_realloc(mem_ctx, *visited, struct dsdb_dn *,
+					 (*visited_count) + 1);
+		if (*visited == NULL) {
+			talloc_free(tmp_ctx);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		(*visited)[(*visited_count)] = to_visit;
+		(*visited_count)++;
+	}
+
+	/*
+	 * steal to_visit into visited array context, as it has to live until
+	 * the array is freed.
+	 */
+	talloc_steal(*visited, to_visit);
+
+	/*
+	 * Iterate over the values of the attribute of the entry being
+	 * visited (to_visit) and follow them, calling this function
+	 * recursively.
+	 * If the value is in the visited array, skip it.
+	 * Otherwise, follow the link and visit it.
+	 */
+	for (i=0; i<el->num_values; i++) {
+		struct dsdb_dn *next_to_visit;
+		bool skip = false;
+
+		next_to_visit = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], dn_oid);
+		if (next_to_visit == NULL) {
+			talloc_free(tmp_ctx);
+			*matched = false;
+			return LDB_ERR_INVALID_DN_SYNTAX;
+		}
+
+		/*
+		 * If the value is already in the visited array, skip it.
+		 * Note the last element of the array is ignored because it is
+		 * the current entry DN.
+		 */
+		for (j=0; j < (*visited_count) - 1; j++) {
+			struct dsdb_dn *visited_dn = (*visited)[j];
+			if (ldb_dn_compare(visited_dn->dn,
+					   next_to_visit->dn) == 0) {
+				skip = true;
+				break;
+			}
+		}
+		if (skip) {
+			talloc_free(next_to_visit);
+			continue;
+		}
+
+		/* If the value is not in the visited array, evaluate it */
+		ret = ldb_eval_transitive_filter_helper(tmp_ctx, ldb, attr,
+							dn_to_match, dn_oid,
+							next_to_visit,
+							visited, visited_count,
+							matched);
+		if (ret != LDB_SUCCESS) {
+			talloc_free(tmp_ctx);
+			return ret;
+		}
+		if (*matched) {
+			talloc_free(tmp_ctx);
+			return LDB_SUCCESS;
+		}
+	}
+
+	talloc_free(tmp_ctx);
+	*matched = false;
+	return LDB_SUCCESS;
+}
+
+/*
+ * This function parses the linked attribute value to match, whose syntax
+ * will be one of the different DN syntaxes, into a ldb_dn struct.
+ */
+static int ldb_eval_transitive_filter(TALLOC_CTX *mem_ctx,
+				      struct ldb_context *ldb,
+				      const char *attr,
+				      const struct ldb_val *value_to_match,
+				      struct dsdb_dn *current_object_dn,
+				      bool *matched)
+{
+	const struct dsdb_schema *schema;
+	const struct dsdb_attribute *schema_attr;
+	struct dsdb_dn *dn_to_match;
+	const char *dn_oid;
+	unsigned int count;
+	struct dsdb_dn **visited;
+
+	schema = dsdb_get_schema(ldb, mem_ctx);
+	if (schema == NULL) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attr);
+	if (schema_attr == NULL) {
+		return LDB_ERR_NO_SUCH_ATTRIBUTE;
+	}
+
+	/* This is the DN syntax of the attribute being matched */
+	dn_oid = schema_attr->syntax->ldap_oid;
+
+	/*
+	 * Build a ldb_dn struct holding the value to match, which is the
+	 * value entered in the search filter
+	 */
+	dn_to_match = dsdb_dn_parse(mem_ctx, ldb, value_to_match, dn_oid);
+	if (dn_to_match == NULL) {
+		*matched = false;
+		return LDB_SUCCESS;
+	}
+
+	return ldb_eval_transitive_filter_helper(mem_ctx, ldb, attr,
+						 dn_to_match, dn_oid,
+						 current_object_dn,
+						 &visited, &count, matched);
+}
+
+/*
+ * This rule provides recursive search of a link attribute
+ *
+ * Documented in [MS-ADTS] section 3.1.1.3.4.4.3 LDAP_MATCHING_RULE_TRANSITIVE_EVAL
+ * This allows a search filter such as:
+ *
+ * member:1.2.840.113556.1.4.1941:=cn=user,cn=users,dc=samba,dc=example,dc=com
+ *
+ * This searches not only the member attribute, but also any member
+ * attributes that point at an object with this member in them.  All the
+ * various DN syntax types are supported, not just plain DNs.
+ *
+ */
+static int ldb_comparator_trans(struct ldb_context *ldb,
+				const char *oid,
+				const struct ldb_message *msg,
+				const char *attribute_to_match,
+				const struct ldb_val *value_to_match,
+				bool *matched)
+{
+	const struct dsdb_schema *schema;
+	const struct dsdb_attribute *schema_attr;
+	struct ldb_dn *msg_dn;
+	struct dsdb_dn *dsdb_msg_dn;
+	TALLOC_CTX *tmp_ctx;
+	int ret;
+
+	tmp_ctx = talloc_new(ldb);
+	if (tmp_ctx == NULL) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	/*
+	 * If the target attribute to match is not a linked attribute, then
+	 * the filter evaluates to undefined
+	 */
+	schema = dsdb_get_schema(ldb, tmp_ctx);
+	if (schema == NULL) {
+		talloc_free(tmp_ctx);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attribute_to_match);
+	if (schema_attr == NULL) {
+		talloc_free(tmp_ctx);
+		return LDB_ERR_NO_SUCH_ATTRIBUTE;
+	}
+
+	/*
+	 * This extended match filter is only valid for linked attributes,
+	 * following the MS definition (the schema attribute has a linkID
+	 * defined). See dochelp request 114111212024789 on cifs-protocols
+	 * mailing list.
+	 */
+	if (schema_attr->linkID == 0) {
+		*matched = false;
+		talloc_free(tmp_ctx);
+		return LDB_SUCCESS;
+	}
+
+	/* Duplicate original msg dn as the msg must not be modified */
+	msg_dn = ldb_dn_copy(tmp_ctx, msg->dn);
+	if (msg_dn == NULL) {
+		talloc_free(tmp_ctx);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	/*
+	 * Build a dsdb dn from the message copied DN, which should be a plain
+	 * DN syntax.
+	 */
+	dsdb_msg_dn = dsdb_dn_construct(tmp_ctx, msg_dn, data_blob_null,
+					LDB_SYNTAX_DN);
+	if (dsdb_msg_dn == NULL) {
+		*matched = false;
+		return LDB_ERR_INVALID_DN_SYNTAX;
+	}
+
+	ret = ldb_eval_transitive_filter(tmp_ctx, ldb,
+					 attribute_to_match,
+					 value_to_match,
+					 dsdb_msg_dn, matched);
+	talloc_free(tmp_ctx);
+	return ret;
+}
+
+
+int ldb_register_samba_matching_rules(struct ldb_context *ldb)
+{
+	struct ldb_extended_match_rule *transitive_eval;
+	int ret;
+
+	transitive_eval = talloc_zero(ldb, struct ldb_extended_match_rule);
+	transitive_eval->oid = SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL;
+	transitive_eval->callback = ldb_comparator_trans;
+	ret = ldb_register_extended_match_rule(ldb, transitive_eval);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(transitive_eval);
+		return ret;
+	}
+
+	return LDB_SUCCESS;
+}
diff --git a/lib/ldb-samba/ldb_matching_rules.h b/lib/ldb-samba/ldb_matching_rules.h
new file mode 100644
index 0000000..e969b3d
--- /dev/null
+++ b/lib/ldb-samba/ldb_matching_rules.h
@@ -0,0 +1,28 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   ldb database library - Extended match rules
+
+   Copyright (C) 2014 Samuel Cabrero <samuelcabrero at kernevil.me>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LDB_MATCHING_RULES_H_
+#define _LDB_MATCHING_RULES_H_
+
+/* This rule provides recursive search of a link attribute */
+#define SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL	"1.2.840.113556.1.4.1941"
+
+#endif /* _LDB_MATCHING_RULES_H_ */
diff --git a/lib/ldb-samba/ldb_wrap.c b/lib/ldb-samba/ldb_wrap.c
index 05d0451..838306f 100644
--- a/lib/ldb-samba/ldb_wrap.c
+++ b/lib/ldb-samba/ldb_wrap.c
@@ -67,8 +67,12 @@ static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
 	};
 	if (CHECK_DEBUGLVL(samba_level)) {
 		char *s = NULL;
-		vasprintf(&s, fmt, ap);
-		if (!s) return;
+		int ret;
+
+		ret = vasprintf(&s, fmt, ap);
+		if (ret == -1) {
+			return;
+		}
 		DEBUG(samba_level, ("ldb: %s\n", s));
 		free(s);
 	}
diff --git a/lib/ldb-samba/ldif_handlers.c b/lib/ldb-samba/ldif_handlers.c
index 65f1d88..3b84084 100644
--- a/lib/ldb-samba/ldif_handlers.c
+++ b/lib/ldb-samba/ldif_handlers.c
@@ -1697,6 +1697,12 @@ int ldb_register_samba_handlers(struct ldb_context *ldb)
 
 	}
 
+	ret = ldb_register_samba_matching_rules(ldb);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(ldb);
+		return LDB_SUCCESS;
+	}
+
 	ret = ldb_set_opaque(ldb, "SAMBA_HANDLERS_REGISTERED", (void*)1);
 	if (ret != LDB_SUCCESS) {
 		return ret;
diff --git a/lib/ldb-samba/tests/match_rules.py b/lib/ldb-samba/tests/match_rules.py
index 6b31392..9c92b8b 100755
--- a/lib/ldb-samba/tests/match_rules.py
+++ b/lib/ldb-samba/tests/match_rules.py
@@ -14,20 +14,24 @@ from samba.dcerpc import security, misc
 from samba.samdb import SamDB
 from samba.auth import system_session
 from samba.ndr import ndr_unpack
-from ldb import Message, MessageElement, Dn
+from ldb import Message, MessageElement, Dn, LdbError
 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
-from ldb import SCOPE_BASE, SCOPE_SUBTREE
+from ldb import SCOPE_BASE, SCOPE_SUBTREE, SCOPE_ONELEVEL
 
+# TODO I'm ignoring case in these tests for now.
+#       This should be fixed to work inline with Windows.
+#       The literal strings are in the case Windows uses.
+# Windows appear to preserve casing of the RDN and uppercase the other keys.
 class MatchRulesTests(samba.tests.TestCase):
     def setUp(self):
         super(MatchRulesTests, self).setUp()
         self.lp = lp
         self.ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp)
         self.base_dn = self.ldb.domain_dn()
-        self.ou = "ou=matchrulestest,%s" % self.base_dn
-        self.ou_users = "ou=users,%s" % self.ou
-        self.ou_groups = "ou=groups,%s" % self.ou
-        self.ou_computers = "ou=computers,%s" % self.ou
+        self.ou = "OU=matchrulestest,%s" % self.base_dn
+        self.ou_users = "OU=users,%s" % self.ou
+        self.ou_groups = "OU=groups,%s" % self.ou
+        self.ou_computers = "OU=computers,%s" % self.ou
 
         # Add a organizational unit to create objects
         self.ldb.add({
@@ -98,10 +102,10 @@ class MatchRulesTests(samba.tests.TestCase):
             "dn": "cn=g2,%s" % self.ou_groups,
             "objectclass": "group" })
         self.ldb.add({
-            "dn": "cn=g3,%s" % self.ou_groups,
+            "dn": "cn=g4,%s" % self.ou_groups,
             "objectclass": "group" })
         self.ldb.add({
-            "dn": "cn=g4,%s" % self.ou_groups,
+            "dn": "cn=g3,%s" % self.ou_groups,
             "objectclass": "group" })
 
         # Add four users
@@ -155,14 +159,14 @@ class MatchRulesTests(samba.tests.TestCase):
 
         # u1 member of g1
         m = Message()
-        m.dn = Dn(self.ldb, "cn=g1,%s" % self.ou_groups)
-        m["member"] = MessageElement("cn=u1,%s" % self.ou_users,
+        m.dn = Dn(self.ldb, "CN=g1,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=u1,%s" % self.ou_users,
                                      FLAG_MOD_ADD, "member")
         self.ldb.modify(m)
 
         # u2 member of g2
         m = Message()
-        m.dn = Dn(self.ldb, "cn=g2,%s" % self.ou_groups)
+        m.dn = Dn(self.ldb, "CN=g2,%s" % self.ou_groups)
         m["member"] = MessageElement("cn=u2,%s" % self.ou_users,
                                      FLAG_MOD_ADD, "member")
         self.ldb.modify(m)
@@ -170,7 +174,7 @@ class MatchRulesTests(samba.tests.TestCase):
         # u3 member of g3
         m = Message()
         m.dn = Dn(self.ldb, "cn=g3,%s" % self.ou_groups)
-        m["member"] = MessageElement("cn=u3,%s" % self.ou_users,
+        m["member"] = MessageElement("CN=u3,%s" % self.ou_users,
                                      FLAG_MOD_ADD, "member")
         self.ldb.modify(m)
 
@@ -183,7 +187,7 @@ class MatchRulesTests(samba.tests.TestCase):
 
         # g3 member of g4
         m = Message()
-        m.dn = Dn(self.ldb, "cn=g4,%s" % self.ou_groups)
+        m.dn = Dn(self.ldb, "CN=g4,%s" % self.ou_groups)
         m["member"] = MessageElement("cn=g3,%s" % self.ou_groups,
                                      FLAG_MOD_ADD, "member")
         self.ldb.modify(m)
@@ -191,7 +195,7 @@ class MatchRulesTests(samba.tests.TestCase):
         # g2 member of g3
         m = Message()
         m.dn = Dn(self.ldb, "cn=g3,%s" % self.ou_groups)
-        m["member"] = MessageElement("cn=g2,%s" % self.ou_groups,
+        m["member"] = MessageElement("CN=g2,%s" % self.ou_groups,
                                      FLAG_MOD_ADD, "member")
         self.ldb.modify(m)
 
@@ -294,97 +298,159 @@ class MatchRulesTests(samba.tests.TestCase):
         res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
                         scope=SCOPE_BASE,
                         expression="member=cn=u1,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 0)
+        self.assertEqual(len(res1), 0)
 
         res1 = self.ldb.search("cn=u1,%s" % self.ou_users,
                         scope=SCOPE_BASE,
                         expression="memberOf=cn=g4,%s" % self.ou_groups)
-        self.assertTrue(len(res1) == 0)
+        self.assertEqual(len(res1), 0)
 
         # Search with transitive match must return 1 results
         res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
                         scope=SCOPE_BASE,
                         expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
 
         res1 = self.ldb.search("cn=u1,%s" % self.ou_users,
                         scope=SCOPE_BASE,
                         expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=u1,%s" % self.ou_users).lower())
 
     def test_g1_member_of_g4(self):
         # Search without transitive match must return 0 results
         res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
                         scope=SCOPE_BASE,
                         expression="member=cn=g1,%s" % self.ou_groups)
-        self.assertTrue(len(res1) == 0)
+        self.assertEqual(len(res1), 0)
 
         res1 = self.ldb.search("cn=g1,%s" % self.ou_groups,
                         scope=SCOPE_BASE,
                         expression="memberOf=cn=g4,%s" % self.ou_groups)
-        self.assertTrue(len(res1) == 0)
+        self.assertEqual(len(res1), 0)
 
         # Search with transitive match must return 1 results
         res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
                         scope=SCOPE_BASE,
                         expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
 
         res1 = self.ldb.search("cn=g1,%s" % self.ou_groups,
                         scope=SCOPE_BASE,
                         expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g1,%s" % self.ou_groups).lower())
 
     def test_u1_groups(self):
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member=cn=u1,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g1,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_users,
+                        scope=SCOPE_SUBTREE,
+                        expression="member=cn=u1,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
 
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 4)
+        self.assertEqual(len(res1), 4)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_users,
+                        scope=SCOPE_SUBTREE,
+                        expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
 
     def test_u2_groups(self):
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member=cn=u2,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g2,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_users,
+                        scope=SCOPE_SUBTREE,
+                        expression="member=cn=u2,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
 
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member:1.2.840.113556.1.4.1941:=cn=u2,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 3)
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_users,
+                        scope=SCOPE_SUBTREE,
+                        expression="member:1.2.840.113556.1.4.1941:=cn=u2,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
 
     def test_u3_groups(self):
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member=cn=u3,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g3,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_users,
+                        scope=SCOPE_SUBTREE,
+                        expression="member=cn=u3,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
 
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member:1.2.840.113556.1.4.1941:=cn=u3,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 2)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_users,
+                        scope=SCOPE_SUBTREE,
+                        expression="member:1.2.840.113556.1.4.1941:=cn=u3,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
 
     def test_u4_groups(self):
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member=cn=u4,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_users,
+                        scope=SCOPE_SUBTREE,
+                        expression="member=cn=u4,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
 
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member:1.2.840.113556.1.4.1941:=cn=u4,%s" % self.ou_users)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_users,
+                        scope=SCOPE_SUBTREE,
+                        expression="member:1.2.840.113556.1.4.1941:=cn=u4,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
 
-    def test_extended_dn(self):
+    def test_extended_dn_u1(self):
         res1 = self.ldb.search("cn=u1,%s" % self.ou_users,
                         scope=SCOPE_BASE,
                         expression="objectClass=*",
                         attrs=['objectSid', 'objectGUID'])
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("cn=u1,%s" % self.ou_users).lower())
 
         sid = self.ldb.schema_format_value("objectSid", res1[0]["objectSid"][0])
         guid = self.ldb.schema_format_value("objectGUID", res1[0]['objectGUID'][0])
@@ -392,66 +458,1323 @@ class MatchRulesTests(samba.tests.TestCase):
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member=<SID=%s>" % sid)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g1,%s" % self.ou_groups).lower())
 
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member=<GUID=%s>" % guid)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g1,%s" % self.ou_groups).lower())
 
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
-        self.assertTrue(len(res1) == 4)
+        self.assertEqual(len(res1), 4)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_ONELEVEL,
+                        expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 4)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
 
         res1 = self.ldb.search(self.ou_groups,
                         scope=SCOPE_SUBTREE,
                         expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
-        self.assertTrue(len(res1) == 4)
+        self.assertEqual(len(res1), 4)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_ONELEVEL,
+                        expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 4)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+    def test_extended_dn_u2(self):
+        res1 = self.ldb.search("cn=u2,%s" % self.ou_users,
+                        scope=SCOPE_BASE,
+                        expression="objectClass=*",
+                        attrs=['objectSid', 'objectGUID'])
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("cn=u2,%s" % self.ou_users).lower())
+
+        sid = self.ldb.schema_format_value("objectSid", res1[0]["objectSid"][0])
+        guid = self.ldb.schema_format_value("objectGUID", res1[0]['objectGUID'][0])
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_SUBTREE,
+                        expression="member=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g2,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_SUBTREE,
+                        expression="member=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g2,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_SUBTREE,
+                        expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_ONELEVEL,
+                        expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_SUBTREE,
+                        expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_ONELEVEL,
+                        expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+    def test_extended_dn_u3(self):
+        res1 = self.ldb.search("cn=u3,%s" % self.ou_users,
+                        scope=SCOPE_BASE,
+                        expression="objectClass=*",
+                        attrs=['objectSid', 'objectGUID'])
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("cn=u3,%s" % self.ou_users).lower())
+
+        sid = self.ldb.schema_format_value("objectSid", res1[0]["objectSid"][0])
+        guid = self.ldb.schema_format_value("objectGUID", res1[0]['objectGUID'][0])
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_SUBTREE,
+                        expression="member=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g3,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_SUBTREE,
+                        expression="member=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g3,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_ONELEVEL,
+                                expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_SUBTREE,
+                        expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                        scope=SCOPE_ONELEVEL,
+                        expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+        self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+    def test_extended_dn_u4(self):
+        res1 = self.ldb.search("cn=u4,%s" % self.ou_users,
+                                scope=SCOPE_BASE,
+                                expression="objectClass=*",
+                                attrs=['objectSid', 'objectGUID'])
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("cn=u4,%s" % self.ou_users).lower())
+
+        sid = self.ldb.schema_format_value("objectSid", res1[0]["objectSid"][0])
+        guid = self.ldb.schema_format_value("objectGUID", res1[0]['objectGUID'][0])
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_ONELEVEL,
+                                expression="member=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_ONELEVEL,
+                                expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_ONELEVEL,
+                                expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
 
     def test_object_dn_binary(self):
         res1 = self.ldb.search(self.ou_computers,
                         scope=SCOPE_SUBTREE,
                         expression="msDS-RevealedUsers=B:8:01010101:cn=c3,%s" % self.ou_computers)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=c2,%s" % self.ou_computers).lower())
+
+        res1 = self.ldb.search(self.ou_computers,
+                        scope=SCOPE_ONELEVEL,
+                        expression="msDS-RevealedUsers=B:8:01010101:cn=c3,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=c2,%s" % self.ou_computers).lower())
 
         res1 = self.ldb.search(self.ou_computers,
                         scope=SCOPE_SUBTREE,
                         expression="msDS-RevealedUsers:1.2.840.113556.1.4.1941:=B:8:01010101:cn=c3,%s" % self.ou_computers)
-        self.assertTrue(len(res1) == 2)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=c1,%s" % self.ou_computers).lower() in dn_list)
+        self.assertTrue(("CN=c2,%s" % self.ou_computers).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou_computers,
+                        scope=SCOPE_ONELEVEL,
+                        expression="msDS-RevealedUsers:1.2.840.113556.1.4.1941:=B:8:01010101:cn=c3,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=c1,%s" % self.ou_computers).lower() in dn_list)
+        self.assertTrue(("CN=c2,%s" % self.ou_computers).lower() in dn_list)
 
     def test_one_way_links(self):
         res1 = self.ldb.search(self.ou,
                         scope=SCOPE_SUBTREE,
                         expression="addressBookRoots2=cn=c1,%s" % self.ou_computers)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=e2,%s" % self.ou).lower())
+
+        res1 = self.ldb.search(self.ou,
+                        scope=SCOPE_ONELEVEL,
+                        expression="addressBookRoots2=cn=c1,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), ("CN=e2,%s" % self.ou).lower())
 
         res1 = self.ldb.search(self.ou,
                         scope=SCOPE_SUBTREE,
                         expression="addressBookRoots2:1.2.840.113556.1.4.1941:=cn=c1,%s" % self.ou_computers)
-        self.assertTrue(len(res1) == 2)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=e1,%s" % self.ou).lower() in dn_list)
+        self.assertTrue(("CN=e1,%s" % self.ou).lower() in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                        scope=SCOPE_ONELEVEL,
+                        expression="addressBookRoots2:1.2.840.113556.1.4.1941:=cn=c1,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn).lower() for res in res1]
+        self.assertTrue(("CN=e1,%s" % self.ou).lower() in dn_list)
+        self.assertTrue(("CN=e1,%s" % self.ou).lower() in dn_list)
 
     def test_not_linked_attrs(self):
         res1 = self.ldb.search(self.base_dn,
                         scope=SCOPE_BASE,
                         expression="wellKnownObjects=B:32:aa312825768811d1aded00c04fd8d5cd:CN=computers,%s" % self.base_dn)
-        self.assertTrue(len(res1) == 1)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn).lower(), self.base_dn.lower())
 
+    def test_invalid_basedn(self):
         res1 = self.ldb.search(self.base_dn,
-                        scope=SCOPE_BASE,
-                        expression="wellKnownObjects:1.2.840.113556.1.4.1941:=B:32:aa312825768811d1aded00c04fd8d5cd:CN=computers,%s" % self.base_dn)
-        self.assertTrue(len(res1) == 0)
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=c1,ou=computers,ou=matchrulestest,%sXX" % self.base_dn)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.base_dn,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=XX,ou=computers,ou=matchrulestest,%s" % self.base_dn)
+        self.assertEqual(len(res1), 0)
+
+    def test_subtree(self):
+	    res1 = self.ldb.search(self.ou,
+			    scope=SCOPE_SUBTREE,
+			    expression="otherWellKnownObjects=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
+	    self.assertEqual(len(res1), 1)
+	    self.assertEqual(str(res1[0].dn).lower(), ("OU=o3,OU=o2,OU=o1,%s" % self.ou).lower())
+
+	    res1 = self.ldb.search(self.ou,
+			    scope=SCOPE_ONELEVEL,
+			    expression="otherWellKnownObjects=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
+	    self.assertEqual(len(res1), 0)
+
+	    res1 = self.ldb.search(self.ou,
+			    scope=SCOPE_SUBTREE,
+			    expression="otherWellKnownObjects:1.2.840.113556.1.4.1941:=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
+	    self.assertEqual(len(res1), 0)
+
+	    res1 = self.ldb.search(self.ou,
+			    scope=SCOPE_ONELEVEL,
+			    expression="otherWellKnownObjects:1.2.840.113556.1.4.1941:=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
+	    self.assertEqual(len(res1), 0)
+
+    def test_unknown_oid(self):
+        res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="member:2.4.681.226012.2.8.3882:=cn=u1,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="member:8.16.8720.1008448.8.32.15528:=cn=u1,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="member:1.2.3.4:=cn=u1,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
+
+    def test_nul_text(self):
+        self.assertRaises(TypeError, lambda: self.ldb.search("cn=g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="\00member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users))
+        self.assertRaises(TypeError, lambda: self.ldb.search("cn=g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member:1.2.840\00.113556.1.4.1941:=cn=u1,%s" % self.ou_users))
+        self.assertRaises(TypeError, lambda: self.ldb.search("cn=g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member:1.2.840.113556.1.4.1941:=cn=u1\00,%s" % self.ou_users))
+        self.assertRaises(LdbError, lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users))
+        self.assertRaises(LdbError, lambda: self.ldb.search("cn=g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member:1.2.840.113556.1.4.1941:"))
+        res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member:1.2.840.113556.1.4.1941:=")
+        self.assertEqual(len(res1), 0)
+        res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member=")
+        self.assertEqual(len(res1), 0)
+        res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member:1.2.840.113556.1.4.1941:=nonexistent")
+        self.assertEqual(len(res1), 0)
+        res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member=nonexistent")
+        self.assertEqual(len(res1), 0)
+        self.assertRaises(LdbError, lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member:1.2.840.113556.1.4.1941:cn=u1,%s" % self.ou_users))
+        self.assertRaises(LdbError, lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member:1.2.840.113556.1.4.1941:=cn=u1"))
+        self.assertRaises(LdbError, lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member:1.2.840.113556.1.4.1941:=cn="))
+        self.assertRaises(LdbError, lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+                            scope=SCOPE_BASE,
+                            expression="member::=cn=u1,%s" % self.ou_users))
+
+    def test_misc_matches(self):
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="member=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search("cn=g1,%s" % self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="member=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), "CN=g2,%s" % self.ou_groups)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_ONELEVEL,
+                                expression="member=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), "CN=g2,%s" % self.ou_groups)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search("cn=g1,%s" % self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_ONELEVEL,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_ONELEVEL,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="memberOf=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="memberOf=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), ("CN=g3,%s" % self.ou_groups))
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_ONELEVEL,
+                                expression="memberOf=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), ("CN=g3,%s" % self.ou_groups))
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+                                scope=SCOPE_BASE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_ONELEVEL,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
 
+        res1 = self.ldb.search(self.ou_groups,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+        self.assertEqual(len(res1), 0)
+
+class MatchRuleConditionTests(samba.tests.TestCase):
+    def setUp(self):
+        super(MatchRuleConditionTests, self).setUp()
+        self.lp = lp
+        self.ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp)
+        self.base_dn = self.ldb.domain_dn()
+        self.ou = "OU=matchruleconditiontests,%s" % self.base_dn
+        self.ou_users = "OU=users,%s" % self.ou
+        self.ou_groups = "OU=groups,%s" % self.ou
+        self.ou_computers = "OU=computers,%s" % self.ou
+
+        # Add a organizational unit to create objects
+        self.ldb.add({
+            "dn": self.ou,
+            "objectclass": "organizationalUnit"})
 
-	res1 = self.ldb.search(self.ou,
-			scope=SCOPE_SUBTREE,
-			expression="otherWellKnownObjects=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
-	self.assertTrue(len(res1) == 1)
+        # Create users, groups, and computers
+        self.ldb.add({
+            "dn": self.ou_users,
+            "objectclass": "organizationalUnit"})
+        self.ldb.add({
+            "dn": self.ou_groups,
+            "objectclass": "organizationalUnit"})
+        self.ldb.add({
+            "dn": self.ou_computers,
+            "objectclass": "organizationalUnit"})
 
-	res1 = self.ldb.search(self.ou,
-			scope=SCOPE_SUBTREE,
-			expression="otherWellKnownObjects:1.2.840.113556.1.4.1941:=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
-	self.assertTrue(len(res1) == 0)
+        self.ldb.add({
+            "dn": "cn=g1,%s" % self.ou_groups,
+            "objectclass": "group" })
+        self.ldb.add({
+            "dn": "cn=g2,%s" % self.ou_groups,
+            "objectclass": "group" })
+        self.ldb.add({
+            "dn": "cn=g3,%s" % self.ou_groups,
+            "objectclass": "group" })
+        self.ldb.add({
+            "dn": "cn=g4,%s" % self.ou_groups,
+            "objectclass": "group" })
+
+        self.ldb.add({
+            "dn": "cn=u1,%s" % self.ou_users,
+            "objectclass": "group"})
+        self.ldb.add({
+            "dn": "cn=u2,%s" % self.ou_users,
+            "objectclass": "group"})
+        self.ldb.add({
+            "dn": "cn=u3,%s" % self.ou_users,
+            "objectclass": "group"})
+        self.ldb.add({
+            "dn": "cn=u4,%s" % self.ou_users,
+            "objectclass": "group"})
+
+        self.ldb.add({
+            "dn": "cn=c1,%s" % self.ou_computers,
+            "objectclass": "user"})
+
+        self.ldb.add({
+            "dn": "cn=c2,%s" % self.ou_computers,
+            "objectclass": "user"})
+
+        self.ldb.add({
+            "dn": "cn=c3,%s" % self.ou_computers,
+            "objectclass": "user"})
+
+        self.ldb.add({
+            "dn": "cn=c4,%s" % self.ou_computers,
+            "objectclass": "user"})
+
+        # Assign groups according to the following structure:
+        #  g1-->g2---->g3   --g4
+        #     \  |    / |  / / |
+        #  u1- >u2-- | u3<- | u4
+        #     \     \ \      \ |
+        #  c1* >c2   ->c3     c4
+        # *c1 is a member of u1, u2, u3, and u4
+
+        # u2 is a member of g1 and g2
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=g1,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=u2,%s" % self.ou_users,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=g2,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=u2,%s" % self.ou_users,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        # g2 is a member of g1
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=g1,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=g2,%s" % self.ou_groups,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        # g3 is a member of g2
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=g2,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=g3,%s" % self.ou_groups,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        # u3 is a member of g3 and g4
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=g3,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=u3,%s" % self.ou_users,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=g4,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=u3,%s" % self.ou_users,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        # u4 is a member of g4
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=g4,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=u4,%s" % self.ou_users,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        # c1 is a member of u1, u2, u3, and u4
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=u1,%s" % self.ou_users)
+        m["member"] = MessageElement("CN=c1,%s" % self.ou_computers,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=u2,%s" % self.ou_users)
+        m["member"] = MessageElement("CN=c1,%s" % self.ou_computers,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=u3,%s" % self.ou_users)
+        m["member"] = MessageElement("CN=c1,%s" % self.ou_computers,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=u4,%s" % self.ou_users)
+        m["member"] = MessageElement("CN=c1,%s" % self.ou_computers,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        # c2 is a member of u1
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=u1,%s" % self.ou_users)
+        m["member"] = MessageElement("CN=c2,%s" % self.ou_computers,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        # c3 is a member of u2 and g3
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=u2,%s" % self.ou_users)
+        m["member"] = MessageElement("CN=c3,%s" % self.ou_computers,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=g3,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=c3,%s" % self.ou_computers,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        # c4 is a member of u4 and g4
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=u4,%s" % self.ou_users)
+        m["member"] = MessageElement("CN=c4,%s" % self.ou_computers,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        m = Message()
+        m.dn = Dn(self.ldb, "CN=g4,%s" % self.ou_groups)
+        m["member"] = MessageElement("CN=c4,%s" % self.ou_computers,
+                                     FLAG_MOD_ADD, "member")
+        self.ldb.modify(m)
+
+        self.question = 6*(9-2)
+        self.answer = 42
+
+    def tearDown(self):
+        super(MatchRuleConditionTests, self).tearDown()
+        delete_force(self.ldb, "cn=u4,%s" % self.ou_users)
+        delete_force(self.ldb, "cn=u3,%s" % self.ou_users)
+        delete_force(self.ldb, "cn=u2,%s" % self.ou_users)
+        delete_force(self.ldb, "cn=u1,%s" % self.ou_users)
+        delete_force(self.ldb, "cn=g4,%s" % self.ou_groups)
+        delete_force(self.ldb, "cn=g3,%s" % self.ou_groups)
+        delete_force(self.ldb, "cn=g2,%s" % self.ou_groups)
+        delete_force(self.ldb, "cn=g1,%s" % self.ou_groups)
+        delete_force(self.ldb, "cn=c1,%s" % self.ou_computers)
+        delete_force(self.ldb, "cn=c2,%s" % self.ou_computers)
+        delete_force(self.ldb, "cn=c3,%s" % self.ou_computers)
+        delete_force(self.ldb, "cn=c4,%s" % self.ou_computers)
+        delete_force(self.ldb, self.ou_users)
+        delete_force(self.ldb, self.ou_groups)
+        delete_force(self.ldb, self.ou_computers)
+        delete_force(self.ldb, self.ou)
+
+
+    def test_g1_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=g1,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 6)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=g1,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 0)
+
+    def test_g2_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=g2,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 5)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=g2,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 1)
+        self.assertEquals(str(res1[0].dn), "CN=g1,%s" % self.ou_groups)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g2,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 1)
+        self.assertEquals(str(res1[0].dn), "CN=g1,%s" % self.ou_groups)
+
+    def test_g3_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=g3,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=g3,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 1)
+        self.assertEquals(str(res1[0].dn), "CN=g2,%s" % self.ou_groups)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g3,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+
+    def test_g4_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=g4,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 4)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=g4,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+        self.assertEquals(len(res1), 0)
+
+    def test_u1_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=u1,%s" % self.ou_users)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c2,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c2,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=u1,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+        self.assertEqual(len(res1), 0)
+
+    def test_u2_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=u2,%s" % self.ou_users)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=u2,%s" % self.ou_users)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=u2,%s" % self.ou_users)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=u2,%s" % self.ou_users)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+
+    def test_u3_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=u3,%s" % self.ou_users)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=u3,%s" % self.ou_users)
+        self.assertEqual(len(res1), 4)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=u3,%s" % self.ou_users)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), "CN=c1,%s" % self.ou_computers)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=u3,%s" % self.ou_users)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), "CN=c1,%s" % self.ou_computers)
+
+    def test_u4_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=u4,%s" % self.ou_users)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), "CN=g4,%s" % self.ou_groups)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=u4,%s" % self.ou_users)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), "CN=g4,%s" % self.ou_groups)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=u4,%s" % self.ou_users)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=u4,%s" % self.ou_users)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+    def test_c1_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=c1,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 4)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=c1,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 8)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=c1,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=c1,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 0)
+
+    def test_c2_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=c2,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), "CN=u1,%s" % self.ou_users)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=c2,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), "CN=u1,%s" % self.ou_users)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=c2,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=c2,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 0)
+
+    def test_c3_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=c3,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=c3,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 4)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=c3,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=c3,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 0)
+
+    def test_c4_members(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member=cn=c4,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="member:1.2.840.113556.1.4.1941:=cn=c4,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf=cn=c4,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression="memberOf:1.2.840.113556.1.4.1941:=cn=c4,%s" % self.ou_computers)
+        self.assertEqual(len(res1), 0)
+
+    def test_or_member_queries(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(member:1.2.840.113556.1.4.1941:=cn=c1,%s)"
+                                            "(member:1.2.840.113556.1.4.1941:=cn=c2,%s))") % (
+                                            self.ou_computers, self.ou_computers))
+        self.assertEqual(len(res1), 8)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(member:1.2.840.113556.1.4.1941:=cn=c2,%s)"
+                                            "(member:1.2.840.113556.1.4.1941:=cn=c3,%s))") % (
+                                            self.ou_computers, self.ou_computers))
+        self.assertEqual(len(res1), 5)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(member:1.2.840.113556.1.4.1941:=cn=c2,%s)"
+                                            "(member:1.2.840.113556.1.4.1941:=cn=c4,%s))") % (
+                                            self.ou_computers, self.ou_computers))
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(member:1.2.840.113556.1.4.1941:=cn=c3,%s)"
+                                            "(member:1.2.840.113556.1.4.1941:=cn=c4,%s))") % (
+                                            self.ou_computers, self.ou_computers))
+        self.assertEqual(len(res1), 6)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(member:1.2.840.113556.1.4.1941:=cn=u1,%s)"
+                                            "(member:1.2.840.113556.1.4.1941:=cn=c4,%s))") % (
+                                            self.ou_users, self.ou_computers))
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+    def test_and_member_queries(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(member:1.2.840.113556.1.4.1941:=cn=c1,%s)"
+                                            "(member:1.2.840.113556.1.4.1941:=cn=c2,%s))") % (
+                                            self.ou_computers, self.ou_computers))
+        self.assertEqual(len(res1), 1)
+        self.assertEqual(str(res1[0].dn), "CN=u1,%s" % self.ou_users)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(member:1.2.840.113556.1.4.1941:=cn=c2,%s)"
+                                            "(member:1.2.840.113556.1.4.1941:=cn=c3,%s))") % (
+                                            self.ou_computers, self.ou_computers))
+        self.assertEqual(len(res1), 0)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(member:1.2.840.113556.1.4.1941:=cn=c3,%s)"
+                                            "(member:1.2.840.113556.1.4.1941:=cn=u3,%s))") % (
+                                            self.ou_computers, self.ou_users))
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(member:1.2.840.113556.1.4.1941:=cn=c1,%s)"
+                                            "(member:1.2.840.113556.1.4.1941:=cn=u4,%s))") % (
+                                            self.ou_computers, self.ou_computers))
+        self.assertEqual(len(res1), 0)
+
+    def test_or_memberOf_queries(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 6)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 6)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 8)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s))") %
+                                            (self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 5)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 7)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 5)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+    def test_and_memberOf_queries(self):
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 5)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 3)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+        self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+                                            self.ou_groups, self.ou_groups))
+        self.assertEqual(len(res1), 2)
+        dn_list = [str(res.dn) for res in res1]
+        self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+        self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+
+        res1 = self.ldb.search(self.ou,
+                                scope=SCOPE_SUBTREE,
+                                expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+                                            "(memberOf:1.2.840.113556.1.4.1941:=cn=c1,%s))") % (
+                                            self.ou_groups, self.ou_computers))
+        self.assertEqual(len(res1), 0)
 
 parser = optparse.OptionParser("match_rules.py [options] <host>")
 sambaopts = options.SambaOptions(parser)
diff --git a/lib/ldb-samba/wscript_build b/lib/ldb-samba/wscript_build
index 7016b2f..3625f8b 100644
--- a/lib/ldb-samba/wscript_build
+++ b/lib/ldb-samba/wscript_build
@@ -5,10 +5,10 @@
 # the symbols of all of ldb_ildap's dependencies. 
 
 bld.SAMBA_LIBRARY('ldbsamba',
-                  source='ldif_handlers.c',
+                  source='ldif_handlers.c ldb_matching_rules.c',
                   autoproto='ldif_handlers_proto.h',
                   public_deps='ldb',
-                  deps='samba-security ndr NDR_DRSBLOBS NDR_DNSP ldbwrap samdb-common SAMDB_SCHEMA tdb errors',
+                  deps='samba-security ndr NDR_DRSBLOBS NDR_DNSP ldbwrap samdb-common SAMDB_SCHEMA tdb samba-errors',
                   private_library=True
                   )
 
diff --git a/lib/ldb/ABI/ldb-1.1.22.sigs b/lib/ldb/ABI/ldb-1.1.22.sigs
new file mode 100644
index 0000000..6d9767b
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.22.sigs
@@ -0,0 +1,264 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.23.sigs b/lib/ldb/ABI/ldb-1.1.23.sigs
new file mode 100644
index 0000000..6d9767b
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.23.sigs
@@ -0,0 +1,264 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.24.sigs b/lib/ldb/ABI/ldb-1.1.24.sigs
new file mode 100644
index 0000000..6d9767b
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.24.sigs
@@ -0,0 +1,264 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.25.sigs b/lib/ldb/ABI/ldb-1.1.25.sigs
new file mode 100644
index 0000000..3f33df9
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.25.sigs
@@ -0,0 +1,265 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.26.sigs b/lib/ldb/ABI/ldb-1.1.26.sigs
new file mode 100644
index 0000000..3f33df9
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.26.sigs
@@ -0,0 +1,265 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.22.sigs b/lib/ldb/ABI/pyldb-util-1.1.22.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.22.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.23.sigs b/lib/ldb/ABI/pyldb-util-1.1.23.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.23.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.24.sigs b/lib/ldb/ABI/pyldb-util-1.1.24.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.24.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.25.sigs b/lib/ldb/ABI/pyldb-util-1.1.25.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.25.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.26.sigs b/lib/ldb/ABI/pyldb-util-1.1.26.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.26.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util.py3-1.1.23.sigs b/lib/ldb/ABI/pyldb-util.py3-1.1.23.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util.py3-1.1.23.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util.py3-1.1.24.sigs b/lib/ldb/ABI/pyldb-util.py3-1.1.24.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util.py3-1.1.24.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util.py3-1.1.25.sigs b/lib/ldb/ABI/pyldb-util.py3-1.1.25.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util.py3-1.1.25.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs b/lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/_ldb_text.py b/lib/ldb/_ldb_text.py
new file mode 100644
index 0000000..f6f1ac0
--- /dev/null
+++ b/lib/ldb/_ldb_text.py
@@ -0,0 +1,148 @@
+# Text wrapper for ldb bindings
+#
+# Copyright (C) 2015 Petr Viktorin <pviktori at redhat.com>
+# Published under the GNU LGPLv3 or later
+
+import sys
+import functools
+
+import ldb
+
+
+def _recursive_encode(obj):
+    if isinstance(obj, bytes):
+        return obj
+    elif isinstance(obj, str):
+        return obj.encode('utf-8')
+    else:
+        return [_recursive_encode(o) for o in obj]
+
+
+class _WrapBase(object):
+
+    @classmethod
+    def _wrap(cls, wrapped):
+        self = cls.__new__(cls)
+        self._wrapped = wrapped
+        return self
+
+    def __len__(self):
+        return len(self._wrapped)
+
+    def __eq__(self, other):
+        if hasattr(other, '_wrapped'):
+            return self._wrapped == other._wrapped
+        else:
+            return self._wrapped == other
+
+    def __ne__(self, other):
+        if hasattr(other, '_wrapped'):
+            return self._wrapped != other._wrapped
+        else:
+            return self._wrapped != other
+
+    def __lt__(self, other):
+        if hasattr(other, '_wrapped'):
+            return self._wrapped < other._wrapped
+        else:
+            return self._wrapped < other
+
+    def __le__(self, other):
+        if hasattr(other, '_wrapped'):
+            return self._wrapped >= other._wrapped
+        else:
+            return self._wrapped >= other
+
+    def __gt__(self, other):
+        if hasattr(other, '_wrapped'):
+            return self._wrapped > other._wrapped
+        else:
+            return self._wrapped > other
+
+    def __ge__(self, other):
+        if hasattr(other, '_wrapped'):
+            return self._wrapped >= other._wrapped
+        else:
+            return self._wrapped >= other
+
+    def __repr__(self):
+        return '%s.text' % repr(self._wrapped)
+
+
+class MessageElementTextWrapper(_WrapBase):
+
+    """Text interface for a LDB message element"""
+
+    def __iter__(self):
+        for item in self._wrapped:
+            yield item.decode('utf-8')
+
+    def __getitem__(self, key):
+        result = self._wrapped[key]
+        if result is None:
+            return None
+        else:
+            return result.decode('utf-8')
+
+    @property
+    def flags(self):
+        return self._wrapped.flags
+
+    @property
+    def set_flags(self):
+        return self._wrapped.set_flags
+
+_wrap_element = MessageElementTextWrapper._wrap
+
+
+class MessageTextWrapper(_WrapBase):
+
+    """Text interface for a LDB message"""
+
+    def __getitem__(self, key):
+        result = self._wrapped[key]
+        if result is None:
+            return None
+        else:
+            return _wrap_element(result)
+
+    def get(self, *args, **kwargs):
+        result = self._wrapped.get(*args, **kwargs)
+        if isinstance(result, ldb.MessageElement):
+            return _wrap_element(result)
+        elif isinstance(result, bytes):
+            return result.decode('utf-8')
+        else:
+            return result
+
+    def __setitem__(self, key, item):
+        self._wrapped[key] = _recursive_encode(item)
+
+    def __delitem__(self, key):
+        del self._wrapped[key]
+
+    def elements(self):
+        return [_wrap_element(el) for el in self._wrapped.elements()]
+
+    def items(self):
+        return [(attr, _wrap_element(el)) for attr, el in self._wrapped.items()]
+
+    @property
+    def keys(self):
+        return self._wrapped.keys
+
+    @property
+    def remove(self):
+        return self._wrapped.remove
+
+    @property
+    def add(self):
+        return self._wrapped.add
+
+    @property
+    def dn(self):
+        return self._wrapped.dn
+
+    @dn.setter
+    def dn(self, new_value):
+        self._wrapped.dn = new_value
diff --git a/lib/ldb/common/ldb_controls.c b/lib/ldb/common/ldb_controls.c
index 097ae20..af056d0 100644
--- a/lib/ldb/common/ldb_controls.c
+++ b/lib/ldb/common/ldb_controls.c
@@ -367,6 +367,26 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr
 		talloc_free(cookie);
 		return res;
 	}
+	if (strcmp(control->oid, LDB_CONTROL_DIRSYNC_EX_OID) == 0) {
+		char *cookie;
+		struct ldb_dirsync_control *rep_control = talloc_get_type(control->data,
+								struct ldb_dirsync_control);
+
+		cookie = ldb_base64_encode(mem_ctx, rep_control->cookie,
+				rep_control->cookie_len);
+		if (cookie == NULL) {
+			return NULL;
+		}
+		res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%s",
+					LDB_CONTROL_DIRSYNC_EX_NAME,
+					control->critical,
+					rep_control->flags,
+					rep_control->max_attributes,
+					cookie);
+
+		talloc_free(cookie);
+		return res;
+	}
 
 	if (strcmp(control->oid, LDB_CONTROL_VERIFY_NAME_OID) == 0) {
 		struct ldb_verify_name_control *rep_control = talloc_get_type(control->data, struct ldb_verify_name_control);
@@ -407,7 +427,7 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr
 
 
 /*
- * A little trick to allow to use constants defined in headers rather than
+ * A little trick to allow one to use constants defined in headers rather than
  * hardwritten in the file.
  * "sizeof" will return the \0 char as well so it will take the place of ":"
  * in the length of the string.
@@ -492,7 +512,7 @@ struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLO
 		p = &(control_strings[sizeof(LDB_CONTROL_DIRSYNC_NAME)]);
 		ret = sscanf(p, "%d:%u:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie);
 
-		if ((ret < 3) || (crit < 0) || (crit > 1) || (flags < 0) || (max_attrs < 0)) {
+		if ((ret < 3) || (crit < 0) || (crit > 1) || (max_attrs < 0)) {
 			error_string = talloc_asprintf(mem_ctx, "invalid dirsync control syntax\n");
 			error_string = talloc_asprintf_append(error_string, " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n");
 			error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number, o = b64 binary blob");
@@ -525,6 +545,51 @@ struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLO
 
 		return ctrl;
 	}
+	if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DIRSYNC_EX_NAME) == 0) {
+		struct ldb_dirsync_control *control;
+		const char *p;
+		char cookie[1024];
+		int crit, max_attrs, ret;
+		uint32_t flags;
+
+		cookie[0] = '\0';
+		p = &(control_strings[sizeof(LDB_CONTROL_DIRSYNC_EX_NAME)]);
+		ret = sscanf(p, "%d:%u:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie);
+
+		if ((ret < 3) || (crit < 0) || (crit > 1) || (max_attrs < 0)) {
+			error_string = talloc_asprintf(mem_ctx, "invalid %s control syntax\n",
+						       LDB_CONTROL_DIRSYNC_EX_NAME);
+			error_string = talloc_asprintf_append(error_string, " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n");
+			error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number, o = b64 binary blob");
+			ldb_set_errstring(ldb, error_string);
+			talloc_free(error_string);
+			talloc_free(ctrl);
+			return NULL;
+		}
+
+		/* w2k3 seems to ignore the parameter,
+		 * but w2k sends a wrong cookie when this value is to small
+		 * this would cause looping forever, while getting
+		 * the same data and same cookie forever
+		 */
+		if (max_attrs == 0) max_attrs = 0x0FFFFFFF;
+
+		ctrl->oid = LDB_CONTROL_DIRSYNC_EX_OID;
+		ctrl->critical = crit;
+		control = talloc(ctrl, struct ldb_dirsync_control);
+		control->flags = flags;
+		control->max_attributes = max_attrs;
+		if (*cookie) {
+			control->cookie_len = ldb_base64_decode(cookie);
+			control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len);
+		} else {
+			control->cookie = NULL;
+			control->cookie_len = 0;
+		}
+		ctrl->data = control;
+
+		return ctrl;
+	}
 
 	if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_ASQ_NAME) == 0) {
 		struct ldb_asq_control *control;
@@ -598,7 +663,7 @@ struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLO
 
 		p = &(control_strings[sizeof(LDB_CONTROL_SD_FLAGS_NAME)]);
 		ret = sscanf(p, "%d:%u", &crit, &secinfo_flags);
-		if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags < 0) || (secinfo_flags > 0xF)) {
+		if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags > 0xF)) {
 			error_string = talloc_asprintf(mem_ctx, "invalid sd_flags control syntax\n");
 			error_string = talloc_asprintf_append(error_string, " syntax: crit(b):secinfo_flags(n)\n");
 			error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number");
@@ -625,7 +690,7 @@ struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLO
 
 		p = &(control_strings[sizeof(LDB_CONTROL_SEARCH_OPTIONS_NAME)]);
 		ret = sscanf(p, "%d:%u", &crit, &search_options);
-		if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options < 0) || (search_options > 0xF)) {
+		if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options > 0xF)) {
 			error_string = talloc_asprintf(mem_ctx, "invalid search_options control syntax\n");
 			error_string = talloc_asprintf_append(error_string, " syntax: crit(b):search_options(n)\n");
 			error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number");
diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c
index cd17cda..b7d2de7 100644
--- a/lib/ldb/common/ldb_dn.c
+++ b/lib/ldb/common/ldb_dn.c
@@ -586,6 +586,12 @@ static bool ldb_dn_explode(struct ldb_dn *dn)
 
 				p++;
 				*d++ = '\0';
+
+				/*
+				 * This talloc_memdup() is OK with the
+				 * +1 because *d has been set to '\0'
+				 * just above
+				 */
 				dn->components[dn->comp_num].value.data = \
 					(uint8_t *)talloc_memdup(dn->components, dt, l + 1);
 				dn->components[dn->comp_num].value.length = l;
@@ -708,6 +714,11 @@ static bool ldb_dn_explode(struct ldb_dn *dn)
 	}
 
 	*d++ = '\0';
+	/*
+	 * This talloc_memdup() is OK with the
+	 * +1 because *d has been set to '\0'
+	 * just above.
+	 */
 	dn->components[dn->comp_num].value.length = l;
 	dn->components[dn->comp_num].value.data =
 		(uint8_t *)talloc_memdup(dn->components, dt, l + 1);
@@ -1901,17 +1912,37 @@ int ldb_dn_set_component(struct ldb_dn *dn, int num,
 		return LDB_ERR_OTHER;
 	}
 
+	if (num < 0) {
+		return LDB_ERR_OTHER;
+	}
+
+	if (val.length > val.length + 1) {
+		return LDB_ERR_OTHER;
+	}
+
 	n = talloc_strdup(dn, name);
 	if ( ! n) {
 		return LDB_ERR_OTHER;
 	}
 
 	v.length = val.length;
-	v.data = (uint8_t *)talloc_memdup(dn, val.data, v.length+1);
+
+	/*
+	 * This is like talloc_memdup(dn, v.data, v.length + 1), but
+	 * avoids the over-read
+	 */
+	v.data = (uint8_t *)talloc_size(dn, v.length+1);
 	if ( ! v.data) {
 		talloc_free(n);
 		return LDB_ERR_OTHER;
 	}
+	memcpy(v.data, val.data, val.length);
+
+	/*
+	 * Enforce NUL termination outside the stated length, as is
+	 * traditional in LDB
+	 */
+	v.data[v.length] = '\0';
 
 	talloc_free(dn->components[num].name);
 	talloc_free(dn->components[num].value.data);
@@ -2154,3 +2185,8 @@ bool ldb_dn_minimise(struct ldb_dn *dn)
 
 	return true;
 }
+
+struct ldb_context *ldb_dn_get_ldb_context(struct ldb_dn *dn)
+{
+	return dn->ldb;
+}
diff --git a/lib/ldb/common/ldb_ldif.c b/lib/ldb/common/ldb_ldif.c
index f9743dc..0aeda94b 100644
--- a/lib/ldb/common/ldb_ldif.c
+++ b/lib/ldb/common/ldb_ldif.c
@@ -1,4 +1,4 @@
-/* 
+/*
    ldb database library
 
    Copyright (C) Andrew Tridgell  2004
@@ -6,7 +6,7 @@
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
      ** under the LGPL
-   
+
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
@@ -39,7 +39,7 @@
 #include "system/locale.h"
 
 /*
-  
+
 */
 static int ldb_read_data_file(TALLOC_CTX *mem_ctx, struct ldb_val *value)
 {
@@ -236,7 +236,7 @@ static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *priva
   encode as base64 to a file
 */
 static int base64_encode_f(struct ldb_context *ldb,
-			   int (*fprintf_fn)(void *, const char *, ...), 
+			   int (*fprintf_fn)(void *, const char *, ...),
 			   void *private_data,
 			   const char *buf, int len, int start_pos)
 {
@@ -273,9 +273,9 @@ static const struct {
   write to ldif, using a caller supplied write method, and only printing secrets if we are not in a trace
 */
 static int ldb_ldif_write_trace(struct ldb_context *ldb,
-				int (*fprintf_fn)(void *, const char *, ...), 
+				int (*fprintf_fn)(void *, const char *, ...),
 				void *private_data,
-				const struct ldb_ldif *ldif, 
+				const struct ldb_ldif *ldif,
 				bool in_trace)
 {
 	TALLOC_CTX *mem_ctx;
@@ -324,20 +324,20 @@ static int ldb_ldif_write_trace(struct ldb_context *ldb,
 		if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
 			switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
 			case LDB_FLAG_MOD_ADD:
-				fprintf_fn(private_data, "add: %s\n", 
+				fprintf_fn(private_data, "add: %s\n",
 					   msg->elements[i].name);
 				break;
 			case LDB_FLAG_MOD_DELETE:
-				fprintf_fn(private_data, "delete: %s\n", 
+				fprintf_fn(private_data, "delete: %s\n",
 					   msg->elements[i].name);
 				break;
 			case LDB_FLAG_MOD_REPLACE:
-				fprintf_fn(private_data, "replace: %s\n", 
+				fprintf_fn(private_data, "replace: %s\n",
 					   msg->elements[i].name);
 				break;
 			}
 		}
-		
+
 		if (in_trace && secret_attributes && ldb_attr_in_list(secret_attributes, msg->elements[i].name)) {
 			/* Deliberatly skip printing this password */
 			ret = fprintf_fn(private_data, "# %s::: REDACTED SECRET ATTRIBUTE\n",
@@ -348,18 +348,26 @@ static int ldb_ldif_write_trace(struct ldb_context *ldb,
 
 		for (j=0;j<msg->elements[i].num_values;j++) {
 			struct ldb_val v;
-			bool use_b64_encode;
+			bool use_b64_encode = false;
+
 			ret = a->syntax->ldif_write_fn(ldb, mem_ctx, &msg->elements[i].values[j], &v);
 			if (ret != LDB_SUCCESS) {
 				v = msg->elements[i].values[j];
 			}
-			use_b64_encode = !(ldb->flags & LDB_FLG_SHOW_BINARY)
-					&& ldb_should_b64_encode(ldb, &v);
+
+			if (ldb->flags & LDB_FLG_SHOW_BINARY) {
+				use_b64_encode = false;
+			} else if (a->flags & LDB_ATTR_FLAG_FORCE_BASE64_LDIF) {
+				use_b64_encode = true;
+			} else {
+				use_b64_encode = ldb_should_b64_encode(ldb, &v);
+			}
+
 			if (ret != LDB_SUCCESS || use_b64_encode) {
-				ret = fprintf_fn(private_data, "%s:: ", 
+				ret = fprintf_fn(private_data, "%s:: ",
 						 msg->elements[i].name);
 				CHECK_RET;
-				ret = base64_encode_f(ldb, fprintf_fn, private_data, 
+				ret = base64_encode_f(ldb, fprintf_fn, private_data,
 						      (char *)v.data, v.length,
 						      strlen(msg->elements[i].name)+3);
 				CHECK_RET;
@@ -369,7 +377,7 @@ static int ldb_ldif_write_trace(struct ldb_context *ldb,
 				ret = fprintf_fn(private_data, "%s: ", msg->elements[i].name);
 				CHECK_RET;
 				if (ldb->flags & LDB_FLG_SHOW_BINARY) {
-					ret = fprintf_fn(private_data, "%*.*s", 
+					ret = fprintf_fn(private_data, "%*.*s",
 							 v.length, v.length, (char *)v.data);
 				} else {
 					ret = fold_string(fprintf_fn, private_data,
@@ -403,7 +411,7 @@ static int ldb_ldif_write_trace(struct ldb_context *ldb,
   write to ldif, using a caller supplied write method
 */
 int ldb_ldif_write(struct ldb_context *ldb,
-		   int (*fprintf_fn)(void *, const char *, ...), 
+		   int (*fprintf_fn)(void *, const char *, ...),
 		   void *private_data,
 		   const struct ldb_ldif *ldif)
 {
@@ -417,7 +425,7 @@ int ldb_ldif_write(struct ldb_context *ldb,
 
   caller frees
 */
-static char *next_chunk(struct ldb_context *ldb, 
+static char *next_chunk(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
 			int (*fgetc_fn)(void *), void *private_data)
 {
 	size_t alloc_size=0, chunk_size = 0;
@@ -429,7 +437,7 @@ static char *next_chunk(struct ldb_context *ldb,
 		if (chunk_size+1 >= alloc_size) {
 			char *c2;
 			alloc_size += 1024;
-			c2 = talloc_realloc(ldb, chunk, char, alloc_size);
+			c2 = talloc_realloc(mem_ctx, chunk, char, alloc_size);
 			if (!c2) {
 				talloc_free(chunk);
 				errno = ENOMEM;
@@ -442,15 +450,15 @@ static char *next_chunk(struct ldb_context *ldb,
 			if (c == '\n') {
 				in_comment = 0;
 			}
-			continue;			
+			continue;
 		}
-		
+
 		/* handle continuation lines - see RFC2849 */
 		if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
 			chunk_size--;
 			continue;
 		}
-		
+
 		/* chunks are terminated by a double line-feed */
 		if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
 			chunk[chunk_size-1] = 0;
@@ -774,18 +782,17 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
 	msg->elements = NULL;
 	msg->num_elements = 0;
 
-	chunk = next_chunk(ldb, fgetc_fn, private_data);
+	chunk = next_chunk(ldb, ldif, fgetc_fn, private_data);
 	if (!chunk) {
 		goto failed;
 	}
-	talloc_steal(ldif, chunk);
 
 	s = chunk;
 
 	if (next_attr(ldif, &s, &attr, &value) != 0) {
 		goto failed;
 	}
-	
+
 	/* first line must be a dn */
 	if (ldb_attr_cmp(attr, "dn") != 0) {
 		ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: First line of ldif must be a dn not '%s'",
@@ -845,7 +852,7 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
 			}
 			continue;
 		}
-		
+
 		el = &msg->elements[msg->num_elements-1];
 
 		a = ldb_schema_attribute_by_name(ldb, attr);
@@ -853,8 +860,8 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
 		if (msg->num_elements > 0 && ldb_attr_cmp(attr, el->name) == 0 &&
 		    flags == el->flags) {
 			/* its a continuation */
-			el->values = 
-				talloc_realloc(msg->elements, el->values, 
+			el->values =
+				talloc_realloc(msg->elements, el->values,
 						 struct ldb_val, el->num_values+1);
 			if (!el->values) {
 				goto failed;
@@ -874,8 +881,8 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
 			el->num_values++;
 		} else {
 			/* its a new attribute */
-			msg->elements = talloc_realloc(msg, msg->elements, 
-							 struct ldb_message_element, 
+			msg->elements = talloc_realloc(msg, msg->elements,
+							 struct ldb_message_element,
 							 msg->num_elements+1);
 			if (!msg->elements) {
 				goto failed;
@@ -934,7 +941,7 @@ static int fgetc_file(void *private_data)
 	return c;
 }
 
-struct ldb_ldif *ldb_ldif_read_file_state(struct ldb_context *ldb, 
+struct ldb_ldif *ldb_ldif_read_file_state(struct ldb_context *ldb,
 					  struct ldif_read_file_state *state)
 {
 	return ldb_ldif_read(ldb, fgetc_file, state);
@@ -1020,7 +1027,7 @@ static int ldif_printf_string(void *private_data, const char *fmt, ...)
 	va_list ap;
 	size_t oldlen = talloc_get_size(state->string);
 	va_start(ap, fmt);
-	
+
 	state->string = talloc_vasprintf_append(state->string, fmt, ap);
 	va_end(ap);
 	if (!state->string) {
@@ -1030,7 +1037,7 @@ static int ldif_printf_string(void *private_data, const char *fmt, ...)
 	return talloc_get_size(state->string) - oldlen;
 }
 
-char *ldb_ldif_write_redacted_trace_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
+char *ldb_ldif_write_redacted_trace_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
 					   const struct ldb_ldif *ldif)
 {
 	struct ldif_write_string_state state;
@@ -1044,7 +1051,7 @@ char *ldb_ldif_write_redacted_trace_string(struct ldb_context *ldb, TALLOC_CTX *
 	return state.string;
 }
 
-char *ldb_ldif_write_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
+char *ldb_ldif_write_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
 			    const struct ldb_ldif *ldif)
 {
 	struct ldif_write_string_state state;
@@ -1062,7 +1069,7 @@ char *ldb_ldif_write_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
   convenient function to turn a ldb_message into a string. Useful for
   debugging
  */
-char *ldb_ldif_message_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
+char *ldb_ldif_message_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
 			      enum ldb_changetype changetype,
 			      const struct ldb_message *msg)
 {
diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c
index 182c6ce..e83ad63 100644
--- a/lib/ldb/common/ldb_match.c
+++ b/lib/ldb/common/ldb_match.c
@@ -503,9 +503,10 @@ static int ldb_match_extended(struct ldb_context *ldb,
 
 	rule = ldb_find_extended_match_rule(ldb, tree->u.extended.rule_id);
 	if (rule == NULL) {
+		*matched = false;
 		ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s",
 			  tree->u.extended.rule_id);
-		return LDB_ERR_INAPPROPRIATE_MATCHING;
+		return LDB_SUCCESS;
 	}
 
 	return rule->callback(ldb, rule->oid, msg,
@@ -712,7 +713,7 @@ int ldb_register_extended_match_rule(struct ldb_context *ldb,
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 	entry->rule = rule;
-	DLIST_ADD_END(ldb->extended_match_rules, entry, struct ldb_extended_match_entry);
+	DLIST_ADD_END(ldb->extended_match_rules, entry);
 
 	return LDB_SUCCESS;
 }
diff --git a/lib/ldb/common/ldb_modules.c b/lib/ldb/common/ldb_modules.c
index 91412a6..2105966 100644
--- a/lib/ldb/common/ldb_modules.c
+++ b/lib/ldb/common/ldb_modules.c
@@ -162,7 +162,7 @@ int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn, bool
 			talloc_free(be);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
-		DLIST_ADD_END(ldb_backends, be, struct backends_list_entry);
+		DLIST_ADD_END(ldb_backends, be);
 	}
 
 	be->ops->name = url_prefix;
@@ -240,7 +240,7 @@ int ldb_register_hook(ldb_hook_fn hook_fn)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 	lc->hook_fn = hook_fn;
-	DLIST_ADD_END(ldb_hooks, lc, struct ldb_hooks);
+	DLIST_ADD_END(ldb_hooks, lc);
 	return LDB_SUCCESS;
 }
 
@@ -926,7 +926,7 @@ static int ldb_modules_load_path(const char *path, const char *version)
 	le->st_ino = st.st_ino;
 	le->st_dev = st.st_dev;
 
-	DLIST_ADD_END(loaded, le, struct loaded);
+	DLIST_ADD_END(loaded, le);
 
 	/* if it is a directory, recurse */
 	if (S_ISDIR(st.st_mode)) {
diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c
index 4382d5b..7970b9d 100644
--- a/lib/ldb/common/ldb_pack.c
+++ b/lib/ldb/common/ldb_pack.c
@@ -77,7 +77,7 @@ int ldb_pack_data(struct ldb_context *ldb,
 		  struct ldb_val *data)
 {
 	unsigned int i, j, real_elements=0;
-	size_t size;
+	size_t size, dn_len, attr_len, value_len;
 	const char *dn;
 	uint8_t *p;
 	size_t len;
@@ -91,8 +91,19 @@ int ldb_pack_data(struct ldb_context *ldb,
 	/* work out how big it needs to be */
 	size = 8;
 
-	size += 1 + strlen(dn);
+	size += 1;
 
+	dn_len = strlen(dn);
+	if (size + dn_len < size) {
+		errno = ENOMEM;
+		return -1;
+	}
+	size += dn_len;
+
+	/*
+	 * First calcuate the buffer size we need, and check for
+	 * overflows
+	 */
 	for (i=0;i<message->num_elements;i++) {
 		if (attribute_storable_values(&message->elements[i]) == 0) {
 			continue;
@@ -100,9 +111,32 @@ int ldb_pack_data(struct ldb_context *ldb,
 
 		real_elements++;
 
-		size += 1 + strlen(message->elements[i].name) + 4;
+		if (size + 5 < size) {
+			errno = ENOMEM;
+			return -1;
+		}
+		size += 5;
+
+		attr_len = strlen(message->elements[i].name);
+		if (size + attr_len < size) {
+			errno = ENOMEM;
+			return -1;
+		}
+		size += attr_len;
+
 		for (j=0;j<message->elements[i].num_values;j++) {
-			size += 4 + message->elements[i].values[j].length + 1;
+			if (size + 5 < size) {
+				errno = ENOMEM;
+				return -1;
+			}
+			size += 5;
+
+			value_len = message->elements[i].values[j].length;
+			if (size + value_len < size) {
+				errno = ENOMEM;
+				return -1;
+			}
+			size += value_len;
 		}
 	}
 
@@ -121,7 +155,7 @@ int ldb_pack_data(struct ldb_context *ldb,
 
 	/* the dn needs to be packed so we can be case preserving
 	   while hashing on a case folded dn */
-	len = strlen(dn);
+	len = dn_len;
 	memcpy(p, dn, len+1);
 	p += len + 1;
 
@@ -146,20 +180,64 @@ int ldb_pack_data(struct ldb_context *ldb,
 	return 0;
 }
 
-/*
-  unpack a ldb message from a linear buffer in ldb_val
+static bool ldb_consume_element_data(uint8_t **pp, size_t *premaining)
+{
+	unsigned int remaining = *premaining;
+	uint8_t *p = *pp;
+	uint32_t num_values = pull_uint32(p, 0);
+	uint32_t len;
+	int j;
+
+	p += 4;
+	if (remaining < 4) {
+		return false;
+	}
+	remaining -= 4;
+	for (j = 0; j < num_values; j++) {
+		len = pull_uint32(p, 0);
+		if (remaining < 5) {
+			return false;
+		}
+		remaining -= 5;
+		if (len > remaining) {
+			return false;
+		}
+		remaining -= len;
+		p += len + 4 + 1;
+	}
 
-  Free with ldb_unpack_data_free()
-*/
-int ldb_unpack_data(struct ldb_context *ldb,
-		    const struct ldb_val *data,
-		    struct ldb_message *message)
+	*premaining = remaining;
+	*pp = p;
+	return true;
+}
+
+/*
+ * Unpack a ldb message from a linear buffer in ldb_val
+ *
+ * Providing a list of attributes to this function allows selective unpacking.
+ * Giving a NULL list (or a list_size of 0) unpacks all the attributes.
+ *
+ * Free with ldb_unpack_data_free()
+ */
+int ldb_unpack_data_only_attr_list(struct ldb_context *ldb,
+				   const struct ldb_val *data,
+				   struct ldb_message *message,
+				   const char * const *list,
+				   unsigned int list_size,
+				   unsigned int *nb_elements_in_db)
 {
 	uint8_t *p;
-	unsigned int remaining;
+	size_t remaining;
+	size_t dn_len;
 	unsigned int i, j;
 	unsigned format;
+	unsigned int nelem = 0;
 	size_t len;
+	unsigned int found = 0;
+
+	if (list == NULL) {
+		list_size = 0;
+	}
 
 	message->elements = NULL;
 
@@ -172,6 +250,9 @@ int ldb_unpack_data(struct ldb_context *ldb,
 	format = pull_uint32(p, 0);
 	message->num_elements = pull_uint32(p, 4);
 	p += 8;
+	if (nb_elements_in_db) {
+		*nb_elements_in_db = message->num_elements;
+	}
 
 	remaining = data->length - 8;
 
@@ -181,8 +262,12 @@ int ldb_unpack_data(struct ldb_context *ldb,
 		break;
 
 	case LDB_PACKING_FORMAT:
-		len = strnlen((char *)p, remaining);
-		if (len == remaining) {
+		/*
+		 * With this check, we know that the DN at p is \0
+		 * terminated.
+		 */
+		dn_len = strnlen((char *)p, remaining);
+		if (dn_len == remaining) {
 			errno = EIO;
 			goto failed;
 		}
@@ -191,8 +276,17 @@ int ldb_unpack_data(struct ldb_context *ldb,
 			errno = ENOMEM;
 			goto failed;
 		}
-		remaining -= len + 1;
-		p += len + 1;
+		/*
+		 * Redundant: by definition, remaining must be more
+		 * than one less than dn_len, as otherwise it would be
+		 * == dn_len
+		 */
+		if (remaining < dn_len + 1) {
+			errno = EIO;
+			goto failed;
+		}
+		remaining -= dn_len + 1;
+		p += dn_len + 1;
 		break;
 
 	default:
@@ -209,74 +303,157 @@ int ldb_unpack_data(struct ldb_context *ldb,
 		goto failed;
 	}
 
-	message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
+	message->elements = talloc_zero_array(message, struct ldb_message_element,
+					      message->num_elements);
 	if (!message->elements) {
 		errno = ENOMEM;
 		goto failed;
 	}
 
-	memset(message->elements, 0,
-	       message->num_elements * sizeof(struct ldb_message_element));
-
 	for (i=0;i<message->num_elements;i++) {
+		const char *attr = NULL;
+		size_t attr_len;
+		struct ldb_message_element *element = NULL;
+
 		if (remaining < 10) {
 			errno = EIO;
 			goto failed;
 		}
-		len = strnlen((char *)p, remaining-6);
-		if (len == remaining-6) {
+		/*
+		 * With this check, we know that the attribute name at
+		 * p is \0 terminated.
+		 */
+		attr_len = strnlen((char *)p, remaining-6);
+		if (attr_len == remaining-6) {
 			errno = EIO;
 			goto failed;
 		}
-		if (len == 0) {
+		if (attr_len == 0) {
 			errno = EIO;
 			goto failed;
 		}
-		message->elements[i].flags = 0;
-		message->elements[i].name = talloc_strndup(message->elements, (char *)p, len);
-		if (message->elements[i].name == NULL) {
+		attr = (char *)p;
+
+		/*
+		 * The general idea is to reduce allocations by skipping over
+		 * attributes that we do not actually care about.
+		 *
+		 * This is a bit expensive but normally the list is pretty small
+		 * also the cost of freeing unused attributes is quite important
+		 * and can dwarf the cost of looping.
+		 */
+		if (list_size != 0) {
+			bool keep = false;
+			int h;
+
+			/*
+			 * We know that p has a \0 terminator before the
+			 * end of the buffer due to the check above.
+			 */
+			for (h = 0; h < list_size && found < list_size; h++) {
+				if (ldb_attr_cmp(attr, list[h]) == 0) {
+					keep = true;
+					found++;
+					break;
+				}
+			}
+
+			if (!keep) {
+				if (remaining < (attr_len + 1)) {
+					errno = EIO;
+					goto failed;
+				}
+				remaining -= attr_len + 1;
+				p += attr_len + 1;
+				if (!ldb_consume_element_data(&p, &remaining)) {
+					errno = EIO;
+					goto failed;
+				}
+				continue;
+			}
+		}
+		element = &message->elements[nelem];
+		element->name = talloc_memdup(message->elements, attr, attr_len+1);
+
+		if (element->name == NULL) {
 			errno = ENOMEM;
 			goto failed;
 		}
-		remaining -= len + 1;
-		p += len + 1;
-		message->elements[i].num_values = pull_uint32(p, 0);
-		message->elements[i].values = NULL;
-		if (message->elements[i].num_values != 0) {
-			message->elements[i].values = talloc_array(message->elements,
-								     struct ldb_val,
-								     message->elements[i].num_values);
-			if (!message->elements[i].values) {
+		element->flags = 0;
+
+		if (remaining < (attr_len + 1)) {
+			errno = EIO;
+			goto failed;
+		}
+		remaining -= attr_len + 1;
+		p += attr_len + 1;
+		element->num_values = pull_uint32(p, 0);
+		element->values = NULL;
+		if (element->num_values != 0) {
+			element->values = talloc_array(message->elements,
+						       struct ldb_val,
+						       element->num_values);
+			if (!element->values) {
 				errno = ENOMEM;
 				goto failed;
 			}
 		}
 		p += 4;
+		if (remaining < 4) {
+			errno = EIO;
+			goto failed;
+		}
 		remaining -= 4;
-		for (j=0;j<message->elements[i].num_values;j++) {
+		for (j = 0; j < element->num_values; j++) {
+			if (remaining < 5) {
+				errno = EIO;
+				goto failed;
+			}
+			remaining -= 5;
+
 			len = pull_uint32(p, 0);
-			if (len > remaining-5) {
+			if (remaining < len) {
+				errno = EIO;
+				goto failed;
+			}
+			if (len + 1 < len) {
 				errno = EIO;
 				goto failed;
 			}
 
-			message->elements[i].values[j].length = len;
-			message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1);
-			if (message->elements[i].values[j].data == NULL) {
+			element->values[j].length = len;
+			element->values[j].data = talloc_size(element->values, len+1);
+			if (element->values[j].data == NULL) {
 				errno = ENOMEM;
 				goto failed;
 			}
-			memcpy(message->elements[i].values[j].data, p+4, len);
-			message->elements[i].values[j].data[len] = 0;
+			memcpy(element->values[j].data, p + 4,
+			       len);
+			element->values[j].data[len] = 0;
 
-			remaining -= len+4+1;
+			remaining -= len;
 			p += len+4+1;
 		}
+		nelem++;
 	}
+	/*
+	 * Adapt the number of elements to the real number of unpacked elements,
+	 * it means that we overallocated elements array.
+	 */
+	message->num_elements = nelem;
+
+	/*
+	 * Shrink the allocated size.  On current talloc behaviour
+	 * this will help if we skipped 32 or more attributes.
+	 */
+	message->elements = talloc_realloc(message, message->elements,
+					   struct ldb_message_element,
+					   message->num_elements);
 
 	if (remaining != 0) {
 		ldb_debug(ldb, LDB_DEBUG_ERROR,
-			  "Error: %d bytes unread in ldb_unpack_data", remaining);
+			  "Error: %zu bytes unread in ldb_unpack_data_only_attr_list",
+			  remaining);
 	}
 
 	return 0;
@@ -285,3 +462,10 @@ failed:
 	talloc_free(message->elements);
 	return -1;
 }
+
+int ldb_unpack_data(struct ldb_context *ldb,
+		    const struct ldb_val *data,
+		    struct ldb_message *message)
+{
+	return ldb_unpack_data_only_attr_list(ldb, data, message, NULL, 0, NULL);
+}
diff --git a/lib/ldb/include/dlinklist.h b/lib/ldb/include/dlinklist.h
index f640b0f..ef01aec 100644
--- a/lib/ldb/include/dlinklist.h
+++ b/lib/ldb/include/dlinklist.h
@@ -57,10 +57,6 @@
   This allows us to find the tail of the list by using
   list_head->prev, which means we can add to the end of the list in
   O(1) time
-
-
-  Note that the 'type' arguments below are no longer needed, but
-  are kept for now to prevent an incompatible argument change
  */
 
 
@@ -135,9 +131,8 @@ do { \
 
 /*
    add to the end of a list.
-   Note that 'type' is ignored
 */
-#define DLIST_ADD_END(list, p, type)			\
+#define DLIST_ADD_END(list, p) \
 do { \
 	if (!(list)) { \
 		DLIST_ADD(list, p); \
@@ -155,20 +150,18 @@ do { \
 
 /*
    demote an element to the end of a list.
-   Note that 'type' is ignored
 */
-#define DLIST_DEMOTE(list, p, type)			\
+#define DLIST_DEMOTE(list, p) \
 do { \
 	DLIST_REMOVE(list, p); \
-	DLIST_ADD_END(list, p, NULL);		\
+	DLIST_ADD_END(list, p); \
 } while (0)
 
 /*
    concatenate two lists - putting all elements of the 2nd list at the
    end of the first list.
-   Note that 'type' is ignored
 */
-#define DLIST_CONCATENATE(list1, list2, type)	\
+#define DLIST_CONCATENATE(list1, list2) \
 do { \
 	if (!(list1)) { \
 		(list1) = (list2); \
diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h
index f48f753..e715b92 100644
--- a/lib/ldb/include/ldb.h
+++ b/lib/ldb/include/ldb.h
@@ -422,6 +422,11 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
  */
 #define LDB_ATTR_FLAG_SINGLE_VALUE (1<<4)
 
+/*
+ * The values should always be base64 encoded
+ */
+#define LDB_ATTR_FLAG_FORCE_BASE64_LDIF        (1<<5)
+
 /**
   LDAP attribute syntax for a DN
 
@@ -652,6 +657,8 @@ typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque);
 */
 #define LDB_CONTROL_DIRSYNC_OID		"1.2.840.113556.1.4.841"
 #define LDB_CONTROL_DIRSYNC_NAME	"dirsync"
+#define LDB_CONTROL_DIRSYNC_EX_OID	"1.2.840.113556.1.4.2090"
+#define LDB_CONTROL_DIRSYNC_EX_NAME	"dirsync_ex"
 
 
 /**
diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h
index 34e33c0..c6a24d3 100644
--- a/lib/ldb/include/ldb_module.h
+++ b/lib/ldb/include/ldb_module.h
@@ -382,4 +382,22 @@ struct ldb_extended_match_rule
 int ldb_register_extended_match_rule(struct ldb_context *ldb,
 				     const struct ldb_extended_match_rule *rule);
 
+/*
+ * these pack/unpack functions are exposed in the library for use by
+ * ldb tools like ldbdump and for use in tests,
+ * but are not part of the public API
+ */
+int ldb_pack_data(struct ldb_context *ldb,
+		  const struct ldb_message *message,
+		  struct ldb_val *data);
+int ldb_unpack_data_only_attr_list(struct ldb_context *ldb,
+				   const struct ldb_val *data,
+				   struct ldb_message *message,
+				   const char* const * list,
+				   unsigned int list_size,
+				   unsigned int *nb_attributes_indb);
+int ldb_unpack_data(struct ldb_context *ldb,
+		    const struct ldb_val *data,
+		    struct ldb_message *message);
+
 #endif
diff --git a/lib/ldb/include/ldb_private.h b/lib/ldb/include/ldb_private.h
index 7977448..26a9d42 100644
--- a/lib/ldb/include/ldb_private.h
+++ b/lib/ldb/include/ldb_private.h
@@ -201,14 +201,11 @@ char *ldb_ldif_write_redacted_trace_string(struct ldb_context *ldb, TALLOC_CTX *
 					   const struct ldb_ldif *ldif);
 
 /*
- * these pack/unpack functions are exposed in the library for use by
- * ldb tools like ldbdump, but are not part of the public API
+ * Get the LDB context in use on an LDB DN.
+ *
+ * This is helpful to the python LDB code, which may use as part of
+ * adding base and child components to an existing DN.
  */
-int ldb_pack_data(struct ldb_context *ldb,
-		  const struct ldb_message *message,
-		  struct ldb_val *data);
-int ldb_unpack_data(struct ldb_context *ldb,
-		    const struct ldb_val *data,
-		    struct ldb_message *message);
+struct ldb_context *ldb_dn_get_ldb_context(struct ldb_dn *dn);
 
 #endif
diff --git a/lib/ldb/ldb_ldap/ldb_ldap.c b/lib/ldb/ldb_ldap/ldb_ldap.c
index 7e6ac90..29f8938 100644
--- a/lib/ldb/ldb_ldap/ldb_ldap.c
+++ b/lib/ldb/ldb_ldap/ldb_ldap.c
@@ -252,8 +252,11 @@ static int lldb_search(struct lldb_context *lldb_ac)
 		break;
 	}
 
-	tv.tv_sec = req->timeout;
+	tv.tv_sec = 0;
 	tv.tv_usec = 0;
+	if (req->timeout > 0) {
+		tv.tv_sec = req->timeout;
+	}
 
 	ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope, 
 			      expression, 
@@ -836,12 +839,13 @@ static int lldb_handle_request(struct ldb_module *module, struct ldb_request *re
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-
-	tv.tv_sec = req->starttime + req->timeout;
-	tv.tv_usec = 0;
-	te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
-	if (NULL == te) {
-		return LDB_ERR_OPERATIONS_ERROR;
+	if (req->timeout > 0) {
+		tv.tv_sec = req->starttime + req->timeout;
+		tv.tv_usec = 0;
+		te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
+		if (NULL == te) {
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
 	}
 
 	return LDB_SUCCESS;
diff --git a/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
index 223868a..60b39e8 100644
--- a/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
+++ b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
@@ -1566,10 +1566,13 @@ static int lsql_handle_request(struct ldb_module *module, struct ldb_request *re
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	tv.tv_sec = req->starttime + req->timeout;
-	ac->timeout_event = tevent_add_timer(ev, ac, tv, lsql_timeout, ac);
-	if (NULL == ac->timeout_event) {
-		return LDB_ERR_OPERATIONS_ERROR;
+	if (req->timeout > 0) {
+		tv.tv_sec = req->starttime + req->timeout;
+		tv.tv_usec = 0;
+		ac->timeout_event = tevent_add_timer(ev, ac, tv, lsql_timeout, ac);
+		if (NULL == ac->timeout_event) {
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
 	}
 
 	return LDB_SUCCESS;
diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index 1e7e7ea..62a36c7 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -407,10 +407,18 @@ int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
 	}
 
 	talloc_free(msg->elements);
-	msg->elements = talloc_realloc(msg, el2, struct ldb_message_element, msg->num_elements);
+
+	if (num_elements > 0) {
+		msg->elements = talloc_realloc(msg, el2, struct ldb_message_element,
+					       num_elements);
+	} else {
+		msg->elements = talloc_array(msg, struct ldb_message_element, 0);
+		talloc_free(el2);
+	}
 	if (msg->elements == NULL) {
 		return -1;
 	}
+
 	msg->num_elements = num_elements;
 
 	return 0;
@@ -437,6 +445,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
 
 	msg = ldb_msg_new(ac);
 	if (!msg) {
+		ac->error = LDB_ERR_OPERATIONS_ERROR;
 		return -1;
 	}
 
@@ -444,6 +453,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
 	ret = ldb_unpack_data(ldb, (struct ldb_val *)&data, msg);
 	if (ret == -1) {
 		talloc_free(msg);
+		ac->error = LDB_ERR_OPERATIONS_ERROR;
 		return -1;
 	}
 
@@ -452,6 +462,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
 				     (char *)key.dptr + 3);
 		if (msg->dn == NULL) {
 			talloc_free(msg);
+			ac->error = LDB_ERR_OPERATIONS_ERROR;
 			return -1;
 		}
 	}
@@ -461,6 +472,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
 				  ac->tree, ac->base, ac->scope, &matched);
 	if (ret != LDB_SUCCESS) {
 		talloc_free(msg);
+		ac->error = LDB_ERR_OPERATIONS_ERROR;
 		return -1;
 	}
 	if (!matched) {
@@ -473,6 +485,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
 
 	if (ret == -1) {
 		talloc_free(msg);
+		ac->error = LDB_ERR_OPERATIONS_ERROR;
 		return -1;
 	}
 
@@ -480,6 +493,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
 	if (ret != LDB_SUCCESS) {
 		ac->request_terminated = true;
 		/* the callback failed, abort the operation */
+		ac->error = LDB_ERR_OPERATIONS_ERROR;
 		return -1;
 	}
 
@@ -497,6 +511,7 @@ static int ltdb_search_full(struct ltdb_context *ctx)
 	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
 	int ret;
 
+	ctx->error = LDB_SUCCESS;
 	if (ltdb->in_transaction != 0) {
 		ret = tdb_traverse(ltdb->tdb, search_func, ctx);
 	} else {
@@ -507,7 +522,7 @@ static int ltdb_search_full(struct ltdb_context *ctx)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	return LDB_SUCCESS;
+	return ctx->error;
 }
 
 /*
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index bcb8f0f..8d1fd36 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -1469,11 +1469,15 @@ static int ltdb_handle_request(struct ldb_module *module,
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	tv.tv_sec = req->starttime + req->timeout;
-	ac->timeout_event = tevent_add_timer(ev, ac, tv, ltdb_timeout, ac);
-	if (NULL == ac->timeout_event) {
-		talloc_free(ac);
-		return LDB_ERR_OPERATIONS_ERROR;
+	if (req->timeout > 0) {
+		tv.tv_sec = req->starttime + req->timeout;
+		tv.tv_usec = 0;
+		ac->timeout_event = tevent_add_timer(ev, ac, tv,
+						     ltdb_timeout, ac);
+		if (NULL == ac->timeout_event) {
+			talloc_free(ac);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
 	}
 
 	/* set a spy so that we do not try to use the request context
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index 3521800..caa98eb 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -48,6 +48,9 @@ struct ltdb_context {
 	enum ldb_scope scope;
 	const char * const *attrs;
 	struct tevent_timer *timeout_event;
+
+	/* error handling */
+	int error;
 };
 
 /* special record types */
diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index f18e06e..bea837f 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -30,7 +30,29 @@
 
 #include <Python.h>
 #include "ldb_private.h"
+#include "ldb_handlers.h"
 #include "pyldb.h"
+#include "dlinklist.h"
+
+struct py_ldb_search_iterator_reply;
+
+typedef struct {
+	PyObject_HEAD
+	TALLOC_CTX *mem_ctx;
+	PyLdbObject *ldb;
+	struct {
+		struct ldb_request *req;
+		struct py_ldb_search_iterator_reply *next;
+		struct py_ldb_search_iterator_reply *result;
+		PyObject *exception;
+	} state;
+} PyLdbSearchIteratorObject;
+
+struct py_ldb_search_iterator_reply {
+	struct py_ldb_search_iterator_reply *prev, *next;
+	PyLdbSearchIteratorObject *py_iter;
+	PyObject *obj;
+};
 
 void initldb(void);
 static PyObject *PyLdbMessage_FromMessage(struct ldb_message *msg);
@@ -38,6 +60,7 @@ static PyObject *PyExc_LdbError;
 
 static PyTypeObject PyLdbControl;
 static PyTypeObject PyLdbResult;
+static PyTypeObject PyLdbSearchIterator;
 static PyTypeObject PyLdbMessage;
 #define PyLdbMessage_Check(ob) PyObject_TypeCheck(ob, &PyLdbMessage)
 static PyTypeObject PyLdbModule;
@@ -57,15 +80,51 @@ static struct ldb_message_element *PyObject_AsMessageElement(
 						      unsigned int flags,
 						      const char *attr_name);
 
-/* There's no Py_ssize_t in 2.4, apparently */
-#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
-typedef int Py_ssize_t;
-typedef inquiry lenfunc;
-typedef intargfunc ssizeargfunc;
+#if PY_MAJOR_VERSION >= 3
+#define PyStr_Check PyUnicode_Check
+#define PyStr_FromString PyUnicode_FromString
+#define PyStr_FromStringAndSize PyUnicode_FromStringAndSize
+#define PyStr_FromFormat PyUnicode_FromFormat
+#define PyStr_FromFormatV PyUnicode_FromFormatV
+#define PyStr_AsUTF8 PyUnicode_AsUTF8
+#define PyStr_AsUTF8AndSize PyUnicode_AsUTF8AndSize
+#define PyInt_FromLong PyLong_FromLong
+#else
+#define PyStr_Check PyString_Check
+#define PyStr_FromString PyString_FromString
+#define PyStr_FromStringAndSize PyString_FromStringAndSize
+#define PyStr_FromFormat PyString_FromFormat
+#define PyStr_FromFormatV PyString_FromFormatV
+#define PyStr_AsUTF8 PyString_AsString
+
+const char *PyStr_AsUTF8AndSize(PyObject *pystr, Py_ssize_t *sizeptr);
+const char *
+PyStr_AsUTF8AndSize(PyObject *pystr, Py_ssize_t *sizeptr)
+{
+	const char * ret = PyString_AsString(pystr);
+	if (ret == NULL)
+		return NULL;
+	*sizeptr = PyString_Size(pystr);
+	return ret;
+}
 #endif
 
-#define SIGN(a) (((a) == 0)?0:((a) < 0?-1:1))
-
+static PyObject *richcmp(int cmp_val, int op)
+{
+	int ret;
+	switch (op) {
+		case Py_LT: ret = cmp_val < 0;  break;
+		case Py_LE: ret = cmp_val <= 0; break;
+		case Py_EQ: ret = cmp_val == 0; break;
+		case Py_NE: ret = cmp_val != 0; break;
+		case Py_GT: ret = cmp_val > 0;  break;
+		case Py_GE: ret = cmp_val >= 0; break;
+		default:
+			Py_INCREF(Py_NotImplemented);
+			return Py_NotImplemented;
+	}
+	return PyBool_FromLong(ret);
+}
 
 
 static PyObject *py_ldb_control_str(PyLdbControlObject *self)
@@ -76,9 +135,9 @@ static PyObject *py_ldb_control_str(PyLdbControlObject *self)
 			PyErr_NoMemory();
 			return NULL;
 		}
-		return PyString_FromString(control);
+		return PyStr_FromString(control);
 	} else {
-		return PyString_FromFormat("ldb control");
+		return PyStr_FromString("ldb control");
 	}
 }
 
@@ -91,9 +150,32 @@ static void py_ldb_control_dealloc(PyLdbControlObject *self)
 	Py_TYPE(self)->tp_free(self);
 }
 
+/* Create a text (rather than bytes) interface for a LDB result object */
+static PyObject *wrap_text(const char *type, PyObject *wrapped)
+{
+	PyObject *mod, *cls, *constructor, *inst;
+	mod = PyImport_ImportModule("_ldb_text");
+	if (mod == NULL)
+		return NULL;
+	cls = PyObject_GetAttrString(mod, type);
+	Py_DECREF(mod);
+	if (cls == NULL) {
+		Py_DECREF(mod);
+		return NULL;
+	}
+	constructor = PyObject_GetAttrString(cls, "_wrap");
+	Py_DECREF(cls);
+	if (constructor == NULL) {
+		return NULL;
+	}
+	inst = PyObject_CallFunction(constructor, discard_const_p(char, "O"), wrapped);
+	Py_DECREF(constructor);
+	return inst;
+}
+
 static PyObject *py_ldb_control_get_oid(PyLdbControlObject *self)
 {
-	return PyString_FromString(self->data->oid);
+	return PyStr_FromString(self->data->oid);
 }
 
 static PyObject *py_ldb_control_get_critical(PyLdbControlObject *self)
@@ -191,7 +273,12 @@ static void PyErr_SetLdbError(PyObject *error, int ret, struct ldb_context *ldb_
 
 static PyObject *PyObject_FromLdbValue(const struct ldb_val *val)
 {
-	return PyString_FromStringAndSize((const char *)val->data, val->length);
+	return PyBytes_FromStringAndSize((const char *)val->data, val->length);
+}
+
+static PyObject *PyStr_FromLdbValue(const struct ldb_val *val)
+{
+	return PyStr_FromStringAndSize((const char *)val->data, val->length);
 }
 
 /**
@@ -317,7 +404,7 @@ static PyObject *PyLdbResult_FromResult(struct ldb_result *result)
 	}
 
 	for (i = 0;result->refs && result->refs[i]; i++) {
-		PyList_SetItem(referals, i, PyString_FromString(result->refs[i]));
+		PyList_SetItem(referals, i, PyStr_FromString(result->refs[i]));
 	}
 	ret->referals = referals;
 	return (PyObject *)ret;
@@ -375,22 +462,22 @@ static PyObject *py_ldb_dn_is_null(PyLdbDnObject *self)
  
 static PyObject *py_ldb_dn_get_casefold(PyLdbDnObject *self)
 {
-	return PyString_FromString(ldb_dn_get_casefold(self->dn));
+	return PyStr_FromString(ldb_dn_get_casefold(self->dn));
 }
 
 static PyObject *py_ldb_dn_get_linearized(PyLdbDnObject *self)
 {
-	return PyString_FromString(ldb_dn_get_linearized(self->dn));
+	return PyStr_FromString(ldb_dn_get_linearized(self->dn));
 }
 
 static PyObject *py_ldb_dn_canonical_str(PyLdbDnObject *self)
 {
-	return PyString_FromString(ldb_dn_canonical_string(self->dn, self->dn));
+	return PyStr_FromString(ldb_dn_canonical_string(self->dn, self->dn));
 }
 
 static PyObject *py_ldb_dn_canonical_ex_str(PyLdbDnObject *self)
 {
-	return PyString_FromString(ldb_dn_canonical_ex_string(self->dn, self->dn));
+	return PyStr_FromString(ldb_dn_canonical_ex_string(self->dn, self->dn));
 }
 
 static PyObject *py_ldb_dn_extended_str(PyLdbDnObject *self, PyObject *args, PyObject *kwargs)
@@ -401,7 +488,7 @@ static PyObject *py_ldb_dn_extended_str(PyLdbDnObject *self, PyObject *args, PyO
 					 discard_const_p(char *, kwnames),
 					 &mode))
 		return NULL;
-	return PyString_FromString(ldb_dn_get_extended_linearized(self->dn, self->dn, mode));
+	return PyStr_FromString(ldb_dn_get_extended_linearized(self->dn, self->dn, mode));
 }
 
 static PyObject *py_ldb_dn_get_extended_component(PyLdbDnObject *self, PyObject *args)
@@ -416,28 +503,25 @@ static PyObject *py_ldb_dn_get_extended_component(PyLdbDnObject *self, PyObject
 		Py_RETURN_NONE;
 	}
 
-	return PyString_FromStringAndSize((const char *)val->data, val->length);
+	return PyBytes_FromStringAndSize((const char *)val->data, val->length);
 }
 
 static PyObject *py_ldb_dn_set_extended_component(PyLdbDnObject *self, PyObject *args)
 {
 	char *name;
-	PyObject *value;
 	int err;
+	uint8_t *value;
+	Py_ssize_t size = 0;
 
-	if (!PyArg_ParseTuple(args, "sO", &name, &value))
+	if (!PyArg_ParseTuple(args, "sz#", &name, (const char**)&value, &size))
 		return NULL;
 
-	if (value == Py_None) {
+	if (value == NULL) {
 		err = ldb_dn_set_extended_component(self->dn, name, NULL);
 	} else {
 		struct ldb_val val;
-		if (!PyString_Check(value)) {
-			PyErr_SetString(PyExc_TypeError, "Expected a string argument");
-			return NULL;
-		}
-		val.data = (uint8_t *)PyString_AsString(value);
-		val.length = PyString_Size(value);
+		val.data = (uint8_t *)value;
+		val.length = size;
 		err = ldb_dn_set_extended_component(self->dn, name, &val);
 	}
 
@@ -451,7 +535,19 @@ static PyObject *py_ldb_dn_set_extended_component(PyLdbDnObject *self, PyObject
 
 static PyObject *py_ldb_dn_repr(PyLdbDnObject *self)
 {
-	return PyString_FromFormat("Dn(%s)", PyObject_REPR(PyString_FromString(ldb_dn_get_linearized(self->dn))));
+	PyObject *str = PyStr_FromString(ldb_dn_get_linearized(self->dn));
+	PyObject *repr, *result;
+	if (str == NULL)
+		return NULL;
+	repr = PyObject_Repr(str);
+	if (repr == NULL) {
+		Py_DECREF(str);
+		return NULL;
+	}
+	result = PyStr_FromFormat("Dn(%s)", PyStr_AsUTF8(repr));
+	Py_DECREF(str);
+	Py_DECREF(repr);
+	return result;
 }
 
 static PyObject *py_ldb_dn_check_special(PyLdbDnObject *self, PyObject *args)
@@ -464,13 +560,15 @@ static PyObject *py_ldb_dn_check_special(PyLdbDnObject *self, PyObject *args)
 	return PyBool_FromLong(ldb_dn_check_special(self->dn, name));
 }
 
-static int py_ldb_dn_compare(PyLdbDnObject *dn1, PyLdbDnObject *dn2)
+static PyObject *py_ldb_dn_richcmp(PyObject *dn1, PyObject *dn2, int op)
 {
 	int ret;
-	ret = ldb_dn_compare(dn1->dn, dn2->dn);
-	if (ret < 0) ret = -1;
-	if (ret > 0) ret = 1;
-	return ret;
+	if (!pyldb_Dn_Check(dn2)) {
+		Py_INCREF(Py_NotImplemented);
+		return Py_NotImplemented;
+	}
+	ret = ldb_dn_compare(pyldb_Dn_AsDn(dn1), pyldb_Dn_AsDn(dn2));
+	return richcmp(ret, op);
 }
 
 static PyObject *py_ldb_dn_get_parent(PyLdbDnObject *self)
@@ -497,8 +595,6 @@ static PyObject *py_ldb_dn_get_parent(PyLdbDnObject *self)
 	return (PyObject *)py_ret;
 }
 
-#define dn_ldb_ctx(dn) ((struct ldb_context *)dn)
-
 static PyObject *py_ldb_dn_add_child(PyLdbDnObject *self, PyObject *args)
 {
 	PyObject *py_other;
@@ -508,7 +604,7 @@ static PyObject *py_ldb_dn_add_child(PyLdbDnObject *self, PyObject *args)
 
 	dn = pyldb_Dn_AsDn((PyObject *)self);
 
-	if (!pyldb_Object_AsDn(NULL, py_other, dn_ldb_ctx(dn), &other))
+	if (!pyldb_Object_AsDn(NULL, py_other, ldb_dn_get_ldb_context(dn), &other))
 		return NULL;
 
 	return PyBool_FromLong(ldb_dn_add_child(dn, other));
@@ -523,7 +619,7 @@ static PyObject *py_ldb_dn_add_base(PyLdbDnObject *self, PyObject *args)
 
 	dn = pyldb_Dn_AsDn((PyObject *)self);
 
-	if (!pyldb_Object_AsDn(NULL, py_other, dn_ldb_ctx(dn), &other))
+	if (!pyldb_Object_AsDn(NULL, py_other, ldb_dn_get_ldb_context(dn), &other))
 		return NULL;
 
 	return PyBool_FromLong(ldb_dn_add_base(dn, other));
@@ -550,7 +646,7 @@ static PyObject *py_ldb_dn_is_child_of(PyLdbDnObject *self, PyObject *args)
 
 	dn = pyldb_Dn_AsDn((PyObject *)self);
 
-	if (!pyldb_Object_AsDn(NULL, py_base, dn_ldb_ctx(dn), &base))
+	if (!pyldb_Object_AsDn(NULL, py_base, ldb_dn_get_ldb_context(dn), &base))
 		return NULL;
 
 	return PyBool_FromLong(ldb_dn_compare_base(base, dn) == 0);
@@ -572,7 +668,7 @@ static PyObject *py_ldb_dn_get_component_name(PyLdbDnObject *self, PyObject *arg
 		Py_RETURN_NONE;
 	}
 
-	return PyString_FromString(name);
+	return PyStr_FromString(name);
 }
 
 static PyObject *py_ldb_dn_get_component_value(PyLdbDnObject *self, PyObject *args)
@@ -591,28 +687,22 @@ static PyObject *py_ldb_dn_get_component_value(PyLdbDnObject *self, PyObject *ar
 		Py_RETURN_NONE;
 	}
 
-	return PyObject_FromLdbValue(val);
+	return PyStr_FromLdbValue(val);
 }
 
 static PyObject *py_ldb_dn_set_component(PyLdbDnObject *self, PyObject *args)
 {
 	unsigned int num = 0;
-	char *name = NULL;
-	PyObject *value = Py_None;
+	char *name = NULL, *value = NULL;
 	struct ldb_val val = { NULL, };
 	int err;
+	Py_ssize_t size = 0;
 
-	if (!PyArg_ParseTuple(args, "IsO", &num, &name, &value))
+	if (!PyArg_ParseTuple(args, "Iss#", &num, &name, &value, &size))
 		return NULL;
 
-	if (value != Py_None) {
-		if (!PyString_Check(value)) {
-			PyErr_SetString(PyExc_TypeError, "Expected a string argument");
-			return NULL;
-		}
-		val.data = (uint8_t *)PyString_AsString(value);
-		val.length = PyString_Size(value);
-	}
+	val.data = (unsigned char*) value;
+	val.length = size;
 
 	err = ldb_dn_set_component(self->dn, num, name, val);
 	if (err != LDB_SUCCESS) {
@@ -635,7 +725,7 @@ static PyObject *py_ldb_dn_get_rdn_name(PyLdbDnObject *self)
 		Py_RETURN_NONE;
 	}
 
-	return PyString_FromString(name);
+	return PyStr_FromString(name);
 }
 
 static PyObject *py_ldb_dn_get_rdn_value(PyLdbDnObject *self)
@@ -650,7 +740,7 @@ static PyObject *py_ldb_dn_get_rdn_value(PyLdbDnObject *self)
 		Py_RETURN_NONE;
 	}
 
-	return PyObject_FromLdbValue(val);
+	return PyStr_FromLdbValue(val);
 }
 
 static PyMethodDef py_ldb_dn_methods[] = {
@@ -822,7 +912,7 @@ static PyTypeObject PyLdbDn = {
 	.tp_methods = py_ldb_dn_methods,
 	.tp_str = (reprfunc)py_ldb_dn_get_linearized,
 	.tp_repr = (reprfunc)py_ldb_dn_repr,
-	.tp_compare = (cmpfunc)py_ldb_dn_compare,
+	.tp_richcompare = (richcmpfunc)py_ldb_dn_richcmp,
 	.tp_as_sequence = &py_ldb_dn_seq,
 	.tp_doc = "A LDB distinguished name.",
 	.tp_new = py_ldb_dn_new,
@@ -836,9 +926,11 @@ static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *
 static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap)
 {
 	PyObject *fn = (PyObject *)context;
-	PyObject_CallFunction(fn, discard_const_p(char, "(i,O)"), level, PyString_FromFormatV(fmt, ap));
+	PyObject_CallFunction(fn, discard_const_p(char, "(i,O)"), level, PyStr_FromFormatV(fmt, ap));
 }
 
+static PyObject *py_ldb_debug_func;
+
 static PyObject *py_ldb_set_debug(PyObject *self, PyObject *args)
 {
 	PyObject *cb;
@@ -847,8 +939,13 @@ static PyObject *py_ldb_set_debug(PyObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "O", &cb))
 		return NULL;
 
+	if (py_ldb_debug_func != NULL) {
+		Py_DECREF(py_ldb_debug_func);
+	}
+
 	Py_INCREF(cb);
-	/* FIXME: Where do we DECREF cb ? */
+	/* FIXME: DECREF cb when exiting program */
+	py_ldb_debug_func = cb;
 	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
 	PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError,
 		ldb_set_debug(ldb_ctx, py_ldb_debug, cb),
@@ -926,7 +1023,7 @@ static PyObject *py_ldb_setup_wellknown_attributes(PyLdbObject *self)
 
 static PyObject *py_ldb_repr(PyLdbObject *self)
 {
-	return PyString_FromFormat("<ldb connection>");
+	return PyStr_FromString("<ldb connection>");
 }
 
 static PyObject *py_ldb_get_root_basedn(PyLdbObject *self)
@@ -962,8 +1059,8 @@ static PyObject *py_ldb_get_default_basedn(PyLdbObject *self)
 	return py_ldb_dn_copy(dn);
 }
 
-static const char **PyList_AsStringList(TALLOC_CTX *mem_ctx, PyObject *list, 
-					const char *paramname)
+static const char **PyList_AsStrList(TALLOC_CTX *mem_ctx, PyObject *list,
+                    const char *paramname)
 {
 	const char **ret;
 	Py_ssize_t i;
@@ -978,13 +1075,20 @@ static const char **PyList_AsStringList(TALLOC_CTX *mem_ctx, PyObject *list,
 	}
 
 	for (i = 0; i < PyList_Size(list); i++) {
+		const char *str = NULL;
+		Py_ssize_t size;
 		PyObject *item = PyList_GetItem(list, i);
-		if (!PyString_Check(item)) {
+		if (!PyStr_Check(item)) {
 			PyErr_Format(PyExc_TypeError, "%s should be strings", paramname);
+			talloc_free(ret);
+			return NULL;
+		}
+		str = PyStr_AsUTF8AndSize(item, &size);
+		if (str == NULL) {
+			talloc_free(ret);
 			return NULL;
 		}
-		ret[i] = talloc_strndup(ret, PyString_AsString(item),
-					PyString_Size(item));
+		ret[i] = talloc_strndup(ret, str, size);
 	}
 	ret[i] = NULL;
 	return ret;
@@ -1010,7 +1114,7 @@ static int py_ldb_init(PyLdbObject *self, PyObject *args, PyObject *kwargs)
 	if (py_options == Py_None) {
 		options = NULL;
 	} else {
-		options = PyList_AsStringList(ldb, py_options, "options");
+		options = PyList_AsStrList(ldb, py_options, "options");
 		if (options == NULL)
 			return -1;
 	}
@@ -1066,7 +1170,7 @@ static PyObject *py_ldb_connect(PyLdbObject *self, PyObject *args, PyObject *kwa
 	if (py_options == Py_None) {
 		options = NULL;
 	} else {
-		options = PyList_AsStringList(NULL, py_options, "options");
+		options = PyList_AsStrList(NULL, py_options, "options");
 		if (options == NULL)
 			return NULL;
 	}
@@ -1108,7 +1212,7 @@ static PyObject *py_ldb_modify(PyLdbObject *self, PyObject *args, PyObject *kwar
 	if (py_controls == Py_None) {
 		parsed_controls = NULL;
 	} else {
-		const char **controls = PyList_AsStringList(mem_ctx, py_controls, "controls");
+		const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
 		if (controls == NULL) {
 			talloc_free(mem_ctx);
 			return NULL;
@@ -1135,7 +1239,7 @@ static PyObject *py_ldb_modify(PyLdbObject *self, PyObject *args, PyObject *kwar
 
 	ret = ldb_build_mod_req(&req, ldb_ctx, mem_ctx, msg, parsed_controls,
 				NULL, ldb_op_default_callback, NULL);
-        if (ret != LDB_SUCCESS) {
+	if (ret != LDB_SUCCESS) {
 		PyErr_SetString(PyExc_TypeError, "failed to build request");
 		talloc_free(mem_ctx);
 		return NULL;
@@ -1212,7 +1316,7 @@ static struct ldb_message *PyDict_AsMessage(TALLOC_CTX *mem_ctx,
 	}
 
 	while (PyDict_Next(py_obj, &dict_pos, &key, &value)) {
-		char *key_str = PyString_AsString(key);
+		char *key_str = PyStr_AsUTF8(key);
 		if (ldb_attr_cmp(key_str, "dn") != 0) {
 			msg_el = PyObject_AsMessageElement(msg->elements, value,
 							   mod_flags, key_str);
@@ -1257,7 +1361,7 @@ static PyObject *py_ldb_add(PyLdbObject *self, PyObject *args, PyObject *kwargs)
 	if (py_controls == Py_None) {
 		parsed_controls = NULL;
 	} else {
-		const char **controls = PyList_AsStringList(mem_ctx, py_controls, "controls");
+		const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
 		if (controls == NULL) {
 			talloc_free(mem_ctx);
 			return NULL;
@@ -1350,7 +1454,7 @@ static PyObject *py_ldb_delete(PyLdbObject *self, PyObject *args, PyObject *kwar
 	if (py_controls == Py_None) {
 		parsed_controls = NULL;
 	} else {
-		const char **controls = PyList_AsStringList(mem_ctx, py_controls, "controls");
+		const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
 		if (controls == NULL) {
 			talloc_free(mem_ctx);
 			return NULL;
@@ -1428,7 +1532,7 @@ static PyObject *py_ldb_rename(PyLdbObject *self, PyObject *args, PyObject *kwar
 	if (py_controls == Py_None) {
 		parsed_controls = NULL;
 	} else {
-		const char **controls = PyList_AsStringList(mem_ctx, py_controls, "controls");
+		const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
 		if (controls == NULL) {
 			talloc_free(mem_ctx);
 			return NULL;
@@ -1553,7 +1657,7 @@ static PyObject *py_ldb_write_ldif(PyLdbObject *self, PyObject *args)
 		return NULL;
 	}
 
-	ret = PyString_FromString(string);
+	ret = PyStr_FromString(string);
 
 	talloc_free(mem_ctx);
 
@@ -1642,14 +1746,16 @@ static PyObject *py_ldb_schema_format_value(PyLdbObject *self, PyObject *args)
 	PyObject *ret;
 	char *element_name;
 	PyObject *val;
+	Py_ssize_t size;
+	int result;
 
 	if (!PyArg_ParseTuple(args, "sO", &element_name, &val))
 		return NULL;
 
-	old_val.data = (uint8_t *)PyString_AsString(val);
-	old_val.length = PyString_Size(val);
+	result = PyBytes_AsStringAndSize(val, (char **)&old_val.data, &size);
+	old_val.length = size;
 
-	if (old_val.data == NULL) {
+	if (result != 0) {
 		PyErr_SetString(PyExc_RuntimeError, "Failed to convert passed value to String");
 		return NULL;
 	}
@@ -1671,7 +1777,7 @@ static PyObject *py_ldb_schema_format_value(PyLdbObject *self, PyObject *args)
 		Py_RETURN_NONE;
 	}
 
-	ret = PyString_FromStringAndSize((const char *)new_val.data, new_val.length);
+	ret = PyBytes_FromStringAndSize((const char *)new_val.data, new_val.length);
 
 	talloc_free(mem_ctx);
 
@@ -1713,7 +1819,7 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar
 	if (py_attrs == Py_None) {
 		attrs = NULL;
 	} else {
-		attrs = PyList_AsStringList(mem_ctx, py_attrs, "attrs");
+		attrs = PyList_AsStrList(mem_ctx, py_attrs, "attrs");
 		if (attrs == NULL) {
 			talloc_free(mem_ctx);
 			return NULL;
@@ -1723,8 +1829,8 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar
 	if (py_base == Py_None) {
 		base = ldb_get_default_basedn(ldb_ctx);
 	} else {
-		if (!pyldb_Object_AsDn(ldb_ctx, py_base, ldb_ctx, &base)) {
-			talloc_free(attrs);
+		if (!pyldb_Object_AsDn(mem_ctx, py_base, ldb_ctx, &base)) {
+			talloc_free(mem_ctx);
 			return NULL;
 		}
 	}
@@ -1732,7 +1838,7 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar
 	if (py_controls == Py_None) {
 		parsed_controls = NULL;
 	} else {
-		const char **controls = PyList_AsStringList(mem_ctx, py_controls, "controls");
+		const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
 		if (controls == NULL) {
 			talloc_free(mem_ctx);
 			return NULL;
@@ -1785,6 +1891,200 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar
 	return py_ret;
 }
 
+static int py_ldb_search_iterator_reply_destructor(struct py_ldb_search_iterator_reply *reply)
+{
+	if (reply->py_iter != NULL) {
+		DLIST_REMOVE(reply->py_iter->state.next, reply);
+		if (reply->py_iter->state.result == reply) {
+			reply->py_iter->state.result = NULL;
+		}
+		reply->py_iter = NULL;
+	}
+
+	if (reply->obj != NULL) {
+		Py_DECREF(reply->obj);
+		reply->obj = NULL;
+	}
+
+	return 0;
+}
+
+static int py_ldb_search_iterator_callback(struct ldb_request *req,
+					   struct ldb_reply *ares)
+{
+	PyLdbSearchIteratorObject *py_iter = (PyLdbSearchIteratorObject *)req->context;
+	struct ldb_result result = { .msgs = NULL };
+	struct py_ldb_search_iterator_reply *reply = NULL;
+
+	if (ares == NULL) {
+		return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+	}
+
+	if (ares->error != LDB_SUCCESS) {
+		int ret = ares->error;
+		TALLOC_FREE(ares);
+		return ldb_request_done(req, ret);
+	}
+
+	reply = talloc_zero(py_iter->mem_ctx,
+			    struct py_ldb_search_iterator_reply);
+	if (reply == NULL) {
+		TALLOC_FREE(ares);
+		return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+	}
+	reply->py_iter = py_iter;
+	talloc_set_destructor(reply, py_ldb_search_iterator_reply_destructor);
+
+	switch (ares->type) {
+	case LDB_REPLY_ENTRY:
+		reply->obj = PyLdbMessage_FromMessage(ares->message);
+		if (reply->obj == NULL) {
+			TALLOC_FREE(ares);
+			return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+		}
+		DLIST_ADD_END(py_iter->state.next, reply);
+		TALLOC_FREE(ares);
+		return LDB_SUCCESS;
+
+	case LDB_REPLY_REFERRAL:
+		reply->obj = PyStr_FromString(ares->referral);
+		if (reply->obj == NULL) {
+			TALLOC_FREE(ares);
+			return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+		}
+		DLIST_ADD_END(py_iter->state.next, reply);
+		TALLOC_FREE(ares);
+		return LDB_SUCCESS;
+
+	case LDB_REPLY_DONE:
+		result = (struct ldb_result) { .controls = ares->controls };
+		reply->obj = PyLdbResult_FromResult(&result);
+		if (reply->obj == NULL) {
+			TALLOC_FREE(ares);
+			return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+		}
+		py_iter->state.result = reply;
+		TALLOC_FREE(ares);
+		return ldb_request_done(req, LDB_SUCCESS);
+	}
+
+	TALLOC_FREE(ares);
+	return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+}
+
+static PyObject *py_ldb_search_iterator(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+	PyObject *py_base = Py_None;
+	int scope = LDB_SCOPE_DEFAULT;
+	int timeout = 0;
+	char *expr = NULL;
+	PyObject *py_attrs = Py_None;
+	PyObject *py_controls = Py_None;
+	const char * const kwnames[] = { "base", "scope", "expression", "attrs", "controls", "timeout", NULL };
+	int ret;
+	const char **attrs;
+	struct ldb_context *ldb_ctx;
+	struct ldb_control **parsed_controls;
+	struct ldb_dn *base;
+	PyLdbSearchIteratorObject *py_iter;
+
+	/* type "int" rather than "enum" for "scope" is intentional */
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OizOOi",
+					 discard_const_p(char *, kwnames),
+					 &py_base, &scope, &expr, &py_attrs, &py_controls, &timeout))
+		return NULL;
+
+	py_iter = (PyLdbSearchIteratorObject *)PyLdbSearchIterator.tp_alloc(&PyLdbSearchIterator, 0);
+	if (py_iter == NULL) {
+		PyErr_NoMemory();
+		return NULL;
+	}
+	py_iter->ldb = self;
+	Py_INCREF(self);
+	ZERO_STRUCT(py_iter->state);
+	py_iter->mem_ctx = talloc_new(NULL);
+	if (py_iter->mem_ctx == NULL) {
+		Py_DECREF(py_iter);
+		PyErr_NoMemory();
+		return NULL;
+	}
+
+	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+
+	if (py_attrs == Py_None) {
+		attrs = NULL;
+	} else {
+		attrs = PyList_AsStrList(py_iter->mem_ctx, py_attrs, "attrs");
+		if (attrs == NULL) {
+			Py_DECREF(py_iter);
+			PyErr_NoMemory();
+			return NULL;
+		}
+	}
+
+	if (py_base == Py_None) {
+		base = ldb_get_default_basedn(ldb_ctx);
+	} else {
+		if (!pyldb_Object_AsDn(py_iter->mem_ctx, py_base, ldb_ctx, &base)) {
+			Py_DECREF(py_iter);
+			PyErr_NoMemory();
+			return NULL;
+		}
+	}
+
+	if (py_controls == Py_None) {
+		parsed_controls = NULL;
+	} else {
+		const char **controls = NULL;
+
+		controls = PyList_AsStrList(py_iter->mem_ctx,
+					    py_controls, "controls");
+		if (controls == NULL) {
+			Py_DECREF(py_iter);
+			PyErr_NoMemory();
+			return NULL;
+		}
+
+		parsed_controls = ldb_parse_control_strings(ldb_ctx,
+							    py_iter->mem_ctx,
+							    controls);
+		if (controls[0] != NULL && parsed_controls == NULL) {
+			Py_DECREF(py_iter);
+			PyErr_NoMemory();
+			return NULL;
+		}
+		talloc_free(controls);
+	}
+
+	ret = ldb_build_search_req(&py_iter->state.req,
+				   ldb_ctx,
+				   py_iter->mem_ctx,
+				   base,
+				   scope,
+				   expr,
+				   attrs,
+				   parsed_controls,
+				   py_iter,
+				   py_ldb_search_iterator_callback,
+				   NULL);
+	if (ret != LDB_SUCCESS) {
+		Py_DECREF(py_iter);
+		PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+		return NULL;
+	}
+
+	ldb_set_timeout(ldb_ctx, py_iter->state.req, timeout);
+
+	ret = ldb_request(ldb_ctx, py_iter->state.req);
+	if (ret != LDB_SUCCESS) {
+		Py_DECREF(py_iter);
+		PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+		return NULL;
+	}
+
+	return (PyObject *)py_iter;
+}
+
 static PyObject *py_ldb_get_opaque(PyLdbObject *self, PyObject *args)
 {
 	char *name;
@@ -1800,7 +2100,7 @@ static PyObject *py_ldb_get_opaque(PyLdbObject *self, PyObject *args)
 
 	/* FIXME: More interpretation */
 
-	return Py_True;
+	Py_RETURN_TRUE;
 }
 
 static PyObject *py_ldb_set_opaque(PyLdbObject *self, PyObject *args)
@@ -1848,6 +2148,28 @@ static PyObject *py_ldb_sequence_number(PyLdbObject *self, PyObject *args)
 
 	return PyLong_FromLongLong(value);
 }
+
+
+static const struct ldb_dn_extended_syntax test_dn_syntax = {
+	.name             = "TEST",
+	.read_fn          = ldb_handler_copy,
+	.write_clear_fn   = ldb_handler_copy,
+	.write_hex_fn     = ldb_handler_copy,
+};
+
+static PyObject *py_ldb_register_test_extensions(PyLdbObject *self)
+{
+	struct ldb_context *ldb = pyldb_Ldb_AsLdbContext(self);
+	int ret;
+
+	ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &test_dn_syntax);
+
+	PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb);
+
+	Py_RETURN_NONE;
+}
+
+
 static PyMethodDef py_ldb_methods[] = {
 	{ "set_debug", (PyCFunction)py_ldb_set_debug, METH_VARARGS, 
 		"S.set_debug(callback) -> None\n"
@@ -1897,7 +2219,7 @@ static PyMethodDef py_ldb_methods[] = {
 		"S.rename(old_dn, new_dn, controls=None) -> None\n"
 		"Rename an entry." },
 	{ "search", (PyCFunction)py_ldb_search, METH_VARARGS|METH_KEYWORDS,
-		"S.search(base=None, scope=None, expression=None, attrs=None, controls=None) -> msgs\n"
+		"S.search(base=None, scope=None, expression=None, attrs=None, controls=None) -> result\n"
 		"Search in a database.\n"
 		"\n"
 		":param base: Optional base DN to search\n"
@@ -1905,7 +2227,19 @@ static PyMethodDef py_ldb_methods[] = {
 		":param expression: Optional search expression\n"
 		":param attrs: Attributes to return (defaults to all)\n"
 		":param controls: Optional list of controls\n"
-		":return: Iterator over Message objects\n"
+		":return: ldb.Result object\n"
+	},
+	{ "search_iterator", (PyCFunction)py_ldb_search_iterator, METH_VARARGS|METH_KEYWORDS,
+		"S.search_iterator(base=None, scope=None, expression=None, attrs=None, controls=None, timeout=None) -> iterator\n"
+		"Search in a database.\n"
+		"\n"
+		":param base: Optional base DN to search\n"
+		":param scope: Search scope (SCOPE_BASE, SCOPE_ONELEVEL or SCOPE_SUBTREE)\n"
+		":param expression: Optional search expression\n"
+		":param attrs: Attributes to return (defaults to all)\n"
+		":param controls: Optional list of controls\n"
+		":param timeout: Optional timeout in seconds (defaults to 300), 0 means the default, -1 no timeout\n"
+		":return: ldb.SearchIterator object that provides results when they arrive\n"
 	},
 	{ "schema_attribute_remove", (PyCFunction)py_ldb_schema_attribute_remove, METH_VARARGS,
 		NULL },
@@ -1937,6 +2271,9 @@ static PyMethodDef py_ldb_methods[] = {
 	{ "sequence_number", (PyCFunction)py_ldb_sequence_number, METH_VARARGS,
 		"S.sequence_number(type) -> value\n"
 		"Return the value of the sequence according to the requested type" },
+	{ "_register_test_extensions", (PyCFunction)py_ldb_register_test_extensions, METH_NOARGS,
+		"S._register_test_extensions() -> None\n"
+		"Register internal extensions used in testing" },
 	{ NULL },
 };
 
@@ -1956,7 +2293,11 @@ static PyObject *PyLdbModule_FromModule(struct ldb_module *mod)
 
 static PyObject *py_ldb_get_firstmodule(PyLdbObject *self, void *closure)
 {
-	return PyLdbModule_FromModule(pyldb_Ldb_AsLdbContext(self)->modules);
+	struct ldb_module *mod = pyldb_Ldb_AsLdbContext(self)->modules;
+	if (mod == NULL) {
+		Py_RETURN_NONE;
+	}
+	return PyLdbModule_FromModule(mod);
 }
 
 static PyGetSetDef py_ldb_getset[] = {
@@ -2105,7 +2446,7 @@ static PySequenceMethods py_ldb_result_seq = {
 
 static PyObject *py_ldb_result_repr(PyLdbObject *self)
 {
-	return PyString_FromFormat("<ldb result>");
+	return PyStr_FromString("<ldb result>");
 }
 
 
@@ -2122,15 +2463,156 @@ static PyTypeObject PyLdbResult = {
 	.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 };
 
+static void py_ldb_search_iterator_dealloc(PyLdbSearchIteratorObject *self)
+{
+	Py_XDECREF(self->state.exception);
+	TALLOC_FREE(self->mem_ctx);
+	ZERO_STRUCT(self->state);
+	Py_DECREF(self->ldb);
+	Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *py_ldb_search_iterator_next(PyLdbSearchIteratorObject *self)
+{
+	PyObject *py_ret = NULL;
+
+	if (self->state.req == NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator request already finished");
+		return NULL;
+	}
+
+	/*
+	 * TODO: do we want a non-blocking mode?
+	 * In future we may add an optional 'nonblocking'
+	 * argument to search_iterator().
+	 *
+	 * For now we keep it simple and wait for at
+	 * least one reply.
+	 */
+
+	while (self->state.next == NULL) {
+		int ret;
+
+		if (self->state.result != NULL) {
+			/*
+			 * We (already) got a final result from the server.
+			 *
+			 * We stop the iteration and let
+			 * py_ldb_search_iterator_result() will deliver
+			 * the result details.
+			 */
+			TALLOC_FREE(self->state.req);
+			PyErr_SetNone(PyExc_StopIteration);
+			return NULL;
+		}
+
+		ret = ldb_wait(self->state.req->handle, LDB_WAIT_NONE);
+		if (ret != LDB_SUCCESS) {
+			struct ldb_context *ldb_ctx;
+			TALLOC_FREE(self->state.req);
+			ldb_ctx = pyldb_Ldb_AsLdbContext(self->ldb);
+			/*
+			 * We stop the iteration and let
+			 * py_ldb_search_iterator_result() will deliver
+			 * the exception.
+			 */
+			self->state.exception = Py_BuildValue(discard_const_p(char, "(i,s)"),
+						ret, ldb_errstring(ldb_ctx));
+			PyErr_SetNone(PyExc_StopIteration);
+			return NULL;
+		}
+	}
+
+	py_ret = self->state.next->obj;
+	self->state.next->obj = NULL;
+	/* no TALLOC_FREE() as self->state.next is a list */
+	talloc_free(self->state.next);
+	return py_ret;
+}
+
+static PyObject *py_ldb_search_iterator_result(PyLdbSearchIteratorObject *self)
+{
+	PyObject *py_ret = NULL;
+
+	if (self->state.req != NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator request running");
+		return NULL;
+	}
+
+	if (self->state.next != NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator not fully consumed.");
+		return NULL;
+	}
+
+	if (self->state.exception != NULL) {
+		PyErr_SetObject(PyExc_LdbError, self->state.exception);
+		self->state.exception = NULL;
+		return NULL;
+	}
+
+	if (self->state.result == NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator result already consumed");
+		return NULL;
+	}
+
+	py_ret = self->state.result->obj;
+	self->state.result->obj = NULL;
+	TALLOC_FREE(self->state.result);
+	return py_ret;
+}
+
+static PyObject *py_ldb_search_iterator_abandon(PyLdbSearchIteratorObject *self)
+{
+	if (self->state.req == NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator request already finished");
+		return NULL;
+	}
+
+	Py_XDECREF(self->state.exception);
+	TALLOC_FREE(self->mem_ctx);
+	ZERO_STRUCT(self->state);
+	Py_RETURN_NONE;
+}
+
+static PyMethodDef py_ldb_search_iterator_methods[] = {
+	{ "result", (PyCFunction)py_ldb_search_iterator_result, METH_NOARGS,
+		"S.result() -> ldb.Result (without msgs and referrals)\n" },
+	{ "abandon", (PyCFunction)py_ldb_search_iterator_abandon, METH_NOARGS,
+		"S.abandon()\n" },
+	{ NULL }
+};
+
+static PyObject *py_ldb_search_iterator_repr(PyLdbSearchIteratorObject *self)
+{
+	return PyStr_FromString("<ldb search iterator>");
+}
+
+static PyTypeObject PyLdbSearchIterator = {
+	.tp_name = "ldb.SearchIterator",
+	.tp_repr = (reprfunc)py_ldb_search_iterator_repr,
+	.tp_dealloc = (destructor)py_ldb_search_iterator_dealloc,
+	.tp_iter = PyObject_SelfIter,
+	.tp_iternext = (iternextfunc)py_ldb_search_iterator_next,
+	.tp_methods = py_ldb_search_iterator_methods,
+	.tp_basicsize = sizeof(PyLdbSearchIteratorObject),
+	.tp_doc = "LDB search_iterator.",
+	.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+};
+
 static PyObject *py_ldb_module_repr(PyLdbModuleObject *self)
 {
-	return PyString_FromFormat("<ldb module '%s'>",
+	return PyStr_FromFormat("<ldb module '%s'>",
 		pyldb_Module_AsModule(self)->ops->name);
 }
 
 static PyObject *py_ldb_module_str(PyLdbModuleObject *self)
 {
-	return PyString_FromString(pyldb_Module_AsModule(self)->ops->name);
+	return PyStr_FromString(pyldb_Module_AsModule(self)->ops->name);
 }
 
 static PyObject *py_ldb_module_start_transaction(PyLdbModuleObject *self)
@@ -2171,7 +2653,7 @@ static PyObject *py_ldb_module_search(PyLdbModuleObject *self, PyObject *args, P
 	if (py_attrs == Py_None) {
 		attrs = NULL;
 	} else {
-		attrs = PyList_AsStringList(NULL, py_attrs, "attrs");
+		attrs = PyList_AsStrList(NULL, py_attrs, "attrs");
 		if (attrs == NULL)
 			return NULL;
 	}
@@ -2335,6 +2817,9 @@ static struct ldb_message_element *PyObject_AsMessageElement(
 						      const char *attr_name)
 {
 	struct ldb_message_element *me;
+	const char *msg = NULL;
+	Py_ssize_t size;
+	int result;
 
 	if (pyldb_MessageElement_Check(set_obj)) {
 		PyLdbMessageElementObject *set_obj_as_me = (PyLdbMessageElementObject *)set_obj;
@@ -2354,28 +2839,58 @@ static struct ldb_message_element *PyObject_AsMessageElement(
 
 	me->name = talloc_strdup(me, attr_name);
 	me->flags = flags;
-	if (PyString_Check(set_obj)) {
+	if (PyBytes_Check(set_obj) || PyStr_Check(set_obj)) {
 		me->num_values = 1;
 		me->values = talloc_array(me, struct ldb_val, me->num_values);
-		me->values[0].length = PyString_Size(set_obj);
-		me->values[0].data = talloc_memdup(me, 
-			(uint8_t *)PyString_AsString(set_obj), me->values[0].length+1);
+		if (PyBytes_Check(set_obj)) {
+			char *_msg = NULL;
+			result = PyBytes_AsStringAndSize(set_obj, &_msg, &size);
+			if (result != 0) {
+				talloc_free(me);
+				return NULL;
+			}
+			msg = _msg;
+		} else {
+			msg = PyStr_AsUTF8AndSize(set_obj, &size);
+			if (msg == NULL) {
+				talloc_free(me);
+				return NULL;
+			}
+		}
+		me->values[0].data = talloc_memdup(me,
+						   (const uint8_t *)msg,
+						   size+1);
+		me->values[0].length = size;
 	} else if (PySequence_Check(set_obj)) {
 		Py_ssize_t i;
 		me->num_values = PySequence_Size(set_obj);
 		me->values = talloc_array(me, struct ldb_val, me->num_values);
 		for (i = 0; i < me->num_values; i++) {
 			PyObject *obj = PySequence_GetItem(set_obj, i);
-			if (!PyString_Check(obj)) {
+			if (PyBytes_Check(obj)) {
+				char *_msg = NULL;
+				result = PyBytes_AsStringAndSize(obj, &_msg, &size);
+				if (result != 0) {
+					talloc_free(me);
+					return NULL;
+				}
+				msg = _msg;
+			} else if (PyStr_Check(obj)) {
+				msg = PyStr_AsUTF8AndSize(obj, &size);
+				if (msg == NULL) {
+					talloc_free(me);
+					return NULL;
+				}
+			} else {
 				PyErr_Format(PyExc_TypeError,
 					     "Expected string as element %zd in list", i);
 				talloc_free(me);
 				return NULL;
 			}
-
-			me->values[i].length = PyString_Size(obj);
-			me->values[i].data = talloc_memdup(me, 
-				(uint8_t *)PyString_AsString(obj), me->values[i].length+1);
+			me->values[i].data = talloc_memdup(me,
+							   (const uint8_t *)msg,
+							   size+1);
+			me->values[i].length = size;
 		}
 	} else {
 		PyErr_Format(PyExc_TypeError,
@@ -2453,7 +2968,7 @@ static PyObject *py_ldb_msg_element_find(PyLdbMessageElementObject *self, Py_ssi
 		PyErr_SetString(PyExc_IndexError, "Out of range");
 		return NULL;
 	}
-	return PyString_FromStringAndSize((char *)el->values[idx].data, el->values[idx].length);
+	return PyBytes_FromStringAndSize((char *)el->values[idx].data, el->values[idx].length);
 }
 
 static PySequenceMethods py_ldb_msg_element_seq = {
@@ -2461,11 +2976,16 @@ static PySequenceMethods py_ldb_msg_element_seq = {
 	.sq_item = (ssizeargfunc)py_ldb_msg_element_find,
 };
 
-static int py_ldb_msg_element_cmp(PyLdbMessageElementObject *self, PyLdbMessageElementObject *other)
+static PyObject *py_ldb_msg_element_richcmp(PyObject *self, PyObject *other, int op)
 {
-	int ret = ldb_msg_element_compare(pyldb_MessageElement_AsMessageElement(self),
+	int ret;
+	if (!pyldb_MessageElement_Check(other)) {
+		Py_INCREF(Py_NotImplemented);
+		return Py_NotImplemented;
+	}
+	ret = ldb_msg_element_compare(pyldb_MessageElement_AsMessageElement(self),
 									  pyldb_MessageElement_AsMessageElement(other));
-	return SIGN(ret);
+	return richcmp(ret, op);
 }
 
 static PyObject *py_ldb_msg_element_iter(PyLdbMessageElementObject *self)
@@ -2503,6 +3023,9 @@ static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyOb
 	const char * const kwnames[] = { "elements", "flags", "name", NULL };
 	PyLdbMessageElementObject *ret;
 	TALLOC_CTX *mem_ctx;
+	const char *msg = NULL;
+	Py_ssize_t size;
+	int result;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OIs",
 					 discard_const_p(char *, kwnames),
@@ -2524,7 +3047,8 @@ static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyOb
 
 	if (py_elements != NULL) {
 		Py_ssize_t i;
-		if (PyString_Check(py_elements)) {
+		if (PyBytes_Check(py_elements)) {
+			char *_msg = NULL;
 			el->num_values = 1;
 			el->values = talloc_array(el, struct ldb_val, 1);
 			if (el->values == NULL) {
@@ -2532,9 +3056,15 @@ static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyOb
 				PyErr_NoMemory();
 				return NULL;
 			}
-			el->values[0].length = PyString_Size(py_elements);
+			result = PyBytes_AsStringAndSize(py_elements, &_msg, &size);
+			if (result != 0) {
+				talloc_free(mem_ctx);
+				return NULL;
+			}
+			msg = _msg;
 			el->values[0].data = talloc_memdup(el->values, 
-				(uint8_t *)PyString_AsString(py_elements), el->values[0].length+1);
+				(const uint8_t *)msg, size + 1);
+			el->values[0].length = size;
 		} else if (PySequence_Check(py_elements)) {
 			el->num_values = PySequence_Size(py_elements);
 			el->values = talloc_array(el, struct ldb_val, el->num_values);
@@ -2549,15 +3079,25 @@ static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyOb
 					talloc_free(mem_ctx);
 					return NULL;
 				}
-				if (!PyString_Check(item)) {
+				if (PyBytes_Check(item)) {
+					char *_msg = NULL;
+					result = PyBytes_AsStringAndSize(item, &_msg, &size);
+					msg = _msg;
+				} else if (PyStr_Check(item)) {
+					msg = PyStr_AsUTF8AndSize(item, &size);
+					result = (msg == NULL) ? -1 : 0;
+				} else {
 					PyErr_Format(PyExc_TypeError, 
 						     "Expected string as element %zd in list", i);
+					result = -1;
+				}
+				if (result != 0) {
 					talloc_free(mem_ctx);
 					return NULL;
 				}
-				el->values[i].length = PyString_Size(item);
 				el->values[i].data = talloc_memdup(el,
-					(uint8_t *)PyString_AsString(item), el->values[i].length+1);
+					(const uint8_t *)msg, size+1);
+				el->values[i].length = size;
 			}
 		} else {
 			PyErr_SetString(PyExc_TypeError, 
@@ -2592,17 +3132,17 @@ static PyObject *py_ldb_msg_element_repr(PyLdbMessageElementObject *self)
 		PyObject *o = py_ldb_msg_element_find(self, i);
 		repr = PyObject_Repr(o);
 		if (element_str == NULL)
-			element_str = talloc_strdup(NULL, PyString_AsString(repr));
+			element_str = talloc_strdup(NULL, PyStr_AsUTF8(repr));
 		else
-			element_str = talloc_asprintf_append(element_str, ",%s", PyString_AsString(repr));
+			element_str = talloc_asprintf_append(element_str, ",%s", PyStr_AsUTF8(repr));
 		Py_DECREF(repr);
 	}
 
 	if (element_str != NULL) {
-		ret = PyString_FromFormat("MessageElement([%s])", element_str);
+		ret = PyStr_FromFormat("MessageElement([%s])", element_str);
 		talloc_free(element_str);
 	} else {
-		ret = PyString_FromString("MessageElement([])");
+		ret = PyStr_FromString("MessageElement([])");
 	}
 
 	return ret;
@@ -2613,7 +3153,7 @@ static PyObject *py_ldb_msg_element_str(PyLdbMessageElementObject *self)
 	struct ldb_message_element *el = pyldb_MessageElement_AsMessageElement(self);
 
 	if (el->num_values == 1)
-		return PyString_FromStringAndSize((char *)el->values[0].data, el->values[0].length);
+		return PyStr_FromStringAndSize((char *)el->values[0].data, el->values[0].length);
 	else
 		Py_RETURN_NONE;
 }
@@ -2624,6 +3164,16 @@ static void py_ldb_msg_element_dealloc(PyLdbMessageElementObject *self)
 	PyObject_Del(self);
 }
 
+static PyObject *py_ldb_msg_element_get_text(PyObject *self, void *closure)
+{
+	return wrap_text("MessageElementTextWrapper", self);
+}
+
+static PyGetSetDef py_ldb_msg_element_getset[] = {
+	{ discard_const_p(char, "text"), (getter)py_ldb_msg_element_get_text, NULL, NULL },
+	{ NULL }
+};
+
 static PyTypeObject PyLdbMessageElement = {
 	.tp_name = "ldb.MessageElement",
 	.tp_basicsize = sizeof(PyLdbMessageElementObject),
@@ -2631,7 +3181,8 @@ static PyTypeObject PyLdbMessageElement = {
 	.tp_repr = (reprfunc)py_ldb_msg_element_repr,
 	.tp_str = (reprfunc)py_ldb_msg_element_str,
 	.tp_methods = py_ldb_msg_element_methods,
-	.tp_compare = (cmpfunc)py_ldb_msg_element_cmp,
+	.tp_getset = py_ldb_msg_element_getset,
+	.tp_richcompare = (richcmpfunc)py_ldb_msg_element_richcmp,
 	.tp_iter = (getiterfunc)py_ldb_msg_element_iter,
 	.tp_as_sequence = &py_ldb_msg_element_seq,
 	.tp_new = py_ldb_msg_element_new,
@@ -2700,11 +3251,11 @@ static PyObject *py_ldb_msg_keys(PyLdbMessageObject *self)
 	Py_ssize_t i, j = 0;
 	PyObject *obj = PyList_New(msg->num_elements+(msg->dn != NULL?1:0));
 	if (msg->dn != NULL) {
-		PyList_SetItem(obj, j, PyString_FromString("dn"));
+		PyList_SetItem(obj, j, PyStr_FromString("dn"));
 		j++;
 	}
 	for (i = 0; i < msg->num_elements; i++) {
-		PyList_SetItem(obj, j, PyString_FromString(msg->elements[i].name));
+		PyList_SetItem(obj, j, PyStr_FromString(msg->elements[i].name));
 		j++;
 	}
 	return obj;
@@ -2715,11 +3266,11 @@ static PyObject *py_ldb_msg_getitem_helper(PyLdbMessageObject *self, PyObject *p
 	struct ldb_message_element *el;
 	char *name;
 	struct ldb_message *msg = pyldb_Message_AsMessage(self);
-	if (!PyString_Check(py_name)) {
+	name = PyStr_AsUTF8(py_name);
+	if (name == NULL) {
 		PyErr_SetNone(PyExc_TypeError);
 		return NULL;
 	}
-	name = PyString_AsString(py_name);
 	if (!ldb_attr_cmp(name, "dn"))
 		return pyldb_Dn_FromDn(msg->dn);
 	el = ldb_msg_find_element(msg, name);
@@ -2761,6 +3312,7 @@ static PyObject *py_ldb_msg_get(PyLdbMessageObject *self, PyObject *args, PyObje
 
 	if (el == NULL || (idx != -1 && el->num_values <= idx)) {
 		if (def != NULL) {
+			Py_INCREF(def);
 			return def;
 		}
 		Py_RETURN_NONE;
@@ -2880,12 +3432,12 @@ static int py_ldb_msg_setitem(PyLdbMessageObject *self, PyObject *name, PyObject
 {
 	char *attr_name;
 
-	if (!PyString_Check(name)) {
+	attr_name = PyStr_AsUTF8(name);
+	if (attr_name == NULL) {
 		PyErr_SetNone(PyExc_TypeError);
 		return -1;
 	}
 
-	attr_name = PyString_AsString(name);
 	if (value == NULL) {
 		/* delitem */
 		ldb_msg_remove_attr(self->msg, attr_name);
@@ -2996,17 +3548,29 @@ static int py_ldb_msg_set_dn(PyLdbMessageObject *self, PyObject *value, void *cl
 	return 0;
 }
 
+static PyObject *py_ldb_msg_get_text(PyObject *self, void *closure)
+{
+	return wrap_text("MessageTextWrapper", self);
+}
+
 static PyGetSetDef py_ldb_msg_getset[] = {
 	{ discard_const_p(char, "dn"), (getter)py_ldb_msg_get_dn, (setter)py_ldb_msg_set_dn, NULL },
+	{ discard_const_p(char, "text"), (getter)py_ldb_msg_get_text, NULL, NULL },
 	{ NULL }
 };
 
 static PyObject *py_ldb_msg_repr(PyLdbMessageObject *self)
 {
-	PyObject *dict = PyDict_New(), *ret;
+	PyObject *dict = PyDict_New(), *ret, *repr;
 	if (PyDict_Update(dict, (PyObject *)self) != 0)
 		return NULL;
-	ret = PyString_FromFormat("Message(%s)", PyObject_REPR(dict));
+	repr = PyObject_Repr(dict);
+	if (repr == NULL) {
+		Py_DECREF(dict);
+		return NULL;
+	}
+	ret = PyStr_FromFormat("Message(%s)", PyStr_AsUTF8(repr));
+	Py_DECREF(repr);
 	Py_DECREF(dict);
 	return ret;
 }
@@ -3017,41 +3581,48 @@ static void py_ldb_msg_dealloc(PyLdbMessageObject *self)
 	PyObject_Del(self);
 }
 
-static int py_ldb_msg_compare(PyLdbMessageObject *py_msg1,
-			      PyLdbMessageObject *py_msg2)
+static PyObject *py_ldb_msg_richcmp(PyLdbMessageObject *py_msg1,
+			      PyLdbMessageObject *py_msg2, int op)
 {
-	struct ldb_message *msg1 = pyldb_Message_AsMessage(py_msg1),
-			   *msg2 = pyldb_Message_AsMessage(py_msg2);
+	struct ldb_message *msg1, *msg2;
 	unsigned int i;
 	int ret;
 
+	if (!PyLdbMessage_Check(py_msg2)) {
+		Py_INCREF(Py_NotImplemented);
+		return Py_NotImplemented;
+	}
+
+	msg1 = pyldb_Message_AsMessage(py_msg1),
+	msg2 = pyldb_Message_AsMessage(py_msg2);
+
 	if ((msg1->dn != NULL) || (msg2->dn != NULL)) {
 		ret = ldb_dn_compare(msg1->dn, msg2->dn);
 		if (ret != 0) {
-			return SIGN(ret);
+			return richcmp(ret, op);
 		}
 	}
 
 	ret = msg1->num_elements - msg2->num_elements;
 	if (ret != 0) {
-		return SIGN(ret);
+		return richcmp(ret, op);
 	}
 
 	for (i = 0; i < msg1->num_elements; i++) {
 		ret = ldb_msg_element_compare_name(&msg1->elements[i],
 						   &msg2->elements[i]);
 		if (ret != 0) {
-			return SIGN(ret);
+			return richcmp(ret, op);
 		}
 
 		ret = ldb_msg_element_compare(&msg1->elements[i],
 					      &msg2->elements[i]);
 		if (ret != 0) {
-			return SIGN(ret);
+			return richcmp(ret, op);
 		}
 	}
 
-	return 0;
+	return richcmp(0, op);
 }
 
 static PyTypeObject PyLdbMessage = {
@@ -3065,7 +3636,7 @@ static PyTypeObject PyLdbMessage = {
 	.tp_repr = (reprfunc)py_ldb_msg_repr,
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 	.tp_iter = (getiterfunc)py_ldb_msg_iter,
-	.tp_compare = (cmpfunc)py_ldb_msg_compare,
+	.tp_richcompare = (richcmpfunc)py_ldb_msg_richcmp,
 	.tp_doc = "A LDB Message",
 };
 
@@ -3121,7 +3692,7 @@ static int py_module_search(struct ldb_module *mod, struct ldb_request *req)
 		for (len = 0; req->op.search.attrs[len]; len++);
 		py_attrs = PyList_New(len);
 		for (i = 0; i < len; i++)
-			PyList_SetItem(py_attrs, i, PyString_FromString(req->op.search.attrs[i]));
+			PyList_SetItem(py_attrs, i, PyStr_FromString(req->op.search.attrs[i]));
 	}
 
 	py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "search"),
@@ -3379,7 +3950,7 @@ static PyObject *py_register_module(PyObject *module, PyObject *args)
 		return NULL;
 	}
 
-	ops->name = talloc_strdup(ops, PyString_AsString(PyObject_GetAttrString(input, discard_const_p(char, "name"))));
+	ops->name = talloc_strdup(ops, PyStr_AsUTF8(PyObject_GetAttrString(input, discard_const_p(char, "name"))));
 
 	Py_INCREF(input);
 	ops->private_data = input;
@@ -3412,7 +3983,7 @@ static PyObject *py_timestring(PyObject *module, PyObject *args)
 	if (!PyArg_ParseTuple(args, "l", &t_val))
 		return NULL;
 	tresult = ldb_timestring(NULL, (time_t) t_val);
-	ret = PyString_FromString(tresult);
+	ret = PyStr_FromString(tresult);
 	talloc_free(tresult);
 	return ret;
 }
@@ -3440,7 +4011,7 @@ static PyObject *py_valid_attr_name(PyObject *self, PyObject *args)
 static PyObject *py_binary_encode(PyObject *self, PyObject *args)
 {
 	char *str, *encoded;
-	int size = 0;
+	Py_ssize_t size = 0;
 	struct ldb_val val;
 	PyObject *ret;
 
@@ -3454,7 +4025,7 @@ static PyObject *py_binary_encode(PyObject *self, PyObject *args)
 		PyErr_SetString(PyExc_TypeError, "unable to encode binary string");
 		return NULL;
 	}
-	ret = PyString_FromString(encoded);
+	ret = PyStr_FromString(encoded);
 	talloc_free(encoded);
 	return ret;
 }
@@ -3476,7 +4047,7 @@ static PyObject *py_binary_decode(PyObject *self, PyObject *args)
 		PyErr_SetString(PyExc_TypeError, "unable to decode binary string");
 		return NULL;
 	}
-	ret = Py_BuildValue("s#", val.data, val.length);
+	ret = PyBytes_FromStringAndSize((const char*)val.data, val.length);
 	talloc_free(val.data);
 	return ret;
 }
@@ -3506,102 +4077,130 @@ static PyMethodDef py_ldb_global_methods[] = {
 	{ NULL }
 };
 
-void initldb(void)
+#define MODULE_DOC "An interface to LDB, a LDAP-like API that can either to talk an embedded database (TDB-based) or a standards-compliant LDAP server."
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+	PyModuleDef_HEAD_INIT,
+	.m_name = "ldb",
+	.m_doc = MODULE_DOC,
+	.m_size = -1,
+	.m_methods = py_ldb_global_methods,
+};
+#endif
+
+static PyObject* module_init(void)
 {
 	PyObject *m;
 
 	if (PyType_Ready(&PyLdbDn) < 0)
-		return;
+		return NULL;
 
 	if (PyType_Ready(&PyLdbMessage) < 0)
-		return;
+		return NULL;
 
 	if (PyType_Ready(&PyLdbMessageElement) < 0)
-		return;
+		return NULL;
 
 	if (PyType_Ready(&PyLdb) < 0)
-		return;
+		return NULL;
 
 	if (PyType_Ready(&PyLdbModule) < 0)
-		return;
+		return NULL;
 
 	if (PyType_Ready(&PyLdbTree) < 0)
-		return;
+		return NULL;
 
 	if (PyType_Ready(&PyLdbResult) < 0)
-		return;
+		return NULL;
+
+	if (PyType_Ready(&PyLdbSearchIterator) < 0)
+		return NULL;
 
 	if (PyType_Ready(&PyLdbControl) < 0)
-		return;
+		return NULL;
 
-	m = Py_InitModule3("ldb", py_ldb_global_methods, 
-		"An interface to LDB, a LDAP-like API that can either to talk an embedded database (TDB-based) or a standards-compliant LDAP server.");
+#if PY_MAJOR_VERSION >= 3
+	m = PyModule_Create(&moduledef);
+#else
+	m = Py_InitModule3("ldb", py_ldb_global_methods, MODULE_DOC);
+#endif
 	if (m == NULL)
-		return;
-
-	PyModule_AddObject(m, "SEQ_HIGHEST_SEQ", PyInt_FromLong(LDB_SEQ_HIGHEST_SEQ));
-	PyModule_AddObject(m, "SEQ_HIGHEST_TIMESTAMP", PyInt_FromLong(LDB_SEQ_HIGHEST_TIMESTAMP));
-	PyModule_AddObject(m, "SEQ_NEXT", PyInt_FromLong(LDB_SEQ_NEXT));
-	PyModule_AddObject(m, "SCOPE_DEFAULT", PyInt_FromLong(LDB_SCOPE_DEFAULT));
-	PyModule_AddObject(m, "SCOPE_BASE", PyInt_FromLong(LDB_SCOPE_BASE));
-	PyModule_AddObject(m, "SCOPE_ONELEVEL", PyInt_FromLong(LDB_SCOPE_ONELEVEL));
-	PyModule_AddObject(m, "SCOPE_SUBTREE", PyInt_FromLong(LDB_SCOPE_SUBTREE));
-
-	PyModule_AddObject(m, "CHANGETYPE_NONE", PyInt_FromLong(LDB_CHANGETYPE_NONE));
-	PyModule_AddObject(m, "CHANGETYPE_ADD", PyInt_FromLong(LDB_CHANGETYPE_ADD));
-	PyModule_AddObject(m, "CHANGETYPE_DELETE", PyInt_FromLong(LDB_CHANGETYPE_DELETE));
-	PyModule_AddObject(m, "CHANGETYPE_MODIFY", PyInt_FromLong(LDB_CHANGETYPE_MODIFY));
-
-	PyModule_AddObject(m, "FLAG_MOD_ADD", PyInt_FromLong(LDB_FLAG_MOD_ADD));
-	PyModule_AddObject(m, "FLAG_MOD_REPLACE", PyInt_FromLong(LDB_FLAG_MOD_REPLACE));
-	PyModule_AddObject(m, "FLAG_MOD_DELETE", PyInt_FromLong(LDB_FLAG_MOD_DELETE));
-
-	PyModule_AddObject(m, "SUCCESS", PyInt_FromLong(LDB_SUCCESS));
-	PyModule_AddObject(m, "ERR_OPERATIONS_ERROR", PyInt_FromLong(LDB_ERR_OPERATIONS_ERROR));
-	PyModule_AddObject(m, "ERR_PROTOCOL_ERROR", PyInt_FromLong(LDB_ERR_PROTOCOL_ERROR));
-	PyModule_AddObject(m, "ERR_TIME_LIMIT_EXCEEDED", PyInt_FromLong(LDB_ERR_TIME_LIMIT_EXCEEDED));
-	PyModule_AddObject(m, "ERR_SIZE_LIMIT_EXCEEDED", PyInt_FromLong(LDB_ERR_SIZE_LIMIT_EXCEEDED));
-	PyModule_AddObject(m, "ERR_COMPARE_FALSE", PyInt_FromLong(LDB_ERR_COMPARE_FALSE));
-	PyModule_AddObject(m, "ERR_COMPARE_TRUE", PyInt_FromLong(LDB_ERR_COMPARE_TRUE));
-	PyModule_AddObject(m, "ERR_AUTH_METHOD_NOT_SUPPORTED", PyInt_FromLong(LDB_ERR_AUTH_METHOD_NOT_SUPPORTED));
-	PyModule_AddObject(m, "ERR_STRONG_AUTH_REQUIRED", PyInt_FromLong(LDB_ERR_STRONG_AUTH_REQUIRED));
-	PyModule_AddObject(m, "ERR_REFERRAL", PyInt_FromLong(LDB_ERR_REFERRAL));
-	PyModule_AddObject(m, "ERR_ADMIN_LIMIT_EXCEEDED", PyInt_FromLong(LDB_ERR_ADMIN_LIMIT_EXCEEDED));
-	PyModule_AddObject(m, "ERR_UNSUPPORTED_CRITICAL_EXTENSION", PyInt_FromLong(LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION));
-	PyModule_AddObject(m, "ERR_CONFIDENTIALITY_REQUIRED", PyInt_FromLong(LDB_ERR_CONFIDENTIALITY_REQUIRED));
-	PyModule_AddObject(m, "ERR_SASL_BIND_IN_PROGRESS", PyInt_FromLong(LDB_ERR_SASL_BIND_IN_PROGRESS));
-	PyModule_AddObject(m, "ERR_NO_SUCH_ATTRIBUTE", PyInt_FromLong(LDB_ERR_NO_SUCH_ATTRIBUTE));
-	PyModule_AddObject(m, "ERR_UNDEFINED_ATTRIBUTE_TYPE", PyInt_FromLong(LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE));
-	PyModule_AddObject(m, "ERR_INAPPROPRIATE_MATCHING", PyInt_FromLong(LDB_ERR_INAPPROPRIATE_MATCHING));
-	PyModule_AddObject(m, "ERR_CONSTRAINT_VIOLATION", PyInt_FromLong(LDB_ERR_CONSTRAINT_VIOLATION));
-	PyModule_AddObject(m, "ERR_ATTRIBUTE_OR_VALUE_EXISTS", PyInt_FromLong(LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS));
-	PyModule_AddObject(m, "ERR_INVALID_ATTRIBUTE_SYNTAX", PyInt_FromLong(LDB_ERR_INVALID_ATTRIBUTE_SYNTAX));
-	PyModule_AddObject(m, "ERR_NO_SUCH_OBJECT", PyInt_FromLong(LDB_ERR_NO_SUCH_OBJECT));
-	PyModule_AddObject(m, "ERR_ALIAS_PROBLEM", PyInt_FromLong(LDB_ERR_ALIAS_PROBLEM));
-	PyModule_AddObject(m, "ERR_INVALID_DN_SYNTAX", PyInt_FromLong(LDB_ERR_INVALID_DN_SYNTAX));
-	PyModule_AddObject(m, "ERR_ALIAS_DEREFERINCING_PROBLEM", PyInt_FromLong(LDB_ERR_ALIAS_DEREFERENCING_PROBLEM));
-	PyModule_AddObject(m, "ERR_INAPPROPRIATE_AUTHENTICATION", PyInt_FromLong(LDB_ERR_INAPPROPRIATE_AUTHENTICATION));
-	PyModule_AddObject(m, "ERR_INVALID_CREDENTIALS", PyInt_FromLong(LDB_ERR_INVALID_CREDENTIALS));
-	PyModule_AddObject(m, "ERR_INSUFFICIENT_ACCESS_RIGHTS", PyInt_FromLong(LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS));
-	PyModule_AddObject(m, "ERR_BUSY", PyInt_FromLong(LDB_ERR_BUSY));
-	PyModule_AddObject(m, "ERR_UNAVAILABLE", PyInt_FromLong(LDB_ERR_UNAVAILABLE));
-	PyModule_AddObject(m, "ERR_UNWILLING_TO_PERFORM", PyInt_FromLong(LDB_ERR_UNWILLING_TO_PERFORM));
-	PyModule_AddObject(m, "ERR_LOOP_DETECT", PyInt_FromLong(LDB_ERR_LOOP_DETECT));
-	PyModule_AddObject(m, "ERR_NAMING_VIOLATION", PyInt_FromLong(LDB_ERR_NAMING_VIOLATION));
-	PyModule_AddObject(m, "ERR_OBJECT_CLASS_VIOLATION", PyInt_FromLong(LDB_ERR_OBJECT_CLASS_VIOLATION));
-	PyModule_AddObject(m, "ERR_NOT_ALLOWED_ON_NON_LEAF", PyInt_FromLong(LDB_ERR_NOT_ALLOWED_ON_NON_LEAF));
-	PyModule_AddObject(m, "ERR_NOT_ALLOWED_ON_RDN", PyInt_FromLong(LDB_ERR_NOT_ALLOWED_ON_RDN));
-	PyModule_AddObject(m, "ERR_ENTRY_ALREADY_EXISTS", PyInt_FromLong(LDB_ERR_ENTRY_ALREADY_EXISTS));
-	PyModule_AddObject(m, "ERR_OBJECT_CLASS_MODS_PROHIBITED", PyInt_FromLong(LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED));
-	PyModule_AddObject(m, "ERR_AFFECTS_MULTIPLE_DSAS", PyInt_FromLong(LDB_ERR_AFFECTS_MULTIPLE_DSAS));
-	PyModule_AddObject(m, "ERR_OTHER", PyInt_FromLong(LDB_ERR_OTHER));
-
-	PyModule_AddObject(m, "FLG_RDONLY", PyInt_FromLong(LDB_FLG_RDONLY));
-	PyModule_AddObject(m, "FLG_NOSYNC", PyInt_FromLong(LDB_FLG_NOSYNC));
-	PyModule_AddObject(m, "FLG_RECONNECT", PyInt_FromLong(LDB_FLG_RECONNECT));
-	PyModule_AddObject(m, "FLG_NOMMAP", PyInt_FromLong(LDB_FLG_NOMMAP));
-
-	PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText"));
+		return NULL;
+
+#define ADD_LDB_INT(val) PyModule_AddIntConstant(m, #val, LDB_ ## val)
+
+	ADD_LDB_INT(SEQ_HIGHEST_SEQ);
+	ADD_LDB_INT(SEQ_HIGHEST_TIMESTAMP);
+	ADD_LDB_INT(SEQ_NEXT);
+	ADD_LDB_INT(SCOPE_DEFAULT);
+	ADD_LDB_INT(SCOPE_BASE);
+	ADD_LDB_INT(SCOPE_ONELEVEL);
+	ADD_LDB_INT(SCOPE_SUBTREE);
+
+	ADD_LDB_INT(CHANGETYPE_NONE);
+	ADD_LDB_INT(CHANGETYPE_ADD);
+	ADD_LDB_INT(CHANGETYPE_DELETE);
+	ADD_LDB_INT(CHANGETYPE_MODIFY);
+
+	ADD_LDB_INT(FLAG_MOD_ADD);
+	ADD_LDB_INT(FLAG_MOD_REPLACE);
+	ADD_LDB_INT(FLAG_MOD_DELETE);
+
+	ADD_LDB_INT(ATTR_FLAG_HIDDEN);
+	ADD_LDB_INT(ATTR_FLAG_UNIQUE_INDEX);
+	ADD_LDB_INT(ATTR_FLAG_SINGLE_VALUE);
+	ADD_LDB_INT(ATTR_FLAG_FORCE_BASE64_LDIF);
+
+	ADD_LDB_INT(SUCCESS);
+	ADD_LDB_INT(ERR_OPERATIONS_ERROR);
+	ADD_LDB_INT(ERR_PROTOCOL_ERROR);
+	ADD_LDB_INT(ERR_TIME_LIMIT_EXCEEDED);
+	ADD_LDB_INT(ERR_SIZE_LIMIT_EXCEEDED);
+	ADD_LDB_INT(ERR_COMPARE_FALSE);
+	ADD_LDB_INT(ERR_COMPARE_TRUE);
+	ADD_LDB_INT(ERR_AUTH_METHOD_NOT_SUPPORTED);
+	ADD_LDB_INT(ERR_STRONG_AUTH_REQUIRED);
+	ADD_LDB_INT(ERR_REFERRAL);
+	ADD_LDB_INT(ERR_ADMIN_LIMIT_EXCEEDED);
+	ADD_LDB_INT(ERR_UNSUPPORTED_CRITICAL_EXTENSION);
+	ADD_LDB_INT(ERR_CONFIDENTIALITY_REQUIRED);
+	ADD_LDB_INT(ERR_SASL_BIND_IN_PROGRESS);
+	ADD_LDB_INT(ERR_NO_SUCH_ATTRIBUTE);
+	ADD_LDB_INT(ERR_UNDEFINED_ATTRIBUTE_TYPE);
+	ADD_LDB_INT(ERR_INAPPROPRIATE_MATCHING);
+	ADD_LDB_INT(ERR_CONSTRAINT_VIOLATION);
+	ADD_LDB_INT(ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+	ADD_LDB_INT(ERR_INVALID_ATTRIBUTE_SYNTAX);
+	ADD_LDB_INT(ERR_NO_SUCH_OBJECT);
+	ADD_LDB_INT(ERR_ALIAS_PROBLEM);
+	ADD_LDB_INT(ERR_INVALID_DN_SYNTAX);
+	ADD_LDB_INT(ERR_ALIAS_DEREFERENCING_PROBLEM);
+	ADD_LDB_INT(ERR_INAPPROPRIATE_AUTHENTICATION);
+	ADD_LDB_INT(ERR_INVALID_CREDENTIALS);
+	ADD_LDB_INT(ERR_INSUFFICIENT_ACCESS_RIGHTS);
+	ADD_LDB_INT(ERR_BUSY);
+	ADD_LDB_INT(ERR_UNAVAILABLE);
+	ADD_LDB_INT(ERR_UNWILLING_TO_PERFORM);
+	ADD_LDB_INT(ERR_LOOP_DETECT);
+	ADD_LDB_INT(ERR_NAMING_VIOLATION);
+	ADD_LDB_INT(ERR_OBJECT_CLASS_VIOLATION);
+	ADD_LDB_INT(ERR_NOT_ALLOWED_ON_NON_LEAF);
+	ADD_LDB_INT(ERR_NOT_ALLOWED_ON_RDN);
+	ADD_LDB_INT(ERR_ENTRY_ALREADY_EXISTS);
+	ADD_LDB_INT(ERR_OBJECT_CLASS_MODS_PROHIBITED);
+	ADD_LDB_INT(ERR_AFFECTS_MULTIPLE_DSAS);
+	ADD_LDB_INT(ERR_OTHER);
+
+	ADD_LDB_INT(FLG_RDONLY);
+	ADD_LDB_INT(FLG_NOSYNC);
+	ADD_LDB_INT(FLG_RECONNECT);
+	ADD_LDB_INT(FLG_NOMMAP);
+
+	/* Historical misspelling */
+	PyModule_AddIntConstant(m, "ERR_ALIAS_DEREFERINCING_PROBLEM", LDB_ERR_ALIAS_DEREFERENCING_PROBLEM);
+
+	PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
 
 	PyExc_LdbError = PyErr_NewException(discard_const_p(char, "_ldb.LdbError"), NULL, NULL);
 	PyModule_AddObject(m, "LdbError", PyExc_LdbError);
@@ -3623,9 +4222,9 @@ void initldb(void)
 	PyModule_AddObject(m, "Tree", (PyObject *)&PyLdbTree);
 	PyModule_AddObject(m, "Control", (PyObject *)&PyLdbControl);
 
-	PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION));
+	PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
 
-#define ADD_LDB_STRING(val)  PyModule_AddObject(m, #val, PyString_FromString(LDB_## val))
+#define ADD_LDB_STRING(val)  PyModule_AddStringConstant(m, #val, LDB_## val)
 
 	ADD_LDB_STRING(SYNTAX_DN);
 	ADD_LDB_STRING(SYNTAX_DIRECTORY_STRING);
@@ -3635,4 +4234,20 @@ void initldb(void)
 	ADD_LDB_STRING(SYNTAX_UTC_TIME);
 	ADD_LDB_STRING(OID_COMPARATOR_AND);
 	ADD_LDB_STRING(OID_COMPARATOR_OR);
+
+	return m;
 }
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC PyInit_ldb(void);
+PyMODINIT_FUNC PyInit_ldb(void)
+{
+	return module_init();
+}
+#else
+void initldb(void);
+void initldb(void)
+{
+	module_init();
+}
+#endif
diff --git a/lib/ldb/pyldb.h b/lib/ldb/pyldb.h
index f8aea22..e0cce1e 100644
--- a/lib/ldb/pyldb.h
+++ b/lib/ldb/pyldb.h
@@ -60,11 +60,18 @@ typedef struct {
 } PyLdbModuleObject;
 #define pyldb_Module_AsModule(pyobj) ((PyLdbModuleObject *)pyobj)->mod
 
+/*
+ * NOTE: el (and so the return value of
+ * pyldb_MessageElement_AsMessageElement()) may not be a valid talloc
+ * context, it could be part of an array
+ */
+
 typedef struct {
 	PyObject_HEAD
 	TALLOC_CTX *mem_ctx;
 	struct ldb_message_element *el;
 } PyLdbMessageElementObject;
+
 #define pyldb_MessageElement_AsMessageElement(pyobj) ((PyLdbMessageElementObject *)pyobj)->el
 
 typedef struct {
diff --git a/lib/ldb/pyldb_util.c b/lib/ldb/pyldb_util.c
index 4be9126..3bda1db 100644
--- a/lib/ldb/pyldb_util.c
+++ b/lib/ldb/pyldb_util.c
@@ -29,11 +29,12 @@
 
 static PyObject *ldb_module = NULL;
 
-/* There's no Py_ssize_t in 2.4, apparently */
-#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
-typedef int Py_ssize_t;
-typedef inquiry lenfunc;
-typedef intargfunc ssizeargfunc;
+#if PY_MAJOR_VERSION >= 3
+#define PyStr_Check PyUnicode_Check
+#define PyStr_AsUTF8 PyUnicode_AsUTF8
+#else
+#define PyStr_Check PyString_Check
+#define PyStr_AsUTF8 PyString_AsString
 #endif
 
 /**
@@ -69,8 +70,14 @@ bool pyldb_Object_AsDn(TALLOC_CTX *mem_ctx, PyObject *object,
 	struct ldb_dn *odn;
 	PyTypeObject *PyLdb_Dn_Type;
 
-	if (ldb_ctx != NULL && PyString_Check(object)) {
-		odn = ldb_dn_new(mem_ctx, ldb_ctx, PyString_AsString(object));
+	if (ldb_ctx != NULL && PyStr_Check(object)) {
+		odn = ldb_dn_new(mem_ctx, ldb_ctx, PyStr_AsUTF8(object));
+		*dn = odn;
+		return true;
+	}
+
+	if (ldb_ctx != NULL && PyBytes_Check(object)) {
+		odn = ldb_dn_new(mem_ctx, ldb_ctx, PyBytes_AsString(object));
 		*dn = odn;
 		return true;
 	}
diff --git a/lib/ldb/tests/python/api.py b/lib/ldb/tests/python/api.py
index d101de8..c2b3c89 100755
--- a/lib/ldb/tests/python/api.py
+++ b/lib/ldb/tests/python/api.py
@@ -4,9 +4,12 @@
 
 import os
 from unittest import TestCase
+import sys
 
 import ldb
 
+PY3 = sys.version_info > (3, 0)
+
 
 def filename():
     import tempfile
@@ -24,17 +27,20 @@ class NoContextTests(TestCase):
         self.assertFalse(ldb.valid_attr_name("24foo"))
 
     def test_timestring(self):
-        self.assertEquals("19700101000000.0Z", ldb.timestring(0))
-        self.assertEquals("20071119191012.0Z", ldb.timestring(1195499412))
+        self.assertEqual("19700101000000.0Z", ldb.timestring(0))
+        self.assertEqual("20071119191012.0Z", ldb.timestring(1195499412))
 
     def test_string_to_time(self):
-        self.assertEquals(0, ldb.string_to_time("19700101000000.0Z"))
-        self.assertEquals(1195499412, ldb.string_to_time("20071119191012.0Z"))
+        self.assertEqual(0, ldb.string_to_time("19700101000000.0Z"))
+        self.assertEqual(1195499412, ldb.string_to_time("20071119191012.0Z"))
 
     def test_binary_encode(self):
-        encoded = ldb.binary_encode('test\\x')
+        encoded = ldb.binary_encode(b'test\\x')
         decoded = ldb.binary_decode(encoded)
-        self.assertEquals(decoded, 'test\\x')
+        self.assertEqual(decoded, b'test\\x')
+
+        encoded2 = ldb.binary_encode('test\\x')
+        self.assertEqual(encoded2, encoded)
 
 class SimpleLdb(TestCase):
 
@@ -54,45 +60,55 @@ class SimpleLdb(TestCase):
 
     def test_set_create_perms(self):
         x = ldb.Ldb()
-        x.set_create_perms(0600)
+        x.set_create_perms(0o600)
 
     def test_modules_none(self):
         x = ldb.Ldb()
-        self.assertEquals([], x.modules())
+        self.assertEqual([], x.modules())
 
     def test_modules_tdb(self):
         x = ldb.Ldb(filename())
-        self.assertEquals("[<ldb module 'tdb'>]", repr(x.modules()))
+        self.assertEqual("[<ldb module 'tdb'>]", repr(x.modules()))
+
+    def test_firstmodule_none(self):
+        x = ldb.Ldb()
+        self.assertEqual(x.firstmodule, None)
+
+    def test_firstmodule_tdb(self):
+        x = ldb.Ldb(filename())
+        mod = x.firstmodule
+        self.assertEqual(repr(mod), "<ldb module 'tdb'>")
 
     def test_search(self):
         l = ldb.Ldb(filename())
-        self.assertEquals(len(l.search()), 0)
+        self.assertEqual(len(l.search()), 0)
 
     def test_search_controls(self):
         l = ldb.Ldb(filename())
-        self.assertEquals(len(l.search(controls=["paged_results:0:5"])), 0)
+        self.assertEqual(len(l.search(controls=["paged_results:0:5"])), 0)
 
     def test_search_attrs(self):
         l = ldb.Ldb(filename())
-        self.assertEquals(len(l.search(ldb.Dn(l, ""), ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
+        self.assertEqual(len(l.search(ldb.Dn(l, ""), ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
 
     def test_search_string_dn(self):
         l = ldb.Ldb(filename())
-        self.assertEquals(len(l.search("", ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
+        self.assertEqual(len(l.search("", ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
 
     def test_search_attr_string(self):
         l = ldb.Ldb(filename())
         self.assertRaises(TypeError, l.search, attrs="dc")
+        self.assertRaises(TypeError, l.search, attrs=b"dc")
 
     def test_opaque(self):
         l = ldb.Ldb(filename())
         l.set_opaque("my_opaque", l)
         self.assertTrue(l.get_opaque("my_opaque") is not None)
-        self.assertEquals(None, l.get_opaque("unknown"))
+        self.assertEqual(None, l.get_opaque("unknown"))
 
     def test_search_scope_base(self):
         l = ldb.Ldb(filename())
-        self.assertEquals(len(l.search(ldb.Dn(l, "dc=foo1"), 
+        self.assertEqual(len(l.search(ldb.Dn(l, "dc=foo1"),
                           ldb.SCOPE_ONELEVEL)), 0)
 
     def test_delete(self):
@@ -103,7 +119,7 @@ class SimpleLdb(TestCase):
         l = ldb.Ldb(filename())
         m = ldb.Message()
         m.dn = ldb.Dn(l, "dc=foo1")
-        m["b"] = ["a"]
+        m["b"] = [b"a"]
         l.add(m)
         self.assertRaises(ldb.LdbError, lambda: l.delete(m.dn, ["search_options:1:2"]))
         l.delete(m.dn)
@@ -119,34 +135,147 @@ class SimpleLdb(TestCase):
         l.add(m)
         try:
             self.assertTrue(ldb.Dn(l, "dc=foo3") in l)
+            self.assertFalse(ldb.Dn(l, "dc=foo4") in l)
         finally:
             l.delete(m.dn)
 
     def test_get_config_basedn(self):
         l = ldb.Ldb(filename())
-        self.assertEquals(None, l.get_config_basedn())
+        self.assertEqual(None, l.get_config_basedn())
 
     def test_get_root_basedn(self):
         l = ldb.Ldb(filename())
-        self.assertEquals(None, l.get_root_basedn())
+        self.assertEqual(None, l.get_root_basedn())
 
     def test_get_schema_basedn(self):
         l = ldb.Ldb(filename())
-        self.assertEquals(None, l.get_schema_basedn())
+        self.assertEqual(None, l.get_schema_basedn())
 
     def test_get_default_basedn(self):
         l = ldb.Ldb(filename())
-        self.assertEquals(None, l.get_default_basedn())
+        self.assertEqual(None, l.get_default_basedn())
 
     def test_add(self):
         l = ldb.Ldb(filename())
         m = ldb.Message()
         m.dn = ldb.Dn(l, "dc=foo4")
+        m["bla"] = b"bla"
+        self.assertEqual(len(l.search()), 0)
+        l.add(m)
+        try:
+            self.assertEqual(len(l.search()), 1)
+        finally:
+            l.delete(ldb.Dn(l, "dc=foo4"))
+
+    def test_search_iterator(self):
+        l = ldb.Ldb(filename())
+        s = l.search_iterator()
+        s.abandon()
+        try:
+            for me in s:
+                self.fail()
+            self.fail()
+        except RuntimeError as re:
+            pass
+        try:
+            s.abandon()
+            self.fail()
+        except RuntimeError as re:
+            pass
+        try:
+            s.result()
+            self.fail()
+        except RuntimeError as re:
+            pass
+
+        s = l.search_iterator()
+        count = 0
+        for me in s:
+            self.assertTrue(isinstance(me, ldb.Message))
+            count += 1
+        r = s.result()
+        self.assertEqual(len(r), 0)
+        self.assertEqual(count, 0)
+
+        m1 = ldb.Message()
+        m1.dn = ldb.Dn(l, "dc=foo4")
+        m1["bla"] = b"bla"
+        l.add(m1)
+        try:
+            s = l.search_iterator()
+            msgs = []
+            for me in s:
+                self.assertTrue(isinstance(me, ldb.Message))
+                count += 1
+                msgs.append(me)
+            r = s.result()
+            self.assertEqual(len(r), 0)
+            self.assertEqual(len(msgs), 1)
+            self.assertEqual(msgs[0].dn, m1.dn)
+
+            m2 = ldb.Message()
+            m2.dn = ldb.Dn(l, "dc=foo5")
+            m2["bla"] = b"bla"
+            l.add(m2)
+
+            s = l.search_iterator()
+            msgs = []
+            for me in s:
+                self.assertTrue(isinstance(me, ldb.Message))
+                count += 1
+                msgs.append(me)
+            r = s.result()
+            self.assertEqual(len(r), 0)
+            self.assertEqual(len(msgs), 2)
+            if msgs[0].dn == m1.dn:
+                self.assertEqual(msgs[0].dn, m1.dn)
+                self.assertEqual(msgs[1].dn, m2.dn)
+            else:
+                self.assertEqual(msgs[0].dn, m2.dn)
+                self.assertEqual(msgs[1].dn, m1.dn)
+
+            s = l.search_iterator()
+            msgs = []
+            for me in s:
+                self.assertTrue(isinstance(me, ldb.Message))
+                count += 1
+                msgs.append(me)
+                break
+            try:
+                s.result()
+                self.fail()
+            except RuntimeError as re:
+                pass
+            for me in s:
+                self.assertTrue(isinstance(me, ldb.Message))
+                count += 1
+                msgs.append(me)
+                break
+            for me in s:
+                self.fail()
+
+            r = s.result()
+            self.assertEqual(len(r), 0)
+            self.assertEqual(len(msgs), 2)
+            if msgs[0].dn == m1.dn:
+                self.assertEqual(msgs[0].dn, m1.dn)
+                self.assertEqual(msgs[1].dn, m2.dn)
+            else:
+                self.assertEqual(msgs[0].dn, m2.dn)
+                self.assertEqual(msgs[1].dn, m1.dn)
+        finally:
+            l.delete(ldb.Dn(l, "dc=foo4"))
+            l.delete(ldb.Dn(l, "dc=foo5"))
+
+    def test_add_text(self):
+        l = ldb.Ldb(filename())
+        m = ldb.Message()
+        m.dn = ldb.Dn(l, "dc=foo4")
         m["bla"] = "bla"
-        self.assertEquals(len(l.search()), 0)
+        self.assertEqual(len(l.search()), 0)
         l.add(m)
         try:
-            self.assertEquals(len(l.search()), 1)
+            self.assertEqual(len(l.search()), 1)
         finally:
             l.delete(ldb.Dn(l, "dc=foo4"))
 
@@ -154,28 +283,49 @@ class SimpleLdb(TestCase):
         l = ldb.Ldb(filename())
         m = ldb.Message()
         m.dn = ldb.Dn(l, "dc=foo4")
-        m["bla"] = "bla"
-        self.assertEquals(len(l.search()), 0)
+        m["bla"] = b"bla"
+        self.assertEqual(len(l.search()), 0)
         self.assertRaises(ldb.LdbError, lambda: l.add(m,["search_options:1:2"]))
 
     def test_add_dict(self):
         l = ldb.Ldb(filename())
         m = {"dn": ldb.Dn(l, "dc=foo5"),
+             "bla": b"bla"}
+        self.assertEqual(len(l.search()), 0)
+        l.add(m)
+        try:
+            self.assertEqual(len(l.search()), 1)
+        finally:
+            l.delete(ldb.Dn(l, "dc=foo5"))
+
+    def test_add_dict_text(self):
+        l = ldb.Ldb(filename())
+        m = {"dn": ldb.Dn(l, "dc=foo5"),
              "bla": "bla"}
-        self.assertEquals(len(l.search()), 0)
+        self.assertEqual(len(l.search()), 0)
         l.add(m)
         try:
-            self.assertEquals(len(l.search()), 1)
+            self.assertEqual(len(l.search()), 1)
         finally:
             l.delete(ldb.Dn(l, "dc=foo5"))
 
     def test_add_dict_string_dn(self):
         l = ldb.Ldb(filename())
-        m = {"dn": "dc=foo6", "bla": "bla"}
-        self.assertEquals(len(l.search()), 0)
+        m = {"dn": "dc=foo6", "bla": b"bla"}
+        self.assertEqual(len(l.search()), 0)
+        l.add(m)
+        try:
+            self.assertEqual(len(l.search()), 1)
+        finally:
+            l.delete(ldb.Dn(l, "dc=foo6"))
+
+    def test_add_dict_bytes_dn(self):
+        l = ldb.Ldb(filename())
+        m = {"dn": b"dc=foo6", "bla": b"bla"}
+        self.assertEqual(len(l.search()), 0)
         l.add(m)
         try:
-            self.assertEquals(len(l.search()), 1)
+            self.assertEqual(len(l.search()), 1)
         finally:
             l.delete(ldb.Dn(l, "dc=foo6"))
 
@@ -183,12 +333,12 @@ class SimpleLdb(TestCase):
         l = ldb.Ldb(filename())
         m = ldb.Message()
         m.dn = ldb.Dn(l, "dc=foo7")
-        m["bla"] = "bla"
-        self.assertEquals(len(l.search()), 0)
+        m["bla"] = b"bla"
+        self.assertEqual(len(l.search()), 0)
         l.add(m)
         try:
             l.rename(ldb.Dn(l, "dc=foo7"), ldb.Dn(l, "dc=bar"))
-            self.assertEquals(len(l.search()), 1)
+            self.assertEqual(len(l.search()), 1)
         finally:
             l.delete(ldb.Dn(l, "dc=bar"))
 
@@ -196,34 +346,76 @@ class SimpleLdb(TestCase):
         l = ldb.Ldb(filename())
         m = ldb.Message()
         m.dn = ldb.Dn(l, "dc=foo8")
-        m["bla"] = "bla"
-        self.assertEquals(len(l.search()), 0)
+        m["bla"] = b"bla"
+        self.assertEqual(len(l.search()), 0)
         l.add(m)
-        self.assertEquals(len(l.search()), 1)
+        self.assertEqual(len(l.search()), 1)
         try:
             l.rename("dc=foo8", "dc=bar")
-            self.assertEquals(len(l.search()), 1)
+            self.assertEqual(len(l.search()), 1)
         finally:
             l.delete(ldb.Dn(l, "dc=bar"))
 
+    def test_empty_dn(self):
+        l = ldb.Ldb(filename())
+        self.assertEqual(0, len(l.search()))
+        m = ldb.Message()
+        m.dn = ldb.Dn(l, "dc=empty")
+        l.add(m)
+        rm = l.search()
+        self.assertEqual(1, len(rm))
+        self.assertEqual(set(["dn", "distinguishedName"]), set(rm[0].keys()))
+
+        rm = l.search(m.dn)
+        self.assertEqual(1, len(rm))
+        self.assertEqual(set(["dn", "distinguishedName"]), set(rm[0].keys()))
+        rm = l.search(m.dn, attrs=["blah"])
+        self.assertEqual(1, len(rm))
+        self.assertEqual(0, len(rm[0]))
+
     def test_modify_delete(self):
         l = ldb.Ldb(filename())
         m = ldb.Message()
         m.dn = ldb.Dn(l, "dc=modifydelete")
-        m["bla"] = ["1234"]
+        m["bla"] = [b"1234"]
         l.add(m)
         rm = l.search(m.dn)[0]
-        self.assertEquals(["1234"], list(rm["bla"]))
+        self.assertEqual([b"1234"], list(rm["bla"]))
         try:
             m = ldb.Message()
             m.dn = ldb.Dn(l, "dc=modifydelete")
             m["bla"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "bla")
-            self.assertEquals(ldb.FLAG_MOD_DELETE, m["bla"].flags())
+            self.assertEqual(ldb.FLAG_MOD_DELETE, m["bla"].flags())
             l.modify(m)
-            rm = l.search(m.dn)[0]
-            self.assertEquals(1, len(rm))
+            rm = l.search(m.dn)
+            self.assertEqual(1, len(rm))
+            self.assertEqual(set(["dn", "distinguishedName"]), set(rm[0].keys()))
             rm = l.search(m.dn, attrs=["bla"])
-            self.assertEquals(0, len(rm))
+            self.assertEqual(1, len(rm))
+            self.assertEqual(0, len(rm[0]))
+        finally:
+            l.delete(ldb.Dn(l, "dc=modifydelete"))
+
+    def test_modify_delete_text(self):
+        l = ldb.Ldb(filename())
+        m = ldb.Message()
+        m.dn = ldb.Dn(l, "dc=modifydelete")
+        m.text["bla"] = ["1234"]
+        l.add(m)
+        rm = l.search(m.dn)[0]
+        self.assertEqual(["1234"], list(rm.text["bla"]))
+        try:
+            m = ldb.Message()
+            m.dn = ldb.Dn(l, "dc=modifydelete")
+            m["bla"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "bla")
+            self.assertEqual(ldb.FLAG_MOD_DELETE, m["bla"].flags())
+            l.modify(m)
+            rm = l.search(m.dn)
+            self.assertEqual(1, len(rm))
+            self.assertEqual(set(["dn", "distinguishedName"]), set(rm[0].keys()))
+            rm = l.search(m.dn, attrs=["bla"])
+            self.assertEqual(1, len(rm))
+            self.assertEqual(0, len(rm[0]))
         finally:
             l.delete(ldb.Dn(l, "dc=modifydelete"))
 
@@ -231,17 +423,35 @@ class SimpleLdb(TestCase):
         l = ldb.Ldb(filename())
         m = ldb.Message()
         m.dn = ldb.Dn(l, "dc=add")
-        m["bla"] = ["1234"]
+        m["bla"] = [b"1234"]
+        l.add(m)
+        try:
+            m = ldb.Message()
+            m.dn = ldb.Dn(l, "dc=add")
+            m["bla"] = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
+            self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
+            l.modify(m)
+            rm = l.search(m.dn)[0]
+            self.assertEqual(2, len(rm))
+            self.assertEqual([b"1234", b"456"], list(rm["bla"]))
+        finally:
+            l.delete(ldb.Dn(l, "dc=add"))
+
+    def test_modify_add_text(self):
+        l = ldb.Ldb(filename())
+        m = ldb.Message()
+        m.dn = ldb.Dn(l, "dc=add")
+        m.text["bla"] = ["1234"]
         l.add(m)
         try:
             m = ldb.Message()
             m.dn = ldb.Dn(l, "dc=add")
             m["bla"] = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
-            self.assertEquals(ldb.FLAG_MOD_ADD, m["bla"].flags())
+            self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
             l.modify(m)
             rm = l.search(m.dn)[0]
-            self.assertEquals(2, len(rm))
-            self.assertEquals(["1234", "456"], list(rm["bla"]))
+            self.assertEqual(2, len(rm))
+            self.assertEqual(["1234", "456"], list(rm.text["bla"]))
         finally:
             l.delete(ldb.Dn(l, "dc=add"))
 
@@ -249,19 +459,39 @@ class SimpleLdb(TestCase):
         l = ldb.Ldb(filename())
         m = ldb.Message()
         m.dn = ldb.Dn(l, "dc=modify2")
-        m["bla"] = ["1234", "456"]
+        m["bla"] = [b"1234", b"456"]
+        l.add(m)
+        try:
+            m = ldb.Message()
+            m.dn = ldb.Dn(l, "dc=modify2")
+            m["bla"] = ldb.MessageElement([b"789"], ldb.FLAG_MOD_REPLACE, "bla")
+            self.assertEqual(ldb.FLAG_MOD_REPLACE, m["bla"].flags())
+            l.modify(m)
+            rm = l.search(m.dn)[0]
+            self.assertEqual(2, len(rm))
+            self.assertEqual([b"789"], list(rm["bla"]))
+            rm = l.search(m.dn, attrs=["bla"])[0]
+            self.assertEqual(1, len(rm))
+        finally:
+            l.delete(ldb.Dn(l, "dc=modify2"))
+
+    def test_modify_replace_text(self):
+        l = ldb.Ldb(filename())
+        m = ldb.Message()
+        m.dn = ldb.Dn(l, "dc=modify2")
+        m.text["bla"] = ["1234", "456"]
         l.add(m)
         try:
             m = ldb.Message()
             m.dn = ldb.Dn(l, "dc=modify2")
             m["bla"] = ldb.MessageElement(["789"], ldb.FLAG_MOD_REPLACE, "bla")
-            self.assertEquals(ldb.FLAG_MOD_REPLACE, m["bla"].flags())
+            self.assertEqual(ldb.FLAG_MOD_REPLACE, m["bla"].flags())
             l.modify(m)
             rm = l.search(m.dn)[0]
-            self.assertEquals(2, len(rm))
-            self.assertEquals(["789"], list(rm["bla"]))
+            self.assertEqual(2, len(rm))
+            self.assertEqual(["789"], list(rm.text["bla"]))
             rm = l.search(m.dn, attrs=["bla"])[0]
-            self.assertEquals(1, len(rm))
+            self.assertEqual(1, len(rm))
         finally:
             l.delete(ldb.Dn(l, "dc=modify2"))
 
@@ -269,25 +499,51 @@ class SimpleLdb(TestCase):
         l = ldb.Ldb(filename())
         m = ldb.Message()
         m.dn = ldb.Dn(l, "dc=add")
-        m["bla"] = ["1234"]
+        m["bla"] = [b"1234"]
+        l.add(m)
+        try:
+            m = ldb.Message()
+            m.dn = ldb.Dn(l, "dc=add")
+            m["bla"] = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
+            self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
+            l.modify(m)
+            rm = l.search(m.dn)[0]
+            self.assertEqual(2, len(rm))
+            self.assertEqual([b"1234", b"456"], list(rm["bla"]))
+
+            # Now create another modify, but switch the flags before we do it
+            m["bla"] = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
+            m["bla"].set_flags(ldb.FLAG_MOD_DELETE)
+            l.modify(m)
+            rm = l.search(m.dn, attrs=["bla"])[0]
+            self.assertEqual(1, len(rm))
+            self.assertEqual([b"1234"], list(rm["bla"]))
+        finally:
+            l.delete(ldb.Dn(l, "dc=add"))
+
+    def test_modify_flags_change_text(self):
+        l = ldb.Ldb(filename())
+        m = ldb.Message()
+        m.dn = ldb.Dn(l, "dc=add")
+        m.text["bla"] = ["1234"]
         l.add(m)
         try:
             m = ldb.Message()
             m.dn = ldb.Dn(l, "dc=add")
             m["bla"] = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
-            self.assertEquals(ldb.FLAG_MOD_ADD, m["bla"].flags())
+            self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
             l.modify(m)
             rm = l.search(m.dn)[0]
-            self.assertEquals(2, len(rm))
-            self.assertEquals(["1234", "456"], list(rm["bla"]))
+            self.assertEqual(2, len(rm))
+            self.assertEqual(["1234", "456"], list(rm.text["bla"]))
 
             # Now create another modify, but switch the flags before we do it
             m["bla"] = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
             m["bla"].set_flags(ldb.FLAG_MOD_DELETE)
             l.modify(m)
             rm = l.search(m.dn, attrs=["bla"])[0]
-            self.assertEquals(1, len(rm))
-            self.assertEquals(["1234"], list(rm["bla"]))
+            self.assertEqual(1, len(rm))
+            self.assertEqual(["1234"], list(rm.text["bla"]))
         finally:
             l.delete(ldb.Dn(l, "dc=add"))
 
@@ -295,7 +551,7 @@ class SimpleLdb(TestCase):
         l = ldb.Ldb(filename())
         l.transaction_start()
         m = ldb.Message(ldb.Dn(l, "dc=foo9"))
-        m["foo"] = ["bar"]
+        m["foo"] = [b"bar"]
         l.add(m)
         l.transaction_commit()
         l.delete(m.dn)
@@ -304,10 +560,10 @@ class SimpleLdb(TestCase):
         l = ldb.Ldb(filename())
         l.transaction_start()
         m = ldb.Message(ldb.Dn(l, "dc=foo10"))
-        m["foo"] = ["bar"]
+        m["foo"] = [b"bar"]
         l.add(m)
         l.transaction_cancel()
-        self.assertEquals(0, len(l.search(ldb.Dn(l, "dc=foo10"))))
+        self.assertEqual(0, len(l.search(ldb.Dn(l, "dc=foo10"))))
 
     def test_set_debug(self):
         def my_report_fn(level, text):
@@ -319,14 +575,14 @@ class SimpleLdb(TestCase):
         """Testing we do not get trapped in the \0 byte in a property string."""
         l = ldb.Ldb(filename())
         l.add({
-            "dn" : "dc=somedn",
-            "objectclass" : "user",
-            "cN" : "LDAPtestUSER",
-            "givenname" : "ldap",
-            "displayname" : "foo\0bar",
+            "dn" : b"dc=somedn",
+            "objectclass" : b"user",
+            "cN" : b"LDAPtestUSER",
+            "givenname" : b"ldap",
+            "displayname" : b"foo\0bar",
         })
         res = l.search(expression="(dn=dc=somedn)")
-        self.assertEquals("foo\0bar", res[0]["displayname"][0])
+        self.assertEqual(b"foo\0bar", res[0]["displayname"][0])
 
     def test_no_crash_broken_expr(self):
         l = ldb.Ldb(filename())
@@ -348,21 +604,21 @@ class DnTests(TestCase):
     def test_eq(self):
         x = ldb.Dn(self.ldb, "dc=foo11,bar=bloe")
         y = ldb.Dn(self.ldb, "dc=foo11,bar=bloe")
-        self.assertEquals(x, y)
+        self.assertEqual(x, y)
         y = ldb.Dn(self.ldb, "dc=foo11,bar=blie")
-        self.assertNotEquals(x, y)
+        self.assertNotEqual(x, y)
 
     def test_str(self):
         x = ldb.Dn(self.ldb, "dc=foo12,bar=bloe")
-        self.assertEquals(x.__str__(), "dc=foo12,bar=bloe")
+        self.assertEqual(x.__str__(), "dc=foo12,bar=bloe")
 
     def test_repr(self):
         x = ldb.Dn(self.ldb, "dc=foo13,bla=blie")
-        self.assertEquals(x.__repr__(), "Dn('dc=foo13,bla=blie')")
+        self.assertEqual(x.__repr__(), "Dn('dc=foo13,bla=blie')")
 
     def test_get_casefold(self):
         x = ldb.Dn(self.ldb, "dc=foo14,bar=bloe")
-        self.assertEquals(x.get_casefold(), "DC=FOO14,BAR=bloe")
+        self.assertEqual(x.get_casefold(), "DC=FOO14,BAR=bloe")
 
     def test_validate(self):
         x = ldb.Dn(self.ldb, "dc=foo15,bar=bloe")
@@ -370,11 +626,11 @@ class DnTests(TestCase):
 
     def test_parent(self):
         x = ldb.Dn(self.ldb, "dc=foo16,bar=bloe")
-        self.assertEquals("bar=bloe", x.parent().__str__())
+        self.assertEqual("bar=bloe", x.parent().__str__())
 
     def test_parent_nonexistent(self):
         x = ldb.Dn(self.ldb, "@BLA")
-        self.assertEquals(None, x.parent())
+        self.assertEqual(None, x.parent())
 
     def test_is_valid(self):
         x = ldb.Dn(self.ldb, "dc=foo18,dc=bloe")
@@ -396,53 +652,64 @@ class DnTests(TestCase):
 
     def test_len(self):
         x = ldb.Dn(self.ldb, "dc=foo21,bar=bloe")
-        self.assertEquals(2, len(x))
+        self.assertEqual(2, len(x))
         x = ldb.Dn(self.ldb, "dc=foo21")
-        self.assertEquals(1, len(x))
+        self.assertEqual(1, len(x))
 
     def test_add_child(self):
         x = ldb.Dn(self.ldb, "dc=foo22,bar=bloe")
         self.assertTrue(x.add_child(ldb.Dn(self.ldb, "bla=bloe")))
-        self.assertEquals("bla=bloe,dc=foo22,bar=bloe", x.__str__())
+        self.assertEqual("bla=bloe,dc=foo22,bar=bloe", x.__str__())
 
     def test_add_base(self):
         x = ldb.Dn(self.ldb, "dc=foo23,bar=bloe")
         base = ldb.Dn(self.ldb, "bla=bloe")
         self.assertTrue(x.add_base(base))
-        self.assertEquals("dc=foo23,bar=bloe,bla=bloe", x.__str__())
+        self.assertEqual("dc=foo23,bar=bloe,bla=bloe", x.__str__())
+
+    def test_add_child_str(self):
+        x = ldb.Dn(self.ldb, "dc=foo22,bar=bloe")
+        self.assertTrue(x.add_child("bla=bloe"))
+        self.assertEqual("bla=bloe,dc=foo22,bar=bloe", x.__str__())
+
+    def test_add_base_str(self):
+        x = ldb.Dn(self.ldb, "dc=foo23,bar=bloe")
+        base = "bla=bloe"
+        self.assertTrue(x.add_base(base))
+        self.assertEqual("dc=foo23,bar=bloe,bla=bloe", x.__str__())
 
     def test_add(self):
         x = ldb.Dn(self.ldb, "dc=foo24")
         y = ldb.Dn(self.ldb, "bar=bla")
-        self.assertEquals("dc=foo24,bar=bla", str(x + y))
+        self.assertEqual("dc=foo24,bar=bla", str(x + y))
 
     def test_remove_base_components(self):
         x = ldb.Dn(self.ldb, "dc=foo24,dc=samba,dc=org")
         x.remove_base_components(len(x)-1)
-        self.assertEquals("dc=foo24", str(x))
+        self.assertEqual("dc=foo24", str(x))
 
     def test_parse_ldif(self):
         msgs = self.ldb.parse_ldif("dn: foo=bar\n")
-        msg = msgs.next()
-        self.assertEquals("foo=bar", str(msg[1].dn))
+        msg = next(msgs)
+        self.assertEqual("foo=bar", str(msg[1].dn))
         self.assertTrue(isinstance(msg[1], ldb.Message))
         ldif = self.ldb.write_ldif(msg[1], ldb.CHANGETYPE_NONE)
-        self.assertEquals("dn: foo=bar\n\n", ldif)
+        self.assertEqual("dn: foo=bar\n\n", ldif)
 
     def test_parse_ldif_more(self):
         msgs = self.ldb.parse_ldif("dn: foo=bar\n\n\ndn: bar=bar")
-        msg = msgs.next()
-        self.assertEquals("foo=bar", str(msg[1].dn))
-        msg = msgs.next()
-        self.assertEquals("bar=bar", str(msg[1].dn))
+        msg = next(msgs)
+        self.assertEqual("foo=bar", str(msg[1].dn))
+        msg = next(msgs)
+        self.assertEqual("bar=bar", str(msg[1].dn))
 
     def test_canonical_string(self):
         x = ldb.Dn(self.ldb, "dc=foo25,bar=bloe")
-        self.assertEquals("/bloe/foo25", x.canonical_str())
+        self.assertEqual("/bloe/foo25", x.canonical_str())
 
     def test_canonical_ex_string(self):
         x = ldb.Dn(self.ldb, "dc=foo26,bar=bloe")
-        self.assertEquals("/bloe\nfoo26", x.canonical_ex_str())
+        self.assertEqual("/bloe\nfoo26", x.canonical_ex_str())
 
     def test_ldb_is_child_of(self):
         """Testing ldb_dn_compare_dn"""
@@ -457,6 +724,105 @@ class DnTests(TestCase):
         self.assertFalse(dn3.is_child_of(dn2))
         self.assertFalse(dn1.is_child_of(dn4))
 
+    def test_ldb_is_child_of_str(self):
+        """Testing ldb_dn_compare_dn"""
+        dn1_str = "dc=base"
+        dn2_str = "cn=foo,dc=base"
+        dn3_str = "cn=bar,dc=base"
+        dn4_str = "cn=baz,cn=bar,dc=base"
+
+        dn1 = ldb.Dn(self.ldb, dn1_str)
+        dn2 = ldb.Dn(self.ldb, dn2_str)
+        dn3 = ldb.Dn(self.ldb, dn3_str)
+        dn4 = ldb.Dn(self.ldb, dn4_str)
+
+        self.assertTrue(dn2.is_child_of(dn1_str))
+        self.assertTrue(dn4.is_child_of(dn1_str))
+        self.assertTrue(dn4.is_child_of(dn3_str))
+        self.assertFalse(dn3.is_child_of(dn2_str))
+        self.assertFalse(dn1.is_child_of(dn4_str))
+
+    def test_get_component_name(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+        self.assertEqual(dn.get_component_name(0), 'cn')
+        self.assertEqual(dn.get_component_name(1), 'dc')
+        self.assertEqual(dn.get_component_name(2), None)
+        self.assertEqual(dn.get_component_name(-1), None)
+
+    def test_get_component_value(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+        self.assertEqual(dn.get_component_value(0), 'foo')
+        self.assertEqual(dn.get_component_value(1), 'base')
+        self.assertEqual(dn.get_component_name(2), None)
+        self.assertEqual(dn.get_component_name(-1), None)
+
+    def test_set_component(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+        dn.set_component(0, 'cn', 'bar')
+        self.assertEqual(str(dn), "cn=bar,dc=base")
+        dn.set_component(1, 'o', 'asep')
+        self.assertEqual(str(dn), "cn=bar,o=asep")
+        self.assertRaises(TypeError, dn.set_component, 2, 'dc', 'base')
+        self.assertEqual(str(dn), "cn=bar,o=asep")
+        dn.set_component(1, 'o', 'a,b+c')
+        self.assertEqual(str(dn), r"cn=bar,o=a\,b\+c")
+
+    def test_set_component_bytes(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+        dn.set_component(0, 'cn', b'bar')
+        self.assertEqual(str(dn), "cn=bar,dc=base")
+        dn.set_component(1, 'o', b'asep')
+        self.assertEqual(str(dn), "cn=bar,o=asep")
+
+    def test_set_component_none(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,cn=bar,dc=base")
+        self.assertRaises(TypeError, dn.set_component, 1, 'cn', None)
+
+    def test_get_extended_component_null(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,cn=bar,dc=base")
+        self.assertEqual(dn.get_extended_component("TEST"), None)
+
+    def test_get_extended_component(self):
+        self.ldb._register_test_extensions()
+        dn = ldb.Dn(self.ldb, "<TEST=foo>;cn=bar,dc=base")
+        self.assertEqual(dn.get_extended_component("TEST"), b"foo")
+
+    def test_set_extended_component(self):
+        self.ldb._register_test_extensions()
+        dn = ldb.Dn(self.ldb, "dc=base")
+        dn.set_extended_component("TEST", "foo")
+        self.assertEqual(dn.get_extended_component("TEST"), b"foo")
+        dn.set_extended_component("TEST", b"bar")
+        self.assertEqual(dn.get_extended_component("TEST"), b"bar")
+
+    def test_extended_str(self):
+        self.ldb._register_test_extensions()
+        dn = ldb.Dn(self.ldb, "<TEST=foo>;cn=bar,dc=base")
+        self.assertEqual(dn.extended_str(), "<TEST=foo>;cn=bar,dc=base")
+
+    def test_get_rdn_name(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+        self.assertEqual(dn.get_rdn_name(), 'cn')
+
+    def test_get_rdn_value(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+        self.assertEqual(dn.get_rdn_value(), 'foo')
+
+    def test_get_casefold(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+        self.assertEqual(dn.get_casefold(), 'CN=FOO,DC=BASE')
+
+    def test_get_linearized(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+        self.assertEqual(dn.get_linearized(), 'cn=foo,dc=base')
+
+    def test_is_null(self):
+        dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+        self.assertFalse(dn.is_null())
+
+        dn = ldb.Dn(self.ldb, '')
+        self.assertTrue(dn.is_null())
+
 class LdbMsgTests(TestCase):
 
     def setUp(self):
@@ -465,20 +831,35 @@ class LdbMsgTests(TestCase):
 
     def test_init_dn(self):
         self.msg = ldb.Message(ldb.Dn(ldb.Ldb(), "dc=foo27"))
-        self.assertEquals("dc=foo27", str(self.msg.dn))
+        self.assertEqual("dc=foo27", str(self.msg.dn))
 
     def test_iter_items(self):
-        self.assertEquals(0, len(self.msg.items()))
+        self.assertEqual(0, len(self.msg.items()))
         self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "dc=foo28")
-        self.assertEquals(1, len(self.msg.items()))
+        self.assertEqual(1, len(self.msg.items()))
 
     def test_repr(self):
         self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "dc=foo29")
-        self.msg["dc"] = "foo"
-        self.assertEquals("Message({'dn': Dn('dc=foo29'), 'dc': MessageElement(['foo'])})", repr(self.msg))
+        self.msg["dc"] = b"foo"
+        if PY3:
+            self.assertIn(repr(self.msg), [
+                "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])})",
+                "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')})",
+            ])
+            self.assertIn(repr(self.msg.text), [
+                "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])}).text",
+                "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')}).text",
+            ])
+        else:
+            self.assertEqual(
+                repr(self.msg),
+                "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement(['foo'])})")
+            self.assertEqual(
+                repr(self.msg.text),
+                "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement(['foo'])}).text")
 
     def test_len(self):
-        self.assertEquals(0, len(self.msg))
+        self.assertEqual(0, len(self.msg))
 
     def test_notpresent(self):
         self.assertRaises(KeyError, lambda: self.msg["foo"])
@@ -487,79 +868,131 @@ class LdbMsgTests(TestCase):
         del self.msg["foo"]
 
     def test_add(self):
+        self.msg.add(ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla"))
+
+    def test_add_text(self):
         self.msg.add(ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla"))
 
     def test_elements_empty(self):
-        self.assertEquals([], self.msg.elements())
+        self.assertEqual([], self.msg.elements())
 
     def test_elements(self):
-        el = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
+        el = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
         self.msg.add(el)
-        self.assertEquals([el], self.msg.elements())
+        self.assertEqual([el], self.msg.elements())
+        self.assertEqual([el.text], self.msg.text.elements())
 
     def test_add_value(self):
-        self.assertEquals(0, len(self.msg))
+        self.assertEqual(0, len(self.msg))
+        self.msg["foo"] = [b"foo"]
+        self.assertEqual(1, len(self.msg))
+
+    def test_add_value_text(self):
+        self.assertEqual(0, len(self.msg))
         self.msg["foo"] = ["foo"]
-        self.assertEquals(1, len(self.msg))
+        self.assertEqual(1, len(self.msg))
 
     def test_add_value_multiple(self):
-        self.assertEquals(0, len(self.msg))
+        self.assertEqual(0, len(self.msg))
+        self.msg["foo"] = [b"foo", b"bla"]
+        self.assertEqual(1, len(self.msg))
+        self.assertEqual([b"foo", b"bla"], list(self.msg["foo"]))
+
+    def test_add_value_multiple_text(self):
+        self.assertEqual(0, len(self.msg))
         self.msg["foo"] = ["foo", "bla"]
-        self.assertEquals(1, len(self.msg))
-        self.assertEquals(["foo", "bla"], list(self.msg["foo"]))
+        self.assertEqual(1, len(self.msg))
+        self.assertEqual(["foo", "bla"], list(self.msg.text["foo"]))
 
     def test_set_value(self):
+        self.msg["foo"] = [b"fool"]
+        self.assertEqual([b"fool"], list(self.msg["foo"]))
+        self.msg["foo"] = [b"bar"]
+        self.assertEqual([b"bar"], list(self.msg["foo"]))
+
+    def test_set_value_text(self):
         self.msg["foo"] = ["fool"]
-        self.assertEquals(["fool"], list(self.msg["foo"]))
+        self.assertEqual(["fool"], list(self.msg.text["foo"]))
         self.msg["foo"] = ["bar"]
-        self.assertEquals(["bar"], list(self.msg["foo"]))
+        self.assertEqual(["bar"], list(self.msg.text["foo"]))
 
     def test_keys(self):
         self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+        self.msg["foo"] = [b"bla"]
+        self.msg["bar"] = [b"bla"]
+        self.assertEqual(["dn", "foo", "bar"], self.msg.keys())
+
+    def test_keys_text(self):
+        self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
         self.msg["foo"] = ["bla"]
         self.msg["bar"] = ["bla"]
-        self.assertEquals(["dn", "foo", "bar"], self.msg.keys())
+        self.assertEqual(["dn", "foo", "bar"], self.msg.text.keys())
 
     def test_dn(self):
         self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
-        self.assertEquals("@BASEINFO", self.msg.dn.__str__())
+        self.assertEqual("@BASEINFO", self.msg.dn.__str__())
 
     def test_get_dn(self):
         self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
-        self.assertEquals("@BASEINFO", self.msg.get("dn").__str__())
+        self.assertEqual("@BASEINFO", self.msg.get("dn").__str__())
+
+    def test_dn_text(self):
+        self.msg.text.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+        self.assertEqual("@BASEINFO", str(self.msg.dn))
+        self.assertEqual("@BASEINFO", str(self.msg.text.dn))
+
+    def test_get_dn_text(self):
+        self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+        self.assertEqual("@BASEINFO", str(self.msg.get("dn")))
+        self.assertEqual("@BASEINFO", str(self.msg.text.get("dn")))
 
     def test_get_invalid(self):
         self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
         self.assertRaises(TypeError, self.msg.get, 42)
 
     def test_get_other(self):
+        self.msg["foo"] = [b"bar"]
+        self.assertEqual(b"bar", self.msg.get("foo")[0])
+        self.assertEqual(b"bar", self.msg.get("foo", idx=0))
+        self.assertEqual(None, self.msg.get("foo", idx=1))
+        self.assertEqual("", self.msg.get("foo", default='', idx=1))
+
+    def test_get_other_text(self):
         self.msg["foo"] = ["bar"]
-        self.assertEquals("bar", self.msg.get("foo")[0])
-        self.assertEquals("bar", self.msg.get("foo", idx=0))
-        self.assertEquals(None, self.msg.get("foo", idx=1))
-        self.assertEquals("", self.msg.get("foo", default='', idx=1))
+        self.assertEqual(["bar"], list(self.msg.text.get("foo")))
+        self.assertEqual("bar", self.msg.text.get("foo")[0])
+        self.assertEqual("bar", self.msg.text.get("foo", idx=0))
+        self.assertEqual(None, self.msg.get("foo", idx=1))
+        self.assertEqual("", self.msg.get("foo", default='', idx=1))
 
     def test_get_default(self):
-        self.assertEquals(None, self.msg.get("tatayoyo", idx=0))
-        self.assertEquals("anniecordie", self.msg.get("tatayoyo", "anniecordie"))
+        self.assertEqual(None, self.msg.get("tatayoyo", idx=0))
+        self.assertEqual("anniecordie", self.msg.get("tatayoyo", "anniecordie"))
+
+    def test_get_default_text(self):
+        self.assertEqual(None, self.msg.text.get("tatayoyo", idx=0))
+        self.assertEqual("anniecordie", self.msg.text.get("tatayoyo", "anniecordie"))
 
     def test_get_unknown(self):
-        self.assertEquals(None, self.msg.get("lalalala"))
+        self.assertEqual(None, self.msg.get("lalalala"))
+
+    def test_get_unknown_text(self):
+        self.assertEqual(None, self.msg.text.get("lalalala"))
 
     def test_msg_diff(self):
         l = ldb.Ldb()
         msgs = l.parse_ldif("dn: foo=bar\nfoo: bar\nbaz: do\n\ndn: foo=bar\nfoo: bar\nbaz: dont\n")
-        msg1 = msgs.next()[1]
-        msg2 = msgs.next()[1]
+        msg1 = next(msgs)[1]
+        msg2 = next(msgs)[1]
         msgdiff = l.msg_diff(msg1, msg2)
-        self.assertEquals("foo=bar", msgdiff.get("dn").__str__())
+        self.assertEqual("foo=bar", msgdiff.get("dn").__str__())
         self.assertRaises(KeyError, lambda: msgdiff["foo"])
-        self.assertEquals(1, len(msgdiff))
+        self.assertEqual(1, len(msgdiff))
 
     def test_equal_empty(self):
         msg1 = ldb.Message()
         msg2 = ldb.Message()
-        self.assertEquals(msg1, msg2)
+        self.assertEqual(msg1, msg2)
 
     def test_equal_simplel(self):
         db = ldb.Ldb(filename())
@@ -567,23 +1000,40 @@ class LdbMsgTests(TestCase):
         msg1.dn = ldb.Dn(db, "foo=bar")
         msg2 = ldb.Message()
         msg2.dn = ldb.Dn(db, "foo=bar")
-        self.assertEquals(msg1, msg2)
-        msg1['foo'] = 'bar'
-        msg2['foo'] = 'bar'
-        self.assertEquals(msg1, msg2)
-        msg2['foo'] = 'blie'
-        self.assertNotEquals(msg1, msg2)
-        msg2['foo'] = 'blie'
+        self.assertEqual(msg1, msg2)
+        msg1['foo'] = b'bar'
+        msg2['foo'] = b'bar'
+        self.assertEqual(msg1, msg2)
+        msg2['foo'] = b'blie'
+        self.assertNotEqual(msg1, msg2)
+        msg2['foo'] = b'blie'
 
     def test_from_dict(self):
         rec = {"dn": "dc=fromdict",
+               "a1": [b"a1-val1", b"a1-val1"]}
+        l = ldb.Ldb()
+        # check different types of input Flags
+        for flags in [ldb.FLAG_MOD_ADD, ldb.FLAG_MOD_REPLACE, ldb.FLAG_MOD_DELETE]:
+            m = ldb.Message.from_dict(l, rec, flags)
+            self.assertEqual(rec["a1"], list(m["a1"]))
+            self.assertEqual(flags, m["a1"].flags())
+        # check input params
+        self.assertRaises(TypeError, ldb.Message.from_dict, dict(), rec, ldb.FLAG_MOD_REPLACE)
+        self.assertRaises(TypeError, ldb.Message.from_dict, l, list(), ldb.FLAG_MOD_REPLACE)
+        self.assertRaises(ValueError, ldb.Message.from_dict, l, rec, 0)
+        # Message.from_dict expects dictionary with 'dn'
+        err_rec = {"a1": [b"a1-val1", b"a1-val1"]}
+        self.assertRaises(TypeError, ldb.Message.from_dict, l, err_rec, ldb.FLAG_MOD_REPLACE)
+
+    def test_from_dict_text(self):
+        rec = {"dn": "dc=fromdict",
                "a1": ["a1-val1", "a1-val1"]}
         l = ldb.Ldb()
         # check different types of input Flags
         for flags in [ldb.FLAG_MOD_ADD, ldb.FLAG_MOD_REPLACE, ldb.FLAG_MOD_DELETE]:
             m = ldb.Message.from_dict(l, rec, flags)
-            self.assertEquals(rec["a1"], list(m["a1"]))
-            self.assertEquals(flags, m["a1"].flags())
+            self.assertEqual(rec["a1"], list(m.text["a1"]))
+            self.assertEqual(flags, m.text["a1"].flags())
         # check input params
         self.assertRaises(TypeError, ldb.Message.from_dict, dict(), rec, ldb.FLAG_MOD_REPLACE)
         self.assertRaises(TypeError, ldb.Message.from_dict, l, list(), ldb.FLAG_MOD_REPLACE)
@@ -594,8 +1044,8 @@ class LdbMsgTests(TestCase):
 
     def test_copy_add_message_element(self):
         m = ldb.Message()
-        m["1"] = ldb.MessageElement(["val 111"], ldb.FLAG_MOD_ADD, "1")
-        m["2"] = ldb.MessageElement(["val 222"], ldb.FLAG_MOD_ADD, "2")
+        m["1"] = ldb.MessageElement([b"val 111"], ldb.FLAG_MOD_ADD, "1")
+        m["2"] = ldb.MessageElement([b"val 222"], ldb.FLAG_MOD_ADD, "2")
         mto = ldb.Message()
         mto["1"] = m["1"]
         mto["2"] = m["2"]
@@ -607,50 +1057,99 @@ class LdbMsgTests(TestCase):
         self.assertEqual(mto["1"], m["1"])
         self.assertEqual(mto["2"], m["2"])
 
+    def test_copy_add_message_element_text(self):
+        m = ldb.Message()
+        m["1"] = ldb.MessageElement(["val 111"], ldb.FLAG_MOD_ADD, "1")
+        m["2"] = ldb.MessageElement(["val 222"], ldb.FLAG_MOD_ADD, "2")
+        mto = ldb.Message()
+        mto["1"] = m["1"]
+        mto["2"] = m["2"]
+        self.assertEqual(mto["1"], m.text["1"])
+        self.assertEqual(mto["2"], m.text["2"])
+        mto = ldb.Message()
+        mto.add(m["1"])
+        mto.add(m["2"])
+        self.assertEqual(mto.text["1"], m.text["1"])
+        self.assertEqual(mto.text["2"], m.text["2"])
+        self.assertEqual(mto["1"], m["1"])
+        self.assertEqual(mto["2"], m["2"])
+
 
 class MessageElementTests(TestCase):
 
     def test_cmp_element(self):
-        x = ldb.MessageElement(["foo"])
+        x = ldb.MessageElement([b"foo"])
+        y = ldb.MessageElement([b"foo"])
+        z = ldb.MessageElement([b"bzr"])
+        self.assertEqual(x, y)
+        self.assertNotEqual(x, z)
+
+    def test_cmp_element_text(self):
+        x = ldb.MessageElement([b"foo"])
         y = ldb.MessageElement(["foo"])
-        z = ldb.MessageElement(["bzr"])
-        self.assertEquals(x, y)
-        self.assertNotEquals(x, z)
+        self.assertEqual(x, y)
 
     def test_create_iterable(self):
-        x = ldb.MessageElement(["foo"])
-        self.assertEquals(["foo"], list(x))
+        x = ldb.MessageElement([b"foo"])
+        self.assertEqual([b"foo"], list(x))
+        self.assertEqual(["foo"], list(x.text))
 
     def test_repr(self):
-        x = ldb.MessageElement(["foo"])
-        self.assertEquals("MessageElement(['foo'])", repr(x))
-        x = ldb.MessageElement(["foo", "bla"])
-        self.assertEquals(2, len(x))
-        self.assertEquals("MessageElement(['foo','bla'])", repr(x))
+        x = ldb.MessageElement([b"foo"])
+        if PY3:
+            self.assertEqual("MessageElement([b'foo'])", repr(x))
+            self.assertEqual("MessageElement([b'foo']).text", repr(x.text))
+        else:
+            self.assertEqual("MessageElement(['foo'])", repr(x))
+            self.assertEqual("MessageElement(['foo']).text", repr(x.text))
+        x = ldb.MessageElement([b"foo", b"bla"])
+        self.assertEqual(2, len(x))
+        if PY3:
+            self.assertEqual("MessageElement([b'foo',b'bla'])", repr(x))
+            self.assertEqual("MessageElement([b'foo',b'bla']).text", repr(x.text))
+        else:
+            self.assertEqual("MessageElement(['foo','bla'])", repr(x))
+            self.assertEqual("MessageElement(['foo','bla']).text", repr(x.text))
 
     def test_get_item(self):
+        x = ldb.MessageElement([b"foo", b"bar"])
+        self.assertEqual(b"foo", x[0])
+        self.assertEqual(b"bar", x[1])
+        self.assertEqual(b"bar", x[-1])
+        self.assertRaises(IndexError, lambda: x[45])
+
+    def test_get_item_text(self):
         x = ldb.MessageElement(["foo", "bar"])
-        self.assertEquals("foo", x[0])
-        self.assertEquals("bar", x[1])
-        self.assertEquals("bar", x[-1])
+        self.assertEqual("foo", x.text[0])
+        self.assertEqual("bar", x.text[1])
+        self.assertEqual("bar", x.text[-1])
         self.assertRaises(IndexError, lambda: x[45])
 
     def test_len(self):
-        x = ldb.MessageElement(["foo", "bar"])
-        self.assertEquals(2, len(x))
+        x = ldb.MessageElement([b"foo", b"bar"])
+        self.assertEqual(2, len(x))
 
     def test_eq(self):
-        x = ldb.MessageElement(["foo", "bar"])
-        y = ldb.MessageElement(["foo", "bar"])
-        self.assertEquals(y, x)
-        x = ldb.MessageElement(["foo"])
-        self.assertNotEquals(y, x)
-        y = ldb.MessageElement(["foo"])
-        self.assertEquals(y, x)
+        x = ldb.MessageElement([b"foo", b"bar"])
+        y = ldb.MessageElement([b"foo", b"bar"])
+        self.assertEqual(y, x)
+        x = ldb.MessageElement([b"foo"])
+        self.assertNotEqual(y, x)
+        y = ldb.MessageElement([b"foo"])
+        self.assertEqual(y, x)
 
     def test_extended(self):
-        el = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
-        self.assertEquals("MessageElement(['456'])", repr(el))
+        el = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
+        if PY3:
+            self.assertEqual("MessageElement([b'456'])", repr(el))
+            self.assertEqual("MessageElement([b'456']).text", repr(el.text))
+        else:
+            self.assertEqual("MessageElement(['456'])", repr(el))
+            self.assertEqual("MessageElement(['456']).text", repr(el.text))
+
+    def test_bad_text(self):
+        el = ldb.MessageElement(b'\xba\xdd')
+        self.assertRaises(UnicodeDecodeError, el.text.__getitem__, 0)
 
 
 class ModuleTests(TestCase):
@@ -681,9 +1180,9 @@ class ModuleTests(TestCase):
             os.unlink(name)
         l = ldb.Ldb(name)
         l.add({"dn": "@MODULES", "@LIST": "bla"})
-        self.assertEquals([], ops)
+        self.assertEqual([], ops)
         l = ldb.Ldb(name)
-        self.assertEquals(["init"], ops)
+        self.assertEqual(["init"], ops)
 
 class LdbResultTests(TestCase):
 
@@ -694,19 +1193,19 @@ class LdbResultTests(TestCase):
         if os.path.exists(name):
             os.unlink(name)
         self.l = ldb.Ldb(name)
-        self.l.add({"dn": "DC=SAMBA,DC=ORG", "name": "samba.org"})
-        self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG", "name": "Admins"})
-        self.l.add({"dn": "OU=USERS,DC=SAMBA,DC=ORG", "name": "Users"})
-        self.l.add({"dn": "OU=OU1,DC=SAMBA,DC=ORG", "name": "OU #1"})
-        self.l.add({"dn": "OU=OU2,DC=SAMBA,DC=ORG", "name": "OU #2"})
-        self.l.add({"dn": "OU=OU3,DC=SAMBA,DC=ORG", "name": "OU #3"})
-        self.l.add({"dn": "OU=OU4,DC=SAMBA,DC=ORG", "name": "OU #4"})
-        self.l.add({"dn": "OU=OU5,DC=SAMBA,DC=ORG", "name": "OU #5"})
-        self.l.add({"dn": "OU=OU6,DC=SAMBA,DC=ORG", "name": "OU #6"})
-        self.l.add({"dn": "OU=OU7,DC=SAMBA,DC=ORG", "name": "OU #7"})
-        self.l.add({"dn": "OU=OU8,DC=SAMBA,DC=ORG", "name": "OU #8"})
-        self.l.add({"dn": "OU=OU9,DC=SAMBA,DC=ORG", "name": "OU #9"})
-        self.l.add({"dn": "OU=OU10,DC=SAMBA,DC=ORG", "name": "OU #10"})
+        self.l.add({"dn": "DC=SAMBA,DC=ORG", "name": b"samba.org"})
+        self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG", "name": b"Admins"})
+        self.l.add({"dn": "OU=USERS,DC=SAMBA,DC=ORG", "name": b"Users"})
+        self.l.add({"dn": "OU=OU1,DC=SAMBA,DC=ORG", "name": b"OU #1"})
+        self.l.add({"dn": "OU=OU2,DC=SAMBA,DC=ORG", "name": b"OU #2"})
+        self.l.add({"dn": "OU=OU3,DC=SAMBA,DC=ORG", "name": b"OU #3"})
+        self.l.add({"dn": "OU=OU4,DC=SAMBA,DC=ORG", "name": b"OU #4"})
+        self.l.add({"dn": "OU=OU5,DC=SAMBA,DC=ORG", "name": b"OU #5"})
+        self.l.add({"dn": "OU=OU6,DC=SAMBA,DC=ORG", "name": b"OU #6"})
+        self.l.add({"dn": "OU=OU7,DC=SAMBA,DC=ORG", "name": b"OU #7"})
+        self.l.add({"dn": "OU=OU8,DC=SAMBA,DC=ORG", "name": b"OU #8"})
+        self.l.add({"dn": "OU=OU9,DC=SAMBA,DC=ORG", "name": b"OU #9"})
+        self.l.add({"dn": "OU=OU10,DC=SAMBA,DC=ORG", "name": b"OU #10"})
 
     def tearDown(self):
         super(LdbResultTests, self).tearDown()
@@ -715,7 +1214,7 @@ class LdbResultTests(TestCase):
 
     def test_return_type(self):
         res = self.l.search()
-        self.assertEquals(str(res), "<ldb result>")
+        self.assertEqual(str(res), "<ldb result>")
 
     def test_get_msgs(self):
         res = self.l.search()
@@ -748,8 +1247,8 @@ class LdbResultTests(TestCase):
     def test_create_control(self):
         self.assertRaises(ValueError, ldb.Control, self.l, "tatayoyo:0")
         c = ldb.Control(self.l, "relax:1")
-        self.assertEquals(c.critical, True)
-        self.assertEquals(c.oid, "1.3.6.1.4.1.4203.666.5.12")
+        self.assertEqual(c.critical, True)
+        self.assertEqual(c.oid, "1.3.6.1.4.1.4203.666.5.12")
 
     def test_iter_refs(self):
         res = self.l.search().referals
diff --git a/lib/ldb/tests/test-tdb.sh b/lib/ldb/tests/test-tdb.sh
index 82eef69..91c48ab 100755
--- a/lib/ldb/tests/test-tdb.sh
+++ b/lib/ldb/tests/test-tdb.sh
@@ -7,9 +7,7 @@ if [ -n "$TEST_DATA_PREFIX" ]; then
 	PYDESTDIR="$TEST_DATA_PREFIX"
 else
 	LDB_URL="tdbtest.ldb"
-	PYDESTDIR="/tmp"
 fi
-mkdir $PYDESTDIR/tmp
 export LDB_URL
 
 PATH=$BINDIR:$PATH
@@ -38,8 +36,3 @@ $VALGRIND ldbadd $LDBDIR/tests/init.ldif || exit 1
 . $LDBDIR/tests/test-tdb-features.sh
 
 . $LDBDIR/tests/test-controls.sh
-
-which python >/dev/null 2>&1
-if [ $? -eq 0 ]; then
-	SELFTEST_PREFIX=$PYDESTDIR PYTHONPATH=$BINDIR/python python $LDBDIR/tests/python/api.py
-fi
diff --git a/lib/ldb/tools/cmdline.c b/lib/ldb/tools/cmdline.c
index a06445f..6d0a406 100644
--- a/lib/ldb/tools/cmdline.c
+++ b/lib/ldb/tools/cmdline.c
@@ -459,6 +459,39 @@ int handle_controls_reply(struct ldb_control **reply, struct ldb_control **reque
 
 			continue;
 		}
+		if (strcmp(LDB_CONTROL_DIRSYNC_EX_OID, reply[i]->oid) == 0) {
+			struct ldb_dirsync_control *rep_control, *req_control;
+			char *cookie;
+
+			rep_control = talloc_get_type(reply[i]->data, struct ldb_dirsync_control);
+			if (rep_control->cookie_len == 0) /* we are done */
+				break;
+
+			/* more processing required */
+			/* let's fill in the request control with the new cookie */
+
+			for (j = 0; request[j]; j++) {
+				if (strcmp(LDB_CONTROL_DIRSYNC_EX_OID, request[j]->oid) == 0)
+					break;
+			}
+			/* if there's a reply control we must find a request
+			 * control matching it */
+			if (! request[j]) return -1;
+
+			req_control = talloc_get_type(request[j]->data, struct ldb_dirsync_control);
+
+			if (req_control->cookie)
+				talloc_free(req_control->cookie);
+			req_control->cookie = (char *)talloc_memdup(
+				req_control, rep_control->cookie,
+				rep_control->cookie_len);
+			req_control->cookie_len = rep_control->cookie_len;
+
+			cookie = ldb_base64_encode(req_control, rep_control->cookie, rep_control->cookie_len);
+			printf("# DIRSYNC_EX cookie returned was:\n# %s\n", cookie);
+
+			continue;
+		}
 
 		/* no controls matched, throw a warning */
 		fprintf(stderr, "Unknown reply control oid: %s\n", reply[i]->oid);
diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index 4c70e2f..2398ff7 100755
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -1,8 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'ldb'
-VERSION = '1.1.21'
-SYSTEM_VERSION = '1.1.24'
+VERSION = '1.1.26'
 
 blddir = 'bin'
 
@@ -14,7 +13,7 @@ while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5:
     srcdir = srcdir + '/..'
 sys.path.insert(0, srcdir + '/buildtools/wafsamba')
 
-import wafsamba, samba_dist, Options, Utils
+import wafsamba, samba_dist, Utils
 
 samba_dist.DIST_DIRS('''lib/ldb:. lib/replace:lib/replace lib/talloc:lib/talloc
                         lib/tdb:lib/tdb lib/tdb:lib/tdb lib/tevent:lib/tevent
@@ -56,11 +55,11 @@ def configure(conf):
     conf.env.standalone_ldb = conf.IN_LAUNCH_DIR()
 
     if not conf.env.standalone_ldb:
-        if conf.CHECK_BUNDLED_SYSTEM_PKG('pyldb-util', minversion=SYSTEM_VERSION,
+        if conf.CHECK_BUNDLED_SYSTEM_PKG('pyldb-util', minversion=VERSION,
                                      onlyif='talloc tdb tevent',
                                      implied_deps='replace talloc tdb tevent ldb'):
             conf.define('USING_SYSTEM_PYLDB_UTIL', 1)
-            if conf.CHECK_BUNDLED_SYSTEM_PKG('ldb', minversion=SYSTEM_VERSION,
+            if conf.CHECK_BUNDLED_SYSTEM_PKG('ldb', minversion=VERSION,
                                          onlyif='talloc tdb tevent pyldb-util',
                                          implied_deps='replace talloc tdb tevent'):
                 conf.define('USING_SYSTEM_LDB', 1)
@@ -121,21 +120,37 @@ def build(bld):
         bld.env.PACKAGE_VERSION = VERSION
         bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
 
-    if not bld.CONFIG_SET('USING_SYSTEM_PYLDB_UTIL'):
-        bld.SAMBA_LIBRARY('pyldb-util',
-                          deps='ldb',
-                          source='pyldb_util.c',
-                          public_headers='pyldb.h',
-                          public_headers_install=not private_library,
-                          vnum=VERSION,
-                          private_library=private_library,
-                          pc_files='pyldb-util.pc',
-                          pyembed=True,
-                          abi_directory='ABI',
-                          abi_match='pyldb_*')
+    if not bld.env.disable_python:
+        if not bld.CONFIG_SET('USING_SYSTEM_PYLDB_UTIL'):
+            for env in bld.gen_python_environments(['PKGCONFIGDIR']):
+                name = bld.pyembed_libname('pyldb-util')
+                bld.SAMBA_LIBRARY(name,
+                                  deps='ldb',
+                                  source='pyldb_util.c',
+                                  public_headers=('' if private_library else 'pyldb.h'),
+                                  public_headers_install=not private_library,
+                                  vnum=VERSION,
+                                  private_library=private_library,
+                                  pc_files='pyldb-util.pc',
+                                  pyembed=True,
+                                  abi_directory='ABI',
+                                  abi_match='pyldb_*')
+
+                if not bld.CONFIG_SET('USING_SYSTEM_LDB'):
+                    bld.SAMBA_PYTHON('pyldb', 'pyldb.c',
+                                     deps='ldb ' + name,
+                                     realname='ldb.so',
+                                     cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
+
+            for env in bld.gen_python_environments(['PKGCONFIGDIR']):
+                bld.SAMBA_SCRIPT('_ldb_text.py',
+                                 pattern='_ldb_text.py',
+                                 installdir='python')
+
+                bld.INSTALL_FILES('${PYTHONARCHDIR}', '_ldb_text.py')
 
     if not bld.CONFIG_SET('USING_SYSTEM_LDB'):
-        if Options.is_install:
+        if bld.is_install:
             modules_dir = bld.EXPAND_VARIABLES('${LDB_MODULESDIR}')
         else:
             # when we run from the source directory, we want to use
@@ -144,12 +159,14 @@ def build(bld):
 
         abi_match = '!ldb_*module_ops !ldb_*backend_ops ldb_*'
 
+        ldb_headers = ('include/ldb.h include/ldb_errors.h '
+                       'include/ldb_module.h include/ldb_handlers.h')
+
         bld.SAMBA_LIBRARY('ldb',
                           COMMON_SRC + ' ' + LDB_MAP_SRC,
                           deps='tevent LIBLDB_MAIN replace',
                           includes='include',
-                          public_headers='include/ldb.h include/ldb_errors.h '\
-                          'include/ldb_module.h include/ldb_handlers.h',
+                          public_headers=('' if private_library else ldb_headers),
                           public_headers_install=not private_library,
                           pc_files='ldb.pc',
                           vnum=VERSION,
@@ -168,11 +185,6 @@ def build(bld):
         t.env.LDB_VERSION = VERSION
 
 
-        bld.SAMBA_PYTHON('pyldb', 'pyldb.c',
-                         deps='ldb pyldb-util',
-                         realname='ldb.so',
-                         cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
-
         bld.SAMBA_MODULE('ldb_paged_results',
                          'modules/paged_results.c',
                          init_function='ldb_paged_results_init',
@@ -285,8 +297,15 @@ def test(ctx):
     cmd = 'tests/test-tdb.sh %s' % Utils.g_module.blddir
     ret = samba_utils.RUN_COMMAND(cmd)
     print("testsuite returned %d" % ret)
-    # FIXME: Run python testsuite
-    sys.exit(ret)
+
+    tmp_dir = os.path.join(test_prefix, 'tmp')
+    if not os.path.exists(tmp_dir):
+        os.mkdir(tmp_dir)
+    pyret = samba_utils.RUN_PYTHON_TESTS(
+        ['tests/python/api.py'],
+        extra_env={'SELFTEST_PREFIX': test_prefix})
+    print("Python testsuite returned %d" % pyret)
+    sys.exit(ret or pyret)
 
 def dist():
     '''makes a tarball for distribution'''
diff --git a/lib/nss_wrapper/nss_wrapper.c b/lib/nss_wrapper/nss_wrapper.c
index a41de9e..c4f1b33 100644
--- a/lib/nss_wrapper/nss_wrapper.c
+++ b/lib/nss_wrapper/nss_wrapper.c
@@ -35,6 +35,8 @@
 
 #include "config.h"
 
+#include <pthread.h>
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
@@ -50,6 +52,11 @@
 #include <unistd.h>
 #include <ctype.h>
 
+#include <netinet/in.h>
+
+#include <search.h>
+#include <assert.h>
+
 /*
  * Defining _POSIX_PTHREAD_SEMANTICS before including pwd.h and grp.h  gives us
  * the posix getpwnam_r(), getpwuid_r(), getgrnam_r and getgrgid_r calls on
@@ -61,6 +68,9 @@
 
 #include <pwd.h>
 #include <grp.h>
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif /* HAVE_SHADOW_H */
 
 #include <netdb.h>
 #include <arpa/inet.h>
@@ -140,6 +150,72 @@ typedef nss_status_t NSS_STATUS;
 
 #define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
 
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
+#endif
+
+#ifdef HAVE_IPV6
+#define NWRAP_INET_ADDRSTRLEN INET6_ADDRSTRLEN
+#else
+#define NWRAP_INET_ADDRSTRLEN INET_ADDRSTRLEN
+#endif
+
+#define NWRAP_LOCK(m) do { \
+	pthread_mutex_lock(&( m ## _mutex)); \
+} while(0)
+
+#define NWRAP_UNLOCK(m) do { \
+	pthread_mutex_unlock(&( m ## _mutex)); \
+} while(0)
+
+
+static bool nwrap_initialized = false;
+static pthread_mutex_t nwrap_initialized_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* The mutex or accessing the id */
+static pthread_mutex_t nwrap_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t nwrap_gr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t nwrap_he_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t nwrap_pw_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t nwrap_sp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Add new global locks here please */
+/* Also don't forget to add locks to
+ * nwrap_init() function.
+ */
+# define NWRAP_LOCK_ALL do { \
+	NWRAP_LOCK(nwrap_initialized); \
+	NWRAP_LOCK(nwrap_global); \
+	NWRAP_LOCK(nwrap_gr_global); \
+	NWRAP_LOCK(nwrap_he_global); \
+	NWRAP_LOCK(nwrap_pw_global); \
+	NWRAP_LOCK(nwrap_sp_global); \
+} while (0);
+
+# define NWRAP_UNLOCK_ALL do {\
+	NWRAP_UNLOCK(nwrap_sp_global); \
+	NWRAP_UNLOCK(nwrap_pw_global); \
+	NWRAP_UNLOCK(nwrap_he_global); \
+	NWRAP_UNLOCK(nwrap_gr_global); \
+	NWRAP_UNLOCK(nwrap_global); \
+	NWRAP_UNLOCK(nwrap_initialized); \
+} while (0);
+
+static void nwrap_thread_prepare(void)
+{
+	NWRAP_LOCK_ALL;
+}
+
+static void nwrap_thread_parent(void)
+{
+	NWRAP_UNLOCK_ALL;
+}
+
+static void nwrap_thread_child(void)
+{
+	NWRAP_UNLOCK_ALL;
+}
+
 enum nwrap_dbglvl_e {
 	NWRAP_LOG_ERROR = 0,
 	NWRAP_LOG_WARN,
@@ -330,6 +406,7 @@ struct nwrap_ops {
 /* Public prototypes */
 
 bool nss_wrapper_enabled(void);
+bool nss_wrapper_shadow_enabled(void);
 bool nss_wrapper_hosts_enabled(void);
 
 /* prototypes for files backend */
@@ -455,25 +532,174 @@ struct nwrap_libc {
 };
 
 struct nwrap_main {
-	const char *nwrap_switch;
 	int num_backends;
 	struct nwrap_backend *backends;
 	struct nwrap_libc *libc;
 };
 
-struct nwrap_main *nwrap_main_global;
-struct nwrap_main __nwrap_main_global;
+static struct nwrap_main *nwrap_main_global;
+static struct nwrap_main __nwrap_main_global;
+
+/*
+ * PROTOTYPES
+ */
+static int nwrap_convert_he_ai(const struct hostent *he,
+			       unsigned short port,
+			       const struct addrinfo *hints,
+			       struct addrinfo **pai,
+			       bool skip_canonname);
+
+/*
+ * VECTORS
+ */
+
+#define DEFAULT_VECTOR_CAPACITY 16
+
+struct nwrap_vector {
+	void **items;
+	size_t count;
+	size_t capacity;
+};
+
+/* Macro returns pointer to first element of vector->items array.
+ *
+ * nwrap_vector is used as a memory backend which take care of
+ * memory allocations and other stuff like memory growing.
+ * nwrap_vectors should not be considered as some abstract structures.
+ * On this level, vectors are more handy than direct realloc/malloc
+ * calls.
+ *
+ * nwrap_vector->items is array inside nwrap_vector which can be
+ * directly pointed by libc structure assembled by cwrap itself.
+ *
+ * EXAMPLE:
+ *
+ * 1) struct hostent contains char **h_addr_list element.
+ * 2) nwrap_vector holds array of pointers to addresses.
+ *    It's easier to use vector to store results of
+ *    file parsing etc.
+ *
+ * Now, pretend that cwrap assembled struct hostent and
+ * we need to set h_addr_list to point to nwrap_vector.
+ * Idea behind is to shield users from internal nwrap_vector
+ * implementation.
+ * (Yes, not fully - array terminated by NULL is needed because
+ * it's result expected by libc function caller.)
+ *
+ *
+ * CODE EXAMPLE:
+ *
+ * struct hostent he;
+ * struct nwrap_vector *vector = malloc(sizeof(struct nwrap_vector));
+ * ... don't care about failed allocation now ...
+ *
+ * ... fill nwrap vector ...
+ *
+ * struct hostent he;
+ * he.h_addr_list = nwrap_vector_head(vector);
+ *
+ */
+#define nwrap_vector_head(vect) ((void *)((vect)->items))
+
+#define nwrap_vector_foreach(item, vect, iter) \
+	for (iter = 0, (item) = (vect).items == NULL ? NULL : (vect).items[0]; \
+	     item != NULL; \
+	     (item) = (vect).items[++iter])
+
+#define nwrap_vector_is_initialized(vector) ((vector)->items != NULL)
+
+static inline bool nwrap_vector_init(struct nwrap_vector *const vector)
+{
+	if (vector == NULL) {
+		return false;
+	}
+
+	/* count is initialized by ZERO_STRUCTP */
+	ZERO_STRUCTP(vector);
+	vector->items = malloc(sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
+	if (vector->items == NULL) {
+		return false;
+	}
+	vector->capacity = DEFAULT_VECTOR_CAPACITY;
+	memset(vector->items, '\0', sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
+
+	return true;
+}
+
+static bool nwrap_vector_add_item(struct nwrap_vector *vector, void *const item)
+{
+	assert (vector != NULL);
+
+	if (vector->items == NULL) {
+		nwrap_vector_init(vector);
+	}
+
+	if (vector->count == vector->capacity) {
+		/* Items array _MUST_ be NULL terminated because it's passed
+		 * as result to caller which expect NULL terminated array from libc.
+		 */
+		void **items = realloc(vector->items, sizeof(void *) * ((vector->capacity * 2) + 1));
+		if (items == NULL) {
+			return false;
+		}
+		vector->items = items;
+
+		/* Don't count ending NULL to capacity */
+		vector->capacity *= 2;
+	}
+
+	vector->items[vector->count] = item;
+
+	vector->count += 1;
+	vector->items[vector->count] = NULL;
+
+	return true;
+}
+
+static bool nwrap_vector_merge(struct nwrap_vector *dst,
+			       struct nwrap_vector *src)
+{
+	void **dst_items = NULL;
+	size_t count;
+
+	if (src->count == 0) {
+		return true;
+	}
+
+	count = dst->count + src->count;
+
+	/* We don't need reallocation if we have enough capacity. */
+	if (src->count > (dst->capacity - dst->count)) {
+		dst_items = (void **)realloc(dst->items, (count + 1) * sizeof(void *));
+		if (dst_items == NULL) {
+			return false;
+		}
+		dst->items = dst_items;
+		dst->capacity = count;
+	}
+
+	memcpy((void *)(((long *)dst->items) + dst->count),
+	       src->items,
+	       src->count * sizeof(void *));
+	dst->count = count;
+
+	return true;
+}
 
 struct nwrap_cache {
 	const char *path;
 	int fd;
+	FILE *fp;
 	struct stat st;
-	uint8_t *buf;
 	void *private_data;
+
+	struct nwrap_vector lines;
+
 	bool (*parse_line)(struct nwrap_cache *, char *line);
 	void (*unload)(struct nwrap_cache *);
 };
 
+/* passwd */
 struct nwrap_pw {
 	struct nwrap_cache *cache;
 
@@ -488,6 +714,24 @@ struct nwrap_pw nwrap_pw_global;
 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
 static void nwrap_pw_unload(struct nwrap_cache *nwrap);
 
+/* shadow */
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+struct nwrap_sp {
+	struct nwrap_cache *cache;
+
+	struct spwd *list;
+	int num;
+	int idx;
+};
+
+struct nwrap_cache __nwrap_cache_sp;
+struct nwrap_sp nwrap_sp_global;
+
+static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line);
+static void nwrap_sp_unload(struct nwrap_cache *nwrap);
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+/* group */
 struct nwrap_gr {
 	struct nwrap_cache *cache;
 
@@ -499,29 +743,42 @@ struct nwrap_gr {
 struct nwrap_cache __nwrap_cache_gr;
 struct nwrap_gr nwrap_gr_global;
 
+/* hosts */
 static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line);
 static void nwrap_he_unload(struct nwrap_cache *nwrap);
 
 struct nwrap_addrdata {
 	unsigned char host_addr[16]; /* IPv4 or IPv6 address */
-	char *h_addr_ptrs[2]; /* host_addr pointer + NULL */
 };
 
+static size_t max_hostents = 100;
+
 struct nwrap_entdata {
-	struct nwrap_addrdata *addr;
+	struct nwrap_addrdata addr;
 	struct hostent ht;
+
+	struct nwrap_vector nwrap_addrdata;
+
+	ssize_t aliases_count;
+};
+
+struct nwrap_entlist {
+	struct nwrap_entlist *next;
+	struct nwrap_entdata *ed;
 };
 
 struct nwrap_he {
 	struct nwrap_cache *cache;
 
-	struct nwrap_entdata *list;
+	struct nwrap_vector entries;
+	struct nwrap_vector lists;
+
 	int num;
 	int idx;
 };
 
-struct nwrap_cache __nwrap_cache_he;
-struct nwrap_he nwrap_he_global;
+static struct nwrap_cache __nwrap_cache_he;
+static struct nwrap_he nwrap_he_global;
 
 
 /*********************************************************
@@ -575,11 +832,14 @@ static void *nwrap_load_lib_handle(enum nwrap_lib lib)
 #ifdef HAVE_LIBNSL
 		handle = nwrap_main_global->libc->nsl_handle;
 		if (handle == NULL) {
-			for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
+			for (i = 10; i >= 0; i--) {
 				char soname[256] = {0};
 
 				snprintf(soname, sizeof(soname), "libnsl.so.%d", i);
 				handle = dlopen(soname, flags);
+				if (handle != NULL) {
+					break;
+				}
 			}
 
 			nwrap_main_global->libc->nsl_handle = handle;
@@ -591,11 +851,14 @@ static void *nwrap_load_lib_handle(enum nwrap_lib lib)
 #ifdef HAVE_LIBSOCKET
 		handle = nwrap_main_global->libc->sock_handle;
 		if (handle == NULL) {
-			for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
+			for (i = 10; i >= 0; i--) {
 				char soname[256] = {0};
 
 				snprintf(soname, sizeof(soname), "libsocket.so.%d", i);
 				handle = dlopen(soname, flags);
+				if (handle != NULL) {
+					break;
+				}
 			}
 
 			nwrap_main_global->libc->sock_handle = handle;
@@ -606,11 +869,14 @@ static void *nwrap_load_lib_handle(enum nwrap_lib lib)
 	case NWRAP_LIBC:
 		handle = nwrap_main_global->libc->handle;
 		if (handle == NULL) {
-			for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
+			for (i = 10; i >= 0; i--) {
 				char soname[256] = {0};
 
 				snprintf(soname, sizeof(soname), "libc.so.%d", i);
 				handle = dlopen(soname, flags);
+				if (handle != NULL) {
+					break;
+				}
 			}
 
 			nwrap_main_global->libc->handle = handle;
@@ -664,6 +930,19 @@ static void *_nwrap_load_lib_function(enum nwrap_lib lib, const char *fn_name)
 			_nwrap_load_lib_function(lib, #fn_name); \
 	}
 
+/* INTERNAL HELPER FUNCTIONS */
+static void nwrap_lines_unload(struct nwrap_cache *const nwrap)
+{
+	size_t p;
+	void *item;
+	nwrap_vector_foreach(item, nwrap->lines, p) {
+		/* Maybe some vectors were merged ... */
+		SAFE_FREE(item);
+	}
+	SAFE_FREE(nwrap->lines.items);
+	ZERO_STRUCTP(&nwrap->lines);
+}
+
 /*
  * IMPORTANT
  *
@@ -734,6 +1013,37 @@ static int libc_getpwuid_r(uid_t uid,
 }
 #endif
 
+static inline void str_tolower(char *dst, char *src)
+{
+	register char *src_tmp = src;
+	register char *dst_tmp = dst;
+
+	while (*src_tmp != '\0') {
+		*dst_tmp = tolower(*src_tmp);
+		++src_tmp;
+		++dst_tmp;
+	}
+}
+
+static bool str_tolower_copy(char **dst_name, const char *const src_name)
+{
+	char *h_name_lower;
+
+	if ((dst_name == NULL) || (src_name == NULL)) {
+		return false;
+	}
+
+	h_name_lower = strdup(src_name);
+	if (h_name_lower == NULL) {
+		NWRAP_LOG(NWRAP_LOG_DEBUG, "Out of memory while strdup");
+		return false;
+	}
+
+	str_tolower(h_name_lower, h_name_lower);
+	*dst_name = h_name_lower;
+	return true;
+}
+
 static void libc_setpwent(void)
 {
 	nwrap_load_lib_function(NWRAP_LIBC, setpwent);
@@ -1069,8 +1379,7 @@ static void *nwrap_load_module_fn(struct nwrap_backend *b,
 			  "Cannot find function %s in %s",
 			  s, b->so_path);
 	}
-	free(s);
-	s = NULL;
+	SAFE_FREE(s);
 	return res;
 }
 
@@ -1221,10 +1530,56 @@ static void nwrap_backend_init(struct nwrap_main *r)
 
 static void nwrap_init(void)
 {
-	static bool initialized;
+	const char *env;
+	char *endptr;
+	size_t max_hostents_tmp;
+
+	NWRAP_LOCK(nwrap_initialized);
+	if (nwrap_initialized) {
+		NWRAP_UNLOCK(nwrap_initialized);
+		return;
+	}
 
-	if (initialized) return;
-	initialized = true;
+	/*
+	 * Still holding nwrap_initialized lock here.
+	 * We don't use NWRAP_(UN)LOCK_ALL macros here because we
+	 * want to avoid overhead when other threads do their job.
+	 */
+	NWRAP_LOCK(nwrap_global);
+	NWRAP_LOCK(nwrap_gr_global);
+	NWRAP_LOCK(nwrap_he_global);
+	NWRAP_LOCK(nwrap_pw_global);
+	NWRAP_LOCK(nwrap_sp_global);
+
+	nwrap_initialized = true;
+
+	/* Initialize pthread_atfork handlers */
+	pthread_atfork(&nwrap_thread_prepare, &nwrap_thread_parent,
+		       &nwrap_thread_child);
+
+	env = getenv("NSS_WRAPPER_MAX_HOSTENTS");
+	if (env != NULL) {
+		max_hostents_tmp = (size_t)strtol(env, &endptr, 10);
+		if (((env != '\0') && (endptr == '\0')) ||
+		    (max_hostents_tmp == 0)) {
+			NWRAP_LOG(NWRAP_LOG_DEBUG,
+				  "Error parsing NSS_WRAPPER_MAX_HOSTENTS "
+				  "value or value is too small. "
+				  "Using default value: %lu.",
+				  (unsigned long)max_hostents);
+		} else {
+			max_hostents = max_hostents_tmp;
+		}
+	}
+	/* Initialize hash table */
+	NWRAP_LOG(NWRAP_LOG_DEBUG,
+		  "Initializing hash table of size %lu items.",
+		  (unsigned long)max_hostents);
+	if (hcreate(max_hostents) == 0) {
+		NWRAP_LOG(NWRAP_LOG_ERROR,
+			  "Failed to initialize hash table");
+		goto done;
+	}
 
 	nwrap_main_global = &__nwrap_main_global;
 
@@ -1232,29 +1587,51 @@ static void nwrap_init(void)
 
 	nwrap_backend_init(nwrap_main_global);
 
+	/* passwd */
 	nwrap_pw_global.cache = &__nwrap_cache_pw;
 
 	nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
+	nwrap_pw_global.cache->fp = NULL;
 	nwrap_pw_global.cache->fd = -1;
 	nwrap_pw_global.cache->private_data = &nwrap_pw_global;
 	nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
 	nwrap_pw_global.cache->unload = nwrap_pw_unload;
 
+	/* shadow */
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+	nwrap_sp_global.cache = &__nwrap_cache_sp;
+
+	nwrap_sp_global.cache->path = getenv("NSS_WRAPPER_SHADOW");
+	nwrap_sp_global.cache->fp = NULL;
+	nwrap_sp_global.cache->fd = -1;
+	nwrap_sp_global.cache->private_data = &nwrap_sp_global;
+	nwrap_sp_global.cache->parse_line = nwrap_sp_parse_line;
+	nwrap_sp_global.cache->unload = nwrap_sp_unload;
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+	/* group */
 	nwrap_gr_global.cache = &__nwrap_cache_gr;
 
 	nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
+	nwrap_gr_global.cache->fp = NULL;
 	nwrap_gr_global.cache->fd = -1;
 	nwrap_gr_global.cache->private_data = &nwrap_gr_global;
 	nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
 	nwrap_gr_global.cache->unload = nwrap_gr_unload;
 
+	/* hosts */
 	nwrap_he_global.cache = &__nwrap_cache_he;
 
 	nwrap_he_global.cache->path = getenv("NSS_WRAPPER_HOSTS");
+	nwrap_he_global.cache->fp = NULL;
 	nwrap_he_global.cache->fd = -1;
 	nwrap_he_global.cache->private_data = &nwrap_he_global;
 	nwrap_he_global.cache->parse_line = nwrap_he_parse_line;
 	nwrap_he_global.cache->unload = nwrap_he_unload;
+
+done:
+	/* We hold all locks here so we can use NWRAP_UNLOCK_ALL. */
+	NWRAP_UNLOCK_ALL;
 }
 
 bool nss_wrapper_enabled(void)
@@ -1273,6 +1650,20 @@ bool nss_wrapper_enabled(void)
 	return true;
 }
 
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+bool nss_wrapper_shadow_enabled(void)
+{
+	nwrap_init();
+
+	if (nwrap_sp_global.cache->path == NULL ||
+	    nwrap_sp_global.cache->path[0] == '\0') {
+		return false;
+	}
+
+	return true;
+}
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
 bool nss_wrapper_hosts_enabled(void)
 {
 	nwrap_init();
@@ -1298,109 +1689,103 @@ static bool nwrap_hostname_enabled(void)
 
 static bool nwrap_parse_file(struct nwrap_cache *nwrap)
 {
-	int ret;
-	uint8_t *buf = NULL;
-	char *nline;
+	char *line = NULL;
+	ssize_t n;
+	/* Unused but getline needs it */
+	size_t len;
+	bool ok;
 
 	if (nwrap->st.st_size == 0) {
 		NWRAP_LOG(NWRAP_LOG_DEBUG, "size == 0");
-		goto done;
+		return true;
 	}
 
+	/* Support for 32-bit system I guess */
 	if (nwrap->st.st_size > INT32_MAX) {
 		NWRAP_LOG(NWRAP_LOG_ERROR,
 			  "Size[%u] larger than INT32_MAX",
 			  (unsigned)nwrap->st.st_size);
-		goto failed;
-	}
-
-	ret = lseek(nwrap->fd, 0, SEEK_SET);
-	if (ret != 0) {
-		NWRAP_LOG(NWRAP_LOG_ERROR, "lseek - rc=%d\n", ret);
-		goto failed;
-	}
-
-	buf = (uint8_t *)malloc(nwrap->st.st_size + 1);
-	if (!buf) {
-		NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
-		goto failed;
-	}
-
-	ret = read(nwrap->fd, buf, nwrap->st.st_size);
-	if (ret != nwrap->st.st_size) {
-		NWRAP_LOG(NWRAP_LOG_ERROR,
-			  "read(%u) rc=%d\n",
-			  (unsigned)nwrap->st.st_size, ret);
-		goto failed;
+		return false;
 	}
 
-	buf[nwrap->st.st_size] = '\0';
+	rewind(nwrap->fp);
 
-	nline = (char *)buf;
-	while (nline != NULL && nline[0] != '\0') {
-		char *line;
-		char *e;
-		bool ok;
+	do {
+		n = getline(&line, &len, nwrap->fp);
+		if (n < 0) {
+			SAFE_FREE(line);
+			if (feof(nwrap->fp)) {
+				break;
+			}
 
-		line = nline;
-		nline = NULL;
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "Unable to read line from file: %s",
+				  nwrap->path);
+			return false;
+		}
 
-		e = strchr(line, '\n');
-		if (e) {
-			e[0] = '\0';
-			e++;
-			if (e[0] == '\r') {
-				e[0] = '\0';
-				e++;
-			}
-			nline = e;
+		if (line[n - 1] == '\n') {
+			line[n - 1] = '\0';
 		}
 
-		if (strlen(line) == 0) {
+		if (line[0] == '\0') {
+			SAFE_FREE(line);
 			continue;
 		}
 
 		ok = nwrap->parse_line(nwrap, line);
 		if (!ok) {
-			goto failed;
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "Unable to parse line file: %s",
+				  line);
+			SAFE_FREE(line);
+			return false;
 		}
-	}
 
-done:
-	nwrap->buf = buf;
-	return true;
+		/* Line is parsed without issues so add it to list */
+		ok = nwrap_vector_add_item(&(nwrap->lines), (void *const) line);
+		if (!ok) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "Unable to add line to vector");
+			return false;
+		}
 
-failed:
-	if (buf) free(buf);
-	return false;
+		/* This forces getline to allocate new memory for line. */
+		line = NULL;
+	} while (!feof(nwrap->fp));
+
+	return true;
 }
 
 static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
 {
 	nwrap->unload(nwrap);
 
-	if (nwrap->buf) free(nwrap->buf);
-
-	nwrap->buf = NULL;
+	nwrap_lines_unload(nwrap);
 }
 
-static void nwrap_files_cache_reload(struct nwrap_cache *nwrap)
+static bool nwrap_files_cache_reload(struct nwrap_cache *nwrap)
 {
 	struct stat st;
 	int ret;
 	bool ok;
 	bool retried = false;
 
+	assert(nwrap != NULL);
+
 reopen:
 	if (nwrap->fd < 0) {
-		nwrap->fd = open(nwrap->path, O_RDONLY);
-		if (nwrap->fd < 0) {
+		nwrap->fp = fopen(nwrap->path, "re");
+		if (nwrap->fp == NULL) {
+			nwrap->fd = -1;
 			NWRAP_LOG(NWRAP_LOG_ERROR,
 				  "Unable to open '%s' readonly %d:%s",
 				  nwrap->path, nwrap->fd,
 				  strerror(errno));
-			return;
+			return false;
+
 		}
+		nwrap->fd = fileno(nwrap->fp);
 		NWRAP_LOG(NWRAP_LOG_DEBUG, "Open '%s'", nwrap->path);
 	}
 
@@ -1411,7 +1796,10 @@ reopen:
 			  nwrap->path,
 			  ret,
 			  strerror(errno));
-		return;
+		fclose(nwrap->fp);
+		nwrap->fp = NULL;
+		nwrap->fd = -1;
+		return false;
 	}
 
 	if (retried == false && st.st_nlink == 0) {
@@ -1421,7 +1809,8 @@ reopen:
 			  nwrap->path);
 		retried = true;
 		memset(&nwrap->st, 0, sizeof(nwrap->st));
-		close(nwrap->fd);
+		fclose(nwrap->fp);
+		nwrap->fp = NULL;
 		nwrap->fd = -1;
 		goto reopen;
 	}
@@ -1430,7 +1819,7 @@ reopen:
 		NWRAP_LOG(NWRAP_LOG_TRACE,
 			  "st_mtime[%u] hasn't changed, skip reload",
 			  (unsigned)st.st_mtime);
-		return;
+		return true;
 	}
 
 	NWRAP_LOG(NWRAP_LOG_TRACE,
@@ -1446,9 +1835,11 @@ reopen:
 	if (!ok) {
 		NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to reload %s", nwrap->path);
 		nwrap_files_cache_unload(nwrap);
+		return false;
 	}
 
 	NWRAP_LOG(NWRAP_LOG_TRACE, "Reloaded %s", nwrap->path);
+	return true;
 }
 
 /*
@@ -1617,9 +2008,7 @@ static void nwrap_pw_unload(struct nwrap_cache *nwrap)
 	struct nwrap_pw *nwrap_pw;
 	nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
 
-	if (nwrap_pw->list) free(nwrap_pw->list);
-
-	nwrap_pw->list = NULL;
+	SAFE_FREE(nwrap_pw->list);
 	nwrap_pw->num = 0;
 	nwrap_pw->idx = 0;
 }
@@ -1664,58 +2053,351 @@ static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
 	return 0;
 }
 
-/*
- * the caller has to call nwrap_unload() on failure
- */
-static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line)
 {
-	struct nwrap_gr *nwrap_gr;
+	struct nwrap_sp *nwrap_sp;
+	struct spwd *sp;
+	size_t list_size;
 	char *c;
-	char *p;
 	char *e;
-	struct group *gr;
-	size_t list_size;
-	unsigned nummem;
+	char *p;
 
-	nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
+	nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
 
-	list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
-	gr = (struct group *)realloc(nwrap_gr->list, list_size);
-	if (!gr) {
-		NWRAP_LOG(NWRAP_LOG_ERROR, "realloc failed");
+	list_size = sizeof(*nwrap_sp->list) * (nwrap_sp->num+1);
+	sp = (struct spwd *)realloc(nwrap_sp->list, list_size);
+	if (sp == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR,
+			  "realloc(%u) failed",
+			  (unsigned)list_size);
 		return false;
 	}
-	nwrap_gr->list = gr;
+	nwrap_sp->list = sp;
 
-	gr = &nwrap_gr->list[nwrap_gr->num];
+	sp = &nwrap_sp->list[nwrap_sp->num];
 
 	c = line;
 
 	/* name */
 	p = strchr(c, ':');
-	if (!p) {
-		NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+	if (p == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR,
+			  "name -- Invalid line[%s]: '%s'",
+			  line,
+			  c);
 		return false;
 	}
 	*p = '\0';
 	p++;
-	gr->gr_name = c;
+	sp->sp_namp = c;
 	c = p;
 
-	NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]", gr->gr_name);
+	NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", sp->sp_namp);
 
-	/* password */
+	/* pwd */
 	p = strchr(c, ':');
-	if (!p) {
-		NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+	if (p == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR,
+			  "pwd -- Invalid line[%s]: '%s'",
+			  line,
+			  c);
 		return false;
 	}
 	*p = '\0';
 	p++;
-	gr->gr_passwd = c;
+	sp->sp_pwdp = c;
 	c = p;
 
-	NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]", gr->gr_passwd);
+	/* lstchg (long) */
+	if (c[0] == ':') {
+		sp->sp_lstchg = -1;
+		p++;
+	} else {
+		p = strchr(c, ':');
+		if (p == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "lstchg -- Invalid line[%s]: '%s'",
+				  line,
+				  c);
+			return false;
+		}
+		*p = '\0';
+		p++;
+		sp->sp_lstchg = strtol(c, &e, 10);
+		if (c == e) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "lstchg -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "lstchg -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e[0] != '\0') {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "lstchg -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+	}
+	c = p;
+
+	/* min (long) */
+	if (c[0] == ':') {
+		sp->sp_min = -1;
+		p++;
+	} else {
+		p = strchr(c, ':');
+		if (p == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "min -- Invalid line[%s]: '%s'",
+				  line,
+				  c);
+			return false;
+		}
+		*p = '\0';
+		p++;
+		sp->sp_min = strtol(c, &e, 10);
+		if (c == e) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "min -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "min -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e[0] != '\0') {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "min -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+	}
+	c = p;
+
+	/* max (long) */
+	if (c[0] == ':') {
+		sp->sp_max = -1;
+		p++;
+	} else {
+		p = strchr(c, ':');
+		if (p == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "max -- Invalid line[%s]: '%s'",
+				  line,
+				  c);
+			return false;
+		}
+		*p = '\0';
+		p++;
+		sp->sp_max = strtol(c, &e, 10);
+		if (c == e) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "max -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "max -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e[0] != '\0') {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "max -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+	}
+	c = p;
+
+	/* warn (long) */
+	if (c[0] == ':') {
+		sp->sp_warn = -1;
+		p++;
+	} else {
+		p = strchr(c, ':');
+		if (p == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "warn -- Invalid line[%s]: '%s'",
+				  line,
+				  c);
+			return false;
+		}
+		*p = '\0';
+		p++;
+		sp->sp_warn = strtol(c, &e, 10);
+		if (c == e) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "warn -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "warn -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e[0] != '\0') {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "warn -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+	}
+	c = p;
+
+	/* inact (long) */
+	if (c[0] == ':') {
+		sp->sp_inact = -1;
+		p++;
+	} else {
+		p = strchr(c, ':');
+		if (p == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "inact -- Invalid line[%s]: '%s'",
+				  line,
+				  c);
+			return false;
+		}
+		*p = '\0';
+		p++;
+		sp->sp_inact = strtol(c, &e, 10);
+		if (c == e) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "inact -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "inact -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e[0] != '\0') {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "inact -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+	}
+	c = p;
+
+	/* expire (long) */
+	if (c[0] == ':') {
+		sp->sp_expire = -1;
+		p++;
+	} else {
+		p = strchr(c, ':');
+		if (p == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "expire -- Invalid line[%s]: '%s'",
+				  line,
+				  c);
+			return false;
+		}
+		*p = '\0';
+		p++;
+		sp->sp_expire = strtol(c, &e, 10);
+		if (c == e) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "expire -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e == NULL) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "expire -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+		if (e[0] != '\0') {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "expire -- Invalid line[%s]: '%s' - %s",
+				  line, c, strerror(errno));
+			return false;
+		}
+	}
+	c = p;
+
+	nwrap_sp->num++;
+	return true;
+}
+
+static void nwrap_sp_unload(struct nwrap_cache *nwrap)
+{
+	struct nwrap_sp *nwrap_sp;
+	nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
+
+	SAFE_FREE(nwrap_sp->list);
+	nwrap_sp->num = 0;
+	nwrap_sp->idx = 0;
+}
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+/*
+ * the caller has to call nwrap_unload() on failure
+ */
+static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
+{
+	struct nwrap_gr *nwrap_gr;
+	char *c;
+	char *p;
+	char *e;
+	struct group *gr;
+	size_t list_size;
+	unsigned nummem;
+
+	nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
+
+	list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
+	gr = (struct group *)realloc(nwrap_gr->list, list_size);
+	if (!gr) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "realloc failed");
+		return false;
+	}
+	nwrap_gr->list = gr;
+
+	gr = &nwrap_gr->list[nwrap_gr->num];
+
+	c = line;
+
+	/* name */
+	p = strchr(c, ':');
+	if (!p) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+		return false;
+	}
+	*p = '\0';
+	p++;
+	gr->gr_name = c;
+	c = p;
+
+	NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]", gr->gr_name);
+
+	/* password */
+	p = strchr(c, ':');
+	if (!p) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+		return false;
+	}
+	*p = '\0';
+	p++;
+	gr->gr_passwd = c;
+	c = p;
+
+	NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]", gr->gr_passwd);
 
 	/* gid */
 	p = strchr(c, ':');
@@ -1804,14 +2486,11 @@ static void nwrap_gr_unload(struct nwrap_cache *nwrap)
 
 	if (nwrap_gr->list) {
 		for (i=0; i < nwrap_gr->num; i++) {
-			if (nwrap_gr->list[i].gr_mem) {
-				free(nwrap_gr->list[i].gr_mem);
-			}
+			SAFE_FREE(nwrap_gr->list[i].gr_mem);
 		}
-		free(nwrap_gr->list);
+		SAFE_FREE(nwrap_gr->list);
 	}
 
-	nwrap_gr->list = NULL;
 	nwrap_gr->num = 0;
 	nwrap_gr->idx = 0;
 }
@@ -1869,34 +2548,178 @@ static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
 	return 0;
 }
 
+static struct nwrap_entlist *nwrap_entlist_init(struct nwrap_entdata *ed)
+{
+	struct nwrap_entlist *el;
+
+	if (ed == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR,
+			  "entry is NULL, can't create list item");
+		return NULL;
+	}
+
+	el = (struct nwrap_entlist *)malloc(sizeof(struct nwrap_entlist));
+	if (el == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "malloc failed");
+		return NULL;
+	}
+
+	el->next = NULL;
+	el->ed = ed;
+
+	return el;
+}
+
+static bool nwrap_ed_inventarize_add_new(char *const h_name,
+					 struct nwrap_entdata *const ed)
+{
+	ENTRY e;
+	ENTRY *p;
+	struct nwrap_entlist *el;
+	bool ok;
+
+	if (h_name == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "h_name NULL - can't add");
+		return false;
+	}
+
+	el = nwrap_entlist_init(ed);
+	if (el == NULL) {
+		return false;
+	}
+
+	e.key = h_name;
+	e.data = (void *)el;
+
+	p = hsearch(e, ENTER);
+	if (p == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Hash table is full!");
+		return false;
+	}
+
+	ok = nwrap_vector_add_item(&(nwrap_he_global.lists), (void *)el);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR,
+			  "Failed to add list entry to vector.");
+		return false;
+	}
+
+	return true;
+}
+
+static bool nwrap_ed_inventarize_add_to_existing(struct nwrap_entdata *const ed,
+						 struct nwrap_entlist *const el)
+{
+	struct nwrap_entlist *cursor;
+	struct nwrap_entlist *el_new;
+
+	if (el == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "list is NULL, can not add");
+		return false;
+	}
+
+
+	for (cursor = el; cursor->next != NULL; cursor = cursor->next)
+	{
+		if (cursor->ed == ed) {
+			/* The entry already exists in this list. */
+			return true;
+		}
+	}
+
+	if (cursor->ed == ed) {
+		/* The entry already exists in this list. */
+		return true;
+	}
+
+	el_new = nwrap_entlist_init(ed);
+	if (el_new == NULL) {
+		return false;
+	}
+
+	cursor->next = el_new;
+	return true;
+}
+
+static bool nwrap_ed_inventarize(char *const name,
+				 struct nwrap_entdata *const ed)
+{
+	ENTRY e;
+	ENTRY *p;
+	bool ok;
+
+	e.key = name;
+	e.data = NULL;
+
+	NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key);
+
+	p = hsearch(e, FIND);
+	if (p == NULL) {
+		NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", name);
+		ok = nwrap_ed_inventarize_add_new(name, ed);
+	} else {
+		struct nwrap_entlist *el = (struct nwrap_entlist *)p->data;
+
+		NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", name);
+		ok = nwrap_ed_inventarize_add_to_existing(ed, el);
+	}
+
+	return ok;
+}
+
+static bool nwrap_add_hname(struct nwrap_entdata *const ed)
+{
+	char *const h_name = (char *const)(ed->ht.h_name);
+	unsigned i;
+	bool ok;
+
+	ok = nwrap_ed_inventarize(h_name, ed);
+	if (!ok) {
+		return false;
+	}
+
+	if (ed->ht.h_aliases == NULL) {
+		return true;
+	}
+
+	/* Itemize aliases */
+	for (i = 0; ed->ht.h_aliases[i] != NULL; ++i) {
+		char *h_name_alias;
+
+		h_name_alias = ed->ht.h_aliases[i];
+
+		NWRAP_LOG(NWRAP_LOG_DEBUG, "Add alias: %s", h_name_alias);
+
+		if (!nwrap_ed_inventarize(h_name_alias, ed)) {
+			NWRAP_LOG(NWRAP_LOG_ERROR,
+				  "Unable to add alias: %s", h_name_alias);
+			return false;
+		}
+	}
+
+	return true;
+}
+
 static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
 {
 	struct nwrap_he *nwrap_he = (struct nwrap_he *)nwrap->private_data;
-	struct nwrap_entdata *ed;
-	size_t list_size;
 	bool do_aliases = true;
-	int aliases_count = 0;
+	ssize_t aliases_count = 0;
 	char *p;
 	char *i;
 	char *n;
 
-	list_size = sizeof(struct nwrap_entdata) * (nwrap_he->num + 1);
+	char *ip;
+	bool ok;
 
-	ed = (struct nwrap_entdata *)realloc(nwrap_he->list, list_size);
+	struct nwrap_entdata *ed = (struct nwrap_entdata *)
+				   malloc(sizeof(struct nwrap_entdata));
 	if (ed == NULL) {
-		NWRAP_LOG(NWRAP_LOG_ERROR, "realloc[%zd] failed", list_size);
-		return false;
-	}
-	nwrap_he->list = ed;
-
-	/* set it to the last element */
-	ed = &(nwrap_he->list[nwrap_he->num]);
-
-	ed->addr = malloc(sizeof(struct nwrap_addrdata));
-	if (ed->addr == NULL) {
-		NWRAP_LOG(NWRAP_LOG_ERROR, "realloc[%zd] failed", list_size);
+		NWRAP_LOG(NWRAP_LOG_ERROR,
+			  "Unable to allocate memory for nwrap_entdata");
 		return false;
 	}
+	ZERO_STRUCTP(ed);
 
 	i = line;
 
@@ -1910,6 +2733,7 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
 			NWRAP_LOG(NWRAP_LOG_ERROR,
 				  "Invalid line[%s]: '%s'",
 				  line, i);
+			free(ed);
 			return false;
 		}
 	}
@@ -1919,17 +2743,18 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
 			NWRAP_LOG(NWRAP_LOG_ERROR,
 				  "Invalid line[%s]: '%s'",
 				  line, i);
+			free(ed);
 			return false;
 		}
 	}
 
 	*p = '\0';
 
-	if (inet_pton(AF_INET, i, ed->addr->host_addr)) {
+	if (inet_pton(AF_INET, i, ed->addr.host_addr)) {
 		ed->ht.h_addrtype = AF_INET;
 		ed->ht.h_length = 4;
 #ifdef HAVE_IPV6
-	} else if (inet_pton(AF_INET6, i, ed->addr->host_addr)) {
+	} else if (inet_pton(AF_INET6, i, ed->addr.host_addr)) {
 		ed->ht.h_addrtype = AF_INET6;
 		ed->ht.h_length = 16;
 #endif
@@ -1938,13 +2763,19 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
 			  "Invalid line[%s]: '%s'",
 			  line, i);
 
+		free(ed);
 		return false;
 	}
+	ip = i;
 
-	ed->addr->h_addr_ptrs[0] = (char *)ed->addr->host_addr;
-	ed->addr->h_addr_ptrs[1] = NULL;
-
-	ed->ht.h_addr_list = ed->addr->h_addr_ptrs;
+	ok = nwrap_vector_add_item(&(ed->nwrap_addrdata),
+				   (void *const)ed->addr.host_addr);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add addrdata to vector");
+		free(ed);
+		return false;
+	}
+	ed->ht.h_addr_list = nwrap_vector_head(&ed->nwrap_addrdata);
 
 	p++;
 
@@ -1959,6 +2790,7 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
 				  "Invalid line[%s]: '%s'",
 				  line, n);
 
+			free(ed);
 			return false;
 		}
 	}
@@ -1972,11 +2804,14 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
 
 	*p = '\0';
 
+	/* Convert to lowercase. This operate on same memory region */
+	str_tolower(n, n);
 	ed->ht.h_name = n;
 
 	/* glib's getent always dereferences he->h_aliases */
 	ed->ht.h_aliases = malloc(sizeof(char *));
 	if (ed->ht.h_aliases == NULL) {
+		free(ed);
 		return false;
 	}
 	ed->ht.h_aliases[0] = NULL;
@@ -2013,14 +2848,35 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
 
 		aliases = realloc(ed->ht.h_aliases, sizeof(char *) * (aliases_count + 2));
 		if (aliases == NULL) {
+			free(ed);
 			return false;
 		}
 		ed->ht.h_aliases = aliases;
 
+		str_tolower(a, a);
 		aliases[aliases_count] = a;
 		aliases[aliases_count + 1] = NULL;
 
-		aliases_count++;
+		aliases_count += 1;
+	}
+
+	ok = nwrap_vector_add_item(&(nwrap_he->entries), (void *const)ed);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add entry to vector");
+		free(ed);
+		return false;
+	}
+
+	ed->aliases_count = aliases_count;
+	/* Inventarize item */
+	ok = nwrap_add_hname(ed);
+	if (!ok) {
+		return false;
+	}
+
+	ok = nwrap_ed_inventarize(ip, ed);
+	if (!ok) {
+		return false;
 	}
 
 	nwrap_he->num++;
@@ -2031,23 +2887,47 @@ static void nwrap_he_unload(struct nwrap_cache *nwrap)
 {
 	struct nwrap_he *nwrap_he =
 		(struct nwrap_he *)nwrap->private_data;
-	int i;
+	struct nwrap_entdata *ed;
+	struct nwrap_entlist *el;
+	size_t i;
+	int rc;
 
-	if (nwrap_he->list != NULL) {
-		for (i = 0; i < nwrap_he->num; i++) {
-			if (nwrap_he->list[i].ht.h_aliases != NULL) {
-				free(nwrap_he->list[i].ht.h_aliases);
-			}
-			if (nwrap_he->list[i].addr != NULL) {
-				free(nwrap_he->list[i].addr);
-			}
+	nwrap_vector_foreach (ed, nwrap_he->entries, i)
+	{
+		SAFE_FREE(ed->nwrap_addrdata.items);
+		SAFE_FREE(ed->ht.h_aliases);
+		SAFE_FREE(ed);
+	}
+	SAFE_FREE(nwrap_he->entries.items);
+	nwrap_he->entries.count = nwrap_he->entries.capacity = 0;
+
+	nwrap_vector_foreach(el, nwrap_he->lists, i)
+	{
+		while (el != NULL) {
+			struct nwrap_entlist *el_next;
+
+			el_next = el->next;
+			SAFE_FREE(el);
+			el = el_next;
 		}
-		free(nwrap_he->list);
 	}
+	SAFE_FREE(nwrap_he->lists.items);
+	nwrap_he->lists.count = nwrap_he->lists.capacity = 0;
 
-	nwrap_he->list = NULL;
 	nwrap_he->num = 0;
 	nwrap_he->idx = 0;
+
+	/*
+	 * If we unload the file, the pointers in the hash table point to
+	 * invalid memory. So we need to destroy the hash table and recreate
+	 * it.
+	 */
+	hdestroy();
+	rc = hcreate(max_hostents);
+	if (rc == 0) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to initialize hash table");
+		exit(-1);
+	}
 }
 
 
@@ -2056,12 +2936,17 @@ static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
 					   const char *name)
 {
 	int i;
+	bool ok;
 
 	(void) b; /* unused */
 
 	NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
 
-	nwrap_files_cache_reload(nwrap_pw_global.cache);
+	ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
+		return NULL;
+	}
 
 	for (i=0; i<nwrap_pw_global.num; i++) {
 		if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
@@ -2101,10 +2986,15 @@ static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
 					   uid_t uid)
 {
 	int i;
+	bool ok;
 
 	(void) b; /* unused */
 
-	nwrap_files_cache_reload(nwrap_pw_global.cache);
+	ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
+		return NULL;
+	}
 
 	for (i=0; i<nwrap_pw_global.num; i++) {
 		if (nwrap_pw_global.list[i].pw_uid == uid) {
@@ -2155,7 +3045,12 @@ static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
 	(void) b; /* unused */
 
 	if (nwrap_pw_global.idx == 0) {
-		nwrap_files_cache_reload(nwrap_pw_global.cache);
+		bool ok;
+		ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
+		if (!ok) {
+			NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
+			return NULL;
+		}
 	}
 
 	if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
@@ -2193,19 +3088,145 @@ static void nwrap_files_endpwent(struct nwrap_backend *b)
 {
 	(void) b; /* unused */
 
-	nwrap_pw_global.idx = 0;
-}
+	nwrap_pw_global.idx = 0;
+}
+
+/* shadow */
+
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+
+#ifdef HAVE_SETSPENT
+static void nwrap_files_setspent(void)
+{
+	nwrap_sp_global.idx = 0;
+}
+
+static struct spwd *nwrap_files_getspent(void)
+{
+	struct spwd *sp;
+
+	if (nwrap_sp_global.idx == 0) {
+		bool ok;
+
+		ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
+		if (!ok) {
+			NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
+			return NULL;
+		}
+	}
+
+	if (nwrap_sp_global.idx >= nwrap_sp_global.num) {
+		errno = ENOENT;
+		return NULL;
+	}
+
+	sp = &nwrap_sp_global.list[nwrap_sp_global.idx++];
+
+	NWRAP_LOG(NWRAP_LOG_DEBUG,
+		  "return user[%s]",
+		  sp->sp_namp);
+
+	return sp;
+}
+
+static void nwrap_files_endspent(void)
+{
+	nwrap_sp_global.idx = 0;
+}
+#endif /* HAVE_SETSPENT */
+
+static struct spwd *nwrap_files_getspnam(const char *name)
+{
+	int i;
+	bool ok;
+
+	NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
+
+	ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
+		return NULL;
+	}
+
+	for (i=0; i<nwrap_sp_global.num; i++) {
+		if (strcmp(nwrap_sp_global.list[i].sp_namp, name) == 0) {
+			NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name);
+			return &nwrap_sp_global.list[i];
+		}
+		NWRAP_LOG(NWRAP_LOG_DEBUG,
+			  "user[%s] does not match [%s]",
+			  name,
+			  nwrap_sp_global.list[i].sp_namp);
+	}
+
+	NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name);
+
+	errno = ENOENT;
+	return NULL;
+}
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+/* misc functions */
+static int nwrap_files_initgroups(struct nwrap_backend *b,
+				  const char *user,
+				  gid_t group)
+{
+	struct group *grp;
+	gid_t *groups;
+	int size = 1;
+	int rc;
+
+	groups = (gid_t *)malloc(size * sizeof(gid_t));
+	if (groups == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
+		errno = ENOMEM;
+		return -1;
+	}
+	groups[0] = group;
+
+	nwrap_files_setgrent(b);
+	while ((grp = nwrap_files_getgrent(b)) != NULL) {
+		int i = 0;
+
+		NWRAP_LOG(NWRAP_LOG_DEBUG,
+			  "Inspecting %s for group membership",
+			  grp->gr_name);
+
+		for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
+			if (group != grp->gr_gid &&
+			    (strcmp(user, grp->gr_mem[i]) == 0)) {
+				NWRAP_LOG(NWRAP_LOG_DEBUG,
+					  "%s is member of %s",
+					  user,
+					  grp->gr_name);
+
+				groups = (gid_t *)realloc(groups,
+							  (size + 1) * sizeof(gid_t));
+				if (groups == NULL) {
+					NWRAP_LOG(NWRAP_LOG_ERROR,
+						  "Out of memory");
+					errno = ENOMEM;
+					return -1;
+				}
+
+				groups[size] = grp->gr_gid;
+				size++;
+			}
+		}
+	}
+
+	nwrap_files_endgrent(b);
+
+	NWRAP_LOG(NWRAP_LOG_DEBUG,
+		  "%s is member of %d groups",
+		  user, size);
+
+	/* This really only works if uid_wrapper is loaded */
+	rc = setgroups(size, groups);
 
-/* misc functions */
-static int nwrap_files_initgroups(struct nwrap_backend *b,
-				  const char *user, gid_t group)
-{
-	(void) b; /* unused */
-	(void) user; /* unused */
-	(void) group; /* used */
+	free(groups);
 
-	/* TODO: maybe we should also fake this... */
-	return EPERM;
+	return rc;
 }
 
 /* group functions */
@@ -2213,10 +3234,15 @@ static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
 					  const char *name)
 {
 	int i;
+	bool ok;
 
 	(void) b; /* unused */
 
-	nwrap_files_cache_reload(nwrap_gr_global.cache);
+	ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
+		return NULL;
+	}
 
 	for (i=0; i<nwrap_gr_global.num; i++) {
 		if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
@@ -2256,10 +3282,15 @@ static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
 					  gid_t gid)
 {
 	int i;
+	bool ok;
 
 	(void) b; /* unused */
 
-	nwrap_files_cache_reload(nwrap_gr_global.cache);
+	ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
+		return NULL;
+	}
 
 	for (i=0; i<nwrap_gr_global.num; i++) {
 		if (nwrap_gr_global.list[i].gr_gid == gid) {
@@ -2310,7 +3341,13 @@ static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
 	(void) b; /* unused */
 
 	if (nwrap_gr_global.idx == 0) {
-		nwrap_files_cache_reload(nwrap_gr_global.cache);
+		bool ok;
+
+		ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
+		if (!ok) {
+			NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
+			return NULL;
+		}
 	}
 
 	if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
@@ -2352,14 +3389,25 @@ static void nwrap_files_endgrent(struct nwrap_backend *b)
 }
 
 /* hosts functions */
-static struct hostent *nwrap_files_gethostbyname(const char *name, int af)
+static int nwrap_files_gethostbyname(const char *name, int af,
+				     struct hostent *result,
+				     struct nwrap_vector *addr_list)
 {
+	struct nwrap_entlist *el;
 	struct hostent *he;
+	char *h_name_lower;
+	ENTRY e;
+	ENTRY *e_p;
 	char canon_name[DNS_NAME_MAX] = { 0 };
 	size_t name_len;
-	int i;
+	bool he_found = false;
+	bool ok;
 
-	nwrap_files_cache_reload(nwrap_he_global.cache);
+	ok = nwrap_files_cache_reload(nwrap_he_global.cache);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
+		goto no_ent;
+	}
 
 	name_len = strlen(name);
 	if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
@@ -2367,37 +3415,75 @@ static struct hostent *nwrap_files_gethostbyname(const char *name, int af)
 		name = canon_name;
 	}
 
-	for (i = 0; i < nwrap_he_global.num; i++) {
-		int j;
+	if (!str_tolower_copy(&h_name_lower, name)) {
+		NWRAP_LOG(NWRAP_LOG_DEBUG,
+			  "Out of memory while converting to lower case");
+		goto no_ent;
+	}
+
+	/* Look at hash table for element */
+	NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
+	e.key = h_name_lower;
+	e.data = NULL;
+	e_p = hsearch(e, FIND);
+	if (e_p == NULL) {
+		NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
+		SAFE_FREE(h_name_lower);
+		goto no_ent;
+	}
+	SAFE_FREE(h_name_lower);
+
+	/* Always cleanup vector and results */
+	if (!nwrap_vector_is_initialized(addr_list)) {
+		if (!nwrap_vector_init(addr_list)) {
+			NWRAP_LOG(NWRAP_LOG_DEBUG,
+				  "Unable to initialize memory for addr_list vector");
+			goto no_ent;
+		}
+	} else {
+		/* When vector is initialized data are valid no more.
+		 * Quick way how to free vector is: */
+		addr_list->count = 0;
+	}
 
-		he = &nwrap_he_global.list[i].ht;
+	/* Iterate through results */
+	for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
+	{
+		he = &(el->ed->ht);
 
 		/* Filter by address familiy if provided */
 		if (af != AF_UNSPEC && he->h_addrtype != af) {
 			continue;
 		}
 
-		if (strcasecmp(he->h_name, name) == 0) {
-			NWRAP_LOG(NWRAP_LOG_DEBUG, "name[%s] found", name);
-			return he;
-		}
-
-		if (he->h_aliases == NULL) {
+		/*
+		 * GLIBC HACK?
+		 * glibc doesn't return ipv6 addresses when AF_UNSPEC is used
+		 */
+		if (af == AF_UNSPEC && he->h_addrtype != AF_INET) {
 			continue;
 		}
 
-		for (j = 0; he->h_aliases[j] != NULL; j++) {
-			if (strcasecmp(he->h_aliases[j], name) == 0) {
-				NWRAP_LOG(NWRAP_LOG_DEBUG,
-					  "name[%s] found",
-					  name);
-				return he;
-			}
+		if (!he_found) {
+			memcpy(result, he, sizeof(struct hostent));
+			NWRAP_LOG(NWRAP_LOG_DEBUG,
+				  "Name found. Returning record for %s",
+				  he->h_name);
+			he_found = true;
 		}
+		nwrap_vector_merge(addr_list, &el->ed->nwrap_addrdata);
+		result->h_addr_list = nwrap_vector_head(addr_list);
+	}
+
+	if (he_found) {
+		return 0;
 	}
+	NWRAP_LOG(NWRAP_LOG_DEBUG,
+		  "Name found in database. No records matches type.");
 
+no_ent:
 	errno = ENOENT;
-	return NULL;
+	return -1;
 }
 
 #ifdef HAVE_GETHOSTBYNAME_R
@@ -2406,15 +3492,46 @@ static int nwrap_gethostbyname_r(const char *name,
 				 char *buf, size_t buflen,
 				 struct hostent **result, int *h_errnop)
 {
-	*result = nwrap_files_gethostbyname(name, AF_UNSPEC);
-	if (*result != NULL) {
-		memset(buf, '\0', buflen);
-		*ret = **result;
-		return 0;
-	} else {
+	struct nwrap_vector *addr_list = malloc(sizeof(struct nwrap_vector));
+	int rc;
+
+	if (addr_list == NULL) {
+		NWRAP_LOG(NWRAP_LOG_ERROR,
+			  "Unable to allocate memory for address list");
+		errno = ENOENT;
+		return -1;
+	}
+
+	ZERO_STRUCTP(addr_list);
+
+	rc = nwrap_files_gethostbyname(name, AF_UNSPEC, ret, addr_list);
+	if (rc == -1) {
 		*h_errnop = h_errno;
+		if (addr_list->items != NULL) {
+			free(addr_list->items);
+		}
+		SAFE_FREE(addr_list);
+		errno = ENOENT;
 		return -1;
 	}
+
+	if (buflen < (addr_list->count * sizeof(void *))) {
+		SAFE_FREE(addr_list->items);
+		SAFE_FREE(addr_list);
+		return ERANGE;
+	}
+
+	/* Copy all to user provided buffer and change
+	 * pointers in returned structure.
+	 * +1 is for ending NULL pointer. */
+	memcpy(buf, addr_list->items, (addr_list->count + 1) * sizeof(void *));
+
+	free(addr_list->items);
+	free(addr_list);
+
+	ret->h_addr_list = (char **)buf;
+	*result = ret;
+	return 0;
 }
 
 int gethostbyname_r(const char *name,
@@ -2435,17 +3552,125 @@ int gethostbyname_r(const char *name,
 }
 #endif
 
+static int nwrap_files_getaddrinfo(const char *name,
+				   unsigned short port,
+				   const struct addrinfo *hints,
+				   struct addrinfo **ai)
+{
+	struct nwrap_entlist *el;
+	struct hostent *he;
+	struct addrinfo *ai_head = NULL;
+	struct addrinfo *ai_cur = NULL;
+	char *h_name_lower;
+	size_t name_len;
+	char canon_name[DNS_NAME_MAX] = { 0 };
+	bool skip_canonname = false;
+	ENTRY e = {
+		.key = NULL,
+	};
+	ENTRY *e_p = NULL;
+	int rc;
+	bool ok;
+
+	ok = nwrap_files_cache_reload(nwrap_he_global.cache);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
+		return EAI_SYSTEM;
+	}
+
+	name_len = strlen(name);
+	if (name_len < DNS_NAME_MAX && name[name_len - 1] == '.') {
+		strncpy(canon_name, name, name_len - 1);
+		name = canon_name;
+	}
+
+	if (!str_tolower_copy(&h_name_lower, name)) {
+		NWRAP_LOG(NWRAP_LOG_DEBUG,
+			  "Out of memory while converting to lower case");
+		return EAI_MEMORY;
+	}
+
+	NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
+	e.key = h_name_lower;
+	e.data = NULL;
+	e_p = hsearch(e, FIND);
+	if (e_p == NULL) {
+		NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
+		SAFE_FREE(h_name_lower);
+		errno = ENOENT;
+		return EAI_NONAME;
+	}
+	NWRAP_LOG(NWRAP_LOG_DEBUG, "Name: %s found.", h_name_lower);
+	SAFE_FREE(h_name_lower);
+
+	rc = EAI_NONAME;
+	for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
+	{
+		int rc2;
+		struct addrinfo *ai_new = NULL;
+
+		he = &(el->ed->ht);
+
+		if (hints->ai_family != AF_UNSPEC &&
+		    he->h_addrtype != hints->ai_family)
+		{
+			NWRAP_LOG(NWRAP_LOG_DEBUG,
+				  "Entry found but with wrong AF - "
+				  "remembering EAI_ADDRINFO.");
+			rc = EAI_ADDRFAMILY;
+			continue;
+		}
+
+		/* Function allocates memory and returns it in ai. */
+		rc2 = nwrap_convert_he_ai(he,
+					 port,
+					 hints,
+					 &ai_new,
+					 skip_canonname);
+		if (rc2 != 0) {
+			NWRAP_LOG(NWRAP_LOG_ERROR, "Error converting he to ai");
+			if (ai_head != NULL) {
+				freeaddrinfo(ai_head);
+			}
+			return rc2;
+		}
+		skip_canonname = true;
+
+		if (ai_head == NULL) {
+			ai_head = ai_new;
+		}
+		if (ai_cur != NULL) {
+			ai_cur->ai_next = ai_new;
+		}
+		ai_cur = ai_new;
+	}
+
+	if (ai_head != NULL) {
+		rc = 0;
+	}
+
+	*ai = ai_head;
+
+	return rc;
+}
+
 static struct hostent *nwrap_files_gethostbyaddr(const void *addr,
 						 socklen_t len, int type)
 {
 	struct hostent *he;
-	char ip[INET6_ADDRSTRLEN] = {0};
+	char ip[NWRAP_INET_ADDRSTRLEN] = {0};
+	struct nwrap_entdata *ed;
 	const char *a;
-	int i;
+	size_t i;
+	bool ok;
 
 	(void) len; /* unused */
 
-	nwrap_files_cache_reload(nwrap_he_global.cache);
+	ok = nwrap_files_cache_reload(nwrap_he_global.cache);
+	if (!ok) {
+		NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
+		return NULL;
+	}
 
 	a = inet_ntop(type, addr, ip, sizeof(ip));
 	if (a == NULL) {
@@ -2453,9 +3678,9 @@ static struct hostent *nwrap_files_gethostbyaddr(const void *addr,
 		return NULL;
 	}
 
-	for (i = 0; i < nwrap_he_global.num; i++) {
-		he = &nwrap_he_global.list[i].ht;
-
+	nwrap_vector_foreach(ed, nwrap_he_global.entries, i)
+	{
+		he = &(ed->ht);
 		if (he->h_addrtype != type) {
 			continue;
 		}
@@ -2517,7 +3742,13 @@ static struct hostent *nwrap_files_gethostent(void)
 	struct hostent *he;
 
 	if (nwrap_he_global.idx == 0) {
-		nwrap_files_cache_reload(nwrap_he_global.cache);
+		bool ok;
+
+		ok = nwrap_files_cache_reload(nwrap_he_global.cache);
+		if (!ok) {
+			NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading hosts file");
+			return NULL;
+		}
 	}
 
 	if (nwrap_he_global.idx >= nwrap_he_global.num) {
@@ -2525,7 +3756,7 @@ static struct hostent *nwrap_files_gethostent(void)
 		return NULL;
 	}
 
-	he = &nwrap_he_global.list[nwrap_he_global.idx++].ht;
+	he = &((struct nwrap_entdata *)nwrap_he_global.entries.items[nwrap_he_global.idx++])->ht;
 
 	NWRAP_LOG(NWRAP_LOG_DEBUG, "return hosts[%s]", he->h_name);
 
@@ -2541,9 +3772,6 @@ static void nwrap_files_endhostent(void)
  * module backend
  */
 
-#ifndef SAFE_FREE
-#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
-#endif
 
 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
 					    const char *name)
@@ -3549,7 +4777,6 @@ static int nwrap_getgrouplist(const char *user, gid_t group,
 	struct group *grp;
 	gid_t *groups_tmp;
 	int count = 1;
-	const char *name_of_group = "";
 
 	NWRAP_LOG(NWRAP_LOG_DEBUG, "getgrouplist called for %s", user);
 
@@ -3559,13 +4786,7 @@ static int nwrap_getgrouplist(const char *user, gid_t group,
 		errno = ENOMEM;
 		return -1;
 	}
-
-	memcpy(groups_tmp, &group, sizeof(gid_t));
-
-	grp = nwrap_getgrgid(group);
-	if (grp) {
-		name_of_group = grp->gr_name;
-	}
+	groups_tmp[0] = group;
 
 	nwrap_setgrent();
 	while ((grp = nwrap_getgrent()) != NULL) {
@@ -3577,8 +4798,8 @@ static int nwrap_getgrouplist(const char *user, gid_t group,
 
 		for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
 
-			if ((strcmp(user, grp->gr_mem[i]) == 0) &&
-			    (strcmp(name_of_group, grp->gr_name) != 0)) {
+			if (group != grp->gr_gid &&
+			    (strcmp(user, grp->gr_mem[i]) == 0)) {
 
 				NWRAP_LOG(NWRAP_LOG_DEBUG,
 					  "%s is member of %s",
@@ -3592,8 +4813,8 @@ static int nwrap_getgrouplist(const char *user, gid_t group,
 					errno = ENOMEM;
 					return -1;
 				}
+				groups_tmp[count] = grp->gr_gid;
 
-				memcpy(&groups_tmp[count], &grp->gr_gid, sizeof(gid_t));
 				count++;
 			}
 		}
@@ -3629,6 +4850,72 @@ int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
 #endif
 
 /**********************************************************
+ * SHADOW
+ **********************************************************/
+
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+
+#ifdef HAVE_SETSPENT
+static void nwrap_setspent(void)
+{
+	nwrap_files_setspent();
+}
+
+void setspent(void)
+{
+	if (!nss_wrapper_shadow_enabled()) {
+		return;
+	}
+
+	nwrap_setspent();
+}
+
+static struct spwd *nwrap_getspent(void)
+{
+	return nwrap_files_getspent();
+}
+
+struct spwd *getspent(void)
+{
+	if (!nss_wrapper_shadow_enabled()) {
+		return NULL;
+	}
+
+	return nwrap_getspent();
+}
+
+static void nwrap_endspent(void)
+{
+	nwrap_files_endspent();
+}
+
+void endspent(void)
+{
+	if (!nss_wrapper_shadow_enabled()) {
+		return;
+	}
+
+	nwrap_endspent();
+}
+#endif /* HAVE_SETSPENT */
+
+static struct spwd *nwrap_getspnam(const char *name)
+{
+	return nwrap_files_getspnam(name);
+}
+
+struct spwd *getspnam(const char *name)
+{
+	if (!nss_wrapper_shadow_enabled()) {
+		return NULL;
+	}
+
+	return nwrap_getspnam(name);
+}
+
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+/**********************************************************
  * NETDB
  **********************************************************/
 
@@ -3703,9 +4990,20 @@ void endhostent(void)
 }
 #endif /* HAVE_SOLARIS_ENDHOSTENT */
 
+#ifdef BSD
+/* BSD implementation stores data in thread local storage but GLIBC does not */
+static __thread struct hostent user_he;
+static __thread struct nwrap_vector user_addrlist;
+#else
+static struct hostent user_he;
+static struct nwrap_vector user_addrlist;
+#endif /* BSD */
 static struct hostent *nwrap_gethostbyname(const char *name)
 {
-	return nwrap_files_gethostbyname(name, AF_UNSPEC);
+	if (nwrap_files_gethostbyname(name, AF_UNSPEC, &user_he, &user_addrlist) == -1) {
+		return NULL;
+	}
+	return &user_he;
 }
 
 struct hostent *gethostbyname(const char *name)
@@ -3717,11 +5015,22 @@ struct hostent *gethostbyname(const char *name)
 	return nwrap_gethostbyname(name);
 }
 
-/* This is a GNU extension */
+/* This is a GNU extension - Also can be found on BSD systems */
 #ifdef HAVE_GETHOSTBYNAME2
+#ifdef BSD
+/* BSD implementation stores data in  thread local storage but GLIBC not */
+static __thread struct hostent user_he2;
+static __thread struct nwrap_vector user_addrlist2;
+#else
+static struct hostent user_he2;
+static struct nwrap_vector user_addrlist2;
+#endif /* BSD */
 static struct hostent *nwrap_gethostbyname2(const char *name, int af)
 {
-	return nwrap_files_gethostbyname(name, af);
+	if (nwrap_files_gethostbyname(name, af, &user_he2, &user_addrlist2) == -1) {
+		return NULL;
+	}
+	return &user_he2;
 }
 
 struct hostent *gethostbyname2(const char *name, int af)
@@ -3765,11 +5074,16 @@ static const struct addrinfo default_hints =
 static int nwrap_convert_he_ai(const struct hostent *he,
 			       unsigned short port,
 			       const struct addrinfo *hints,
-			       struct addrinfo **pai)
+			       struct addrinfo **pai,
+			       bool skip_canonname)
 {
 	struct addrinfo *ai;
 	socklen_t socklen;
 
+	if (he == NULL) {
+		return EAI_MEMORY;
+	}
+
 	switch (he->h_addrtype) {
 		case AF_INET:
 			socklen = sizeof(struct sockaddr_in);
@@ -3788,10 +5102,22 @@ static int nwrap_convert_he_ai(const struct hostent *he,
 		return EAI_MEMORY;
 	}
 
-	ai->ai_flags = 0;
+	ai->ai_flags = hints->ai_flags;
 	ai->ai_family = he->h_addrtype;
 	ai->ai_socktype = hints->ai_socktype;
 	ai->ai_protocol = hints->ai_protocol;
+	ai->ai_canonname = NULL;
+
+	if (ai->ai_socktype == 0) {
+		ai->ai_socktype = SOCK_DGRAM;
+	}
+	if (ai->ai_protocol == 0) {
+		if (ai->ai_socktype == SOCK_DGRAM) {
+			ai->ai_protocol = IPPROTO_UDP;
+		} else if (ai->ai_socktype == SOCK_STREAM) {
+			ai->ai_protocol = IPPROTO_TCP;
+		}
+	}
 
 	ai->ai_addrlen = socklen;
 	ai->ai_addr = (void *)(ai + 1);
@@ -3828,7 +5154,9 @@ static int nwrap_convert_he_ai(const struct hostent *he,
 			sin6p->sin6_port = htons(port);
 			sin6p->sin6_family = AF_INET6;
 
-			memcpy(&sin6p->sin6_addr, he->h_addr_list[0], he->h_length);
+			memcpy(&sin6p->sin6_addr,
+			       he->h_addr_list[0],
+			       he->h_length);
 		}
 		break;
 #endif
@@ -3836,7 +5164,7 @@ static int nwrap_convert_he_ai(const struct hostent *he,
 
 	ai->ai_next = NULL;
 
-	if (he->h_name) {
+	if (he->h_name && !skip_canonname) {
 		ai->ai_canonname = strdup(he->h_name);
 		if (ai->ai_canonname == NULL) {
 			freeaddrinfo(ai);
@@ -3854,9 +5182,7 @@ static int nwrap_getaddrinfo(const char *node,
 			     struct addrinfo **res)
 {
 	struct addrinfo *ai = NULL;
-	struct addrinfo *p = NULL;
 	unsigned short port = 0;
-	struct hostent *he;
 	struct {
 		int family;
 		union {
@@ -3868,149 +5194,161 @@ static int nwrap_getaddrinfo(const char *node,
 	} addr = {
 		.family = AF_UNSPEC,
 	};
-	int eai = EAI_SYSTEM;
-	int ret;
 	int rc;
 
 	if (node == NULL && service == NULL) {
 		return EAI_NONAME;
 	}
 
-	ret = libc_getaddrinfo(node, service, hints, &p);
-	if (ret == 0) {
-		*res = p;
+	if (hints == NULL) {
+		hints = &default_hints;
+	}
+
+        /* EAI_BADFLAGS
+              hints.ai_flags   contains   invalid  flags;  or,  hints.ai_flags
+              included AI_CANONNAME and name was NULL.
+	*/
+	if ((hints->ai_flags & AI_CANONNAME) && (node == NULL)) {
+		return EAI_BADFLAGS;
 	}
 
 	/* If no node has been specified, let glibc deal with it */
 	if (node == NULL) {
-		return ret;
-	}
+		int ret;
+		struct addrinfo *p = NULL;
 
-	if (hints == NULL) {
-		hints = &default_hints;
-	}
+		ret = libc_getaddrinfo(node, service, hints, &p);
 
-	if ((hints->ai_flags & AI_CANONNAME) && node == NULL) {
-		return EAI_BADFLAGS;
+		if (ret == 0) {
+			*res = p;
+		}
+		return ret;
 	}
 
 	if (service != NULL && service[0] != '\0') {
-		if (isdigit((int)service[0])) {
-			port = (unsigned short)atoi(service);
-		} else {
-			const char *proto = NULL;
-			struct servent *s;
+		const char *proto = NULL;
+		struct servent *s;
+		char *end_ptr;
+		long sl;
+
+		errno = 0;
+		sl = strtol(service, &end_ptr, 10);
+
+		if (*end_ptr == '\0') {
+			port = sl;
+			goto valid_port;
+		} else if (hints->ai_flags & AI_NUMERICSERV) {
+			return EAI_NONAME;
+		}
 
-			if (hints->ai_protocol != 0) {
-				struct protoent *pent;
+		if (hints->ai_protocol != 0) {
+			struct protoent *pent;
 
-				pent = getprotobynumber(hints->ai_protocol);
-				if (pent != NULL) {
-					proto = pent->p_name;
-				}
+			pent = getprotobynumber(hints->ai_protocol);
+			if (pent != NULL) {
+				proto = pent->p_name;
 			}
+		}
 
-			s = getservbyname(service, proto);
-			if (s != NULL) {
-				port = ntohs(s->s_port);
-			} else {
-				if (p != NULL) {
-					freeaddrinfo(p);
-				}
-				return EAI_SERVICE;
-			}
+		s = getservbyname(service, proto);
+		if (s == NULL) {
+			return EAI_NONAME;
 		}
+		port = ntohs(s->s_port);
 	}
 
-	rc = 0;
-	if (hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET) {
-		rc = inet_pton(AF_INET, node, &addr.in.v4);
-	}
+valid_port:
+
+	rc = inet_pton(AF_INET, node, &addr.in.v4);
 	if (rc == 1) {
 		addr.family = AF_INET;
+	}
 #ifdef HAVE_IPV6
-	} else {
+	if (addr.family == AF_UNSPEC) {
 		rc = inet_pton(AF_INET6, node, &addr.in.v6);
 		if (rc == 1) {
 			addr.family = AF_INET6;
 		}
-#endif
 	}
-
-	if (addr.family == AF_INET) {
-		he = nwrap_files_gethostbyaddr(&addr.in.v4,
-					       sizeof(struct in_addr),
-					       addr.family);
-		if (he != NULL) {
-			rc = nwrap_convert_he_ai(he, port, hints, &ai);
-		} else {
-			eai = EAI_NODATA;
-			rc = -1;
-		}
-#ifdef HAVE_IPV6
-	} else if (addr.family == AF_INET6) {
-		he = nwrap_files_gethostbyaddr(&addr.in.v6,
-					       sizeof(struct in6_addr),
-					       addr.family);
-		if (he != NULL) {
-			rc = nwrap_convert_he_ai(he, port, hints, &ai);
-			eai = rc;
-		} else {
-			eai = EAI_NODATA;
-			rc = -1;
-		}
 #endif
-	} else {
-		he = nwrap_files_gethostbyname(node, hints->ai_family);
-		if (he != NULL) {
-			rc = nwrap_convert_he_ai(he, port, hints, &ai);
-			eai = rc;
-		} else {
-			eai = EAI_NODATA;
-			rc = -1;
+
+	if (addr.family == AF_UNSPEC) {
+	       if (hints->ai_flags & AI_NUMERICHOST) {
+			return EAI_NONAME;
 		}
+	} else if ((hints->ai_family != AF_UNSPEC) &&
+		   (hints->ai_family != addr.family))
+	{
+		return EAI_ADDRFAMILY;
 	}
 
-	if (rc < 0) {
-		return ret == 0 ? 0 : eai;
-	}
+	rc = nwrap_files_getaddrinfo(node, port, hints, &ai);
+	if (rc != 0) {
+		int ret;
+		struct addrinfo *p = NULL;
 
-	if (ret == 0) {
-		freeaddrinfo(p);
-	}
+		ret = libc_getaddrinfo(node, service, hints, &p);
 
-	if (ai->ai_flags == 0) {
-		ai->ai_flags = hints->ai_flags;
-	}
-	if (ai->ai_socktype == 0) {
-		ai->ai_socktype = SOCK_DGRAM;
-	}
-	if (ai->ai_protocol == 0 && ai->ai_socktype == SOCK_DGRAM) {
-		ai->ai_protocol = 17; /* UDP */
-	} else if (ai->ai_protocol == 0 && ai->ai_socktype == SOCK_STREAM) {
-		ai->ai_protocol = 6; /* TCP */
+		if (ret == 0) {
+			/*
+			 * nwrap_files_getaddrinfo failed, but libc was
+			 * successful -- use the result from libc.
+			 */
+			*res = p;
+			return 0;
+		}
+
+		return rc;
 	}
 
+	/*
+	 * If the socktype was not specified, duplicate
+	 * each ai returned, so that we have variants for
+	 * both UDP and TCP.
+	 */
 	if (hints->ai_socktype == 0) {
-		/* Add second ai */
-		rc = nwrap_convert_he_ai(he, port, hints, &ai->ai_next);
-		if (rc < 0) {
-			freeaddrinfo(ai);
-			return rc;
-		}
+		struct addrinfo *ai_cur;
 
-		if (ai->ai_next->ai_flags == 0) {
-			ai->ai_next->ai_flags = hints->ai_flags;
-		}
-		if (ai->ai_socktype == SOCK_DGRAM) {
-			ai->ai_next->ai_socktype = SOCK_STREAM;
-		} else if (ai->ai_socktype == SOCK_STREAM) {
-			ai->ai_next->ai_socktype = SOCK_DGRAM;
-		}
-		if (ai->ai_next->ai_socktype == SOCK_DGRAM) {
-			ai->ai_next->ai_protocol = 17; /* UDP */
-		} else if (ai->ai_next->ai_socktype == SOCK_STREAM) {
-			ai->ai_next->ai_protocol = 6; /* TCP */
+		/* freeaddrinfo() frees ai_canonname and ai so allocate them */
+		for (ai_cur = ai; ai_cur != NULL; ai_cur = ai_cur->ai_next) {
+			struct addrinfo *ai_new;
+
+			/* duplicate the current entry */
+
+			ai_new = malloc(sizeof(struct addrinfo));
+			if (ai_new == NULL) {
+				freeaddrinfo(ai);
+				return EAI_MEMORY;
+			}
+
+			memcpy(ai_new, ai_cur, sizeof(struct addrinfo));
+			ai_new->ai_next = NULL;
+
+			/* We need a deep copy or freeaddrinfo() will blow up */
+			if (ai_cur->ai_canonname != NULL) {
+				ai_new->ai_canonname =
+					strdup(ai_cur->ai_canonname);
+			}
+
+			if (ai_cur->ai_socktype == SOCK_DGRAM) {
+				ai_new->ai_socktype = SOCK_STREAM;
+			} else if (ai_cur->ai_socktype == SOCK_STREAM) {
+				ai_new->ai_socktype = SOCK_DGRAM;
+			}
+			if (ai_cur->ai_protocol == IPPROTO_TCP) {
+				ai_new->ai_protocol = IPPROTO_UDP;
+			} else if (ai_cur->ai_protocol == IPPROTO_UDP) {
+				ai_new->ai_protocol = IPPROTO_TCP;
+			}
+
+			/* now insert the new entry */
+
+			ai_new->ai_next = ai_cur->ai_next;
+			ai_cur->ai_next = ai_new;
+
+			/* and move on (don't duplicate the new entry) */
+
+			ai_cur = ai_new;
 		}
 	}
 
@@ -4173,6 +5511,7 @@ void nwrap_destructor(void)
 {
 	int i;
 
+	NWRAP_LOCK_ALL;
 	if (nwrap_main_global != NULL) {
 		struct nwrap_main *m = nwrap_main_global;
 
@@ -4206,7 +5545,8 @@ void nwrap_destructor(void)
 
 		nwrap_files_cache_unload(c);
 		if (c->fd >= 0) {
-			close(c->fd);
+			fclose(c->fp);
+			c->fd = -1;
 		}
 
 		SAFE_FREE(nwrap_pw_global.list);
@@ -4218,22 +5558,45 @@ void nwrap_destructor(void)
 
 		nwrap_files_cache_unload(c);
 		if (c->fd >= 0) {
-			close(c->fd);
+			fclose(c->fp);
+			c->fd = -1;
 		}
 
 		SAFE_FREE(nwrap_gr_global.list);
 		nwrap_pw_global.num = 0;
 	}
 
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+	if (nwrap_sp_global.cache != NULL) {
+		struct nwrap_cache *c = nwrap_sp_global.cache;
+
+		nwrap_files_cache_unload(c);
+		if (c->fd >= 0) {
+			fclose(c->fp);
+			c->fd = -1;
+		}
+
+		nwrap_sp_global.num = 0;
+	}
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
 	if (nwrap_he_global.cache != NULL) {
 		struct nwrap_cache *c = nwrap_he_global.cache;
 
 		nwrap_files_cache_unload(c);
 		if (c->fd >= 0) {
-			close(c->fd);
+			fclose(c->fp);
+			c->fd = -1;
 		}
 
-		SAFE_FREE(nwrap_he_global.list);
 		nwrap_he_global.num = 0;
 	}
+
+	free(user_addrlist.items);
+#ifdef HAVE_GETHOSTBYNAME2
+	free(user_addrlist2.items);
+#endif
+
+	hdestroy();
+	NWRAP_UNLOCK_ALL;
 }
diff --git a/lib/nss_wrapper/wscript b/lib/nss_wrapper/wscript
index b25b83d..6c3d7f7 100644
--- a/lib/nss_wrapper/wscript
+++ b/lib/nss_wrapper/wscript
@@ -2,7 +2,7 @@
 
 import os
 
-VERSION="1.0.3"
+VERSION="1.1.2"
 
 def configure(conf):
     if conf.CHECK_BUNDLED_SYSTEM('nss_wrapper', minversion=VERSION, set_target=False):
@@ -102,7 +102,6 @@ def build(bld):
         # breaks preloading!
         bld.SAMBA_LIBRARY('nss_wrapper',
                           source='nss_wrapper.c',
-                          cflags='-DNDEBUG',
                           deps='dl',
                           install=False,
                           realname='libnss-wrapper.so')
diff --git a/lib/param/README b/lib/param/README
index 6a53a45..d83fe9a 100644
--- a/lib/param/README
+++ b/lib/param/README
@@ -10,13 +10,23 @@ such as the configured shares, default parameter values and host secret keys.
 Adding a parameter
 ------------------
 
-To add or change an smb.conf option, you only have to modify
-lib/param/param_table.c and add the documentation to docs-xml/smbdotconf.
-If special defaults are needed, the functions loadparm_int() in
-lib/param/loadparm.c and/or init_globals() in source3/param/loadparm.c
-need to be adapted accordingly.
+To add or change an smb.conf option, in general you only have to add
+the documentation to docs-xml/smbdotconf, or change it.
+In addition to that, if special defaults are needed, the functions
+loadparm_init() in lib/param/loadparm.c and/or init_globals() in
+source3/param/loadparm.c need to be adapted accordingly.
 The rest is generated for you.
 
+It is important to get the attributes right in the <samba:parameter ...>
+tag of the xml files.  These determine the details of the generated code.
+
+- Supported attributes are name, context, type, constant, function,
+  generated_function, synonym, parm, enumlist, handler, and deprecated.
+- Supported contexts are 'G' (for global) and 'S' (for share).
+- Supported types are boolean, boolean-rev, boolean-auto, list,
+  cmdlist, string, ustring, char, integer, bytes, octal, and enum.
+
+
 
 Using smb.conf parameters in the code
 -------------------------------------
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index 7b75f13..9a3451f 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -68,6 +68,11 @@
 #include "libcli/smb/smb_constants.h"
 #include "tdb.h"
 #include "librpc/gen_ndr/nbt.h"
+#include "libds/common/roles.h"
+
+#ifdef HAVE_HTTPCONNECTENCRYPT
+#include <cups/http.h>
+#endif
 
 #define standard_sub_basic talloc_strdup
 
@@ -209,12 +214,14 @@ static struct loadparm_context *global_loadparm_context;
 
 #define FN_LOCAL_PARM_INTEGER(fn_name, val) FN_LOCAL_INTEGER(fn_name, val)
 
-#define FN_LOCAL_PARM_CHAR(fn_name,val) \
+#define FN_LOCAL_CHAR(fn_name,val) \
  _PUBLIC_ char lpcfg_ ## fn_name(struct loadparm_service *service, \
 				struct loadparm_service *sDefault) {	\
 	 return((service != NULL)? service->val : sDefault->val); \
  }
 
+#define FN_LOCAL_PARM_CHAR(fn_name,val) FN_LOCAL_CHAR(fn_name, val)
+
 #include "lib/param/param_functions.c"
 
 /* These functions cannot be auto-generated */
@@ -322,6 +329,20 @@ unsigned long lp_ulong(const char *s)
 }
 
 /**
+ * convenience routine to return unsigned long long parameters.
+ */
+unsigned long long lp_ulonglong(const char *s)
+{
+
+	if (!s || !*s) {
+		DEBUG(0, ("lp_ulonglong(%s): is called with NULL!\n", s));
+		return -1;
+	}
+
+	return strtoull(s, NULL, 0);
+}
+
+/**
  * convenience routine to return unsigned long parameters.
  */
 static long lp_long(const char *s)
@@ -466,6 +487,25 @@ unsigned long lpcfg_parm_ulong(struct loadparm_context *lp_ctx,
 	return default_v;
 }
 
+/**
+ * Return parametric option from a given service.
+ * Type is a part of option before ':'
+ * Parametric option has following syntax: 'Type: option = value'
+ */
+unsigned long long lpcfg_parm_ulonglong(struct loadparm_context *lp_ctx,
+					struct loadparm_service *service,
+					const char *type, const char *option,
+					unsigned long long default_v)
+{
+	const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+	if (value) {
+		return lp_ulonglong(value);
+	}
+
+	return default_v;
+}
+
 long lpcfg_parm_long(struct loadparm_context *lp_ctx,
 		     struct loadparm_service *service, const char *type,
 		     const char *option, long default_v)
@@ -671,7 +711,7 @@ bool lpcfg_add_home(struct loadparm_context *lp_ctx,
 	if (!(*(service->comment))) {
 		service->comment = talloc_asprintf(service, "Home directory of %s", user);
 	}
-	service->bAvailable = default_service->bAvailable;
+	service->available = default_service->available;
 	service->browseable = default_service->browseable;
 
 	DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n",
@@ -818,10 +858,8 @@ void set_param_opt(TALLOC_CTX *mem_ctx,
 		   unsigned priority)
 {
 	struct parmlist_entry *new_opt, *opt;
-	bool not_added;
 
 	opt = *opt_list;
-	not_added = true;
 
 	/* Traverse destination */
 	while (opt) {
@@ -836,25 +874,25 @@ void set_param_opt(TALLOC_CTX *mem_ctx,
 			TALLOC_FREE(opt->list);
 			lpcfg_string_set(opt, &opt->value, opt_value);
 			opt->priority = priority;
-			not_added = false;
-			break;
+			return;
 		}
 		opt = opt->next;
 	}
-	if (not_added) {
-		new_opt = talloc(mem_ctx, struct parmlist_entry);
-		if (new_opt == NULL) {
-			smb_panic("OOM");
-		}
-		new_opt->key = NULL;
-		lpcfg_string_set(new_opt, &new_opt->key, opt_name);
-		new_opt->value = NULL;
-		lpcfg_string_set(new_opt, &new_opt->value, opt_value);
 
-		new_opt->list = NULL;
-		new_opt->priority = priority;
-		DLIST_ADD(*opt_list, new_opt);
+	new_opt = talloc_pooled_object(
+		mem_ctx, struct parmlist_entry,
+		2, strlen(opt_name) + 1 + strlen(opt_value) + 1);
+	if (new_opt == NULL) {
+		smb_panic("OOM");
 	}
+	new_opt->key = NULL;
+	lpcfg_string_set(new_opt, &new_opt->key, opt_name);
+	new_opt->value = NULL;
+	lpcfg_string_set(new_opt, &new_opt->value, opt_value);
+
+	new_opt->list = NULL;
+	new_opt->priority = priority;
+	DLIST_ADD(*opt_list, new_opt);
 }
 
 /**
@@ -964,10 +1002,10 @@ bool lpcfg_service_ok(struct loadparm_service *service)
 	{
 		DEBUG(0, ("WARNING: No path in service %s - making it unavailable!\n",
 			service->szService));
-		service->bAvailable = false;
+		service->available = false;
 	}
 
-	if (!service->bAvailable)
+	if (!service->available)
 		DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
 			  service->szService));
 
@@ -1094,7 +1132,7 @@ bool handle_realm(struct loadparm_context *lp_ctx, struct loadparm_service *serv
 		return false;
 	}
 
-	lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
+	lpcfg_string_set(lp_ctx->globals->ctx, &lp_ctx->globals->realm_original, pszParmValue);
 	lpcfg_string_set(lp_ctx->globals->ctx, &lp_ctx->globals->realm, upper);
 	lpcfg_string_set(lp_ctx->globals->ctx, &lp_ctx->globals->dnsdomain, lower);
 
@@ -1109,6 +1147,8 @@ bool handle_include(struct loadparm_context *lp_ctx, struct loadparm_service *se
 			   const char *pszParmValue, char **ptr)
 {
 	char *fname;
+	const char *substitution_variable_substring;
+	char next_char;
 
 	if (lp_ctx->s3_fns) {
 		return lp_ctx->s3_fns->lp_include(lp_ctx, service, pszParmValue, ptr);
@@ -1123,6 +1163,22 @@ bool handle_include(struct loadparm_context *lp_ctx, struct loadparm_service *se
 	if (file_exist(fname))
 		return pm_process(fname, do_section, lpcfg_do_parameter, lp_ctx);
 
+       /*
+        * If the file doesn't exist, we check that it isn't due to variable
+        * substitution
+        */
+	substitution_variable_substring = strchr(fname, '%');
+
+	if (substitution_variable_substring != NULL) {
+		next_char = substitution_variable_substring[1];
+		if ((next_char >= 'a' && next_char <= 'z')
+		    || (next_char >= 'A' && next_char <= 'Z')) {
+			DEBUG(2, ("Tried to load %s but variable substitution in "
+				 "filename, ignoring file.\n", fname));
+			return true;
+		}
+	}
+
 	DEBUG(2, ("Can't find include file %s\n", fname));
 
 	return false;
@@ -1379,6 +1435,49 @@ bool handle_smb_ports(struct loadparm_context *lp_ctx, struct loadparm_service *
 	return true;
 }
 
+bool handle_smb2_max_credits(struct loadparm_context *lp_ctx,
+			     struct loadparm_service *service,
+			     const char *pszParmValue, char **ptr)
+{
+	int value = lp_int(pszParmValue);
+
+	if (value <= 0) {
+		value = DEFAULT_SMB2_MAX_CREDITS;
+	}
+
+	*(int *)ptr = value;
+
+	return true;
+}
+
+bool handle_cups_encrypt(struct loadparm_context *lp_ctx,
+			 struct loadparm_service *service,
+			 const char *pszParmValue, char **ptr)
+{
+	int result = 0;
+#ifdef HAVE_HTTPCONNECTENCRYPT
+	int value = lp_int(pszParmValue);
+
+	switch (value) {
+		case Auto:
+			result = HTTP_ENCRYPT_REQUIRED;
+			break;
+		case true:
+			result = HTTP_ENCRYPT_ALWAYS;
+			break;
+		case false:
+			result = HTTP_ENCRYPT_NEVER;
+			break;
+		default:
+			result = 0;
+			break;
+	}
+#endif
+	*(int *)ptr = result;
+
+	return true;
+}
+
 /***************************************************************************
  Initialise a copymap.
 ***************************************************************************/
@@ -1570,7 +1669,8 @@ static bool set_variable_helper(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr
 
 }
 
-bool set_variable(TALLOC_CTX *mem_ctx, struct loadparm_service *service, int parmnum, void *parm_ptr,
+static bool set_variable(TALLOC_CTX *mem_ctx, struct loadparm_service *service,
+			 int parmnum, void *parm_ptr,
 			 const char *pszParmName, const char *pszParmValue,
 			 struct loadparm_context *lp_ctx, bool on_globals)
 {
@@ -2401,8 +2501,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 	lp_ctx->sDefault = talloc_zero(lp_ctx, struct loadparm_service);
 	lp_ctx->flags = talloc_zero_array(lp_ctx, unsigned int, num_parameters());
 
-	lp_ctx->sDefault->iMaxPrintJobs = 1000;
-	lp_ctx->sDefault->bAvailable = true;
+	lp_ctx->sDefault->max_print_jobs = 1000;
+	lp_ctx->sDefault->available = true;
 	lp_ctx->sDefault->browseable = true;
 	lp_ctx->sDefault->read_only = true;
 	lp_ctx->sDefault->map_archive = true;
@@ -2677,7 +2777,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
 	lpcfg_do_global_parameter(lp_ctx, "allocation roundup size", "1048576");
 
-	lpcfg_do_global_parameter(lp_ctx, "ldap page size", "1024");
+	lpcfg_do_global_parameter(lp_ctx, "ldap page size", "1000");
 
 	lpcfg_do_global_parameter(lp_ctx, "kernel share modes", "yes");
 
@@ -2787,6 +2887,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
 	lpcfg_do_global_parameter(lp_ctx, "printjob username", "%U");
 
+	lpcfg_do_global_parameter(lp_ctx, "aio max threads", "100");
+
 	/* Allow modules to adjust defaults */
 	for (defaults_hook = defaults_hooks; defaults_hook;
 		 defaults_hook = defaults_hook->next) {
@@ -3121,7 +3223,8 @@ const char *lpcfg_printername(struct loadparm_service *service, struct loadparm_
  */
 int lpcfg_maxprintjobs(struct loadparm_service *service, struct loadparm_service *sDefault)
 {
-	int maxjobs = (service != NULL) ? service->iMaxPrintJobs : sDefault->iMaxPrintJobs;
+	int maxjobs = lpcfg_max_print_jobs(service, sDefault);
+
 	if (maxjobs <= 0 || maxjobs >= PRINT_MAX_JOBID)
 		maxjobs = PRINT_MAX_JOBID - 1;
 
diff --git a/lib/param/loadparm.h b/lib/param/loadparm.h
index c762259..b453aca 100644
--- a/lib/param/loadparm.h
+++ b/lib/param/loadparm.h
@@ -31,7 +31,18 @@
 #define _LOADPARM_H
 
 #include <talloc.h>
-#include "../lib/util/parmlist.h"
+
+struct parmlist_entry {
+	struct parmlist_entry *prev, *next;
+	char *key;
+	char *value;
+	char **list; /* For the source3 parametric options, to save the parsed list */
+	int priority;
+};
+
+struct parmlist {
+	struct parmlist_entry *entries;
+};
 
 /* the following are used by loadparm for option lists */
 typedef enum {
@@ -232,15 +243,9 @@ enum case_handling {CASE_LOWER,CASE_UPPER};
 #define DEFAULT_SMB2_MAX_CREDITS 8192
 
 #define LOADPARM_EXTRA_LOCALS						\
-	bool valid;						        \
 	int usershare;							\
 	struct timespec usershare_last_mod;				\
-	int iMaxPrintJobs;						\
-	char *szCopy;							\
 	char *szService;						\
-	char *szInclude;						\
-	bool bWidelinks;						\
-	bool bAvailable;							\
 	struct parmlist_entry *param_opt;				\
 	struct bitmap *copymap;						\
 	char dummy[3];		/* for alignment */
@@ -249,20 +254,8 @@ enum case_handling {CASE_LOWER,CASE_UPPER};
 
 #define LOADPARM_EXTRA_GLOBALS \
 	struct parmlist_entry *param_opt;				\
-	char *realm_original;						\
-	int iminreceivefile;						\
-	char *szPrintcapname;						\
-	int CupsEncrypt;						\
-	int  iPreferredMaster;						\
-	char *szLdapMachineSuffix;					\
-	char *szLdapUserSuffix;						\
-	char *szLdapIdmapSuffix;					\
-	char *szLdapGroupSuffix;					\
-	char *szIdmapUID;						\
-	char *szIdmapGID;						\
-	char *szIdmapBackend;						\
-	int winbindMaxDomainConnections;				\
-	int ismb2_max_credits;
+	char *dnsdomain;						\
+	char *realm_original;
 
 const char* server_role_str(uint32_t role);
 int lp_find_server_role(int server_role, int security, int domain_logons, int domain_master);
diff --git a/lib/param/param.h b/lib/param/param.h
index af321e1..fb28218 100644
--- a/lib/param/param.h
+++ b/lib/param/param.h
@@ -37,12 +37,8 @@ struct param_section {
 struct param_context;
 struct smbsrv_connection;
 
-typedef bool (*lpcfg_defaults_hook) (struct loadparm_context *);
-
 #define Auto (2)
 
-#include "libds/common/roles.h"
-
 struct loadparm_context;
 struct loadparm_service;
 struct smbcli_options;
@@ -51,6 +47,8 @@ struct gensec_settings;
 struct bitmap;
 struct file_lists;
 
+typedef bool (*lpcfg_defaults_hook) (struct loadparm_context *);
+
 #ifdef CONFIG_H_IS_FROM_SAMBA
 #include "lib/param/param_proto.h"
 #include "lib/param/param_functions.h"
@@ -100,6 +98,10 @@ int lpcfg_parm_bytes(struct loadparm_context *lp_ctx,
 unsigned long lpcfg_parm_ulong(struct loadparm_context *lp_ctx,
 			    struct loadparm_service *service, const char *type,
 			    const char *option, unsigned long default_v);
+unsigned long long lpcfg_parm_ulonglong(struct loadparm_context *lp_ctx,
+					struct loadparm_service *service,
+					const char *type, const char *option,
+					unsigned long long default_v);
 long lpcfg_parm_long(struct loadparm_context *lp_ctx,
 		     struct loadparm_service *service, const char *type,
 		     const char *option, long default_v);
diff --git a/lib/param/param_table.c b/lib/param/param_table.c
index 3a0247c..1ebb2f8 100644
--- a/lib/param/param_table.c
+++ b/lib/param/param_table.c
@@ -32,6 +32,7 @@
 #include "lib/param/loadparm.h"
 #include "lib/param/param_global.h"
 #include "libcli/smb/smb_constants.h"
+#include "libds/common/roles.h"
 
 #ifndef N_
 #define N_(x) x
@@ -282,3732 +283,7 @@ static const struct enum_list enum_case[] = {
 #define GLOBAL_VAR(name) offsetof(struct loadparm_global, name)
 #define LOCAL_VAR(name) offsetof(struct loadparm_service, name)
 
-
-struct parm_struct parm_table[] = {
-	{
-		.label		= "dos charset",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(dos_charset),
-		.special	= handle_dos_charset,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "unix charset",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(unix_charset),
-		.special	= handle_charset,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "comment",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(comment),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "path",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(path),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "directory",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(path),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "workgroup",
-		.type		= P_USTRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(workgroup),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "realm",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(realm_original),
-		.special	= handle_realm,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "netbios name",
-		.type		= P_USTRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(netbios_name),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "netbios aliases",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(netbios_aliases),
-		.special	= handle_netbios_aliases,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "netbios scope",
-		.type		= P_USTRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(netbios_scope),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "server string",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(server_string),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "interfaces",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(interfaces),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "bind interfaces only",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(bind_interfaces_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "config backend",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(config_backend),
-		.special	= NULL,
-		.enum_list	= enum_config_backend,
-	},
-	{
-		.label		= "server role",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_server_role),
-		.special	= NULL,
-		.enum_list	= enum_server_role,
-	},
-	{
-		.label		= "security",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_security),
-		.special	= NULL,
-		.enum_list	= enum_security,
-	},
-	{
-		.label		= "auth methods",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(auth_methods),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "encrypt passwords",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(encrypt_passwords),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "client schannel",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(client_schannel),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-	},
-	{
-		.label		= "server schannel",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(server_schannel),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-	},
-	{
-		.label		= "allow trusted domains",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(allow_trusted_domains),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "map to guest",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(map_to_guest),
-		.special	= NULL,
-		.enum_list	= enum_map_to_guest,
-	},
-	{
-		.label		= "null passwords",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(null_passwords),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "old password allowed period",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(old_password_allowed_period),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "obey pam restrictions",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(obey_pam_restrictions),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "password server",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(password_server),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "smb passwd file",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(smb_passwd_file),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "private dir",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(private_dir),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "private directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(private_dir),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "passdb backend",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(passdb_backend),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "algorithmic rid base",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(algorithmic_rid_base),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "root directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(root_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "root dir",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(root_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "root",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(root_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "guest account",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(guest_account),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "enable privileges",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(enable_privileges),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-
-	{
-		.label		= "pam password change",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(pam_password_change),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "passwd program",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(passwd_program),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "passwd chat",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(passwd_chat),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "passwd chat debug",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(passwd_chat_debug),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "passwd chat timeout",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(passwd_chat_timeout),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "check password script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(check_password_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "username map",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(username_map),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "username level",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(username_level),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "unix password sync",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(unix_password_sync),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "restrict anonymous",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(restrict_anonymous),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "lanman auth",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(lanman_auth),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ntlm auth",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ntlm_auth),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "client NTLMv2 auth",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(client_ntlmv2_auth),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "client lanman auth",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(client_lanman_auth),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "client plaintext auth",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(client_plaintext_auth),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "client use spnego principal",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(client_use_spnego_principal),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "username",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(username),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "user",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(username),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "users",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(username),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "invalid users",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(invalid_users),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "valid users",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(valid_users),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "admin users",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(admin_users),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "read list",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(read_list),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "write list",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(write_list),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "force user",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(force_user),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "force group",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(force_group),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "group",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(force_group),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "read only",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(read_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "spotlight",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(spotlight),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "write ok",
-		.type		= P_BOOLREV,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(read_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "writeable",
-		.type		= P_BOOLREV,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(read_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "writable",
-		.type		= P_BOOLREV,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(read_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "acl check permissions",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(acl_check_permissions),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "acl group control",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(acl_group_control),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "acl map full control",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(acl_map_full_control),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "acl allow execute always",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(acl_allow_execute_always),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-
-	{
-		.label		= "create mask",
-		.type		= P_OCTAL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(create_mask),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "create mode",
-		.type		= P_OCTAL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(create_mask),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "force create mode",
-		.type		= P_OCTAL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(force_create_mode),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "directory mask",
-		.type		= P_OCTAL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(directory_mask),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "directory mode",
-		.type		= P_OCTAL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(directory_mask),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "force directory mode",
-		.type		= P_OCTAL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(force_directory_mode),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "force unknown acl user",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(force_unknown_acl_user),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "inherit permissions",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(inherit_permissions),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "inherit acls",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(inherit_acls),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "inherit owner",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(inherit_owner),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "guest only",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(guest_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "only guest",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(guest_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "administrative share",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(administrative_share),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-
-	{
-		.label		= "guest ok",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(guest_ok),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "public",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(guest_ok),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "only user",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(only_user),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "hosts allow",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(hosts_allow),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "allow hosts",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(hosts_allow),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "hosts deny",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(hosts_deny),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "deny hosts",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(hosts_deny),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "preload modules",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(preload_modules),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dedicated keytab file",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(dedicated_keytab_file),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "kerberos method",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(kerberos_method),
-		.special	= NULL,
-		.enum_list	= enum_kerberos_method,
-	},
-	{
-		.label		= "map untrusted to domain",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(map_untrusted_to_domain),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "log level",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(log_level),
-		.special	= handle_debug_list,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "debuglevel",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(log_level),
-		.special	= handle_debug_list,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "syslog",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(syslog),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "syslog only",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(syslog_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "log file",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(logfile),
-		.special	= handle_logfile,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "logging",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(logging),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max log size",
-		.type		= P_BYTES,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(max_log_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "debug timestamp",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(timestamp_logs),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "timestamp logs",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(timestamp_logs),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "debug prefix timestamp",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(debug_prefix_timestamp),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "debug hires timestamp",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(debug_hires_timestamp),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "debug pid",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(debug_pid),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "debug uid",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(debug_uid),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "debug class",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(debug_class),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "enable core files",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(enable_core_files),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "allocation roundup size",
-		.type		= P_BYTES,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(allocation_roundup_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "aio read size",
-		.type		= P_BYTES,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(aio_read_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "aio write size",
-		.type		= P_BYTES,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(aio_write_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "aio write behind",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(aio_write_behind),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "smb ports",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(smb_ports),
-		.special	= handle_smb_ports,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "large readwrite",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(large_readwrite),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "server max protocol",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(server_max_protocol),
-		.special	= NULL,
-		.enum_list	= enum_protocol,
-	},
-	{
-		.label		= "max protocol",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(server_max_protocol),
-		.special	= NULL,
-		.enum_list	= enum_protocol,
-	},
-	{
-		.label		= "protocol",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(server_max_protocol),
-		.special	= NULL,
-		.enum_list	= enum_protocol,
-	},
-	{
-		.label		= "server min protocol",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(server_min_protocol),
-		.special	= NULL,
-		.enum_list	= enum_protocol,
-	},
-	{
-		.label		= "min protocol",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(server_min_protocol),
-		.special	= NULL,
-		.enum_list	= enum_protocol,
-	},
-	{
-		.label		= "client max protocol",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_client_max_protocol),
-		.special	= NULL,
-		.enum_list	= enum_protocol,
-	},
-	{
-		.label		= "client min protocol",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(client_min_protocol),
-		.special	= NULL,
-		.enum_list	= enum_protocol,
-	},
-	{
-		.label		= "unicode",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(unicode),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "min receivefile size",
-		.type		= P_BYTES,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(iminreceivefile),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "read raw",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(read_raw),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "write raw",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(write_raw),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "disable netbios",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(disable_netbios),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "reset on zero vc",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(reset_on_zero_vc),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "log writeable files on exit",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(log_writeable_files_on_exit),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "defer sharing violations",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(defer_sharing_violations),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ea support",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(ea_support),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "nt acl support",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(nt_acl_support),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "nt pipe support",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(nt_pipe_support),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "nt status support",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(nt_status_support),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "smbd profiling level",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(smbd_profiling_level),
-		.special	= NULL,
-		.enum_list	= enum_smbd_profiling_level,
-	},
-	{
-		.label		= "profile acls",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(profile_acls),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "map acl inherit",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(map_acl_inherit),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "afs share",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(afs_share),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max mux",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(max_mux),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max xmit",
-		.type		= P_BYTES,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(max_xmit),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "name resolve order",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(name_resolve_order),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max ttl",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(max_ttl),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max wins ttl",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(max_wins_ttl),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "min wins ttl",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(min_wins_ttl),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "time server",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(time_server),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "unix extensions",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(unix_extensions),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "use spnego",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(use_spnego),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "client signing",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(client_signing),
-		.special	= NULL,
-		.enum_list	= enum_smb_signing_vals,
-	},
-	{
-		.label		= "server signing",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(server_signing),
-		.special	= NULL,
-		.enum_list	= enum_smb_signing_vals,
-	},
-	{
-		.label		= "smb encrypt",
-		.type		= P_ENUM,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(smb_encrypt),
-		.special	= NULL,
-		.enum_list	= enum_smb_signing_vals,
-	},
-	{
-		.label		= "client use spnego",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(client_use_spnego),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "client ldap sasl wrapping",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(client_ldap_sasl_wrapping),
-		.special	= NULL,
-		.enum_list	= enum_ldap_sasl_wrapping,
-	},
-	{
-		.label		= "enable asu support",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(enable_asu_support),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "svcctl list",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(svcctl_list),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "cldap port",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(cldap_port),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "dgram port",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(dgram_port),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags          = FLAG_DEPRECATED
-	},
-	{
-		.label		= "nbt port",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(nbt_port),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags          = FLAG_DEPRECATED
-	},
-	{
-		.label		= "krb5 port",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(krb5_port),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "kpasswd port",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(kpasswd_port),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "web port",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(web_port),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "rpc big endian",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(rpc_big_endian),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "durable handles",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(durable_handles),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "block size",
-		.type		= P_BYTES,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(block_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "deadtime",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(deadtime),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "getwd cache",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(getwd_cache),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "keepalive",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(keepalive),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "change notify",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(change_notify),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "directory name cache size",
-		.type		= P_INTEGER,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(directory_name_cache_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "kernel change notify",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(kernel_change_notify),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "lpq cache time",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(lpq_cache_time),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max smbd processes",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(max_smbd_processes),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max connections",
-		.type		= P_INTEGER,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(max_connections),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max disk size",
-		.type		= P_BYTES,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(max_disk_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max open files",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(max_open_files),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "min print space",
-		.type		= P_INTEGER,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(min_print_space),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "socket options",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(socket_options),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "strict allocate",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(strict_allocate),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "strict rename",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(strict_rename),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "strict sync",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(strict_sync),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "sync always",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(sync_always),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "use mmap",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(use_mmap),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "use sendfile",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(_use_sendfile),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "hostname lookups",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(hostname_lookups),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "write cache size",
-		.type		= P_BYTES,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(write_cache_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "name cache timeout",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(name_cache_timeout),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ctdbd socket",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_ctdbd_socket),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "cluster addresses",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(cluster_addresses),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "clustering",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(clustering),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ctdb timeout",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ctdb_timeout),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ctdb locktime warn threshold",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ctdb_locktime_warn_threshold),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "smb2 max read",
-		.type		= P_BYTES,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(smb2_max_read),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "smb2 max write",
-		.type		= P_BYTES,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(smb2_max_write),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "smb2 max trans",
-		.type		= P_BYTES,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(smb2_max_trans),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "smb2 max credits",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ismb2_max_credits),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max reported print jobs",
-		.type		= P_INTEGER,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(max_reported_print_jobs),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max print jobs",
-		.type		= P_INTEGER,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(iMaxPrintJobs),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "load printers",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(load_printers),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "printcap cache time",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(printcap_cache_time),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "printcap name",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szPrintcapname),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "printcap",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szPrintcapname),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "printable",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(printable),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "print notify backchannel",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(print_notify_backchannel),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "print ok",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(printable),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "printing",
-		.type		= P_ENUM,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(printing),
-		.special	= handle_printing,
-		.enum_list	= enum_printing,
-	},
-	{
-		.label		= "cups options",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(cups_options),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "cups server",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(cups_server),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label          = "cups encrypt",
-		.type           = P_ENUM,
-		.p_class        = P_GLOBAL,
-		.offset         = GLOBAL_VAR(CupsEncrypt),
-		.special        = NULL,
-		.enum_list      = enum_bool_auto,
-	},
-	{
-
-		.label		= "cups connection timeout",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(cups_connection_timeout),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "iprint server",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(iprint_server),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "print command",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(print_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "disable spoolss",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_disable_spoolss),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "enable spoolss",
-		.type		= P_BOOLREV,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_disable_spoolss),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "lpq command",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(lpq_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "lprm command",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(lprm_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "lppause command",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(lppause_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "lpresume command",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(lpresume_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "queuepause command",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(queuepause_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "queueresume command",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(queueresume_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "addport command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(addport_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "enumports command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(enumports_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "addprinter command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(addprinter_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "deleteprinter command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(deleteprinter_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "show add printer wizard",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(show_add_printer_wizard),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "os2 driver map",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(os2_driver_map),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-
-	{
-		.label		= "printer name",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(_printername),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "printer",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(_printername),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "use client driver",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(use_client_driver),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "default devmode",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(default_devmode),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "force printername",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(force_printername),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "printjob username",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(printjob_username),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "mangling method",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(mangling_method),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "mangle prefix",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(mangle_prefix),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-
-	{
-		.label		= "default case",
-		.type		= P_ENUM,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(default_case),
-		.special	= NULL,
-		.enum_list	= enum_case,
-	},
-	{
-		.label		= "case sensitive",
-		.type		= P_ENUM,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(case_sensitive),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-	},
-	{
-		.label		= "casesignames",
-		.type		= P_ENUM,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(case_sensitive),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "preserve case",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(preserve_case),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "short preserve case",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(short_preserve_case),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "mangling char",
-		.type		= P_CHAR,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(mangling_char),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "hide dot files",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(hide_dot_files),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "hide special files",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(hide_special_files),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "hide unreadable",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(hide_unreadable),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "hide unwriteable files",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(hide_unwriteable_files),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "delete veto files",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(delete_veto_files),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "veto files",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(veto_files),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "hide files",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(hide_files),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "veto oplock files",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(veto_oplock_files),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "map archive",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(map_archive),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "map hidden",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(map_hidden),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "map system",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(map_system),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "map readonly",
-		.type		= P_ENUM,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(map_readonly),
-		.special	= NULL,
-		.enum_list	= enum_map_readonly,
-	},
-	{
-		.label		= "mangled names",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(mangled_names),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "max stat cache size",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(max_stat_cache_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "stat cache",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(stat_cache),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "store dos attributes",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(store_dos_attributes),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dmapi support",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(dmapi_support),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "machine password timeout",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(machine_password_timeout),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "add user script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(add_user_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "rename user script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(rename_user_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "delete user script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(delete_user_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "add group script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(add_group_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "delete group script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(delete_group_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "add user to group script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(add_user_to_group_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "delete user from group script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(delete_user_from_group_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "set primary group script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(set_primary_group_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "add machine script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(add_machine_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "shutdown script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(shutdown_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "abort shutdown script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(abort_shutdown_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "username map script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(username_map_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "username map cache time",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(username_map_cache_time),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "logon script",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(logon_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "logon path",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(logon_path),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "logon drive",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(logon_drive),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "logon home",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(logon_home),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "domain logons",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_domain_logons),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-
-	{
-		.label		= "init logon delayed hosts",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(init_logon_delayed_hosts),
-		.special        = NULL,
-		.enum_list	= NULL,
-	},
-
-	{
-		.label		= "init logon delay",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(init_logon_delay),
-		.special        = NULL,
-		.enum_list	= NULL,
-
-	},
-	{
-		.label		= "os level",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(os_level),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "lm announce",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(lm_announce),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-	},
-	{
-		.label		= "lm interval",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(lm_interval),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "preferred master",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(iPreferredMaster),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-	},
-	{
-		.label		= "prefered master",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(iPreferredMaster),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "local master",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(local_master),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "domain master",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_domain_master),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-	},
-	{
-		.label		= "browse list",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(browse_list),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "browseable",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(browseable),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "browsable",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(browseable),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "access based share enum",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(access_based_share_enum),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "enhanced browsing",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(enhanced_browsing),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dns proxy",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(wins_dns_proxy),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "wins proxy",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(wins_proxy),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "wins server",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(wins_server_list),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "wins support",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(we_are_a_wins_server),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "wins hook",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(wins_hook),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "blocking locks",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(blocking_locks),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "csc policy",
-		.type		= P_ENUM,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(csc_policy),
-		.special	= NULL,
-		.enum_list	= enum_csc_policy,
-	},
-	{
-		.label		= "fake oplocks",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(fake_oplocks),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "kernel oplocks",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(kernel_oplocks),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "kernel share modes",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(kernel_share_modes),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "smb2 leases",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(smb2_leases),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "locking",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(locking),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "lock spin time",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(lock_spin_time),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "oplocks",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(oplocks),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "level2 oplocks",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(level2_oplocks),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "oplock break wait time",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(oplock_break_wait_time),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "oplock contention limit",
-		.type		= P_INTEGER,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(oplock_contention_limit),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "posix locking",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(posix_locking),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "strict locking",
-		.type		= P_ENUM,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(strict_locking),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-	},
-	{
-		.label		= "ldap admin dn",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_admin_dn),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap delete dn",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_delete_dn),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap group suffix",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szLdapGroupSuffix),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap idmap suffix",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szLdapIdmapSuffix),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap machine suffix",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szLdapMachineSuffix),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap passwd sync",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_passwd_sync),
-		.special	= NULL,
-		.enum_list	= enum_ldap_passwd_sync,
-	},
-	{
-		.label		= "ldap password sync",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_passwd_sync),
-		.special	= NULL,
-		.enum_list	= enum_ldap_passwd_sync,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "ldap replication sleep",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_replication_sleep),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap suffix",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_suffix),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap ssl",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_ssl),
-		.special	= NULL,
-		.enum_list	= enum_ldap_ssl,
-	},
-	{
-		.label		= "ldap ssl ads",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_ssl_ads),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap deref",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_deref),
-		.special	= NULL,
-		.enum_list	= enum_ldap_deref,
-	},
-	{
-		.label		= "ldap follow referral",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_follow_referral),
-		.special	= NULL,
-		.enum_list	= enum_bool_auto,
-	},
-	{
-		.label		= "ldap timeout",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_timeout),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap connection timeout",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_connection_timeout),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap page size",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_page_size),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap user suffix",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szLdapUserSuffix),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap debug level",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_debug_level),
-		.special	= handle_ldap_debug_level,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ldap debug threshold",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ldap_debug_threshold),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "eventlog list",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(eventlog_list),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "add share command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(add_share_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "change share command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(change_share_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "delete share command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(delete_share_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "config file",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(next_configfile),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "preload",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(auto_services),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "auto services",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(auto_services),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "lock directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(lock_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "lock dir",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(lock_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "state directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(state_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "cache directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(cache_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "pid directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(pid_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ntp signd socket directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ntp_signd_socket_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-
-#ifdef WITH_UTMP
-	{
-		.label		= "utmp directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(utmp_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "wtmp directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(wtmp_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "utmp",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(utmp),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-#endif
-	{
-		.label		= "default service",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(defaultservice),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "default",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(defaultservice),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "message command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(message_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dfree cache time",
-		.type		= P_INTEGER,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(dfree_cache_time),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dfree command",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(dfree_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "get quota command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(get_quota_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "set quota command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(set_quota_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "remote announce",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(remote_announce),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "remote browse sync",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(remote_browse_sync),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "nbt client socket address",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(nbt_client_socket_address),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "socket address",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(nbt_client_socket_address),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "nmbd bind explicit broadcast",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(nmbd_bind_explicit_broadcast),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "homedir map",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(homedir_map),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "afs username map",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(afs_username_map),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "afs token lifetime",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(afs_token_lifetime),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "log nt token command",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(log_nt_token_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "NIS homedir",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(nis_homedir),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "-valid",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(valid),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "copy",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(szCopy),
-		.special	= handle_copy,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "include",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(szInclude),
-		.special	= handle_include,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "preexec",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(preexec),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "exec",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(preexec),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "preexec close",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(preexec_close),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "postexec",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(postexec),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "root preexec",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(root_preexec),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "root preexec close",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(root_preexec_close),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "root postexec",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(root_postexec),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "available",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(bAvailable),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "registry shares",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(registry_shares),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "usershare allow guests",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(usershare_allow_guests),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "usershare max shares",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(usershare_max_shares),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "usershare owner only",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(usershare_owner_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "usershare path",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(usershare_path),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "usershare prefix allow list",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(usershare_prefix_allow_list),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "usershare prefix deny list",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(usershare_prefix_deny_list),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "usershare template share",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(usershare_template_share),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "volume",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(volume),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "fstype",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(fstype),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "allow insecure wide links",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(allow_insecure_wide_links),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "wide links",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(bWidelinks),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "follow symlinks",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(follow_symlinks),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dont descend",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(dont_descend),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "magic script",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(magic_script),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "magic output",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(magic_output),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "delete readonly",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(delete_readonly),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dos filemode",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(dos_filemode),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dos filetimes",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(dos_filetimes),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dos filetime resolution",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(dos_filetime_resolution),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "fake directory create times",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(fake_directory_create_times),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "async smb echo handler",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(async_smb_echo_handler),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "panic action",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(panic_action),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "perfcount module",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(perfcount_module),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "vfs objects",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(vfs_objects),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "vfs object",
-		.type		= P_CMDLIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(vfs_objects),
-		.special	= NULL,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "msdfs root",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(msdfs_root),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "msdfs proxy",
-		.type		= P_STRING,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(msdfs_proxy),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "msdfs shuffle referrals",
-		.type		= P_BOOL,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(msdfs_shuffle_referrals),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "host msdfs",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(host_msdfs),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "passdb expand explicit",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(passdb_expand_explicit),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "idmap backend",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szIdmapBackend),
-		.special	= handle_idmap_backend,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "idmap cache time",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(idmap_cache_time),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "idmap negative cache time",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(idmap_negative_cache_time),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "idmap uid",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szIdmapUID),
-		.special	= handle_idmap_uid,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "winbind uid",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szIdmapUID),
-		.special	= handle_idmap_uid,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "idmap gid",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szIdmapGID),
-		.special	= handle_idmap_gid,
-		.enum_list	= NULL,
-		.flags		= FLAG_DEPRECATED,
-	},
-	{
-		.label		= "winbind gid",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(szIdmapGID),
-		.special	= handle_idmap_gid,
-		.enum_list	= NULL,
-		.flags		= FLAG_SYNONYM,
-	},
-	{
-		.label		= "template homedir",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(template_homedir),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "template shell",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(template_shell),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind separator",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_separator),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind cache time",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_cache_time),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind reconnect delay",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_reconnect_delay),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind request timeout",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_request_timeout),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind max clients",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_max_clients),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind enum users",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_enum_users),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind enum groups",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_enum_groups),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind use default domain",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_use_default_domain),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind trusted domains only",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_trusted_domains_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind nested groups",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_nested_groups),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind expand groups",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_expand_groups),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind nss info",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_nss_info),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind refresh tickets",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_refresh_tickets),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind offline logon",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_offline_logon),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind normalize names",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_normalize_names),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind rpc only",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_rpc_only),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "create krb5 conf",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(create_krb5_conf),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "ncalrpc dir",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(ncalrpc_dir),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind max domain connections",
-		.type		= P_INTEGER,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbindMaxDomainConnections),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbindd socket directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbindd_socket_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbindd privileged socket directory",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbindd_privileged_socket_directory),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "winbind sealed pipes",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(winbind_sealed_pipes),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "neutralize nt4 emulation",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(neutralize_nt4_emulation),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "reject md5 servers",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(reject_md5_servers),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "require strong key",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(require_strong_key),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "allow dns updates",
-		.type		= P_ENUM,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(allow_dns_updates),
-		.special	= NULL,
-		.enum_list	= enum_dns_update_settings,
-	},
-	{
-		.label		= "dns forwarder",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(dns_forwarder),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "dns update command",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(dns_update_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "nsupdate command",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(nsupdate_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "rndc command",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(rndc_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "multicast dns register",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(multicast_dns_register),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "samba kcc command",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(samba_kcc_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "server services",
-		.type		= P_LIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(server_services),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "dcerpc endpoint servers",
-		.type		= P_LIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(dcerpc_endpoint_servers),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "spn update command",
-		.type		= P_CMDLIST,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(spn_update_command),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "share backend",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(share_backend),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "ntvfs handler",
-		.type		= P_LIST,
-		.p_class	= P_LOCAL,
-		.offset		= LOCAL_VAR(ntvfs_handler),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "allow nt4 crypto",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(allow_nt4_crypto),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "reject md5 clients",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(reject_md5_clients),
-		.special	= NULL,
-		.enum_list	= NULL,
-	},
-	{
-		.label		= "tls enabled",
-		.type		= P_BOOL,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(tls_enabled),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "tls keyfile",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_tls_keyfile),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "tls certfile",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_tls_certfile),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "tls cafile",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_tls_cafile),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "tls crlfile",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_tls_crlfile),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "tls dh params file",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(_tls_dhpfile),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-	{
-		.label		= "tls priority",
-		.type		= P_STRING,
-		.p_class	= P_GLOBAL,
-		.offset		= GLOBAL_VAR(tls_priority),
-		.special	= NULL,
-		.enum_list	= NULL
-	},
-
-	{NULL,  P_BOOL,  P_NONE,  0,  NULL,  NULL,  0}
-};
+#include "lib/param/param_table_gen.c"
 
 int num_parameters(void)
 {
diff --git a/lib/param/util.c b/lib/param/util.c
index 7e4232d..bf9e0b8 100644
--- a/lib/param/util.c
+++ b/lib/param/util.c
@@ -28,6 +28,7 @@
 #include "system/filesys.h"
 #include "system/dir.h"
 #include "param/param.h"
+#include "libds/common/roles.h"
 
 /**
  * @file
diff --git a/lib/param/wscript_build b/lib/param/wscript_build
index 66003e9..c7fe577 100644
--- a/lib/param/wscript_build
+++ b/lib/param/wscript_build
@@ -24,6 +24,12 @@ bld.SAMBA_GENERATOR('param_global.h',
                     group='build_source',
                     rule='${PYTHON} ${SRC[0].abspath(env)} --file ${SRC[1].abspath(env)} --output ${TGT} --mode=PARAMDEFS --scope=GLOBAL')
 
+bld.SAMBA_GENERATOR('param_table_gen.c',
+                    source='../../script/generate_param.py ../../docs-xml/smbdotconf/parameters.all.xml',
+                    target='param_table_gen.c',
+                    group='build_source',
+                    rule='${PYTHON} ${SRC[0].abspath(env)} --file ${SRC[1].abspath(env)} --output ${TGT} --mode=PARAMTABLE')
+
 bld.SAMBA_LIBRARY('server-role',
                   source='loadparm_server_role.c',
                   deps='samba-util',
diff --git a/lib/replace/replace.c b/lib/replace/replace.c
index 798990a..b5d7f11 100644
--- a/lib/replace/replace.c
+++ b/lib/replace/replace.c
@@ -541,6 +541,7 @@ long long int rep_strtoll(const char *str, char **endptr, int base)
 #undef strtoll
 long long int rep_strtoll(const char *str, char **endptr, int base)
 {
+	int saved_errno = errno;
 	long long int nb = strtoll(str, endptr, base);
 	/* With glibc EINVAL is only returned if base is not ok */
 	if (errno == EINVAL) {
@@ -549,7 +550,7 @@ long long int rep_strtoll(const char *str, char **endptr, int base)
 			 * able to make the convertion.
 			 * Let's reset errno.
 			 */
-			errno = 0;
+			errno = saved_errno;
 		}
 	}
 	return nb;
@@ -573,25 +574,23 @@ unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
 }
 #else
 #ifdef HAVE_BSD_STRTOLL
-#ifdef HAVE_STRTOUQ
+#undef strtoull
 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
 {
-	unsigned long long int nb = strtouq(str, endptr, base);
-	/* In linux EINVAL is only returned if base is not ok */
+	int saved_errno = errno;
+	unsigned long long int nb = strtoull(str, endptr, base);
+	/* With glibc EINVAL is only returned if base is not ok */
 	if (errno == EINVAL) {
 		if (base == 0 || (base >1 && base <37)) {
 			/* Base was ok so it's because we were not
 			 * able to make the convertion.
 			 * Let's reset errno.
 			 */
-			errno = 0;
+			errno = saved_errno;
 		}
 	}
 	return nb;
 }
-#else
-#error "You need the strtouq function"
-#endif /* HAVE_STRTOUQ */
 #endif /* HAVE_BSD_STRTOLL */
 #endif /* HAVE_STRTOULL */
 
@@ -829,7 +828,7 @@ int rep_clock_gettime(clockid_t clk_id, struct timespec *tp)
 	struct timeval tval;
 	switch (clk_id) {
 		case 0: /* CLOCK_REALTIME :*/
-#ifdef HAVE_GETTIMEOFDAY_TZ
+#if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
 			gettimeofday(&tval,NULL);
 #else
 			gettimeofday(&tval);
diff --git a/lib/replace/wscript b/lib/replace/wscript
index 30eede2..37cbbb7 100644
--- a/lib/replace/wscript
+++ b/lib/replace/wscript
@@ -14,7 +14,7 @@ while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5:
 sys.path.insert(0, srcdir + '/buildtools/wafsamba')
 
 import wafsamba, samba_dist
-import Options
+import Options, Utils
 
 samba_dist.DIST_DIRS('lib/replace buildtools:buildtools third_party/waf:third_party/waf')
 
@@ -23,7 +23,7 @@ def set_options(opt):
     opt.PRIVATE_EXTENSION_DEFAULT('')
     opt.RECURSE('buildtools/wafsamba')
 
- at wafsamba.runonce
+ at Utils.run_once
 def configure(conf):
     conf.RECURSE('buildtools/wafsamba')
 
@@ -43,7 +43,12 @@ def configure(conf):
     conf.CHECK_HEADERS('sys/id.h sys/ioctl.h sys/ipc.h sys/mman.h sys/mode.h sys/ndir.h sys/priv.h')
     conf.CHECK_HEADERS('sys/resource.h sys/security.h sys/shm.h sys/statfs.h sys/statvfs.h sys/termio.h')
     conf.CHECK_HEADERS('sys/vfs.h sys/xattr.h termio.h termios.h sys/file.h')
-    conf.CHECK_HEADERS('sys/ucontext.h sys/wait.h sys/stat.h malloc.h grp.h')
+    conf.CHECK_HEADERS('sys/ucontext.h sys/wait.h sys/stat.h')
+
+    if not conf.CHECK_DECLS('malloc', headers='stdlib.h'):
+        conf.CHECK_HEADERS('malloc.h')
+
+    conf.CHECK_HEADERS('grp.h')
     conf.CHECK_HEADERS('sys/select.h setjmp.h utime.h sys/syslog.h syslog.h')
     conf.CHECK_HEADERS('stdarg.h vararg.h sys/mount.h mntent.h')
     conf.CHECK_HEADERS('stropts.h unix.h string.h strings.h sys/param.h limits.h')
@@ -71,7 +76,7 @@ def configure(conf):
     conf.CHECK_HEADERS('valgrind.h valgrind/valgrind.h valgrind/memcheck.h')
     conf.CHECK_HEADERS('nss_common.h nsswitch.h ns_api.h')
     conf.CHECK_HEADERS('sys/extattr.h sys/ea.h sys/proplist.h sys/cdefs.h')
-    conf.CHECK_HEADERS('utmp.h utmpx.h lastlog.h malloc.h')
+    conf.CHECK_HEADERS('utmp.h utmpx.h lastlog.h')
     conf.CHECK_HEADERS('syscall.h sys/syscall.h inttypes.h')
     conf.CHECK_HEADERS('sys/atomic.h')
     conf.CHECK_HEADERS('libgen.h')
@@ -245,6 +250,10 @@ def configure(conf):
     conf.CHECK_FUNCS('link readlink symlink realpath snprintf vsnprintf')
     conf.CHECK_FUNCS('asprintf vasprintf setenv unsetenv strnlen strtoull __strtoull')
     conf.CHECK_FUNCS('strtouq strtoll __strtoll strtoq memalign posix_memalign')
+
+    if conf.CONFIG_SET('HAVE_MEMALIGN'):
+        conf.CHECK_DECLS('memalign', headers='malloc.h')
+
     conf.CHECK_FUNCS('prctl dirname basename')
 
     # libbsd on some platforms provides strlcpy and strlcat
@@ -361,13 +370,6 @@ removeea setea
     # try to find libintl (if --without-gettext is not given)
     conf.env.intl_libs=''
     if not Options.options.disable_gettext:
-        # any extra path given to look at?
-        if not Options.options.gettext_location == 'None':
-           conf.env['CFLAGS'].extend(["-I%s" % Options.options.gettext_location]);
-           conf.env['LDFLAGS'].extend(["-L%s" % Options.options.gettext_location]);
-        else:
-           conf.env['CFLAGS'].extend(["-I/usr/local"]);
-           conf.env['LDFLAGS'].extend(["-L/usr/local"]);
         conf.CHECK_HEADERS('libintl.h')
         conf.CHECK_LIB('intl')
         conf.CHECK_DECLS('dgettext gettext bindtextdomain textdomain bind_textdomain_codeset', headers="libintl.h")
@@ -407,10 +409,6 @@ removeea setea
        conf.undefine('HAVE_DGETTEXT')
        conf.undefine('HAVE_DECL_DGETTEXT')
 
-    # did the user insist on gettext (--with-gettext)?
-    if Options.options.gettext_location != 'None' and (not conf.env['HAVE_GETTEXT'] or not conf.env['HAVE_DGETTEXT']):
-        conf.fatal('library gettext not found at specified location')
-
     conf.CHECK_FUNCS_IN('pthread_create', 'pthread', checklibc=True, headers='pthread.h')
 
     PTHREAD_CFLAGS='error'
@@ -502,7 +500,14 @@ removeea setea
                        addmain=False,
                        msg='Checking for working strptime')
 
-    conf.CHECK_CODE('gettimeofday(NULL, NULL)', 'HAVE_GETTIMEOFDAY_TZ', execute=False)
+    conf.CHECK_C_PROTOTYPE('gettimeofday',
+                           'int gettimeofday(struct timeval *tv, struct timezone *tz)',
+                           define='HAVE_GETTIMEOFDAY_TZ', headers='sys/time.h')
+
+    conf.CHECK_C_PROTOTYPE('gettimeofday',
+                           'int gettimeofday(struct timeval *tv, void *tz)',
+                           define='HAVE_GETTIMEOFDAY_TZ_VOID',
+                           headers='sys/time.h')
 
     conf.CHECK_CODE('#include "test/snprintf.c"',
                     define="HAVE_C99_VSNPRINTF",
diff --git a/lib/resolv_wrapper/resolv_wrapper.c b/lib/resolv_wrapper/resolv_wrapper.c
index 10af360..d36d080 100644
--- a/lib/resolv_wrapper/resolv_wrapper.c
+++ b/lib/resolv_wrapper/resolv_wrapper.c
@@ -981,51 +981,68 @@ static int rwrap_res_fake_hosts(const char *hostfile,
 
 #include <dlfcn.h>
 
-struct rwrap_libc_fns {
-	int (*libc_res_init)(void);
-	int (*libc___res_init)(void);
-	int (*libc_res_ninit)(struct __res_state *state);
-	int (*libc___res_ninit)(struct __res_state *state);
-	void (*libc_res_nclose)(struct __res_state *state);
-	void (*libc___res_nclose)(struct __res_state *state);
-	void (*libc_res_close)(void);
-	void (*libc___res_close)(void);
-	int (*libc_res_nquery)(struct __res_state *state,
-			       const char *dname,
-			       int class,
-			       int type,
-			       unsigned char *answer,
-			       int anslen);
-	int (*libc___res_nquery)(struct __res_state *state,
+typedef int (*__libc_res_ninit)(struct __res_state *state);
+typedef int (*__libc___res_ninit)(struct __res_state *state);
+typedef void (*__libc_res_nclose)(struct __res_state *state);
+typedef void (*__libc___res_nclose)(struct __res_state *state);
+typedef int (*__libc_res_nquery)(struct __res_state *state,
 				 const char *dname,
 				 int class,
 				 int type,
 				 unsigned char *answer,
 				 int anslen);
-	int (*libc_res_nsearch)(struct __res_state *state,
-				const char *dname,
-				int class,
-				int type,
-				unsigned char *answer,
-				int anslen);
-	int (*libc___res_nsearch)(struct __res_state *state,
+typedef int (*__libc___res_nquery)(struct __res_state *state,
+				   const char *dname,
+				   int class,
+				   int type,
+				   unsigned char *answer,
+				   int anslen);
+typedef int (*__libc_res_nsearch)(struct __res_state *state,
 				  const char *dname,
 				  int class,
 				  int type,
 				  unsigned char *answer,
 				  int anslen);
+typedef int (*__libc___res_nsearch)(struct __res_state *state,
+				    const char *dname,
+				    int class,
+				    int type,
+				    unsigned char *answer,
+				    int anslen);
+
+#define RWRAP_SYMBOL_ENTRY(i) \
+	union { \
+		__libc_##i f; \
+		void *obj; \
+	} _libc_##i
+
+struct rwrap_libc_symbols {
+	RWRAP_SYMBOL_ENTRY(res_ninit);
+	RWRAP_SYMBOL_ENTRY(__res_ninit);
+	RWRAP_SYMBOL_ENTRY(res_nclose);
+	RWRAP_SYMBOL_ENTRY(__res_nclose);
+	RWRAP_SYMBOL_ENTRY(res_nquery);
+	RWRAP_SYMBOL_ENTRY(__res_nquery);
+	RWRAP_SYMBOL_ENTRY(res_nsearch);
+	RWRAP_SYMBOL_ENTRY(__res_nsearch);
 };
+#undef RWRAP_SYMBOL_ENTRY
 
 struct rwrap {
-	void *libc_handle;
-	void *libresolv_handle;
+	struct {
+		void *handle;
+		struct rwrap_libc_symbols symbols;
+	} libc;
+
+	struct {
+		void *handle;
+		struct rwrap_libc_symbols symbols;
+	} libresolv;
 
 	bool initialised;
 	bool enabled;
 
 	char *socket_dir;
-
-	struct rwrap_libc_fns fns;
 };
 
 static struct rwrap rwrap;
@@ -1063,7 +1080,7 @@ static void *rwrap_load_lib_handle(enum rwrap_lib lib)
 	switch (lib) {
 	case RWRAP_LIBRESOLV:
 #ifdef HAVE_LIBRESOLV
-		handle = rwrap.libresolv_handle;
+		handle = rwrap.libresolv.handle;
 		if (handle == NULL) {
 			for (i = 10; i >= 0; i--) {
 				char soname[256] = {0};
@@ -1075,18 +1092,18 @@ static void *rwrap_load_lib_handle(enum rwrap_lib lib)
 				}
 			}
 
-			rwrap.libresolv_handle = handle;
+			rwrap.libresolv.handle = handle;
 		}
 		break;
 #endif
 		/* FALL TROUGH */
 	case RWRAP_LIBC:
-		handle = rwrap.libc_handle;
+		handle = rwrap.libc.handle;
 #ifdef LIBC_SO
 		if (handle == NULL) {
 			handle = dlopen(LIBC_SO, flags);
 
-			rwrap.libc_handle = handle;
+			rwrap.libc.handle = handle;
 		}
 #endif
 		if (handle == NULL) {
@@ -1100,14 +1117,14 @@ static void *rwrap_load_lib_handle(enum rwrap_lib lib)
 				}
 			}
 
-			rwrap.libc_handle = handle;
+			rwrap.libc.handle = handle;
 		}
 		break;
 	}
 
 	if (handle == NULL) {
 #ifdef RTLD_NEXT
-		handle = rwrap.libc_handle = rwrap.libresolv_handle = RTLD_NEXT;
+		handle = rwrap.libc.handle = rwrap.libresolv.handle = RTLD_NEXT;
 #else
 		RWRAP_LOG(RWRAP_LOG_ERROR,
 			  "Failed to dlopen library: %s\n",
@@ -1119,7 +1136,7 @@ static void *rwrap_load_lib_handle(enum rwrap_lib lib)
 	return handle;
 }
 
-static void *_rwrap_load_lib_function(enum rwrap_lib lib, const char *fn_name)
+static void *_rwrap_bind_symbol(enum rwrap_lib lib, const char *fn_name)
 {
 	void *handle;
 	void *func;
@@ -1140,10 +1157,16 @@ static void *_rwrap_load_lib_function(enum rwrap_lib lib, const char *fn_name)
 	return func;
 }
 
-#define rwrap_load_lib_function(lib, fn_name) \
-	if (rwrap.fns.libc_##fn_name == NULL) { \
-		*(void **) (&rwrap.fns.libc_##fn_name) = \
-			_rwrap_load_lib_function(lib, #fn_name); \
+#define rwrap_bind_symbol_libc(sym_name) \
+	if (rwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
+		rwrap.libc.symbols._libc_##sym_name.obj = \
+			_rwrap_bind_symbol(RWRAP_LIBC, #sym_name); \
+	}
+
+#define rwrap_bind_symbol_libresolv(sym_name) \
+	if (rwrap.libresolv.symbols._libc_##sym_name.obj == NULL) { \
+		rwrap.libresolv.symbols._libc_##sym_name.obj = \
+			_rwrap_bind_symbol(RWRAP_LIBRESOLV, #sym_name); \
 	}
 
 /*
@@ -1154,36 +1177,25 @@ static void *_rwrap_load_lib_function(enum rwrap_lib lib, const char *fn_name)
  * has probably something todo with with the linker.
  * So we need load each function at the point it is called the first time.
  */
-#if 0
-static int libc_res_init(void)
-{
-#if defined(HAVE_RES_INIT)
-	rwrap_load_lib_function(RWRAP_LIBRESOLV, res_init);
-
-	return rwrap.fns.libc_res_init();
-#elif defined(HAVE___RES_INIT)
-	rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_init);
-
-	return rwrap.fns.libc___res_init();
-#endif
-}
-#endif
 
 static int libc_res_ninit(struct __res_state *state)
 {
-#if defined(HAVE_RES_NINIT)
+#if !defined(res_ninit) && defined(HAVE_RES_NINIT)
 
 #if defined(HAVE_RES_NINIT_IN_LIBRESOLV)
-	rwrap_load_lib_function(RWRAP_LIBRESOLV, res_ninit);
+	rwrap_bind_symbol_libresolv(res_ninit);
+
+	return rwrap.libresolv.symbols._libc_res_ninit.f(state);
 #else /* HAVE_RES_NINIT_IN_LIBRESOLV */
-	rwrap_load_lib_function(RWRAP_LIBC, res_ninit);
+	rwrap_bind_symbol_libc(res_ninit);
+
+	return rwrap.libc.symbols._libc_res_ninit.f(state);
 #endif /* HAVE_RES_NINIT_IN_LIBRESOLV */
 
-	return rwrap.fns.libc_res_ninit(state);
 #elif defined(HAVE___RES_NINIT)
-	rwrap_load_lib_function(RWRAP_LIBC, __res_ninit);
+	rwrap_bind_symbol_libc(__res_ninit);
 
-	return rwrap.fns.libc___res_ninit(state);
+	return rwrap.libc.symbols._libc___res_ninit.f(state);
 #else
 #error "No res_ninit function"
 #endif
@@ -1191,19 +1203,24 @@ static int libc_res_ninit(struct __res_state *state)
 
 static void libc_res_nclose(struct __res_state *state)
 {
-#if defined(HAVE_RES_NCLOSE)
+#if !defined(res_close) && defined(HAVE_RES_NCLOSE)
 
 #if defined(HAVE_RES_NCLOSE_IN_LIBRESOLV)
-	rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nclose);
+	rwrap_bind_symbol_libresolv(res_nclose);
+
+	rwrap.libresolv.symbols._libc_res_nclose.f(state);
+	return;
 #else /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
-	rwrap_load_lib_function(RWRAP_LIBC, res_nclose);
+	rwrap_bind_symbol_libc(res_nclose);
+
+	rwrap.libc.symbols._libc_res_nclose.f(state);
+	return;
 #endif /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
 
-	rwrap.fns.libc_res_nclose(state);
 #elif defined(HAVE___RES_NCLOSE)
-	rwrap_load_lib_function(RWRAP_LIBC, __res_nclose);
+	rwrap_bind_symbol_libc(__res_nclose);
 
-	rwrap.fns.libc___res_nclose(state);
+	rwrap.libc.symbols._libc___res_nclose.f(state);
 #else
 #error "No res_nclose function"
 #endif
@@ -1216,24 +1233,24 @@ static int libc_res_nquery(struct __res_state *state,
 			   unsigned char *answer,
 			   int anslen)
 {
-#if defined(HAVE_RES_NQUERY)
-	rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nquery);
-
-	return rwrap.fns.libc_res_nquery(state,
-					 dname,
-					 class,
-					 type,
-					 answer,
-					 anslen);
+#if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
+	rwrap_bind_symbol_libresolv(res_nquery);
+
+	return rwrap.libresolv.symbols._libc_res_nquery.f(state,
+							  dname,
+							  class,
+							  type,
+							  answer,
+							  anslen);
 #elif defined(HAVE___RES_NQUERY)
-	rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nquery);
-
-	return rwrap.fns.libc___res_nquery(state,
-					   dname,
-					   class,
-					   type,
-					   answer,
-					   anslen);
+	rwrap_bind_symbol_libresolv(__res_nquery);
+
+	return rwrap.libresolv.symbols._libc___res_nquery.f(state,
+							    dname,
+							    class,
+							    type,
+							    answer,
+							    anslen);
 #else
 #error "No res_nquery function"
 #endif
@@ -1246,24 +1263,24 @@ static int libc_res_nsearch(struct __res_state *state,
 			    unsigned char *answer,
 			    int anslen)
 {
-#if defined(HAVE_RES_NSEARCH)
-	rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nsearch);
-
-	return rwrap.fns.libc_res_nsearch(state,
-					  dname,
-					  class,
-					  type,
-					  answer,
-					  anslen);
+#if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
+	rwrap_bind_symbol_libresolv(res_nsearch);
+
+	return rwrap.libresolv.symbols._libc_res_nsearch.f(state,
+							   dname,
+							   class,
+							   type,
+							   answer,
+							   anslen);
 #elif defined(HAVE___RES_NSEARCH)
-	rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nsearch);
-
-	return rwrap.fns.libc___res_nsearch(state,
-					    dname,
-					    class,
-					    type,
-					    answer,
-					    anslen);
+	rwrap_bind_symbol_libresolv(__res_nsearch);
+
+	return rwrap.libresolv.symbols._libc___res_nsearch.f(state,
+							     dname,
+							     class,
+							     type,
+							     answer,
+							     anslen);
 #else
 #error "No res_nsearch function"
 #endif
@@ -1418,7 +1435,7 @@ static int rwrap_res_ninit(struct __res_state *state)
 	return rc;
 }
 
-#if defined(HAVE_RES_NINIT)
+#if !defined(res_ninit) && defined(HAVE_RES_NINIT)
 int res_ninit(struct __res_state *state)
 #elif defined(HAVE___RES_NINIT)
 int __res_ninit(struct __res_state *state)
@@ -1442,7 +1459,7 @@ static int rwrap_res_init(void)
 	return rc;
 }
 
-#if defined(HAVE_RES_INIT)
+#if !defined(res_ninit) && defined(HAVE_RES_INIT)
 int res_init(void)
 #elif defined(HAVE___RES_INIT)
 int __res_init(void)
@@ -1472,7 +1489,7 @@ static void rwrap_res_nclose(struct __res_state *state)
 #endif
 }
 
-#if defined(HAVE_RES_NCLOSE)
+#if !defined(res_nclose) && defined(HAVE_RES_NCLOSE)
 void res_nclose(struct __res_state *state)
 #elif defined(HAVE___RES_NCLOSE)
 void __res_nclose(struct __res_state *state)
@@ -1545,7 +1562,7 @@ static int rwrap_res_nquery(struct __res_state *state,
 	return rc;
 }
 
-#if defined(HAVE_RES_NQUERY)
+#if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
 int res_nquery(struct __res_state *state,
 	       const char *dname,
 	       int class,
@@ -1591,7 +1608,7 @@ static int rwrap_res_query(const char *dname,
 	return rc;
 }
 
-#if defined(HAVE_RES_QUERY)
+#if !defined(res_query) && defined(HAVE_RES_QUERY)
 int res_query(const char *dname,
 	      int class,
 	      int type,
@@ -1653,7 +1670,7 @@ static int rwrap_res_nsearch(struct __res_state *state,
 	return rc;
 }
 
-#if defined(HAVE_RES_NSEARCH)
+#if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
 int res_nsearch(struct __res_state *state,
 		const char *dname,
 		int class,
@@ -1699,7 +1716,7 @@ static int rwrap_res_search(const char *dname,
 	return rc;
 }
 
-#if defined(HAVE_RES_SEARCH)
+#if !defined(res_search) && defined(HAVE_RES_SEARCH)
 int res_search(const char *dname,
 	       int class,
 	       int type,
diff --git a/lib/resolv_wrapper/wscript b/lib/resolv_wrapper/wscript
index f30621b..34c00d2 100644
--- a/lib/resolv_wrapper/wscript
+++ b/lib/resolv_wrapper/wscript
@@ -2,7 +2,7 @@
 
 import os
 
-VERSION="1.1.2"
+VERSION="1.1.3"
 
 def configure(conf):
     if conf.CHECK_BUNDLED_SYSTEM('resolv_wrapper', minversion=VERSION, set_target=False):
@@ -92,7 +92,6 @@ def build(bld):
         # breaks preloading!
         bld.SAMBA_LIBRARY('resolv_wrapper',
                           source='resolv_wrapper.c',
-                          cflags='-DNDEBUG',
                           deps='dl resolv',
                           install=False,
                           realname='libresolv-wrapper.so')
diff --git a/lib/socket/interfaces.c b/lib/socket/interfaces.c
index e62da3c..dacd118 100644
--- a/lib/socket/interfaces.c
+++ b/lib/socket/interfaces.c
@@ -24,6 +24,12 @@
 #include "system/network.h"
 #include "interfaces.h"
 #include "lib/util/tsort.h"
+#include "librpc/gen_ndr/ioctl.h"
+
+#ifdef HAVE_ETHTOOL
+#include "linux/sockios.h"
+#include "linux/ethtool.h"
+#endif
 
 /****************************************************************************
  Create a struct sockaddr_storage with the netmask bits set to 1.
@@ -119,6 +125,53 @@ void make_net(struct sockaddr_storage *pss_out,
 	make_bcast_or_net(pss_out, pss_in, nmask, false);
 }
 
+#ifdef HAVE_ETHTOOL
+static void query_iface_speed_from_name(const char *name, uint64_t *speed)
+{
+	int ret = 0;
+	struct ethtool_cmd ecmd;
+	struct ethtool_value edata;
+	struct ifreq ifr;
+	int fd;
+
+	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+	if (fd == -1) {
+		DBG_ERR("Failed to open socket.");
+		return;
+	}
+
+	if (strlen(name) >= IF_NAMESIZE) {
+		DBG_ERR("Interface name too long.");
+		goto done;
+	}
+
+	ZERO_STRUCT(ifr);
+	strncpy(ifr.ifr_name, name, IF_NAMESIZE);
+
+	ifr.ifr_data = (void *)&edata;
+	edata.cmd = ETHTOOL_GLINK;
+	ret = ioctl(fd, SIOCETHTOOL, &ifr);
+	if (ret == -1) {
+		goto done;
+	}
+	if (edata.data == 0) {
+		/* no link detected */
+		*speed = 0;
+		goto done;
+	}
+
+	ifr.ifr_data = (void *)&ecmd;
+	ecmd.cmd = ETHTOOL_GSET;
+	ret = ioctl(fd, SIOCETHTOOL, &ifr);
+	if (ret == -1) {
+		goto done;
+	}
+	*speed = ((uint64_t)ethtool_cmd_speed(&ecmd)) * 1000 * 1000;
+
+done:
+	(void)close(fd);
+}
+#endif
 
 /****************************************************************************
  Try the "standard" getifaddrs/freeifaddrs interfaces.
@@ -161,6 +214,7 @@ static int _get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
 
 	/* Loop through interfaces, looking for given IP address */
 	for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
+		uint64_t if_speed = 1000 * 1000 * 1000; /* 1Gbps */
 
 		if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
 			continue;
@@ -214,6 +268,18 @@ static int _get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
 			continue;
 		}
 
+		ifaces[total].if_index = if_nametoindex(ifptr->ifa_name);
+		if (ifaces[total].if_index == 0) {
+			DBG_ERR("Failed to retrieve interface index for '%s': "
+				"%s\n", ifptr->ifa_name, strerror(errno));
+		}
+
+#ifdef HAVE_ETHTOOL
+		query_iface_speed_from_name(ifptr->ifa_name, &if_speed);
+#endif
+		ifaces[total].linkspeed = if_speed;
+		ifaces[total].capability = FSCTL_NET_IFACE_NONE_CAPABLE;
+
 		if (strlcpy(ifaces[total].name, ifptr->ifa_name,
 			sizeof(ifaces[total].name)) >=
 				sizeof(ifaces[total].name)) {
diff --git a/lib/socket/interfaces.h b/lib/socket/interfaces.h
index b4e113d..0876f09 100644
--- a/lib/socket/interfaces.h
+++ b/lib/socket/interfaces.h
@@ -27,6 +27,9 @@ struct iface_struct {
 	struct sockaddr_storage ip;
 	struct sockaddr_storage netmask;
 	struct sockaddr_storage bcast;
+	uint32_t if_index;
+	uint64_t linkspeed;
+	uint32_t capability;
 };
 
 struct interface;
diff --git a/lib/socket/wscript b/lib/socket/wscript
new file mode 100644
index 0000000..d8c269a
--- /dev/null
+++ b/lib/socket/wscript
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+def configure(conf):
+    conf.CHECK_HEADERS('linux/sockios.h linux/ethtool.h')
+    if (conf.CONFIG_SET('HAVE_LINUX_SOCKIOS_H') and \
+                    conf.CONFIG_SET('HAVE_LINUX_ETHTOOL_H')):
+        conf.DEFINE('HAVE_ETHTOOL', 1)
diff --git a/lib/socket_wrapper/socket_wrapper.c b/lib/socket_wrapper/socket_wrapper.c
index 1188c4e..45282ed 100644
--- a/lib/socket_wrapper/socket_wrapper.c
+++ b/lib/socket_wrapper/socket_wrapper.c
@@ -203,11 +203,12 @@ enum swrap_dbglvl_e {
 #define SOCKET_TYPE_CHAR_UDP_V6		'Y'
 
 /*
- * Cut down to 1500 byte packets for stream sockets,
- * which makes it easier to format PCAP capture files
- * (as the caller will simply continue from here)
+ * Set the packet MTU to 1500 bytes for stream sockets to make it it easier to
+ * format PCAP capture files (as the caller will simply continue from here).
  */
-#define SOCKET_MAX_PACKET 1500
+#define SOCKET_WRAPPER_MTU_DEFAULT 1500
+#define SOCKET_WRAPPER_MTU_MIN     512
+#define SOCKET_WRAPPER_MTU_MAX     32768
 
 #define SOCKET_MAX_SOCKETS 1024
 
@@ -912,6 +913,38 @@ static const char *socket_wrapper_dir(void)
 	return s;
 }
 
+static unsigned int socket_wrapper_mtu(void)
+{
+	static unsigned int max_mtu = 0;
+	unsigned int tmp;
+	const char *s;
+	char *endp;
+
+	if (max_mtu != 0) {
+		return max_mtu;
+	}
+
+	max_mtu = SOCKET_WRAPPER_MTU_DEFAULT;
+
+	s = getenv("SOCKET_WRAPPER_MTU");
+	if (s == NULL) {
+		goto done;
+	}
+
+	tmp = strtol(s, &endp, 10);
+	if (s == endp) {
+		goto done;
+	}
+
+	if (tmp < SOCKET_WRAPPER_MTU_MIN || tmp > SOCKET_WRAPPER_MTU_MAX) {
+		goto done;
+	}
+	max_mtu = tmp;
+
+done:
+	return max_mtu;
+}
+
 bool socket_wrapper_enabled(void)
 {
 	const char *s = socket_wrapper_dir();
@@ -3743,7 +3776,9 @@ static ssize_t swrap_sendmsg_before(int fd,
 	}
 
 	switch (si->type) {
-	case SOCK_STREAM:
+	case SOCK_STREAM: {
+		unsigned long mtu;
+
 		if (!si->connected) {
 			errno = ENOTCONN;
 			return -1;
@@ -3753,22 +3788,23 @@ static ssize_t swrap_sendmsg_before(int fd,
 			break;
 		}
 
+		mtu = socket_wrapper_mtu();
 		for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
 			size_t nlen;
 			nlen = len + msg->msg_iov[i].iov_len;
-			if (nlen > SOCKET_MAX_PACKET) {
+			if (nlen > mtu) {
 				break;
 			}
 		}
 		msg->msg_iovlen = i;
 		if (msg->msg_iovlen == 0) {
 			*tmp_iov = msg->msg_iov[0];
-			tmp_iov->iov_len = MIN(tmp_iov->iov_len, SOCKET_MAX_PACKET);
+			tmp_iov->iov_len = MIN(tmp_iov->iov_len, (size_t)mtu);
 			msg->msg_iov = tmp_iov;
 			msg->msg_iovlen = 1;
 		}
 		break;
-
+	}
 	case SOCK_DGRAM:
 		if (si->connected) {
 			if (msg->msg_name) {
@@ -3958,7 +3994,8 @@ static int swrap_recvmsg_before(int fd,
 	(void)fd; /* unused */
 
 	switch (si->type) {
-	case SOCK_STREAM:
+	case SOCK_STREAM: {
+		unsigned int mtu;
 		if (!si->connected) {
 			errno = ENOTCONN;
 			return -1;
@@ -3968,22 +4005,23 @@ static int swrap_recvmsg_before(int fd,
 			break;
 		}
 
+		mtu = socket_wrapper_mtu();
 		for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
 			size_t nlen;
 			nlen = len + msg->msg_iov[i].iov_len;
-			if (nlen > SOCKET_MAX_PACKET) {
+			if (nlen > mtu) {
 				break;
 			}
 		}
 		msg->msg_iovlen = i;
 		if (msg->msg_iovlen == 0) {
 			*tmp_iov = msg->msg_iov[0];
-			tmp_iov->iov_len = MIN(tmp_iov->iov_len, SOCKET_MAX_PACKET);
+			tmp_iov->iov_len = MIN(tmp_iov->iov_len, (size_t)mtu);
 			msg->msg_iov = tmp_iov;
 			msg->msg_iovlen = 1;
 		}
 		break;
-
+	}
 	case SOCK_DGRAM:
 		if (msg->msg_name == NULL) {
 			errno = EINVAL;
@@ -4051,6 +4089,19 @@ static int swrap_recvmsg_after(int fd,
 		avail += msg->msg_iov[i].iov_len;
 	}
 
+	/* Convert the socket address before we leave */
+	if (si->type == SOCK_DGRAM && un_addr != NULL) {
+		rc = sockaddr_convert_from_un(si,
+					      un_addr,
+					      un_addrlen,
+					      si->family,
+					      msg->msg_name,
+					      &msg->msg_namelen);
+		if (rc == -1) {
+			goto done;
+		}
+	}
+
 	if (avail == 0) {
 		rc = 0;
 		goto done;
@@ -4096,16 +4147,6 @@ static int swrap_recvmsg_after(int fd,
 		}
 
 		if (un_addr != NULL) {
-			rc = sockaddr_convert_from_un(si,
-						      un_addr,
-						      un_addrlen,
-						      si->family,
-						      msg->msg_name,
-						      &msg->msg_namelen);
-			if (rc == -1) {
-				goto done;
-			}
-
 			swrap_pcap_dump_packet(si,
 					  msg->msg_name,
 					  SWRAP_RECVFROM,
@@ -4549,9 +4590,6 @@ static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags)
 
 	ret = libc_recvmsg(s, &msg, flags);
 
-	msg.msg_name = omsg->msg_name;
-	msg.msg_namelen = omsg->msg_namelen;
-
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
 	msg_ctrllen_filled += msg.msg_controllen;
 	msg_ctrllen_left -= msg.msg_controllen;
@@ -4593,6 +4631,25 @@ static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags)
 #endif
 	omsg->msg_iovlen = msg.msg_iovlen;
 
+	/*
+	 * From the manpage:
+	 *
+	 * The  msg_name  field  points  to a caller-allocated buffer that is
+	 * used to return the source address if the socket is unconnected.  The
+	 * caller should set msg_namelen to the size of this buffer before this
+	 * call; upon return from a successful call, msg_name will contain the
+	 * length of the returned address.  If the application  does  not  need
+	 * to know the source address, msg_name can be specified as NULL.
+	 */
+	if (si->type == SOCK_STREAM) {
+		omsg->msg_namelen = 0;
+	} else if (omsg->msg_name != NULL &&
+	           omsg->msg_namelen != 0 &&
+	           omsg->msg_namelen >= msg.msg_namelen) {
+		memcpy(omsg->msg_name, msg.msg_name, msg.msg_namelen);
+		omsg->msg_namelen = msg.msg_namelen;
+	}
+
 	return ret;
 }
 
@@ -4627,8 +4684,11 @@ static ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
 	tmp.iov_len = 0;
 
 	ZERO_STRUCT(msg);
-	msg.msg_name = omsg->msg_name;             /* optional address */
-	msg.msg_namelen = omsg->msg_namelen;       /* size of address */
+
+	if (si->connected == 0) {
+		msg.msg_name = omsg->msg_name;             /* optional address */
+		msg.msg_namelen = omsg->msg_namelen;       /* size of address */
+	}
 	msg.msg_iov = omsg->msg_iov;               /* scatter/gather array */
 	msg.msg_iovlen = omsg->msg_iovlen;         /* # elements in msg_iov */
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
@@ -5071,4 +5131,11 @@ void swrap_destructor(void)
 		}
 		s = sockets;
 	}
+
+	if (swrap.libc_handle != NULL) {
+		dlclose(swrap.libc_handle);
+	}
+	if (swrap.libsocket_handle) {
+		dlclose(swrap.libsocket_handle);
+	}
 }
diff --git a/lib/socket_wrapper/wscript b/lib/socket_wrapper/wscript
index 36c6dbe..9d9bf01 100644
--- a/lib/socket_wrapper/wscript
+++ b/lib/socket_wrapper/wscript
@@ -2,7 +2,7 @@
 
 import os
 
-VERSION="1.1.3"
+VERSION="1.1.4"
 
 def configure(conf):
     if conf.CHECK_BUNDLED_SYSTEM('socket_wrapper', minversion=VERSION, set_target=False):
@@ -107,7 +107,6 @@ def build(bld):
         # breaks preloading!
         bld.SAMBA_LIBRARY('socket_wrapper',
                           source='socket_wrapper.c',
-                          cflags='-DNDEBUG',
                           deps='dl',
                           install=False,
                           realname='libsocket-wrapper.so')
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.4.sigs b/lib/talloc/ABI/pytalloc-util-2.1.4.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.4.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.5.sigs b/lib/talloc/ABI/pytalloc-util-2.1.5.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.5.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.6.sigs b/lib/talloc/ABI/pytalloc-util-2.1.6.sigs
new file mode 100644
index 0000000..666fec0
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.6.sigs
@@ -0,0 +1,13 @@
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util.py3-2.1.5.sigs b/lib/talloc/ABI/pytalloc-util.py3-2.1.5.sigs
new file mode 100644
index 0000000..0807eb3
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util.py3-2.1.5.sigs
@@ -0,0 +1,5 @@
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util.py3-2.1.6.sigs b/lib/talloc/ABI/pytalloc-util.py3-2.1.6.sigs
new file mode 100644
index 0000000..4410f11
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util.py3-2.1.6.sigs
@@ -0,0 +1,12 @@
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/talloc-2.1.4.sigs b/lib/talloc/ABI/talloc-2.1.4.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.4.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.5.sigs b/lib/talloc/ABI/talloc-2.1.5.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.5.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.6.sigs b/lib/talloc/ABI/talloc-2.1.6.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.6.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/pytalloc.c b/lib/talloc/pytalloc.c
index 3afae9c..74349da 100644
--- a/lib/talloc/pytalloc.c
+++ b/lib/talloc/pytalloc.c
@@ -20,6 +20,7 @@
 #include <Python.h>
 #include <talloc.h>
 #include <pytalloc.h>
+#include "pytalloc_private.h"
 
 static PyTypeObject TallocObject_Type;
 
@@ -157,6 +158,86 @@ static PyTypeObject TallocObject_Type = {
 #endif
 };
 
+/**
+ * Default (but only slightly more useful than the default) implementation of Repr().
+ */
+static PyObject *pytalloc_base_default_repr(PyObject *obj)
+{
+	pytalloc_BaseObject *talloc_obj = (pytalloc_BaseObject *)obj;
+	PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj);
+
+	return PyStr_FromFormat("<%s talloc based object at 0x%p>",
+				type->tp_name, talloc_obj->ptr);
+}
+
+/**
+ * Simple dealloc for talloc-wrapping PyObjects
+ */
+static void pytalloc_base_dealloc(PyObject* self)
+{
+	pytalloc_BaseObject *obj = (pytalloc_BaseObject *)self;
+	assert(talloc_unlink(NULL, obj->talloc_ctx) != -1);
+	obj->talloc_ctx = NULL;
+	self->ob_type->tp_free(self);
+}
+
+/**
+ * Default (but only slightly more useful than the default) implementation of cmp.
+ */
+#if PY_MAJOR_VERSION >= 3
+static PyObject *pytalloc_base_default_richcmp(PyObject *obj1, PyObject *obj2, int op)
+{
+	void *ptr1;
+	void *ptr2;
+	if (Py_TYPE(obj1) == Py_TYPE(obj2)) {
+		/* When types match, compare pointers */
+		ptr1 = pytalloc_get_ptr(obj1);
+		ptr2 = pytalloc_get_ptr(obj2);
+	} else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) {
+		/* Otherwise, compare types */
+		ptr1 = Py_TYPE(obj1);
+		ptr2 = Py_TYPE(obj2);
+	} else {
+		Py_INCREF(Py_NotImplemented);
+		return Py_NotImplemented;
+	}
+	switch (op) {
+		case Py_EQ: return PyBool_FromLong(ptr1 == ptr2);
+		case Py_NE: return PyBool_FromLong(ptr1 != ptr2);
+		case Py_LT: return PyBool_FromLong(ptr1 < ptr2);
+		case Py_GT: return PyBool_FromLong(ptr1 > ptr2);
+		case Py_LE: return PyBool_FromLong(ptr1 <= ptr2);
+		case Py_GE: return PyBool_FromLong(ptr1 >= ptr2);
+	}
+	Py_INCREF(Py_NotImplemented);
+	return Py_NotImplemented;
+}
+#else
+static int pytalloc_base_default_cmp(PyObject *_obj1, PyObject *_obj2)
+{
+	pytalloc_BaseObject *obj1 = (pytalloc_BaseObject *)_obj1,
+					 *obj2 = (pytalloc_BaseObject *)_obj2;
+	if (obj1->ob_type != obj2->ob_type)
+		return ((char *)obj1->ob_type - (char *)obj2->ob_type);
+
+	return ((char *)pytalloc_get_ptr(obj1) - (char *)pytalloc_get_ptr(obj2));
+}
+#endif
+
+static PyTypeObject TallocBaseObject_Type = {
+	.tp_name = "talloc.BaseObject",
+	.tp_doc = "Python wrapper for a talloc-maintained object.",
+	.tp_basicsize = sizeof(pytalloc_BaseObject),
+	.tp_dealloc = (destructor)pytalloc_base_dealloc,
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+	.tp_repr = pytalloc_base_default_repr,
+#if PY_MAJOR_VERSION >= 3
+	.tp_richcompare = pytalloc_base_default_richcmp,
+#else
+	.tp_compare = pytalloc_base_default_cmp,
+#endif
+};
+
 #define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
 
 #if PY_MAJOR_VERSION >= 3
@@ -177,6 +258,9 @@ static PyObject *module_init(void)
 	if (PyType_Ready(&TallocObject_Type) < 0)
 		return NULL;
 
+	if (PyType_Ready(&TallocBaseObject_Type) < 0)
+		return NULL;
+
 #if PY_MAJOR_VERSION >= 3
 	m = PyModule_Create(&moduledef);
 #else
@@ -187,6 +271,8 @@ static PyObject *module_init(void)
 
 	Py_INCREF(&TallocObject_Type);
 	PyModule_AddObject(m, "Object", (PyObject *)&TallocObject_Type);
+	Py_INCREF(&TallocBaseObject_Type);
+	PyModule_AddObject(m, "BaseObject", (PyObject *)&TallocBaseObject_Type);
 	return m;
 }
 
diff --git a/lib/talloc/pytalloc.h b/lib/talloc/pytalloc.h
index 608328e..6a0ac18 100644
--- a/lib/talloc/pytalloc.h
+++ b/lib/talloc/pytalloc.h
@@ -26,24 +26,29 @@
 typedef struct {
 	PyObject_HEAD
 	TALLOC_CTX *talloc_ctx;
-	void *ptr;
+	void *ptr; /* eg the array element */
 } pytalloc_Object;
 
 /* Return the PyTypeObject for pytalloc_Object. Returns a new reference. */
 PyTypeObject *pytalloc_GetObjectType(void);
 
+/* Return the PyTypeObject for pytalloc_BaseObject. Returns a new reference. */
+PyTypeObject *pytalloc_GetBaseObjectType(void);
+
 /* Check whether a specific object is a talloc Object. */
 int pytalloc_Check(PyObject *);
 
+int pytalloc_BaseObject_check(PyObject *);
+
 /* Retrieve the pointer for a pytalloc_object. Like talloc_get_type() 
  * but for pytalloc_Objects. */
+void *_pytalloc_get_type(PyObject *py_obj, const char *type_name);
+#define pytalloc_get_type(py_obj, type) ((type *)_pytalloc_get_type((PyObject *)(py_obj), #type))
 
-/* FIXME: Call PyErr_SetString(PyExc_TypeError, "expected " __STR(type) ") 
- * when talloc_get_type() returns NULL. */
-#define pytalloc_get_type(py_obj, type) (talloc_get_type(pytalloc_get_ptr(py_obj), type))
-
-#define pytalloc_get_ptr(py_obj) (((pytalloc_Object *)py_obj)->ptr)
-#define pytalloc_get_mem_ctx(py_obj)  ((pytalloc_Object *)py_obj)->talloc_ctx
+void *_pytalloc_get_ptr(PyObject *py_obj);
+#define pytalloc_get_ptr(py_obj) _pytalloc_get_ptr((PyObject *)(py_obj))
+TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj);
+#define pytalloc_get_mem_ctx(py_obj) _pytalloc_get_mem_ctx((PyObject *)(py_obj))
 
 PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr);
 PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr);
@@ -56,4 +61,8 @@ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void
 PyObject *pytalloc_CObject_FromTallocPtr(void *);
 #endif
 
+size_t pytalloc_BaseObject_size(void);
+
+int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type);
+
 #endif /* _PYTALLOC_H_ */
diff --git a/lib/talloc/pytalloc_guide.txt b/lib/talloc/pytalloc_guide.txt
index 36ae5ff..1aa4f99 100644
--- a/lib/talloc/pytalloc_guide.txt
+++ b/lib/talloc/pytalloc_guide.txt
@@ -29,7 +29,7 @@ Python's PEP3149 ABI tag, for example "pytalloc.cpython34m".
 To make a build for Python 3, configure with PYTHON=/usr/bin/python3.
 .
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-pytalloc_Object
+pytalloc_Object / pytalloc_BaseObject
 
 This is the new base class that all Python objects that wrap talloc pointers
 derive from. It is itself a subclass of the "Object" type that all objects
@@ -53,12 +53,31 @@ compares the pointers the object is wrapping rather than the objects
 themselves (since there can be multiple objects that wrap the same talloc
 pointer).
 
+It is preferred to use pytalloc_BaseObject as this implementation
+exposes less in the C ABI and correctly supports pointers in C arrays
+in the way needed by PIDL.
+
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 PyTypeObject *pytalloc_GetObjectType(void)
 
-Obtain a reference to the PyTypeObject for `pytalloc_Object`. The reference
-counter for the object will be incremented, so the caller will have to
-decrement it when it no longer needs it (using `Py_DECREF`).
+Obtain a pointer to the PyTypeObject for `pytalloc_Object`. The
+reference counter for the object will be NOT incremented, so the
+caller MUST NOT decrement it when it no longer needs it (eg by using
+`Py_DECREF`).
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyTypeObject *pytalloc_GetBaseObjectType(void)
+
+Obtain a pointer to the PyTypeObject for `pytalloc_BaseObject`. The
+reference counter for the object will be NOT incremented, so the
+caller MUST NOT decrement it when it no longer needs it (eg by using
+`Py_DECREF`).
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type);
+
+Wrapper for PyType_Ready() that will set the correct values into
+the PyTypeObject to create a BaseObject
 
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
 int pytalloc_Check(PyObject *)
@@ -66,6 +85,12 @@ int pytalloc_Check(PyObject *)
 Check whether a specific object is a talloc Object. Returns non-zero if it is
 a pytalloc_Object and zero otherwise.
 
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
+int pytalloc_BaseObject_Check(PyObject *)
+
+Check whether a specific object is a talloc BaseObject. Returns non-zero if it is
+a pytalloc_BaseObject and zero otherwise.
+
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 type *pytalloc_get_type(PyObject *py_obj, type)
 
@@ -75,13 +100,14 @@ C type, similar to a type passed to `talloc_get_type`.
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 pytalloc_get_ptr(PyObject *py_obj)
 
-Retrieve the pointer from a `pytalloc_Object` py_obj. There is no
-type checking - use `pytalloc_get_type` if possible.
+Retrieve the pointer from a `pytalloc_Object` or `pytalloc_BaseObject`
+py_obj. There is no type checking - use `pytalloc_get_type` if
+possible.
 
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 TALLOC_CTX *pytalloc_get_mem_ctx(PyObject *py_obj)
 
-Retrieve the talloc context associated with a pytalloc_Object.
+Retrieve the talloc context associated with a pytalloc_Object or pytalloc_BaseObject.
 
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
diff --git a/lib/talloc/pytalloc_private.h b/lib/talloc/pytalloc_private.h
new file mode 100644
index 0000000..b23cdfc
--- /dev/null
+++ b/lib/talloc/pytalloc_private.h
@@ -0,0 +1,26 @@
+/*
+   Unix SMB/CIFS implementation.
+   Samba utility functions
+   Copyright (C) Jelmer Vernooij <jelmer at samba.org> 2008
+   Copyright (C) Andrew Bartlett <abartlet at samba.org> 2016
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+typedef struct {
+	PyObject_HEAD
+	TALLOC_CTX *talloc_ctx;
+	TALLOC_CTX *talloc_ptr_ctx; /* eg the start of the array */
+	void *ptr; /* eg the array element */
+} pytalloc_BaseObject;
diff --git a/lib/talloc/pytalloc_util.c b/lib/talloc/pytalloc_util.c
index 0af7c05..cb71dc9 100644
--- a/lib/talloc/pytalloc_util.c
+++ b/lib/talloc/pytalloc_util.c
@@ -22,6 +22,7 @@
 #include <talloc.h>
 #include "pytalloc.h"
 #include <assert.h>
+#include "pytalloc_private.h"
 
 _PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
 {
@@ -43,23 +44,82 @@ _PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
 	return type;
 }
 
+_PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void)
+{
+	static PyTypeObject *type = NULL;
+	PyObject *mod;
+
+	if (type != NULL) {
+		return type;
+	}
+
+	mod = PyImport_ImportModule("talloc");
+	if (mod == NULL) {
+		return NULL;
+	}
+
+	type = (PyTypeObject *)PyObject_GetAttrString(mod, "BaseObject");
+	Py_DECREF(mod);
+
+	return type;
+}
+
 /**
  * Import an existing talloc pointer into a Python object.
  */
 _PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx,
-						   void *ptr)
+				     void *ptr)
 {
-	pytalloc_Object *ret = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
-	ret->talloc_ctx = talloc_new(NULL);
-	if (ret->talloc_ctx == NULL) {
-		return NULL;
+	PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
+	PyTypeObject *ObjectType = pytalloc_GetObjectType();
+
+	if (mem_ctx == NULL) {
+		return PyErr_NoMemory();
 	}
-	if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
+
+	if (PyType_IsSubtype(py_type, BaseObjectType)) {
+		pytalloc_BaseObject *ret
+			= (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
+
+		ret->talloc_ctx = talloc_new(NULL);
+		if (ret->talloc_ctx == NULL) {
+			return NULL;
+		}
+
+		/*
+		 * This allows us to keep multiple references to this object -
+		 * we only reference this context, which is per ptr, not the
+		 * talloc_ctx, which is per pytalloc_Object
+		 */
+		if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
+			return NULL;
+		}
+		ret->talloc_ptr_ctx = mem_ctx;
+		talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
+		ret->ptr = ptr;
+		return (PyObject *)ret;
+
+	} else if (PyType_IsSubtype(py_type, ObjectType)) {
+		pytalloc_Object *ret
+			= (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
+
+		ret->talloc_ctx = talloc_new(NULL);
+		if (ret->talloc_ctx == NULL) {
+			return NULL;
+		}
+
+		if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
+			return NULL;
+		}
+		talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
+		ret->ptr = ptr;
+		return (PyObject *)ret;
+	} else {
+		PyErr_SetString(PyExc_RuntimeError,
+				"pytalloc_steal_ex() called for object type "
+				"not based on talloc");
 		return NULL;
 	}
-	talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
-	ret->ptr = ptr;
-	return (PyObject *)ret;
 }
 
 /**
@@ -74,27 +134,57 @@ _PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
 /**
  * Import an existing talloc pointer into a Python object, leaving the
  * original parent, and creating a reference to the object in the python
- * object
+ * object.
+ *
+ * We remember the object we hold the reference to (a
+ * possibly-non-talloc pointer), the existing parent (typically the
+ * start of the array) and the new referenced parent.  That way we can
+ * cope with the fact that we will have multiple parents, one per time
+ * python sees the object.
  */
-_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
+_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type,
+					 TALLOC_CTX *mem_ctx, void *ptr)
 {
-	pytalloc_Object *ret;
+	PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
+	PyTypeObject *ObjectType = pytalloc_GetObjectType();
 
-	if (ptr == NULL) {
-		Py_RETURN_NONE;
+	if (mem_ctx == NULL) {
+		return PyErr_NoMemory();
 	}
 
-	ret = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
-	ret->talloc_ctx = talloc_new(NULL);
-	if (ret->talloc_ctx == NULL) {
+	if (PyType_IsSubtype(py_type, BaseObjectType)) {
+		pytalloc_BaseObject *ret
+			= (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
+		ret->talloc_ctx = talloc_new(NULL);
+		if (ret->talloc_ctx == NULL) {
+			return NULL;
+		}
+		if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
+			return NULL;
+		}
+		talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
+		ret->talloc_ptr_ctx = mem_ctx;
+		ret->ptr = ptr;
+		return (PyObject *)ret;
+	} else if (PyType_IsSubtype(py_type, ObjectType)) {
+		pytalloc_Object *ret
+			= (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
+		ret->talloc_ctx = talloc_new(NULL);
+		if (ret->talloc_ctx == NULL) {
+			return NULL;
+		}
+		if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
+			return NULL;
+		}
+		talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
+		ret->ptr = ptr;
+		return (PyObject *)ret;
+	} else {
+		PyErr_SetString(PyExc_RuntimeError,
+				"pytalloc_reference_ex() called for object type "
+				"not based on talloc");
 		return NULL;
 	}
-	if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
-		return NULL;
-	}
-	talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
-	ret->ptr = ptr;
-	return (PyObject *)ret;
 }
 
 #if PY_MAJOR_VERSION < 3
@@ -120,3 +210,66 @@ _PUBLIC_ int pytalloc_Check(PyObject *obj)
 
 	return PyObject_TypeCheck(obj, tp);
 }
+
+_PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj)
+{
+	PyTypeObject *tp = pytalloc_GetBaseObjectType();
+
+	return PyObject_TypeCheck(obj, tp);
+}
+
+_PUBLIC_ size_t pytalloc_BaseObject_size(void)
+{
+	return sizeof(pytalloc_BaseObject);
+}
+
+_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
+{
+	void *ptr = _pytalloc_get_ptr(py_obj);
+	void *type_obj = talloc_check_name(ptr, type_name);
+
+	if (type_obj == NULL) {
+		const char *name = talloc_get_name(ptr);
+		PyErr_Format(PyExc_TypeError, "pytalloc: expected %s, got %s",
+			     type_name, name);
+		return NULL;
+	}
+
+	return ptr;
+}
+
+_PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
+{
+	if (pytalloc_BaseObject_check(py_obj)) {
+		return ((pytalloc_BaseObject *)py_obj)->ptr;
+	}
+	if (pytalloc_Check(py_obj)) {
+		return ((pytalloc_Object *)py_obj)->ptr;
+	}
+	return NULL;
+}
+
+_PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj)
+{
+	if (pytalloc_BaseObject_check(py_obj)) {
+		return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx;
+	}
+	if (pytalloc_Check(py_obj)) {
+		return ((pytalloc_Object *)py_obj)->talloc_ctx;
+	}
+	return NULL;
+}
+
+_PUBLIC_ int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type)
+{
+	PyTypeObject *talloc_type = pytalloc_GetBaseObjectType();
+	if (talloc_type == NULL) {
+		PyErr_Format(PyExc_TypeError, "pytalloc: unable to get talloc.BaseObject type");
+		return -1;
+	}
+
+	type->tp_base = talloc_type;
+	type->tp_basicsize = pytalloc_BaseObject_size();
+
+	return PyType_Ready(type);
+}
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index c10fd53..90b9d96 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -33,6 +33,10 @@
 #include "replace.h"
 #include "talloc.h"
 
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#endif
+
 #ifdef TALLOC_BUILD_VERSION_MAJOR
 #if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR)
 #error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR"
@@ -60,20 +64,26 @@
 
 
 #define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC_BASE 0xe814ec70
-#define TALLOC_MAGIC ( \
-	TALLOC_MAGIC_BASE + \
-	(TALLOC_VERSION_MAJOR << 12) + \
-	(TALLOC_VERSION_MINOR << 4) \
-)
 
 #define TALLOC_FLAG_FREE 0x01
 #define TALLOC_FLAG_LOOP 0x02
 #define TALLOC_FLAG_POOL 0x04		/* This is a talloc pool */
 #define TALLOC_FLAG_POOLMEM 0x08	/* This is allocated in a pool */
 
+/*
+ * Bits above this are random, used to make it harder to fake talloc
+ * headers during an attack.  Try not to change this without good reason.
+ */
+#define TALLOC_FLAG_MASK 0x0F
+
 #define TALLOC_MAGIC_REFERENCE ((const char *)1)
 
+#define TALLOC_MAGIC_BASE 0xe814ec70
+static unsigned int talloc_magic = (
+	TALLOC_MAGIC_BASE +
+	(TALLOC_VERSION_MAJOR << 12) +
+	(TALLOC_VERSION_MINOR << 4));
+
 /* by default we abort when given a bad pointer (such as when talloc_free() is called
    on a pointer that came from malloc() */
 #ifndef TALLOC_ABORT
@@ -249,13 +259,13 @@ typedef int (*talloc_destructor_t)(void *);
 struct talloc_pool_hdr;
 
 struct talloc_chunk {
+	unsigned flags;
 	struct talloc_chunk *next, *prev;
 	struct talloc_chunk *parent, *child;
 	struct talloc_reference_handle *refs;
 	talloc_destructor_t destructor;
 	const char *name;
 	size_t size;
-	unsigned flags;
 
 	/*
 	 * limit semantics:
@@ -290,6 +300,11 @@ _PUBLIC_ int talloc_version_minor(void)
 	return TALLOC_VERSION_MINOR;
 }
 
+_PUBLIC_ int talloc_test_get_magic(void)
+{
+	return talloc_magic;
+}
+
 static void (*talloc_log_fn)(const char *message);
 
 _PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message))
@@ -297,6 +312,50 @@ _PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message))
 	talloc_log_fn = log_fn;
 }
 
+#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
+void talloc_lib_init(void) __attribute__((constructor));
+void talloc_lib_init(void)
+{
+	uint32_t random_value;
+#if defined(HAVE_GETAUXVAL) && defined(AT_RANDOM)
+	uint8_t *p;
+	/*
+	 * Use the kernel-provided random values used for
+	 * ASLR.  This won't change per-exec, which is ideal for us
+	 */
+	p = (uint8_t *) getauxval(AT_RANDOM);
+	if (p) {
+		/*
+		 * We get 16 bytes from getauxval.  By calling rand(),
+		 * a totally insecure PRNG, but one that will
+		 * deterministically have a different value when called
+		 * twice, we ensure that if two talloc-like libraries
+		 * are somehow loaded in the same address space, that
+		 * because we choose different bytes, we will keep the
+		 * protection against collision of multiple talloc
+		 * libs.
+		 *
+		 * This protection is important because the effects of
+		 * passing a talloc pointer from one to the other may
+		 * be very hard to determine.
+		 */
+		int offset = rand() % (16 - sizeof(random_value));
+		memcpy(&random_value, p + offset, sizeof(random_value));
+	} else
+#endif
+	{
+		/*
+		 * Otherwise, hope the location we are loaded in
+		 * memory is randomised by someone else
+		 */
+		random_value = ((uintptr_t)talloc_lib_init & 0xFFFFFFFF);
+	}
+	talloc_magic = random_value & ~TALLOC_FLAG_MASK;
+}
+#else
+#warning "No __attribute__((constructor)) support found on this platform, additional talloc security measures not available"
+#endif
+
 static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
 static void talloc_log(const char *fmt, ...)
 {
@@ -345,12 +404,6 @@ static void talloc_abort(const char *reason)
 
 static void talloc_abort_magic(unsigned magic)
 {
-	unsigned striped = magic - TALLOC_MAGIC_BASE;
-	unsigned major = (striped & 0xFFFFF000) >> 12;
-	unsigned minor = (striped & 0x00000FF0) >> 4;
-	talloc_log("Bad talloc magic[0x%08X/%u/%u] expected[0x%08X/%u/%u]\n",
-		   magic, major, minor,
-		   TALLOC_MAGIC, TALLOC_VERSION_MAJOR, TALLOC_VERSION_MINOR);
 	talloc_abort("Bad talloc magic value - wrong talloc version used/mixed");
 }
 
@@ -369,9 +422,9 @@ static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
 {
 	const char *pp = (const char *)ptr;
 	struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
-	if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
-		if ((tc->flags & (~0xFFF)) == TALLOC_MAGIC_BASE) {
-			talloc_abort_magic(tc->flags & (~0xF));
+	if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK)) != talloc_magic)) {
+		if ((tc->flags & (~0xF)) == talloc_magic) {
+			talloc_abort_magic(tc->flags & (~TALLOC_FLAG_MASK));
 			return NULL;
 		}
 
@@ -561,7 +614,7 @@ static inline struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent
 
 	pool_hdr->end = (void *)((char *)pool_hdr->end + chunk_size);
 
-	result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
+	result->flags = talloc_magic | TALLOC_FLAG_POOLMEM;
 	result->pool = pool_hdr;
 
 	pool_hdr->object_count++;
@@ -617,7 +670,7 @@ static inline void *__talloc_with_prefix(const void *context, size_t size,
 			return NULL;
 		}
 		tc = (struct talloc_chunk *)(ptr + prefix_len);
-		tc->flags = TALLOC_MAGIC;
+		tc->flags = talloc_magic;
 		tc->pool  = NULL;
 
 		talloc_memlimit_grow(limit, total_len);
diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h
index 5ece54d..b0917b5 100644
--- a/lib/talloc/talloc.h
+++ b/lib/talloc/talloc.h
@@ -47,6 +47,8 @@ extern "C" {
 
 int talloc_version_major(void);
 int talloc_version_minor(void);
+/* This is mostly useful only for testing */
+int talloc_test_get_magic(void);
 
 /**
  * @brief Define a talloc parent type
@@ -749,7 +751,7 @@ type *talloc_get_type(const void *ptr, #type);
  * @brief Safely turn a void pointer into a typed pointer.
  *
  * This macro is used together with talloc(mem_ctx, struct foo). If you had to
- * assing the talloc chunk pointer to some void pointer variable,
+ * assign the talloc chunk pointer to some void pointer variable,
  * talloc_get_type_abort() is the recommended way to get the convert the void
  * pointer back to a typed pointer.
  *
diff --git a/lib/talloc/test_magic_differs.sh b/lib/talloc/test_magic_differs.sh
new file mode 100755
index 0000000..1b6ba2e
--- /dev/null
+++ b/lib/talloc/test_magic_differs.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# This test ensures that two different talloc processes do not use the same
+# magic value to lessen the opportunity for transferrable attacks.
+
+echo "test: magic differs"
+
+helper=$1
+m1=$($helper)
+m2=$($helper)
+
+if [ $m1 -eq $m2 ]; then
+	echo "failure: magic remained the same between executions ($m1 vs $m2)"
+	exit 1
+fi
+
+echo "success: magic differs"
diff --git a/lib/talloc/test_magic_differs_helper.c b/lib/talloc/test_magic_differs_helper.c
new file mode 100644
index 0000000..6798827
--- /dev/null
+++ b/lib/talloc/test_magic_differs_helper.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include "talloc.h"
+
+/*
+ * This program is called by a testing shell script in order to ensure that
+ * if the library is loaded into different processes it uses different magic
+ * values in order to thwart security attacks.
+ */
+int main(int argc, char *argv[]) {
+	printf("%i\n", talloc_test_get_magic());
+	return 0;
+}
diff --git a/lib/talloc/test_pytalloc.c b/lib/talloc/test_pytalloc.c
index f66b4e5..a7c31c1 100644
--- a/lib/talloc/test_pytalloc.c
+++ b/lib/talloc/test_pytalloc.c
@@ -42,24 +42,53 @@ static PyObject *testpytalloc_get_object_type(PyObject *mod) {
 	return type;
 }
 
+static PyObject *testpytalloc_base_new(PyTypeObject *mod)
+{
+	char *obj = talloc_strdup(NULL, "This is a test string for a BaseObject");;
+	return pytalloc_steal(pytalloc_GetBaseObjectType(), obj);
+}
+
+static PyObject *testpytalloc_base_get_object_type(PyObject *mod) {
+	PyObject *type = (PyObject *)pytalloc_GetBaseObjectType();
+	Py_INCREF(type);
+	return type;
+}
+
 static PyObject *testpytalloc_reference(PyObject *mod, PyObject *args) {
-	pytalloc_Object *source = NULL;
+	PyObject *source = NULL;
 	void *ptr;
 
 	if (!PyArg_ParseTuple(args, "O!", pytalloc_GetObjectType(), &source))
 		return NULL;
 
-	ptr = source->ptr;
+	ptr = pytalloc_get_ptr(source);
 	return pytalloc_reference_ex(pytalloc_GetObjectType(), ptr, ptr);
 }
 
+static PyObject *testpytalloc_base_reference(PyObject *mod, PyObject *args) {
+	PyObject *source = NULL;
+	void *mem_ctx;
+
+	if (!PyArg_ParseTuple(args, "O!", pytalloc_GetBaseObjectType(), &source)) {
+		return NULL;
+	}
+	mem_ctx = pytalloc_get_mem_ctx(source);
+	return pytalloc_reference_ex(pytalloc_GetBaseObjectType(), mem_ctx, mem_ctx);
+}
+
 static PyMethodDef test_talloc_methods[] = {
 	{ "new", (PyCFunction)testpytalloc_new, METH_NOARGS,
 		"create a talloc Object with a testing string"},
 	{ "get_object_type", (PyCFunction)testpytalloc_get_object_type, METH_NOARGS,
 		"call pytalloc_GetObjectType"},
+	{ "base_new", (PyCFunction)testpytalloc_base_new, METH_NOARGS,
+		"create a talloc BaseObject with a testing string"},
+	{ "base_get_object_type", (PyCFunction)testpytalloc_base_get_object_type, METH_NOARGS,
+		"call pytalloc_GetBaseObjectType"},
 	{ "reference", (PyCFunction)testpytalloc_reference, METH_VARARGS,
 		"call pytalloc_reference_ex"},
+	{ "base_reference", (PyCFunction)testpytalloc_base_reference, METH_VARARGS,
+		"call pytalloc_reference_ex"},
 	{ NULL }
 };
 
@@ -104,6 +133,46 @@ static PyTypeObject DObject_Type = {
 	.tp_doc = "test talloc object that calls a function when underlying data is freed\n",
 };
 
+static PyTypeObject DBaseObject_Type;
+
+static int d_base_object_destructor(void *ptr)
+{
+	PyObject *destructor_func = *talloc_get_type(ptr, PyObject*);
+	PyObject *ret;
+	ret = PyObject_CallObject(destructor_func, NULL);
+	Py_DECREF(destructor_func);
+	if (ret == NULL) {
+		PyErr_Print();
+	} else {
+		Py_DECREF(ret);
+	}
+	return 0;
+}
+
+static PyObject *d_base_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+	PyObject *destructor_func = NULL;
+	PyObject **obj;
+
+	if (!PyArg_ParseTuple(args, "O", &destructor_func))
+		return NULL;
+	Py_INCREF(destructor_func);
+
+	obj = talloc(NULL, PyObject*);
+	*obj = destructor_func;
+
+	talloc_set_destructor((void*)obj, d_base_object_destructor);
+	return pytalloc_steal(&DBaseObject_Type, obj);
+}
+
+static PyTypeObject DBaseObject_Type = {
+	.tp_name = "_test_pytalloc.DBaseObject",
+	.tp_methods = NULL,
+	.tp_new = d_base_object_new,
+	.tp_flags = Py_TPFLAGS_DEFAULT,
+	.tp_doc = "test talloc object that calls a function when underlying data is freed\n",
+};
+
 #define MODULE_DOC PyDoc_STR("Test utility module for pytalloc")
 
 #if PY_MAJOR_VERSION >= 3
@@ -126,6 +195,12 @@ static PyObject *module_init(void)
 		return NULL;
 	}
 
+	DBaseObject_Type.tp_basicsize = pytalloc_BaseObject_size();
+	DBaseObject_Type.tp_base = pytalloc_GetBaseObjectType();
+	if (PyType_Ready(&DBaseObject_Type) < 0) {
+		return NULL;
+	}
+
 #if PY_MAJOR_VERSION >= 3
 	m = PyModule_Create(&moduledef);
 #else
@@ -140,6 +215,10 @@ static PyObject *module_init(void)
 	Py_INCREF(DObject_Type.tp_base);
 	PyModule_AddObject(m, "DObject", (PyObject *)&DObject_Type);
 
+	Py_INCREF(&DBaseObject_Type);
+	Py_INCREF(DBaseObject_Type.tp_base);
+	PyModule_AddObject(m, "DBaseObject", (PyObject *)&DBaseObject_Type);
+
 	return m;
 }
 
diff --git a/lib/talloc/test_pytalloc.py b/lib/talloc/test_pytalloc.py
index a613373..2e58d28 100644
--- a/lib/talloc/test_pytalloc.py
+++ b/lib/talloc/test_pytalloc.py
@@ -43,6 +43,12 @@ class TallocTests(unittest.TestCase):
         self.assertTrue(repr(obj).startswith(prefix))
         self.assertEqual(repr(obj), str(obj))
 
+    def test_base_repr(self):
+        obj = _test_pytalloc.base_new()
+        prefix = '<talloc.BaseObject talloc based object at'
+        self.assertTrue(repr(obj).startswith(prefix))
+        self.assertEqual(repr(obj), str(obj))
+
     def test_destructor(self):
         # Check correct lifetime of the talloc'd data
         lst = []
@@ -52,6 +58,15 @@ class TallocTests(unittest.TestCase):
         gc.collect()
         self.assertEqual(lst, ['dead'])
 
+    def test_base_destructor(self):
+        # Check correct lifetime of the talloc'd data
+        lst = []
+        obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
+        self.assertEqual(lst, [])
+        del obj
+        gc.collect()
+        self.assertEqual(lst, ['dead'])
+
 
 class TallocComparisonTests(unittest.TestCase):
 
@@ -94,13 +109,54 @@ class TallocComparisonTests(unittest.TestCase):
         self.assertFalse(obj1 >= obj2)
         self.assertFalse(obj1 > obj2)
 
+class TallocBaseComparisonTests(unittest.TestCase):
+
+    def test_compare_same(self):
+        obj1 = _test_pytalloc.base_new()
+        self.assertTrue(obj1 == obj1)
+        self.assertFalse(obj1 != obj1)
+        self.assertTrue(obj1 <= obj1)
+        self.assertFalse(obj1 < obj1)
+        self.assertTrue(obj1 >= obj1)
+        self.assertFalse(obj1 > obj1)
+
+    def test_compare_different(self):
+        # object comparison is consistent
+        obj1, obj2 = sorted([
+            _test_pytalloc.base_new(),
+            _test_pytalloc.base_new()])
+        self.assertFalse(obj1 == obj2)
+        self.assertTrue(obj1 != obj2)
+        self.assertTrue(obj1 <= obj2)
+        self.assertTrue(obj1 < obj2)
+        self.assertFalse(obj1 >= obj2)
+        self.assertFalse(obj1 > obj2)
+
+    def test_compare_different_types(self):
+        # object comparison falls back to comparing types
+        if sys.version_info >= (3, 0):
+            # In Python 3, types are unorderable -- nothing to test
+            return
+        if talloc.BaseObject < _test_pytalloc.DBaseObject:
+            obj1 = _test_pytalloc.base_new()
+            obj2 = _test_pytalloc.DBaseObject(dummy_func)
+        else:
+            obj2 = _test_pytalloc.base_new()
+            obj1 = _test_pytalloc.DBaseObject(dummy_func)
+        self.assertFalse(obj1 == obj2)
+        self.assertTrue(obj1 != obj2)
+        self.assertTrue(obj1 <= obj2)
+        self.assertTrue(obj1 < obj2)
+        self.assertFalse(obj1 >= obj2)
+        self.assertFalse(obj1 > obj2)
+
 
 class TallocUtilTests(unittest.TestCase):
 
     def test_get_type(self):
         self.assertTrue(talloc.Object is _test_pytalloc.get_object_type())
 
-    def test_refrence(self):
+    def test_reference(self):
         # Check correct lifetime of the talloc'd data with multiple references
         lst = []
         obj = _test_pytalloc.DObject(lambda: lst.append('dead'))
@@ -112,6 +168,21 @@ class TallocUtilTests(unittest.TestCase):
         gc.collect()
         self.assertEqual(lst, ['dead'])
 
+    def test_get_base_type(self):
+        self.assertTrue(talloc.BaseObject is _test_pytalloc.base_get_object_type())
+
+    def test_base_reference(self):
+        # Check correct lifetime of the talloc'd data with multiple references
+        lst = []
+        obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
+        ref = _test_pytalloc.base_reference(obj)
+        del obj
+        gc.collect()
+        self.assertEqual(lst, [])
+        del ref
+        gc.collect()
+        self.assertEqual(lst, ['dead'])
+
 
 if __name__ == '__main__':
     unittest.TestProgram()
diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
index 6d0fe94..34410b8 100644
--- a/lib/talloc/testsuite.c
+++ b/lib/talloc/testsuite.c
@@ -31,6 +31,9 @@
 #include <pthread.h>
 #endif
 
+#include <unistd.h>
+#include <sys/wait.h>
+
 #include "talloc_testsuite.h"
 
 static struct timeval timeval_current(void)
@@ -1747,6 +1750,7 @@ static void *thread_fn(void *arg)
 		ret = pthread_cond_wait(&condvar, &mtx);
 		if (ret != 0) {
 			talloc_free(top_ctx);
+			pthread_mutex_unlock(&mtx);
 			return NULL;
 		}
 	}
@@ -1827,6 +1831,7 @@ static bool test_pthread_talloc_passing(void)
 				printf("pthread_cond_wait %d failed (%d)\n", i,
 					ret);
 				talloc_free(mem_ctx);
+				pthread_mutex_unlock(&mtx);
 				return false;
 			}
 		}
@@ -1850,6 +1855,70 @@ static bool test_pthread_talloc_passing(void)
 }
 #endif
 
+static void test_magic_protection_abort(const char *reason)
+{
+	/* exit with errcode 42 to communicate successful test to the parent process */
+	if (strcmp(reason, "Bad talloc magic value - unknown value") == 0) {
+		_exit(42);
+	} else {
+		printf("talloc aborted for an unexpected reason\n");
+	}
+}
+
+static bool test_magic_protection(void)
+{
+	void *pool = talloc_pool(NULL, 1024);
+	int *p1, *p2;
+	pid_t pid;
+	int exit_status;
+
+	printf("test: magic_protection\n");
+	p1 = talloc(pool, int);
+	p2 = talloc(pool, int);
+
+	/* To avoid complaints from the compiler assign values to the p1 & p2. */
+	*p1 = 6;
+	*p2 = 9;
+
+	pid = fork();
+	if (pid == 0) {
+		talloc_set_abort_fn(test_magic_protection_abort);
+
+		/*
+		 * Simulate a security attack
+		 * by triggering a buffer overflow in memset to overwrite the
+		 * constructor in the next pool chunk.
+		 *
+		 * Real attacks would attempt to set a real destructor.
+		 */
+		memset(p1, '\0', 32);
+
+		/* Then the attack takes effect when the memory's freed. */
+		talloc_free(pool);
+
+		/* Never reached. Make compilers happy */
+		return true;
+	}
+
+	while (wait(&exit_status) != pid);
+
+	if (!WIFEXITED(exit_status)) {
+		printf("Child exited through unexpected abnormal means\n");
+		return false;
+	}
+	if (WEXITSTATUS(exit_status) != 42) {
+		printf("Child exited with wrong exit status\n");
+		return false;
+	}
+	if (WIFSIGNALED(exit_status)) {
+		printf("Child recieved unexpected signal\n");
+		return false;
+	}
+
+	printf("success: magic_protection\n");
+	return true;
+}
+
 static void test_reset(void)
 {
 	talloc_set_log_fn(test_log_stdout);
@@ -1932,6 +2001,8 @@ bool torture_local_talloc(struct torture_context *tctx)
 	}
 	test_reset();
 	ret &= test_autofree();
+	test_reset();
+	ret &= test_magic_protection();
 
 	test_reset();
 	talloc_disable_null_tracking();
diff --git a/lib/talloc/wscript b/lib/talloc/wscript
index bbe0cb1..ae0b227 100644
--- a/lib/talloc/wscript
+++ b/lib/talloc/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'talloc'
-VERSION = '2.1.3'
+VERSION = '2.1.6'
 
 
 blddir = 'bin'
@@ -66,6 +66,9 @@ def configure(conf):
             Logs.warn('Disabling pytalloc-util as python devel libs not found')
             conf.env.disable_python = True
 
+    conf.CHECK_HEADERS('sys/auxv.h')
+    conf.CHECK_FUNCS('getauxval')
+
     conf.SAMBA_CONFIG_H()
 
     conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
@@ -97,6 +100,10 @@ def build(bld):
                          testsuite_deps,
                          install=False)
 
+        bld.SAMBA_BINARY('talloc_test_magic_differs_helper',
+                         'test_magic_differs_helper.c',
+                         'talloc', install=False)
+
     else:
         private_library = True
 
@@ -109,7 +116,7 @@ def build(bld):
                           abi_match='talloc* _talloc*',
                           hide_symbols=True,
                           vnum=VERSION,
-                          public_headers='talloc.h',
+                          public_headers=('' if private_library else 'talloc.h'),
                           pc_files='talloc.pc',
                           public_headers_install=not private_library,
                           private_library=private_library,
@@ -126,9 +133,9 @@ def build(bld):
                 vnum=VERSION,
                 hide_symbols=True,
                 abi_directory='ABI',
-                abi_match='pytalloc_*',
+                abi_match='pytalloc_* _pytalloc_*',
                 private_library=private_library,
-                public_headers='pytalloc.h',
+                public_headers=('' if private_library else 'pytalloc.h'),
                 pc_files='pytalloc-util.pc'
                 )
             bld.SAMBA_PYTHON('pytalloc',
@@ -151,9 +158,15 @@ def test(ctx):
     cmd = os.path.join(Utils.g_module.blddir, 'talloc_testsuite')
     ret = samba_utils.RUN_COMMAND(cmd)
     print("testsuite returned %d" % ret)
+    magic_helper_cmd = os.path.join(Utils.g_module.blddir, 'talloc_test_magic_differs_helper')
+    magic_cmd = os.path.join(srcdir, 'lib', 'talloc',
+                             'test_magic_differs.sh')
+
+    magic_ret = samba_utils.RUN_COMMAND(magic_cmd + " " +  magic_helper_cmd)
+    print("magic differs test returned %d" % magic_ret)
     pyret = samba_utils.RUN_PYTHON_TESTS(['test_pytalloc.py'])
     print("python testsuite returned %d" % pyret)
-    sys.exit(ret or pyret)
+    sys.exit(ret or magic_ret or pyret)
 
 def dist():
     '''makes a tarball for distribution'''
diff --git a/lib/tdb/ABI/tdb-1.3.8.sigs b/lib/tdb/ABI/tdb-1.3.8.sigs
new file mode 100644
index 0000000..2545c99
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.8.sigs
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/common/open.c b/lib/tdb/common/open.c
index 3b53fa7..f3ef856 100644
--- a/lib/tdb/common/open.c
+++ b/lib/tdb/common/open.c
@@ -593,6 +593,13 @@ _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int td
 		errno = ENOSYS;
 		goto fail;
 	}
+
+	if (header.hash_size == 0) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: invalid database: 0 hash_size\n"));
+		errno = ENOSYS;
+		goto fail;
+	}
+
 	tdb->hash_size = header.hash_size;
 
 	if (header.rwlocks == TDB_FEATURE_FLAG_MAGIC) {
diff --git a/lib/tdb/docs/mutex.txt b/lib/tdb/docs/mutex.txt
index 7625662..a5a7542 100644
--- a/lib/tdb/docs/mutex.txt
+++ b/lib/tdb/docs/mutex.txt
@@ -8,11 +8,11 @@ forming a linked list of records that share a hash value. The individual
 linked lists are protected across processes with 1-byte fcntl locks on the
 starting pointer of the linked list representing a hash value.
 
-The external locking API of tdb allows to lock individual records. Instead of
+The external locking API of tdb allows one to lock individual records. Instead of
 really locking individual records, the tdb API locks a complete linked list
 with a fcntl lock.
 
-The external locking API of tdb also allows to lock the complete database, and
+The external locking API of tdb also allows one to lock the complete database, and
 ctdb uses this facility to freeze databases during a recovery. While the
 so-called allrecord lock is held, all linked lists and all individual records
 are frozen alltogether. Tdb achieves this by locking the complete file range
diff --git a/lib/tdb/wscript b/lib/tdb/wscript
index 1822e74..e5c0ead 100644
--- a/lib/tdb/wscript
+++ b/lib/tdb/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'tdb'
-VERSION = '1.3.7'
+VERSION = '1.3.8'
 
 blddir = 'bin'
 
@@ -138,7 +138,7 @@ def build(bld):
                           abi_match='tdb_*',
                           hide_symbols=True,
                           vnum=VERSION,
-                          public_headers='include/tdb.h',
+                          public_headers=('' if private_library else 'include/tdb.h'),
                           public_headers_install=not private_library,
                           pc_files='tdb.pc',
                           private_library=private_library)
diff --git a/lib/tdb_wrap/tdb_wrap.c b/lib/tdb_wrap/tdb_wrap.c
index a1bddf3..864656f 100644
--- a/lib/tdb_wrap/tdb_wrap.c
+++ b/lib/tdb_wrap/tdb_wrap.c
@@ -90,19 +90,15 @@ static struct tdb_wrap_private *tdb_wrap_private_open(TALLOC_CTX *mem_ctx,
 						      mode_t mode)
 {
 	struct tdb_wrap_private *result;
-	struct tdb_logging_context lctx;
+	struct tdb_logging_context lctx = { .log_fn = tdb_wrap_log };
 
-	result = talloc(mem_ctx, struct tdb_wrap_private);
+	result = talloc_pooled_object(mem_ctx, struct tdb_wrap_private,
+				      1, strlen(name)+1);
 	if (result == NULL) {
 		return NULL;
 	}
+	/* Doesn't fail, see talloc_pooled_object */
 	result->name = talloc_strdup(result, name);
-	if (result->name == NULL) {
-		goto fail;
-	}
-
-	lctx.log_fn = tdb_wrap_log;
-	lctx.log_private = NULL;
 
 	result->tdb = tdb_open_ex(name, hash_size, tdb_flags,
 				  open_flags, mode, &lctx, NULL);
diff --git a/lib/tevent/ABI/tevent-0.9.26.sigs b/lib/tevent/ABI/tevent-0.9.26.sigs
new file mode 100644
index 0000000..1357751
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.26.sigs
@@ -0,0 +1,90 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.27.sigs b/lib/tevent/ABI/tevent-0.9.27.sigs
new file mode 100644
index 0000000..1357751
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.27.sigs
@@ -0,0 +1,90 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.28.sigs b/lib/tevent/ABI/tevent-0.9.28.sigs
new file mode 100644
index 0000000..1357751
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.28.sigs
@@ -0,0 +1,90 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/doc/tevent_thread.dox b/lib/tevent/doc/tevent_thread.dox
new file mode 100644
index 0000000..7b45820
--- /dev/null
+++ b/lib/tevent/doc/tevent_thread.dox
@@ -0,0 +1,322 @@
+/**
+ at page tevent_context Chapter 6: Tevent with threads
+
+ at section context Tevent with threads
+
+In order to use tevent with threads, you must first understand
+how to use the talloc library in threaded programs. For more
+information about working with talloc, please visit <a
+href="https://talloc.samba.org/">talloc website</a> where tutorial and
+documentation are located.
+
+If a tevent context structure is talloced from a NULL, thread-safe talloc
+context, then it can be safe to use in a threaded program. The function
+<code>talloc_disable_null_tracking()</code> <b>must</b> be called from the initial
+program thread before any talloc calls are made to ensure talloc is thread-safe.
+
+Each thread must create it's own tevent context structure as follows
+<code>tevent_context_init(NULL)</code> and no talloc memory contexts
+can be shared between threads.
+
+Separate threads using tevent in this way can communicate
+by writing data into file descriptors that are being monitored
+by a tevent context on another thread. For example (simplified
+with no error handling):
+
+ at code
+Main thread:
+
+main()
+{
+	talloc_disable_null_tracking();
+
+	struct tevent_context *master_ev = tevent_context_init(NULL);
+	void *mem_ctx = talloc_new(master_ev);
+
+	// Create file descriptor to monitor.
+	int pipefds[2];
+
+	pipe(pipefds);
+
+	struct tevent_fd *fde = tevent_add_fd(master_ev,
+				mem_ctx,
+				pipefds[0], // read side of pipe
+				TEVENT_FD_READ,
+				pipe_read_handler, // callback function
+				private_data_pointer);
+
+	// Create sub thread, pass pipefds[1] write side of pipe to it.
+	// The above code not shown here..
+
+	// Process events.
+	tevent_loop_wait(master_ev);
+
+	// Cleanup if loop exits.
+	talloc_free(master_ev);
+}
+
+ at endcode
+
+When the subthread writes to pipefds[1], the function
+<code>pipe_read_handler()</code> will be called in the main thread.
+
+ at subsection More sophisticated use
+
+A popular way to use an event library within threaded programs
+is to allow a sub-thread to asynchronously schedule a tevent_immediate
+function call from the event loop of another thread. This can be built
+out of the basic functions and isolation mechanisms of tevent,
+but tevent also comes with some utility functions that make
+this easier, so long as you understand the limitations that
+using threads with talloc and tevent impose.
+
+To allow a tevent context to receive an asynchronous tevent_immediate
+function callback from another thread, create a struct tevent_thread_proxy *
+by calling @code
+
+struct tevent_thread_proxy *tevent_thread_proxy_create(
+                struct tevent_context *dest_ev_ctx);
+
+ at endcode
+
+This function allocates the internal data structures to
+allow asynchronous callbacks as a talloc child of the
+struct tevent_context *, and returns a struct tevent_thread_proxy *
+that can be passed to another thread.
+
+When you have finished receiving asynchronous callbacks, simply
+talloc_free the struct tevent_thread_proxy *, or talloc_free
+the struct tevent_context *, which will deallocate the resources
+used.
+
+To schedule an asynchronous tevent_immediate function call from one
+thread on the tevent loop of another thread, use
+ at code
+
+void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
+                                struct tevent_immediate **pp_im,
+                                tevent_immediate_handler_t handler,
+                                void **pp_private_data);
+
+ at endcode
+
+This function causes the function <code>handler()</code>
+to be invoked as a tevent_immediate callback from the event loop
+of the thread that created the struct tevent_thread_proxy *
+(so the owning <code>struct tevent_context *</code> should be
+long-lived and not in the process of being torn down).
+
+The <code>struct tevent_thread_proxy</code> object being
+used here is a child of the event context of the target
+thread. So external synchronization mechanisms must be
+used to ensure that the target object is still in use
+at the time of the <code>tevent_thread_proxy_schedule()</code>
+call. In the example below, the request/response nature
+of the communication ensures this.
+
+The <code>struct tevent_immediate **pp_im</code> passed into this function
+should be a struct tevent_immediate * allocated on a talloc context
+local to this thread, and will be reparented via talloc_move
+to be owned by <code>struct tevent_thread_proxy *tp</code>.
+<code>*pp_im</code> will be set to NULL on successful scheduling
+of the tevent_immediate call.
+
+<code>handler()</code> will be called as a normal tevent_immediate
+callback from the <code>struct tevent_context *</code> of the destination
+event loop that created the <code>struct tevent_thread_proxy *</code>
+
+Returning from this functions does not mean that the <code>handler</code>
+has been invoked, merely that it has been scheduled to be called in the
+destination event loop.
+
+Because the calling thread does not wait for the
+callback to be scheduled and run on the destination
+thread, this is a fire-and-forget call. If you wish
+confirmation of the <code>handler()</code> being
+successfully invoked, you must ensure it replies to the
+caller in some way.
+
+Because of asynchronous nature of this call, the nature
+of the parameter passed to the destination thread has some
+restructions. If you don't need parameters, merely pass
+<code>NULL</code> as the value of
+<code>void **pp_private_data</code>.
+
+If you wish to pass a pointer to data between the threads,
+it <b>MUST</b> be a pointer to a talloced pointer, which is
+not part of a talloc-pool, and it must not have a destructor
+attached. The ownership of the memory pointed to will
+be passed from the calling thread to the tevent library,
+and if the receiving thread does not talloc-reparent
+it to its own contexts, it will be freed once the
+<code>handler</code> is called.
+
+On success, <code>*pp_private</code> will be <code>NULL</code>
+to signify the talloc memory ownership has been moved.
+
+In practice for message passing between threads in
+event loops these restrictions are not very onerous.
+
+The easiest way to to a request-reply pair between
+tevent loops on different threads is to pass the
+parameter block of memory back and forth using
+a reply <code>tevent_thread_proxy_schedule()</code>
+call.
+
+Here is an example (without error checking for
+simplicity):
+
+ at code
+------------------------------------------------
+// Master thread.
+
+main()
+{
+	// Make talloc thread-safe.
+
+	talloc_disable_null_tracking();
+
+	// Create the master event context.
+
+	struct tevent_context *master_ev = tevent_context_init(NULL);
+
+	// Create the master thread proxy to allow it to receive
+	// async callbacks from other threads.
+
+	struct tevent_thread_proxy *master_tp =
+			tevent_thread_proxy_create(master_ev);
+
+	// Create sub-threads, passing master_tp in
+	// some way to them.
+	// This code not shown..
+
+	// Process events.
+	// Function master_callback() below
+	// will be invoked on this thread on
+	// master_ev event context.
+
+	tevent_loop_wait(master_ev);
+
+	// Cleanup if loop exits.
+
+	talloc_free(master_ev);
+}
+
+// Data passed between threads.
+struct reply_state {
+	struct tevent_thread_proxy *reply_tp;
+	pthread_t thread_id;
+	bool *p_finished;
+};
+
+// Callback Called in child thread context.
+
+static void thread_callback(struct tevent_context *ev,
+                                struct tevent_immediate *im,
+                                void *private_ptr)
+{
+	// Move the ownership of what private_ptr
+	// points to from the tevent library back to this thread.
+
+	struct reply_state *rsp =
+		talloc_get_type_abort(private_ptr, struct reply_state);
+
+	talloc_steal(ev, rsp);
+
+	*rsp->p_finished = true;
+
+	// im will be talloc_freed on return from this call.
+	// but rsp will not.
+}
+
+// Callback Called in master thread context.
+
+static void master_callback(struct tevent_context *ev,
+                                struct tevent_immediate *im,
+                                void *private_ptr)
+{
+	// Move the ownership of what private_ptr
+	// points to from the tevent library to this thread.
+
+	struct reply_state *rsp =
+		talloc_get_type_abort(private_ptr, struct reply_state);
+
+	talloc_steal(ev, rsp);
+
+	printf("Callback from thread %s\n", thread_id_to_string(rsp->thread_id));
+
+	/* Now reply to the thread ! */
+	tevent_thread_proxy_schedule(rsp->reply_tp,
+				&im,
+				thread_callback,
+				&rsp);
+
+	// Note - rsp and im are now NULL as the tevent library
+	// owns the memory.
+}
+
+// Child thread.
+
+static void *thread_fn(void *private_ptr)
+{
+	struct tevent_thread_proxy *master_tp =
+		talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+	bool finished = false;
+	int ret;
+
+	// Create our own event context.
+
+	struct tevent_context *ev = tevent_context_init(NULL);
+
+	// Create the local thread proxy to allow us to receive
+	// async callbacks from other threads.
+
+	struct tevent_thread_proxy *local_tp =
+			tevent_thread_proxy_create(master_ev);
+
+	// Setup the data to send.
+
+	struct reply_state *rsp = talloc(ev, struct reply_state);
+
+	rsp->reply_tp = local_tp;
+	rsp->thread_id = pthread_self();
+	rsp->p_finished = &finished;
+
+	// Create the immediate event to use.
+
+	struct tevent_immediate *im = tevent_create_immediate(ev);
+
+	// Call the master thread.
+
+	tevent_thread_proxy_schedule(master_tp,
+				&im,
+				master_callback,
+				&rsp);
+
+	// Note - rsp and im are now NULL as the tevent library
+	// owns the memory.
+
+	// Wait for the reply.
+
+	while (!finished) {
+		tevent_loop_once(ev);
+	}
+
+	// Cleanup.
+
+	talloc_free(ev);
+	return NULL;
+}
+
+ at endcode
+
+Note this doesn't have to be a master-subthread communication.
+Any thread that has access to the <code>struct tevent_thread_proxy *</code>
+pointer of another thread that has called <code>tevent_thread_proxy_create()
+</code> can send an async tevent_immediate request.
+
+But remember the caveat that external synchronization must be used
+to ensure the target <code>struct tevent_thread_proxy *</code> object
+exists at the time of the <code>tevent_thread_proxy_schedule()</code>
+call or unreproducible crashes will result.
+*/
diff --git a/lib/tevent/doc/tevent_tutorial.dox b/lib/tevent/doc/tevent_tutorial.dox
index 9f01fa1..207a244 100644
--- a/lib/tevent/doc/tevent_tutorial.dox
+++ b/lib/tevent/doc/tevent_tutorial.dox
@@ -17,4 +17,6 @@ Tutorial describing working with tevent library.
 
 @subpage tevent_queue
 
+ at subpage tevent_thread
+
 */
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index c63c878..bcd27fd 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -808,6 +808,327 @@ static bool test_event_context_threaded(struct torture_context *test,
 	return true;
 }
 
+#define NUM_TEVENT_THREADS 100
+
+/* Ugly, but needed for torture_comment... */
+static struct torture_context *thread_test_ctx;
+static pthread_t thread_map[NUM_TEVENT_THREADS];
+static unsigned thread_counter;
+
+/* Called in master thread context */
+static void callback_nowait(struct tevent_context *ev,
+				struct tevent_immediate *im,
+				void *private_ptr)
+{
+	pthread_t *thread_id_ptr =
+		talloc_get_type_abort(private_ptr, pthread_t);
+	unsigned i;
+
+	for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+		if (pthread_equal(*thread_id_ptr,
+				thread_map[i])) {
+			break;
+		}
+	}
+	torture_comment(thread_test_ctx,
+			"Callback %u from thread %u\n",
+			thread_counter,
+			i);
+	thread_counter++;
+}
+
+/* Blast the master tevent_context with a callback, no waiting. */
+static void *thread_fn_nowait(void *private_ptr)
+{
+	struct tevent_thread_proxy *master_tp =
+		talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+	struct tevent_immediate *im;
+	pthread_t *thread_id_ptr;
+
+	im = tevent_create_immediate(NULL);
+	if (im == NULL) {
+		return NULL;
+	}
+	thread_id_ptr = talloc(NULL, pthread_t);
+	if (thread_id_ptr == NULL) {
+		return NULL;
+	}
+	*thread_id_ptr = pthread_self();
+
+	tevent_thread_proxy_schedule(master_tp,
+				&im,
+				callback_nowait,
+				&thread_id_ptr);
+	return NULL;
+}
+
+static void timeout_fn(struct tevent_context *ev,
+			struct tevent_timer *te,
+			struct timeval tv, void *p)
+{
+	thread_counter = NUM_TEVENT_THREADS * 10;
+}
+
+static bool test_multi_tevent_threaded(struct torture_context *test,
+					const void *test_data)
+{
+	unsigned i;
+	struct tevent_context *master_ev;
+	struct tevent_thread_proxy *tp;
+
+	talloc_disable_null_tracking();
+
+	/* Ugly global stuff. */
+	thread_test_ctx = test;
+	thread_counter = 0;
+
+	master_ev = tevent_context_init(NULL);
+	if (master_ev == NULL) {
+		return false;
+	}
+	tevent_set_debug_stderr(master_ev);
+
+	tp = tevent_thread_proxy_create(master_ev);
+	if (tp == NULL) {
+		torture_fail(test,
+			talloc_asprintf(test,
+				"tevent_thread_proxy_create failed\n"));
+		talloc_free(master_ev);
+		return false;
+	}
+
+	for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+		int ret = pthread_create(&thread_map[i],
+				NULL,
+				thread_fn_nowait,
+				tp);
+		if (ret != 0) {
+			torture_fail(test,
+				talloc_asprintf(test,
+					"Failed to create thread %i, %d\n",
+					i, ret));
+			return false;
+		}
+	}
+
+	/* Ensure we don't wait more than 10 seconds. */
+	tevent_add_timer(master_ev,
+			master_ev,
+			timeval_current_ofs(10,0),
+			timeout_fn,
+			NULL);
+
+	while (thread_counter < NUM_TEVENT_THREADS) {
+		int ret = tevent_loop_once(master_ev);
+		torture_assert(test, ret == 0, "tevent_loop_once failed");
+	}
+
+	torture_assert(test, thread_counter == NUM_TEVENT_THREADS,
+		"thread_counter fail\n");
+
+	talloc_free(master_ev);
+	return true;
+}
+
+struct reply_state {
+	struct tevent_thread_proxy *reply_tp;
+	pthread_t thread_id;
+	int *p_finished;
+};
+
+static void thread_timeout_fn(struct tevent_context *ev,
+			struct tevent_timer *te,
+			struct timeval tv, void *p)
+{
+	int *p_finished = (int *)p;
+
+	*p_finished = 2;
+}
+
+/* Called in child-thread context */
+static void thread_callback(struct tevent_context *ev,
+				struct tevent_immediate *im,
+				void *private_ptr)
+{
+	struct reply_state *rsp =
+		talloc_get_type_abort(private_ptr, struct reply_state);
+
+	talloc_steal(ev, rsp);
+	*rsp->p_finished = 1;
+}
+
+/* Called in master thread context */
+static void master_callback(struct tevent_context *ev,
+				struct tevent_immediate *im,
+				void *private_ptr)
+{
+	struct reply_state *rsp =
+		talloc_get_type_abort(private_ptr, struct reply_state);
+	unsigned i;
+
+	talloc_steal(ev, rsp);
+
+	for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+		if (pthread_equal(rsp->thread_id,
+				thread_map[i])) {
+			break;
+		}
+	}
+	torture_comment(thread_test_ctx,
+			"Callback %u from thread %u\n",
+			thread_counter,
+			i);
+	/* Now reply to the thread ! */
+	tevent_thread_proxy_schedule(rsp->reply_tp,
+				&im,
+				thread_callback,
+				&rsp);
+
+	thread_counter++;
+}
+
+static void *thread_fn_1(void *private_ptr)
+{
+	struct tevent_thread_proxy *master_tp =
+		talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+	struct tevent_thread_proxy *tp;
+	struct tevent_immediate *im;
+	struct tevent_context *ev;
+	struct reply_state *rsp;
+	int finished = 0;
+	int ret;
+
+	ev = tevent_context_init(NULL);
+	if (ev == NULL) {
+		return NULL;
+	}
+
+	tp = tevent_thread_proxy_create(ev);
+	if (tp == NULL) {
+		talloc_free(ev);
+		return NULL;
+	}
+
+	im = tevent_create_immediate(ev);
+	if (im == NULL) {
+		talloc_free(ev);
+		return NULL;
+	}
+
+	rsp = talloc(ev, struct reply_state);
+	if (rsp == NULL) {
+		talloc_free(ev);
+		return NULL;
+	}
+
+	rsp->thread_id = pthread_self();
+	rsp->reply_tp = tp;
+	rsp->p_finished = &finished;
+
+	/* Introduce a little randomness into the mix.. */
+	usleep(random() % 7000);
+
+	tevent_thread_proxy_schedule(master_tp,
+				&im,
+				master_callback,
+				&rsp);
+
+	/* Ensure we don't wait more than 10 seconds. */
+	tevent_add_timer(ev,
+			ev,
+			timeval_current_ofs(10,0),
+			thread_timeout_fn,
+			&finished);
+
+	while (finished == 0) {
+		ret = tevent_loop_once(ev);
+		assert(ret == 0);
+	}
+
+	if (finished > 1) {
+		/* Timeout ! */
+		abort();
+	}
+
+	/*
+	 * NB. We should talloc_free(ev) here, but if we do
+	 * we currently get hit by helgrind Fix #323432
+	 * "When calling pthread_cond_destroy or pthread_mutex_destroy
+	 * with initializers as argument Helgrind (incorrectly) reports errors."
+	 *
+	 * http://valgrind.10908.n7.nabble.com/Helgrind-3-9-0-false-positive-
+	 * with-pthread-mutex-destroy-td47757.html
+	 *
+	 * Helgrind doesn't understand that the request/reply
+	 * messages provide synchronization between the lock/unlock
+	 * in tevent_thread_proxy_schedule(), and the pthread_destroy()
+	 * when the struct tevent_thread_proxy object is talloc_free'd.
+	 *
+	 * As a work-around for now return ev for the parent thread to free.
+	 */
+	return ev;
+}
+
+static bool test_multi_tevent_threaded_1(struct torture_context *test,
+					const void *test_data)
+{
+	unsigned i;
+	struct tevent_context *master_ev;
+	struct tevent_thread_proxy *master_tp;
+	int ret;
+
+	talloc_disable_null_tracking();
+
+	/* Ugly global stuff. */
+	thread_test_ctx = test;
+	thread_counter = 0;
+
+	master_ev = tevent_context_init(NULL);
+	if (master_ev == NULL) {
+		return false;
+	}
+	tevent_set_debug_stderr(master_ev);
+
+	master_tp = tevent_thread_proxy_create(master_ev);
+	if (master_tp == NULL) {
+		torture_fail(test,
+			talloc_asprintf(test,
+				"tevent_thread_proxy_create failed\n"));
+		talloc_free(master_ev);
+		return false;
+	}
+
+	for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+		ret = pthread_create(&thread_map[i],
+				NULL,
+				thread_fn_1,
+				master_tp);
+		if (ret != 0) {
+			torture_fail(test,
+				talloc_asprintf(test,
+					"Failed to create thread %i, %d\n",
+					i, ret));
+				return false;
+		}
+	}
+
+	while (thread_counter < NUM_TEVENT_THREADS) {
+		ret = tevent_loop_once(master_ev);
+		torture_assert(test, ret == 0, "tevent_loop_once failed");
+	}
+
+	/* Wait for all the threads to finish - join 'em. */
+	for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+		void *retval;
+		ret = pthread_join(thread_map[i], &retval);
+		torture_assert(test, ret == 0, "pthread_join failed");
+		/* Free the child thread event context. */
+		talloc_free(retval);
+	}
+
+	talloc_free(master_ev);
+	return true;
+}
 #endif
 
 struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
@@ -841,6 +1162,15 @@ struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
 	torture_suite_add_simple_tcase_const(suite, "threaded_poll_mt",
 					     test_event_context_threaded,
 					     NULL);
+
+	torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded",
+					     test_multi_tevent_threaded,
+					     NULL);
+
+	torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded_1",
+					     test_multi_tevent_threaded_1,
+					     NULL);
+
 #endif
 
 	return suite;
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index b6c39d1..cb95507 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -39,6 +39,7 @@ struct tevent_fd;
 struct tevent_timer;
 struct tevent_immediate;
 struct tevent_signal;
+struct tevent_thread_proxy;
 
 /**
  * @defgroup tevent The tevent API
@@ -1698,6 +1699,57 @@ typedef int (*tevent_nesting_hook)(struct tevent_context *ev,
 				   bool begin,
 				   void *stack_ptr,
 				   const char *location);
+
+/**
+ * @brief Create a tevent_thread_proxy for message passing between threads.
+ *
+ * The tevent_context must have been allocated on the NULL
+ * talloc context, and talloc_disable_null_tracking() must
+ * have been called.
+ *
+ * @param[in]  dest_ev_ctx      The tevent_context to receive events.
+ *
+ * @return              An allocated tevent_thread_proxy, NULL on error.
+ *                      If tevent was compiled without PTHREAD support
+ *                      NULL is always returned and errno set to ENOSYS.
+ *
+ * @see tevent_thread_proxy_schedule()
+ */
+struct tevent_thread_proxy *tevent_thread_proxy_create(
+                struct tevent_context *dest_ev_ctx);
+
+/**
+ * @brief Schedule an immediate event on an event context from another thread.
+ *
+ * Causes dest_ev_ctx, being run by another thread, to receive an
+ * immediate event calling the handler with the *pp_private parameter.
+ *
+ * *pp_im must be a pointer to an immediate event talloced on a context owned
+ * by the calling thread, or the NULL context. Ownership will
+ * be transferred to the tevent_thread_proxy and *pp_im will be returned as NULL.
+ *
+ * *pp_private_data must be a talloced area of memory with no destructors.
+ * Ownership of this memory will be transferred to the tevent library and
+ * *pp_private_data will be set to NULL on successful completion of
+ * the call. Set pp_private to NULL if no parameter transfer
+ * needed (a pure callback). This is an asynchronous request, caller
+ * does not wait for callback to be completed before returning.
+ *
+ * @param[in]  tp               The tevent_thread_proxy to use.
+ *
+ * @param[in]  pp_im            Pointer to immediate event pointer.
+ *
+ * @param[in]  handler          The function that will be called.
+ *
+ * @param[in]  pp_private_data  The talloced memory to transfer.
+ *
+ * @see tevent_thread_proxy_create()
+ */
+void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
+				  struct tevent_immediate **pp_im,
+				  tevent_immediate_handler_t handler,
+				  void *pp_private_data);
+
 #ifdef TEVENT_DEPRECATED
 #ifndef _DEPRECATED_
 #if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 )
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 01fcde6..507ea5c 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -216,7 +216,7 @@ static void epoll_update_event(struct epoll_event_context *epoll_ev, struct teve
 
 /*
   reopen the epoll handle when our pid changes
-  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
+  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
   demonstration of why this is needed
  */
 static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
@@ -661,7 +661,7 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
 	}
 
 	for (i=0;i<ret;i++) {
-		struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 
+		struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
 						       struct tevent_fd);
 		uint16_t flags = 0;
 		struct tevent_fd *mpx_fde = NULL;
@@ -888,7 +888,7 @@ static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
 }
 
 /*
-  do a single event loop using the events defined in ev 
+  do a single event loop using the events defined in ev
 */
 static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
 {
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index 1ac293e..9ff5322 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -88,7 +88,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
 	im->cancel_fn		= NULL;
 	im->additional_data	= NULL;
 
-	DLIST_ADD_END(ev->immediate_events, im, struct tevent_immediate *);
+	DLIST_ADD_END(ev->immediate_events, im);
 	talloc_set_destructor(im, tevent_common_immediate_destructor);
 
 	tevent_debug(ev, TEVENT_DEBUG_TRACE,
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 573ba93..e1c305d 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -498,6 +498,7 @@ static int poll_event_loop_poll(struct tevent_context *ev,
 	int timeout = -1;
 	int poll_errno;
 	struct tevent_fd *fde = NULL;
+	struct tevent_fd *next = NULL;
 	unsigned i;
 
 	if (ev->signal_events && tevent_common_check_signal(ev)) {
@@ -542,11 +543,13 @@ static int poll_event_loop_poll(struct tevent_context *ev,
 	   which ones and call the handler, being careful to allow
 	   the handler to remove itself when called */
 
-	for (fde = ev->fd_events; fde; fde = fde->next) {
+	for (fde = ev->fd_events; fde; fde = next) {
 		uint64_t idx = fde->additional_flags;
 		struct pollfd *pfd;
 		uint16_t flags = 0;
 
+		next = fde->next;
+
 		if (idx == UINT64_MAX) {
 			continue;
 		}
@@ -598,7 +601,7 @@ static int poll_event_loop_poll(struct tevent_context *ev,
 		 */
 		flags &= fde->flags;
 		if (flags != 0) {
-			DLIST_DEMOTE(ev->fd_events, fde, struct tevent_fd);
+			DLIST_DEMOTE(ev->fd_events, fde);
 			fde->handler(ev, fde, flags, fde->private_data);
 			return 0;
 		}
diff --git a/lib/tevent/tevent_port.c b/lib/tevent/tevent_port.c
index 5b487d7..4b524df 100644
--- a/lib/tevent/tevent_port.c
+++ b/lib/tevent/tevent_port.c
@@ -496,10 +496,24 @@ static int port_event_loop(struct port_event_context *port_ev, struct timeval *t
 		return 0;
 	}
 
-	if (ret == -1 && port_errno == ETIME && tvalp) {
-		/* we don't care about a possible delay here */
-		tevent_common_loop_timer_delay(ev);
-		return 0;
+	if (ret == -1 && port_errno == ETIME) {
+		/*
+		 * If errno is set to ETIME it is possible that we still got an event.
+		 * In that case we need to go through the processing loop so that we
+		 * reassociate the received event with the port or the association will
+		 * be lost so check the value of nget is 0 before returning.
+		 */
+		if (nget == 0) {
+			/* we don't care about a possible delay here */
+			tevent_common_loop_timer_delay(ev);
+			return 0;
+		}
+		/*
+		 * Set the return value to 0 since we do not actually have an error and we
+		 * do have events that need to be processed.  This keeps us from getting
+		 * caught in the generic error test.
+		 */
+		ret = 0;
 	}
 
 	if (ret == -1) {
diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c
index 35742e5..cefe91a 100644
--- a/lib/tevent/tevent_queue.c
+++ b/lib/tevent/tevent_queue.c
@@ -195,7 +195,7 @@ static struct tevent_queue_entry *tevent_queue_add_internal(
 		allow_direct = false;
 	}
 
-	DLIST_ADD_END(queue->list, e, struct tevent_queue_entry *);
+	DLIST_ADD_END(queue->list, e);
 	queue->length++;
 	talloc_set_destructor(e, tevent_queue_entry_destructor);
 
diff --git a/lib/tevent/tevent_select.c b/lib/tevent/tevent_select.c
index 40a4dc0..ec7565d 100644
--- a/lib/tevent/tevent_select.c
+++ b/lib/tevent/tevent_select.c
@@ -219,7 +219,7 @@ static int select_event_loop_select(struct select_event_context *select_ev, stru
 				flags |= TEVENT_FD_WRITE;
 			}
 			if (flags) {
-				DLIST_DEMOTE(select_ev->ev->fd_events, fde, struct tevent_fd);
+				DLIST_DEMOTE(select_ev->ev->fd_events, fde);
 				fde->handler(select_ev->ev, fde, flags, fde->private_data);
 				break;
 			}
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 924dc05..9bc11ed 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -212,6 +212,7 @@ static int tevent_signal_destructor(struct tevent_signal *se)
 		/* restore old handler, if any */
 		if (sig_state->oldact[se->signum]) {
 			sigaction(se->signum, sig_state->oldact[se->signum], NULL);
+			talloc_free(sig_state->oldact[se->signum]);
 			sig_state->oldact[se->signum] = NULL;
 		}
 #ifdef SA_SIGINFO
@@ -342,6 +343,8 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
 			return NULL;
 		}
 		if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
+			talloc_free(sig_state->oldact[signum]);
+			sig_state->oldact[signum] = NULL;
 			talloc_free(se);
 			return NULL;
 		}
@@ -505,6 +508,7 @@ void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
 	if (sig_state->sig_handlers[se->signum] == NULL) {
 		if (sig_state->oldact[se->signum]) {
 			sigaction(se->signum, sig_state->oldact[se->signum], NULL);
+			talloc_free(sig_state->oldact[se->signum]);
 			sig_state->oldact[se->signum] = NULL;
 		}
 	}
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
new file mode 100644
index 0000000..8d44e4f
--- /dev/null
+++ b/lib/tevent/tevent_threads.c
@@ -0,0 +1,370 @@
+/*
+   tevent event library.
+
+   Copyright (C) Jeremy Allison 2015
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "talloc.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+#if defined(HAVE_PTHREAD)
+#include <pthread.h>
+
+struct tevent_immediate_list {
+	struct tevent_immediate_list *next, *prev;
+	tevent_immediate_handler_t handler;
+	struct tevent_immediate *im;
+	void *private_ptr;
+};
+
+struct tevent_thread_proxy {
+	pthread_mutex_t mutex;
+	struct tevent_context *dest_ev_ctx;
+	int read_fd;
+	int write_fd;
+	struct tevent_fd *pipe_read_fde;
+	/* Pending events list. */
+	struct tevent_immediate_list *im_list;
+	/* Completed events list. */
+	struct tevent_immediate_list *tofree_im_list;
+	struct tevent_immediate *free_im;
+};
+
+static void free_im_list(struct tevent_immediate_list **pp_list_head)
+{
+	struct tevent_immediate_list *im_entry = NULL;
+	struct tevent_immediate_list *im_next = NULL;
+
+	for (im_entry = *pp_list_head; im_entry; im_entry = im_next) {
+		im_next = im_entry->next;
+		DLIST_REMOVE(*pp_list_head, im_entry);
+		TALLOC_FREE(im_entry);
+	}
+}
+
+static void free_list_handler(struct tevent_context *ev,
+				struct tevent_immediate *im,
+				void *private_ptr)
+{
+	struct tevent_thread_proxy *tp =
+		talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+	int ret;
+
+	ret = pthread_mutex_lock(&tp->mutex);
+	if (ret != 0) {
+		abort();
+		/* Notreached. */
+		return;
+	}
+
+	free_im_list(&tp->tofree_im_list);
+
+	ret = pthread_mutex_unlock(&tp->mutex);
+	if (ret != 0) {
+		abort();
+		/* Notreached. */
+		return;
+	}
+}
+
+static void schedule_immediate_functions(struct tevent_thread_proxy *tp)
+{
+	struct tevent_immediate_list *im_entry = NULL;
+	struct tevent_immediate_list *im_next = NULL;
+
+	for (im_entry = tp->im_list; im_entry; im_entry = im_next) {
+		im_next = im_entry->next;
+		DLIST_REMOVE(tp->im_list, im_entry);
+
+		tevent_schedule_immediate(im_entry->im,
+					tp->dest_ev_ctx,
+					im_entry->handler,
+					im_entry->private_ptr);
+
+		/* Move from pending list to free list. */
+		DLIST_ADD(tp->tofree_im_list, im_entry);
+	}
+	if (tp->tofree_im_list != NULL) {
+		/*
+		 * Once the current immediate events
+		 * are processed, we need to reshedule
+		 * ourselves to free them. This works
+		 * as tevent_schedule_immediate()
+		 * always adds events to the *END* of
+		 * the immediate events list.
+		 */
+		tevent_schedule_immediate(tp->free_im,
+					tp->dest_ev_ctx,
+					free_list_handler,
+					tp);
+	}
+}
+
+static void pipe_read_handler(struct tevent_context *ev,
+				struct tevent_fd *fde,
+				uint16_t flags,
+				void *private_ptr)
+{
+	struct tevent_thread_proxy *tp =
+		talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+	ssize_t len = 64;
+	int ret;
+
+	ret = pthread_mutex_lock(&tp->mutex);
+	if (ret != 0) {
+		abort();
+		/* Notreached. */
+		return;
+	}
+
+	/*
+	 * Clear out all data in the pipe. We
+	 * don't really care if this returns -1.
+	 */
+	while (len == 64) {
+		char buf[64];
+		len = read(tp->read_fd, buf, 64);
+	};
+
+	schedule_immediate_functions(tp);
+
+	ret = pthread_mutex_unlock(&tp->mutex);
+	if (ret != 0) {
+		abort();
+		/* Notreached. */
+		return;
+	}
+}
+
+static int tevent_thread_proxy_destructor(struct tevent_thread_proxy *tp)
+{
+	int ret;
+
+	ret = pthread_mutex_lock(&tp->mutex);
+	if (ret != 0) {
+		abort();
+		/* Notreached. */
+		return 0;
+	}
+
+	TALLOC_FREE(tp->pipe_read_fde);
+
+	if (tp->read_fd != -1) {
+		(void)close(tp->read_fd);
+		tp->read_fd = -1;
+	}
+	if (tp->write_fd != -1) {
+		(void)close(tp->write_fd);
+		tp->write_fd = -1;
+	}
+
+	/* Hmmm. It's probably an error if we get here with
+	   any non-NULL immediate entries.. */
+
+	free_im_list(&tp->im_list);
+	free_im_list(&tp->tofree_im_list);
+
+	TALLOC_FREE(tp->free_im);
+
+	ret = pthread_mutex_unlock(&tp->mutex);
+	if (ret != 0) {
+		abort();
+		/* Notreached. */
+		return 0;
+	}
+
+	ret = pthread_mutex_destroy(&tp->mutex);
+	if (ret != 0) {
+		abort();
+		/* Notreached. */
+		return 0;
+	}
+
+	return 0;
+}
+
+/*
+ * Create a struct that can be passed to other threads
+ * to allow them to signal the struct tevent_context *
+ * passed in.
+ */
+
+struct tevent_thread_proxy *tevent_thread_proxy_create(
+		struct tevent_context *dest_ev_ctx)
+{
+	int ret;
+	int pipefds[2];
+	struct tevent_thread_proxy *tp;
+
+	tp = talloc_zero(dest_ev_ctx, struct tevent_thread_proxy);
+	if (tp == NULL) {
+		return NULL;
+	}
+
+	ret = pthread_mutex_init(&tp->mutex, NULL);
+	if (ret != 0) {
+		goto fail;
+	}
+
+	tp->dest_ev_ctx = dest_ev_ctx;
+	tp->read_fd = -1;
+	tp->write_fd = -1;
+
+	talloc_set_destructor(tp, tevent_thread_proxy_destructor);
+
+	ret = pipe(pipefds);
+	if (ret == -1) {
+		goto fail;
+	}
+
+	tp->read_fd = pipefds[0];
+	tp->write_fd = pipefds[1];
+
+	ret = ev_set_blocking(pipefds[0], false);
+	if (ret != 0) {
+		goto fail;
+	}
+	ret = ev_set_blocking(pipefds[1], false);
+	if (ret != 0) {
+		goto fail;
+	}
+	if (!ev_set_close_on_exec(pipefds[0])) {
+		goto fail;
+	}
+	if (!ev_set_close_on_exec(pipefds[1])) {
+		goto fail;
+	}
+
+	tp->pipe_read_fde = tevent_add_fd(dest_ev_ctx,
+				tp,
+				tp->read_fd,
+				TEVENT_FD_READ,
+				pipe_read_handler,
+				tp);
+	if (tp->pipe_read_fde == NULL) {
+		goto fail;
+	}
+
+	/*
+	 * Create an immediate event to free
+	 * completed lists.
+	 */
+	tp->free_im = tevent_create_immediate(tp);
+	if (tp->free_im == NULL) {
+		goto fail;
+	}
+
+	return tp;
+
+  fail:
+
+	TALLOC_FREE(tp);
+	return NULL;
+}
+
+/*
+ * This function schedules an immediate event to be called with argument
+ * *pp_private in the thread context of dest_ev_ctx. Caller doesn't
+ * wait for activation to take place, this is simply fire-and-forget.
+ *
+ * pp_im must be a pointer to an immediate event talloced on
+ * a context owned by the calling thread, or the NULL context.
+ * Ownership of *pp_im will be transfered to the tevent library.
+ *
+ * pp_private can be null, or contents of *pp_private must be
+ * talloc'ed memory on a context owned by the calling thread
+ * or the NULL context. If non-null, ownership of *pp_private will
+ * be transfered to the tevent library.
+ *
+ * If you want to return a message, have the destination use the
+ * same function call to send back to the caller.
+ */
+
+
+void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
+				  struct tevent_immediate **pp_im,
+				  tevent_immediate_handler_t handler,
+				  void *pp_private_data)
+{
+	struct tevent_immediate_list *im_entry;
+	int ret;
+	char c;
+
+	ret = pthread_mutex_lock(&tp->mutex);
+	if (ret != 0) {
+		abort();
+		/* Notreached. */
+		return;
+	}
+
+	if (tp->write_fd == -1) {
+		/* In the process of being destroyed. Ignore. */
+		goto end;
+	}
+
+	/* Create a new immediate_list entry. MUST BE ON THE NULL CONTEXT */
+	im_entry = talloc_zero(NULL, struct tevent_immediate_list);
+	if (im_entry == NULL) {
+		goto end;
+	}
+
+	im_entry->handler = handler;
+	im_entry->im = talloc_move(im_entry, pp_im);
+
+	if (pp_private_data != NULL) {
+		void **pptr = (void **)pp_private_data;
+		im_entry->private_ptr = talloc_move(im_entry, pptr);
+	}
+
+	DLIST_ADD(tp->im_list, im_entry);
+
+	/* And notify the dest_ev_ctx to wake up. */
+	c = '\0';
+	(void)write(tp->write_fd, &c, 1);
+
+  end:
+
+	ret = pthread_mutex_unlock(&tp->mutex);
+	if (ret != 0) {
+		abort();
+		/* Notreached. */
+	}
+}
+#else
+/* !HAVE_PTHREAD */
+struct tevent_thread_proxy *tevent_thread_proxy_create(
+		struct tevent_context *dest_ev_ctx)
+{
+	errno = ENOSYS;
+	return NULL;
+}
+
+void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
+				  struct tevent_immediate **pp_im,
+				  tevent_immediate_handler_t handler,
+				  void *pp_private_data)
+{
+	;
+}
+#endif
diff --git a/lib/tevent/tevent_util.h b/lib/tevent/tevent_util.h
index 6f91983..e2cdbb8 100644
--- a/lib/tevent/tevent_util.h
+++ b/lib/tevent/tevent_util.h
@@ -53,10 +53,6 @@
   This allows us to find the tail of the list by using
   list_head->prev, which means we can add to the end of the list in
   O(1) time
-
-
-  Note that the 'type' arguments below are no longer needed, but
-  are kept for now to prevent an incompatible argument change
  */
 
 
@@ -131,9 +127,8 @@ do { \
 
 /*
    add to the end of a list.
-   Note that 'type' is ignored
 */
-#define DLIST_ADD_END(list, p, type)			\
+#define DLIST_ADD_END(list, p) \
 do { \
 	if (!(list)) { \
 		DLIST_ADD(list, p); \
@@ -151,20 +146,18 @@ do { \
 
 /*
    demote an element to the end of a list.
-   Note that 'type' is ignored
 */
-#define DLIST_DEMOTE(list, p, type)			\
+#define DLIST_DEMOTE(list, p) \
 do { \
 	DLIST_REMOVE(list, p); \
-	DLIST_ADD_END(list, p, NULL);		\
+	DLIST_ADD_END(list, p); \
 } while (0)
 
 /*
    concatenate two lists - putting all elements of the 2nd list at the
    end of the first list.
-   Note that 'type' is ignored
 */
-#define DLIST_CONCATENATE(list1, list2, type)	\
+#define DLIST_CONCATENATE(list1, list2) \
 do { \
 	if (!(list1)) { \
 		(list1) = (list2); \
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 827094c..2bdb5ac 100755
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'tevent'
-VERSION = '0.9.25'
+VERSION = '0.9.28'
 
 blddir = 'bin'
 
@@ -83,7 +83,7 @@ def build(bld):
 
     SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c
              tevent_queue.c tevent_req.c tevent_select.c
-             tevent_poll.c
+             tevent_poll.c tevent_threads.c
              tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c'''
 
     if bld.CONFIG_SET('HAVE_EPOLL'):
@@ -107,7 +107,7 @@ def build(bld):
                           abi_directory='ABI',
                           abi_match='tevent_* _tevent_*',
                           vnum=VERSION,
-                          public_headers='tevent.h',
+                          public_headers=('' if private_library else 'tevent.h'),
                           public_headers_install=not private_library,
                           pc_files='tevent.pc',
                           private_library=private_library)
@@ -133,6 +133,9 @@ def test(ctx):
     '''test tevent'''
     print("The tevent testsuite is part of smbtorture in samba4")
 
+    samba_utils.ADD_LD_LIBRARY_PATH('bin/shared')
+    samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private')
+
     pyret = samba_utils.RUN_PYTHON_TESTS(['bindings.py'])
     sys.exit(pyret)
 
diff --git a/lib/torture/torture.c b/lib/torture/torture.c
index 78d8261..40807d9 100644
--- a/lib/torture/torture.c
+++ b/lib/torture/torture.c
@@ -277,7 +277,7 @@ struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase,
 	test->dangerous = false;
 	test->data = data;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 }
@@ -296,7 +296,7 @@ bool torture_suite_init_tcase(struct torture_suite *suite,
 	tcase->fixture_persistent = true;
 	tcase->tests = NULL;
 
-	DLIST_ADD_END(suite->testcases, tcase, struct torture_tcase *);
+	DLIST_ADD_END(suite->testcases, tcase);
 
 	return true;
 }
@@ -617,7 +617,7 @@ struct torture_tcase *torture_suite_add_simple_tcase_const(
 	test->data = data;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return tcase;
 }
@@ -651,7 +651,7 @@ struct torture_tcase *torture_suite_add_simple_test(
 	test->fn = run;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return tcase;
 }
@@ -665,7 +665,7 @@ bool torture_suite_add_suite(struct torture_suite *suite,
 	if (child == NULL)
 		return false;
 
-	DLIST_ADD_END(suite->children, child, struct torture_suite *);
+	DLIST_ADD_END(suite->children, child);
 
 	/* FIXME: Check for duplicates and return false if the 
 	 * added suite already exists as a child */
@@ -716,7 +716,7 @@ struct torture_test *torture_tcase_add_simple_test_const(
 	test->data = NULL;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 }
@@ -747,7 +747,7 @@ struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase,
 	test->data = NULL;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 }
diff --git a/lib/torture/torture.h b/lib/torture/torture.h
index 2d99e65..356922a 100644
--- a/lib/torture/torture.h
+++ b/lib/torture/torture.h
@@ -293,6 +293,14 @@ void torture_result(struct torture_context *test,
 	}\
 	} while(0)
 
+#define torture_assert_hresult_equal(torture_ctx, got, expected, cmt) \
+	do { HRESULT __got = got, __expected = expected; \
+	if (!HRES_IS_EQUAL(__got, __expected)) { \
+		torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", hresult_errstr(__got), hresult_errstr(__expected), cmt); \
+		return false; \
+	} \
+	} while (0)
+
 #define torture_assert_casestr_equal(torture_ctx,got,expected,cmt) \
 	do { const char *__got = (got), *__expected = (expected); \
 	if (!strequal(__got, __expected)) { \
@@ -563,6 +571,9 @@ void torture_result(struct torture_context *test,
 #define torture_assert_ndr_success(torture_ctx,expr,cmt) \
 		torture_assert_ndr_err_equal(torture_ctx,expr,NDR_ERR_SUCCESS,cmt)
 
+#define torture_assert_hresult_ok(torture_ctx,expr,cmt) \
+		torture_assert_hresult_equal(torture_ctx,expr,HRES_ERROR(0), cmt)
+
 /* Getting settings */
 const char *torture_setting_string(struct torture_context *test, \
 								   const char *name, 
diff --git a/lib/torture/torture.pc.in b/lib/torture/torture.pc.in
deleted file mode 100644
index e0421b0..0000000
--- a/lib/torture/torture.pc.in
+++ /dev/null
@@ -1,12 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-modulesdir=${prefix}/modules/torture
-
-Name: torture
-Description: Samba torture (test) suite
-Requires: talloc
-Version: @PACKAGE_VERSION@
-Libs: @LIB_RPATH@ -L${libdir} -ltorture
-Cflags: -I${includedir}  -DHAVE_IMMEDIATE_STRUCTURES=1
diff --git a/lib/torture/wscript_build b/lib/torture/wscript_build
index ad047e2..31c3862 100644
--- a/lib/torture/wscript_build
+++ b/lib/torture/wscript_build
@@ -1,9 +1,8 @@
 #!/usr/bin/env python
 
 bld.SAMBA_LIBRARY('torture',
-	source='torture.c subunit.c simple.c',
-	vnum='0.0.1',
-	pc_files='torture.pc',
-	public_deps='samba-hostconfig samba-util errors talloc tevent',
-	public_headers='torture.h'
-	)
+    private_library=True,
+    source='torture.c subunit.c simple.c',
+    public_deps='samba-hostconfig samba-util samba-errors talloc tevent',
+    private_headers='torture.h'
+    )
diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
index 0756fb3..9608dde 100644
--- a/lib/tsocket/tsocket_bsd.c
+++ b/lib/tsocket/tsocket_bsd.c
@@ -2174,8 +2174,6 @@ static struct tevent_req *tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
 		talloc_get_type_abort(remote->private_data,
 		struct tsocket_address_bsd);
 	int ret;
-	int err;
-	bool retry;
 	bool do_bind = false;
 	bool do_reuseaddr = false;
 	bool do_ipv6only = false;
@@ -2316,12 +2314,11 @@ static struct tevent_req *tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
 	}
 
 	ret = connect(state->fd, &rbsda->u.sa, rbsda->sa_socklen);
-	err = tsocket_bsd_error_from_errno(ret, errno, &retry);
-	if (retry) {
-		/* retry later */
-		goto async;
-	}
-	if (tevent_req_error(req, err)) {
+	if (ret == -1) {
+		if (errno == EINPROGRESS) {
+			goto async;
+		}
+		tevent_req_error(req, errno);
 		goto post;
 	}
 
diff --git a/lib/uid_wrapper/uid_wrapper.c b/lib/uid_wrapper/uid_wrapper.c
index 1d49a85..ab47dd0 100644
--- a/lib/uid_wrapper/uid_wrapper.c
+++ b/lib/uid_wrapper/uid_wrapper.c
@@ -136,10 +136,10 @@ enum uwrap_dbglvl_e {
 #ifdef NDEBUG
 # define UWRAP_LOG(...)
 #else /* NDEBUG */
-static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
-# define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __VA_ARGS__)
+static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
+# define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
 
-static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...)
+static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
 {
 	char buffer[1024];
 	va_list va;
@@ -156,28 +156,28 @@ static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...)
 	va_end(va);
 
 	if (lvl >= dbglvl) {
+		const char *prefix;
 		switch (dbglvl) {
 			case UWRAP_LOG_ERROR:
-				fprintf(stderr,
-					"UWRAP_ERROR(%d): %s\n",
-					(int)getpid(), buffer);
+				prefix = "UWRAP_ERROR";
 				break;
 			case UWRAP_LOG_WARN:
-				fprintf(stderr,
-					"UWRAP_WARN(%d): %s\n",
-					(int)getpid(), buffer);
+				prefix = "UWRAP_WARN";
 				break;
 			case UWRAP_LOG_DEBUG:
-				fprintf(stderr,
-					"UWRAP_DEBUG(%d): %s\n",
-					(int)getpid(), buffer);
+				prefix = "UWRAP_DEBUG";
 				break;
 			case UWRAP_LOG_TRACE:
-				fprintf(stderr,
-					"UWRAP_TRACE(%d): %s\n",
-					(int)getpid(), buffer);
+				prefix = "UWRAP_TRACE";
 				break;
 		}
+
+		fprintf(stderr,
+			"%s(%d) - %s: %s\n",
+			prefix,
+			(int)getpid(),
+			function,
+			buffer);
 	}
 }
 #endif /* NDEBUG */
@@ -812,6 +812,11 @@ static void uwrap_thread_prepare(void)
 {
 	struct uwrap_thread *id = uwrap_tls_id;
 
+	/* uid_wrapper is loaded but not enabled */
+	if (id == NULL) {
+		return;
+	}
+
 	UWRAP_LOCK_ALL;
 
 	/*
@@ -826,6 +831,12 @@ static void uwrap_thread_prepare(void)
 static void uwrap_thread_parent(void)
 {
 	struct uwrap_thread *id = uwrap_tls_id;
+
+	/* uid_wrapper is loaded but not enabled */
+	if (id == NULL) {
+		return;
+	}
+
 	id->enabled = true;
 
 	UWRAP_UNLOCK_ALL;
@@ -836,6 +847,11 @@ static void uwrap_thread_child(void)
 	struct uwrap_thread *id = uwrap_tls_id;
 	struct uwrap_thread *u = uwrap.ids;
 
+	/* uid_wrapper is loaded but not enabled */
+	if (id == NULL) {
+		return;
+	}
+
 	/*
 	 * "Garbage collector" - Inspired by DESTRUCTOR.
 	 * All threads (except one which called fork()) are dead now.. Dave
@@ -952,8 +968,9 @@ static void uwrap_init(void)
 		id->enabled = true;
 
 		UWRAP_LOG(UWRAP_LOG_DEBUG,
-			  "Enabled uid_wrapper as %s",
-			  uwrap.myuid == 0 ? "root" : "user");
+			  "Enabled uid_wrapper as %s (real uid=%u)",
+			  id->ruid == 0 ? "root" : "user",
+			  (unsigned int)uwrap.myuid);
 	}
 
 	UWRAP_UNLOCK(uwrap_id);
@@ -977,33 +994,61 @@ bool uid_wrapper_enabled(void)
 	return enabled;
 }
 
-#ifdef HAVE_GETRESUID
-static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
+/*
+ * UWRAP_SETxUID FUNCTIONS
+ */
+
+static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
 {
 	struct uwrap_thread *id = uwrap_tls_id;
 
-	UWRAP_LOCK(uwrap_id);
-
-	*ruid = id->ruid;
-	*euid = id->euid;
-	*suid = id->suid;
-
-	UWRAP_UNLOCK(uwrap_id);
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
+		  id->ruid, ruid, id->euid, euid, id->suid, suid);
+
+	if (id->euid != 0) {
+		if (ruid != (uid_t)-1 &&
+		    ruid != id->ruid &&
+		    ruid != id->euid &&
+		    ruid != id->suid) {
+			errno = EPERM;
+			return -1;
+		}
+		if (euid != (uid_t)-1 &&
+		    euid != id->ruid &&
+		    euid != id->euid &&
+		    euid != id->suid) {
+			errno = EPERM;
+			return -1;
+		}
+		if (suid != (uid_t)-1 &&
+		    suid != id->ruid &&
+		    suid != id->euid &&
+		    suid != id->suid) {
+			errno = EPERM;
+			return -1;
+		}
+	}
 
 	return 0;
 }
-#endif
 
 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
 {
 	struct uwrap_thread *id = uwrap_tls_id;
+	int rc;
 
-	if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
-		errno = EINVAL;
-		return -1;
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
+		  id->ruid, ruid, id->euid, euid, id->suid, suid);
+
+	rc = uwrap_setresuid_args(ruid, euid, suid);
+	if (rc != 0) {
+		return rc;
 	}
 
 	UWRAP_LOCK(uwrap_id);
+
 	if (ruid != (uid_t)-1) {
 		id->ruid = ruid;
 	}
@@ -1021,6 +1066,204 @@ static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
 	return 0;
 }
 
+static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+	struct uwrap_thread *id = uwrap_tls_id;
+	int rc;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
+		  id->ruid, ruid, id->euid, euid, id->suid, suid);
+
+	rc = uwrap_setresuid_args(ruid, euid, suid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	UWRAP_LOCK(uwrap_id);
+
+	for (id = uwrap.ids; id; id = id->next) {
+		if (ruid != (uid_t)-1) {
+			id->ruid = ruid;
+		}
+
+		if (euid != (uid_t)-1) {
+			id->euid = euid;
+		}
+
+		if (suid != (uid_t)-1) {
+			id->suid = suid;
+		}
+	}
+
+	UWRAP_UNLOCK(uwrap_id);
+
+	return 0;
+}
+
+static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
+			       uid_t *_new_ruid,
+			       uid_t *_new_euid,
+			       uid_t *_new_suid)
+{
+	struct uwrap_thread *id = uwrap_tls_id;
+	uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "ruid %d -> %d, euid %d -> %d",
+		  id->ruid, ruid, id->euid, euid);
+
+	if (ruid != (uid_t)-1) {
+		new_ruid = ruid;
+		if (ruid != id->ruid &&
+		    ruid != id->euid &&
+		    id->euid != 0) {
+			errno = EPERM;
+			return -1;
+		}
+	}
+
+	if (euid != (uid_t)-1) {
+		new_euid = euid;
+		if (euid != id->ruid &&
+		    euid != id->euid &&
+		    euid != id->suid &&
+		    id->euid != 0) {
+			errno = EPERM;
+			return -1;
+		}
+	}
+
+	if (ruid != (uid_t) -1 ||
+	    (euid != (uid_t)-1 && id->ruid != euid)) {
+		new_suid = new_euid;
+	}
+
+	*_new_ruid = new_ruid;
+	*_new_euid = new_euid;
+	*_new_suid = new_suid;
+
+	return 0;
+}
+
+static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
+{
+#ifndef NDEBUG
+	struct uwrap_thread *id = uwrap_tls_id;
+#endif
+	uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+	int rc;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "ruid %d -> %d, euid %d -> %d",
+		  id->ruid, ruid, id->euid, euid);
+
+	rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
+}
+
+#ifdef HAVE_SETREUID
+static int uwrap_setreuid(uid_t ruid, uid_t euid)
+{
+#ifndef NDEBUG
+	struct uwrap_thread *id = uwrap_tls_id;
+#endif
+	uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+	int rc;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "ruid %d -> %d, euid %d -> %d",
+		  id->ruid, ruid, id->euid, euid);
+
+	rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	return uwrap_setresuid(new_ruid, new_euid, new_suid);
+}
+#endif
+
+static int uwrap_setuid_args(uid_t uid,
+			     uid_t *new_ruid,
+			     uid_t *new_euid,
+			     uid_t *new_suid)
+{
+	struct uwrap_thread *id = uwrap_tls_id;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "uid %d -> %d",
+		  id->ruid, uid);
+
+	if (uid == (uid_t)-1) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (id->euid == 0) {
+		*new_suid = *new_ruid = uid;
+	} else if (uid != id->ruid &&
+		   uid != id->suid) {
+		errno = EPERM;
+		return -1;
+	}
+
+	*new_euid = uid;
+
+	return 0;
+}
+
+static int uwrap_setuid_thread(uid_t uid)
+{
+	uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+	int rc;
+
+	rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
+}
+
+static int uwrap_setuid(uid_t uid)
+{
+	uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+	int rc;
+
+	rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	return uwrap_setresuid(new_ruid, new_euid, new_suid);
+}
+
+/*
+ * UWRAP_GETxUID FUNCTIONS
+ */
+
+#ifdef HAVE_GETRESUID
+static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
+{
+	struct uwrap_thread *id = uwrap_tls_id;
+
+	UWRAP_LOCK(uwrap_id);
+
+	*ruid = id->ruid;
+	*euid = id->euid;
+	*suid = id->suid;
+
+	UWRAP_UNLOCK(uwrap_id);
+
+	return 0;
+}
+#endif
+
 #ifdef HAVE_GETRESGID
 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
 {
@@ -1038,27 +1281,105 @@ static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
 }
 #endif
 
-static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+/*
+ * UWRAP_SETxGID FUNCTIONS
+ */
+
+static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
 {
-	struct uwrap_thread *id;
+	struct uwrap_thread *id = uwrap_tls_id;
 
-	if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
-		errno = EINVAL;
-		return -1;
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
+		  id->rgid, rgid, id->egid, egid, id->sgid, sgid);
+
+	if (id->euid != 0) {
+		if (rgid != (gid_t)-1 &&
+		    rgid != id->rgid &&
+		    rgid != id->egid &&
+		    rgid != id->sgid) {
+			errno = EPERM;
+			return -1;
+		}
+		if (egid != (gid_t)-1 &&
+		    egid != id->rgid &&
+		    egid != id->egid &&
+		    egid != id->sgid) {
+			errno = EPERM;
+			return -1;
+		}
+		if (sgid != (gid_t)-1 &&
+		    sgid != id->rgid &&
+		    sgid != id->egid &&
+		    sgid != id->sgid) {
+			errno = EPERM;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
+{
+	struct uwrap_thread *id = uwrap_tls_id;
+	int rc;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
+		  id->rgid, rgid, id->egid, egid, id->sgid, sgid);
+
+	rc = uwrap_setresgid_args(rgid, egid, sgid);
+	if (rc != 0) {
+		return rc;
 	}
 
 	UWRAP_LOCK(uwrap_id);
+
+	if (rgid != (gid_t)-1) {
+		id->rgid = rgid;
+	}
+
+	if (egid != (gid_t)-1) {
+		id->egid = egid;
+	}
+
+	if (sgid != (gid_t)-1) {
+		id->sgid = sgid;
+	}
+
+	UWRAP_UNLOCK(uwrap_id);
+
+	return 0;
+}
+
+static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+{
+	struct uwrap_thread *id = uwrap_tls_id;
+	int rc;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
+		  id->rgid, rgid, id->egid, egid, id->sgid, sgid);
+
+	rc = uwrap_setresgid_args(rgid, egid, sgid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	UWRAP_LOCK(uwrap_id);
+
 	for (id = uwrap.ids; id; id = id->next) {
-		if (ruid != (uid_t)-1) {
-			id->ruid = ruid;
+		if (rgid != (gid_t)-1) {
+			id->rgid = rgid;
 		}
 
-		if (euid != (uid_t)-1) {
-			id->euid = euid;
+		if (egid != (gid_t)-1) {
+			id->egid = egid;
 		}
 
-		if (suid != (uid_t)-1) {
-			id->suid = suid;
+		if (sgid != (gid_t)-1) {
+			id->sgid = sgid;
 		}
 	}
 
@@ -1067,6 +1388,148 @@ static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
 	return 0;
 }
 
+static int uwrap_setregid_args(gid_t rgid, gid_t egid,
+			       gid_t *_new_rgid,
+			       gid_t *_new_egid,
+			       gid_t *_new_sgid)
+{
+	struct uwrap_thread *id = uwrap_tls_id;
+	gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "rgid %d -> %d, egid %d -> %d",
+		  id->rgid, rgid, id->egid, egid);
+
+	if (rgid != (gid_t)-1) {
+		new_rgid = rgid;
+		if (rgid != id->rgid &&
+		    rgid != id->egid &&
+		    id->euid != 0) {
+			errno = EPERM;
+			return -1;
+		}
+	}
+
+	if (egid != (gid_t)-1) {
+		new_egid = egid;
+		if (egid != id->rgid &&
+		    egid != id->egid &&
+		    egid != id->sgid &&
+		    id->euid != 0) {
+			errno = EPERM;
+			return -1;
+		}
+	}
+
+	if (rgid != (gid_t) -1 ||
+	    (egid != (gid_t)-1 && id->rgid != egid)) {
+		new_sgid = new_egid;
+	}
+
+	*_new_rgid = new_rgid;
+	*_new_egid = new_egid;
+	*_new_sgid = new_sgid;
+
+	return 0;
+}
+
+static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
+{
+#ifndef NDEBUG
+	struct uwrap_thread *id = uwrap_tls_id;
+#endif
+	gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+	int rc;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "rgid %d -> %d, egid %d -> %d",
+		  id->rgid, rgid, id->egid, egid);
+
+	rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
+}
+
+#ifdef HAVE_SETREGID
+static int uwrap_setregid(gid_t rgid, gid_t egid)
+{
+#ifndef NDEBUG
+	struct uwrap_thread *id = uwrap_tls_id;
+#endif
+	gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+	int rc;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "rgid %d -> %d, egid %d -> %d",
+		  id->rgid, rgid, id->egid, egid);
+
+	rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	return uwrap_setresgid(new_rgid, new_egid, new_sgid);
+}
+#endif
+
+static int uwrap_setgid_args(gid_t gid,
+			     gid_t *new_rgid,
+			     gid_t *new_egid,
+			     gid_t *new_sgid)
+{
+	struct uwrap_thread *id = uwrap_tls_id;
+
+	UWRAP_LOG(UWRAP_LOG_TRACE,
+		  "gid %d -> %d",
+		  id->rgid, gid);
+
+	if (gid == (gid_t)-1) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (id->euid == 0) {
+		*new_sgid = *new_rgid = gid;
+	} else if (gid != id->rgid &&
+		   gid != id->sgid) {
+		errno = EPERM;
+		return -1;
+	}
+
+	*new_egid = gid;
+
+	return 0;
+}
+
+static int uwrap_setgid_thread(gid_t gid)
+{
+	gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+	int rc;
+
+	rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
+}
+
+static int uwrap_setgid(gid_t gid)
+{
+	gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+	int rc;
+
+	rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
+	if (rc != 0) {
+		return rc;
+	}
+
+	return uwrap_setresgid(new_rgid, new_egid, new_sgid);
+}
+
 /*
  * SETUID
  */
@@ -1077,21 +1540,22 @@ int setuid(uid_t uid)
 	}
 
 	uwrap_init();
-	return uwrap_setresuid(uid, -1, -1);
+	return uwrap_setuid(uid);
 }
 
 #ifdef HAVE_SETEUID
 int seteuid(uid_t euid)
 {
+	if (!uid_wrapper_enabled()) {
+		return libc_seteuid(euid);
+	}
+
+	/* On FreeBSD the uid_t -1 is set and doesn't produce and error */
 	if (euid == (uid_t)-1) {
 		errno = EINVAL;
 		return -1;
 	}
 
-	if (!uid_wrapper_enabled()) {
-		return libc_seteuid(euid);
-	}
-
 	uwrap_init();
 	return uwrap_setresuid(-1, euid, -1);
 }
@@ -1100,17 +1564,12 @@ int seteuid(uid_t euid)
 #ifdef HAVE_SETREUID
 int setreuid(uid_t ruid, uid_t euid)
 {
-	if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
-		errno = EINVAL;
-		return -1;
-	}
-
 	if (!uid_wrapper_enabled()) {
 		return libc_setreuid(ruid, euid);
 	}
 
 	uwrap_init();
-	return uwrap_setresuid(ruid, euid, -1);
+	return uwrap_setreuid(ruid, euid);
 }
 #endif
 
@@ -1194,61 +1653,6 @@ uid_t geteuid(void)
 	return uwrap_geteuid();
 }
 
-static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
-{
-	struct uwrap_thread *id = uwrap_tls_id;
-
-	if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	UWRAP_LOCK(uwrap_id);
-	if (rgid != (gid_t)-1) {
-		id->rgid = rgid;
-	}
-
-	if (egid != (gid_t)-1) {
-		id->egid = egid;
-	}
-
-	if (sgid != (gid_t)-1) {
-		id->sgid = sgid;
-	}
-
-	UWRAP_UNLOCK(uwrap_id);
-
-	return 0;
-}
-
-static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
-{
-	struct uwrap_thread *id;
-
-	if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	UWRAP_LOCK(uwrap_id);
-	for (id = uwrap.ids; id; id = id->next) {
-		if (rgid != (gid_t)-1) {
-			id->rgid = rgid;
-		}
-
-		if (egid != (gid_t)-1) {
-			id->egid = egid;
-		}
-
-		if (sgid != (gid_t)-1) {
-			id->sgid = sgid;
-		}
-	}
-	UWRAP_UNLOCK(uwrap_id);
-
-	return 0;
-}
-
 /*
  * SETGID
  */
@@ -1259,7 +1663,7 @@ int setgid(gid_t gid)
 	}
 
 	uwrap_init();
-	return uwrap_setresgid(gid, -1, -1);
+	return uwrap_setgid(gid);
 }
 
 #ifdef HAVE_SETEGID
@@ -1269,6 +1673,12 @@ int setegid(gid_t egid)
 		return libc_setegid(egid);
 	}
 
+	/* On FreeBSD the uid_t -1 is set and doesn't produce and error */
+	if (egid == (gid_t)-1) {
+		errno = EINVAL;
+		return -1;
+	}
+
 	uwrap_init();
 	return uwrap_setresgid(-1, egid, -1);
 }
@@ -1282,7 +1692,7 @@ int setregid(gid_t rgid, gid_t egid)
 	}
 
 	uwrap_init();
-	return uwrap_setresgid(rgid, egid, -1);
+	return uwrap_setregid(rgid, egid);
 }
 #endif
 
@@ -1509,7 +1919,7 @@ static long int uwrap_syscall (long int sysno, va_list vp)
 			{
 				gid_t gid = (gid_t) va_arg(vp, gid_t);
 
-				rc = uwrap_setresgid_thread(gid, -1, -1);
+				rc = uwrap_setgid_thread(gid);
 			}
 			break;
 		case SYS_setregid:
@@ -1520,7 +1930,7 @@ static long int uwrap_syscall (long int sysno, va_list vp)
 				gid_t rgid = (gid_t) va_arg(vp, gid_t);
 				gid_t egid = (gid_t) va_arg(vp, gid_t);
 
-				rc = uwrap_setresgid_thread(rgid, egid, -1);
+				rc = uwrap_setregid_thread(rgid, egid);
 			}
 			break;
 #ifdef SYS_setresgid
@@ -1537,7 +1947,7 @@ static long int uwrap_syscall (long int sysno, va_list vp)
 			}
 			break;
 #endif /* SYS_setresgid */
-#ifdef SYS_getresgid
+#if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
 		case SYS_getresgid:
 #ifdef HAVE_LINUX_32BIT_SYSCALLS
 		case SYS_getresgid32:
@@ -1550,7 +1960,7 @@ static long int uwrap_syscall (long int sysno, va_list vp)
 				rc = uwrap_getresgid(rgid, egid, sgid);
 			}
 			break;
-#endif /* SYS_getresgid */
+#endif /* SYS_getresgid && HAVE_GETRESGID */
 
 		/* uid */
 		case SYS_getuid:
@@ -1578,7 +1988,7 @@ static long int uwrap_syscall (long int sysno, va_list vp)
 			{
 				uid_t uid = (uid_t) va_arg(vp, uid_t);
 
-				rc = uwrap_setresuid_thread(uid, -1, -1);
+				rc = uwrap_setuid_thread(uid);
 			}
 			break;
 		case SYS_setreuid:
@@ -1589,7 +1999,7 @@ static long int uwrap_syscall (long int sysno, va_list vp)
 				uid_t ruid = (uid_t) va_arg(vp, uid_t);
 				uid_t euid = (uid_t) va_arg(vp, uid_t);
 
-				rc = uwrap_setresuid_thread(ruid, euid, -1);
+				rc = uwrap_setreuid_thread(ruid, euid);
 			}
 			break;
 #ifdef SYS_setresuid
@@ -1606,7 +2016,7 @@ static long int uwrap_syscall (long int sysno, va_list vp)
 			}
 			break;
 #endif /* SYS_setresuid */
-#ifdef SYS_getresuid
+#if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
 		case SYS_getresuid:
 #ifdef HAVE_LINUX_32BIT_SYSCALLS
 		case SYS_getresuid32:
@@ -1619,7 +2029,7 @@ static long int uwrap_syscall (long int sysno, va_list vp)
 				rc = uwrap_getresuid(ruid, euid, suid);
 			}
 			break;
-#endif /* SYS_getresuid */
+#endif /* SYS_getresuid && HAVE_GETRESUID*/
 		/* groups */
 		case SYS_setgroups:
 #ifdef HAVE_LINUX_32BIT_SYSCALLS
@@ -1634,7 +2044,7 @@ static long int uwrap_syscall (long int sysno, va_list vp)
 			break;
 		default:
 			UWRAP_LOG(UWRAP_LOG_DEBUG,
-				  "UID_WRAPPER calling non-wrapped syscall %lu\n",
+				  "UID_WRAPPER calling non-wrapped syscall %lu",
 				  sysno);
 
 			rc = libc_vsyscall(sysno, vp);
diff --git a/lib/uid_wrapper/wscript b/lib/uid_wrapper/wscript
index 3b3d5bf..1c87236 100644
--- a/lib/uid_wrapper/wscript
+++ b/lib/uid_wrapper/wscript
@@ -1,9 +1,9 @@
 #!/usr/bin/env python
 
 import Options
-import os
+import os, sys
 
-VERSION="1.1.0"
+VERSION="1.2.0"
 
 def configure(conf):
     if conf.CHECK_BUNDLED_SYSTEM('uid_wrapper', minversion=VERSION, set_target=False):
@@ -35,40 +35,6 @@ def configure(conf):
             addmain=False,
             msg='Checking for thread local storage')
 
-        # check HAVE_CONSTRUCTOR_ATTRIBUTE
-        conf.CHECK_CODE('''
-            void test_constructor_attribute(void) __attribute__ ((constructor));
-
-            void test_constructor_attribute(void)
-            {
-                return;
-            }
-
-            int main(void) {
-                return 0;
-            }
-            ''',
-            'HAVE_CONSTRUCTOR_ATTRIBUTE',
-            addmain=False,
-            msg='Checking for library constructor support')
-
-        # check HAVE_DESTRUCTOR_ATTRIBUTE
-        conf.CHECK_CODE('''
-            void test_destructor_attribute(void) __attribute__ ((destructor));
-
-            void test_destructor_attribute(void)
-            {
-                return;
-            }
-
-            int main(void) {
-                return 0;
-            }
-            ''',
-            'HAVE_DESTRUCTOR_ATTRIBUTE',
-            addmain=False,
-            msg='Checking for library destructor support')
-
         if Options.options.address_sanitizer:
             # check HAVE_ADDRESS_SANITIZER_ATTRIBUTE
             conf.CHECK_CODE('''
@@ -107,6 +73,42 @@ def configure(conf):
 			'int syscall(int number, ...)',
 			define='HAVE_SYSCALL_INT', headers='unistd.h sys/syscall.h')
 
+        if (sys.platform.rfind('linux') > -1):
+            conf.CHECK_CODE('''
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_PRIV_H
+#include <sys/priv.h>
+#endif
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
+#endif
+
+#if defined(HAVE_SYSCALL_H)
+#include <syscall.h>
+#endif
+
+#if defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h>
+#endif
+
+syscall(SYS_setresuid32, -1, -1, -1);
+syscall(SYS_setresgid32, -1, -1, -1);
+syscall(SYS_setreuid32, -1, -1);
+syscall(SYS_setregid32, -1, -1);
+syscall(SYS_setuid32, -1);
+syscall(SYS_setgid32, -1);
+syscall(SYS_setgroups32, 0, NULL);
+''',
+                'HAVE_LINUX_32BIT_SYSCALLS',
+                msg="Checking whether Linux has 32-bit credential calls");
+
         conf.CHECK_FUNCS('getresuid getresgid')
 
         # Create full path to uid_wrapper
@@ -123,7 +125,6 @@ def build(bld):
         # breaks preloading!
         bld.SAMBA_LIBRARY('uid_wrapper',
                           source='uid_wrapper.c',
-                          cflags='-DNDEBUG',
                           deps='dl',
                           install=False,
                           realname='libuid-wrapper.so')
diff --git a/lib/util/asn1.c b/lib/util/asn1.c
index 9f4924c..8f2c516 100644
--- a/lib/util/asn1.c
+++ b/lib/util/asn1.c
@@ -17,8 +17,26 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "../lib/util/asn1.h"
+#include "replace.h"
+#include "system/locale.h"
+#include "lib/util/asn1.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+struct nesting {
+	off_t start;
+	size_t taglen; /* for parsing */
+	struct nesting *next;
+};
+
+
+struct asn1_data {
+	uint8_t *data;
+	size_t length;
+	off_t ofs;
+	struct nesting *nesting;
+	bool has_error;
+};
 
 /* allocate an asn1 structure */
 struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx)
@@ -36,10 +54,36 @@ void asn1_free(struct asn1_data *data)
 	talloc_free(data);
 }
 
+bool asn1_has_error(const struct asn1_data *data)
+{
+	return data->has_error;
+}
+
+void asn1_set_error(struct asn1_data *data)
+{
+	data->has_error = true;
+}
+
+bool asn1_has_nesting(const struct asn1_data *data)
+{
+	return data->nesting != NULL;
+}
+
+off_t asn1_current_ofs(const struct asn1_data *data)
+{
+	return data->ofs;
+}
+
 /* write to the ASN1 buffer, advancing the buffer pointer */
 bool asn1_write(struct asn1_data *data, const void *p, int len)
 {
 	if (data->has_error) return false;
+
+	if ((len < 0) || (data->ofs + (size_t)len < data->ofs)) {
+		data->has_error = true;
+		return false;
+	}
+
 	if (data->length < data->ofs+len) {
 		uint8_t *newp;
 		newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len);
@@ -66,7 +110,9 @@ bool asn1_push_tag(struct asn1_data *data, uint8_t tag)
 {
 	struct nesting *nesting;
 
-	asn1_write_uint8(data, tag);
+	if (!asn1_write_uint8(data, tag)) {
+		return false;
+	}
 	nesting = talloc(data, struct nesting);
 	if (!nesting) {
 		data->has_error = true;
@@ -85,6 +131,10 @@ bool asn1_pop_tag(struct asn1_data *data)
 	struct nesting *nesting;
 	size_t len;
 
+	if (data->has_error) {
+		return false;
+	}
+
 	nesting = data->nesting;
 
 	if (!nesting) {
@@ -184,6 +234,10 @@ static bool push_int_bigendian(struct asn1_data *data, unsigned int i, bool nega
 
 bool asn1_write_implicit_Integer(struct asn1_data *data, int i)
 {
+	if (data->has_error) {
+		return false;
+	}
+
 	if (i == -1) {
 		/* -1 is special as it consists of all-0xff bytes. In
                     push_int_bigendian this is the only case that is not
@@ -230,7 +284,7 @@ bool ber_write_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *OID)
 	if (newp[0] != '.') return false;
 	p = newp + 1;
 
-	/*the ber representation can't use more space then the string one */
+	/*the ber representation can't use more space than the string one */
 	*blob = data_blob_talloc(mem_ctx, NULL, strlen(OID));
 	if (!blob->data) return false;
 
@@ -489,7 +543,8 @@ bool asn1_peek_tag(struct asn1_data *data, uint8_t tag)
 /*
  * just get the needed size the tag would consume
  */
-bool asn1_peek_tag_needed_size(struct asn1_data *data, uint8_t tag, size_t *size)
+static bool asn1_peek_tag_needed_size(struct asn1_data *data, uint8_t tag,
+				      size_t *size)
 {
 	off_t start_ofs = data->ofs;
 	uint8_t b;
@@ -986,6 +1041,26 @@ bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob)
 	return true;
 }
 
+bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+		       DATA_BLOB *pblob)
+{
+	DATA_BLOB blob;
+
+	if (!asn1_blob(asn1, &blob)) {
+		return false;
+	}
+
+	*pblob = (DATA_BLOB) { .length = blob.length };
+	pblob->data = talloc_move(mem_ctx, &blob.data);
+
+	/*
+	 * Stop access from here on
+	 */
+	asn1->has_error = true;
+
+	return true;
+}
+
 /*
   Fill in an asn1 struct without making a copy
 */
@@ -996,35 +1071,7 @@ void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len)
 	data->length = len;
 }
 
-/*
-  check if a ASN.1 blob is a full tag
-*/
-NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
-{
-	struct asn1_data *asn1 = asn1_init(NULL);
-	int size;
-
-	NT_STATUS_HAVE_NO_MEMORY(asn1);
-
-	asn1->data = blob.data;
-	asn1->length = blob.length;
-	if (!asn1_start_tag(asn1, tag)) {
-		talloc_free(asn1);
-		return STATUS_MORE_ENTRIES;
-	}
-	size = asn1_tag_remaining(asn1) + asn1->ofs;
-
-	talloc_free(asn1);
-
-	if (size > blob.length) {
-		return STATUS_MORE_ENTRIES;
-	}
-
-	*packet_size = size;
-	return NT_STATUS_OK;
-}
-
-NTSTATUS asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
+int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
 {
 	struct asn1_data asn1;
 	size_t size;
@@ -1036,14 +1083,14 @@ NTSTATUS asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
 
 	ok = asn1_peek_tag_needed_size(&asn1, tag, &size);
 	if (!ok) {
-		return NT_STATUS_INVALID_BUFFER_SIZE;
+		return EMSGSIZE;
 	}
 
 	if (size > blob.length) {
 		*packet_size = size;
-		return STATUS_MORE_ENTRIES;
+		return EAGAIN;
 	}		
 
 	*packet_size = size;
-	return NT_STATUS_OK;
+	return 0;
 }
diff --git a/lib/util/asn1.h b/lib/util/asn1.h
index 568b4e4..9ebf453 100644
--- a/lib/util/asn1.h
+++ b/lib/util/asn1.h
@@ -20,20 +20,13 @@
 #ifndef _ASN_1_H
 #define _ASN_1_H
 
-struct nesting {
-	off_t start;
-	size_t taglen; /* for parsing */
-	struct nesting *next;
-};
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/data_blob.h"
 
-struct asn1_data {
-	uint8_t *data;
-	size_t length;
-	off_t ofs;
-	struct nesting *nesting;
-	bool has_error;
-};
 
+struct nesting;
+struct asn1_data;
 typedef struct asn1_data ASN1_DATA;
 
 #define ASN1_APPLICATION(x) ((x)+0x60)
@@ -54,6 +47,10 @@ typedef struct asn1_data ASN1_DATA;
 
 struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx);
 void asn1_free(struct asn1_data *data);
+bool asn1_has_error(const struct asn1_data *data);
+void asn1_set_error(struct asn1_data *data);
+bool asn1_has_nesting(const struct asn1_data *data);
+off_t asn1_current_ofs(const struct asn1_data *data);
 bool asn1_write(struct asn1_data *data, const void *p, int len);
 bool asn1_write_uint8(struct asn1_data *data, uint8_t v);
 bool asn1_push_tag(struct asn1_data *data, uint8_t tag);
@@ -79,7 +76,6 @@ bool asn1_peek(struct asn1_data *data, void *p, int len);
 bool asn1_read(struct asn1_data *data, void *p, int len);
 bool asn1_read_uint8(struct asn1_data *data, uint8_t *v);
 bool asn1_peek_uint8(struct asn1_data *data, uint8_t *v);
-bool asn1_peek_tag_needed_size(struct asn1_data *data, uint8_t tag, size_t *size);
 bool asn1_peek_tag(struct asn1_data *data, uint8_t tag);
 bool asn1_start_tag(struct asn1_data *data, uint8_t tag);
 bool asn1_end_tag(struct asn1_data *data);
@@ -99,8 +95,9 @@ bool asn1_read_enumerated(struct asn1_data *data, int *v);
 bool asn1_check_enumerated(struct asn1_data *data, int v);
 bool asn1_write_enumerated(struct asn1_data *data, uint8_t v);
 bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob);
+bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+		       DATA_BLOB *pblob);
 void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len);
-NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
-NTSTATUS asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
+int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
 
 #endif /* _ASN_1_H */
diff --git a/lib/util/charset/util_str.c b/lib/util/charset/util_str.c
index 90197e0..550fba3 100644
--- a/lib/util/charset/util_str.c
+++ b/lib/util/charset/util_str.c
@@ -546,13 +546,13 @@ char *strstr_m(const char *src, const char *findstr)
 	frame = talloc_stackframe();
 
 	if (!push_ucs2_talloc(frame, &src_w, src, &converted_size)) {
-		DBG_WARNING("strstr_m: src malloc fail\n");
+		DBG_WARNING("src malloc fail\n");
 		TALLOC_FREE(frame);
 		return NULL;
 	}
 
 	if (!push_ucs2_talloc(frame, &find_w, findstr, &converted_size)) {
-		DBG_WARNING("strstr_m: find malloc fail\n");
+		DBG_WARNING("find malloc fail\n");
 		TALLOC_FREE(frame);
 		return NULL;
 	}
diff --git a/lib/util/debug.c b/lib/util/debug.c
index f2a445b..4bb54d7 100644
--- a/lib/util/debug.c
+++ b/lib/util/debug.c
@@ -780,7 +780,7 @@ void debug_set_settings(struct debug_settings *settings,
 
 	/*
 	 * If 'logging' is not set, create backend settings from
-	 * deprecated 'syslog' and 'syslog only' paramters
+	 * deprecated 'syslog' and 'syslog only' parameters
 	 */
 	if (logging_param != NULL) {
 		len = strlen(logging_param);
diff --git a/lib/util/debug.h b/lib/util/debug.h
index c312bbf..95b0a30 100644
--- a/lib/util/debug.h
+++ b/lib/util/debug.h
@@ -25,7 +25,7 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-
+#include <stdarg.h>
 #include "attr.h"
 
 
@@ -204,6 +204,14 @@ extern int  *DEBUGLEVEL_CLASS;
 #define DEBUGSEP(level)\
 	DEBUG((level),("===============================================================\n"))
 
+/* Prefix messages with the function name */
+#define DBG_PREFIX(level, body ) \
+	(void)( ((level) <= MAX_DEBUG_LEVEL) &&			\
+		unlikely(DEBUGLEVEL_CLASS[ DBGC_CLASS ] >= (level))	\
+		&& (dbghdrclass(level, DBGC_CLASS, __location__, __func__ )) \
+		&& (dbgtext("%s: ", __func__))				\
+		&& (dbgtext body) )
+
 /*
  * Debug levels matching RFC 3164
  */
@@ -213,11 +221,11 @@ extern int  *DEBUGLEVEL_CLASS;
 #define DBGLVL_INFO	 5	/* informational message */
 #define DBGLVL_DEBUG	10	/* debug-level message */
 
-#define DBG_ERR(...)		DEBUG(DBGLVL_ERR,	(__VA_ARGS__))
-#define DBG_WARNING(...)	DEBUG(DBGLVL_WARNING,	(__VA_ARGS__))
-#define DBG_NOTICE(...)	DEBUG(DBGLVL_NOTICE,	(__VA_ARGS__))
-#define DBG_INFO(...)		DEBUG(DBGLVL_INFO,	(__VA_ARGS__))
-#define DBG_DEBUG(...)		DEBUG(DBGLVL_DEBUG,	(__VA_ARGS__))
+#define DBG_ERR(...)		DBG_PREFIX(DBGLVL_ERR,		(__VA_ARGS__))
+#define DBG_WARNING(...)	DBG_PREFIX(DBGLVL_WARNING,	(__VA_ARGS__))
+#define DBG_NOTICE(...)		DBG_PREFIX(DBGLVL_NOTICE,	(__VA_ARGS__))
+#define DBG_INFO(...)		DBG_PREFIX(DBGLVL_INFO,		(__VA_ARGS__))
+#define DBG_DEBUG(...)		DBG_PREFIX(DBGLVL_DEBUG,	(__VA_ARGS__))
 
 /* The following definitions come from lib/debug.c  */
 
diff --git a/lib/util/dlinklist.h b/lib/util/dlinklist.h
index 5520901..8a1b84d 100644
--- a/lib/util/dlinklist.h
+++ b/lib/util/dlinklist.h
@@ -53,10 +53,6 @@
   This allows us to find the tail of the list by using
   list_head->prev, which means we can add to the end of the list in
   O(1) time
-
-
-  Note that the 'type' arguments below are no longer needed, but
-  are kept for now to prevent an incompatible argument change
  */
 
 
@@ -131,9 +127,8 @@ do { \
 
 /*
    add to the end of a list.
-   Note that 'type' is ignored
 */
-#define DLIST_ADD_END(list, p, type)			\
+#define DLIST_ADD_END(list, p) \
 do { \
 	if (!(list)) { \
 		DLIST_ADD(list, p); \
@@ -151,20 +146,18 @@ do { \
 
 /*
    demote an element to the end of a list.
-   Note that 'type' is ignored
 */
-#define DLIST_DEMOTE(list, p, type)			\
+#define DLIST_DEMOTE(list, p) \
 do { \
 	DLIST_REMOVE(list, p); \
-	DLIST_ADD_END(list, p, NULL);		\
+	DLIST_ADD_END(list, p); \
 } while (0)
 
 /*
    concatenate two lists - putting all elements of the 2nd list at the
    end of the first list.
-   Note that 'type' is ignored
 */
-#define DLIST_CONCATENATE(list1, list2, type)	\
+#define DLIST_CONCATENATE(list1, list2) \
 do { \
 	if (!(list1)) { \
 		(list1) = (list2); \
diff --git a/lib/util/genrand.c b/lib/util/genrand.c
index 4473433..a775535 100644
--- a/lib/util/genrand.c
+++ b/lib/util/genrand.c
@@ -21,268 +21,41 @@
 
 #include "replace.h"
 #include "system/filesys.h"
-#include "../lib/crypto/crypto.h"
 #include "lib/util/genrand.h"
+#include "sys_rw_data.h"
 #include "lib/util/blocking.h"
-#include "lib/util/time_basic.h"
-#include "lib/util/byteorder.h"
-
-/**
- * @file
- * @brief Random number generation
- */
-
-static unsigned char hash[258];
-static uint32_t counter;
-
-static bool done_reseed = false;
-static unsigned int bytes_since_reseed = 0;
 
 static int urand_fd = -1;
 
-static void (*reseed_callback)(void *userdata, int *newseed);
-static void *reseed_callback_userdata = NULL;
-
-/**
- Copy any user given reseed data.
-**/
-
-_PUBLIC_ void set_rand_reseed_callback(void (*fn)(void *, int *), void *userdata)
-{
-	reseed_callback = fn;
-	reseed_callback_userdata = userdata;
-	set_need_random_reseed();
-}
-
-/**
- * Tell the random number generator it needs to reseed.
- */
-_PUBLIC_ void set_need_random_reseed(void)
+static void open_urandom(void)
 {
-	done_reseed = false;
-	bytes_since_reseed = 0;
-}
-
-static void get_rand_reseed_data(int *reseed_data)
-{
-	if (reseed_callback) {
-		reseed_callback(reseed_callback_userdata, reseed_data);
-	} else {
-		*reseed_data = 0;
-	}
-}
-
-/****************************************************************
- Setup the seed.
-*****************************************************************/
-
-static void seed_random_stream(unsigned char *seedval, size_t seedlen)
-{
-	unsigned char j = 0;
-	size_t ind;
-
-	for (ind = 0; ind < 256; ind++)
-		hash[ind] = (unsigned char)ind;
-
-	for( ind = 0; ind < 256; ind++) {
-		unsigned char tc;
-
-		j += (hash[ind] + seedval[ind%seedlen]);
-
-		tc = hash[ind];
-		hash[ind] = hash[j];
-		hash[j] = tc;
-	}
-
-	hash[256] = 0;
-	hash[257] = 0;
-}
-
-/****************************************************************
- Get datasize bytes worth of random data.
-*****************************************************************/
-
-static void get_random_stream(unsigned char *data, size_t datasize)
-{
-	unsigned char index_i = hash[256];
-	unsigned char index_j = hash[257];
-	size_t ind;
-
-	for( ind = 0; ind < datasize; ind++) {
-		unsigned char tc;
-		unsigned char t;
-
-		index_i++;
-		index_j += hash[index_i];
-
-		tc = hash[index_i];
-		hash[index_i] = hash[index_j];
-		hash[index_j] = tc;
-
-		t = hash[index_i] + hash[index_j];
-		data[ind] = hash[t];
-	}
-
-	hash[256] = index_i;
-	hash[257] = index_j;
-}
-
-/****************************************************************
- Get a 16 byte hash from the contents of a file.
-
- Note that the hash is initialised, because the extra entropy is not
- worth the valgrind pain.
-*****************************************************************/
-
-static void do_filehash(const char *fname, unsigned char *the_hash)
-{
-	unsigned char buf[1011]; /* deliberate weird size */
-	unsigned char tmp_md4[16];
-	int fd, n;
-
-	ZERO_STRUCT(tmp_md4);
-
-	fd = open(fname,O_RDONLY,0);
-	if (fd == -1)
+	if (urand_fd != -1) {
 		return;
-
-	while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
-		mdfour(tmp_md4, buf, n);
-		for (n=0;n<16;n++)
-			the_hash[n] ^= tmp_md4[n];
-	}
-	close(fd);
-}
-
-/**************************************************************
- Try and get a good random number seed. Try a number of
- different factors. Firstly, try /dev/urandom - use if exists.
-
- We use /dev/urandom as a read of /dev/random can block if
- the entropy pool dries up. This leads clients to timeout
- or be very slow on connect.
-
- If we can't use /dev/urandom then seed the stream random generator
- above...
-**************************************************************/
-
-static int do_reseed(int fd)
-{
-	unsigned char seed_inbuf[40];
-	uint32_t v1, v2; struct timeval tval; pid_t mypid;
-	int reseed_data = 0;
-
-	if (fd == -1) {
-		fd = open( "/dev/urandom", O_RDONLY,0);
-		if (fd != -1) {
-			smb_set_close_on_exec(fd);
-		}
-	}
-	if (fd != -1
-	    && (read(fd, seed_inbuf, sizeof(seed_inbuf)) == sizeof(seed_inbuf))) {
-		seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
-		return fd;
 	}
-
-	/* Add in some secret file contents */
-
-	do_filehash("/etc/shadow", &seed_inbuf[0]);
-
-	/*
-	 * Add the counter, time of day, and pid.
-	 */
-
-	GetTimeOfDay(&tval);
-	mypid = getpid();
-	v1 = (counter++) + mypid + tval.tv_sec;
-	v2 = (counter++) * mypid + tval.tv_usec;
-
-	SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32));
-	SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36));
-
-	/*
-	 * Add any user-given reseed data.
-	 */
-
-	get_rand_reseed_data(&reseed_data);
-	if (reseed_data) {
-		size_t i;
-		for (i = 0; i < sizeof(seed_inbuf); i++)
-			seed_inbuf[i] ^= ((char *)(&reseed_data))[i % sizeof(reseed_data)];
+	urand_fd = open( "/dev/urandom", O_RDONLY,0);
+	if (urand_fd == -1) {
+		abort();
 	}
-
-	seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
-
-	return -1;
+	smb_set_close_on_exec(urand_fd);
 }
 
-/**
- Interface to the (hopefully) good crypto random number generator.
- Will use our internal PRNG if more than 40 bytes of random generation
- has been requested, otherwise tries to read from /dev/random
-**/
 _PUBLIC_ void generate_random_buffer(uint8_t *out, int len)
 {
-	unsigned char md4_buf[64];
-	unsigned char tmp_buf[16];
-	unsigned char *p;
-
-	if(!done_reseed) {
-		bytes_since_reseed += len;
-
-		/* Magic constant to try and avoid reading 40 bytes
-		 * and setting up the PRNG if the app only ever wants
-		 * a few bytes */
-		if (bytes_since_reseed < 40) {
-			if (urand_fd == -1) {
-				urand_fd = open( "/dev/urandom", O_RDONLY,0);
-				if (urand_fd != -1) {
-					smb_set_close_on_exec(urand_fd);
-				}
-			}
-			if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
-				return;
-			}
-		}
-
-		urand_fd = do_reseed(urand_fd);
-		done_reseed = true;
-	}
-
-	/*
-	 * Generate random numbers in chunks of 64 bytes,
-	 * then md4 them & copy to the output buffer.
-	 * This way the raw state of the stream is never externally
-	 * seen.
-	 */
+	ssize_t rw_ret;
 
-	p = out;
-	while(len > 0) {
-		int copy_len = len > 16 ? 16 : len;
+	open_urandom();
 
-		get_random_stream(md4_buf, sizeof(md4_buf));
-		mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
-		memcpy(p, tmp_buf, copy_len);
-		p += copy_len;
-		len -= copy_len;
+	rw_ret = read_data(urand_fd, out, len);
+	if (rw_ret != len) {
+		abort();
 	}
 }
 
-/**
- Interface to the (hopefully) good crypto random number generator.
- Will always use /dev/urandom if available.
-**/
+/*
+ * Keep generate_secret_buffer in case we ever want to do something
+ * different
+ */
 _PUBLIC_ void generate_secret_buffer(uint8_t *out, int len)
 {
-	if (urand_fd == -1) {
-		urand_fd = open( "/dev/urandom", O_RDONLY,0);
-		if (urand_fd != -1) {
-			smb_set_close_on_exec(urand_fd);
-		}
-	}
-	if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
-		return;
-	}
-
 	generate_random_buffer(out, len);
 }
diff --git a/lib/util/genrand.h b/lib/util/genrand.h
index 73ca601..ef6bbc6 100644
--- a/lib/util/genrand.h
+++ b/lib/util/genrand.h
@@ -20,17 +20,6 @@
 */
 
 /**
- Copy any user given reseed data.
-**/
-
-void set_rand_reseed_callback(void (*fn)(void *, int *), void *userdata);
-
-/**
- * Tell the random number generator it needs to reseed.
- */
-void set_need_random_reseed(void);
-
-/**
  Interface to the (hopefully) good crypto random number generator.
  Will use our internal PRNG if more than 40 bytes of random generation
  has been requested, otherwise tries to read from /dev/random
diff --git a/lib/util/idtree.c b/lib/util/idtree.c
index 2104c74..e2cfcc5 100644
--- a/lib/util/idtree.c
+++ b/lib/util/idtree.c
@@ -181,8 +181,13 @@ restart:
 	 */
 	n = id;
 	while (p->bitmap == IDR_FULL) {
-		if (!(p = pa[++l]))
+		if (l >= MAX_LEVEL) {
 			break;
+		}
+		p = pa[++l];
+		if (p == NULL) {
+			break;
+		}
 		n = n >> IDR_BITS;
 		set_bit((n & IDR_MASK), p->bitmap);
 	}
diff --git a/lib/util/parmlist.c b/lib/util/parmlist.c
deleted file mode 100644
index b3e1e9f..0000000
--- a/lib/util/parmlist.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* 
- *  Unix SMB/CIFS implementation.
- *  Copyright (C) Jelmer Vernooij			2009
- *  
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-#include "../lib/util/dlinklist.h"
-#include "../lib/util/parmlist.h"
-
-#undef strcasecmp
-
-struct parmlist_entry *parmlist_get(struct parmlist *ctx, const char *name)
-{
-	struct parmlist_entry *e;
-	for (e = ctx->entries; e; e = e->next) {
-		if (strcasecmp(e->key, name) == 0)
-			return e;
-	}
-
-	return NULL;
-}
-
-int parmlist_get_int(struct parmlist *ctx, const char *name, int default_v)
-{
-	struct parmlist_entry *p = parmlist_get(ctx, name);
-
-	if (p != NULL)
-		return strtol(p->value, NULL, 0); 
-
-	return default_v;
-}
-
-bool parmlist_get_bool(struct parmlist *ctx, const char *name, bool default_v)
-{
-	struct parmlist_entry *p = parmlist_get(ctx, name);
-	bool ret;
-
-	if (p == NULL)
-		return default_v;
-
-	if (!set_boolean(p->value, &ret)) {
-		DEBUG(0,("lp_bool(%s): value is not boolean!\n", p->value));
-		return default_v;
-	}
-
-	return ret;
-}
-
-const char *parmlist_get_string(struct parmlist *ctx, const char *name, 
-								const char *default_v)
-{
-	struct parmlist_entry *p = parmlist_get(ctx, name);
-
-	if (p == NULL)
-		return default_v;
-
-	return p->value;
-}
-
-const char **parmlist_get_string_list(struct parmlist *ctx, const char *name, 
-									  const char *separator)
-{
-	struct parmlist_entry *p = parmlist_get(ctx, name);
-	char **l;
-
-	if (p == NULL) {
-		return NULL;
-	}
-
-	l = str_list_make(ctx, p->value, separator);
-	return discard_const_p(const char *, l);
-}
-
-static struct parmlist_entry *parmlist_get_add(struct parmlist *ctx, const char *name)
-{
-	struct parmlist_entry *e = parmlist_get(ctx, name);
-
-	if (e != NULL)
-		return e;
-
-	e = talloc(ctx, struct parmlist_entry);
-	if (e == NULL)
-		return NULL;
-	e->key = talloc_strdup(e, name);
-	DLIST_ADD(ctx->entries, e);
-	return e;
-}
-
-int parmlist_set_string(struct parmlist *ctx, const char *name, 
-						const char *value)
-{
-	struct parmlist_entry *e = parmlist_get_add(ctx, name);
-	if (e == NULL)
-		return -1;
-
-	e->value = talloc_strdup(e, value);
-	return 0;
-}
diff --git a/lib/util/parmlist.h b/lib/util/parmlist.h
deleted file mode 100644
index 9bc4f36..0000000
--- a/lib/util/parmlist.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Generic parameter parsing interface
-   Copyright (C) Jelmer Vernooij					  2009
-   
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _PARMLIST_H /* _PARMLIST_H */
-#define _PARMLIST_H 
-
-struct parmlist_entry {
-	struct parmlist_entry *prev, *next;
-	char *key;
-	char *value;
-	char **list; /* For the source3 parametric options, to save the parsed list */
-	int priority;
-};
-
-struct parmlist {
-	struct parmlist_entry *entries;
-};
-
-/** Retrieve an integer from a parameter list. If not found, return default_v. */
-int parmlist_get_int(struct parmlist *ctx, const char *name, int default_v);
-
-/** Retrieve a string from a parameter list. If not found, return default_v. */
-const char *parmlist_get_string(struct parmlist *ctx, const char *name, 
-								const char *default_v);
-
-/** Retrieve the struct for an entry in a parmlist. */
-struct parmlist_entry *parmlist_get(struct parmlist *ctx, const char *name);
-
-/** Retrieve a string list from a parameter list. 
- * separator can contain characters to consider separators or can be 
- * NULL for the default set. */
-const char **parmlist_get_string_list(struct parmlist *ctx, const char *name, 
-									  const char *separator);
-
-/** Retrieve boolean from a parameter list. If not set, return default_v. */
-bool parmlist_get_bool(struct parmlist *ctx, const char *name, bool default_v);
-
-/** Set a parameter. */
-int parmlist_set_string(struct parmlist *ctx, const char *name, const char *value);
-
-#endif /* _PARMLIST_H */
diff --git a/lib/util/samba_util.h b/lib/util/samba_util.h
index 496923c..1f265e8 100644
--- a/lib/util/samba_util.h
+++ b/lib/util/samba_util.h
@@ -61,6 +61,8 @@ extern const char *panic_action;
 
 #include "fault.h"
 
+#include "lib/util/util.h"
+
 /**
  * Write backtrace to debug log
  */
@@ -583,35 +585,6 @@ _PUBLIC_ bool process_exists_by_pid(pid_t pid);
 _PUBLIC_ bool fcntl_lock(int fd, int op, off_t offset, off_t count, int type);
 
 /**
- * Write dump of binary data to a callback
- */
-void dump_data_cb(const uint8_t *buf, int len,
-		  bool omit_zero_bytes,
-		  void (*cb)(const char *buf, void *private_data),
-		  void *private_data);
-
-/**
- * Write dump of binary data to a FILE
- */
-void dump_data_file(const uint8_t *buf, int len, bool omit_zero_bytes,
-		    FILE *f);
-
-/**
- * Write dump of binary data to the log file.
- *
- * The data is only written if the log level is at least level.
- */
-_PUBLIC_ void dump_data(int level, const uint8_t *buf,int len);
-
-/**
- * Write dump of binary data to the log file.
- *
- * The data is only written if the log level is at least level for
- * debug class dbgc_class.
- */
-_PUBLIC_ void dump_data_dbgc(int dbgc_class, int level, const uint8_t *buf, int len);
-
-/**
  * Write dump of binary data to the log file.
  *
  * The data is only written if the log level is at least level.
@@ -847,6 +820,7 @@ struct server_id;
 
 struct server_id_buf { char buf[48]; }; /* probably a bit too large ... */
 char *server_id_str_buf(struct server_id id, struct server_id_buf *dst);
+size_t server_id_str_buf_unique(struct server_id id, char *buf, size_t buflen);
 
 bool server_id_same_process(const struct server_id *p1,
 			    const struct server_id *p2);
diff --git a/lib/util/server_id.c b/lib/util/server_id.c
index 60b5235..83a262d 100644
--- a/lib/util/server_id.c
+++ b/lib/util/server_id.c
@@ -65,14 +65,36 @@ char *server_id_str_buf(struct server_id id, struct server_id_buf *dst)
 	return dst->buf;
 }
 
+size_t server_id_str_buf_unique(struct server_id id, char *buf, size_t buflen)
+{
+	struct server_id_buf idbuf;
+	char unique_buf[21];	/* 2^64 is 18446744073709551616, 20 chars */
+	size_t idlen, unique_len, needed;
+
+	server_id_str_buf(id, &idbuf);
+
+	idlen = strlen(idbuf.buf);
+	unique_len = snprintf(unique_buf, sizeof(unique_buf), "%"PRIu64,
+			      id.unique_id);
+	needed = idlen + unique_len + 2;
+
+	if (buflen >= needed) {
+		memcpy(buf, idbuf.buf, idlen);
+		buf[idlen] = '/';
+		memcpy(buf + idlen + 1, unique_buf, unique_len+1);
+	}
+
+	return needed;
+}
+
 struct server_id server_id_from_string(uint32_t local_vnn,
 				       const char *pid_string)
 {
+	struct server_id templ = {
+		.vnn = NONCLUSTER_VNN, .pid = UINT64_MAX
+	};
 	struct server_id result;
-	unsigned long long pid;
-	unsigned int vnn, task_id = 0;
-
-	ZERO_STRUCT(result);
+	int ret;
 
 	/*
 	 * We accept various forms with 1, 2 or 3 component forms
@@ -80,27 +102,73 @@ struct server_id server_id_from_string(uint32_t local_vnn,
 	 * we want backwards compatibility for scripts that may call
 	 * smbclient.
 	 */
-	if (sscanf(pid_string, "%u:%llu.%u", &vnn, &pid, &task_id) == 3) {
-		result.vnn = vnn;
-		result.pid = pid;
-		result.task_id = task_id;
-	} else if (sscanf(pid_string, "%u:%llu", &vnn, &pid) == 2) {
-		result.vnn = vnn;
-		result.pid = pid;
-	} else if (sscanf(pid_string, "%llu.%u", &pid, &task_id) == 2) {
+
+	result = templ;
+	ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32"/%"SCNu64,
+		     &result.vnn, &result.pid, &result.task_id,
+		     &result.unique_id);
+	if (ret == 4) {
+		return result;
+	}
+
+	result = templ;
+	ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32,
+		     &result.vnn, &result.pid, &result.task_id);
+	if (ret == 3) {
+		return result;
+	}
+
+	result = templ;
+	ret = sscanf(pid_string, "%"SCNu32":%"SCNu64"/%"SCNu64,
+		     &result.vnn, &result.pid, &result.unique_id);
+	if (ret == 3) {
+		return result;
+	}
+
+	result = templ;
+	ret = sscanf(pid_string, "%"SCNu32":%"SCNu64,
+		     &result.vnn, &result.pid);
+	if (ret == 2) {
+		return result;
+	}
+
+	result = templ;
+	ret = sscanf(pid_string, "%"SCNu64".%"SCNu32"/%"SCNu64,
+		     &result.pid, &result.task_id, &result.unique_id);
+	if (ret == 3) {
+		result.vnn = local_vnn;
+		return result;
+	}
+
+	result = templ;
+	ret = sscanf(pid_string, "%"SCNu64".%"SCNu32,
+		     &result.pid, &result.task_id);
+	if (ret == 2) {
 		result.vnn = local_vnn;
-		result.pid = pid;
-		result.task_id = task_id;
-	} else if (sscanf(pid_string, "%llu", &pid) == 1) {
+		return result;
+	}
+
+	result = templ;
+	ret = sscanf(pid_string, "%"SCNu64"/%"SCNu64,
+		     &result.pid, &result.unique_id);
+	if (ret == 2) {
 		result.vnn = local_vnn;
-		result.pid = pid;
-	} else if (strcmp(pid_string, "disconnected") ==0) {
+		return result;
+	}
+
+	result = templ;
+	ret = sscanf(pid_string, "%"SCNu64, &result.pid);
+	if (ret == 1) {
+		result.vnn = local_vnn;
+		return result;
+	}
+
+	if (strcmp(pid_string, "disconnected") == 0) {
 		server_id_set_disconnected(&result);
-	} else {
-		result.vnn = NONCLUSTER_VNN;
-		result.pid = UINT64_MAX;
+		return result;
 	}
-	return result;
+
+	return templ;
 }
 
 /**
diff --git a/lib/util/server_id_db.c b/lib/util/server_id_db.c
index 0874129..1e65ce2 100644
--- a/lib/util/server_id_db.c
+++ b/lib/util/server_id_db.c
@@ -93,8 +93,7 @@ static int server_id_db_destructor(struct server_id_db *db)
 int server_id_db_add(struct server_id_db *db, const char *name)
 {
 	struct tdb_context *tdb = db->tdb->tdb;
-	struct server_id_buf buf;
-	TDB_DATA key, data;
+	TDB_DATA key;
 	char *n;
 	int ret;
 
@@ -110,10 +109,17 @@ int server_id_db_add(struct server_id_db *db, const char *name)
 
 	key = string_term_tdb_data(name);
 
-	server_id_str_buf(db->pid, &buf);
-	data = string_term_tdb_data(buf.buf);
+	{
+		size_t idlen = server_id_str_buf_unique(db->pid, NULL, 0);
+		char idbuf[idlen];
+
+		server_id_str_buf_unique(db->pid, idbuf, idlen);
+
+		ret = tdb_append(
+			tdb, key,
+			(TDB_DATA) { .dptr = (uint8_t *)idbuf, .dsize = idlen });
+	}
 
-	ret = tdb_append(tdb, key, data);
 	if (ret != 0) {
 		enum TDB_ERROR err = tdb_error(tdb);
 		strv_delete(&db->names, strv_find(db->names, name));
@@ -127,14 +133,15 @@ int server_id_db_prune_name(struct server_id_db *db, const char *name,
 			    struct server_id server)
 {
 	struct tdb_context *tdb = db->tdb->tdb;
-	struct server_id_buf buf;
+	size_t idbuf_len = server_id_str_buf_unique(server, NULL, 0);
+	char idbuf[idbuf_len];
 	TDB_DATA key;
 	uint8_t *data;
 	char *ids, *id;
 	int ret;
 
 	key = string_term_tdb_data(name);
-	server_id_str_buf(server, &buf);
+	server_id_str_buf_unique(server, idbuf, idbuf_len);
 
 	ret = tdb_chainlock(tdb, key);
 	if (ret == -1) {
@@ -150,7 +157,7 @@ int server_id_db_prune_name(struct server_id_db *db, const char *name,
 
 	ids = (char *)data;
 
-	id = strv_find(ids, buf.buf);
+	id = strv_find(ids, idbuf);
 	if (id == NULL) {
 		tdb_chainunlock(tdb, key);
 		TALLOC_FREE(data);
diff --git a/lib/util/sys_rw.c b/lib/util/sys_rw.c
new file mode 100644
index 0000000..f625066
--- /dev/null
+++ b/lib/util/sys_rw.c
@@ -0,0 +1,101 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison  1998-2005
+ * Copyright (C) Timur Bakeyev        2005
+ * Copyright (C) Bjoern Jacke    2006-2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "lib/util/sys_rw.h"
+
+/*******************************************************************
+A read wrapper that will deal with EINTR/EWOULDBLOCK
+********************************************************************/
+
+ssize_t sys_read(int fd, void *buf, size_t count)
+{
+	ssize_t ret;
+
+	do {
+		ret = read(fd, buf, count);
+	} while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
+			       errno == EWOULDBLOCK));
+
+	return ret;
+}
+
+/*******************************************************************
+A write wrapper that will deal with EINTR/EWOULDBLOCK.
+********************************************************************/
+
+ssize_t sys_write(int fd, const void *buf, size_t count)
+{
+	ssize_t ret;
+
+	do {
+		ret = write(fd, buf, count);
+	} while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
+			       errno == EWOULDBLOCK));
+
+	return ret;
+}
+
+/*******************************************************************
+A writev wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
+{
+	ssize_t ret;
+
+	do {
+		ret = writev(fd, iov, iovcnt);
+	} while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
+			       errno == EWOULDBLOCK));
+
+	return ret;
+}
+
+/*******************************************************************
+A pread wrapper that will deal with EINTR
+********************************************************************/
+
+ssize_t sys_pread(int fd, void *buf, size_t count, off_t off)
+{
+	ssize_t ret;
+
+	do {
+		ret = pread(fd, buf, count, off);
+	} while (ret == -1 && errno == EINTR);
+	return ret;
+}
+
+/*******************************************************************
+A write wrapper that will deal with EINTR
+********************************************************************/
+
+ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off)
+{
+	ssize_t ret;
+
+	do {
+		ret = pwrite(fd, buf, count, off);
+	} while (ret == -1 && errno == EINTR);
+	return ret;
+}
diff --git a/source3/lib/sys_rw.h b/lib/util/sys_rw.h
similarity index 100%
rename from source3/lib/sys_rw.h
rename to lib/util/sys_rw.h
diff --git a/lib/util/sys_rw_data.c b/lib/util/sys_rw_data.c
new file mode 100644
index 0000000..de71716
--- /dev/null
+++ b/lib/util/sys_rw_data.c
@@ -0,0 +1,117 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison  1998-2005
+ * Copyright (C) Timur Bakeyev        2005
+ * Copyright (C) Bjoern Jacke    2006-2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "lib/util/sys_rw_data.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/iov_buf.h"
+
+/****************************************************************************
+ Write all data from an iov array
+ NB. This can be called with a non-socket fd, don't add dependencies
+ on socket calls.
+****************************************************************************/
+
+ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt)
+{
+	ssize_t to_send;
+	ssize_t thistime;
+	size_t sent;
+	struct iovec iov_copy[iovcnt];
+	struct iovec *iov;
+
+	to_send = iov_buflen(orig_iov, iovcnt);
+	if (to_send == -1) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	thistime = sys_writev(fd, orig_iov, iovcnt);
+	if ((thistime <= 0) || (thistime == to_send)) {
+		return thistime;
+	}
+	sent = thistime;
+
+	/*
+	 * We could not send everything in one call. Make a copy of iov that
+	 * we can mess with.
+	 */
+
+	memcpy(iov_copy, orig_iov, sizeof(struct iovec) * iovcnt);
+	iov = iov_copy;
+
+	while (sent < to_send) {
+		bool ok;
+
+		ok = iov_advance(&iov, &iovcnt, thistime);
+		if (!ok) {
+			errno = EIO;
+			return -1;
+		}
+
+		thistime = sys_writev(fd, iov, iovcnt);
+		if (thistime <= 0) {
+			break;
+		}
+		sent += thistime;
+	}
+
+	return sent;
+}
+
+/****************************************************************************
+ Write data to a fd.
+ NB. This can be called with a non-socket fd, don't add dependencies
+ on socket calls.
+****************************************************************************/
+
+ssize_t write_data(int fd, const void *buffer, size_t n)
+{
+	struct iovec iov;
+
+	iov.iov_base = discard_const_p(void, buffer);
+	iov.iov_len = n;
+	return write_data_iov(fd, &iov, 1);
+}
+
+/*
+ * Blocking read n bytes from a fd
+ */
+
+ssize_t read_data(int fd, void *buffer, size_t n)
+{
+	ssize_t nread;
+
+	nread = 0;
+
+	while (nread < n) {
+		ssize_t ret;
+		ret = sys_read(fd, ((char *)buffer) + nread, n - nread);
+		if (ret <= 0) {
+			return ret;
+		}
+		nread += ret;
+	}
+
+	return nread;
+}
diff --git a/source3/lib/sys_rw_data.h b/lib/util/sys_rw_data.h
similarity index 100%
rename from source3/lib/sys_rw_data.h
rename to lib/util/sys_rw_data.h
diff --git a/lib/util/talloc_report.c b/lib/util/talloc_report.c
index 8d7d548..9b98347 100644
--- a/lib/util/talloc_report.c
+++ b/lib/util/talloc_report.c
@@ -146,11 +146,11 @@ static void talloc_report_str_helper(const void *ptr, int depth, int max_depth,
 
 	state->s = talloc_asprintf_append_largebuf(
 		state->s, &state->str_len,
-		"%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
+		"%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
 		depth*4, "", name,
 		(unsigned long)talloc_total_size(ptr),
 		(unsigned long)talloc_total_blocks(ptr),
-		talloc_reference_count(ptr));
+		talloc_reference_count(ptr), ptr);
 }
 
 char *talloc_report_str(TALLOC_CTX *mem_ctx, TALLOC_CTX *root)
diff --git a/lib/util/tests/asn1_tests.c b/lib/util/tests/asn1_tests.c
index 6dd7c64..e4b386a 100644
--- a/lib/util/tests/asn1_tests.c
+++ b/lib/util/tests/asn1_tests.c
@@ -337,8 +337,10 @@ static bool test_asn1_Integer(struct torture_context *tctx)
 
 		if (!asn1_write_Integer(data, integer_tests[i].value)) goto err;
 
-		blob.data = data->data;
-		blob.length = data->length;
+		if (!asn1_blob(data, &blob)) {
+			goto err;
+		}
+
 		torture_assert_data_blob_equal(tctx, blob, integer_tests[i].blob, "asn1_write_Integer gave incorrect result");
 
 		if (!asn1_load(data, blob)) goto err;
diff --git a/lib/util/tests/dlinklist.c b/lib/util/tests/dlinklist.c
index bef61d2..50adab3 100644
--- a/lib/util/tests/dlinklist.c
+++ b/lib/util/tests/dlinklist.c
@@ -43,7 +43,7 @@ static bool torture_local_dlinklist_simple(struct torture_context *tctx)
 	torture_comment(tctx, "add 5 elements at end\n");
 	for (i=0; i<5; i++) {
 		el = talloc(mem_ctx, struct listel);
-		DLIST_ADD_END(l1, el, NULL);
+		DLIST_ADD_END(l1, el);
 	}
 
 	torture_comment(tctx, "delete 3 from front\n");
@@ -57,7 +57,7 @@ static bool torture_local_dlinklist_simple(struct torture_context *tctx)
 	for (i=0; i < 3; i++) {
 		el = DLIST_TAIL(l1);
 		DLIST_REMOVE(l1, el);
-		DLIST_ADD_END(l2, el, NULL);
+		DLIST_ADD_END(l2, el);
 	}
 
 	torture_comment(tctx, "count forward\n");
@@ -87,7 +87,7 @@ static bool torture_local_dlinklist_simple(struct torture_context *tctx)
 	torture_assert(tctx, el2->next->next == el, "3rd in list");
 
 	torture_comment(tctx, "check DLIST_DEMOTE\n");
-	DLIST_DEMOTE(l1, el, NULL);
+	DLIST_DEMOTE(l1, el);
 	torture_assert(tctx, el->next == NULL, "last in list");
 	torture_assert(tctx, el2->prev == el, "backlink from head");
 
@@ -100,7 +100,7 @@ static bool torture_local_dlinklist_simple(struct torture_context *tctx)
 	torture_assert_int_equal(tctx, i, 6, "should have 6 elements");
 
 	torture_comment(tctx, "check DLIST_CONCATENATE\n");
-	DLIST_CONCATENATE(l1, l2, NULL);
+	DLIST_CONCATENATE(l1, l2);
 	torture_comment(tctx, "count forward\n");
 	for (i=0,el=l1; el; el=el->next) i++;
 	torture_assert_int_equal(tctx, i, 12, "should have 12 elements");
diff --git a/lib/util/tests/genrand.c b/lib/util/tests/genrand.c
index 3d48be0..81c20bc 100644
--- a/lib/util/tests/genrand.c
+++ b/lib/util/tests/genrand.c
@@ -23,17 +23,6 @@
 #include "torture/torture.h"
 #include "torture/local/proto.h"
 
-static void dummy_reseed(void *userdata, int *d)
-{
-	*d = 42;
-}
-
-static bool test_reseed_callback(struct torture_context *tctx)
-{
-	set_rand_reseed_callback(dummy_reseed, NULL);
-	return true;
-}
-
 static bool test_check_password_quality(struct torture_context *tctx)
 {
 	torture_assert(tctx, !check_password_quality(""), "empty password");
@@ -64,7 +53,6 @@ static bool test_generate_random_str(struct torture_context *tctx)
 struct torture_suite *torture_local_genrand(TALLOC_CTX *mem_ctx)
 {
 	struct torture_suite *suite = torture_suite_create(mem_ctx, "genrand");
-	torture_suite_add_simple_test(suite, "reseed_callback", test_reseed_callback);
 	torture_suite_add_simple_test(suite, "check_password_quality", test_check_password_quality);
 	torture_suite_add_simple_test(suite, "generate_random_str", test_generate_random_str);
 	return suite;
diff --git a/lib/util/tests/genrandperf.c b/lib/util/tests/genrandperf.c
new file mode 100644
index 0000000..32d19ab
--- /dev/null
+++ b/lib/util/tests/genrandperf.c
@@ -0,0 +1,39 @@
+/*
+   Unix SMB/CIFS implementation.
+   local testing of random data routines.
+   Copyright (C) Volker Lendecke <vl at samba.org> 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/genrand.h"
+
+int main(int argc, const char *argv[])
+{
+	int i, num;
+	uint64_t val;
+
+	if (argc != 2) {
+		fprintf(stderr, "genrandperf <num>\n");
+		exit(1);
+	}
+	num = atoi(argv[1]);
+
+	for(i=0; i<num; i++) {
+		generate_random_buffer((uint8_t *)&val, sizeof(val));
+	}
+	printf("%"PRIu64"\n", val);
+	return 0;
+}
diff --git a/lib/util/tests/parmlist.c b/lib/util/tests/parmlist.c
deleted file mode 100644
index df589ef..0000000
--- a/lib/util/tests/parmlist.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-
-   parmlist testing
-
-   Copyright (C) Jelmer Vernooij 2009
-   
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "torture/torture.h"
-#include "torture/local/proto.h"
-#include "../lib/util/parmlist.h"
-
-static bool test_get_int(struct torture_context *tctx)
-{
-	struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
-	parmlist_set_string(pctx, "bar", "3");
-	parmlist_set_string(pctx, "notint", "bla");
-	torture_assert_int_equal(tctx, 3, parmlist_get_int(pctx, "bar", 42), 
-							 "existing");
-	torture_assert_int_equal(tctx, 42, parmlist_get_int(pctx, "foo", 42),
-							 "default");
-	torture_assert_int_equal(tctx, 0, parmlist_get_int(pctx, "notint", 42),
-							 "Not an integer");
-	return true;
-}
-
-static bool test_get_string(struct torture_context *tctx)
-{
-	struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
-	parmlist_set_string(pctx, "bar", "mystring");
-	torture_assert_str_equal(tctx, "mystring", 
-		parmlist_get_string(pctx, "bar", "bla"), "existing");
-	torture_assert_str_equal(tctx, "bla", 
-		parmlist_get_string(pctx, "foo", "bla"), "default");
-	return true;
-}
-
-static bool test_get(struct torture_context *tctx)
-{
-	struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
-	struct parmlist_entry *e;
-	parmlist_set_string(pctx, "bar", "mystring");
-
-	e = parmlist_get(pctx, "bar");
-	torture_assert(tctx, e != NULL, "entry");
-	torture_assert_str_equal(tctx, e->key, "bar", "key");
-	torture_assert_str_equal(tctx, e->value, "mystring", "value");
-
-	e = parmlist_get(pctx, "non-existent");
-	torture_assert(tctx, e == NULL, "non-existent");
-	return true;
-}
-
-static bool test_get_bool(struct torture_context *tctx)
-{
-	struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
-	parmlist_set_string(pctx, "bar", "true");
-	parmlist_set_string(pctx, "gasoline", "invalid");
-
-	torture_assert(tctx, parmlist_get_bool(pctx, "bar", false), "set");
-	torture_assert(tctx, !parmlist_get_bool(pctx, "foo", false), "default");
-	torture_assert(tctx, !parmlist_get_bool(pctx, "gasoline", false), 
-				   "invalid");
-	return true;
-}
-
-static bool test_get_string_list(struct torture_context *tctx)
-{
-	struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
-	const char **ret;
-	parmlist_set_string(pctx, "bar", "true, false");
-
-	ret = parmlist_get_string_list(pctx, "bar", NULL);
-	torture_assert_int_equal(tctx, str_list_length(ret), 2, "length");
-	torture_assert_str_equal(tctx, "true", ret[0], "ret[0]");
-	torture_assert_str_equal(tctx, "false", ret[1], "ret[1]");
-	torture_assert(tctx, NULL == parmlist_get_string_list(pctx, "non-existent", NULL), "non-existent");
-
-	return true;
-}
-
-struct torture_suite *torture_local_util_parmlist(TALLOC_CTX *mem_ctx)
-{
-	struct torture_suite *suite = torture_suite_create(mem_ctx, "parmlist");
-
-	torture_suite_add_simple_test(suite, "get_int", test_get_int);
-	torture_suite_add_simple_test(suite, "get_string", test_get_string);
-	torture_suite_add_simple_test(suite, "get", test_get);
-	torture_suite_add_simple_test(suite, "get_bool", test_get_bool);
-	torture_suite_add_simple_test(suite, "get_string_list", test_get_string_list);
-
-	return suite;
-}
diff --git a/lib/util/time_basic.c b/lib/util/time_basic.c
index e4b0886..095236b 100644
--- a/lib/util/time_basic.c
+++ b/lib/util/time_basic.c
@@ -22,6 +22,7 @@
  */
 
 #include "replace.h"
+#include "system/time.h"
 #include "lib/util/time_basic.h"
 
 /**
@@ -29,7 +30,7 @@ a gettimeofday wrapper
 **/
 _PUBLIC_ void GetTimeOfDay(struct timeval *tval)
 {
-#ifdef HAVE_GETTIMEOFDAY_TZ
+#if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
 	gettimeofday(tval,NULL);
 #else
 	gettimeofday(tval);
diff --git a/lib/util/time_basic.h b/lib/util/time_basic.h
index d485399..e04cf1c 100644
--- a/lib/util/time_basic.h
+++ b/lib/util/time_basic.h
@@ -24,8 +24,7 @@
 #ifndef _SAMBA_TIME_BASIC_H_
 #define _SAMBA_TIME_BASIC_H_
 
-#include "replace.h"
-#include "system/time.h"
+struct timeval;
 
 /**
 a gettimeofday wrapper
diff --git a/lib/util/util.c b/lib/util/util.c
index d8a84da..03edd7f 100644
--- a/lib/util/util.c
+++ b/lib/util/util.c
@@ -773,7 +773,7 @@ void *malloc_array(size_t el_size, unsigned int count)
 
 void *memalign_array(size_t el_size, size_t align, unsigned int count)
 {
-	if (count*el_size >= MAX_MALLOC_SIZE) {
+	if (el_size == 0 || count >= MAX_MALLOC_SIZE/el_size) {
 		return NULL;
 	}
 
diff --git a/lib/util/util.h b/lib/util/util.h
new file mode 100644
index 0000000..5a0ce5c
--- /dev/null
+++ b/lib/util/util.h
@@ -0,0 +1,53 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Utility functions for Samba
+   Copyright (C) Andrew Tridgell 1992-1999
+   Copyright (C) Jelmer Vernooij 2005
+    
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __UTIL_SAMBA_UTIL_H__
+#define __UTIL_SAMBA_UTIL_H__
+
+/**
+ * Write dump of binary data to a callback
+ */
+void dump_data_cb(const uint8_t *buf, int len,
+		  bool omit_zero_bytes,
+		  void (*cb)(const char *buf, void *private_data),
+		  void *private_data);
+
+/**
+ * Write dump of binary data to a FILE
+ */
+void dump_data_file(const uint8_t *buf, int len, bool omit_zero_bytes,
+		    FILE *f);
+
+/**
+ * Write dump of binary data to the log file.
+ *
+ * The data is only written if the log level is at least level.
+ */
+_PUBLIC_ void dump_data(int level, const uint8_t *buf,int len);
+
+/**
+ * Write dump of binary data to the log file.
+ *
+ * The data is only written if the log level is at least level for
+ * debug class dbgc_class.
+ */
+_PUBLIC_ void dump_data_dbgc(int dbgc_class, int level, const uint8_t *buf, int len);
+
+#endif
diff --git a/lib/util/util_process.c b/lib/util/util_process.c
index 6036e27..bde6060 100644
--- a/lib/util/util_process.c
+++ b/lib/util/util_process.c
@@ -20,6 +20,7 @@
  */
 
 #include "util_process.h"
+#include "config.h"
 
 #ifdef HAVE_SYS_PRCTL_H
 #include <sys/prctl.h>
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index 9663bb0..31e2958 100755
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -54,24 +54,46 @@ bld.SAMBA_LIBRARY('socket-blocking',
                   local_include=False,
                   private_library=True)
 
+bld.SAMBA_LIBRARY('talloc_report',
+                  source='talloc_report.c',
+                  local_include=False,
+                  public_deps='talloc',
+                  private_library=True
+                  )
+
 bld.SAMBA_SUBSYSTEM('samba-util-core',
                     source='''xfile.c data_blob.c util_file.c time.c
                               signal.c util.c idtree.c fault.c
-                              substitute.c''',
+                              substitute.c util_process.c''',
                     deps='''time-basic samba-debug socket-blocking talloc
                             tevent execinfo pthread''',
                     local_include=False)
 
+bld.SAMBA_LIBRARY('tevent-unix-util',
+                  source='tevent_unix.c',
+                  local_include=False,
+                  deps='tevent',
+                  public_headers='tevent_unix.h',
+                  header_path=[ ('*', 'util') ],
+                  pc_files=[],
+                  vnum='0.0.1')
+
 if not bld.env.SAMBA_UTIL_CORE_ONLY:
 
     bld.env.public_headers_skip.append('charset_compat.h')
 
     bld.SAMBA_LIBRARY('genrand',
                       source='genrand.c',
-                      deps='time-basic socket-blocking LIBCRYPTO',
+                      deps='replace socket-blocking sys_rw',
                       local_include=False,
                       private_library=True)
 
+    bld.SAMBA_BINARY('genrandperf',
+                     source='tests/genrandperf.c',
+                     deps='genrand replace',
+                     local_include=False,
+                     install=False)
+
     bld.SAMBA_LIBRARY('samba-util',
                   source='''talloc_stack.c smb_threads.c
                     rbtree.c rfc1738.c become_daemon.c system.c select.c getpass.c
@@ -79,12 +101,11 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY:
                     params.c util_id.c util_net.c
                     util_strlist.c util_paths.c idtree_random.c base64.c
                     util_str.c util_str_common.c ms_fnmatch.c
-                    server_id.c dprintf.c parmlist.c bitmap.c pidfile.c
-                    tevent_debug.c util_process.c memcache.c''',
+                    server_id.c dprintf.c bitmap.c pidfile.c
+                    tevent_debug.c memcache.c''',
                   deps='samba-util-core DYNCONFIG close-low-fd tini tiniparser genrand',
-
                   public_deps='talloc tevent execinfo pthread LIBCRYPTO charset util_setid systemd systemd-daemon',
-                  public_headers='debug.h attr.h byteorder.h data_blob.h memory.h safe_string.h time.h talloc_stack.h xfile.h dlinklist.h samba_util.h string_wrappers.h idtree.h idtree_random.h blocking.h signal.h substitute.h fault.h genrand.h',
+                  public_headers='debug.h attr.h byteorder.h data_blob.h memory.h safe_string.h time.h talloc_stack.h xfile.h string_wrappers.h idtree.h idtree_random.h blocking.h signal.h substitute.h fault.h genrand.h',
                   header_path= [ ('dlinklist.h samba_util.h', '.'), ('*', 'util') ],
                   local_include=False,
                   vnum='0.0.1',
@@ -93,7 +114,7 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY:
 
     bld.SAMBA_LIBRARY('samba-modules',
                       source='modules.c',
-                      deps='errors samba-util',
+                      deps='samba-errors samba-util',
                       local_include=False,
                       private_library=True)
 
@@ -119,18 +140,11 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY:
                       private_library=True
                       )
 
-    bld.SAMBA_LIBRARY('talloc_report',
-                      source='talloc_report.c',
-                      local_include=False,
-                      public_deps='talloc',
-                      private_library=True
-                      )
-
     bld.SAMBA_LIBRARY('tevent-util',
-                      source='tevent_unix.c tevent_ntstatus.c tevent_werror.c',
+                      source='tevent_ntstatus.c tevent_werror.c',
                       local_include=False,
-                      public_deps='tevent errors',
-                      public_headers='tevent_ntstatus.h tevent_unix.h tevent_werror.h',
+                      public_deps='tevent samba-errors tevent-unix-util',
+                      public_headers='tevent_ntstatus.h tevent_werror.h',
                       header_path=[ ('*', 'util') ],
                       pc_files=[],
                       vnum='0.0.1'
@@ -172,3 +186,9 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY:
                       source='iov_buf.c',
                       local_include=False,
                       private_library=True)
+
+    bld.SAMBA3_LIBRARY('sys_rw',
+                       source='sys_rw.c sys_rw_data.c',
+                       deps='replace iov_buf',
+                       local_include=False,
+                       private_library=True)
diff --git a/lib/util/wscript_configure b/lib/util/wscript_configure
index e7bcbd6..a1e5801 100644
--- a/lib/util/wscript_configure
+++ b/lib/util/wscript_configure
@@ -110,19 +110,19 @@ conf.SET_TARGET_TYPE('systemd-journal', 'EMPTY')
 conf.SET_TARGET_TYPE('systemd', 'EMPTY')
 
 if Options.options.enable_systemd != False:
-    conf.check_cfg(package='libsystemd-daemon', args='--cflags --libs',
+    conf.CHECK_CFG(package='libsystemd-daemon', args='--cflags --libs',
                    msg='Checking for libsystemd-daemon')
     if not conf.CHECK_LIB('systemd-daemon', shlib=True):
         conf.CHECK_LIB('systemd', shlib=True)
 
 if Options.options.enable_systemd != False:
-    conf.check_cfg(package='libsystemd-journal', args='--cflags --libs',
+    conf.CHECK_CFG(package='libsystemd-journal', args='--cflags --libs',
                    msg='Checking for libsystemd-journal')
     if not conf.CHECK_LIB('systemd-journal', shlib=True):
         conf.CHECK_LIB('systemd', shlib=True)
 
 if Options.options.enable_lttng != False:
-    conf.check_cfg(package='lttng-ust', args='--cflags --libs',
+    conf.CHECK_CFG(package='lttng-ust', args='--cflags --libs',
                    msg='Checking for lttng-ust', uselib_store="LTTNG-UST")
     conf.CHECK_HEADERS('lttng/tracef.h', lib='lttng-st')
     conf.CHECK_LIB('lttng-ust', shlib=True)
diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 1ea2f75..38b1351 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -35,6 +35,7 @@
 #include "netlogon_creds_cli.h"
 #include "source3/include/messages.h"
 #include "source3/include/g_lock.h"
+#include "libds/common/roles.h"
 
 struct netlogon_creds_cli_locked_state;
 
@@ -1030,11 +1031,8 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 		return req;
 	}
 
-	status = dbwrap_delete(state->context->db.ctx,
-			       state->context->db.key_data);
-	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
-		status = NT_STATUS_OK;
-	}
+	status = dbwrap_purge(state->context->db.ctx,
+			      state->context->db.key_data);
 	if (tevent_req_nterror(req, status)) {
 		return tevent_req_post(req, ev);
 	}
@@ -1064,11 +1062,8 @@ static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
 	}
 	state->locked_state->is_glocked = true;
 
-	status = dbwrap_delete(state->context->db.ctx,
-			       state->context->db.key_data);
-	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
-		status = NT_STATUS_OK;
-	}
+	status = dbwrap_purge(state->context->db.ctx,
+			      state->context->db.key_data);
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
diff --git a/libcli/auth/spnego_parse.c b/libcli/auth/spnego_parse.c
index d4c5bdc..1b294df 100644
--- a/libcli/auth/spnego_parse.c
+++ b/libcli/auth/spnego_parse.c
@@ -32,12 +32,12 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
 	if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
 	if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
 
-	while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
+	while (!asn1_has_error(asn1) && 0 < asn1_tag_remaining(asn1)) {
 		int i;
 		uint8_t context;
 
 		if (!asn1_peek_uint8(asn1, &context)) {
-			asn1->has_error = true;
+			asn1_set_error(asn1);
 			break;
 		}
 
@@ -51,10 +51,10 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
 
 			mechTypes = talloc(mem_ctx, const char *);
 			if (mechTypes == NULL) {
-				asn1->has_error = true;
+				asn1_set_error(asn1);
 				return false;
 			}
-			for (i = 0; !asn1->has_error &&
+			for (i = 0; !asn1_has_error(asn1) &&
 				     0 < asn1_tag_remaining(asn1); i++) {
 				char *oid;
 				const char **p;
@@ -63,7 +63,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
 						   const char *, i+2);
 				if (p == NULL) {
 					talloc_free(mechTypes);
-					asn1->has_error = true;
+					asn1_set_error(asn1);
 					return false;
 				}
 				mechTypes = p;
@@ -97,7 +97,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
 			uint8_t type_peek;
 			if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
 			if (!asn1_peek_uint8(asn1, &type_peek)) {
-				asn1->has_error = true;
+				asn1_set_error(asn1);
 				break;
 			}
 			if (type_peek == ASN1_OCTET_STRING) {
@@ -119,7 +119,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
 			break;
 		}
 		default:
-			asn1->has_error = true;
+			asn1_set_error(asn1);
 			break;
 		}
 	}
@@ -127,7 +127,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
 	if (!asn1_end_tag(asn1)) return false;
 	if (!asn1_end_tag(asn1)) return false;
 
-	return !asn1->has_error;
+	return !asn1_has_error(asn1);
 }
 
 static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenInit *token)
@@ -190,7 +190,7 @@ static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenIni
 	if (!asn1_pop_tag(asn1)) return false;
 	if (!asn1_pop_tag(asn1)) return false;
 
-	return !asn1->has_error;
+	return !asn1_has_error(asn1);
 }
 
 static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
@@ -201,11 +201,11 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
 	if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
 	if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
 
-	while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
+	while (!asn1_has_error(asn1) && 0 < asn1_tag_remaining(asn1)) {
 		uint8_t context;
 		char *oid;
 		if (!asn1_peek_uint8(asn1, &context)) {
-			asn1->has_error = true;
+			asn1_set_error(asn1);
 			break;
 		}
 
@@ -234,7 +234,7 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
 			if (!asn1_end_tag(asn1)) return false;
 			break;
 		default:
-			asn1->has_error = true;
+			asn1_set_error(asn1);
 			break;
 		}
 	}
@@ -242,7 +242,7 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
 	if (!asn1_end_tag(asn1)) return false;
 	if (!asn1_end_tag(asn1)) return false;
 
-	return !asn1->has_error;
+	return !asn1_has_error(asn1);
 }
 
 static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTarg *token)
@@ -279,7 +279,7 @@ static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTar
 	if (!asn1_pop_tag(asn1)) return false;
 	if (!asn1_pop_tag(asn1)) return false;
 
-	return !asn1->has_error;
+	return !asn1_has_error(asn1);
 }
 
 ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token)
@@ -302,7 +302,7 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data
 	if (!asn1_load(asn1, data)) goto err;
 
 	if (!asn1_peek_uint8(asn1, &context)) {
-		asn1->has_error = true;
+		asn1_set_error(asn1);
 	} else {
 		switch (context) {
 		case ASN1_APPLICATION(0):
@@ -319,12 +319,14 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data
 			}
 			break;
 		default:
-			asn1->has_error = true;
+			asn1_set_error(asn1);
 			break;
 		}
 	}
 
-	if (!asn1->has_error) ret = asn1->ofs;
+	if (!asn1_has_error(asn1)) {
+		ret = asn1_current_ofs(asn1);
+	}
 
   err:
 
@@ -353,15 +355,16 @@ ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_da
 		write_negTokenTarg(asn1, &spnego->negTokenTarg);
 		break;
 	default:
-		asn1->has_error = true;
+		asn1_set_error(asn1);
 		break;
 	}
 
-	if (!asn1->has_error) {
-		*blob = data_blob_talloc(mem_ctx, asn1->data, asn1->length);
-		ret = asn1->ofs;
+	if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
+		goto err;
 	}
 
+	ret = asn1_current_ofs(asn1);
+
   err:
 
 	asn1_free(asn1);
@@ -423,12 +426,11 @@ bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
 		if (!asn1_pop_tag(asn1)) goto err;
 	}
 
-	if (asn1->has_error) {
+	if (asn1_has_error(asn1)) {
 		goto err;
 	}
 
-	*blob = data_blob_talloc(mem_ctx, asn1->data, asn1->length);
-	if (blob->length != asn1->length) {
+	if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
 		goto err;
 	}
 
diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build
index 51eb293..475b7d6 100755
--- a/libcli/auth/wscript_build
+++ b/libcli/auth/wscript_build
@@ -2,7 +2,7 @@
 
 bld.SAMBA_LIBRARY('cliauth',
                   source='',
-                  deps='MSRPC_PARSE LIBCLI_AUTH COMMON_SCHANNEL PAM_ERRORS SPNEGO_PARSE krb5samba errors NTLM_CHECK UTIL_LSARPC',
+                  deps='MSRPC_PARSE LIBCLI_AUTH COMMON_SCHANNEL PAM_ERRORS SPNEGO_PARSE krb5samba samba-errors NTLM_CHECK UTIL_LSARPC',
                   private_library=True,
                   grouping_library=True)
 
diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c
index 964cb0a..c5977cc 100644
--- a/libcli/cldap/cldap.c
+++ b/libcli/cldap/cldap.c
@@ -220,7 +220,6 @@ nomem:
 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
 				    struct cldap_incoming *in)
 {
-	DATA_BLOB blob;
 	struct asn1_data *asn1;
 	void *p;
 	struct cldap_search_state *search;
@@ -230,16 +229,12 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
 		goto error;
 	}
 
-	blob = data_blob_const(in->buf, in->len);
-
 	asn1 = asn1_init(in);
 	if (!asn1) {
 		goto nomem;
 	}
 
-	if (!asn1_load(asn1, blob)) {
-		goto nomem;
-	}
+	asn1_load_nocopy(asn1, in->buf, in->len);
 
 	in->ldap_msg = talloc(in, struct ldap_message);
 	if (in->ldap_msg == NULL) {
@@ -267,8 +262,11 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
 
 	search = talloc_get_type_abort(p, struct cldap_search_state);
 	search->response.in = talloc_move(search, &in);
+
 	search->response.asn1 = asn1;
-	search->response.asn1->ofs = 0;
+
+	asn1_load_nocopy(search->response.asn1,
+			 search->response.in->buf, search->response.in->len);
 
 	DLIST_REMOVE(c->searches.list, search);
 
@@ -677,7 +675,7 @@ struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
 	}
 	tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
 
-	DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
+	DLIST_ADD_END(cldap->searches.list, state);
 
 	return req;
 
diff --git a/libcli/dns/dns.c b/libcli/dns/dns.c
index 43e1c4e..7d066d8 100644
--- a/libcli/dns/dns.c
+++ b/libcli/dns/dns.c
@@ -23,9 +23,8 @@
 #include "system/network.h"
 #include <tevent.h>
 #include "lib/tsocket/tsocket.h"
-#include "libcli/util/werror.h"
 #include "libcli/dns/libdns.h"
-#include "lib/util/tevent_werror.h"
+#include "lib/util/tevent_unix.h"
 #include "lib/util/samba_util.h"
 #include "libcli/util/error.h"
 #include "librpc/gen_ndr/dns.h"
@@ -67,20 +66,20 @@ struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
 	ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
 						&local_addr);
 	if (ret != 0) {
-		tevent_req_werror(req, unix_to_werror(ret));
+		tevent_req_error(req, errno);
 		return tevent_req_post(req, ev);
 	}
 
 	ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
 						DNS_SERVICE_PORT, &server_addr);
 	if (ret != 0) {
-		tevent_req_werror(req, unix_to_werror(ret));
+		tevent_req_error(req, errno);
 		return tevent_req_post(req, ev);
 	}
 
 	ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
 	if (ret != 0) {
-		tevent_req_werror(req, unix_to_werror(ret));
+		tevent_req_error(req, errno);
 		return tevent_req_post(req, ev);
 	}
 
@@ -96,10 +95,10 @@ struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
 
 	if (!tevent_req_set_endtime(req, ev,
 				timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
+		tevent_req_oom(req);
 		return tevent_req_post(req, ev);
 	}
 
-
 	tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
 	return req;
 }
@@ -117,12 +116,12 @@ static void dns_udp_request_get_reply(struct tevent_req *subreq)
 	TALLOC_FREE(subreq);
 
 	if (len == -1 && err != 0) {
-		tevent_req_werror(req, unix_to_werror(err));
+		tevent_req_error(req, err);
 		return;
 	}
 
 	if (len != state->query_len) {
-		tevent_req_werror(req, WERR_NET_WRITE_FAULT);
+		tevent_req_error(req, EIO);
 		return;
 	}
 
@@ -132,7 +131,6 @@ static void dns_udp_request_get_reply(struct tevent_req *subreq)
 	}
 
 	tevent_req_set_callback(subreq, dns_udp_request_done, req);
-	return;
 }
 
 static void dns_udp_request_done(struct tevent_req *subreq)
@@ -149,7 +147,7 @@ static void dns_udp_request_done(struct tevent_req *subreq)
 	TALLOC_FREE(subreq);
 
 	if (len == -1 && err != 0) {
-		tevent_req_werror(req, unix_to_werror(err));
+		tevent_req_error(req, err);
 		return;
 	}
 
@@ -158,23 +156,23 @@ static void dns_udp_request_done(struct tevent_req *subreq)
 	tevent_req_done(req);
 }
 
-WERROR dns_udp_request_recv(struct tevent_req *req,
-			    TALLOC_CTX *mem_ctx,
-			    uint8_t **reply,
-			    size_t *reply_len)
+int dns_udp_request_recv(struct tevent_req *req,
+			 TALLOC_CTX *mem_ctx,
+			 uint8_t **reply,
+			 size_t *reply_len)
 {
 	struct dns_udp_request_state *state = tevent_req_data(req,
 			struct dns_udp_request_state);
-	WERROR w_error;
+	int err;
 
-	if (tevent_req_is_werror(req, &w_error)) {
+	if (tevent_req_is_unix_error(req, &err)) {
 		tevent_req_received(req);
-		return w_error;
+		return err;
 	}
 
 	*reply = talloc_move(mem_ctx, &state->reply);
 	*reply_len = state->reply_len;
 	tevent_req_received(req);
 
-	return WERR_OK;
+	return 0;
 }
diff --git a/libcli/dns/libdns.h b/libcli/dns/libdns.h
index 31474eb..7ea2eb6 100644
--- a/libcli/dns/libdns.h
+++ b/libcli/dns/libdns.h
@@ -43,11 +43,11 @@ struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
  *@param mem_ctx   talloc memory context to use for the reply string
  *@param reply     buffer that will be allocated and filled with the dns reply
  *@param reply_len length of the reply buffer
- *@return WERROR code depending on the async request result
+ *@return 0/errno
  */
-WERROR dns_udp_request_recv(struct tevent_req *req,
-			    TALLOC_CTX *mem_ctx,
-			    uint8_t **reply,
-			    size_t *reply_len);
+int dns_udp_request_recv(struct tevent_req *req,
+			 TALLOC_CTX *mem_ctx,
+			 uint8_t **reply,
+			 size_t *reply_len);
 
 #endif /*__LIBDNS_H__*/
diff --git a/libcli/drsuapi/drsuapi.h b/libcli/drsuapi/drsuapi.h
index a4fb15f..7c6cf2f 100644
--- a/libcli/drsuapi/drsuapi.h
+++ b/libcli/drsuapi/drsuapi.h
@@ -29,6 +29,7 @@ WERROR drsuapi_decrypt_attribute_value(TALLOC_CTX *mem_ctx,
 WERROR drsuapi_decrypt_attribute(TALLOC_CTX *mem_ctx, 
 				 const DATA_BLOB *gensec_skey,
 				 uint32_t rid,
+				 uint32_t dsdb_repl_flags,
 				 struct drsuapi_DsReplicaAttribute *attr);
 
 
diff --git a/libcli/drsuapi/repl_decrypt.c b/libcli/drsuapi/repl_decrypt.c
index 00b8db8..4a2a28f 100644
--- a/libcli/drsuapi/repl_decrypt.c
+++ b/libcli/drsuapi/repl_decrypt.c
@@ -28,6 +28,7 @@
 #include "../lib/crypto/crypto.h"
 #include "../libcli/drsuapi/drsuapi.h"
 #include "libcli/auth/libcli_auth.h"
+#include "dsdb/samdb/samdb.h"
 
 WERROR drsuapi_decrypt_attribute_value(TALLOC_CTX *mem_ctx,
 				       const DATA_BLOB *gensec_skey,
@@ -134,6 +135,7 @@ WERROR drsuapi_decrypt_attribute_value(TALLOC_CTX *mem_ctx,
 WERROR drsuapi_decrypt_attribute(TALLOC_CTX *mem_ctx, 
 				 const DATA_BLOB *gensec_skey,
 				 uint32_t rid,
+				 uint32_t dsdb_repl_flags,
 				 struct drsuapi_DsReplicaAttribute *attr)
 {
 	WERROR status;
@@ -164,6 +166,10 @@ WERROR drsuapi_decrypt_attribute(TALLOC_CTX *mem_ctx,
 		return WERR_OK;
 	}
 
+	if (dsdb_repl_flags & DSDB_REPL_FLAG_EXPECT_NO_SECRETS) {
+		return WERR_TOO_MANY_SECRETS;
+	}
+
 	if (attr->value_ctr.num_values > 1) {
 		return WERR_DS_DRA_INVALID_PARAMETER;
 	}
diff --git a/libcli/drsuapi/wscript_build b/libcli/drsuapi/wscript_build
index 9d9e54d..af57c63 100644
--- a/libcli/drsuapi/wscript_build
+++ b/libcli/drsuapi/wscript_build
@@ -3,6 +3,6 @@
 
 bld.SAMBA_SUBSYSTEM('LIBCLI_DRSUAPI',
 	source='repl_decrypt.c',
-	public_deps='LIBCLI_AUTH'
+	public_deps='LIBCLI_AUTH samdb'
 	)
 
diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c
index 0c664b7..76d2ee9 100644
--- a/libcli/ldap/ldap_message.c
+++ b/libcli/ldap/ldap_message.c
@@ -322,7 +322,7 @@ static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
 		if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(7))) return false;
 		if (!asn1_write_LDAPString(data, tree->u.present.attr)) return false;
 		if (!asn1_pop_tag(data)) return false;
-		return !data->has_error;
+		return !asn1_has_error(data);
 
 	case LDB_OP_APPROX:
 		/* approx test */
@@ -366,7 +366,7 @@ static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
 	default:
 		return false;
 	}
-	return !data->has_error;
+	return !asn1_has_error(data);
 }
 
 static bool ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
@@ -691,7 +691,10 @@ _PUBLIC_ bool ldap_encode(struct ldap_message *msg,
 
 	if (!asn1_pop_tag(data)) goto err;
 
-	*result = data_blob_talloc(mem_ctx, data->data, data->length);
+	if (!asn1_extract_blob(data, mem_ctx, result)) {
+		goto err;
+	}
+
 	asn1_free(data);
 
 	return true;
@@ -762,7 +765,7 @@ static struct ldb_val **ldap_decode_substring(TALLOC_CTX *mem_ctx, struct ldb_va
 	}
 	chunks[chunk_num]->length = strlen(value);
 
-	chunks[chunk_num + 1] = '\0';
+	chunks[chunk_num + 1] = NULL;
 
 	return chunks;
 }
@@ -845,7 +848,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
 		if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
 		if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
 		if (!asn1_end_tag(data)) goto failed;
-		if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
+		if (asn1_has_error(data) || (attrib == NULL) ||
+		    (value.data == NULL)) {
 			goto failed;
 		}
 
@@ -960,7 +964,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
 		if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
 		if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
 		if (!asn1_end_tag(data)) goto failed;
-		if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
+		if (asn1_has_error(data) || (attrib == NULL) ||
+		    (value.data == NULL)) {
 			goto failed;
 		}
 
@@ -979,7 +984,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
 		if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
 		if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
 		if (!asn1_end_tag(data)) goto failed;
-		if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
+		if (asn1_has_error(data) || (attrib == NULL) ||
+		    (value.data == NULL)) {
 			goto failed;
 		}
 
@@ -1017,7 +1023,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
 		if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
 		if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
 		if (!asn1_end_tag(data)) goto failed;
-		if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
+		if (asn1_has_error(data) || (attrib == NULL) ||
+		    (value.data == NULL)) {
 			goto failed;
 		}
 
@@ -1618,7 +1625,7 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
 	}
 
 	if (!asn1_end_tag(data)) goto prot_err;
-	if ((data->has_error) || (data->nesting != NULL)) {
+	if (asn1_has_error(data) || asn1_has_nesting(data)) {
 		return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
 	}
 	return NT_STATUS_OK;
@@ -1635,6 +1642,8 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
 */
 NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_size)
 {
+	int ret;
+
 	if (blob.length < 6) {
 		/*
 		 * We need at least 6 bytes to workout the length
@@ -1642,5 +1651,10 @@ NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_siz
 		 */
 		return STATUS_MORE_ENTRIES;
 	}
-	return asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), packet_size);
+
+	ret = asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), packet_size);
+	if (ret != 0) {
+		return map_nt_error_from_unix_common(ret);
+	}
+	return NT_STATUS_OK;
 }
diff --git a/libcli/ldap/wscript_build b/libcli/ldap/wscript_build
index 211a320..db5b1df 100644
--- a/libcli/ldap/wscript_build
+++ b/libcli/ldap/wscript_build
@@ -2,8 +2,7 @@
 
 bld.SAMBA_LIBRARY('cli-ldap-common',
                   source='ldap_message.c ldap_ndr.c',
-                  public_deps='errors talloc ldb',
-                  public_headers='ldap_message.h ldap_errors.h ldap_ndr.h',
+                  public_deps='samba-errors talloc ldb',
+                  private_headers='ldap_message.h ldap_errors.h ldap_ndr.h',
                   deps='samba-util asn1util NDR_SECURITY tevent',
-                  private_library=True
-	)
+                  private_library=True)
diff --git a/libcli/nbt/libnbt.h b/libcli/nbt/libnbt.h
index c345a1f..fd0c7fe 100644
--- a/libcli/nbt/libnbt.h
+++ b/libcli/nbt/libnbt.h
@@ -24,6 +24,8 @@
 
 #include "librpc/gen_ndr/nbt.h"
 #include "librpc/ndr/libndr.h"
+#include "lib/util/xfile.h"
+
 /*
   possible states for pending requests
 */
diff --git a/libcli/nbt/nbtsocket.c b/libcli/nbt/nbtsocket.c
index 6c62739..dacacae 100644
--- a/libcli/nbt/nbtsocket.c
+++ b/libcli/nbt/nbtsocket.c
@@ -127,8 +127,7 @@ static void nbt_name_socket_timeout(struct tevent_context *ev, struct tevent_tim
 					   nbt_name_socket_timeout, req);
 		if (req->state != NBT_REQUEST_SEND) {
 			req->state = NBT_REQUEST_SEND;
-			DLIST_ADD_END(req->nbtsock->send_queue, req,
-				      struct nbt_name_request *);
+			DLIST_ADD_END(req->nbtsock->send_queue, req);
 		}
 		TEVENT_FD_WRITEABLE(req->nbtsock->fde);
 		return;
@@ -418,7 +417,7 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
 				       (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
 
-	DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
+	DLIST_ADD_END(nbtsock->send_queue, req);
 
 	if (DEBUGLVL(10)) {
 		DEBUG(10,("Queueing nbt packet to %s:%d\n",
@@ -469,7 +468,7 @@ _PUBLIC_ NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
 		return ndr_map_error2ntstatus(ndr_err);
 	}
 
-	DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
+	DLIST_ADD_END(nbtsock->send_queue, req);
 
 	TEVENT_FD_WRITEABLE(nbtsock->fde);
 
diff --git a/libcli/security/dom_sid.h b/libcli/security/dom_sid.h
index cf3cede..bdcec94 100644
--- a/libcli/security/dom_sid.h
+++ b/libcli/security/dom_sid.h
@@ -36,6 +36,9 @@ extern const struct dom_sid global_sid_System;
 extern const struct dom_sid global_sid_NULL;
 extern const struct dom_sid global_sid_Authenticated_Users;
 extern const struct dom_sid global_sid_Network;
+extern const struct dom_sid global_sid_Asserted_Identity;
+extern const struct dom_sid global_sid_Asserted_Identity_Service;
+extern const struct dom_sid global_sid_Asserted_Identity_Authentication_Authority;
 extern const struct dom_sid global_sid_Creator_Owner;
 extern const struct dom_sid global_sid_Creator_Group;
 extern const struct dom_sid global_sid_Owner_Rights;
@@ -93,8 +96,7 @@ bool sid_split_rid(struct dom_sid *sid, uint32_t *rid);
 bool sid_peek_rid(const struct dom_sid *sid, uint32_t *rid);
 bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid *sid, uint32_t *rid);
 void sid_copy(struct dom_sid *dst, const struct dom_sid *src);
-bool sid_blob_parse(DATA_BLOB in, struct dom_sid *sid);
-bool sid_parse(const char *inbuf, size_t len, struct dom_sid *sid);
+bool sid_parse(const uint8_t *inbuf, size_t len, struct dom_sid *sid);
 int sid_compare_domain(const struct dom_sid *sid1, const struct dom_sid *sid2);
 NTSTATUS add_sid_to_array(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
 			  struct dom_sid **sids, uint32_t *num);
diff --git a/libcli/security/secace.c b/libcli/security/secace.c
index b7c9fc54..26c366a 100644
--- a/libcli/security/secace.c
+++ b/libcli/security/secace.c
@@ -69,25 +69,6 @@ void init_sec_ace(struct security_ace *t, const struct dom_sid *sid, enum securi
 	t->trustee = *sid;
 }
 
-/*******************************************************************
-  modify SID's permissions at ACL 
-********************************************************************/
-
-NTSTATUS sec_ace_mod_sid(struct security_ace *ace, size_t num, const struct dom_sid *sid, uint32_t mask)
-{
-	unsigned int i = 0;
-
-	if (!ace || !sid)  return NT_STATUS_INVALID_PARAMETER;
-
-	for (i = 0; i < num; i ++) {
-		if (dom_sid_equal(&ace[i].trustee, sid)) {
-			ace[i].access_mask = mask;
-			return NT_STATUS_OK;
-		}
-	}
-	return NT_STATUS_NOT_FOUND;
-}
-
 int nt_ace_inherit_comp(const struct security_ace *a1, const struct security_ace *a2)
 {
 	int a1_inh = a1->flags & SEC_ACE_FLAG_INHERITED_ACE;
diff --git a/libcli/security/secace.h b/libcli/security/secace.h
index 5416134..16c495d 100644
--- a/libcli/security/secace.h
+++ b/libcli/security/secace.h
@@ -27,7 +27,6 @@ bool sec_ace_object(uint8_t type);
 void sec_ace_copy(struct security_ace *ace_dest, const struct security_ace *ace_src);
 void init_sec_ace(struct security_ace *t, const struct dom_sid *sid, enum security_ace_type type,
 		  uint32_t mask, uint8_t flag);
-NTSTATUS sec_ace_mod_sid(struct security_ace *ace, size_t num, const struct dom_sid *sid, uint32_t mask);
 int nt_ace_inherit_comp( const struct security_ace *a1, const struct security_ace *a2);
 int nt_ace_canon_comp( const struct security_ace *a1, const struct security_ace *a2);
 void dacl_sort_into_canonical_order(struct security_ace *srclist, unsigned int num_aces);
diff --git a/libcli/security/secdesc.c b/libcli/security/secdesc.c
index 46b820e..6e20e90 100644
--- a/libcli/security/secdesc.c
+++ b/libcli/security/secdesc.c
@@ -396,25 +396,6 @@ struct sec_desc_buf *dup_sec_desc_buf(TALLOC_CTX *ctx, struct sec_desc_buf *src)
 	return make_sec_desc_buf( ctx, src->sd_size, src->sd);
 }
 
-/*******************************************************************
- Modify a SID's permissions in a struct security_descriptor.
-********************************************************************/
-
-NTSTATUS sec_desc_mod_sid(struct security_descriptor *sd, struct dom_sid *sid, uint32_t mask)
-{
-	NTSTATUS status;
-
-	if (!sd || !sid)
-		return NT_STATUS_INVALID_PARAMETER;
-
-	status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
-
-	if (!NT_STATUS_IS_OK(status))
-		return status;
-
-	return NT_STATUS_OK;
-}
-
 /*
  * Determine if an struct security_ace is inheritable
  */
@@ -586,7 +567,7 @@ NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
 			  " inherited as %s:%d/0x%02x/0x%08x\n",
 			  dom_sid_string(frame, &ace->trustee),
 			  ace->type, ace->flags, ace->access_mask,
-			  dom_sid_string(frame, &ace->trustee),
+			  dom_sid_string(frame, &new_ace->trustee),
 			  new_ace->type, new_ace->flags,
 			  new_ace->access_mask));
 
diff --git a/libcli/security/secdesc.h b/libcli/security/secdesc.h
index 4c96ccd..34d9d77 100644
--- a/libcli/security/secdesc.h
+++ b/libcli/security/secdesc.h
@@ -89,11 +89,6 @@ struct sec_desc_buf *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, struct secur
 ********************************************************************/
 struct sec_desc_buf *dup_sec_desc_buf(TALLOC_CTX *ctx, struct sec_desc_buf *src);
 
-/*******************************************************************
- Modify a SID's permissions in a struct security_descriptor.
-********************************************************************/
-NTSTATUS sec_desc_mod_sid(struct security_descriptor *sd, struct dom_sid *sid, uint32_t mask);
-
 bool sd_has_inheritable_components(const struct security_descriptor *parent_ctr, bool container);
 NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
 					struct security_descriptor **ppsd,
diff --git a/libcli/security/util_sid.c b/libcli/security/util_sid.c
index 5127109..ab3018a 100644
--- a/libcli/security/util_sid.c
+++ b/libcli/security/util_sid.c
@@ -55,6 +55,14 @@ const struct dom_sid global_sid_Authenticated_Users =	/* All authenticated rids
 const struct dom_sid global_sid_Restriced =			/* Restriced Code */
 { 1, 1, {0,0,0,0,0,5}, {12,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
 #endif
+
+const struct dom_sid global_sid_Asserted_Identity =       /* Asserted Identity */
+{ 1, 0, {0,0,0,0,0,18}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const struct dom_sid global_sid_Asserted_Identity_Service =	/* Asserted Identity Service */
+{ 1, 1, {0,0,0,0,0,18}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const struct dom_sid global_sid_Asserted_Identity_Authentication_Authority =	/* Asserted Identity Authentication Authority */
+{ 1, 1, {0,0,0,0,0,18}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
 const struct dom_sid global_sid_Network =			/* Network rids */
 { 1, 1, {0,0,0,0,0,5}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
 
@@ -254,14 +262,16 @@ void sid_copy(struct dom_sid *dst, const struct dom_sid *src)
 }
 
 /*****************************************************************
- Parse a on-the-wire SID (in a DATA_BLOB) to a struct dom_sid.
+ Parse a on-the-wire SID to a struct dom_sid.
 *****************************************************************/
 
-bool sid_blob_parse(DATA_BLOB in, struct dom_sid *sid)
+bool sid_parse(const uint8_t *inbuf, size_t len, struct dom_sid *sid)
 {
+	DATA_BLOB in = data_blob_const(inbuf, len);
 	enum ndr_err_code ndr_err;
-	ndr_err = ndr_pull_struct_blob_all(&in, NULL, sid,
-					   (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+
+	ndr_err = ndr_pull_struct_blob_all(
+		&in, NULL, sid, (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 		return false;
 	}
@@ -269,16 +279,6 @@ bool sid_blob_parse(DATA_BLOB in, struct dom_sid *sid)
 }
 
 /*****************************************************************
- Parse a on-the-wire SID to a struct dom_sid.
-*****************************************************************/
-
-bool sid_parse(const char *inbuf, size_t len, struct dom_sid *sid)
-{
-	DATA_BLOB in = data_blob_const(inbuf, len);
-	return sid_blob_parse(in, sid);
-}
-
-/*****************************************************************
  See if 2 SIDs are in the same domain
  this just compares the leading sub-auths
 *****************************************************************/
@@ -327,8 +327,9 @@ NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
 	uint32_t i;
 
 	for (i=0; i<(*num_sids); i++) {
-		if (dom_sid_compare(sid, &(*sids)[i]) == 0)
+		if (dom_sid_equal(sid, &(*sids)[i])) {
 			return NT_STATUS_OK;
+		}
 	}
 
 	return add_sid_to_array(mem_ctx, sid, sids, num_sids);
diff --git a/libcli/smb/smb1cli_read.c b/libcli/smb/smb1cli_read.c
index ab250ab..d7a7f43 100644
--- a/libcli/smb/smb1cli_read.c
+++ b/libcli/smb/smb1cli_read.c
@@ -26,9 +26,9 @@
 struct smb1cli_readx_state {
 	uint32_t size;
 	uint16_t vwv[12];
-	NTSTATUS status;
 	uint32_t received;
 	uint8_t *buf;
+	bool out_valid;
 };
 
 static void smb1cli_readx_done(struct tevent_req *subreq);
@@ -131,27 +131,36 @@ static void smb1cli_readx_done(struct tevent_req *subreq)
 	uint8_t *bytes;
 	uint16_t data_offset;
 	uint32_t bytes_offset;
+	NTSTATUS status;
 	static const struct smb1cli_req_expected_response expected[] = {
 	{
 		.status = NT_STATUS_OK,
 		.wct = 0x0C
 	},
+	{
+		.status = STATUS_BUFFER_OVERFLOW,
+		.wct = 0x0C
+	},
 	};
 
-	state->status = smb1cli_req_recv(subreq, state,
-					 &recv_iov,
-					 NULL, /* phdr */
-					 &wct,
-					 &vwv,
-					 NULL, /* pvwv_offset */
-					 &num_bytes,
-					 &bytes,
-					 &bytes_offset,
-					 NULL, /* inbuf */
-					 expected, ARRAY_SIZE(expected));
+	status = smb1cli_req_recv(subreq, state,
+				  &recv_iov,
+				  NULL, /* phdr */
+				  &wct,
+				  &vwv,
+				  NULL, /* pvwv_offset */
+				  &num_bytes,
+				  &bytes,
+				  &bytes_offset,
+				  NULL, /* inbuf */
+				  expected, ARRAY_SIZE(expected));
 	TALLOC_FREE(subreq);
-	if (tevent_req_nterror(req, state->status)) {
-		return;
+	if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+		/* no error */
+	} else {
+		if (tevent_req_nterror(req, status)) {
+			return;
+		}
 	}
 
 	/* size is the number of bytes the server returned.
@@ -189,6 +198,12 @@ static void smb1cli_readx_done(struct tevent_req *subreq)
 
 	state->buf = bytes + (data_offset - bytes_offset);
 
+	state->out_valid = true;
+
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
 	tevent_req_done(req);
 }
 
@@ -205,7 +220,7 @@ static void smb1cli_readx_done(struct tevent_req *subreq)
  * @param[out] received The number of bytes received.
  * @param[out] rcvbuf Pointer to the bytes received.
  *
- * @return NT_STATUS_OK on succsess.
+ * @return NT_STATUS_OK or STATUS_BUFFER_OVERFLOW on succsess.
  */
 NTSTATUS smb1cli_readx_recv(struct tevent_req *req,
 			    uint32_t *received,
@@ -213,12 +228,14 @@ NTSTATUS smb1cli_readx_recv(struct tevent_req *req,
 {
 	struct smb1cli_readx_state *state = tevent_req_data(
 		req, struct smb1cli_readx_state);
-	NTSTATUS status;
+	NTSTATUS status = NT_STATUS_OK;
 
-	if (tevent_req_is_nterror(req, &status)) {
+	if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+		*received = 0;
+		*rcvbuf = NULL;
 		return status;
 	}
 	*received = state->received;
 	*rcvbuf = state->buf;
-	return NT_STATUS_OK;
+	return status;
 }
diff --git a/libcli/smb/smb2_signing.c b/libcli/smb/smb2_signing.c
index 489e18b..b723554 100644
--- a/libcli/smb/smb2_signing.c
+++ b/libcli/smb/smb2_signing.c
@@ -22,6 +22,7 @@
 #include "system/filesys.h"
 #include "../libcli/smb/smb_common.h"
 #include "../lib/crypto/crypto.h"
+#include "lib/util/iov_buf.h"
 
 NTSTATUS smb2_signing_sign_pdu(DATA_BLOB signing_key,
 			       enum protocol_types protocol,
@@ -217,7 +218,7 @@ NTSTATUS smb2_signing_encrypt_pdu(DATA_BLOB encryption_key,
 	uint8_t sig[16];
 	int i;
 	size_t a_total;
-	size_t m_total = 0;
+	ssize_t m_total;
 	union {
 		struct aes_ccm_128_context ccm;
 		struct aes_gcm_128_context gcm;
@@ -241,8 +242,10 @@ NTSTATUS smb2_signing_encrypt_pdu(DATA_BLOB encryption_key,
 	}
 
 	a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
-	for (i=1; i < count; i++) {
-		m_total += vector[i].iov_len;
+
+	m_total = iov_buflen(&vector[1], count-1);
+	if (m_total == -1) {
+		return NT_STATUS_BUFFER_TOO_SMALL;
 	}
 
 	SSVAL(tf, SMB2_TF_FLAGS, SMB2_TF_FLAGS_ENCRYPTED);
@@ -311,7 +314,7 @@ NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key,
 	uint8_t sig[16];
 	int i;
 	size_t a_total;
-	size_t m_total = 0;
+	ssize_t m_total;
 	uint32_t msg_size = 0;
 	union {
 		struct aes_ccm_128_context ccm;
@@ -336,8 +339,10 @@ NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key,
 	}
 
 	a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
-	for (i=1; i < count; i++) {
-		m_total += vector[i].iov_len;
+
+	m_total = iov_buflen(&vector[1], count-1);
+	if (m_total == -1) {
+		return NT_STATUS_BUFFER_TOO_SMALL;
 	}
 
 	flags = SVAL(tf, SMB2_TF_FLAGS);
diff --git a/libcli/smb/smb2cli_ioctl.c b/libcli/smb/smb2cli_ioctl.c
index 42a424e..2b572ba 100644
--- a/libcli/smb/smb2cli_ioctl.c
+++ b/libcli/smb/smb2cli_ioctl.c
@@ -22,8 +22,6 @@
 #include "lib/util/tevent_ntstatus.h"
 #include "smb_common.h"
 #include "smbXcli_base.h"
-#include "librpc/ndr/libndr.h"
-#include "librpc/gen_ndr/ioctl.h"
 
 struct smb2cli_ioctl_state {
 	uint8_t fixed[0x38];
@@ -31,6 +29,7 @@ struct smb2cli_ioctl_state {
 	uint32_t max_input_length;
 	uint32_t max_output_length;
 	struct iovec *recv_iov;
+	bool out_valid;
 	DATA_BLOB out_input_buffer;
 	DATA_BLOB out_output_buffer;
 	uint32_t ctl_code;
@@ -161,32 +160,6 @@ struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx,
 	return req;
 }
 
-/*
- * 3.3.4.4 Sending an Error Response
- * An error code other than one of the following indicates a failure:
- */
-static bool smb2cli_ioctl_is_failure(uint32_t ctl_code, NTSTATUS status,
-				     size_t data_size)
-{
-	if (NT_STATUS_IS_OK(status)) {
-		return false;
-	}
-
-	/*
-	 * STATUS_INVALID_PARAMETER in a FSCTL_SRV_COPYCHUNK or
-	 * FSCTL_SRV_COPYCHUNK_WRITE Response, when returning an
-	 * SRV_COPYCHUNK_RESPONSE as described in section 2.2.32.1.
-	 */
-	if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) &&
-	    (ctl_code == FSCTL_SRV_COPYCHUNK ||
-	     ctl_code == FSCTL_SRV_COPYCHUNK_WRITE) &&
-	    data_size == sizeof(struct srv_copychunk_rsp)) {
-		return false;
-	}
-
-	return true;
-}
-
 static void smb2cli_ioctl_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req =
@@ -225,6 +198,16 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq)
 		.body_size = 0x09,
 	},
 	{
+		/*
+		 * a normal error
+		 */
+		.status = NT_STATUS_INVALID_PARAMETER,
+		.body_size = 0x09
+	},
+	{
+		/*
+		 * a special case for FSCTL_SRV_COPYCHUNK_*
+		 */
 		.status = NT_STATUS_INVALID_PARAMETER,
 		.body_size = 0x31
 	},
@@ -233,10 +216,35 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq)
 	status = smb2cli_req_recv(subreq, state, &iov,
 				  expected, ARRAY_SIZE(expected));
 	TALLOC_FREE(subreq);
-	if (iov == NULL && tevent_req_nterror(req, status)) {
-		return;
+	if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+		switch (state->ctl_code) {
+		case FSCTL_SRV_COPYCHUNK:
+		case FSCTL_SRV_COPYCHUNK_WRITE:
+			break;
+		default:
+			tevent_req_nterror(req, status);
+			return;
+		}
+
+		if (iov[1].iov_len != 0x30) {
+			tevent_req_nterror(req,
+					NT_STATUS_INVALID_NETWORK_RESPONSE);
+			return;
+		}
+	} else if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+		/* no error */
+	} else {
+		if (tevent_req_nterror(req, status)) {
+			return;
+		}
 	}
 
+	/*
+	 * At this stage we're sure that got a body size of 0x31,
+	 * either with NT_STATUS_OK, STATUS_BUFFER_OVERFLOW or
+	 * NT_STATUS_INVALID_PARAMETER.
+	 */
+
 	state->recv_iov = iov;
 	fixed = (uint8_t *)iov[1].iov_base;
 	dyn = (uint8_t *)iov[2].iov_base;
@@ -247,11 +255,6 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq)
 	output_buffer_offset = IVAL(fixed, 0x20);
 	output_buffer_length = IVAL(fixed, 0x24);
 
-	if (smb2cli_ioctl_is_failure(state->ctl_code, status, output_buffer_length) &&
-	    tevent_req_nterror(req, status)) {
-		return;
-	}
-
 	if ((input_buffer_offset > 0) && (input_buffer_length > 0)) {
 		uint32_t ofs;
 
@@ -332,6 +335,8 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq)
 		state->out_output_buffer.length = output_buffer_length;
 	}
 
+	state->out_valid = true;
+
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
@@ -349,8 +354,13 @@ NTSTATUS smb2cli_ioctl_recv(struct tevent_req *req,
 		struct smb2cli_ioctl_state);
 	NTSTATUS status = NT_STATUS_OK;
 
-	if (tevent_req_is_nterror(req, &status) &&
-	    smb2cli_ioctl_is_failure(state->ctl_code, status, state->out_output_buffer.length)) {
+	if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+		if (out_input_buffer) {
+			*out_input_buffer = data_blob_null;
+		}
+		if (out_output_buffer) {
+			*out_output_buffer = data_blob_null;
+		}
 		tevent_req_received(req);
 		return status;
 	}
diff --git a/libcli/smb/smb2cli_query_info.c b/libcli/smb/smb2cli_query_info.c
index a24844b..d499611 100644
--- a/libcli/smb/smb2cli_query_info.c
+++ b/libcli/smb/smb2cli_query_info.c
@@ -29,6 +29,7 @@ struct smb2cli_query_info_state {
 	uint32_t max_output_length;
 	struct iovec *recv_iov;
 	DATA_BLOB out_output_buffer;
+	bool out_valid;
 };
 
 static void smb2cli_query_info_done(struct tevent_req *subreq);
@@ -135,8 +136,12 @@ static void smb2cli_query_info_done(struct tevent_req *subreq)
 	status = smb2cli_req_recv(subreq, state, &iov,
 				  expected, ARRAY_SIZE(expected));
 	TALLOC_FREE(subreq);
-	if (tevent_req_nterror(req, status)) {
-		return;
+	if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+		/* no error */
+	} else {
+		if (tevent_req_nterror(req, status)) {
+			return;
+		}
 	}
 
 	state->recv_iov = iov;
@@ -170,6 +175,12 @@ static void smb2cli_query_info_done(struct tevent_req *subreq)
 		state->out_output_buffer.length = output_buffer_length;
 	}
 
+	state->out_valid = true;
+
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
 	tevent_req_done(req);
 }
 
@@ -180,9 +191,12 @@ NTSTATUS smb2cli_query_info_recv(struct tevent_req *req,
 	struct smb2cli_query_info_state *state =
 		tevent_req_data(req,
 		struct smb2cli_query_info_state);
-	NTSTATUS status;
+	NTSTATUS status = NT_STATUS_OK;
 
-	if (tevent_req_is_nterror(req, &status)) {
+	if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+		if (out_output_buffer) {
+			*out_output_buffer = data_blob_null;
+		}
 		tevent_req_received(req);
 		return status;
 	}
@@ -193,7 +207,7 @@ NTSTATUS smb2cli_query_info_recv(struct tevent_req *req,
 	}
 
 	tevent_req_received(req);
-	return NT_STATUS_OK;
+	return status;
 }
 
 NTSTATUS smb2cli_query_info(struct smbXcli_conn *conn,
diff --git a/libcli/smb/smb2cli_read.c b/libcli/smb/smb2cli_read.c
index 4a31622..8110b65 100644
--- a/libcli/smb/smb2cli_read.c
+++ b/libcli/smb/smb2cli_read.c
@@ -29,6 +29,7 @@ struct smb2cli_read_state {
 	struct iovec *recv_iov;
 	uint8_t *data;
 	uint32_t data_length;
+	bool out_valid;
 };
 
 static void smb2cli_read_done(struct tevent_req *subreq);
@@ -105,8 +106,12 @@ static void smb2cli_read_done(struct tevent_req *subreq)
 	status = smb2cli_req_recv(subreq, state, &iov,
 				  expected, ARRAY_SIZE(expected));
 	TALLOC_FREE(subreq);
-	if (tevent_req_nterror(req, status)) {
-		return;
+	if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+		/* no error */
+	} else {
+		if (tevent_req_nterror(req, status)) {
+			return;
+		}
 	}
 
 	data_offset = CVAL(iov[1].iov_base, 2);
@@ -120,6 +125,13 @@ static void smb2cli_read_done(struct tevent_req *subreq)
 
 	state->recv_iov = iov;
 	state->data = (uint8_t *)iov[2].iov_base;
+
+	state->out_valid = true;
+
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
 	tevent_req_done(req);
 }
 
@@ -129,15 +141,19 @@ NTSTATUS smb2cli_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	struct smb2cli_read_state *state =
 		tevent_req_data(req,
 		struct smb2cli_read_state);
-	NTSTATUS status;
+	NTSTATUS status = NT_STATUS_OK;
 
-	if (tevent_req_is_nterror(req, &status)) {
+	if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+		*data_length = 0;
+		*data = NULL;
+		tevent_req_received(req);
 		return status;
 	}
 	talloc_steal(mem_ctx, state->recv_iov);
 	*data_length = state->data_length;
 	*data = state->data;
-	return NT_STATUS_OK;
+	tevent_req_received(req);
+	return status;
 }
 
 NTSTATUS smb2cli_read(struct smbXcli_conn *conn,
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index 505d40d..ad6a254 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -3295,6 +3295,21 @@ static void smb2cli_req_writev_done(struct tevent_req *subreq)
 	}
 }
 
+static struct smbXcli_session* smbXcli_session_by_uid(struct smbXcli_conn *conn,
+						     uint64_t uid)
+{
+	struct smbXcli_session *s = conn->sessions;
+
+	for (; s; s = s->next) {
+		if (s->smb2->session_id != uid) {
+			continue;
+		}
+		break;
+	}
+
+	return s;
+}
+
 static NTSTATUS smb2cli_inbuf_parse_compound(struct smbXcli_conn *conn,
 					     uint8_t *buf,
 					     size_t buflen,
@@ -3362,14 +3377,7 @@ static NTSTATUS smb2cli_inbuf_parse_compound(struct smbXcli_conn *conn,
 				goto inval;
 			}
 
-			s = conn->sessions;
-			for (; s; s = s->next) {
-				if (s->smb2->session_id != uid) {
-					continue;
-				}
-				break;
-			}
-
+			s = smbXcli_session_by_uid(conn, uid);
 			if (s == NULL) {
 				DEBUG(10, ("unknown session_id %llu\n",
 					   (unsigned long long)uid));
@@ -3588,17 +3596,8 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
 			uint64_t uid = BVAL(inhdr, SMB2_HDR_SESSION_ID);
 
 			if (session == NULL) {
-				struct smbXcli_session *s;
-
-				s = state->conn->sessions;
-				for (; s; s = s->next) {
-					if (s->smb2->session_id != uid) {
-						continue;
-					}
-
-					session = s;
-					break;
-				}
+				session = smbXcli_session_by_uid(state->conn,
+								 uid);
 			}
 
 			if (session == NULL) {
@@ -5265,7 +5264,7 @@ struct smbXcli_session *smbXcli_session_create(TALLOC_CTX *mem_ctx,
 	}
 	talloc_set_destructor(session, smbXcli_session_destructor);
 
-	DLIST_ADD_END(conn->sessions, session, struct smbXcli_session *);
+	DLIST_ADD_END(conn->sessions, session);
 	session->conn = conn;
 
 	memcpy(session->smb2_channel.preauth_sha512,
@@ -5295,7 +5294,7 @@ struct smbXcli_session *smbXcli_session_copy(TALLOC_CTX *mem_ctx,
 	session->smb2_channel = src->smb2_channel;
 	session->disconnect_expired = src->disconnect_expired;
 
-	DLIST_ADD_END(src->conn->sessions, session, struct smbXcli_session *);
+	DLIST_ADD_END(src->conn->sessions, session);
 	talloc_set_destructor(session, smbXcli_session_destructor);
 
 	return session;
@@ -5794,7 +5793,7 @@ NTSTATUS smb2cli_session_create_channel(TALLOC_CTX *mem_ctx,
 	}
 
 	talloc_set_destructor(session2, smbXcli_session_destructor);
-	DLIST_ADD_END(conn->sessions, session2, struct smbXcli_session *);
+	DLIST_ADD_END(conn->sessions, session2);
 	session2->conn = conn;
 
 	memcpy(session2->smb2_channel.preauth_sha512,
diff --git a/libcli/smb/smb_constants.h b/libcli/smb/smb_constants.h
index c4cca15..563a574 100644
--- a/libcli/smb/smb_constants.h
+++ b/libcli/smb/smb_constants.h
@@ -309,7 +309,6 @@ enum csc_policy {
 #define FLAGS2_READ_PERMIT_EXECUTE     0x2000
 #define FLAGS2_32_BIT_ERROR_CODES      0x4000
 #define FLAGS2_UNICODE_STRINGS         0x8000
-#define FLAGS2_WIN2K_SIGNATURE         0xC852 /* Hack alert ! For now... JRA. */
 
 /* FileAttributes (search attributes) field */
 #define FILE_ATTRIBUTE_READONLY		0x0001L
diff --git a/libcli/smb/smb_unix_ext.h b/libcli/smb/smb_unix_ext.h
index ff705aa..e74976b 100644
--- a/libcli/smb/smb_unix_ext.h
+++ b/libcli/smb/smb_unix_ext.h
@@ -358,7 +358,7 @@ enum smb_whoami_flags {
  */
 
 #define SMB_REQUEST_TRANSPORT_ENCRYPTION     0x203 /* QFSINFO */
-
+#define SMB_ENCRYPTION_GSSAPI                0x8000
 
 /* The query/set info levels for POSIX ACLs. */
 #define SMB_QUERY_POSIX_ACL  0x204
diff --git a/libcli/smb/tstream_smbXcli_np.c b/libcli/smb/tstream_smbXcli_np.c
index 9cd6302..af0863e 100644
--- a/libcli/smb/tstream_smbXcli_np.c
+++ b/libcli/smb/tstream_smbXcli_np.c
@@ -976,7 +976,14 @@ static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
 		received = out_output_buffer.length;
 	}
 	TALLOC_FREE(subreq);
-	if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+	if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+		/*
+		 * STATUS_BUFFER_OVERFLOW means that there's
+		 * more data to read when the named pipe is used
+		 * in message mode (which is the case here).
+		 *
+		 * But we hide this from the caller.
+		 */
 		status = NT_STATUS_OK;
 	}
 	if (!NT_STATUS_IS_OK(status)) {
@@ -1052,9 +1059,9 @@ static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
 	 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
 	 * child of that.
 	 */
-	if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+	if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
 		/*
-		 * NT_STATUS_BUFFER_TOO_SMALL means that there's
+		 * STATUS_BUFFER_OVERFLOW means that there's
 		 * more data to read when the named pipe is used
 		 * in message mode (which is the case here).
 		 *
diff --git a/libcli/smb/wscript b/libcli/smb/wscript
index dad9821..394136b 100755
--- a/libcli/smb/wscript
+++ b/libcli/smb/wscript
@@ -9,7 +9,7 @@ def build(bld):
         deps='LIBASYNC_REQ',
         public_deps='talloc tevent',
         private_library=True,
-        public_headers='''
+        private_headers='''
             read_smb.h
         ''',
         )
@@ -43,12 +43,12 @@ def build(bld):
                 tstream_smbXcli_np.c
 	''',
 	deps='''
-                LIBCRYPTO NDR_SMB2_LEASE_STRUCT errors gensec krb5samba
+                LIBCRYPTO NDR_SMB2_LEASE_STRUCT samba-errors gensec krb5samba
                 smb_transport
         ''',
 	public_deps='talloc samba-util iov_buf',
 	private_library=True,
-	public_headers='''
+	private_headers='''
 		smb_common.h smb2_constants.h smb_constants.h
 		smb_signing.h smb_seal.h
 		smb2_create_blob.h smb2_signing.h
diff --git a/libcli/smbreadline/smbreadline.c b/libcli/smbreadline/smbreadline.c
index 80e10b0..c585554 100644
--- a/libcli/smbreadline/smbreadline.c
+++ b/libcli/smbreadline/smbreadline.c
@@ -137,6 +137,12 @@ char *smb_readline(const char *prompt, void (*callback)(void),
 		works in all of them to date, but we get compiler
 		warnings in some.  */
 		rl_attempted_completion_function = RL_COMPLETION_CAST completion_fn;
+
+		/*
+		 * We only want sensible characters as the word-break chars
+		 * for the most part. This allows us to tab through a path.
+		 */
+		rl_basic_word_break_characters = " \t\n";
 	}
 
 #if HAVE_DECL_RL_EVENT_HOOK
diff --git a/libcli/util/wscript_build b/libcli/util/wscript_build
index ccb882d..8123914 100644
--- a/libcli/util/wscript_build
+++ b/libcli/util/wscript_build
@@ -1,11 +1,13 @@
 #!/usr/bin/env python
 
 
-bld.SAMBA_LIBRARY('errors',
+bld.SAMBA_LIBRARY('samba-errors',
                   public_headers='error.h ntstatus.h doserr.h werror.h hresult.h',
                   header_path='core',
                   source='doserr.c errormap.c nterr.c errmap_unix.c hresult.c',
                   public_deps='talloc samba-debug',
-                  private_library=True
+                  # private_library=True,
+                  pc_files=[],
+                  vnum='1',
                   )
 
diff --git a/libds/common/flags.h b/libds/common/flags.h
index f821e17..88b93cb 100644
--- a/libds/common/flags.h
+++ b/libds/common/flags.h
@@ -187,7 +187,9 @@
 					   * Level */
 #define DS_DOMAIN_FUNCTION_2003		2
 #define DS_DOMAIN_FUNCTION_2008		3
-#define DS_DOMAIN_FUNCTION_2008_R2	4 
+#define DS_DOMAIN_FUNCTION_2008_R2	4
+#define DS_DOMAIN_FUNCTION_2012 	5
+#define DS_DOMAIN_FUNCTION_2012_R2	6
 
 /* sa->systemFlags on attributes */
 #define DS_FLAG_ATTR_NOT_REPLICATED    0x00000001
diff --git a/libds/common/wscript_build b/libds/common/wscript_build
index d7f8acb..3da3be2 100644
--- a/libds/common/wscript_build
+++ b/libds/common/wscript_build
@@ -2,6 +2,6 @@
 bld.SAMBA_LIBRARY('flag_mapping',
                   public_deps='talloc replace',
                   source='flag_mapping.c',
-		  private_library=True,
-                  public_headers='roles.h',
-		  deps='samba-util')
+                  private_library=True,
+                  private_headers='roles.h',
+                  deps='samba-util')
diff --git a/libgpo/gpo_ldap.c b/libgpo/gpo_ldap.c
index f797c2f..9a95f8b 100644
--- a/libgpo/gpo_ldap.c
+++ b/libgpo/gpo_ldap.c
@@ -295,7 +295,7 @@ ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads,
 	const char *gp_link, *gp_link_new;
 	ADS_MODLIST mods;
 
-	/* although ADS allows to set anything here, we better check here if
+	/* although ADS allows one to set anything here, we better check here if
 	 * the gpo_dn is sane */
 
 	if (!strnequal(gpo_dn, "LDAP://CN={", strlen("LDAP://CN={")) != 0) {
diff --git a/librpc/idl/clusapi.idl b/librpc/idl/clusapi.idl
index 5cb7610..8c4a227 100644
--- a/librpc/idl/clusapi.idl
+++ b/librpc/idl/clusapi.idl
@@ -1,9 +1,9 @@
-import "security.idl", "winreg.idl";
+import "winreg.idl", "misc.idl";
 
 #include "idl_types.h"
 
 [
-	uuid(b97db8b2-4c63-11cf-bff6-08002be23f2f),
+	uuid("b97db8b2-4c63-11cf-bff6-08002be23f2f"),
 	version(3.0),
 	pointer_default(unique),
 	endpoint("ncacn_ip_tcp:"),
@@ -28,15 +28,15 @@ import "security.idl", "winreg.idl";
 	typedef [context_handle] void *HNETINTERFACE_RPC;
 	typedef [context_handle] void *HBATCH_PORT_RPC;
 #else
-	#define HCLUSTER_RPC policy_handle
-	#define HNODE_RPC policy_handle
-	#define HGROUP_RPC policy_handle
-	#define HRES_RPC policy_handle
-	#define HKEY_RPC policy_handle
-	#define HNOTIFY_RPC policy_handle
-	#define HNETWORK_RPC policy_handle
-	#define HNETINTERFACE_RPC policy_handle
-	#define HBATCH_PORT_RPC policy_handle
+#define HCLUSTER_RPC policy_handle
+#define HNODE_RPC policy_handle
+#define HGROUP_RPC policy_handle
+#define HRES_RPC policy_handle
+#define HKEY_RPC policy_handle
+#define HNOTIFY_RPC policy_handle
+#define HNETWORK_RPC policy_handle
+#define HNETINTERFACE_RPC policy_handle
+#define HBATCH_PORT_RPC policy_handle
 #endif
 
 	typedef struct {
@@ -546,7 +546,7 @@ import "security.idl", "winreg.idl";
 	clusapi_SetValue(
 		[ in ] HKEY_RPC hKey,
 		[ in, string ] [charset(UTF16)] uint16 *lpValueName,
-		[ in ] uint32 dwType,
+		[ in ] winreg_Type dwType,
 		[ in, size_is(cbData) ] uint8 *lpData,
 		[ in ] uint32 cbData,
 		[ out ] WERROR *rpc_status
@@ -569,7 +569,7 @@ import "security.idl", "winreg.idl";
 	clusapi_QueryValue(
 		[ in ] HKEY_RPC hKey,
 		[ in, string ] [charset(UTF16)] uint16 *lpValueName,
-		[ out ] uint32 *lpValueType,
+		[ out ] winreg_Type *lpValueType,
 		[ out, size_is(cbData) ] uint8 *lpData,
 		[ in ] uint32 cbData,
 		[ out ] uint32 *lpcbRequired,
@@ -594,7 +594,7 @@ import "security.idl", "winreg.idl";
 		[ in ] HKEY_RPC hKey,
 		[ in ] uint32 dwIndex,
 		[ out, string ] [charset(UTF16)] uint16 **lpValueName,
-		[ out ] uint32 *lpType,
+		[ out ] winreg_Type *lpType,
 		[ out, size_is(*lpcbData) ] uint8 *lpData,
 		[ in, out ] uint32 *lpcbData,
 		[ out ] uint32 *TotalSize,
@@ -1114,10 +1114,29 @@ import "security.idl", "winreg.idl";
 	/*****************/
 	/* Function 0x4D */
 
+	typedef [v1_enum] enum {
+		CLUSCTL_GROUP_UNKNOWN				= 0x03000000,
+		CLUSCTL_GROUP_GET_CHARACTERISTICS		= 0x03000005,
+		CLUSCTL_GROUP_GET_FLAGS				= 0x03000009,
+		CLUSCTL_GROUP_GET_NAME				= 0x03000029,
+		CLUSCTL_GROUP_GET_ID				= 0x03000039,
+		CLUSCTL_GROUP_ENUM_COMMON_PROPERTIES		= 0x03000051,
+		CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES		= 0x03000055,
+		CLUSCTL_GROUP_GET_COMMON_PROPERTIES		= 0x03000059,
+		CLUSCTL_GROUP_SET_COMMON_PROPERTIES		= 0x0340005E,
+		CLUSCTL_GROUP_VALIDATE_COMMON_PROPERTIES	= 0x03000061,
+		CLUSCTL_GROUP_GET_COMMON_PROPERTY_FMTS		= 0x03000065,
+		CLUSCTL_GROUP_ENUM_PRIVATE_PROPERTIES		= 0x03000079,
+		CLUSCTL_GROUP_GET_RO_PRIVATE_PROPERTIES		= 0x0300007D,
+		CLUSCTL_GROUP_GET_PRIVATE_PROPERTIES		= 0x03000081,
+		CLUSCTL_GROUP_SET_PRIVATE_PROPERTIES		= 0x03400086,
+		CLUSCTL_GROUP_VALIDATE_PRIVATE_PROPERTIES	= 0x03000089
+	} clusapi_GroupControlCode;
+
 	WERROR
 	clusapi_GroupControl(
 		[ in ] HGROUP_RPC hGroup,
-		[ in ] uint32 dwControlCode,
+		[ in ] clusapi_GroupControlCode dwControlCode,
 		[ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
 		[ in ] uint32 nInBufferSize,
 		[ out, size_is(nOutBufferSize),
@@ -1149,10 +1168,29 @@ import "security.idl", "winreg.idl";
 	/*****************/
 	/* Function 0x4F */
 
+	typedef [v1_enum] enum {
+		CLUSCTL_NODE_UNKNOWN				= 0x04000000,
+		CLUSCTL_NODE_GET_CHARACTERISTICS		= 0x04000005,
+		CLUSCTL_NODE_GET_FLAGS				= 0x04000009,
+		CLUSCTL_NODE_GET_NAME				= 0x04000029,
+		CLUSCTL_NODE_GET_ID				= 0x04000039,
+		CLUSCTL_NODE_GET_CLUSTER_SERVICE_ACCOUNT_NAME	= 0x04000041,
+		CLUSCTL_NODE_ENUM_COMMON_PROPERTIES		= 0x04000051,
+		CLUSCTL_NODE_GET_RO_COMMON_PROPERTIES		= 0x04000055,
+		CLUSCTL_NODE_GET_COMMON_PROPERTIES		= 0x04000059,
+		CLUSCTL_NODE_SET_COMMON_PROPERTIES		= 0x0440005E,
+		CLUSCTL_NODE_VALIDATE_COMMON_PROPERTIES		= 0x04000061,
+		CLUSCTL_NODE_ENUM_PRIVATE_PROPERTIES		= 0x04000079,
+		CLUSCTL_NODE_GET_RO_PRIVATE_PROPERTIES		= 0x0400007D,
+		CLUSCTL_NODE_GET_PRIVATE_PROPERTIES		= 0x04000081,
+		CLUSCTL_NODE_SET_PRIVATE_PROPERTIES		= 0x04400086,
+		CLUSCTL_NODE_VALIDATE_PRIVATE_PROPERTIES	= 0x04000089
+	} clusapi_NodeControlCode;
+
 	WERROR
 	clusapi_NodeControl(
 		[ in ] HNODE_RPC hNode,
-		[ in ] uint32 dwControlCode,
+		[ in ] clusapi_NodeControlCode dwControlCode,
 		[ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
 		[ in ] uint32 nInBufferSize,
 		[ out, size_is(nOutBufferSize),
@@ -1530,6 +1568,54 @@ import "security.idl", "winreg.idl";
 		CLUSCTL_CLUSTER_IS_READY_FOR_UPGRADE		= 0x070000d5
 	} clusapi_ClusterControlCode;
 
+	typedef [v1_enum] enum {
+		CLUSPROP_SYNTAX_ENDMARK = 0x00000000,
+		CLUSPROP_SYNTAX_NAME = 0x00040003,
+		CLUSPROP_SYNTAX_RESCLASS = 0x00020002,
+		CLUSPROP_SYNTAX_LIST_VALUE_SZ = 0x00010003,
+		CLUSPROP_SYNTAX_LIST_VALUE_EXPAND_SZ = 0x00010004,
+		CLUSPROP_SYNTAX_LIST_VALUE_DWORD = 0x00010002,
+		CLUSPROP_SYNTAX_LIST_VALUE_BINARY = 0x00010001,
+		CLUSPROP_SYNTAX_LIST_VALUE_MULTI_SZ = 0x00010005,
+		CLUSPROP_SYNTAX_LIST_VALUE_LONG = 0x00010007,
+		CLUSPROP_SYNTAX_LIST_VALUE_EXPANDED_SZ = 0x00010008,
+		CLUSPROP_SYNTAX_LIST_VALUE_SECURITY_DESCRIPTOR = 0x00010009,
+		CLUSPROP_SYNTAX_LIST_VALUE_LARGE_INTEGER = 0x0001000a,
+		CLUSPROP_SYNTAX_LIST_VALUE_ULARGE_INTEGER = 0x00010006,
+		CLUSPROP_SYNTAX_LIST_VALUE_WORD = 0x0001000b,
+		CLUSPROP_SYNTAX_LIST_VALUE_FILETIME = 0x0001000c,
+		CLUSPROP_SYNTAX_DISK_SIGNATURE = 0x00050002,
+		CLUSPROP_SYNTAX_SCSI_ADDRESS = 0x00060002,
+		CLUSPROP_SYNTAX_DISK_NUMBER = 0x00070002,
+		CLUSPROP_SYNTAX_PARTITION_INFO = 0x00080001,
+		CLUSPROP_SYNTAX_DISK_SERIALNUMBER = 0x000a0003,
+		CLUSPROP_SYNTAX_DISK_GUID = 0x000b0003,
+		CLUSPROP_SYNTAX_DISK_SIZE = 0x000c0006,
+		CLUSPROP_SYNTAX_PARTITION_INFO_EX = 0x000d0001
+	} CLUSTER_PROPERTY_SYNTAX;
+
+	typedef struct {
+		CLUSTER_PROPERTY_SYNTAX Syntax;
+		uint32 Size;
+		[subcontext(0),subcontext_size(Size)] [flag(NDR_REMAINING)] DATA_BLOB Buffer;
+		[flag(NDR_ALIGN4)] DATA_BLOB Padding;
+	} clusapi_propertyValues;
+
+	typedef struct {
+		[value(CLUSPROP_SYNTAX_NAME)] CLUSTER_PROPERTY_SYNTAX syntax_name;
+		[value(strlen_m_term(buffer)*2)] uint32 size;
+		nstring buffer;
+		[flag(NDR_ALIGN2)] DATA_BLOB padding;
+		clusapi_propertyValues PropertyValues;
+		[value(CLUSPROP_SYNTAX_ENDMARK)] CLUSTER_PROPERTY_SYNTAX end_mark;
+	} clusapi_propertyValue;
+
+	typedef [public] struct {
+		uint32 propertyCount;
+		clusapi_propertyValue propertyValues[propertyCount];
+		[value(CLUSPROP_SYNTAX_ENDMARK)] CLUSTER_PROPERTY_SYNTAX end_mark;
+	} clusapi_PROPERTY_LIST;
+
 	WERROR
 	clusapi_ClusterControl(
 		[ in ] HCLUSTER_RPC hCluster,
@@ -1811,7 +1897,7 @@ import "security.idl", "winreg.idl";
 	WERROR
 	clusapi_CreateEnumEx(
 		[in] HCLUSTER_RPC hCluster,
-		[in] uint32 dwType,
+		[in] ClusterEnumType dwType,
 		[in] uint32 dwOptions,
 		[out] ENUM_LIST **ReturnIdEnum,
 		[out] ENUM_LIST **ReturnNameEnum,
@@ -1960,7 +2046,7 @@ import "security.idl", "winreg.idl";
 #endif
 
 	typedef struct {
-		uint32 dwObjectType;	  // really of type CLUSTER_OBJECT_TYPE_RPC
+		uint32 dwObjectType;	  /* really of type CLUSTER_OBJECT_TYPE_RPC */
 		hyper FilterFlags;
 	} NOTIFY_FILTER_AND_TYPE_RPC;
 
@@ -1982,9 +2068,9 @@ import "security.idl", "winreg.idl";
 	/*****************/
 	/* Function 0x89 */
 
-	//
-	// Notify interface V2 functions
-	//
+	/*
+	 * Notify interface V2 functions
+	 */
 #if 0
 	HNOTIFY_RPC
 	clusapi_CreateNotifyV2(
@@ -2197,32 +2283,6 @@ import "security.idl", "winreg.idl";
 	} CLUSTER_PROPERTY_FORMAT;
 
 	typedef enum {
-		CLUSPROP_SYNTAX_ENDMARK = 0x00000000,
-		CLUSPROP_SYNTAX_NAME = 0x00040003,
-		CLUSPROP_SYNTAX_RESCLASS = 0x00020002,
-		CLUSPROP_SYNTAX_LIST_VALUE_SZ = 0x00010003,
-		CLUSPROP_SYNTAX_LIST_VALUE_EXPAND_SZ = 0x00010004,
-		CLUSPROP_SYNTAX_LIST_VALUE_DWORD = 0x00010002,
-		CLUSPROP_SYNTAX_LIST_VALUE_BINARY = 0x00010001,
-		CLUSPROP_SYNTAX_LIST_VALUE_MULTI_SZ = 0x00010005,
-		CLUSPROP_SYNTAX_LIST_VALUE_LONG = 0x00010007,
-		CLUSPROP_SYNTAX_LIST_VALUE_EXPANDED_SZ = 0x00010008,
-		CLUSPROP_SYNTAX_LIST_VALUE_SECURITY_DESCRIPTOR = 0x00010009,
-		CLUSPROP_SYNTAX_LIST_VALUE_LARGE_INTEGER = 0x0001000a,
-		CLUSPROP_SYNTAX_LIST_VALUE_ULARGE_INTEGER = 0x00010006,
-		CLUSPROP_SYNTAX_LIST_VALUE_WORD = 0x0001000b,
-		CLUSPROP_SYNTAX_LIST_VALUE_FILETIME = 0x0001000c,
-		CLUSPROP_SYNTAX_DISK_SIGNATURE = 0x00050002,
-		CLUSPROP_SYNTAX_SCSI_ADDRESS = 0x00060002,
-		CLUSPROP_SYNTAX_DISK_NUMBER = 0x00070002,
-		CLUSPROP_SYNTAX_PARTITION_INFO = 0x00080001,
-		CLUSPROP_SYNTAX_DISK_SERIALNUMBER = 0x000a0003,
-		CLUSPROP_SYNTAX_DISK_GUID = 0x000b0003,
-		CLUSPROP_SYNTAX_DISK_SIZE = 0x000c0006,
-		CLUSPROP_SYNTAX_PARTITION_INFO_EX = 0x000d0001
-	} CLUSTER_PROPERTY_SYNTAX;
-
-	typedef enum {
 		CLUS_CHAR_UNKNOWN = 0x00000000,
 		CLUS_CHAR_QUORUM = 0x00000001,
 		CLUS_CHAR_DELETE_REQUIRES_ALL_NODES = 0x00000002,
diff --git a/librpc/idl/dcom.idl b/librpc/idl/dcom.idl
index 30d6d43..e53d7b8 100644
--- a/librpc/idl/dcom.idl
+++ b/librpc/idl/dcom.idl
@@ -26,10 +26,12 @@ interface IUnknown
 {
 	/*****************/
 	/* Function 0x00 */
-	/* Returns the interface with the specified IID 
+	/* Returns the interface with the specified IID
 	   if implemented by this object */
-	[local] WERROR QueryInterface([in,unique] GUID *iid,
-	   [out,iid_is(riid)] IUnknown **data);
+	[local] WERROR QueryInterface(
+		[in,unique] GUID *iid,
+		[out,iid_is(riid)] IUnknown **data
+		);
 
 	/*****************/
 	/* Function 0x01 */
@@ -47,15 +49,19 @@ interface IUnknown
 	pointer_default(unique)
 ] interface IClassFactory : IUnknown
 {
-	[local] WERROR CreateInstance([in,unique] MInterfacePointer *pUnknown, 
-			       [in,unique] GUID *iid,
-			       [out, iid_is(riid),unique] MInterfacePointer *ppv);
+	[local] WERROR CreateInstance(
+		[in,unique] MInterfacePointer *pUnknown,
+		[in,unique] GUID *iid,
+		[out, iid_is(riid),unique] MInterfacePointer *ppv
+		);
 
 	[call_as(CreateInstance)] WERROR RemoteCreateInstance();
 
 	/* Set lock to TRUE when you want to do a lock
 	and set it to FALSE when you want to unlock */
-	[local] WERROR LockServer([in] uint8 lock);
+	[local] WERROR LockServer(
+		[in] uint8 lock
+		);
 
 	[call_as(LockServer)] WERROR RemoteLockServer();
 }
@@ -75,7 +81,7 @@ interface IUnknown
 ]
 interface IRemUnknown : IUnknown
 {
-	typedef [public] struct 
+	typedef [public] struct
 	{
 		WERROR hResult; /* result of call */
 		STDOBJREF std; /* data for returned interface */
@@ -90,7 +96,7 @@ interface IRemUnknown : IUnknown
 		[out, size_is(cIids), unique] MInterfacePointer *ip
 		);
 
-	typedef struct 
+	typedef struct
 	{
 		GUID ipid; /* ipid to AddRef/Release */
 		uint32 cPublicRefs;
@@ -98,14 +104,14 @@ interface IRemUnknown : IUnknown
 	} REMINTERFACEREF;
 
 	[call_as(AddRef)] WERROR RemAddRef (
-		 [in] uint16 cInterfaceRefs,
-		 [in, size_is(cInterfaceRefs)] REMINTERFACEREF InterfaceRefs[],
-		 [out, size_is(cInterfaceRefs), unique] WERROR *pResults
+		[in] uint16 cInterfaceRefs,
+		[in, size_is(cInterfaceRefs)] REMINTERFACEREF InterfaceRefs[],
+		[out, size_is(cInterfaceRefs), unique] WERROR *pResults
 		);
 
 	[call_as(Release)] WERROR RemRelease (
-		 [in] uint16 cInterfaceRefs,
-		 [in, size_is(cInterfaceRefs)] REMINTERFACEREF InterfaceRefs[]
+		[in] uint16 cInterfaceRefs,
+		[in, size_is(cInterfaceRefs)] REMINTERFACEREF InterfaceRefs[]
 		);
 }
 
@@ -114,11 +120,13 @@ interface IRemUnknown : IUnknown
 	object
 ] interface IClassActivator : IUnknown
 {
-	void GetClassObject([in] GUID clsid, 
-		                [in] uint32 context,
-						[in] uint32 locale,
-						[in] GUID iid,
-						[out, iid_is(iid)] MInterfacePointer *data);
+	void GetClassObject(
+		[in] GUID clsid,
+		[in] uint32 context,
+		[in] uint32 locale,
+		[in] GUID iid,
+		[out, iid_is(iid)] MInterfacePointer *data
+		);
 }
 
 [
@@ -133,7 +141,7 @@ interface IRemUnknown : IUnknown
 [
 	pointer_default(unique),
 	uuid("c6f3ee72-ce7e-11d1-b71e-00c04fc3111a")
-] interface IMachineLocalActivator 
+] interface IMachineLocalActivator
 {
 	WERROR IMachineLocalActivator_foo();
 }
@@ -146,7 +154,7 @@ interface IRemUnknown : IUnknown
 	WERROR ILocalObjectExporter_Foo();
 }
 
-/* Looks like this is the equivalent of .NET's 
+/* Looks like this is the equivalent of .NET's
    System.Activator class */
 [
 	uuid("000001a0-0000-0000-c000-000000000046"),
@@ -154,11 +162,13 @@ interface IRemUnknown : IUnknown
 ]
 	interface ISystemActivator : IClassActivator
 {
-	WERROR ISystemActivatorRemoteCreateInstance([in] hyper unknown1,  /* OXID ? */
-											  [in] MInterfacePointer iface1,
-											  [in] hyper unknown2,
-											  [out] uint32 *unknown3, 
-											  [out] MInterfacePointer *iface2);
+	WERROR ISystemActivatorRemoteCreateInstance(
+		[in] hyper unknown1,  /* OXID ? */
+		[in] MInterfacePointer iface1,
+		[in] hyper unknown2,
+		[out] uint32 *unknown3,
+		[out] MInterfacePointer *iface2
+		);
 }
 
 
@@ -175,11 +185,11 @@ interface IRemUnknown : IUnknown
 interface IRemUnknown2 : IRemUnknown
 {
 	[call_as(QueryInterface2)] WERROR RemQueryInterface2 (
-		 [in, unique] GUID *ripid,
-		 [in] uint16 cIids,
-		 [in, size_is(cIids), unique] GUID *iids,
-		 [out, size_is(cIids), unique] WERROR *phr,
-		 [out, size_is(cIids), unique] MInterfacePointer *ppMIF
+		[in, unique] GUID *ripid,
+		[in] uint16 cIids,
+		[in, size_is(cIids), unique] GUID *iids,
+		[out, size_is(cIids), unique] WERROR *phr,
+		[out, size_is(cIids), unique] MInterfacePointer *ppMIF
 		);
 }
 
@@ -192,7 +202,8 @@ interface IRemUnknown2 : IRemUnknown
 	/*****************/
 	/* Function 0x03 */
 	WERROR GetTypeInfoCount(
-			[out, unique] uint16 *pctinfo);
+		[out, unique] uint16 *pctinfo
+		);
 
 	typedef struct {
 	} REF_ITypeInfo;
@@ -200,18 +211,20 @@ interface IRemUnknown2 : IRemUnknown
 	/*****************/
 	/* Function 0x04 */
 	WERROR GetTypeInfo (
-			[in] uint16 iTInfo,
-			[in] uint32 lcid,
-			[out, unique] REF_ITypeInfo *ppTInfo);
+		[in] uint16 iTInfo,
+		[in] uint32 lcid,
+		[out, unique] REF_ITypeInfo *ppTInfo
+		);
 
 	/*****************/
 	/* Function 0x05 */
 	WERROR GetIDsOfNames(
-			[in, unique] GUID *riid,
-			/*FIXME[in,size_is(cNames)] OLESTR *rgszNames[], */
-			[in] uint16 cNames,
-			[in] uint32 lcid,
-			[out,size_is(cNames), unique] uint32 *rgDispId);
+		[in, unique] GUID *riid,
+		/*FIXME[in,size_is(cNames)] OLESTR *rgszNames[], */
+		[in] uint16 cNames,
+		[in] uint32 lcid,
+		[out,size_is(cNames), unique] uint32 *rgDispId
+		);
 
 	typedef struct {
 		uint16 vartype;
@@ -230,14 +243,15 @@ interface IRemUnknown2 : IRemUnknown
 	/*****************/
 	/* Function 0x06 */
 	WERROR Invoke(
-			[in] uint32 dispIdMember,
-			[in, unique] GUID *riid,
-			[in] uint32 lcid,
-			[in] uint16 wFlags,
-			[out,in, unique] DISPPARAMS *pDispParams,
-			[out, unique] VARIANT *pVarResult,
-			[out, unique] EXCEPINFO *pExcepInfo,
-			[out, unique] uint16 *puArgErr);
+		[in] uint32 dispIdMember,
+		[in, unique] GUID *riid,
+		[in] uint32 lcid,
+		[in] uint16 wFlags,
+		[out,in, unique] DISPPARAMS *pDispParams,
+		[out, unique] VARIANT *pVarResult,
+		[out, unique] EXCEPINFO *pExcepInfo,
+		[out, unique] uint16 *puArgErr
+		);
 }
 
 [
@@ -251,7 +265,7 @@ interface IRemUnknown2 : IRemUnknown
 }
 
 [
-	uuid(DA23F6DB-6F45-466C-9EED-0B65286F2D78),
+	uuid("DA23F6DB-6F45-466C-9EED-0B65286F2D78"),
 	helpstring("ICoffeeMachine Interface"),
 	pointer_default(unique),
 	object
@@ -276,16 +290,17 @@ interface IRemUnknown2 : IRemUnknown
 interface IStream : IUnknown
 {
 	WERROR Read(
-				[out, size_is(num_requested), length_is(*num_read)] uint8 pv[],
-				[in] uint32 num_requested, 
-				[in, unique] uint32 *num_readx,
-				[out] uint32 *num_read
-				);
+		[out, size_is(num_requested), length_is(*num_read)] uint8 pv[],
+		[in] uint32 num_requested,
+		[in, unique] uint32 *num_readx,
+		[out] uint32 *num_read
+		);
 
 	WERROR Write(
-				[in,size_is(num_requested),unique] uint8 *data,
-				 [in] uint32 num_requested,
-				 [out] uint32 *num_written);
+		[in,size_is(num_requested),unique] uint8 *data,
+		[in] uint32 num_requested,
+		[out] uint32 *num_written
+		 );
 }
 
 [
@@ -293,7 +308,7 @@ interface IStream : IUnknown
 	progid("Samba.Simple"),
 	helpstring("simple class"),
 	internal
-] coclass simple 
+] coclass simple
 {
 	interface IStream;
 }
diff --git a/librpc/idl/ioctl.idl b/librpc/idl/ioctl.idl
index 5c3ee6d..dbeef14 100644
--- a/librpc/idl/ioctl.idl
+++ b/librpc/idl/ioctl.idl
@@ -111,6 +111,7 @@ interface compression
 interface netinterface
 {
 	typedef [bitmap32bit] bitmap {
+		FSCTL_NET_IFACE_NONE_CAPABLE = 0x00000000,
 		FSCTL_NET_IFACE_RSS_CAPABLE = 0x00000001,
 		FSCTL_NET_IFACE_RDMA_CAPABLE = 0x00000002
 	} fsctl_net_iface_capability;
diff --git a/librpc/idl/messaging.idl b/librpc/idl/messaging.idl
index ca99f41..6232322 100644
--- a/librpc/idl/messaging.idl
+++ b/librpc/idl/messaging.idl
@@ -126,6 +126,7 @@ interface messaging
 
 		/* smbXsrv messages */
 		MSG_SMBXSRV_SESSION_CLOSE	= 0x0600,
+		MSG_SMBXSRV_CONNECTION_PASS	= 0x0601,
 
 		/* source4 and NTVFS smb server messages */
 		MSG_BRL_RETRY                   = 0x0700,
diff --git a/librpc/idl/negoex.idl b/librpc/idl/negoex.idl
new file mode 100644
index 0000000..e2f8222
--- /dev/null
+++ b/librpc/idl/negoex.idl
@@ -0,0 +1,156 @@
+#include "idl_types.h"
+
+/*
+  NEGOEX interface definition
+  See http://ietfreport.isoc.org/all-ids/draft-zhu-negoex-04.txt
+*/
+
+import "misc.idl";
+
+[
+	uuid("fcc30ddc-98d0-11e5-8a56-83e9a6706f2f"),
+	helper("../librpc/ndr/ndr_negoex.h"),
+	helpstring("NEGOEX messages")
+]
+interface negoex
+{
+	typedef [nopush,nopull,noprint] struct {
+#if 0
+		[relative,size_is(length)] uint8 *data;
+		uint32 length;
+#else
+		DATA_BLOB blob;
+		/*
+		 * internal helper variable */
+		uint32 _length;
+		/*
+		 * the dummy pointer is needed in order to let the
+		 * callers use NDR_BUFFERS
+		 */
+		[relative] uint8 *_dummy;
+#endif
+	} negoex_BYTE_VECTOR;
+
+	typedef [public] struct {
+		GUID guid;
+	} negoex_AUTH_SCHEME;
+
+	typedef [nopush,nopull] struct {
+		[relative,size_is(count)] negoex_AUTH_SCHEME *array;
+		uint32 count;
+	} negoex_AUTH_SCHEME_VECTOR;
+
+	typedef [v1_enum] enum {
+		NEGOEX_EXTENSION_TYPE_TODO = 0 /* TODO */
+	} negoex_ExtensionTypes;
+
+	typedef [public] struct {
+		negoex_ExtensionTypes type;
+		negoex_BYTE_VECTOR value;
+	} negoex_EXTENSION;
+
+	typedef [nopush,nopull] struct {
+		[relative,size_is(count)] negoex_EXTENSION *array;
+		uint32 count;
+	} negoex_EXTENSION_VECTOR;
+
+	typedef [v1_enum] enum {
+		NEGOEX_CHECKSUM_SCHEME_RFC3961 = 1
+	} negoex_ChecksumSchemes;
+
+	typedef struct {
+		[value(20)] uint32 header_length;
+		negoex_ChecksumSchemes scheme;
+		uint32 type;
+		negoex_BYTE_VECTOR value;
+	} negoex_CHECKSUM;
+
+	typedef [v1_enum] enum {
+		NEGOEX_ALERT_VERIFY_NO_KEY = 1
+	} negoex_AlertReason;
+
+	typedef [public] struct {
+		[value(4)] uint32 header_length; /* TODO: is 4 correct? */
+		negoex_AlertReason reason;
+	} negoex_ALERT_PULSE;
+
+	typedef [v1_enum] enum {
+		NEGOEX_ALERT_TYPE_PULSE = 1
+	} negoex_AlertTypes;
+
+	typedef [public] struct {
+		negoex_AlertTypes type;
+		negoex_BYTE_VECTOR value;
+	} negoex_ALERT;
+
+	typedef [nopush,nopull] struct {
+		[relative,size_is(count)] negoex_ALERT *array;
+		uint32 count;
+	} negoex_ALERT_VECTOR;
+
+	typedef [public,v1_enum] enum {
+		NEGOEX_MESSAGE_TYPE_INITIATOR_NEGO = 0,
+		NEGOEX_MESSAGE_TYPE_ACCEPTOR_NEGO = 1,
+		NEGOEX_MESSAGE_TYPE_INITIATOR_META_DATA = 2,
+		NEGOEX_MESSAGE_TYPE_ACCEPTOR_META_DATA = 3,
+		NEGOEX_MESSAGE_TYPE_CHALLENGE = 4,
+		NEGOEX_MESSAGE_TYPE_AP_REQUEST = 5,
+		NEGOEX_MESSAGE_TYPE_VERIFY = 6,
+		NEGOEX_MESSAGE_TYPE_ALERT = 7
+	} negoex_MESSAGE_TYPE;
+
+	const uint32 NEGOEX_PROTOCOL_VERSION_0 = 0;
+
+	typedef [flag(NDR_PAHEX)] struct {
+		[flag(NDR_PAHEX)] uint8 random[32];
+		[value(NEGOEX_PROTOCOL_VERSION_0)] udlong protocol_version;
+		negoex_AUTH_SCHEME_VECTOR auth_schemes;
+		negoex_EXTENSION_VECTOR extensions;
+	} negoex_NEGO_PAYLOAD;
+
+	typedef struct {
+		negoex_AUTH_SCHEME auth_scheme;
+		negoex_BYTE_VECTOR exchange;
+	} negoex_EXCHANGE_PAYLOAD;
+
+	typedef struct {
+		negoex_AUTH_SCHEME auth_scheme;
+		negoex_CHECKSUM checksum;
+	} negoex_VERIFY_PAYLOAD;
+
+	typedef struct {
+		negoex_AUTH_SCHEME auth_scheme;
+		NTSTATUS status;
+		negoex_ALERT_VECTOR alerts;
+	} negoex_ALERT_PAYLOAD;
+
+	typedef [public,nodiscriminant] union {
+	[case(NEGOEX_MESSAGE_TYPE_INITIATOR_NEGO)] negoex_NEGO_PAYLOAD nego;
+	[case(NEGOEX_MESSAGE_TYPE_ACCEPTOR_NEGO)] negoex_NEGO_PAYLOAD nego;
+	[case(NEGOEX_MESSAGE_TYPE_INITIATOR_META_DATA)] negoex_EXCHANGE_PAYLOAD exchange;
+	[case(NEGOEX_MESSAGE_TYPE_ACCEPTOR_META_DATA)] negoex_EXCHANGE_PAYLOAD exchange;
+	[case(NEGOEX_MESSAGE_TYPE_CHALLENGE)] negoex_EXCHANGE_PAYLOAD exchange;
+	[case(NEGOEX_MESSAGE_TYPE_AP_REQUEST)] negoex_EXCHANGE_PAYLOAD exchange;
+	[case(NEGOEX_MESSAGE_TYPE_VERIFY)] negoex_VERIFY_PAYLOAD verify;
+	[case(NEGOEX_MESSAGE_TYPE_ALERT)] negoex_ALERT_PAYLOAD alert;
+	} negoex_PAYLOAD;
+
+	typedef [public,relative_base,gensize,nopull] struct {
+		[charset(DOS),value("NEGOEXTS")] uint8 signature[8];
+		negoex_MESSAGE_TYPE type;
+		uint32 sequence_number;
+		[value(ndr_negoex_MESSAGE_header_length(r))] uint32 header_length;
+		[value(ndr_size_negoex_MESSAGE(r, ndr->flags))] uint32 message_length;
+		GUID conversation_id;
+		[switch_is(type)] negoex_PAYLOAD p;
+	} negoex_MESSAGE;
+
+	typedef [public,nopush,nopull,flag(NDR_NOALIGN)] struct {
+		uint32 count;
+		negoex_MESSAGE messages[count];
+	} negoex_MESSAGE_ARRAY;
+
+	void decode_negoex_MESSAGE(
+		[in] negoex_MESSAGE_ARRAY array
+		);
+}
diff --git a/librpc/idl/orpc.idl b/librpc/idl/orpc.idl
index d023865..34a35e2 100644
--- a/librpc/idl/orpc.idl
+++ b/librpc/idl/orpc.idl
@@ -41,7 +41,7 @@ interface ObjectRpcBaseTypes
 	/* Component Object Model version number */
 
 
-	typedef [public] struct 
+	typedef [public] struct
 	{
 		uint16 MajorVersion; /* Major version number */
 		uint16 MinorVersion; /* Minor version number */
@@ -58,8 +58,8 @@ interface ObjectRpcBaseTypes
 	} ORPC_FLAGS;
 
 	/* Extension to implicit parameters. */
-	typedef [public] struct 
-	{ 	
+	typedef [public] struct
+	{
 		GUID id; /* Extension identifier. */
 		uint32 size; /* Extension size. */
 		[size_is(((size+7)&~7))] uint8 data[]; /* Extension data. */
@@ -67,7 +67,7 @@ interface ObjectRpcBaseTypes
 
 
 	/* Array of extensions. */
-	typedef struct 
+	typedef struct
 	{
 		uint32 size; /* Num extents. */
 		uint32 reserved; /* Must be zero. */
@@ -77,7 +77,7 @@ interface ObjectRpcBaseTypes
 
 	/* implicit 'this' pointer which is the first [in] parameter on */
 	/* every ORPC call. */
-	typedef [public] struct 
+	typedef [public] struct
 	{
 		COMVERSION version; /* COM version number */
 		uint32 flags; /* ORPCF flags for presence of other data */
@@ -90,7 +90,7 @@ interface ObjectRpcBaseTypes
 
 	/* implicit 'that' pointer which is the first [out] parameter on */
 	/* every ORPC call. */
-	typedef [public] struct 
+	typedef [public] struct
 	{
 		uint32 flags; /* ORPCF flags for presence of other data */
 		/* Extensions. */
@@ -100,33 +100,33 @@ interface ObjectRpcBaseTypes
 
 	/* DUALSTRINGARRAYS are the return type for arrays of network addresses, */
 	/* arrays of endpoints and arrays of both used in many ORPC interfaces */
-	typedef [public,flag(NDR_NOALIGN)] struct 
+	typedef [public,flag(NDR_NOALIGN)] struct
 	{
 		uint16 wTowerId; /* Cannot be zero. */
-		nstring NetworkAddr; 
+		nstring NetworkAddr;
 	} 	STRINGBINDING;
 
-	typedef [public,nopush,nopull,noprint] struct 
+	typedef [public,nopush,nopull,noprint] struct
 	{
 		STRINGBINDING **stringbindings;
 	} STRINGARRAY;
 
-	typedef [public,nopush,nopull,noprint] struct 
+	typedef [public,nopush,nopull,noprint] struct
 	{
 		STRINGBINDING **stringbindings;
 		SECURITYBINDING **securitybindings;
 	} DUALSTRINGARRAY;
 
 	const uint16 COM_C_AUTHZ_NONE = 0xffff;
-	typedef [public,flag(NDR_NOALIGN)] struct 
+	typedef [public,flag(NDR_NOALIGN)] struct
 	{
 		uint16 wAuthnSvc; /* Cannot be zero. */
 		uint16 wAuthzSvc;
-		nstring PrincName; 
+		nstring PrincName;
 	} 	SECURITYBINDING;
 
 	/* signature value for OBJREF (object reference, actually the */
-	/* marshaled form of a COM interface). 
+	/* marshaled form of a COM interface).
 	 * MEOW apparently stands for "Microsoft Extended Object Wireformat"
 	 */
 	const uint32 OBJREF_SIGNATURE = 0x574f454d; /* 'MEOW' */
@@ -156,7 +156,7 @@ interface ObjectRpcBaseTypes
 	} STDOBJREF_FLAGS;
 
 	/* standard object reference */
-	typedef [public] struct 
+	typedef [public] struct
 	{
 		uint32 flags; /* STDOBJREF flags (see above) */
 		uint32 cPublicRefs; /* count of references passed */
@@ -190,7 +190,7 @@ interface ObjectRpcBaseTypes
 	{
 	} u_null;
 
-	typedef [nodiscriminant] union 
+	typedef [nodiscriminant] union
 	{
 		[case(OBJREF_NULL)] u_null u_null;
 		[case(OBJREF_STANDARD)] u_standard u_standard;
@@ -199,7 +199,7 @@ interface ObjectRpcBaseTypes
 	} OBJREF_Types;
 
 	/* OBJREF is the format of a marshaled interface pointer. */
-	typedef [public,flag(NDR_LITTLE_ENDIAN)] struct 
+	typedef [public,flag(NDR_LITTLE_ENDIAN)] struct
 	{
 		uint32 signature;
 		uint32 flags; /* OBJREF flags (see above) */
@@ -208,13 +208,13 @@ interface ObjectRpcBaseTypes
 	} OBJREF;
 
 	/* wire representation of a marshalled interface pointer */
-	typedef [public] struct 
+	typedef [public] struct
 	{
 		uint32 size;
 		[subcontext(4)] OBJREF obj;
 	} MInterfacePointer;
 
-	typedef [v1_enum,public] enum 
+	typedef [v1_enum,public] enum
 	{
 		COM_OK 				= 0x00000000,
 		COM_OUTOFMEMORY 	= 0x80000002,
diff --git a/librpc/idl/oxidresolver.idl b/librpc/idl/oxidresolver.idl
index 67cb430..07700d5 100644
--- a/librpc/idl/oxidresolver.idl
+++ b/librpc/idl/oxidresolver.idl
@@ -3,8 +3,8 @@
   http://www.grimes.demon.co.uk/DCOM/DCOMSpec.htm
  */
 
-/* 
- The OXID Resolver can turn a OXID (Object Exporter ID) into a 
+/*
+ The OXID Resolver can turn a OXID (Object Exporter ID) into a
  RPC binding string that can be used to contact an object
 
  (used by DCOM)
@@ -12,7 +12,7 @@
 
 import "misc.idl", "orpc.idl";
 
-[ 
+[
 	uuid("99fcfec4-5260-101b-bbcb-00aa0021347a"),
 	helpstring("Object Exporter ID Resolver"),
 	endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]", "ncalrpc:"),
@@ -29,13 +29,13 @@ interface IOXIDResolver
 	/* and machine id for an object server given its OXID. */
 
 	[idempotent] WERROR ResolveOxid (
-		 [in] OXID pOxid,
-		 [in] uint16 cRequestedProtseqs,
-		 [in, size_is(cRequestedProtseqs)] uint16 arRequestedProtseqs[],
-		 [out] DUALSTRINGARRAY **ppdsaOxidBindings,
-		 [out,ref] IPID *pipidRemUnknown,
-		 [out,ref] uint32 *pAuthnHint
-			 );
+		[in] OXID pOxid,
+		[in] uint16 cRequestedProtseqs,
+		[in, size_is(cRequestedProtseqs)] uint16 arRequestedProtseqs[],
+		[out] DUALSTRINGARRAY **ppdsaOxidBindings,
+		[out,ref] IPID *pipidRemUnknown,
+		[out,ref] uint32 *pAuthnHint
+		);
 
 	/* Simple ping is used to ping a Set. Client machines use this */
 	/* to inform the object exporter that it is still using the */
@@ -45,7 +45,7 @@ interface IOXIDResolver
 	[idempotent] WERROR SimplePing (
 		[in] SETID *SetId /* Must not be zero */
 		);
-	
+
 	/* Complex ping is used to create sets of OIDs to ping. The */
 	/* whole set can subsequently be pinged using SimplePing, */
 	/* thus reducing network traffic. */
@@ -59,7 +59,7 @@ interface IOXIDResolver
 		/*remove these OIDs from the set */
 		[in, size_is(cDelFromSet)] OID DelFromSet[],
 		[out,ref] uint16 *PingBackoffFactor/* 2^factor = multipler */
-			 );
+		 );
 
 	/* In some cases the client maybe unsure that a particular */
 	/* binding will reach the server. (For example, when the oxid */
@@ -71,26 +71,26 @@ interface IOXIDResolver
 	/* Method to get the protocol sequences, string bindings, */
 	/* RemoteUnknown IPID and COM version for an object server */
 	/* given its OXID. Supported by DCOM */
-	/* version 5.2 and above. Looks like that means 
+	/* version 5.2 and above. Looks like that means
 	 * Windows 2003/XP and above */
 	[idempotent] WERROR ResolveOxid2 (
-											  [in] OXID pOxid,
-											  [in] uint16 cRequestedProtseqs,
-											  [in, size_is(cRequestedProtseqs)] uint16 arRequestedProtseqs[],
-											  [out] DUALSTRINGARRAY **pdsaOxidBindings,
-											  [out,ref] IPID *ipidRemUnknown,
-											  [out,ref] uint32 *AuthnHint,
-											  [out,ref] COMVERSION *ComVersion
-											 );
+		[in] OXID pOxid,
+		[in] uint16 cRequestedProtseqs,
+		[in, size_is(cRequestedProtseqs)] uint16 arRequestedProtseqs[],
+		[out] DUALSTRINGARRAY **pdsaOxidBindings,
+		[out,ref] IPID *ipidRemUnknown,
+		[out,ref] uint32 *AuthnHint,
+		[out,ref] COMVERSION *ComVersion
+		);
+
 	typedef struct {
 		COMVERSION version;
 	  	uint32 unknown1;
 	} COMINFO;
 
 	[idempotent] WERROR ServerAlive2 (
-	  [out,ref] COMINFO *info,
-	  [out,ref] DUALSTRINGARRAY *dualstring,
-	  [out,ref] uint8 *unknown2,
-	  [out,ref] uint8 *unknown3,
-	  [out,ref] uint8 *unknown4);
+		[out,ref] COMINFO *info,
+		[out,ref] DUALSTRINGARRAY **dualstring,
+		[out,ref] uint8 *pReserved
+		);
 }
diff --git a/librpc/idl/remact.idl b/librpc/idl/remact.idl
index 14fd6ce..77134e7 100644
--- a/librpc/idl/remact.idl
+++ b/librpc/idl/remact.idl
@@ -12,8 +12,7 @@ import "misc.idl", "orpc.idl";
 ]
 interface IRemoteActivation
 {
-	typedef enum 
-	{
+	typedef [v1_enum] enum {
 		RPC_C_IMP_LEVEL_DEFAULT = 0,
 		RPC_C_IMP_LEVEL_ANONYMOUS = 1,
 		RPC_C_IMP_LEVEL_IDENTIFY = 2,
@@ -22,25 +21,26 @@ interface IRemoteActivation
 	} imp_levels;
 
 	const uint32 MODE_GET_CLASS_OBJECT = 0xffffffff;
+
 	WERROR RemoteActivation (
-			[in] ORPCTHIS this_object,
-			[out,ref] ORPCTHAT *that,
-			[in] GUID Clsid,
-			[in] [string,charset(UTF16)] uint16 *pwszObjectName,
-			[in] MInterfacePointer *pObjectStorage,
-			[in] uint32 ClientImpLevel,
-			[in] uint32 Mode,
-			[in,range(1,32768)] uint32 Interfaces,
-			[in,size_is(Interfaces)] GUID *pIIDs,
-			[in] uint16 num_protseqs,
-			[in, size_is(num_protseqs)] uint16 protseq[*],
-			[out,ref] hyper *pOxid,
-			[out,ref] DUALSTRINGARRAY *pdsaOxidBindings,
-			[out,ref] GUID *ipidRemUnknown,
-			[out,ref] uint32 *AuthnHint,
-			[out,ref] COMVERSION *ServerVersion,
-			[out,ref] WERROR *hr,
-			[out,size_is(Interfaces)] MInterfacePointer *ifaces[],
-			[out,size_is(Interfaces)] WERROR results[]
-			);
+		[in] ORPCTHIS this_object,
+		[out,ref] ORPCTHAT *that,
+		[in] GUID Clsid,
+		[in] [unique,string,charset(UTF16)] uint16 *pwszObjectName,
+		[in] [unique] MInterfacePointer *pObjectStorage,
+		[in] imp_levels ClientImpLevel,
+		[in] uint32 Mode,
+		[in,range(1,32768)] uint32 Interfaces,
+		[in,unique,size_is(Interfaces)] GUID *pIIDs,
+		[in] uint16 num_protseqs,
+		[in, size_is(num_protseqs)] uint16 protseq[*],
+		[out,ref] hyper *pOxid,
+		[out,ref] DUALSTRINGARRAY **pdsaOxidBindings,
+		[out,ref] GUID *ipidRemUnknown,
+		[out,ref] uint32 *AuthnHint,
+		[out,ref] COMVERSION *ServerVersion,
+		[out,ref] HRESULT *hr,
+		[out,size_is(Interfaces)] MInterfacePointer **ifaces,
+		[out,size_is(Interfaces)] HRESULT results[]
+		);
 }
diff --git a/librpc/idl/rot.idl b/librpc/idl/rot.idl
index 78eee48..7239111 100644
--- a/librpc/idl/rot.idl
+++ b/librpc/idl/rot.idl
@@ -3,42 +3,42 @@ import "orpc.idl";
 [
 	uuid("b9e79e60-3d52-11ce-aaa1-00006901293f"),
 	version(0.2),
-    	pointer_default(unique),
- 	endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]", 
-		  "ncalrpc:[EPMAPPER]")
+	pointer_default(unique),
+	endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]",
+		 "ncalrpc:[EPMAPPER]")
 ] interface rot
 {
 	WERROR rot_add (
-					[in] uint32 flags, 
-					[in] MInterfacePointer *unk, 
-					[in] MInterfacePointer *moniker, 
-					[out] uint32 *rotid
-					);
-	
+		[in] uint32 flags,
+		[in] MInterfacePointer *unk,
+		[in] MInterfacePointer *moniker,
+		[out] uint32 *rotid
+		);
+
 	WERROR rot_remove (
-				  [in] uint32 rotid
-				  );
-	
+		[in] uint32 rotid
+		);
+
 	WERROR rot_is_listed (
-					 [in] MInterfacePointer *moniker
-					 );
-	
+		[in] MInterfacePointer *moniker
+		);
+
 	WERROR rot_get_interface_pointer (
-					 [in] MInterfacePointer *moniker, 
-					 [out] MInterfacePointer *ip
-					 );
-	
+		[in] MInterfacePointer *moniker,
+		[out] MInterfacePointer *ip
+		);
+
 	WERROR rot_set_modification_time (
-						  [in] uint32 rotid, 
-						  [in] NTTIME *t
-						  );
-	
+		[in] uint32 rotid,
+		[in] NTTIME *t
+		);
+
 	WERROR rot_get_modification_time (
-							   [in] MInterfacePointer *moniker,
-							   [out] NTTIME *t
-							   );
-	
+		[in] MInterfacePointer *moniker,
+		[out] NTTIME *t
+		);
+
 	WERROR rot_enum (
-					   [out] MInterfacePointer *EnumMoniker
-					   );
+		[out] MInterfacePointer *EnumMoniker
+		);
 }
diff --git a/librpc/idl/security.idl b/librpc/idl/security.idl
index b78307e..f412ffe 100644
--- a/librpc/idl/security.idl
+++ b/librpc/idl/security.idl
@@ -285,6 +285,9 @@ interface security
 	const string SID_NT_TRUSTED_INSTALLER =
 		"S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464";
 
+	const string SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY = "S-1-18-1";
+	const string SID_SERVICE_ASSERTED_IDENTITY = "S-1-18-2";
+
 	/* well-known domain RIDs */
 	const int DOMAIN_RID_LOGON                   = 9;
 	const int DOMAIN_RID_ENTERPRISE_READONLY_DCS = 498;
diff --git a/librpc/idl/witness.idl b/librpc/idl/witness.idl
index febae25..1557bad 100644
--- a/librpc/idl/witness.idl
+++ b/librpc/idl/witness.idl
@@ -100,12 +100,12 @@ interface witness
 
 	typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN),gensize] struct {
 		witness_IPaddrInfo_flags flags;
-		ipv4address ipv4;
-		ipv6address ipv6;
+		[flag(NDR_BIG_ENDIAN)] ipv4address ipv4;
+		[flag(NDR_BIG_ENDIAN)] ipv6address ipv6;
 	} witness_IPaddrInfo;
 
 	typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN)] struct {
-		[value(r->num*ndr_size_witness_IPaddrInfo(r->addr, ndr->flags))] uint32 length;
+		[value(12+(r->num*ndr_size_witness_IPaddrInfo(r->addr, ndr->flags)))] uint32 length;
 		[value(0)] uint32 reserved;
 		uint32 num;
 		witness_IPaddrInfo addr[num];
diff --git a/librpc/idl/wmi.idl b/librpc/idl/wmi.idl
index 4d428a8..43b7408 100644
--- a/librpc/idl/wmi.idl
+++ b/librpc/idl/wmi.idl
@@ -35,7 +35,7 @@ interface IWbemClassObject : IUnknown
 };
 
 [
-    uuid(9A653086-174F-11d2-B5F9-00104B703EFD)
+    uuid("9A653086-174F-11d2-B5F9-00104B703EFD")
 ]
 coclass WbemClassObject
 {
@@ -486,7 +486,7 @@ coclass WbemClassObject
 
 [
 	object, 
-	uuid(027947e1-d731-11ce-a357-000000000001),
+	uuid("027947e1-d731-11ce-a357-000000000001"),
 	pointer_default(unique)
 ] interface IEnumWbemClassObject : IUnknown
 {
@@ -669,7 +669,7 @@ coclass WbemClassObject
 [
 	object,
 	/*	restricted, */
-	uuid(44aca675-e8fc-11d0-a07c-00c04fb68820)
+	uuid("44aca675-e8fc-11d0-a07c-00c04fb68820")
 ] interface IWbemCallResult : IUnknown
 {
 	WERROR GetResultObject(
@@ -697,7 +697,7 @@ coclass WbemClassObject
 [
 	object,
 	restricted,
-	uuid(7c857801-7381-11cf-884d-00aa004b2e24)
+	uuid("7c857801-7381-11cf-884d-00aa004b2e24")
 ]
 interface IWbemObjectSink : IUnknown
 {
diff --git a/librpc/idl/wscript_build b/librpc/idl/wscript_build
index 6316edd..47acc0d 100644
--- a/librpc/idl/wscript_build
+++ b/librpc/idl/wscript_build
@@ -2,7 +2,7 @@
 
 bld.SAMBA_PIDL_LIST('PIDL',
                     '''atsvc.idl auth.idl drsuapi.idl epmapper.idl initshutdown.idl
-                       misc.idl ntlmssp.idl schannel.idl trkwks.idl
+                       misc.idl ntlmssp.idl negoex.idl schannel.idl trkwks.idl
                        audiosrv.idl dfsblobs.idl dsbackup.idl eventlog.idl file_id.idl keysvc.idl
                        msgsvc.idl ntsvcs.idl remact.idl security.idl smb_acl.idl unixinfo.idl wzcsvc.idl
                        browser.idl dfs.idl dssetup.idl frsapi.idl krb5pac.idl
diff --git a/librpc/idl/xattr.idl b/librpc/idl/xattr.idl
index b4c1b98..efbc84e 100644
--- a/librpc/idl/xattr.idl
+++ b/librpc/idl/xattr.idl
@@ -20,6 +20,7 @@ import "security.idl";
 interface xattr
 {
 	const char *XATTR_DOSATTRIB_NAME = "user.DosAttrib";
+	const char *XATTR_DOSATTRIB_NAME_S3 = "user.DOSATTRIB";
 	const int XATTR_DOSATTRIB_ESTIMATED_SIZE = 64;
 
 	/* we store basic dos attributes in a DosAttrib xattr. By
diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h
index 5c1487b..c6116ed 100644
--- a/librpc/ndr/libndr.h
+++ b/librpc/ndr/libndr.h
@@ -26,8 +26,10 @@
 #define __LIBNDR_H__
 
 #include <talloc.h>
-#include <sys/time.h>
-#include "../lib/util/samba_util.h" /* for discard_const */
+#include "../lib/util/memory.h" /* for discard_const */
+#include "../lib/util/byteorder.h"
+#include "../lib/util/data_blob.h"
+#include "../lib/util/time.h"
 #include "../lib/util/charset/charset.h"
 
 /*
diff --git a/librpc/ndr/ndr_basic.c b/librpc/ndr/ndr_basic.c
index 12e3942..b532cc5 100644
--- a/librpc/ndr/ndr_basic.c
+++ b/librpc/ndr/ndr_basic.c
@@ -19,10 +19,12 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/network.h"
 #include "librpc/ndr/libndr.h"
 #include "lib/util/util_net.h"
+#include "lib/util/debug.h"
+#include "lib/util/util.h"
 
 #define NDR_SVAL(ndr, ofs) (NDR_BE(ndr)?RSVAL(ndr->data,ofs):SVAL(ndr->data,ofs))
 #define NDR_IVAL(ndr, ofs) (NDR_BE(ndr)?RIVAL(ndr->data,ofs):IVAL(ndr->data,ofs))
diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c
index 065d992..ab0c83a 100644
--- a/librpc/ndr/ndr_dns.c
+++ b/librpc/ndr/ndr_dns.c
@@ -169,7 +169,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
 		size_t complen;
 		uint32_t offset;
 
-		/* see if we have pushed the remaing string allready,
+		/* see if we have pushed the remaining string already,
 		 * if so we use a label pointer to this string
 		 */
 		ndr_err = ndr_token_retrieve_cmp_fn(&ndr->dns_string_list, s,
diff --git a/librpc/ndr/ndr_nbt.c b/librpc/ndr/ndr_nbt.c
index ada1335..838f947 100644
--- a/librpc/ndr/ndr_nbt.c
+++ b/librpc/ndr/ndr_nbt.c
@@ -151,7 +151,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, int ndr_fla
 		size_t complen;
 		uint32_t offset;
 
-		/* see if we have pushed the remaing string allready,
+		/* see if we have pushed the remaining string already,
 		 * if so we use a label pointer to this string
 		 */
 		ndr_err = ndr_token_retrieve_cmp_fn(&ndr->nbt_string_list, s, &offset, (comparison_fn_t)strcmp, false);
diff --git a/librpc/ndr/ndr_negoex.c b/librpc/ndr/ndr_negoex.c
new file mode 100644
index 0000000..b5cb5bc
--- /dev/null
+++ b/librpc/ndr/ndr_negoex.c
@@ -0,0 +1,520 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   routines for marshalling/unmarshalling special NEGOEX structures
+
+   Copyright (C) Stefan Metzmacher 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_negoex.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/ndr/ndr_negoex.h"
+
+void ndr_print_negoex_BYTE_VECTOR(struct ndr_print *ndr, const char *name, const struct negoex_BYTE_VECTOR *r)
+{
+	ndr_print_struct(ndr, name, "negoex_BYTE_VECTOR");
+	if (r == NULL) { ndr_print_null(ndr); return; }
+	ndr->depth++;
+	ndr_print_DATA_BLOB(ndr, "blob", r->blob);
+	ndr->depth--;
+}
+
+enum ndr_err_code ndr_push_negoex_BYTE_VECTOR(struct ndr_push *ndr, int ndr_flags, const struct negoex_BYTE_VECTOR *r)
+{
+	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_push_align(ndr, 5));
+		NDR_CHECK(ndr_push_relative_ptr1(ndr, r->blob.data));
+		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->blob.length));
+		NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		if (r->blob.data) {
+			NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->blob.data));
+#if 0
+			NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->blob.length));
+#endif
+			NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->blob.data, r->blob.length));
+			NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->blob.data));
+		}
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_BYTE_VECTOR(struct ndr_pull *ndr, int ndr_flags, struct negoex_BYTE_VECTOR *r)
+{
+	uint32_t _ptr_data;
+	uint32_t size_data_1 = 0;
+	TALLOC_CTX *_mem_save_data_0 = NULL;
+	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+	r->_dummy = NULL;
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_pull_align(ndr, 5));
+		NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+		if (_ptr_data) {
+			NDR_PULL_ALLOC(ndr, r->blob.data);
+			NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->blob.data, _ptr_data));
+		} else {
+			r->blob.data = NULL;
+		}
+		r->blob.length = 0;
+		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size_data_1));
+		r->_length = size_data_1;
+		NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		if (r->blob.data) {
+			uint32_t _relative_save_offset;
+			_relative_save_offset = ndr->offset;
+			NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->blob.data));
+			_mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+			NDR_PULL_SET_MEM_CTX(ndr, r->blob.data, 0);
+#if 0
+			NDR_CHECK(ndr_pull_array_size(ndr, &r->blob.data));
+			size_data_1 = ndr_get_array_size(ndr, &r->blob.data);
+#else
+			size_data_1 = r->_length;
+#endif
+			NDR_PULL_ALLOC_N(ndr, r->blob.data, size_data_1);
+			NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->blob.data, size_data_1));
+			r->blob.length = size_data_1;
+			NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+			if (ndr->offset > ndr->relative_highest_offset) {
+				ndr->relative_highest_offset = ndr->offset;
+			}
+			ndr->offset = _relative_save_offset;
+		}
+#if 0
+		if (r->blob.data) {
+			NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->blob.data, r->blob.length));
+		}
+#endif
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_negoex_AUTH_SCHEME_VECTOR(struct ndr_push *ndr, int ndr_flags, const struct negoex_AUTH_SCHEME_VECTOR *r)
+{
+	uint32_t cntr_array_1;
+	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_push_align(ndr, 5));
+		NDR_CHECK(ndr_push_relative_ptr1(ndr, r->array));
+		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+		NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		if (r->array) {
+			NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->array));
+#if 0
+			NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->count));
+#endif
+			for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+				NDR_CHECK(ndr_push_negoex_AUTH_SCHEME(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+			}
+			NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->array));
+		}
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_AUTH_SCHEME_VECTOR(struct ndr_pull *ndr, int ndr_flags, struct negoex_AUTH_SCHEME_VECTOR *r)
+{
+	uint32_t _ptr_array;
+	uint32_t size_array_1 = 0;
+	uint32_t cntr_array_1;
+	TALLOC_CTX *_mem_save_array_0 = NULL;
+	TALLOC_CTX *_mem_save_array_1 = NULL;
+	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_pull_align(ndr, 5));
+		NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+		if (_ptr_array) {
+			NDR_PULL_ALLOC(ndr, r->array);
+			NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->array, _ptr_array));
+		} else {
+			r->array = NULL;
+		}
+		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+		NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		if (r->array) {
+			uint32_t _relative_save_offset;
+			_relative_save_offset = ndr->offset;
+			NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->array));
+			_mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+			NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+#if 0
+			NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+			size_array_1 = ndr_get_array_size(ndr, &r->array);
+#else
+			size_array_1 = r->count;
+#endif
+			NDR_PULL_ALLOC_N(ndr, r->array, size_array_1);
+			_mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+			NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+			for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+				NDR_CHECK(ndr_pull_negoex_AUTH_SCHEME(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+			}
+			NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+			NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+			if (ndr->offset > ndr->relative_highest_offset) {
+				ndr->relative_highest_offset = ndr->offset;
+			}
+			ndr->offset = _relative_save_offset;
+		}
+#if 0
+		if (r->array) {
+			NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+		}
+#endif
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_negoex_EXTENSION_VECTOR(struct ndr_push *ndr, int ndr_flags, const struct negoex_EXTENSION_VECTOR *r)
+{
+	uint32_t cntr_array_1;
+	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_push_align(ndr, 5));
+		NDR_CHECK(ndr_push_relative_ptr1(ndr, r->array));
+		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+		NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		if (r->array) {
+			NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->array));
+#if 0
+			NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->count));
+#endif
+			for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+				NDR_CHECK(ndr_push_negoex_EXTENSION(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+			}
+			for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+				NDR_CHECK(ndr_push_negoex_EXTENSION(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+			}
+			NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->array));
+		}
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_EXTENSION_VECTOR(struct ndr_pull *ndr, int ndr_flags, struct negoex_EXTENSION_VECTOR *r)
+{
+	uint32_t _ptr_array;
+	uint32_t size_array_1 = 0;
+	uint32_t cntr_array_1;
+	TALLOC_CTX *_mem_save_array_0 = NULL;
+	TALLOC_CTX *_mem_save_array_1 = NULL;
+	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_pull_align(ndr, 5));
+		NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+		if (_ptr_array) {
+			NDR_PULL_ALLOC(ndr, r->array);
+			NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->array, _ptr_array));
+		} else {
+			r->array = NULL;
+		}
+		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+		NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		if (r->array) {
+			uint32_t _relative_save_offset;
+			_relative_save_offset = ndr->offset;
+			NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->array));
+			_mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+			NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+#if 0
+			NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+			size_array_1 = ndr_get_array_size(ndr, &r->array);
+#else
+			size_array_1 = r->count;
+#endif
+			NDR_PULL_ALLOC_N(ndr, r->array, size_array_1);
+			_mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+			NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+			for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+				NDR_CHECK(ndr_pull_negoex_EXTENSION(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+			}
+			for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+				NDR_CHECK(ndr_pull_negoex_EXTENSION(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+			}
+			NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+			NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+			if (ndr->offset > ndr->relative_highest_offset) {
+				ndr->relative_highest_offset = ndr->offset;
+			}
+			ndr->offset = _relative_save_offset;
+		}
+#if 0
+		if (r->array) {
+			NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+		}
+#endif
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_negoex_ALERT_VECTOR(struct ndr_push *ndr, int ndr_flags, const struct negoex_ALERT_VECTOR *r)
+{
+	uint32_t cntr_array_1;
+	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_push_align(ndr, 5));
+		NDR_CHECK(ndr_push_relative_ptr1(ndr, r->array));
+		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+		NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		if (r->array) {
+			NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->array));
+#if 0
+			NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->count));
+#endif
+			for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+				NDR_CHECK(ndr_push_negoex_ALERT(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+			}
+			for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+				NDR_CHECK(ndr_push_negoex_ALERT(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+			}
+			NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->array));
+		}
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_ALERT_VECTOR(struct ndr_pull *ndr, int ndr_flags, struct negoex_ALERT_VECTOR *r)
+{
+	uint32_t _ptr_array;
+	uint32_t size_array_1 = 0;
+	uint32_t cntr_array_1;
+	TALLOC_CTX *_mem_save_array_0 = NULL;
+	TALLOC_CTX *_mem_save_array_1 = NULL;
+	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_pull_align(ndr, 5));
+		NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+		if (_ptr_array) {
+			NDR_PULL_ALLOC(ndr, r->array);
+			NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->array, _ptr_array));
+		} else {
+			r->array = NULL;
+		}
+		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+		NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		if (r->array) {
+			uint32_t _relative_save_offset;
+			_relative_save_offset = ndr->offset;
+			NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->array));
+			_mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+			NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+#if 0
+			NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+			size_array_1 = ndr_get_array_size(ndr, &r->array);
+#else
+			size_array_1 = r->count;
+#endif
+			NDR_PULL_ALLOC_N(ndr, r->array, size_array_1);
+			_mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+			NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+			for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+				NDR_CHECK(ndr_pull_negoex_ALERT(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+			}
+			for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+				NDR_CHECK(ndr_pull_negoex_ALERT(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+			}
+			NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+			NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+			if (ndr->offset > ndr->relative_highest_offset) {
+				ndr->relative_highest_offset = ndr->offset;
+			}
+			ndr->offset = _relative_save_offset;
+		}
+#if 0
+		if (r->array) {
+			NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+		}
+#endif
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+size_t ndr_negoex_MESSAGE_header_length(const struct negoex_MESSAGE *r)
+{
+	size_t size = 0;
+
+	size += 8;  /* signature */
+	size += 4;  /* type */
+	size += 4;  /* sequence_number */
+	size += 4;  /* header_length */
+	size += 4;  /* message_length */
+	size += 16; /* conversation_id */
+
+	switch (r->type) {
+	case NEGOEX_MESSAGE_TYPE_INITIATOR_NEGO:
+	case NEGOEX_MESSAGE_TYPE_ACCEPTOR_NEGO:
+		size += 32; /* random */
+		size += 8;  /* protocol_version */
+		size += 8;  /* auth_schemes */
+		size += 8;  /* extensions */
+		break;
+
+	case NEGOEX_MESSAGE_TYPE_INITIATOR_META_DATA:
+	case NEGOEX_MESSAGE_TYPE_ACCEPTOR_META_DATA:
+	case NEGOEX_MESSAGE_TYPE_CHALLENGE:
+	case NEGOEX_MESSAGE_TYPE_AP_REQUEST:
+		size += 16; /* auth_scheme */
+		size += 8;  /* exchange */
+		break;
+
+	case NEGOEX_MESSAGE_TYPE_VERIFY:
+		size += 16; /* auth_scheme */
+		size += 4;  /* checksum.header_length */
+		size += 4;  /* checksum.scheme */
+		size += 4;  /* checksum.type */
+		size += 8;  /* checksum.value */
+		break;
+
+	case NEGOEX_MESSAGE_TYPE_ALERT:
+		size += 16; /* auth_scheme */
+		size += 4;  /* status */
+		size += 8;  /* alerts */
+		break;
+	}
+
+	return size;
+}
+
+enum ndr_err_code ndr_pull_negoex_MESSAGE(struct ndr_pull *ndr, int ndr_flags, struct negoex_MESSAGE *r)
+{
+	uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);
+	uint32_t size_signature_0 = 0;
+	uint32_t start_data_size = ndr->data_size;
+	uint32_t saved_offset = 0;
+	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_pull_align(ndr, 5));
+		NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset));
+		size_signature_0 = 8;
+		NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->signature, size_signature_0, sizeof(uint8_t), CH_DOS));
+		NDR_CHECK(ndr_pull_negoex_MESSAGE_TYPE(ndr, NDR_SCALARS, &r->type));
+		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sequence_number));
+		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->header_length));
+		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->message_length));
+		saved_offset = ndr->offset;
+		ndr->offset = ndr->relative_base_offset;
+		NDR_PULL_NEED_BYTES(ndr, r->message_length);
+		ndr->data_size = ndr->offset + r->message_length;
+		ndr->offset = saved_offset;
+		NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->conversation_id));
+		NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->p, r->type));
+		NDR_CHECK(ndr_pull_negoex_PAYLOAD(ndr, NDR_SCALARS, &r->p));
+		NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+		ndr->offset = ndr->data_size;
+		ndr->data_size = start_data_size;
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+		NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r));
+		saved_offset = ndr->offset;
+		ndr->offset = ndr->relative_base_offset;
+		NDR_PULL_NEED_BYTES(ndr, r->message_length);
+		ndr->data_size = ndr->offset + r->message_length;
+		ndr->offset = saved_offset;
+		NDR_CHECK(ndr_pull_negoex_PAYLOAD(ndr, NDR_BUFFERS, &r->p));
+		ndr->offset = ndr->data_size;
+		ndr->data_size = start_data_size;
+	}
+	ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_negoex_MESSAGE_ARRAY(struct ndr_push *ndr, int ndr_flags, const struct negoex_MESSAGE_ARRAY *r)
+{
+	uint32_t cntr_messages_0;
+	{
+		uint32_t _flags_save_STRUCT = ndr->flags;
+		ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+		NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+		if (ndr_flags & NDR_SCALARS) {
+			NDR_CHECK(ndr_push_align(ndr, 5));
+			for (cntr_messages_0 = 0; cntr_messages_0 < (r->count); cntr_messages_0++) {
+				NDR_CHECK(ndr_push_negoex_MESSAGE(ndr, NDR_SCALARS|NDR_BUFFERS, &r->messages[cntr_messages_0]));
+			}
+			NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+		}
+		ndr->flags = _flags_save_STRUCT;
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_MESSAGE_ARRAY(struct ndr_pull *ndr, int ndr_flags, struct negoex_MESSAGE_ARRAY *r)
+{
+	uint32_t size_messages_0 = 0;
+	uint32_t cntr_messages_0;
+	TALLOC_CTX *_mem_save_messages_0 = NULL;
+	{
+		uint32_t _flags_save_STRUCT = ndr->flags;
+		ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+		NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+		if (ndr_flags & NDR_SCALARS) {
+			uint32_t saved_offset = ndr->offset;
+			uint32_t available = 0;
+			NDR_CHECK(ndr_pull_align(ndr, 5));
+			r->count = 0;
+			available = ndr->data_size - ndr->offset;
+			while (available > 0) {
+				uint32_t length;
+
+				/*
+				 * The common header is 40 bytes
+				 * and message_length is at offset 20
+				 */
+				NDR_PULL_NEED_BYTES(ndr, 40);
+				ndr->offset += 20;
+				NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length));
+				ndr->offset -= 24;
+				if (length < 40) {
+					/*
+					 * let the pull function catch the error
+					 */
+					length = 40;
+				}
+				NDR_PULL_NEED_BYTES(ndr, length);
+				ndr->offset += length;
+				available -= length;
+				r->count++;
+			}
+			ndr->offset = saved_offset;
+			size_messages_0 = r->count;
+			NDR_PULL_ALLOC_N(ndr, r->messages, size_messages_0);
+			_mem_save_messages_0 = NDR_PULL_GET_MEM_CTX(ndr);
+			NDR_PULL_SET_MEM_CTX(ndr, r->messages, 0);
+			for (cntr_messages_0 = 0; cntr_messages_0 < (size_messages_0); cntr_messages_0++) {
+				NDR_CHECK(ndr_pull_negoex_MESSAGE(ndr, NDR_SCALARS|NDR_BUFFERS, &r->messages[cntr_messages_0]));
+			}
+			NDR_PULL_SET_MEM_CTX(ndr, _mem_save_messages_0, 0);
+			NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+		}
+		ndr->flags = _flags_save_STRUCT;
+	}
+	return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_negoex.h b/librpc/ndr/ndr_negoex.h
new file mode 100644
index 0000000..1be07d8
--- /dev/null
+++ b/librpc/ndr/ndr_negoex.h
@@ -0,0 +1,37 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   routines for marshalling/unmarshalling special NEGOEX structures
+
+   Copyright (C) Stefan Metzmacher 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "librpc/ndr/libndr.h"
+#include "bin/default/librpc/gen_ndr/negoex.h"
+
+_PUBLIC_ void ndr_print_negoex_BYTE_VECTOR(struct ndr_print *ndr, const char *name, const struct negoex_BYTE_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_BYTE_VECTOR(struct ndr_push *ndr, int ndr_flags, const struct negoex_BYTE_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_BYTE_VECTOR(struct ndr_pull *ndr, int ndr_flags, struct negoex_BYTE_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_AUTH_SCHEME_VECTOR(struct ndr_push *ndr, int ndr_flags, const struct negoex_AUTH_SCHEME_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_AUTH_SCHEME_VECTOR(struct ndr_pull *ndr, int ndr_flags, struct negoex_AUTH_SCHEME_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_EXTENSION_VECTOR(struct ndr_push *ndr, int ndr_flags, const struct negoex_EXTENSION_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_EXTENSION_VECTOR(struct ndr_pull *ndr, int ndr_flags, struct negoex_EXTENSION_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_ALERT_VECTOR(struct ndr_push *ndr, int ndr_flags, const struct negoex_ALERT_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_ALERT_VECTOR(struct ndr_pull *ndr, int ndr_flags, struct negoex_ALERT_VECTOR *r);
+_PUBLIC_ size_t ndr_negoex_MESSAGE_header_length(const struct negoex_MESSAGE *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_MESSAGE(struct ndr_pull *ndr, int ndr_flags, struct negoex_MESSAGE *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_MESSAGE_ARRAY(struct ndr_push *ndr, int ndr_flags, const struct negoex_MESSAGE_ARRAY *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_MESSAGE_ARRAY(struct ndr_pull *ndr, int ndr_flags, struct negoex_MESSAGE_ARRAY *r);
diff --git a/librpc/rpc/binding.c b/librpc/rpc/binding.c
index f131d00..d0acd6e 100644
--- a/librpc/rpc/binding.c
+++ b/librpc/rpc/binding.c
@@ -1226,7 +1226,7 @@ _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_towe
 			continue; 
 		}
 
-		for (j = 0; j < transports[i].num_protocols; j++) {
+		for (j = 0; j < transports[i].num_protocols && j < MAX_PROTSEQ; j++) {
 			if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
 				break;
 			}
diff --git a/librpc/rpc/rpc_common.h b/librpc/rpc/rpc_common.h
index 28600c9..b03b9ff 100644
--- a/librpc/rpc/rpc_common.h
+++ b/librpc/rpc/rpc_common.h
@@ -23,6 +23,7 @@
 #define __DEFAULT_LIBRPC_RPCCOMMON_H__
 
 #include "gen_ndr/dcerpc.h"
+#include "lib/util/attr.h"
 
 struct dcerpc_binding_handle;
 struct GUID;
diff --git a/librpc/tools/wscript_build b/librpc/tools/wscript_build
index a7463a9..a647470 100644
--- a/librpc/tools/wscript_build
+++ b/librpc/tools/wscript_build
@@ -3,5 +3,5 @@
 bld.SAMBA_BINARY('ndrdump',
 	source='ndrdump.c',
 	manpages='ndrdump.1',
-	deps='samba-hostconfig samba-util popt POPT_SAMBA ndr-table errors NDR_DCERPC'
+	deps='samba-hostconfig samba-util popt POPT_SAMBA ndr-table samba-errors NDR_DCERPC'
 	)
diff --git a/librpc/wscript_build b/librpc/wscript_build
index d376bec..20d64f1 100644
--- a/librpc/wscript_build
+++ b/librpc/wscript_build
@@ -232,6 +232,11 @@ bld.SAMBA_SUBSYSTEM('NDR_NTLMSSP',
     public_deps='ndr ndr-standard'
     )
 
+bld.SAMBA_SUBSYSTEM('NDR_NEGOEX',
+    source='ndr/ndr_negoex.c gen_ndr/ndr_negoex.c',
+    public_deps='ndr'
+    )
+
 bld.SAMBA_SUBSYSTEM('NDR_DNSP',
     source='gen_ndr/ndr_dnsp.c ndr/ndr_dnsp.c',
     public_deps='ndr'
@@ -311,7 +316,7 @@ bld.SAMBA_SUBSYSTEM('NDR_INITSHUTDOWN',
 
 bld.SAMBA_SUBSYSTEM('NDR_COMPRESSION',
     source='ndr/ndr_compression.c',
-    public_deps='errors ndr',
+    public_deps='samba-errors ndr',
     deps='z LZXPRESS'
     )
 
@@ -668,7 +673,7 @@ bld.SAMBA_SUBSYSTEM('RPC_NDR_MDSSVC',
 # a grouping library for NDR subsystems that may be used by more than one target
 bld.SAMBA_LIBRARY('ndr-samba',
     source=[],
-    deps='''NDR_DRSBLOBS NDR_DRSUAPI NDR_IDMAP NDR_NTLMSSP NDR_SCHANNEL NDR_MGMT
+    deps='''NDR_DRSBLOBS NDR_DRSUAPI NDR_IDMAP NDR_NTLMSSP NDR_NEGOEX NDR_SCHANNEL NDR_MGMT
     NDR_DNSSERVER NDR_EPMAPPER NDR_XATTR NDR_UNIXINFO NDR_NAMED_PIPE_AUTH NDR_DCOM
     NDR_NTPRINTING NDR_FSRVP NDR_WITNESS NDR_MDSSVC NDR_OPEN_FILES NDR_SMBXSRV''',
     private_library=True,
@@ -690,7 +695,7 @@ bld.SAMBA_LIBRARY('dcerpc-samba',
 bld.SAMBA_LIBRARY('ndr',
     source='ndr/ndr_string.c ndr/ndr_basic.c ndr/uuid.c ndr/ndr.c ndr/ndr_misc.c gen_ndr/ndr_misc.c ndr/util.c',
     pc_files='ndr.pc',
-    public_deps='errors talloc samba-util',
+    public_deps='samba-errors talloc samba-util',
     public_headers='gen_ndr/misc.h gen_ndr/ndr_misc.h ndr/libndr.h:ndr.h',
     header_path= [('*gen_ndr*', 'gen_ndr')],
     vnum='0.0.5',
diff --git a/nsswitch/libwbclient/tests/wbclient.c b/nsswitch/libwbclient/tests/wbclient.c
index 5bce0ae..4d04ca9 100644
--- a/nsswitch/libwbclient/tests/wbclient.c
+++ b/nsswitch/libwbclient/tests/wbclient.c
@@ -22,6 +22,7 @@
 #include "libcli/util/werror.h"
 #include "lib/util/data_blob.h"
 #include "lib/util/time.h"
+#include "libcli/resolve/resolve.h"
 #include "nsswitch/libwbclient/wbclient.h"
 #include "torture/smbtorture.h"
 #include "torture/winbind/proto.h"
@@ -404,6 +405,8 @@ static bool test_wbc_resolve_winsbyname(struct torture_context *tctx)
 
 	name = torture_setting_string(tctx, "host", NULL);
 
+	torture_comment(tctx, "test-WinsByName: host='%s'\n", name);
+
 	ret = wbcResolveWinsByName(name, &ip);
 
 	if (is_ipaddress(name)) {
@@ -418,10 +421,25 @@ static bool test_wbc_resolve_winsbyname(struct torture_context *tctx)
 static bool test_wbc_resolve_winsbyip(struct torture_context *tctx)
 {
 	const char *ip;
+	const char *host;
+	struct nbt_name nbt_name;
 	char *name;
 	wbcErr ret;
+	NTSTATUS status;
+
+	host = torture_setting_string(tctx, "host", NULL);
+
+	torture_comment(tctx, "test-WinsByIp: host='%s'\n", host);
+
+	make_nbt_name_server(&nbt_name, host);
+
+	status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+				 0, 0, &nbt_name, tctx, &ip, tctx->ev);
+	torture_assert_ntstatus_ok(tctx, status,
+			talloc_asprintf(tctx,"Failed to resolve %s: %s",
+					nbt_name.name, nt_errstr(status)));
 
-	ip = torture_setting_string(tctx, "host", NULL);
+	torture_comment(tctx, "test-WinsByIp: ip='%s'\n", ip);
 
 	ret = wbcResolveWinsByIP(ip, &name);
 
diff --git a/nsswitch/pam_winbind.c b/nsswitch/pam_winbind.c
index a2d9f3b..b83a276 100644
--- a/nsswitch/pam_winbind.c
+++ b/nsswitch/pam_winbind.c
@@ -1262,7 +1262,7 @@ static void _pam_setup_krb5_env(struct pwb_context *ctx,
 	}
 
 	ret = pam_putenv(ctx->pamh, var);
-	if (ret) {
+	if (ret != PAM_SUCCESS) {
 		_pam_log(ctx, LOG_ERR,
 			 "failed to set KRB5CCNAME to %s: %s",
 			 var, pam_strerror(ctx->pamh, ret));
@@ -1328,7 +1328,7 @@ static void _pam_set_data_string(struct pwb_context *ctx,
 
 	ret = pam_set_data(ctx->pamh, data_name, talloc_strdup(NULL, value),
 			   _pam_winbind_cleanup_func);
-	if (ret) {
+	if (ret != PAM_SUCCESS) {
 		_pam_log_debug(ctx, LOG_DEBUG,
 			       "Could not set data %s: %s\n",
 			       data_name, pam_strerror(ctx->pamh, ret));
@@ -1656,7 +1656,7 @@ static int _pam_mkhomedir(struct pwb_context *ctx)
 		}
 
 		ret = _pam_create_homedir(ctx, create_dir, mode);
-		if (ret) {
+		if (ret != PAM_SUCCESS) {
 			return ret;
 		}
 	}
@@ -2369,7 +2369,7 @@ static const char *get_member_from_config(struct pwb_context *ctx)
 	const char *ret = NULL;
 	ret = get_conf_item_string(ctx, "require_membership_of",
 				   WINBIND_REQUIRED_MEMBERSHIP);
-	if (ret) {
+	if (ret != NULL) {
 		return ret;
 	}
 	return get_conf_item_string(ctx, "require-membership-of",
@@ -2488,7 +2488,7 @@ static int _pam_delete_cred(pam_handle_t *pamh, int flags,
 	ZERO_STRUCT(logoff);
 
 	retval = _pam_winbind_init_context(pamh, flags, argc, argv, type, &ctx);
-	if (retval) {
+	if (retval != PAM_SUCCESS) {
 		return retval;
 	}
 
@@ -2503,7 +2503,7 @@ static int _pam_delete_cred(pam_handle_t *pamh, int flags,
 		struct passwd *pwd = NULL;
 
 		retval = pam_get_user(pamh, &user, _("Username: "));
-		if (retval) {
+		if (retval != PAM_SUCCESS) {
 			_pam_log(ctx, LOG_ERR,
 				 "could not identify user");
 			goto out;
@@ -2624,7 +2624,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
 
 	retval = _pam_winbind_init_context(pamh, flags, argc, argv,
 					   PAM_WINBIND_AUTHENTICATE, &ctx);
-	if (retval) {
+	if (retval != PAM_SUCCESS) {
 		return retval;
 	}
 
@@ -2776,7 +2776,7 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags,
 
 	ret = _pam_winbind_init_context(pamh, flags, argc, argv,
 					PAM_WINBIND_SETCRED, &ctx);
-	if (ret) {
+	if (ret != PAM_SUCCESS) {
 		return ret;
 	}
 
@@ -2830,7 +2830,7 @@ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
 
 	ret = _pam_winbind_init_context(pamh, flags, argc, argv,
 					PAM_WINBIND_ACCT_MGMT, &ctx);
-	if (ret) {
+	if (ret != PAM_SUCCESS) {
 		return ret;
 	}
 
@@ -2926,7 +2926,7 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags,
 
 	ret = _pam_winbind_init_context(pamh, flags, argc, argv,
 					PAM_WINBIND_OPEN_SESSION, &ctx);
-	if (ret) {
+	if (ret != PAM_SUCCESS) {
 		return ret;
 	}
 
@@ -2953,7 +2953,7 @@ int pam_sm_close_session(pam_handle_t *pamh, int flags,
 
 	ret = _pam_winbind_init_context(pamh, flags, argc, argv,
 					PAM_WINBIND_CLOSE_SESSION, &ctx);
-	if (ret) {
+	if (ret != PAM_SUCCESS) {
 		return ret;
 	}
 
@@ -3039,7 +3039,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
 	ret = _pam_winbind_init_context(pamh, flags, argc, argv,
 					PAM_WINBIND_CHAUTHTOK, &ctx);
-	if (ret) {
+	if (ret != PAM_SUCCESS) {
 		return ret;
 	}
 
@@ -3054,7 +3054,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 	 * First get the name of a user
 	 */
 	ret = pam_get_user(pamh, &user, _("Username: "));
-	if (ret) {
+	if (ret != PAM_SUCCESS) {
 		_pam_log(ctx, LOG_ERR,
 			 "password - could not identify user");
 		goto out;
@@ -3215,7 +3215,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
 		ret = winbind_chauthtok_request(ctx, user, pass_old,
 						pass_new, pwdlastset_update);
-		if (ret) {
+		if (ret != PAM_SUCCESS) {
 			pass_old = pass_new = NULL;
 			goto out;
 		}
diff --git a/nsswitch/wb_common.c b/nsswitch/wb_common.c
index 139f010..262181a 100644
--- a/nsswitch/wb_common.c
+++ b/nsswitch/wb_common.c
@@ -88,7 +88,7 @@ static void winbind_close_sock(struct winbindd_context *ctx)
 
 /* Destructor for global context to ensure fd is closed */
 
-#if HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR
+#if HAVE_DESTRUCTOR_ATTRIBUTE
 __attribute__((destructor))
 #endif
 static void winbind_destructor(void)
@@ -195,7 +195,7 @@ static int make_safe_fd(int fd)
  * @brief Check if we talk to the priviliged pipe which should be owned by root.
  *
  * This checks if we have uid_wrapper running and if this is the case it will
- * allow to connect to the winbind privileged pipe even it is not owned by root.
+ * allow one to connect to the winbind privileged pipe even it is not owned by root.
  *
  * @param[in]  uid      The uid to check if we can safely talk to the pipe.
  *
diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c
index f45d7b5..330fa91 100644
--- a/nsswitch/wbinfo.c
+++ b/nsswitch/wbinfo.c
@@ -1831,6 +1831,7 @@ static bool wbinfo_pam_logon(char *username, bool verbose)
 
 	if (verbose && (info != NULL)) {
 		struct wbcAuthUserInfo *i = info->info;
+		uint32_t j;
 
 		if (i->account_name != NULL) {
 			d_printf("account_name: %s\n", i->account_name);
@@ -1863,6 +1864,15 @@ static bool wbinfo_pam_logon(char *username, bool verbose)
 			d_printf("home_drive: %s\n", i->home_drive);
 		}
 
+		d_printf("sids:");
+
+		for (j=0; j<i->num_sids; j++) {
+			char buf[WBC_SID_STRING_BUFLEN];
+			wbcSidToStringBuf(&i->sids[j].sid, buf, sizeof(buf));
+			d_printf(" %s", buf);
+		}
+		d_printf("\n");
+
 		wbcFreeMemory(info);
 		info = NULL;
 	}
diff --git a/nsswitch/wins.c b/nsswitch/wins.c
index 587ec30..3243ffb 100644
--- a/nsswitch/wins.c
+++ b/nsswitch/wins.c
@@ -20,6 +20,7 @@
 
 #include "includes.h"
 #include "nsswitch/winbind_nss.h"
+#include "nsswitch/libwbclient/wbclient.h"
 
 #ifdef HAVE_NS_API_H
 
@@ -38,39 +39,17 @@ static pthread_mutex_t wins_nss_mutex = PTHREAD_MUTEX_INITIALIZER;
 #define INADDRSZ 4
 #endif
 
-static int initialised;
-
 NSS_STATUS _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
 			  char *buffer, size_t buflen, int *h_errnop);
 NSS_STATUS _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
 			   char *buffer, size_t buflen, int *h_errnop);
 
-static void nss_wins_init(void)
-{
-	initialised = 1;
-	lp_set_cmdline("log level", "0");
-
-	TimeInit();
-	setup_logging("nss_wins",False);
-	lp_load_global_no_reinit(get_dyn_CONFIGFILE());
-	load_interfaces();
-}
-
-static struct in_addr *lookup_byname_backend(const char *name, int *count)
+static char *lookup_byname_backend(const char *name)
 {
-	TALLOC_CTX *frame;
-	struct sockaddr_storage *address = NULL;
-	struct in_addr *ret = NULL;
-	NTSTATUS status;
 	const char *p;
+	char *ip;
 	size_t nbt_len;
-	int j;
-
-	if (!initialised) {
-		nss_wins_init();
-	}
-
-	*count = 0;
+	wbcErr result;
 
 	nbt_len = strlen(name);
 	if (nbt_len > MAX_NETBIOSNAME_LEN - 1) {
@@ -81,82 +60,42 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count)
 		return NULL;
 	}
 
-	frame = talloc_stackframe();
-	/* always try with wins first */
-	status = resolve_wins(name, 0x00, talloc_tos(),
-			      &address, count);
-	if (NT_STATUS_IS_OK(status)) {
-		if ( (ret = SMB_MALLOC_P(struct in_addr)) == NULL ) {
-			TALLOC_FREE(frame);
-			return NULL;
-		}
-		if (address[0].ss_family != AF_INET) {
-			free(ret);
-			TALLOC_FREE(frame);
-			return NULL;
-		}
-		*ret = ((struct sockaddr_in *)(void *)address)
-			->sin_addr;
-		TALLOC_FREE(frame);
-		return ret;
+	result = wbcResolveWinsByName(name, &ip);
+	if (result != WBC_ERR_SUCCESS) {
+		return NULL;
 	}
 
-	/* uggh, we have to broadcast to each interface in turn */
-	for (j=iface_count() - 1;j >= 0;j--) {
-		const struct in_addr *bcast = iface_n_bcast_v4(j);
-		struct sockaddr_storage ss;
-		struct sockaddr_storage *pss;
-
-		if (!bcast) {
-			continue;
-		}
-		in_addr_to_sockaddr_storage(&ss, *bcast);
-		status = name_query(name, 0x00, True, True, &ss,
-				    talloc_tos(), &pss, count, NULL);
-		if (NT_STATUS_IS_OK(status) && (*count > 0)) {
-			if ((ret = SMB_MALLOC_P(struct in_addr)) == NULL) {
-				TALLOC_FREE(frame);
-				return NULL;
-			}
-			*ret = ((struct sockaddr_in *)pss)->sin_addr;
-			break;
-		}
-	}
-	TALLOC_FREE(frame);
-	return ret;
+	return ip;
 }
 
 #ifdef HAVE_NS_API_H
 
-static struct node_status *lookup_byaddr_backend(char *addr, int *count)
+static char *lookup_byaddr_backend(const char *ip)
 {
-	struct sockaddr_storage ss;
-	struct nmb_name nname;
-	struct node_status *result;
-	NTSTATUS status;
+	wbcErr result;
+	char *name = NULL;
 
-	if (!initialised) {
-		nss_wins_init();
-	}
-
-	make_nmb_name(&nname, "*", 0);
-	if (!interpret_string_addr(&ss, addr, AI_NUMERICHOST)) {
-		return NULL;
-	}
-	status = node_status_query(NULL, &nname, &ss, &result, count, NULL);
-	if (!NT_STATUS_IS_OK(status)) {
+	result = wbcResolveWinsByIP(ip, &name);
+	if (result != WBC_ERR_SUCCESS) {
 		return NULL;
 	}
 
-	return result;
+	return name;
 }
 
 /* IRIX version */
 
 int init(void)
 {
+	bool ok;
+
 	nsd_logprintf(NSD_LOG_MIN, "entering init (wins)\n");
-	nss_wins_init();
+
+	ok = nss_wins_init();
+	if (!ok) {
+		return NSD_ERROR;
+	}
+
 	return NSD_OK;
 }
 
@@ -165,8 +104,6 @@ int lookup(nsd_file_t *rq)
 	char *map;
 	char *key;
 	char *addr;
-	struct in_addr *ip_list;
-	struct node_status *status;
 	int i, count, len, size;
 	char response[1024];
 	bool found = False;
@@ -195,58 +132,51 @@ int lookup(nsd_file_t *rq)
 	 * ip_address[ ip_address]*\tname[ alias]*
 	 */
 	if (strcasecmp_m(map,"hosts.byaddr") == 0) {
-		if ( status = lookup_byaddr_backend(key, &count)) {
-		    size = strlen(key) + 1;
-		    if (size > len) {
-			talloc_free(status);
-			return NSD_ERROR;
-		    }
-		    len -= size;
-		    strncat(response,key,size);
-		    strncat(response,"\t",1);
-		    for (i = 0; i < count; i++) {
-			/* ignore group names */
-			if (status[i].flags & 0x80) continue;
-			if (status[i].type == 0x20) {
-				size = sizeof(status[i].name) + 1;
-				if (size > len) {
-				    talloc_free(status);
-				    return NSD_ERROR;
-				}
-				len -= size;
-				strncat(response, status[i].name, size);
-				strncat(response, " ", 1);
-				found = True;
+		char *name;
+
+		name = lookup_byaddr_backend(key);
+		if (name != NULL) {
+			size = strlen(key) + 1;
+			if (size > len) {
+				return NSD_ERROR;
 			}
-		    }
-		    response[strlen(response)-1] = '\n';
-		    talloc_free(status);
+			len -= size;
+			strncat(response,key,size);
+			strncat(response,"\t",1);
+
+			size = strlen(name) + 1;
+			if (size > len) {
+				return NSD_ERROR;
+			}
+			len -= size;
+			strncat(response, name, size);
+			strncat(response, " ", 1);
+			found = True;
 		}
+		response[strlen(response)-1] = '\n';
 	} else if (strcasecmp_m(map,"hosts.byname") == 0) {
-	    if (ip_list = lookup_byname_backend(key, &count)) {
-		for (i = count; i ; i--) {
-		    addr = inet_ntoa(ip_list[i-1]);
-		    size = strlen(addr) + 1;
-		    if (size > len) {
-			free(ip_list);
-			return NSD_ERROR;
-		    }
-		    len -= size;
-		    if (i != 0)
-			response[strlen(response)-1] = ' ';
-		    strncat(response,addr,size);
-		    strncat(response,"\t",1);
-		}
-		size = strlen(key) + 1;
-		if (size > len) {
-		    free(ip_list);
-		    return NSD_ERROR;
+		char *ip;
+
+		ip = lookup_byname_backend(key);
+		if (ip != NULL) {
+			size = strlen(ip) + 1;
+			if (size > len) {
+				wbcFreeMemory(ip);
+				return NSD_ERROR;
+			}
+			len -= size;
+			strncat(response,ip,size);
+			strncat(response,"\t",1);
+			size = strlen(key) + 1;
+			wbcFreeMemory(ip);
+			if (size > len) {
+				return NSD_ERROR;
+			}
+			strncat(response,key,size);
+			strncat(response,"\n",1);
+
+			found = True;
 		}
-		strncat(response,key,size);
-		strncat(response,"\n",1);
-		found = True;
-		free(ip_list);
-	    }
 	}
 
 	if (found) {
@@ -265,7 +195,7 @@ int lookup(nsd_file_t *rq)
    are the pointers passed in by the C library to the _nss_*_*
    functions. */
 
-static char *get_static(char **buffer, size_t *buflen, int len)
+static char *get_static(char **buffer, size_t *buflen, size_t len)
 {
 	char *result;
 
@@ -294,36 +224,40 @@ _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
 			  char *buffer, size_t buflen, int *h_errnop)
 {
 	NSS_STATUS nss_status = NSS_STATUS_SUCCESS;
-	struct in_addr *ip_list;
-	int i, count;
+	char *ip;
+	struct in_addr in;
+	int i;
 	fstring name;
 	size_t namelen;
-	TALLOC_CTX *frame;
+	int rc;
 
 #if HAVE_PTHREAD
 	pthread_mutex_lock(&wins_nss_mutex);
 #endif
 
-	frame = talloc_stackframe();
-
 	memset(he, '\0', sizeof(*he));
 	fstrcpy(name, hostname);
 
 	/* Do lookup */
 
-	ip_list = lookup_byname_backend(name, &count);
-
-	if (!ip_list) {
+	ip = lookup_byname_backend(name);
+	if (ip == NULL) {
 		nss_status = NSS_STATUS_NOTFOUND;
 		goto out;
 	}
 
+	rc = inet_pton(AF_INET, ip, &in);
+	wbcFreeMemory(ip);
+	if (rc == 0) {
+		nss_status = NSS_STATUS_TRYAGAIN;
+		goto out;
+	}
+
 	/* Copy h_name */
 
 	namelen = strlen(name) + 1;
 
 	if ((he->h_name = get_static(&buffer, &buflen, namelen)) == NULL) {
-		free(ip_list);
 		nss_status = NSS_STATUS_TRYAGAIN;
 		goto out;
 	}
@@ -336,31 +270,25 @@ _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
 		i = sizeof(char*) - i;
 
 	if (get_static(&buffer, &buflen, i) == NULL) {
-		free(ip_list);
 		nss_status = NSS_STATUS_TRYAGAIN;
 		goto out;
 	}
 
 	if ((he->h_addr_list = (char **)get_static(
-		     &buffer, &buflen, (count + 1) * sizeof(char *))) == NULL) {
-		free(ip_list);
+		     &buffer, &buflen, i * sizeof(char *))) == NULL) {
 		nss_status = NSS_STATUS_TRYAGAIN;
 		goto out;
 	}
 
-	for (i = 0; i < count; i++) {
-		if ((he->h_addr_list[i] = get_static(&buffer, &buflen,
-						     INADDRSZ)) == NULL) {
-			free(ip_list);
-			nss_status = NSS_STATUS_TRYAGAIN;
-			goto out;
-		}
-		memcpy(he->h_addr_list[i], &ip_list[i], INADDRSZ);
+	if ((he->h_addr_list[0] = get_static(&buffer, &buflen,
+					     INADDRSZ)) == NULL) {
+		nss_status = NSS_STATUS_TRYAGAIN;
+		goto out;
 	}
 
-	he->h_addr_list[count] = NULL;
+	memcpy(he->h_addr_list[i], &in, INADDRSZ);
 
-	free(ip_list);
+	he->h_addr_list[0] = NULL;
 
 	/* Set h_addr_type and h_length */
 
@@ -389,8 +317,6 @@ _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
 
   out:
 
-	TALLOC_FREE(frame);
-
 #if HAVE_PTHREAD
 	pthread_mutex_unlock(&wins_nss_mutex);
 #endif
diff --git a/nsswitch/wins_freebsd.c b/nsswitch/wins_freebsd.c
new file mode 100644
index 0000000..c1845d2
--- /dev/null
+++ b/nsswitch/wins_freebsd.c
@@ -0,0 +1,81 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Timur I. Bakeyev 2007
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.
+*/
+
+#include "winbind_client.h"
+
+extern enum nss_status _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
+                          char *buffer, size_t buflen, int *h_errnop);
+
+ns_mtab *nss_module_register(const char *source, unsigned int *, nss_module_unregister_fn *);
+
+NSS_METHOD_PROTOTYPE(__nss_wins_freebsd_gethostbyname2_r);
+
+static ns_mtab methods[] =
+{
+       { NSDB_HOSTS, "getaddrinfo",      NULL, NULL },
+       { NSDB_HOSTS, "ghbyname",         NULL, NULL },
+       { NSDB_HOSTS, "ghbyaddr",         NULL, NULL },
+       { NSDB_HOSTS, "gethostbyaddr_r",  NULL, NULL },
+       { NSDB_HOSTS, "gethostbyname2_r", __nss_wins_freebsd_gethostbyname2_r, _nss_wins_gethostbyname2_r },
+       { NSDB_HOSTS, "getnetbyname_r",   NULL, NULL },
+       { NSDB_HOSTS, "getnetbyaddr_r",   NULL, NULL },
+       { NSDB_HOSTS, "gethostbyname",    NULL, NULL },
+       { NSDB_HOSTS, "gethostbyaddr",    NULL, NULL },
+       { NSDB_HOSTS, "getnetbyname",     NULL, NULL },
+       { NSDB_HOSTS, "getnetbyaddr",     NULL, NULL }
+};
+
+int
+__nss_wins_freebsd_gethostbyname2_r(void *retval, void *mdata, va_list ap)
+{
+       int (*fn)(const char *, int, struct hostent *, char *, size_t, int *);
+       const char      *hostname;
+       int             af;
+       struct hostent  *he;
+       char            *buffer;
+       size_t          buflen;
+       int             *h_errnop;
+       enum nss_status status;
+
+       fn = mdata;
+       hostname = va_arg(ap, const char *);
+       af = va_arg(ap, int);
+       he = va_arg(ap, struct hostent *);
+       buffer = va_arg(ap, char *);
+       buflen = va_arg(ap, size_t);
+       h_errnop = va_arg(ap, int *);
+
+       status = fn(hostname, af, he, buffer, buflen, h_errnop);
+       status = __nss_compat_result(status, *h_errnop);
+       if (status == NS_SUCCESS)
+               *(struct hostent **)retval = he;
+
+       return (status);
+}
+
+ns_mtab *
+nss_module_register(const char *source __unused, unsigned int *mtabsize,
+    nss_module_unregister_fn *unreg)
+{
+       *mtabsize = sizeof(methods) / sizeof(methods[0]);
+       *unreg = NULL;
+       return (methods);
+}
diff --git a/nsswitch/wscript_build b/nsswitch/wscript_build
index 381ff44..f286896 100644
--- a/nsswitch/wscript_build
+++ b/nsswitch/wscript_build
@@ -39,11 +39,10 @@ if (Utils.unversioned_sys_platform() == 'linux' or (host_os.rfind('gnu') > -1)):
               pc_files=[],
               vnum='2')
 
-    # for nss_wins is linux only
     bld.SAMBA3_LIBRARY('nss_wins',
                        keep_underscore=True,
                        source='wins.c',
-                       deps='''param libsmb LIBTSOCKET''',
+                       deps='''wbclient''',
                        public_headers=[],
                        public_headers_install=False,
                        pc_files=[],
@@ -57,6 +56,12 @@ elif (host_os.rfind('freebsd') > -1):
 			  realname='nss_winbind.so.1',
 			  vnum='1')
 
+	bld.SAMBA3_LIBRARY('nss_wins',
+			  source='wins.c wins_freebsd.c',
+			  deps='''wbclient''',
+			  realname='nss_wins.so.1',
+			  vnum='1')
+
 elif (host_os.rfind('netbsd') > -1):
 	# NetBSD winbind client is implemented as a wrapper
 	# around the Linux version. It needs getpwent_r() to
diff --git a/packaging/RHEL-CTDB/configure.rpm b/packaging/RHEL-CTDB/configure.rpm
index 62a326c..a2d35ea 100755
--- a/packaging/RHEL-CTDB/configure.rpm
+++ b/packaging/RHEL-CTDB/configure.rpm
@@ -51,7 +51,6 @@ CC="$CC" CFLAGS="-Wall -g -D_GNU_SOURCE -O3" ./configure -C \
 	--with-ads \
 	--with-automount \
 	--enable-fhs \
-	--with-pam_smbpass \
 	--with-libsmbclient \
 	--without-smbwrapper \
 	--with-pam \
@@ -63,7 +62,6 @@ CC="$CC" CFLAGS="-Wall -g -D_GNU_SOURCE -O3" ./configure -C \
 	--with-ctdb=/usr/include \
 	--without-ldb \
 	--without-dnsupdate \
-	--with-aio-support \
 	--disable-external-libtalloc \
 	--disable-external-libtdb \
 	$*
diff --git a/packaging/RHEL-CTDB/samba.spec.tmpl b/packaging/RHEL-CTDB/samba.spec.tmpl
index ad18826..6380158 100644
--- a/packaging/RHEL-CTDB/samba.spec.tmpl
+++ b/packaging/RHEL-CTDB/samba.spec.tmpl
@@ -169,7 +169,6 @@ CFLAGS="$RPM_OPT_FLAGS $EXTRA -D_GNU_SOURCE" ./configure \
 	--with-ads \
 	--with-automount \
 	--enable-fhs \
-	--with-pam_smbpass \
 	--with-libsmbclient \
 	--without-smbwrapper \
 	--with-pam \
@@ -181,7 +180,6 @@ CFLAGS="$RPM_OPT_FLAGS $EXTRA -D_GNU_SOURCE" ./configure \
 	--with-ctdb=/usr/include \
 	--without-ldb \
 	--without-dnsupdate \
-	--with-aio-support \
 	--disable-external-libtalloc \
 	--disable-external-libtdb
 
@@ -199,7 +197,7 @@ fi
 
 
 make -j %{numcpu} %{?_smp_mflags} \
-	everything modules pam_smbpass
+	everything modules
 
 # check that desired suppor has been compiled into smbd:
 export LD_LIBRARY_PATH=./bin
@@ -419,10 +417,8 @@ exit 0
 %{_libarchdir}/samba/vfs/readahead.so
 %{_libarchdir}/samba/vfs/readonly.so
 %{_libarchdir}/samba/vfs/recycle.so
-%{_libarchdir}/samba/vfs/scannedonly.so
 %{_libarchdir}/samba/vfs/shadow_copy.so
 %{_libarchdir}/samba/vfs/shadow_copy2.so
-%{_libarchdir}/samba/vfs/smb_traffic_analyzer.so
 %{_libarchdir}/samba/vfs/streams_depot.so
 %{_libarchdir}/samba/vfs/streams_xattr.so
 %{_libarchdir}/samba/vfs/syncops.so
@@ -431,7 +427,6 @@ exit 0
 %{_libarchdir}/samba/vfs/tsmsm.so
 %endif
 %{_libarchdir}/samba/vfs/xattr_tdb.so
-%{_libarchdir}/samba/vfs/aio_posix.so
 %{_libarchdir}/samba/vfs/aio_pthread.so
 %{_libarchdir}/samba/vfs/media_harmony.so
 
@@ -446,7 +441,6 @@ exit 0
 %{_mandir}/man8/smbd.8*
 %{_mandir}/man8/eventlogadm.8*
 %{_mandir}/man8/vfs_*.8*
-%{_mandir}/man8/smbta-util.8*
 
 
 ##########
@@ -494,7 +488,6 @@ exit 0
 %{_bindir}/smbtar
 %{_bindir}/smbtree
 %{_bindir}/sharesec
-%{_bindir}/smbta-util
 
 %{_mandir}/man8/smbspool.8*
 %{_mandir}/man1/smbget.1*
@@ -523,7 +516,6 @@ exit 0
 %attr(755,root,root) /%{_libarch}/libnss_winbind.so
 %attr(755,root,root) /%{_libarch}/libnss_winbind.so.2
 %attr(755,root,root) /%{_libarch}/security/pam_winbind.so
-%attr(755,root,root) /%{_libarch}/security/pam_smbpass.so
 /usr/share/locale/*/LC_MESSAGES/pam_winbind.mo
 /usr/share/locale/*/LC_MESSAGES/net.mo
 
diff --git a/packaging/RHEL/samba.spec.tmpl b/packaging/RHEL/samba.spec.tmpl
index 5188fa5..bb8ff11 100644
--- a/packaging/RHEL/samba.spec.tmpl
+++ b/packaging/RHEL/samba.spec.tmpl
@@ -165,7 +165,6 @@ CC="$CC" CFLAGS="$RPM_OPT_FLAGS $EXTRA -D_GNU_SOURCE" ./configure \
 	--with-ads \
         --with-automount \
         --with-fhs \
-	--with-pam_smbpass \
 	--with-libsmbclient \
         --without-smbwrapper \
 	--with-pam \
@@ -188,7 +187,7 @@ if [ ${CC_MAJOR} -ge 3 ]; then
 fi
 
 
-make all modules pam_smbpass
+make all modules
 
 # Remove some permission bits to avoid to many dependencies
 cd ..
@@ -338,7 +337,6 @@ fi
 %{_bindir}/mksmbpasswd.sh
 %{_bindir}/smbcontrol
 %{_bindir}/smbstatus
-%{_bindir}/smbta-util
 %{_bindir}/tdbbackup
 %{_bindir}/tdbtool
 %{_bindir}/tdbdump
@@ -444,7 +442,6 @@ fi
 %attr(755,root,root) /%{_libarch}/libnss_wins.so*
 %attr(755,root,root) /%{_libarch}/libnss_winbind.so*
 %attr(755,root,root) /%{_libarch}/security/pam_winbind.so
-%attr(755,root,root) /%{_libarch}/security/pam_smbpass.so
 /usr/share/locale/de/LC_MESSAGES/net.mo
 /usr/share/locale/de/LC_MESSAGES/pam_winbind.mo
 /usr/share/locale/ar/LC_MESSAGES/pam_winbind.mo
@@ -494,7 +491,6 @@ fi
 %{_mandir}/man8/smbpasswd.8*
 %{_mandir}/man5/pam_winbind.conf.5.*
 %{_mandir}/man7/libsmbclient.7*
-%{_mandir}/man8/smbta-util.8*
 %{_mandir}/man8/pam_winbind.8*
 
 %changelog
diff --git a/pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm b/pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm
index aa913f1..28d5245 100644
--- a/pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm
+++ b/pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm
@@ -13,7 +13,7 @@ use Exporter;
 
 use strict;
 use Parse::Pidl qw(fatal warning error);
-use Parse::Pidl::Util qw(has_property ParseExpr);
+use Parse::Pidl::Util qw(has_property ParseExpr genpad);
 use Parse::Pidl::NDR qw(ContainsPipe);
 use Parse::Pidl::Typelist qw(mapTypeName);
 use Parse::Pidl::Samba4 qw(DeclLong);
@@ -28,15 +28,6 @@ sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n
 sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; } 
 sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); }
 
-sub genpad($)
-{
-	my ($s) = @_;
-	my $nt = int((length($s)+1)/8);
-	my $lt = ($nt*8)-1;
-	my $ns = (length($s)-$lt);
-	return "\t"x($nt)." "x($ns);
-}
-
 sub new($)
 {
 	my ($class) = shift;
diff --git a/pidl/lib/Parse/Pidl/Samba3/Template.pm b/pidl/lib/Parse/Pidl/Samba3/Template.pm
index 3496927..4750cef 100644
--- a/pidl/lib/Parse/Pidl/Samba3/Template.pm
+++ b/pidl/lib/Parse/Pidl/Samba3/Template.pm
@@ -8,19 +8,12 @@ package Parse::Pidl::Samba3::Template;
 use vars qw($VERSION);
 $VERSION = '0.01';
 
+use Parse::Pidl::Util qw(genpad);
+
 use strict;
 
 my($res);
 
-sub genpad($)
-{
-	my ($s) = @_;
-	my $nt = int((length($s)+1)/8);
-	my $lt = ($nt*8)-1;
-	my $ns = (length($s)-$lt);
-	return "\t"x($nt)." "x($ns);
-}
-
 #####################################################################
 # produce boilerplate code for a interface
 sub Template($)
diff --git a/pidl/lib/Parse/Pidl/Samba4/NDR/Client.pm b/pidl/lib/Parse/Pidl/Samba4/NDR/Client.pm
index ee68090..040cd5a 100644
--- a/pidl/lib/Parse/Pidl/Samba4/NDR/Client.pm
+++ b/pidl/lib/Parse/Pidl/Samba4/NDR/Client.pm
@@ -11,7 +11,7 @@ use Exporter;
 @EXPORT_OK = qw(Parse);
 
 use Parse::Pidl qw(fatal warning error);
-use Parse::Pidl::Util qw(has_property ParseExpr);
+use Parse::Pidl::Util qw(has_property ParseExpr genpad);
 use Parse::Pidl::NDR qw(ContainsPipe);
 use Parse::Pidl::Typelist qw(mapTypeName);
 use Parse::Pidl::Samba4 qw(choose_header is_intree DeclLong);
@@ -29,15 +29,6 @@ sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; }
 sub pidl_both($$) { my ($self, $txt) = @_; $self->{hdr} .= "$txt\n"; $self->{res_hdr} .= "$txt\n"; }
 sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); }
 
-sub genpad($)
-{
-	my ($s) = @_;
-	my $nt = int((length($s)+1)/8);
-	my $lt = ($nt*8)-1;
-	my $ns = (length($s)-$lt);
-	return "\t"x($nt)." "x($ns);
-}
-
 sub new($)
 {
 	my ($class) = shift;
diff --git a/pidl/lib/Parse/Pidl/Samba4/Python.pm b/pidl/lib/Parse/Pidl/Samba4/Python.pm
index 180b6b2..6488ac9 100644
--- a/pidl/lib/Parse/Pidl/Samba4/Python.pm
+++ b/pidl/lib/Parse/Pidl/Samba4/Python.pm
@@ -224,7 +224,7 @@ sub PythonStruct($$$$$$)
 			if ($l->{TYPE} eq "POINTER" and
 				not ($nl->{TYPE} eq "ARRAY" and ($nl->{IS_FIXED} or is_charset_array($e, $nl))) and
 				not ($nl->{TYPE} eq "DATA" and Parse::Pidl::Typelist::scalar_is_reference($nl->{DATA_TYPE}))) {
-				$self->pidl("talloc_unlink(pytalloc_get_mem_ctx(py_obj), discard_const($varname));");
+				$self->pidl("talloc_unlink($mem_ctx, discard_const($varname));");
 			}
 			$self->ConvertObjectFromPython($env, $mem_ctx, $e, "value", $varname, "return -1;");
 			$self->pidl("return 0;");
@@ -237,9 +237,16 @@ sub PythonStruct($$$$$$)
 		$self->pidl("static PyGetSetDef ".$getsetters."[] = {");
 		$self->indent;
 		foreach my $e (@{$d->{ELEMENTS}}) {
-			$self->pidl("{ discard_const_p(char, \"$e->{NAME}\"), py_$name\_get_$e->{NAME}, py_$name\_set_$e->{NAME} },");
+			$self->pidl("{");
+			$self->indent;
+			$self->pidl(".name = discard_const_p(char, \"$e->{NAME}\"),");
+			$self->pidl(".get = py_$name\_get_$e->{NAME},");
+			$self->pidl(".set = py_$name\_set_$e->{NAME},");
+			$self->pidl(".doc = discard_const_p(char, \"PIDL-generated element $e->{NAME}\")");
+			$self->deindent;
+			$self->pidl("},");
 		}
-		$self->pidl("{ NULL }");
+		$self->pidl("{ .name = NULL }");
 		$self->deindent;
 		$self->pidl("};");
 		$self->pidl("");
@@ -262,17 +269,28 @@ sub PythonStruct($$$$$$)
 		$self->pidl("{");
 		$self->indent;
 		$self->pidl("$cname *object = ($cname *)pytalloc_get_ptr(py_obj);");
+		$self->pidl("PyObject *ret = NULL;");
 		$self->pidl("DATA_BLOB blob;");
 		$self->pidl("enum ndr_err_code err;");
-		$self->pidl("err = ndr_push_struct_blob(&blob, pytalloc_get_mem_ctx(py_obj), object, (ndr_push_flags_fn_t)ndr_push_$name);");
+		$self->pidl("TALLOC_CTX *tmp_ctx = talloc_new(pytalloc_get_mem_ctx(py_obj));");
+		$self->pidl("if (tmp_ctx == NULL) {");
+		$self->indent;
+		$self->pidl("PyErr_SetNdrError(NDR_ERR_ALLOC);");
+		$self->pidl("return NULL;");
+		$self->deindent;
+		$self->pidl("}");
+		$self->pidl("err = ndr_push_struct_blob(&blob, tmp_ctx, object, (ndr_push_flags_fn_t)ndr_push_$name);");
 		$self->pidl("if (err != NDR_ERR_SUCCESS) {");
 		$self->indent;
+		$self->pidl("TALLOC_FREE(tmp_ctx);");
 		$self->pidl("PyErr_SetNdrError(err);");
 		$self->pidl("return NULL;");
 		$self->deindent;
 		$self->pidl("}");
 		$self->pidl("");
-		$self->pidl("return PyString_FromStringAndSize((char *)blob.data, blob.length);");
+		$self->pidl("ret = PyString_FromStringAndSize((char *)blob.data, blob.length);");
+		$self->pidl("TALLOC_FREE(tmp_ctx);");
+		$self->pidl("return ret;");
 		$self->deindent;
 		$self->pidl("}");
 		$self->pidl("");
@@ -282,7 +300,7 @@ sub PythonStruct($$$$$$)
 		$self->indent;
 		$self->pidl("$cname *object = ($cname *)pytalloc_get_ptr(py_obj);");
 		$self->pidl("DATA_BLOB blob;");
-		$self->pidl("int blob_length = 0;");
+		$self->pidl("Py_ssize_t blob_length = 0;");
 		$self->pidl("enum ndr_err_code err;");
 		$self->pidl("const char * const kwnames[] = { \"data_blob\", \"allow_remaining\", NULL };");
 		$self->pidl("PyObject *allow_remaining_obj = NULL;");
@@ -369,15 +387,16 @@ sub PythonStruct($$$$$$)
 	}
 	$self->pidl(".tp_methods = $py_methods,");
 	$self->pidl(".tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,");
-	$self->pidl(".tp_basicsize = sizeof(pytalloc_Object),");
 	$self->pidl(".tp_new = py_$name\_new,");
 	$self->deindent;
 	$self->pidl("};");
 
 	$self->pidl("");
 
-	my $talloc_typename = $self->import_type_variable("talloc", "Object");
-	$self->register_module_prereadycode(["$name\_Type.tp_base = $talloc_typename;", ""]);
+	my $talloc_typename = $self->import_type_variable("talloc", "BaseObject");
+	$self->register_module_prereadycode(["$name\_Type.tp_base = $talloc_typename;",
+					     "$name\_Type.tp_basicsize = pytalloc_BaseObject_size();",
+					     ""]);
 
 	return "&$typeobject";
 }
@@ -803,7 +822,6 @@ sub Interface($$$)
 		$self->indent;
 		$self->pidl("PyObject_HEAD_INIT(NULL) 0,");
 		$self->pidl(".tp_name = \"$basename.$interface->{NAME}\",");
-		$self->pidl(".tp_basicsize = sizeof(pytalloc_Object),");
 		$self->pidl(".tp_doc = $docstring,");
 		$self->pidl(".tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,");
 		$self->pidl(".tp_new = syntax_$interface->{NAME}_new,");
@@ -814,7 +832,9 @@ sub Interface($$$)
 
 		$self->register_module_typeobject("abstract_syntax", "&$syntax_typename");
 		my $ndr_typename = $self->import_type_variable("samba.dcerpc.misc", "ndr_syntax_id");
-		$self->register_module_prereadycode(["$syntax_typename.tp_base = $ndr_typename;", ""]);
+		$self->register_module_prereadycode(["$syntax_typename.tp_base = $ndr_typename;",
+						     "$syntax_typename.tp_basicsize = pytalloc_BaseObject_size();",
+						     ""]);
 	}
 
 	$self->pidl_hdr("\n");
@@ -1490,6 +1510,7 @@ sub Parse($$$$$)
 
     $self->pidl_hdr("
 /* Python wrapper functions auto-generated by pidl */
+#define PY_SSIZE_T_CLEAN 1 /* We use Py_ssize_t for PyArg_ParseTupleAndKeywords */
 #include <Python.h>
 #include \"includes.h\"
 #include <pytalloc.h>
diff --git a/pidl/lib/Parse/Pidl/Samba4/Template.pm b/pidl/lib/Parse/Pidl/Samba4/Template.pm
index e79af85..d9fb304 100644
--- a/pidl/lib/Parse/Pidl/Samba4/Template.pm
+++ b/pidl/lib/Parse/Pidl/Samba4/Template.pm
@@ -8,19 +8,12 @@ package Parse::Pidl::Samba4::Template;
 use vars qw($VERSION);
 $VERSION = '0.01';
 
+use Parse::Pidl::Util qw(genpad);
+
 use strict;
 
 my($res);
 
-sub genpad($)
-{
-	my ($s) = @_;
-	my $nt = int((length($s)+1)/8);
-	my $lt = ($nt*8)-1;
-	my $ns = (length($s)-$lt);
-	return "\t"x($nt)." "x($ns);
-}
-
 #####################################################################
 # produce boilerplate code for a interface
 sub Template($)
diff --git a/pidl/lib/Parse/Pidl/Util.pm b/pidl/lib/Parse/Pidl/Util.pm
index 421cb8f..83e2393 100644
--- a/pidl/lib/Parse/Pidl/Util.pm
+++ b/pidl/lib/Parse/Pidl/Util.pm
@@ -6,7 +6,7 @@ package Parse::Pidl::Util;
 
 require Exporter;
 @ISA = qw(Exporter);
- at EXPORT = qw(has_property property_matches ParseExpr ParseExprExt is_constant make_str unmake_str print_uuid MyDumper);
+ at EXPORT = qw(has_property property_matches ParseExpr ParseExprExt is_constant make_str unmake_str print_uuid MyDumper genpad);
 use vars qw($VERSION);
 $VERSION = '0.01';
 
@@ -176,6 +176,20 @@ sub ParseExprExt($$$$$)
 		$deref, $use);
 }
 
+=item B<genpad>
+return an empty string consisting of tabs and spaces suitable for proper indent
+of C-functions.
+
+=cut
+sub genpad($)
+{
+	my ($s) = @_;
+	my $nt = int((length($s)+1)/8);
+	my $lt = ($nt*8)-1;
+	my $ns = (length($s)-$lt);
+	return "\t"x($nt)." "x($ns);
+}
+
 =back
 
 =cut
diff --git a/pidl/wscript b/pidl/wscript
index 27cb230..f4ff902 100644
--- a/pidl/wscript
+++ b/pidl/wscript
@@ -1,13 +1,12 @@
 #!/usr/bin/env python
 
-import os, sys, Logs
+import os, Logs
 from samba_utils import MODE_755
 
 # This function checks if a perl module is installed on the system.
 def check_system_perl_module(conf, module, version=None):
     bundle_name = module.replace('::', '_')
     module_check = module
-    found = False
 
     # Create module string with version
     if version:
@@ -65,8 +64,6 @@ def build(bld):
     # use perl to build the manpages
     bld.env.pidl_srcdir = os.path.join(bld.srcnode.abspath(), 'pidl')
 
-    blib_bld = os.path.join(bld.srcnode.abspath(bld.env), 'pidl/blib')
-
     bld.SET_BUILD_GROUP('final')
     if 'POD2MAN' in bld.env and bld.env['POD2MAN'] != '':
         for src, manpage in pidl_manpages.iteritems():
diff --git a/python/pyglue.c b/python/pyglue.c
index 3fc6e38..81244a2 100644
--- a/python/pyglue.c
+++ b/python/pyglue.c
@@ -121,6 +121,15 @@ static PyObject *py_get_debug_level(PyObject *self)
 	return PyInt_FromLong(DEBUGLEVEL);
 }
 
+static PyObject *py_is_ntvfs_fileserver_built(PyObject *self)
+{
+#ifdef WITH_NTVFS_FILESERVER
+	Py_RETURN_TRUE;
+#else
+	Py_RETURN_FALSE;
+#endif
+}
+
 /*
   return the list of interface IPs we have configured
   takes an loadparm context, returns a list of IPs in string form
@@ -267,6 +276,8 @@ static PyMethodDef py_misc_methods[] = {
 		"(for testing) compare two strings using Samba's strcasecmp_m()"},
 	{ "strstr_m", (PyCFunction)py_strstr_m, METH_VARARGS,
 		"(for testing) find one string in another with Samba's strstr_m()"},
+	{ "is_ntvfs_fileserver_built", (PyCFunction)py_is_ntvfs_fileserver_built, METH_NOARGS,
+		"is the NTVFS file server built in this installation?" },
 	{ NULL }
 };
 
diff --git a/python/samba/__init__.py b/python/samba/__init__.py
index aaf335c..7cfbc4c 100644
--- a/python/samba/__init__.py
+++ b/python/samba/__init__.py
@@ -398,3 +398,4 @@ unix2nttime = _glue.unix2nttime
 generate_random_password = _glue.generate_random_password
 strcasecmp_m = _glue.strcasecmp_m
 strstr_m = _glue.strstr_m
+is_ntvfs_fileserver_built = _glue.is_ntvfs_fileserver_built
diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
index 4fb9d12..db0803b 100644
--- a/python/samba/dbchecker.py
+++ b/python/samba/dbchecker.py
@@ -49,6 +49,7 @@ class dbcheck(object):
         self.remove_all_unknown_attributes = False
         self.remove_all_empty_attributes = False
         self.fix_all_normalisation = False
+        self.fix_all_duplicates = False
         self.fix_all_DN_GUIDs = False
         self.fix_all_binary_dn = False
         self.remove_all_deleted_DN_links = False
@@ -64,6 +65,8 @@ class dbcheck(object):
         self.move_to_lost_and_found = False
         self.fix_instancetype = False
         self.fix_replmetadata_zero_invocationid = False
+        self.fix_replmetadata_duplicate_attid = False
+        self.fix_replmetadata_wrong_attid = False
         self.fix_replmetadata_unsorted_attid = False
         self.fix_deleted_deleted_objects = False
         self.fix_dn = False
@@ -290,6 +293,23 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                           validate=False):
             self.report("Normalised attribute %s" % attrname)
 
+    def err_duplicate_values(self, dn, attrname, dup_values, values):
+        '''fix attribute normalisation errors'''
+        self.report("ERROR: Duplicate values for attribute '%s' in '%s'" % (attrname, dn))
+        self.report("Values contain a duplicate: [%s]/[%s]!" % (','.join(dup_values), ','.join(values)))
+        if not self.confirm_all("Fix duplicates for '%s' from '%s'?" % (attrname, dn), 'fix_all_duplicates'):
+            self.report("Not fixing attribute '%s'" % attrname)
+            return
+
+        m = ldb.Message()
+        m.dn = dn
+        m[attrname] = ldb.MessageElement(values, ldb.FLAG_MOD_REPLACE, attrname)
+
+        if self.do_modify(m, ["relax:0", "show_recycled:1"],
+                          "Failed to remove duplicate value on attribute %s" % attrname,
+                          validate=False):
+            self.report("Removed duplicate value on attribute %s" % attrname)
+
     def is_deleted_objects_dn(self, dsdb_dn):
         '''see if a dsdb_Dn is the special Deleted Objects DN'''
         return dsdb_dn.prefix == "B:32:%s:" % dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER
@@ -701,12 +721,14 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
 
         return 0
 
-    def process_metadata(self, val):
+    def process_metadata(self, dn, val):
         '''Read metadata properties and list attributes in it.
            raises KeyError if the attid is unknown.'''
 
         set_att = set()
+        wrong_attids = set()
         list_attid = []
+        in_schema_nc = dn.is_child_of(self.schema_dn)
 
         repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(val))
         obj = repl.ctr
@@ -715,8 +737,12 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
             att = self.samdb_schema.get_lDAPDisplayName_by_attid(o.attid)
             set_att.add(att.lower())
             list_attid.append(o.attid)
+            correct_attid = self.samdb_schema.get_attid_from_lDAPDisplayName(att,
+                                                                             is_schema_nc=in_schema_nc)
+            if correct_attid != o.attid:
+                wrong_attids.add(o.attid)
 
-        return (set_att, list_attid)
+        return (set_att, list_attid, wrong_attids)
 
 
     def fix_metadata(self, dn, attr):
@@ -990,7 +1016,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
 
             if not self.confirm_all('Fix %s on %s by setting originating_invocation_id on some elements to our invocationID %s?'
                                     % (attr, dn, self.samdb.get_invocation_id()), 'fix_replmetadata_zero_invocationid'):
-                self.report('Not fixing %s on %s\n' % (attr, dn))
+                self.report('Not fixing zero originating_invocation_id in %s on %s\n' % (attr, dn))
                 return
 
             nmsg = ldb.Message()
@@ -1015,30 +1041,100 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                 return
 
 
-    def err_replmetadata_unsorted_attid(self, dn, attr, repl_meta_data):
+    def err_replmetadata_incorrect_attid(self, dn, attr, repl_meta_data, wrong_attids):
         repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
                           str(repl_meta_data))
+        fix = False
+
+        set_att = set()
+        remove_attid = set()
+        hash_att = {}
+
+        in_schema_nc = dn.is_child_of(self.schema_dn)
+
         ctr = repl.ctr
-        found = False
+        # Sort the array, except for the last element.  This strange
+        # construction, creating a new list, due to bugs in samba's
+        # array handling in IDL generated objects.
+        ctr.array = sorted(ctr.array[:-1], key=lambda o: o.attid) + [ctr.array[-1]]
+        # Now walk it in reverse, so we see the low (and so incorrect,
+        # the correct values are above 0x80000000) values first and
+        # remove the 'second' value we see.
+        for o in reversed(ctr.array):
+            print "%s: 0x%08x" % (dn, o.attid)
+            att = self.samdb_schema.get_lDAPDisplayName_by_attid(o.attid)
+            if att.lower() in set_att:
+                self.report('ERROR: duplicate attributeID values for %s in %s on %s\n' % (att, attr, dn))
+                if not self.confirm_all('Fix %s on %s by removing the duplicate value 0x%08x for %s (keeping 0x%08x)?'
+                                        % (attr, dn, o.attid, att, hash_att[att].attid),
+                                        'fix_replmetadata_duplicate_attid'):
+                    self.report('Not fixing duplicate value 0x%08x for %s in %s on %s\n'
+                                % (o.attid, att, attr, dn))
+                    return
+                fix = True
+                remove_attid.add(o.attid)
+                # We want to set the metadata for the most recent
+                # update to have been applied locally, that is the metadata
+                # matching the (eg string) value in the attribute
+                if o.local_usn > hash_att[att].local_usn:
+                    # This is always what we would have sent over DRS,
+                    # because the DRS server will have sent the
+                    # msDS-IntID, but with the values from both
+                    # attribute entries.
+                    hash_att[att].version = o.version
+                    hash_att[att].originating_change_time = o.originating_change_time
+                    hash_att[att].originating_invocation_id = o.originating_invocation_id
+                    hash_att[att].originating_usn = o.originating_usn
+                    hash_att[att].local_usn = o.local_usn
+
+                # Do not re-add the value to the set or overwrite the hash value
+                continue
 
-        self.report('ERROR: unsorted attributeID values in %s on %s\n' % (attr, dn))
-        if not self.confirm_all('Fix %s on %s by sorting the attribute list?'
-                                % (attr, dn), 'fix_replmetadata_unsorted_attid'):
-            self.report('Not fixing %s on %s\n' % (attr, dn))
-            return
+            hash_att[att] = o
+            set_att.add(att.lower())
+
+        # Generate a real list we can sort on properly
+        new_list = [o for o in ctr.array if o.attid not in remove_attid]
+
+        if (len(wrong_attids) > 0):
+            for o in new_list:
+                if o.attid in wrong_attids:
+                    att = self.samdb_schema.get_lDAPDisplayName_by_attid(o.attid)
+                    correct_attid = self.samdb_schema.get_attid_from_lDAPDisplayName(att, is_schema_nc=in_schema_nc)
+                    self.report('ERROR: incorrect attributeID values in %s on %s\n' % (attr, dn))
+                    if not self.confirm_all('Fix %s on %s by replacing incorrect value 0x%08x for %s (new 0x%08x)?'
+                                            % (attr, dn, o.attid, att, hash_att[att].attid), 'fix_replmetadata_wrong_attid'):
+                        self.report('Not fixing incorrect value 0x%08x with 0x%08x for %s in %s on %s\n'
+                                    % (o.attid, correct_attid, att, attr, dn))
+                        return
+                    fix = True
+                    o.attid = correct_attid
+            if fix:
+                # Sort the array, except for the last element (we changed
+                # the value so must re-sort)
+                new_list[:-1] = sorted(new_list[:-1], key=lambda o: o.attid)
+
+        # If we did not already need to fix it, then ask about sorting
+        if not fix:
+            self.report('ERROR: unsorted attributeID values in %s on %s\n' % (attr, dn))
+            if not self.confirm_all('Fix %s on %s by sorting the attribute list?'
+                                    % (attr, dn), 'fix_replmetadata_unsorted_attid'):
+                self.report('Not fixing %s on %s\n' % (attr, dn))
+                return
 
-        # Sort the array, except for the last element
-        ctr.array[:-1] = sorted(ctr.array[:-1], key=lambda o: o.attid)
+            # The actual sort done is done at the top of the function
 
+        ctr.count = len(new_list)
+        ctr.array = new_list
         replBlob = ndr_pack(repl)
 
         nmsg = ldb.Message()
         nmsg.dn = dn
         nmsg[attr] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, attr)
         if self.do_modify(nmsg, ["local_oid:%s:0" % dsdb.DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA,
-                                 "local_oid:1.3.6.1.4.1.7165.4.3.14:0",
-                                 "local_oid:1.3.6.1.4.1.7165.4.3.25:0"],
-                          "Failed to fix attribute %s" % attr):
+                             "local_oid:1.3.6.1.4.1.7165.4.3.14:0",
+                             "local_oid:1.3.6.1.4.1.7165.4.3.25:0"],
+                      "Failed to fix attribute %s" % attr):
             self.report("Fixed attribute '%s' of '%s'\n" % (attr, dn))
 
 
@@ -1230,15 +1326,19 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                     # based on what other attributes we see.
 
                 try:
-                    (set_attrs_from_md, list_attid_from_md) = self.process_metadata(obj[attrname])
+                    (set_attrs_from_md, list_attid_from_md, wrong_attids) \
+                        = self.process_metadata(dn, obj[attrname])
                 except KeyError:
                     error_count += 1
                     self.err_replmetadata_unknown_attid(dn, attrname, obj[attrname])
                     continue
 
-                if sorted(list_attid_from_md[:-1]) != list_attid_from_md[:-1]:
-                    error_count += 1
-                    self.err_replmetadata_unsorted_attid(dn, attrname, obj[attrname])
+                if len(set_attrs_from_md) < len(list_attid_from_md) \
+                   or len(wrong_attids) > 0 \
+                   or sorted(list_attid_from_md[:-1]) != list_attid_from_md[:-1]:
+                    error_count +=1
+                    self.err_replmetadata_incorrect_attid(dn, attrname, obj[attrname], wrong_attids)
+
                 else:
                     # Here we check that the first attid is 0
                     # (objectClass) and that the last on is the RDN
@@ -1286,8 +1386,20 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                 continue
 
             if str(attrname).lower() == 'objectclass':
-                normalised = self.samdb.dsdb_normalise_attributes(self.samdb_schema, attrname, list(obj[attrname]))
-                if list(normalised) != list(obj[attrname]):
+                normalised = self.samdb.dsdb_normalise_attributes(self.samdb_schema, attrname, obj[attrname])
+                # Do not consider the attribute incorrect if:
+                #  - The sorted (alphabetically) list is the same, inclding case
+                #  - The first and last elements are the same
+                #
+                # This avoids triggering an error due to
+                # non-determinism in the sort routine in (at least)
+                # 4.3 and earlier, and the fact that any AUX classes
+                # in these attributes are also not sorted when
+                # imported from Windows (they are just in the reverse
+                # order of last set)
+                if sorted(normalised) != sorted(obj[attrname]) \
+                   or normalised[0] != obj[attrname][0] \
+                   or normalised[-1] != obj[attrname][-1]:
                     self.err_normalise_mismatch_replace(dn, attrname, list(obj[attrname]))
                     error_count += 1
                 continue
@@ -1353,14 +1465,22 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                 # it's some form of DN, do specialised checking on those
                 error_count += self.check_dn(obj, attrname, syntax_oid)
 
+            values = set()
             # check for incorrectly normalised attributes
             for val in obj[attrname]:
+                values.add(str(val))
+
                 normalised = self.samdb.dsdb_normalise_attributes(self.samdb_schema, attrname, [val])
                 if len(normalised) != 1 or normalised[0] != val:
                     self.err_normalise_mismatch(dn, attrname, obj[attrname])
                     error_count += 1
                     break
 
+            if len(obj[attrname]) != len(values):
+                   self.err_duplicate_values(dn, attrname, obj[attrname], list(values))
+                   error_count += 1
+                   break
+
             if str(attrname).lower() == "instancetype":
                 calculated_instancetype = self.calculate_instancetype(dn)
                 if len(obj["instanceType"]) != 1 or obj["instanceType"][0] != str(calculated_instancetype):
diff --git a/python/samba/join.py b/python/samba/join.py
index f71f3de..6df337c 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -54,12 +54,13 @@ class dc_join(object):
     def __init__(ctx, logger=None, server=None, creds=None, lp=None, site=None,
                  netbios_name=None, targetdir=None, domain=None,
                  machinepass=None, use_ntvfs=False, dns_backend=None,
-                 promote_existing=False):
+                 promote_existing=False, clone_only=False):
+        ctx.clone_only=clone_only
+
         ctx.logger = logger
         ctx.creds = creds
         ctx.lp = lp
         ctx.site = site
-        ctx.netbios_name = netbios_name
         ctx.targetdir = targetdir
         ctx.use_ntvfs = use_ntvfs
 
@@ -89,8 +90,6 @@ class dc_join(object):
             raise DCJoinException(estr)
 
 
-        ctx.myname = netbios_name
-        ctx.samname = "%s$" % ctx.myname
         ctx.base_dn = str(ctx.samdb.get_default_basedn())
         ctx.root_dn = str(ctx.samdb.get_root_basedn())
         ctx.schema_dn = str(ctx.samdb.get_schema_basedn())
@@ -110,17 +109,34 @@ class dc_join(object):
         else:
             ctx.acct_pass = samba.generate_random_password(32, 40)
 
-        # work out the DNs of all the objects we will be adding
-        ctx.server_dn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (ctx.myname, ctx.site, ctx.config_dn)
-        ctx.ntds_dn = "CN=NTDS Settings,%s" % ctx.server_dn
-        topology_base = "CN=Topology,CN=Domain System Volume,CN=DFSR-GlobalSettings,CN=System,%s" % ctx.base_dn
-        if ctx.dn_exists(topology_base):
-            ctx.topology_dn = "CN=%s,%s" % (ctx.myname, topology_base)
+        ctx.dnsdomain = ctx.samdb.domain_dns_name()
+        if clone_only:
+            # As we don't want to create or delete these DNs, we set them to None
+            ctx.server_dn = None
+            ctx.ntds_dn = None
+            ctx.acct_dn = None
+            ctx.myname = ctx.server.split('.')[0]
+            ctx.ntds_guid = None
         else:
-            ctx.topology_dn = None
+            # work out the DNs of all the objects we will be adding
+            ctx.myname = netbios_name
+            ctx.samname = "%s$" % ctx.myname
+            ctx.server_dn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (ctx.myname, ctx.site, ctx.config_dn)
+            ctx.ntds_dn = "CN=NTDS Settings,%s" % ctx.server_dn
+            ctx.acct_dn = "CN=%s,OU=Domain Controllers,%s" % (ctx.myname, ctx.base_dn)
+            ctx.dnshostname = "%s.%s" % (ctx.myname.lower(), ctx.dnsdomain)
+            ctx.dnsforest = ctx.samdb.forest_dns_name()
+
+            topology_base = "CN=Topology,CN=Domain System Volume,CN=DFSR-GlobalSettings,CN=System,%s" % ctx.base_dn
+            if ctx.dn_exists(topology_base):
+                ctx.topology_dn = "CN=%s,%s" % (ctx.myname, topology_base)
+            else:
+                ctx.topology_dn = None
+
+            ctx.SPNs = [ "HOST/%s" % ctx.myname,
+                         "HOST/%s" % ctx.dnshostname,
+                         "GC/%s/%s" % (ctx.dnshostname, ctx.dnsforest) ]
 
-        ctx.dnsdomain = ctx.samdb.domain_dns_name()
-        ctx.dnsforest = ctx.samdb.forest_dns_name()
         ctx.domaindns_zone = 'DC=DomainDnsZones,%s' % ctx.base_dn
         ctx.forestdns_zone = 'DC=ForestDnsZones,%s' % ctx.root_dn
 
@@ -137,18 +153,10 @@ class dc_join(object):
             else:
                 ctx.dns_backend = dns_backend
 
-        ctx.dnshostname = "%s.%s" % (ctx.myname.lower(), ctx.dnsdomain)
-
         ctx.realm = ctx.dnsdomain
 
-        ctx.acct_dn = "CN=%s,OU=Domain Controllers,%s" % (ctx.myname, ctx.base_dn)
-
         ctx.tmp_samdb = None
 
-        ctx.SPNs = [ "HOST/%s" % ctx.myname,
-                     "HOST/%s" % ctx.dnshostname,
-                     "GC/%s/%s" % (ctx.dnshostname, ctx.dnsforest) ]
-
         # these elements are optional
         ctx.never_reveal_sid = None
         ctx.reveal_sid = None
@@ -538,28 +546,30 @@ class dc_join(object):
         if ctx.krbtgt_dn:
             ctx.add_krbtgt_account()
 
-        print "Adding %s" % ctx.server_dn
-        rec = {
-            "dn": ctx.server_dn,
-            "objectclass" : "server",
-            # windows uses 50000000 decimal for systemFlags. A windows hex/decimal mixup bug?
-            "systemFlags" : str(samba.dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME |
-                                samba.dsdb.SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE |
-                                samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE),
-            # windows seems to add the dnsHostName later
-            "dnsHostName" : ctx.dnshostname}
-
-        if ctx.acct_dn:
-            rec["serverReference"] = ctx.acct_dn
+        if ctx.server_dn:
+            print "Adding %s" % ctx.server_dn
+            rec = {
+                "dn": ctx.server_dn,
+                "objectclass" : "server",
+                # windows uses 50000000 decimal for systemFlags. A windows hex/decimal mixup bug?
+                "systemFlags" : str(samba.dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME |
+                                    samba.dsdb.SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE |
+                                    samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE),
+                # windows seems to add the dnsHostName later
+                "dnsHostName" : ctx.dnshostname}
+
+            if ctx.acct_dn:
+                rec["serverReference"] = ctx.acct_dn
 
-        ctx.samdb.add(rec)
+            ctx.samdb.add(rec)
 
         if ctx.subdomain:
             # the rest is done after replication
             ctx.ntds_guid = None
             return
 
-        ctx.join_add_ntdsdsa()
+        if ctx.ntds_dn:
+            ctx.join_add_ntdsdsa()
 
         if ctx.connection_dn is not None:
             print "Adding %s" % ctx.connection_dn
@@ -876,15 +886,17 @@ class dc_join(object):
         """Finalise the join, mark us synchronised and setup secrets db."""
 
         # FIXME we shouldn't do this in all cases
+
         # If for some reasons we joined in another site than the one of
         # DC we just replicated from then we don't need to send the updatereplicateref
         # as replication between sites is time based and on the initiative of the
         # requesting DC
-        ctx.logger.info("Sending DsReplicaUpdateRefs for all the replicated partitions")
-        for nc in ctx.nc_list:
-            ctx.send_DsReplicaUpdateRefs(nc)
+        if not ctx.clone_only:
+            ctx.logger.info("Sending DsReplicaUpdateRefs for all the replicated partitions")
+            for nc in ctx.nc_list:
+                ctx.send_DsReplicaUpdateRefs(nc)
 
-        if ctx.RODC:
+        if not ctx.clone_only and ctx.RODC:
             print "Setting RODC invocationId"
             ctx.local_samdb.set_invocation_id(str(ctx.invocation_id))
             ctx.local_samdb.set_opaque_integer("domainFunctionality",
@@ -914,11 +926,18 @@ class dc_join(object):
         m = ldb.Message()
         m.dn = ldb.Dn(ctx.local_samdb, '@ROOTDSE')
         m["isSynchronized"] = ldb.MessageElement("TRUE", ldb.FLAG_MOD_REPLACE, "isSynchronized")
-        m["dsServiceName"] = ldb.MessageElement("<GUID=%s>" % str(ctx.ntds_guid),
+
+        # We want to appear to be the server we just cloned
+        if ctx.clone_only:
+            guid = ctx.samdb.get_ntds_GUID()
+        else:
+            guid = ctx.ntds_guid
+
+        m["dsServiceName"] = ldb.MessageElement("<GUID=%s>" % str(guid),
                                                 ldb.FLAG_MOD_REPLACE, "dsServiceName")
         ctx.local_samdb.modify(m)
 
-        if ctx.subdomain:
+        if ctx.clone_only or ctx.subdomain:
             return
 
         secrets_ldb = Ldb(ctx.paths.secrets, session_info=system_session(), lp=ctx.lp)
@@ -1064,23 +1083,26 @@ class dc_join(object):
                 ctx.full_nc_list += [ctx.domaindns_zone]
                 ctx.full_nc_list += [ctx.forestdns_zone]
 
-        if ctx.promote_existing:
-            ctx.promote_possible()
-        else:
-            ctx.cleanup_old_join()
+        if not ctx.clone_only:
+            if ctx.promote_existing:
+                ctx.promote_possible()
+            else:
+                ctx.cleanup_old_join()
 
         try:
-            ctx.join_add_objects()
+            if not ctx.clone_only:
+                ctx.join_add_objects()
             ctx.join_provision()
             ctx.join_replicate()
-            if ctx.subdomain:
+            if (not ctx.clone_only and ctx.subdomain):
                 ctx.join_add_objects2()
                 ctx.join_provision_own_domain()
                 ctx.join_setup_trusts()
             ctx.join_finalise()
         except:
             print "Join failed - cleaning up"
-            ctx.cleanup_old_join()
+            if not ctx.clone_only:
+                ctx.cleanup_old_join()
             raise
 
 
@@ -1170,6 +1192,30 @@ def join_DC(logger=None, server=None, creds=None, lp=None, site=None, netbios_na
     ctx.do_join()
     logger.info("Joined domain %s (SID %s) as a DC" % (ctx.domain_name, ctx.domsid))
 
+def join_clone(logger=None, server=None, creds=None, lp=None,
+               targetdir=None, domain=None, include_secrets=False):
+    """Join as a DC."""
+    ctx = dc_join(logger, server, creds, lp, site=None, netbios_name=None, targetdir=targetdir, domain=domain,
+                  machinepass=None, use_ntvfs=False, dns_backend="NONE", promote_existing=False, clone_only=True)
+
+    lp.set("workgroup", ctx.domain_name)
+    logger.info("workgroup is %s" % ctx.domain_name)
+
+    lp.set("realm", ctx.realm)
+    logger.info("realm is %s" % ctx.realm)
+
+    ctx.replica_flags = (drsuapi.DRSUAPI_DRS_WRIT_REP |
+                         drsuapi.DRSUAPI_DRS_INIT_SYNC |
+                         drsuapi.DRSUAPI_DRS_PER_SYNC |
+                         drsuapi.DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS |
+                         drsuapi.DRSUAPI_DRS_NEVER_SYNCED)
+    if not include_secrets:
+        ctx.replica_flags |= drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING
+    ctx.domain_replica_flags = ctx.replica_flags
+
+    ctx.do_join()
+    logger.info("Cloned domain %s (SID %s)" % (ctx.domain_name, ctx.domsid))
+
 def join_subdomain(logger=None, server=None, creds=None, lp=None, site=None,
         netbios_name=None, targetdir=None, parent_domain=None, dnsdomain=None,
         netbios_domain=None, machinepass=None, adminpass=None, use_ntvfs=False,
diff --git a/python/samba/kcc/__init__.py b/python/samba/kcc/__init__.py
index 46a25ce..c3e92b7 100644
--- a/python/samba/kcc/__init__.py
+++ b/python/samba/kcc/__init__.py
@@ -165,11 +165,12 @@ class KCC(object):
             if transport.name == 'IP':
                 self.ip_transport = transport
             elif transport.name == 'SMTP':
-                logger.info("Samba KCC is ignoring the obsolete SMTP transport.")
+                logger.debug("Samba KCC is ignoring the obsolete "
+                             "SMTP transport.")
 
             else:
-                logger.warning("Samba KCC does not support the transport called %r."
-                               % (transport.name,))
+                logger.warning("Samba KCC does not support the transport "
+                               "called %r." % (transport.name,))
 
         if self.ip_transport is None:
             raise KCCError("there doesn't seem to be an IP transport")
@@ -261,14 +262,15 @@ class KCC(object):
         :return: None
         :raise: KCCError if DSA can't be found
         """
-        dn = ldb.Dn(self.samdb, "<GUID=%s>" % self.samdb.get_ntds_GUID())
+        dn_query = "<GUID=%s>" % self.samdb.get_ntds_GUID()
+        dn = ldb.Dn(self.samdb, dn_query)
         try:
             res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE,
                                     attrs=["objectGUID"])
         except ldb.LdbError, (enum, estr):
-            logger.warning("Search for %s failed: %s.  This typically happens"
-                           " in --importldif mode due to lack of module"
-                           " support.", dn, estr)
+            DEBUG_FN("Search for dn '%s' [from %s] failed: %s. "
+                     "This typically happens in --importldif mode due "
+                     "to lack of module support." % (dn, dn_query, estr))
             try:
                 # We work around the failure above by looking at the
                 # dsServiceName that was put in the fake rootdse by
@@ -305,7 +307,7 @@ class KCC(object):
                                     " it must be RODC.\n"
                                     "Let's add it, because my_dsa is special!"
                                     "\n(likewise for self.dsa_by_guid)" %
-                                    self.my_dsas_dnstr)
+                                    self.my_dsa_dnstr)
 
             self.dsa_by_dnstr[self.my_dsa_dnstr] = self.my_dsa
             self.dsa_by_guid[str(self.my_dsa.dsa_guid)] = self.my_dsa
@@ -432,19 +434,17 @@ class KCC(object):
         # that became active during this run.
         pass
 
-    def remove_unneeded_ntdsconn(self, all_connected):
-        """Remove unneeded NTDS Connections once topology is calculated
+    def _ensure_connections_are_loaded(self, connections):
+        """Load or fake-load NTDSConnections lacking GUIDs
 
-        Based on MS-ADTS 6.2.2.4 Removing Unnecessary Connections
+        New connections don't have GUIDs and created times which are
+        needed for sorting. If we're in read-only mode, we make fake
+        GUIDs, otherwise we ask SamDB to do it for us.
 
-        :param all_connected: indicates whether all sites are connected
+        :param connections: an iterable of NTDSConnection objects.
         :return: None
         """
-        mydsa = self.my_dsa
-
-        # New connections won't have GUIDs which are needed for
-        # sorting. Add them.
-        for cn_conn in mydsa.connect_table.values():
+        for cn_conn in connections:
             if cn_conn.guid is None:
                 if self.readonly:
                     cn_conn.guid = misc.GUID(str(uuid.uuid4()))
@@ -452,135 +452,139 @@ class KCC(object):
                 else:
                     cn_conn.load_connection(self.samdb)
 
-        for cn_conn in mydsa.connect_table.values():
+    def _mark_broken_ntdsconn(self):
+        """Find NTDS Connections that lack a remote
+
+        I'm not sure how they appear. Let's be rid of them by marking
+        them with the to_be_deleted attribute.
 
+        :return: None
+        """
+        for cn_conn in self.my_dsa.connect_table.values():
             s_dnstr = cn_conn.get_from_dnstr()
             if s_dnstr is None:
+                DEBUG_FN("%s has phantom connection %s" % (self.my_dsa,
+                                                           cn_conn))
                 cn_conn.to_be_deleted = True
-                continue
 
-            #XXX should an RODC be regarded as same site
-            same_site = s_dnstr in self.my_site.dsa_table
-
-            # Given an nTDSConnection object cn, if the DC with the
-            # nTDSDSA object dc that is the parent object of cn and
-            # the DC with the nTDSDA object referenced by cn!fromServer
-            # are in the same site, the KCC on dc deletes cn if all of
-            # the following are true:
-            #
-            # Bit NTDSCONN_OPT_IS_GENERATED is clear in cn!options.
-            #
-            # No site settings object s exists for the local DC's site, or
-            # bit NTDSSETTINGS_OPT_IS_TOPL_CLEANUP_DISABLED is clear in
-            # s!options.
-            #
-            # Another nTDSConnection object cn2 exists such that cn and
-            # cn2 have the same parent object, cn!fromServer = cn2!fromServer,
-            # and either
-            #
-            #     cn!whenCreated < cn2!whenCreated
-            #
-            #     cn!whenCreated = cn2!whenCreated and
-            #     cn!objectGUID < cn2!objectGUID
-            #
-            # Bit NTDSCONN_OPT_RODC_TOPOLOGY is clear in cn!options
-            if same_site:
-                if not cn_conn.is_generated():
-                    continue
-
-                if self.my_site.is_cleanup_ntdsconn_disabled():
-                    continue
-
-                # Loop thru connections looking for a duplicate that
-                # fulfills the previous criteria
-                lesser = False
-                packed_guid = ndr_pack(cn_conn.guid)
-                for cn2_conn in mydsa.connect_table.values():
-                    if cn2_conn is cn_conn:
-                        continue
+    def _mark_unneeded_local_ntdsconn(self):
+        """Find unneeded intrasite NTDS Connections for removal
 
-                    s2_dnstr = cn2_conn.get_from_dnstr()
+        Based on MS-ADTS 6.2.2.4 Removing Unnecessary Connections.
+        Every DC removes its own unnecessary intrasite connections.
+        This function tags them with the to_be_deleted attribute.
 
-                    # If the NTDS Connections has a different
-                    # fromServer field then no match
-                    if s2_dnstr != s_dnstr:
-                        continue
+        :return: None
+        """
+        # XXX should an RODC be regarded as same site? It isn't part
+        # of the intrasite ring.
 
-                    lesser = (cn_conn.whenCreated < cn2_conn.whenCreated or
-                              (cn_conn.whenCreated == cn2_conn.whenCreated and
-                               packed_guid < ndr_pack(cn2_conn.guid)))
+        if self.my_site.is_cleanup_ntdsconn_disabled():
+            DEBUG_FN("not doing ntdsconn cleanup for site %s, "
+                     "because it is disabled" % self.my_site)
+            return
 
-                    if lesser:
-                        break
+        mydsa = self.my_dsa
 
-                if lesser and not cn_conn.is_rodc_topology():
-                    cn_conn.to_be_deleted = True
+        self._ensure_connections_are_loaded(mydsa.connect_table.values())
 
-            # Given an nTDSConnection object cn, if the DC with the nTDSDSA
-            # object dc that is the parent object of cn and the DC with
-            # the nTDSDSA object referenced by cn!fromServer are in
-            # different sites, a KCC acting as an ISTG in dc's site
-            # deletes cn if all of the following are true:
-            #
-            #     Bit NTDSCONN_OPT_IS_GENERATED is clear in cn!options.
-            #
-            #     cn!fromServer references an nTDSDSA object for a DC
-            #     in a site other than the local DC's site.
-            #
-            #     The keepConnections sequence returned by
-            #     CreateIntersiteConnections() does not contain
-            #     cn!objectGUID, or cn is "superseded by" (see below)
-            #     another nTDSConnection cn2 and keepConnections
-            #     contains cn2!objectGUID.
-            #
-            #     The return value of CreateIntersiteConnections()
-            #     was true.
-            #
-            #     Bit NTDSCONN_OPT_RODC_TOPOLOGY is clear in
-            #     cn!options
-            #
-            else:  # different site
+        local_connections = []
 
-                if not mydsa.is_istg():
-                    continue
+        for cn_conn in mydsa.connect_table.values():
+            s_dnstr = cn_conn.get_from_dnstr()
+            if s_dnstr in self.my_site.dsa_table:
+                removable = not (cn_conn.is_generated() or
+                                 cn_conn.is_rodc_topology())
+                packed_guid = ndr_pack(cn_conn.guid)
+                local_connections.append((cn_conn, s_dnstr,
+                                          packed_guid, removable))
+
+        for a, b in itertools.permutations(local_connections, 2):
+            cn_conn, s_dnstr, packed_guid, removable = a
+            cn_conn2, s_dnstr2, packed_guid2, removable2 = b
+            if (removable and
+                s_dnstr == s_dnstr2 and
+                cn_conn.whenCreated < cn_conn2.whenCreated or
+                (cn_conn.whenCreated == cn_conn2.whenCreated and
+                 packed_guid < packed_guid2)):
+                cn_conn.to_be_deleted = True
 
-                if not cn_conn.is_generated():
-                    continue
+    def _mark_unneeded_intersite_ntdsconn(self):
+        """find unneeded intersite NTDS Connections for removal
 
-                # TODO
-                # We are directly using this connection in intersite or
-                # we are using a connection which can supersede this one.
-                #
-                # MS-ADTS 6.2.2.4 - Removing Unnecessary Connections does not
-                # appear to be correct.
-                #
-                # 1. cn!fromServer and cn!parent appear inconsistent with
-                #    no cn2
-                # 2. The repsFrom do not imply each other
-                #
-                if cn_conn in self.kept_connections:  # and not_superceded:
-                    continue
+        Based on MS-ADTS 6.2.2.4 Removing Unnecessary Connections. The
+        intersite topology generator removes links for all DCs in its
+        site. Here we just tag them with the to_be_deleted attribute.
 
-                # This is the result of create_intersite_connections
-                if not all_connected:
-                    continue
+        :return: None
+        """
+        # Find the intersite connections
+        local_dsas = self.my_site.dsa_table
+        connections_and_dsas = []
+        for dsa in local_dsas.values():
+            for cn in dsa.connect_table.values():
+                s_dnstr = cn.get_from_dnstr()
+                if s_dnstr not in local_dsas:
+                    from_dsa = self.get_dsa(s_dnstr)
+                    connections_and_dsas.append((cn, dsa, from_dsa))
+
+        self._ensure_connections_are_loaded(x[0] for x in connections_and_dsas)
+        for cn, to_dsa, from_dsa in connections_and_dsas:
+            if not cn.is_generated() or cn.is_rodc_topology():
+                continue
 
-                if not cn_conn.is_rodc_topology():
-                    cn_conn.to_be_deleted = True
+            # If the connection is in the kept_connections list, we
+            # only remove it if an endpoint seems down.
+            if (cn in self.kept_connections and
+                not (self.is_bridgehead_failed(to_dsa, True) or
+                     self.is_bridgehead_failed(from_dsa, True))):
+                continue
 
-        if mydsa.is_ro() or self.readonly:
-            for connect in mydsa.connect_table.values():
+            # this one is broken and might be superseded by another.
+            # But which other? Let's just say another link to the same
+            # site can supersede.
+            from_dnstr = from_dsa.dsa_dnstr
+            for site in self.site_table.values():
+                if from_dnstr in site.rw_dsa_table:
+                    for cn2, to_dsa2, from_dsa2 in connections_and_dsas:
+                        if (cn is not cn2 and
+                            from_dsa2 in site.rw_dsa_table):
+                            cn.to_be_deleted = True
+
+    def _commit_changes(self, dsa):
+        if dsa.is_ro() or self.readonly:
+            for connect in dsa.connect_table.values():
                 if connect.to_be_deleted:
-                    DEBUG_FN("TO BE DELETED:\n%s" % connect)
+                    logger.info("TO BE DELETED:\n%s" % connect)
                 if connect.to_be_added:
-                    DEBUG_FN("TO BE ADDED:\n%s" % connect)
+                    logger.info("TO BE ADDED:\n%s" % connect)
+                if connect.to_be_modified:
+                    logger.info("TO BE MODIFIED:\n%s" % connect)
 
             # Peform deletion from our tables but perform
             # no database modification
-            mydsa.commit_connections(self.samdb, ro=True)
+            dsa.commit_connections(self.samdb, ro=True)
         else:
             # Commit any modified connections
-            mydsa.commit_connections(self.samdb)
+            dsa.commit_connections(self.samdb)
+
+    def remove_unneeded_ntdsconn(self, all_connected):
+        """Remove unneeded NTDS Connections once topology is calculated
+
+        Based on MS-ADTS 6.2.2.4 Removing Unnecessary Connections
+
+        :param all_connected: indicates whether all sites are connected
+        :return: None
+        """
+        self._mark_broken_ntdsconn()
+        self._mark_unneeded_local_ntdsconn()
+        # if we are not the istg, we're done!
+        # if we are the istg, but all_connected is False, we also do nothing.
+        if self.my_dsa.is_istg() and all_connected:
+            self._mark_unneeded_intersite_ntdsconn()
+
+        for dsa in self.my_site.dsa_table.values():
+            self._commit_changes(dsa)
 
     def modify_repsFrom(self, n_rep, t_repsFrom, s_rep, s_dsa, cn_conn):
         """Update an repsFrom object if required.
@@ -797,14 +801,12 @@ class KCC(object):
         :param cn_conn: NTDS Connection
         :return: source DSA or None
         """
-        #XXX different conditions for "implies" than MS-ADTS 6.2.2
+        # XXX different conditions for "implies" than MS-ADTS 6.2.2
+        # preamble.
 
-        # NTDS Connection must satisfy all the following criteria
-        # to imply a repsFrom tuple is needed:
-        #
-        #    cn!enabledConnection = true.
-        #    cn!options does not contain NTDSCONN_OPT_RODC_TOPOLOGY.
-        #    cn!fromServer references an nTDSDSA object.
+        # It boils down to: we want an enabled, non-FRS connections to
+        # a valid remote DSA with a non-RO replica corresponding to
+        # n_rep.
 
         if not cn_conn.is_enabled() or cn_conn.is_rodc_topology():
             return None
@@ -816,39 +818,11 @@ class KCC(object):
         if s_dsa is None:
             return None
 
-        # To imply a repsFrom tuple is needed, each of these
-        # must be True:
-        #
-        #     An NC replica of the NC "is present" on the DC to
-        #     which the nTDSDSA object referenced by cn!fromServer
-        #     corresponds.
-        #
-        #     An NC replica of the NC "should be present" on
-        #     the local DC
         s_rep = s_dsa.get_current_replica(n_rep.nc_dnstr)
 
-        if s_rep is None or not s_rep.is_present():
-            return None
-
-        # To imply a repsFrom tuple is needed, each of these
-        # must be True:
-        #
-        #     The NC replica on the DC referenced by cn!fromServer is
-        #     a writable replica or the NC replica that "should be
-        #     present" on the local DC is a partial replica.
-        #
-        #     The NC is not a domain NC, the NC replica that
-        #     "should be present" on the local DC is a partial
-        #     replica, cn!transportType has no value, or
-        #     cn!transportType has an RDN of CN=IP.
-        #
-        implied = (not s_rep.is_ro() or n_rep.is_partial()) and \
-                  (not n_rep.is_domain() or
-                   n_rep.is_partial() or
-                   cn_conn.transport_dnstr is None or
-                   cn_conn.transport_dnstr.find("CN=IP") == 0)
-
-        if implied:
+        if (s_rep is not None and
+            s_rep.is_present() and
+            (not s_rep.is_ro() or n_rep.is_partial())):
             return s_dsa
         return None
 
@@ -1106,14 +1080,14 @@ class KCC(object):
 
         bhs = self.get_all_bridgeheads(site, part, transport,
                                        partial_ok, detect_failed)
-        if len(bhs) == 0:
-            debug.DEBUG_MAGENTA("get_bridgehead:\n\tsitedn=%s\n\tbhdn=None" %
+        if not bhs:
+            debug.DEBUG_MAGENTA("get_bridgehead FAILED:\nsitedn = %s" %
                                 site.site_dnstr)
             return None
-        else:
-            debug.DEBUG_GREEN("get_bridgehead:\n\tsitedn=%s\n\tbhdn=%s" %
-                              (site.site_dnstr, bhs[0].dsa_dnstr))
-            return bhs[0]
+
+        debug.DEBUG_GREEN("get_bridgehead:\n\tsitedn = %s\n\tbhdn = %s" %
+                          (site.site_dnstr, bhs[0].dsa_dnstr))
+        return bhs[0]
 
     def get_all_bridgeheads(self, site, part, transport,
                             partial_ok, detect_failed):
@@ -1141,7 +1115,6 @@ class KCC(object):
                            "non-IP transport! %r"
                            % (transport.name,))
 
-        DEBUG_FN("get_all_bridgeheads")
         DEBUG_FN(site.rw_dsa_table)
         for dsa in site.rw_dsa_table.values():
 
@@ -1189,7 +1162,7 @@ class KCC(object):
                 DEBUG("bridgehead is failed")
                 continue
 
-            DEBUG_FN("get_all_bridgeheads: dsadn=%s" % dsa.dsa_dnstr)
+            DEBUG_FN("found a bridgehead: %s" % dsa.dsa_dnstr)
             bhs.append(dsa)
 
         # IF bit NTDSSETTINGS_OPT_IS_RAND_BH_SELECTION_DISABLED is set in
@@ -1490,7 +1463,10 @@ class KCC(object):
             # cn!options = opt, cn!transportType is a reference to t,
             # cn!fromServer is a reference to rbh, and cn!schedule = sch
             DEBUG_FN("new connection, KCC dsa: %s" % self.my_dsa.dsa_dnstr)
-            cn = lbh.new_connection(opt, 0, transport,
+            system_flags = (dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME |
+                            dsdb.SYSTEM_FLAG_CONFIG_ALLOW_MOVE)
+
+            cn = lbh.new_connection(opt, system_flags, transport,
                                     rbh.dsa_dnstr, link_sched)
 
             # Display any added connection
@@ -1525,7 +1501,7 @@ class KCC(object):
         # here, but using vertex seems to make more sense. That is,
         # the docs want this:
         #
-        #bh = self.get_bridgehead(vertex.site, vertex.part, transport,
+        #bh = self.get_bridgehead(local_vertex.site, vertex.part, transport,
         #                         local_vertex.is_black(), detect_failed)
         #
         # TODO WHY?????
@@ -1596,7 +1572,7 @@ class KCC(object):
 
         for v in graph.vertices:
             v.color_vertex()
-            if self.add_transports(v, my_vertex, graph, False):
+            if self.add_transports(v, my_vertex, graph, detect_failed):
                 found_failed = True
 
         # No NC replicas for this NC in the site of the local DC,
@@ -2159,7 +2135,6 @@ class KCC(object):
                                   if not self.get_dsa(x).is_ro())
             rw_dot_edges = [(a, b) for a, b in dot_edges if
                             a in rw_dot_vertices and b in rw_dot_vertices]
-            print rw_dot_edges, rw_dot_vertices
             rw_verify_properties = ('connected',
                                     'directed_double_ring_or_small')
             verify_and_dot('intrasite_rw_pre_ntdscon', rw_dot_edges,
@@ -2230,7 +2205,7 @@ class KCC(object):
             # points to us that satisfies the KCC criteria
 
             if tnode.dsa_dnstr == dc_local.dsa_dnstr:
-                tnode.add_connections_from_edges(dc_local)
+                tnode.add_connections_from_edges(dc_local, self.ip_transport)
 
         if self.verify or do_dot_files:
             dot_edges = []
@@ -2255,7 +2230,6 @@ class KCC(object):
                                   if not self.get_dsa(x).is_ro())
             rw_dot_edges = [(a, b) for a, b in dot_edges if
                             a in rw_dot_vertices and b in rw_dot_vertices]
-            print rw_dot_edges, rw_dot_vertices
             rw_verify_properties = ('connected',
                                     'directed_double_ring_or_small')
             verify_and_dot('intrasite_rw_post_ntdscon', rw_dot_edges,
@@ -2346,20 +2320,7 @@ class KCC(object):
                 self.construct_intrasite_graph(mysite, mydsa, part, True,
                                                False)  # don't detect stale
 
-        if self.readonly:
-            # Display any to be added or modified repsFrom
-            for connect in mydsa.connect_table.values():
-                if connect.to_be_deleted:
-                    logger.info("TO BE DELETED:\n%s" % connect)
-                if connect.to_be_modified:
-                    logger.info("TO BE MODIFIED:\n%s" % connect)
-                if connect.to_be_added:
-                    debug.DEBUG_GREEN("TO BE ADDED:\n%s" % connect)
-
-            mydsa.commit_connections(self.samdb, ro=True)
-        else:
-            # Commit any newly created connections to the samdb
-            mydsa.commit_connections(self.samdb)
+        self._commit_changes(mydsa)
 
     def list_dsas(self):
         """Compile a comprehensive list of DSA DNs
@@ -2385,16 +2346,26 @@ class KCC(object):
                          for dsa in site.dsa_table.values()])
         return dsas
 
-    def load_samdb(self, dburl, lp, creds):
+    def load_samdb(self, dburl, lp, creds, force=False):
         """Load the database using an url, loadparm, and credentials
 
+        If force is False, the samdb won't be reloaded if it already
+        exists.
+
         :param dburl: a database url.
         :param lp: a loadparm object.
         :param creds: a Credentials object.
+        :param force: a boolean indicating whether to overwrite.
+
         """
-        self.samdb = SamDB(url=dburl,
-                           session_info=system_session(),
-                           credentials=creds, lp=lp)
+        if force or self.samdb is None:
+            try:
+                self.samdb = SamDB(url=dburl,
+                                   session_info=system_session(),
+                                   credentials=creds, lp=lp)
+            except ldb.LdbError, (num, msg):
+                raise KCCError("Unable to open sam database %s : %s" %
+                               (dburl, msg))
 
     def plot_all_connections(self, basename, verify_properties=()):
         """Helper function to plot and verify NTDSConnections
@@ -2448,15 +2419,9 @@ class KCC(object):
                determine link availability (boolean, default False)
         :return: 1 on error, 0 otherwise
         """
-        # We may already have a samdb setup if we are
-        # currently importing an ldif for a test run
         if self.samdb is None:
-            try:
-                self.load_samdb(dburl, lp, creds)
-            except ldb.LdbError, (num, msg):
-                logger.error("Unable to open sam database %s : %s" %
-                             (dburl, msg))
-                return 1
+            DEBUG_FN("samdb is None; let's load it from %s" % (dburl,))
+            self.load_samdb(dburl, lp, creds, force=False)
 
         if forced_local_dsa:
             self.samdb.set_ntds_settings_dn("CN=NTDS Settings,%s" %
@@ -2523,7 +2488,9 @@ class KCC(object):
                 for dsa in self.my_site.dsa_table.values():
                     dsa.connect_table = dict((k, v) for k, v in
                                              dsa.connect_table.items()
-                                             if v.is_rodc_topology())
+                                             if v.is_rodc_topology() or
+                                             (v.from_dnstr not in
+                                              self.my_site.dsa_table))
                 self.plot_all_connections('dsa_forgotten_local')
 
             if forget_intersite_links:
@@ -2615,7 +2582,7 @@ class KCC(object):
 
         return 0
 
-    def import_ldif(self, dburl, lp, creds, ldif_file, forced_local_dsa=None):
+    def import_ldif(self, dburl, lp, ldif_file, forced_local_dsa=None):
         """Import relevant objects and attributes from an LDIF file.
 
         The point of this function is to allow a programmer/debugger to
@@ -2628,7 +2595,6 @@ class KCC(object):
 
         :param dburl: path to the temporary abbreviated db to create
         :param lp: a loadparm object.
-        :param cred: a Credentials object.
         :param ldif_file: path to the ldif file to import
         :param forced_local_dsa: perform KCC from this DSA's point of view
         :return: zero on success, 1 on error
diff --git a/python/samba/kcc/kcc_utils.py b/python/samba/kcc/kcc_utils.py
index 3b5b0cc..1e00918 100644
--- a/python/samba/kcc/kcc_utils.py
+++ b/python/samba/kcc/kcc_utils.py
@@ -84,8 +84,8 @@ class NamingContext(object):
                                scope=ldb.SCOPE_BASE, attrs=attrs)
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find naming context (%s) - (%s)" %
-                            (self.nc_dnstr, estr))
+            raise KCCError("Unable to find naming context (%s) - (%s)" %
+                           (self.nc_dnstr, estr))
         msg = res[0]
         if "objectGUID" in msg:
             self.nc_guid = misc.GUID(samdb.schema_format_value("objectGUID",
@@ -314,8 +314,8 @@ class NCReplica(NamingContext):
                                attrs=["repsFrom"])
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find NC for (%s) - (%s)" %
-                            (self.nc_dnstr, estr))
+            raise KCCError("Unable to find NC for (%s) - (%s)" %
+                           (self.nc_dnstr, estr))
 
         msg = res[0]
 
@@ -386,8 +386,8 @@ class NCReplica(NamingContext):
             samdb.modify(m)
 
         except ldb.LdbError, estr:
-            raise Exception("Could not set repsFrom for (%s) - (%s)" %
-                            (self.nc_dnstr, estr))
+            raise KCCError("Could not set repsFrom for (%s) - (%s)" %
+                           (self.nc_dnstr, estr))
 
     def load_replUpToDateVector(self, samdb):
         """Given an NC replica which has been discovered thru the nTDSDSA
@@ -402,8 +402,8 @@ class NCReplica(NamingContext):
                                attrs=["replUpToDateVector"])
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find NC for (%s) - (%s)" %
-                            (self.nc_dnstr, estr))
+            raise KCCError("Unable to find NC for (%s) - (%s)" %
+                           (self.nc_dnstr, estr))
 
         msg = res[0]
 
@@ -436,8 +436,8 @@ class NCReplica(NamingContext):
                                attrs=["fSMORoleOwner"])
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find NC for (%s) - (%s)" %
-                            (self.nc_dnstr, estr))
+            raise KCCError("Unable to find NC for (%s) - (%s)" %
+                           (self.nc_dnstr, estr))
 
         msg = res[0]
 
@@ -568,8 +568,8 @@ class DirectoryServiceAgent(object):
                                attrs=attrs)
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find nTDSDSA for (%s) - (%s)" %
-                            (self.dsa_dnstr, estr))
+            raise KCCError("Unable to find nTDSDSA for (%s) - (%s)" %
+                           (self.dsa_dnstr, estr))
 
         msg = res[0]
         self.dsa_guid = misc.GUID(samdb.schema_format_value("objectGUID",
@@ -629,8 +629,8 @@ class DirectoryServiceAgent(object):
                                attrs=ncattrs)
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find nTDSDSA NCs for (%s) - (%s)" %
-                            (self.dsa_dnstr, estr))
+            raise KCCError("Unable to find nTDSDSA NCs for (%s) - (%s)" %
+                           (self.dsa_dnstr, estr))
 
         # The table of NCs for the dsa we are searching
         tmp_table = {}
@@ -675,7 +675,7 @@ class DirectoryServiceAgent(object):
                     if rep.is_default():
                         self.default_dnstr = dnstr
         else:
-            raise Exception("No nTDSDSA NCs for (%s)" % self.dsa_dnstr)
+            raise KCCError("No nTDSDSA NCs for (%s)" % self.dsa_dnstr)
 
         # Assign our newly built NC replica table to this dsa
         self.current_rep_table = tmp_table
@@ -697,8 +697,8 @@ class DirectoryServiceAgent(object):
                                expression="(objectClass=nTDSConnection)")
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find nTDSConnection for (%s) - (%s)" %
-                            (self.dsa_dnstr, estr))
+            raise KCCError("Unable to find nTDSConnection for (%s) - (%s)" %
+                           (self.dsa_dnstr, estr))
 
         for msg in res:
             dnstr = str(msg.dn)
@@ -769,7 +769,8 @@ class DirectoryServiceAgent(object):
         '''Debug dump string output of connect table'''
         return '\n'.join(str(x) for x in self.connect_table)
 
-    def new_connection(self, options, flags, transport, from_dnstr, sched):
+    def new_connection(self, options, system_flags, transport, from_dnstr,
+                       sched):
         """Set up a new connection for the DSA based on input
         parameters.  Connection will be added to the DSA
         connect_table and will be marked as "to be added" pending
@@ -782,7 +783,7 @@ class DirectoryServiceAgent(object):
         connect.enabled = True
         connect.from_dnstr = from_dnstr
         connect.options = options
-        connect.flags = flags
+        connect.system_flags = system_flags
 
         if transport is not None:
             connect.transport_dnstr = transport.dnstr
@@ -874,8 +875,8 @@ class NTDSConnection(object):
                                attrs=attrs)
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find nTDSConnection for (%s) - (%s)" %
-                            (self.dnstr, estr))
+            raise KCCError("Unable to find nTDSConnection for (%s) - (%s)" %
+                           (self.dnstr, estr))
 
         msg = res[0]
 
@@ -889,10 +890,13 @@ class NTDSConnection(object):
         if "systemFlags" in msg:
             self.system_flags = int(msg["systemFlags"][0])
 
-        if "objectGUID" in msg:
+        try:
             self.guid = \
                 misc.GUID(samdb.schema_format_value("objectGUID",
                                                     msg["objectGUID"][0]))
+        except KeyError:
+            raise KCCError("Unable to find objectGUID in nTDSConnection "
+                           "for (%s)" % (self.dnstr))
 
         if "transportType" in msg:
             dsdn = dsdb_Dn(samdb, msg["transportType"][0])
@@ -921,8 +925,8 @@ class NTDSConnection(object):
                                scope=ldb.SCOPE_BASE, attrs=attrs)
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find transport (%s) - (%s)" %
-                            (tdnstr, estr))
+            raise KCCError("Unable to find transport (%s) - (%s)" %
+                           (tdnstr, estr))
 
         if "objectGUID" in res[0]:
             msg = res[0]
@@ -948,8 +952,8 @@ class NTDSConnection(object):
         try:
             samdb.delete(self.dnstr)
         except ldb.LdbError, (enum, estr):
-            raise Exception("Could not delete nTDSConnection for (%s) - (%s)" %
-                            (self.dnstr, estr))
+            raise KCCError("Could not delete nTDSConnection for (%s) - (%s)" %
+                           (self.dnstr, estr))
 
     def commit_added(self, samdb, ro=False):
         """Local helper routine for commit_connections() which
@@ -973,11 +977,11 @@ class NTDSConnection(object):
 
         except ldb.LdbError, (enum, estr):
             if enum != ldb.ERR_NO_SUCH_OBJECT:
-                raise Exception("Unable to search for (%s) - (%s)" %
-                                (self.dnstr, estr))
+                raise KCCError("Unable to search for (%s) - (%s)" %
+                               (self.dnstr, estr))
         if found:
-            raise Exception("nTDSConnection for (%s) already exists!" %
-                            self.dnstr)
+            raise KCCError("nTDSConnection for (%s) already exists!" %
+                           self.dnstr)
 
         if self.enabled:
             enablestr = "TRUE"
@@ -1017,8 +1021,8 @@ class NTDSConnection(object):
         try:
             samdb.add(m)
         except ldb.LdbError, (enum, estr):
-            raise Exception("Could not add nTDSConnection for (%s) - (%s)" %
-                            (self.dnstr, estr))
+            raise KCCError("Could not add nTDSConnection for (%s) - (%s)" %
+                           (self.dnstr, estr))
 
     def commit_modified(self, samdb, ro=False):
         """Local helper routine for commit_connections() which
@@ -1043,7 +1047,7 @@ class NTDSConnection(object):
             if enum == ldb.ERR_NO_SUCH_OBJECT:
                 raise KCCError("nTDSConnection for (%s) doesn't exist!" %
                                self.dnstr)
-            raise KccError("Unable to search for (%s) - (%s)" %
+            raise KCCError("Unable to search for (%s) - (%s)" %
                            (self.dnstr, estr))
 
         if self.enabled:
@@ -1086,18 +1090,12 @@ class NTDSConnection(object):
         try:
             samdb.modify(m)
         except ldb.LdbError, (enum, estr):
-            raise Exception("Could not modify nTDSConnection for (%s) - (%s)" %
-                            (self.dnstr, estr))
+            raise KCCError("Could not modify nTDSConnection for (%s) - (%s)" %
+                           (self.dnstr, estr))
 
     def set_modified(self, truefalse):
         self.to_be_modified = truefalse
 
-    def set_added(self, truefalse):
-        self.to_be_added = truefalse
-
-    def set_deleted(self, truefalse):
-        self.to_be_deleted = truefalse
-
     def is_schedule_minimum_once_per_week(self):
         """Returns True if our schedule includes at least one
         replication interval within the week.  False otherwise
@@ -1244,9 +1242,8 @@ class Partition(NamingContext):
                                attrs=attrs)
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find partition for (%s) - (%s)" % (
-                            self.partstr, estr))
-
+            raise KCCError("Unable to find partition for (%s) - (%s)" %
+                           (self.partstr, estr))
         msg = res[0]
         for k in msg.keys():
             if k == "dn":
@@ -1385,8 +1382,8 @@ class Site(object):
             self_res = samdb.search(base=self.site_dnstr, scope=ldb.SCOPE_BASE,
                                     attrs=['objectGUID'])
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find site settings for (%s) - (%s)" %
-                            (ssdn, estr))
+            raise KCCError("Unable to find site settings for (%s) - (%s)" %
+                           (ssdn, estr))
 
         msg = res[0]
         if "options" in msg:
@@ -1416,7 +1413,7 @@ class Site(object):
                                scope=ldb.SCOPE_SUBTREE,
                                expression="(objectClass=nTDSDSA)")
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find nTDSDSAs - (%s)" % estr)
+            raise KCCError("Unable to find nTDSDSAs - (%s)" % estr)
 
         for msg in res:
             dnstr = str(msg.dn)
@@ -1611,7 +1608,7 @@ class Site(object):
             samdb.modify(m)
 
         except ldb.LdbError, estr:
-            raise Exception(
+            raise KCCError(
                 "Could not set interSiteTopologyGenerator for (%s) - (%s)" %
                 (ssdn, estr))
         return True
@@ -1722,7 +1719,7 @@ class GraphNode(object):
         for connect in dsa.connect_table.values():
             self.add_edge_from(connect.from_dnstr)
 
-    def add_connections_from_edges(self, dsa):
+    def add_connections_from_edges(self, dsa, transport):
         """For each edge directed to this graph node, ensure there
            is a corresponding nTDSConnection object in the dsa.
         """
@@ -1759,7 +1756,7 @@ class GraphNode(object):
             flags = (dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME |
                      dsdb.SYSTEM_FLAG_CONFIG_ALLOW_MOVE)
 
-            dsa.new_connection(opt, flags, None, edge_dnstr, None)
+            dsa.new_connection(opt, flags, transport, edge_dnstr, None)
 
     def has_sufficient_edges(self):
         '''Return True if we have met the maximum "from edges" criteria'''
@@ -1808,8 +1805,8 @@ class Transport(object):
                                attrs=attrs)
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find Transport for (%s) - (%s)" %
-                            (self.dnstr, estr))
+            raise KCCError("Unable to find Transport for (%s) - (%s)" %
+                           (self.dnstr, estr))
 
         msg = res[0]
         self.guid = misc.GUID(samdb.schema_format_value("objectGUID",
@@ -2068,8 +2065,8 @@ class SiteLink(object):
                                attrs=attrs, controls=['extended_dn:0'])
 
         except ldb.LdbError, (enum, estr):
-            raise Exception("Unable to find SiteLink for (%s) - (%s)" %
-                            (self.dnstr, estr))
+            raise KCCError("Unable to find SiteLink for (%s) - (%s)" %
+                           (self.dnstr, estr))
 
         msg = res[0]
 
diff --git a/python/samba/kcc/ldif_import_export.py b/python/samba/kcc/ldif_import_export.py
index ab7c7a0..5e0f337 100644
--- a/python/samba/kcc/ldif_import_export.py
+++ b/python/samba/kcc/ldif_import_export.py
@@ -70,9 +70,13 @@ def ldif_to_samdb(dburl, lp, ldif_file, forced_local_dsa=None):
 changetype: modify
 replace: dsServiceName
 dsServiceName: CN=NTDS Settings,%s
--
             """ % forced_local_dsa)
 
+        tmpdb.add_ldif("""dn: @MODULES
+ at LIST: rootdse,extended_dn_in,extended_dn_out_ldb,objectguid
+-
+""")
+
     except Exception, estr:
         tmpdb.transaction_cancel()
         raise LdifError("Failed to import %s: %s" % (ldif_file, estr))
@@ -82,9 +86,7 @@ dsServiceName: CN=NTDS Settings,%s
     # We have an abbreviated list of options here because we have built
     # an abbreviated database.  We use the rootdse and extended-dn
     # modules only during this re-open
-    samdb = SamDB(url=dburl, session_info=system_session(), lp=lp,
-                  options=["modules:rootdse,extended_dn_in,"
-                           "extended_dn_out_ldb"])
+    samdb = SamDB(url=dburl, session_info=system_session(), lp=lp)
     return samdb
 
 
diff --git a/python/samba/netcmd/dns.py b/python/samba/netcmd/dns.py
index 2cf9a1f..7cedffc 100644
--- a/python/samba/netcmd/dns.py
+++ b/python/samba/netcmd/dns.py
@@ -37,7 +37,11 @@ def dns_connect(server, lp, creds):
     if server.lower() == 'localhost':
         server = '127.0.0.1'
     binding_str = "ncacn_ip_tcp:%s[sign]" % server
-    dns_conn = dnsserver.dnsserver(binding_str, lp, creds)
+    try:
+        dns_conn = dnsserver.dnsserver(binding_str, lp, creds)
+    except RuntimeError, e:
+        raise CommandError('Connecting to DNS RPC server %s failed with %s' % (server, e))
+
     return dns_conn
 
 
diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 119e8b2..6357144 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -5,7 +5,7 @@
 # Copyright Jelmer Vernooij 2007-2012
 # Copyright Giampaolo Lauria 2011
 # Copyright Matthieu Patou <mat at matws.net> 2011
-# Copyright Andrew Bartlett 2008
+# Copyright Andrew Bartlett 2008-2015
 # Copyright Stefan Metzmacher 2012
 #
 # This program is free software; you can redistribute it and/or modify
@@ -31,6 +31,7 @@ import ctypes
 import random
 import tempfile
 import logging
+import subprocess
 from getpass import getpass
 from samba.net import Net, LIBNET_JOIN_AUTOMATIC
 import samba.ntacls
@@ -44,6 +45,7 @@ from samba.dcerpc import lsa
 from samba.dcerpc import netlogon
 from samba.dcerpc import security
 from samba.dcerpc import nbt
+from samba.dcerpc import misc
 from samba.dcerpc.samr import DOMAIN_PASSWORD_COMPLEX, DOMAIN_PASSWORD_STORE_CLEARTEXT
 from samba.netcmd import (
     Command,
@@ -58,7 +60,7 @@ from samba.upgrade import upgrade_from_samba3
 from samba.drs_utils import (
                             sendDsReplicaSync, drsuapi_connect, drsException,
                             sendRemoveDsServer)
-from samba import arcfour_encrypt, string_to_byte_array
+from samba import remove_dc, arcfour_encrypt, string_to_byte_array
 
 from samba.dsdb import (
     DS_DOMAIN_FUNCTION_2000,
@@ -66,11 +68,14 @@ from samba.dsdb import (
     DS_DOMAIN_FUNCTION_2003_MIXED,
     DS_DOMAIN_FUNCTION_2008,
     DS_DOMAIN_FUNCTION_2008_R2,
+    DS_DOMAIN_FUNCTION_2012,
+    DS_DOMAIN_FUNCTION_2012_R2,
     DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL,
     DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL,
     UF_WORKSTATION_TRUST_ACCOUNT,
     UF_SERVER_TRUST_ACCOUNT,
-    UF_TRUSTED_FOR_DELEGATION
+    UF_TRUSTED_FOR_DELEGATION,
+    UF_PARTIAL_SECRETS_ACCOUNT
     )
 
 from samba.provision import (
@@ -85,9 +90,16 @@ from samba.provision.common import (
 )
 
 def get_testparm_var(testparm, smbconf, varname):
-    cmd = "%s -s -l --parameter-name='%s' %s 2>/dev/null" % (testparm, varname, smbconf)
-    output = os.popen(cmd, 'r').readline()
-    return output.strip()
+    errfile = open(os.devnull, 'w')
+    p = subprocess.Popen([testparm, '-s', '-l',
+                          '--parameter-name=%s' % varname, smbconf],
+                         stdout=subprocess.PIPE, stderr=errfile)
+    (out,err) = p.communicate()
+    errfile.close()
+    lines = out.split('\n')
+    if lines:
+        return lines[0].strip()
+    return ""
 
 try:
    import samba.dckeytab
@@ -194,7 +206,7 @@ class cmd_domain_provision(Command):
          Option("--dnspass", type="string", metavar="PASSWORD",
                 help="choose dns password (otherwise random)"),
          Option("--ldapadminpass", type="string", metavar="PASSWORD",
-                help="choose password to set between Samba and it's LDAP backend (otherwise random)"),
+                help="choose password to set between Samba and its LDAP backend (otherwise random)"),
          Option("--root", type="string", metavar="USERNAME",
                 help="choose 'root' unix username"),
          Option("--nobody", type="string", metavar="USERNAME",
@@ -224,7 +236,7 @@ class cmd_domain_provision(Command):
          Option("--ol-mmr-urls", type="string", metavar="LDAPSERVER",
                 help="List of LDAP-URLS [ ldap://<FQHN>:<PORT>/  (where <PORT> has to be different than 389!) ] separated with comma (\",\") for use with OpenLDAP-MMR (Multi-Master-Replication), e.g.: \"ldap://s4dc1:9000,ldap://s4dc2:9000\""),
          Option("--use-xattrs", type="choice", choices=["yes", "no", "auto"], help="Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities", default="auto"),
-         Option("--use-ntvfs", action="store_true", help="Use NTVFS for the fileserver (default = no)"),
+
          Option("--use-rfc2307", action="store_true", help="Use AD to store posix attributes (default = no)"),
         ]
 
@@ -239,9 +251,16 @@ class cmd_domain_provision(Command):
         Option("--ldap-backend-nosync", help="Configure LDAP backend not to call fsync() (for performance in test environments)", action="store_true"),
         ]
 
+    ntvfs_options = [
+         Option("--use-ntvfs", action="store_true", help="Use NTVFS for the fileserver (default = no)"),
+    ]
+
     if os.getenv('TEST_LDAP', "no") == "yes":
         takes_options.extend(openldap_options)
 
+    if samba.is_ntvfs_fileserver_built():
+         takes_options.extend(ntvfs_options)
+
     takes_args = []
 
     def run(self, sambaopts=None, versionopts=None,
@@ -490,8 +509,6 @@ class cmd_domain_dcpromo(Command):
                action="store_true"),
         Option("--machinepass", type=str, metavar="PASSWORD",
                help="choose machine password (otherwise random)"),
-        Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
-               action="store_true"),
         Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
                choices=["SAMBA_INTERNAL", "BIND9_DLZ", "NONE"],
                help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
@@ -502,6 +519,14 @@ class cmd_domain_dcpromo(Command):
         Option("--verbose", help="Be verbose", action="store_true")
         ]
 
+    ntvfs_options = [
+         Option("--use-ntvfs", action="store_true", help="Use NTVFS for the fileserver (default = no)"),
+    ]
+
+    if samba.is_ntvfs_fileserver_built():
+         takes_options.extend(ntvfs_options)
+
+
     takes_args = ["domain", "role?"]
 
     def run(self, domain, role=None, sambaopts=None, credopts=None,
@@ -569,8 +594,6 @@ class cmd_domain_join(Command):
                help="choose machine password (otherwise random)"),
         Option("--adminpass", type="string", metavar="PASSWORD",
                help="choose adminstrator password when joining as a subdomain (otherwise random)"),
-        Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
-               action="store_true"),
         Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
                choices=["SAMBA_INTERNAL", "BIND9_DLZ", "NONE"],
                help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
@@ -581,6 +604,13 @@ class cmd_domain_join(Command):
         Option("--verbose", help="Be verbose", action="store_true")
        ]
 
+    ntvfs_options = [
+        Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
+               action="store_true")
+    ]
+    if samba.is_ntvfs_fileserver_built():
+        takes_options.extend(ntvfs_options)
+
     takes_args = ["domain", "role?"]
 
     def run(self, domain, role=None, sambaopts=None, credopts=None,
@@ -648,8 +678,13 @@ class cmd_domain_demote(Command):
     synopsis = "%prog [options]"
 
     takes_options = [
-        Option("--server", help="DC to force replication before demote", type=str),
-        Option("--targetdir", help="where provision is stored", type=str),
+        Option("--server", help="writable DC to write demotion changes on", type=str),
+        Option("-H", "--URL", help="LDB URL for database or target server", type=str,
+               metavar="URL", dest="H"),
+        Option("--remove-other-dead-server", help="Dead DC (name or NTDS GUID) "
+               "to remove ALL references to (rather than this DC)", type=str),
+        Option("--quiet", help="Be quiet", action="store_true"),
+        Option("--verbose", help="Be verbose", action="store_true"),
         ]
 
     takes_optiongroups = {
@@ -659,13 +694,36 @@ class cmd_domain_demote(Command):
         }
 
     def run(self, sambaopts=None, credopts=None,
-            versionopts=None, server=None, targetdir=None):
+            versionopts=None, server=None,
+            remove_other_dead_server=None, H=None,
+            verbose=False, quiet=False):
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp)
         net = Net(creds, lp, server=credopts.ipaddress)
 
+        logger = self.get_logger()
+        if verbose:
+            logger.setLevel(logging.DEBUG)
+        elif quiet:
+            logger.setLevel(logging.WARNING)
+        else:
+            logger.setLevel(logging.INFO)
+
+        if remove_other_dead_server is not None:
+            if server is not None:
+                samdb = SamDB(url="ldap://%s" % server,
+                              session_info=system_session(),
+                              credentials=creds, lp=lp)
+            else:
+                samdb = SamDB(url=H, session_info=system_session(), credentials=creds, lp=lp)
+            try:
+                remove_dc.remove_dc(samdb, logger, remove_other_dead_server)
+            except remove_dc.DemoteException as err:
+                raise CommandError("Demote failed: %s" % err)
+            return
+
         netbios_name = lp.get("netbios name")
-        samdb = SamDB(session_info=system_session(), credentials=creds, lp=lp)
+        samdb = SamDB(url=H, session_info=system_session(), credentials=creds, lp=lp)
         if not server:
             res = samdb.search(expression='(&(objectClass=computer)(serverReferenceBL=*))', attrs=["dnsHostName", "name"])
             if (len(res) == 0):
@@ -702,37 +760,48 @@ class cmd_domain_demote(Command):
 
         self.errf.write("Deactivating inbound replication\n")
 
-        nmsg = ldb.Message()
-        nmsg.dn = msg[0].dn
+        if not (dsa_options & DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL) and not samdb.am_rodc():
+            nmsg = ldb.Message()
+            nmsg.dn = msg[0].dn
 
-        dsa_options |= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
-        nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
-        samdb.modify(nmsg)
+            dsa_options |= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
+            nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
+            samdb.modify(nmsg)
 
-        if not (dsa_options & DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL) and not samdb.am_rodc():
 
             self.errf.write("Asking partner server %s to synchronize from us\n"
                             % server)
             for part in (samdb.get_schema_basedn(),
                             samdb.get_config_basedn(),
                             samdb.get_root_basedn()):
+                nc = drsuapi.DsReplicaObjectIdentifier()
+                nc.dn = str(part)
+
+                req1 = drsuapi.DsReplicaSyncRequest1()
+                req1.naming_context = nc;
+                req1.options = drsuapi.DRSUAPI_DRS_WRIT_REP
+                req1.source_dsa_guid = misc.GUID(ntds_guid)
+
                 try:
-                    sendDsReplicaSync(drsuapiBind, drsuapi_handle, ntds_guid, str(part), drsuapi.DRSUAPI_DRS_WRIT_REP)
-                except drsException, e:
-                    self.errf.write(
-                        "Error while demoting, "
+                    drsuapiBind.DsReplicaSync(drsuapi_handle, 1, req1)
+                except RuntimeError as (werr, string):
+                    if werr == 8452: #WERR_DS_DRA_NO_REPLICA
+                        pass
+                    else:
+                        self.errf.write(
+                            "Error while demoting, "
                         "re-enabling inbound replication\n")
-                    dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
-                    nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
-                    samdb.modify(nmsg)
-                    raise CommandError("Error while sending a DsReplicaSync for partion %s" % str(part), e)
+                        dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
+                        nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
+                        samdb.modify(nmsg)
+                        raise CommandError("Error while sending a DsReplicaSync for partion %s" % str(part), e)
         try:
             remote_samdb = SamDB(url="ldap://%s" % server,
                                 session_info=system_session(),
                                 credentials=creds, lp=lp)
 
             self.errf.write("Changing userControl and container\n")
-            res = remote_samdb.search(base=str(remote_samdb.get_root_basedn()),
+            res = remote_samdb.search(base=str(remote_samdb.domain_dn()),
                                 expression="(&(objectClass=user)(sAMAccountName=%s$))" %
                                             netbios_name.upper(),
                                 attrs=["userAccountControl"])
@@ -758,7 +827,7 @@ class cmd_domain_demote(Command):
 
         olduac = uac
 
-        uac ^= (UF_SERVER_TRUST_ACCOUNT|UF_TRUSTED_FOR_DELEGATION)
+        uac &= ~(UF_SERVER_TRUST_ACCOUNT|UF_TRUSTED_FOR_DELEGATION|UF_PARTIAL_SECRETS_ACCOUNT)
         uac |= UF_WORKSTATION_TRUST_ACCOUNT
 
         msg = ldb.Message()
@@ -779,13 +848,14 @@ class cmd_domain_demote(Command):
             raise CommandError("Error while changing account control", e)
 
         parent = msg.dn.parent()
-        rdn = str(res[0].dn)
-        rdn = string.replace(rdn, ",%s" % str(parent), "")
+        dc_name = res[0].dn.get_rdn_value()
+        rdn = "CN=%s" % dc_name
+
         # Let's move to the Computer container
         i = 0
-        newrdn = rdn
+        newrdn = str(rdn)
 
-        computer_dn = ldb.Dn(remote_samdb, "CN=Computers,%s" % str(remote_samdb.get_root_basedn()))
+        computer_dn = ldb.Dn(remote_samdb, "CN=Computers,%s" % str(remote_samdb.domain_dn()))
         res = remote_samdb.search(base=computer_dn, expression=rdn, scope=ldb.SCOPE_ONELEVEL)
 
         if (len(res) != 0):
@@ -843,34 +913,36 @@ class cmd_domain_demote(Command):
         domain = remote_samdb.get_root_basedn()
 
         try:
-            sendRemoveDsServer(drsuapiBind, drsuapi_handle, server_dsa_dn, domain)
-        except drsException, e:
-            self.errf.write(
-                "Error while demoting, re-enabling inbound replication\n")
-            dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
-            nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
-            samdb.modify(nmsg)
+            req1 = drsuapi.DsRemoveDSServerRequest1()
+            req1.server_dn = str(server_dsa_dn)
+            req1.domain_dn = str(domain)
+            req1.commit = 1
+
+            drsuapiBind.DsRemoveDSServer(drsuapi_handle, 1, req1)
+        except RuntimeError as (werr, string):
+            if not (dsa_options & DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL) and not samdb.am_rodc():
+                self.errf.write(
+                    "Error while demoting, re-enabling inbound replication\n")
+                dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
+                nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
+                samdb.modify(nmsg)
 
             msg = ldb.Message()
             msg.dn = newdn
 
             msg["userAccountControl"] = ldb.MessageElement("%d" % uac,
-                                                    ldb.FLAG_MOD_REPLACE,
-                                                    "userAccountControl")
-            print str(dc_dn)
+                                                           ldb.FLAG_MOD_REPLACE,
+                                                           "userAccountControl")
             remote_samdb.modify(msg)
             remote_samdb.rename(newdn, dc_dn)
-            raise CommandError("Error while sending a removeDsServer", e)
+            if werr == 8452: #WERR_DS_DRA_NO_REPLICA
+                raise CommandError("The DC %s is not present on (already removed from) the remote server: " % server_dsa_dn, e)
+            else:
+                raise CommandError("Error while sending a removeDsServer of %s: " % server_dsa_dn, e)
 
-        for s in ("CN=Enterprise,CN=Microsoft System Volumes,CN=System,CN=Configuration",
-                  "CN=%s,CN=Microsoft System Volumes,CN=System,CN=Configuration" % lp.get("realm"),
-                  "CN=Domain System Volumes (SYSVOL share),CN=File Replication Service,CN=System"):
-            try:
-                remote_samdb.delete(ldb.Dn(remote_samdb,
-                                    "%s,%s,%s" % (str(rdn), s, str(remote_samdb.get_root_basedn()))))
-            except ldb.LdbError, l:
-                pass
+        remove_dc.remove_sysvol_references(remote_samdb, dc_name)
 
+        # These are objects under the computer account that should be deleted
         for s in ("CN=Enterprise,CN=NTFRS Subscriptions",
                   "CN=%s, CN=NTFRS Subscriptions" % lp.get("realm"),
                   "CN=Domain system Volumes (SYSVOL Share), CN=NTFRS Subscriptions",
@@ -899,10 +971,10 @@ class cmd_domain_level(Command):
         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
                metavar="URL", dest="H"),
         Option("--quiet", help="Be quiet", action="store_true"),
-        Option("--forest-level", type="choice", choices=["2003", "2008", "2008_R2"],
-            help="The forest function level (2003 | 2008 | 2008_R2)"),
-        Option("--domain-level", type="choice", choices=["2003", "2008", "2008_R2"],
-            help="The domain function level (2003 | 2008 | 2008_R2)")
+        Option("--forest-level", type="choice", choices=["2003", "2008", "2008_R2", "2012", "2012_R2"],
+            help="The forest function level (2003 | 2008 | 2008_R2 | 2012 | 2012_R2)"),
+        Option("--domain-level", type="choice", choices=["2003", "2008", "2008_R2", "2012", "2012_R2"],
+            help="The domain function level (2003 | 2008 | 2008_R2 | 2012 | 2012_R2)")
             ]
 
     takes_args = ["subcommand"]
@@ -930,27 +1002,34 @@ class cmd_domain_level(Command):
           attrs=["msDS-Behavior-Version"])
         assert len(res_dc_s) >= 1
 
-        try:
+        # default values, since "msDS-Behavior-Version" does not exist on Windows 2000 AD
+        level_forest = DS_DOMAIN_FUNCTION_2000
+        level_domain = DS_DOMAIN_FUNCTION_2000
+
+        if "msDS-Behavior-Version" in res_forest[0]:
             level_forest = int(res_forest[0]["msDS-Behavior-Version"][0])
+        if "msDS-Behavior-Version" in res_domain[0]:
             level_domain = int(res_domain[0]["msDS-Behavior-Version"][0])
-            level_domain_mixed = int(res_domain[0]["nTMixedDomain"][0])
+        level_domain_mixed = int(res_domain[0]["nTMixedDomain"][0])
 
-            min_level_dc = int(res_dc_s[0]["msDS-Behavior-Version"][0]) # Init value
-            for msg in res_dc_s:
-                if int(msg["msDS-Behavior-Version"][0]) < min_level_dc:
+        min_level_dc = None
+        for msg in res_dc_s:
+            if "msDS-Behavior-Version" in msg:
+                if min_level_dc is None or int(msg["msDS-Behavior-Version"][0]) < min_level_dc:
                     min_level_dc = int(msg["msDS-Behavior-Version"][0])
+            else:
+                min_level_dc = DS_DOMAIN_FUNCTION_2000
+                # well, this is the least
+                break
 
-            if level_forest < 0 or level_domain < 0:
-                raise CommandError("Domain and/or forest function level(s) is/are invalid. Correct them or reprovision!")
-            if min_level_dc < 0:
-                raise CommandError("Lowest function level of a DC is invalid. Correct this or reprovision!")
-            if level_forest > level_domain:
-                raise CommandError("Forest function level is higher than the domain level(s). Correct this or reprovision!")
-            if level_domain > min_level_dc:
-                raise CommandError("Domain function level is higher than the lowest function level of a DC. Correct this or reprovision!")
-
-        except KeyError:
-            raise CommandError("Could not retrieve the actual domain, forest level and/or lowest DC function level!")
+        if level_forest < DS_DOMAIN_FUNCTION_2000 or level_domain < DS_DOMAIN_FUNCTION_2000:
+            raise CommandError("Domain and/or forest function level(s) is/are invalid. Correct them or reprovision!")
+        if min_level_dc < DS_DOMAIN_FUNCTION_2000:
+            raise CommandError("Lowest function level of a DC is invalid. Correct this or reprovision!")
+        if level_forest > level_domain:
+            raise CommandError("Forest function level is higher than the domain level(s). Correct this or reprovision!")
+        if level_domain > min_level_dc:
+            raise CommandError("Domain function level is higher than the lowest function level of a DC. Correct this or reprovision!")
 
         if subcommand == "show":
             self.message("Domain and forest function level for domain '%s'" % domain_dn)
@@ -973,8 +1052,12 @@ class cmd_domain_level(Command):
                 outstr = "2008"
             elif level_forest == DS_DOMAIN_FUNCTION_2008_R2:
                 outstr = "2008 R2"
+            elif level_forest == DS_DOMAIN_FUNCTION_2012:
+                outstr = "2012"
+            elif level_forest == DS_DOMAIN_FUNCTION_2012_R2:
+                outstr = "2012 R2"
             else:
-                outstr = "higher than 2008 R2"
+                outstr = "higher than 2012 R2"
             self.message("Forest function level: (Windows) " + outstr)
 
             if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
@@ -989,8 +1072,12 @@ class cmd_domain_level(Command):
                 outstr = "2008"
             elif level_domain == DS_DOMAIN_FUNCTION_2008_R2:
                 outstr = "2008 R2"
+            elif level_domain == DS_DOMAIN_FUNCTION_2012:
+                outstr = "2012"
+            elif level_domain == DS_DOMAIN_FUNCTION_2012_R2:
+                outstr = "2012 R2"
             else:
-                outstr = "higher than 2008 R2"
+                outstr = "higher than 2012 R2"
             self.message("Domain function level: (Windows) " + outstr)
 
             if min_level_dc == DS_DOMAIN_FUNCTION_2000:
@@ -1001,8 +1088,12 @@ class cmd_domain_level(Command):
                 outstr = "2008"
             elif min_level_dc == DS_DOMAIN_FUNCTION_2008_R2:
                 outstr = "2008 R2"
+            elif min_level_dc == DS_DOMAIN_FUNCTION_2012:
+                outstr = "2012"
+            elif min_level_dc == DS_DOMAIN_FUNCTION_2012_R2:
+                outstr = "2012 R2"
             else:
-                outstr = "higher than 2008 R2"
+                outstr = "higher than 2012 R2"
             self.message("Lowest function level of a DC: (Windows) " + outstr)
 
         elif subcommand == "raise":
@@ -1015,10 +1106,13 @@ class cmd_domain_level(Command):
                     new_level_domain = DS_DOMAIN_FUNCTION_2008
                 elif domain_level == "2008_R2":
                     new_level_domain = DS_DOMAIN_FUNCTION_2008_R2
+                elif domain_level == "2012":
+                    new_level_domain = DS_DOMAIN_FUNCTION_2012
+                elif domain_level == "2012_R2":
+                    new_level_domain = DS_DOMAIN_FUNCTION_2012_R2
 
                 if new_level_domain <= level_domain and level_domain_mixed == 0:
                     raise CommandError("Domain function level can't be smaller than or equal to the actual one!")
-
                 if new_level_domain > min_level_dc:
                     raise CommandError("Domain function level can't be higher than the lowest function level of a DC!")
 
@@ -1071,10 +1165,16 @@ class cmd_domain_level(Command):
                     new_level_forest = DS_DOMAIN_FUNCTION_2008
                 elif forest_level == "2008_R2":
                     new_level_forest = DS_DOMAIN_FUNCTION_2008_R2
+                elif forest_level == "2012":
+                    new_level_forest = DS_DOMAIN_FUNCTION_2012
+                elif forest_level == "2012_R2":
+                    new_level_forest = DS_DOMAIN_FUNCTION_2012_R2
+
                 if new_level_forest <= level_forest:
                     raise CommandError("Forest function level can't be smaller than or equal to the actual one!")
                 if new_level_forest > level_domain:
                     raise CommandError("Forest function level can't be higher than the domain function level(s). Please raise it/them first!")
+
                 m = ldb.Message()
                 m.dn = ldb.Dn(samdb, "CN=Partitions,%s" % samdb.get_config_basedn())
                 m["msDS-Behavior-Version"]= ldb.MessageElement(
@@ -1358,8 +1458,6 @@ class cmd_domain_classicupgrade(Command):
         Option("--verbose", help="Be verbose", action="store_true"),
         Option("--use-xattrs", type="choice", choices=["yes","no","auto"], metavar="[yes|no|auto]",
                    help="Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities", default="auto"),
-        Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
-               action="store_true"),
         Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
                choices=["SAMBA_INTERNAL", "BIND9_FLATFILE", "BIND9_DLZ", "NONE"],
                help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
@@ -1369,6 +1467,13 @@ class cmd_domain_classicupgrade(Command):
                default="SAMBA_INTERNAL")
     ]
 
+    ntvfs_options = [
+        Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
+               action="store_true")
+    ]
+    if samba.is_ntvfs_fileserver_built():
+        takes_options.extend(ntvfs_options)
+
     takes_args = ["smbconf"]
 
     def run(self, smbconf=None, targetdir=None, dbdir=None, testparm=None,
diff --git a/python/samba/netcmd/drs.py b/python/samba/netcmd/drs.py
index e8e9ec8..230dd33 100644
--- a/python/samba/netcmd/drs.py
+++ b/python/samba/netcmd/drs.py
@@ -20,6 +20,7 @@
 
 import samba.getopt as options
 import ldb
+import logging
 
 from samba.auth import system_session
 from samba.netcmd import (
@@ -32,6 +33,7 @@ from samba.samdb import SamDB
 from samba import drs_utils, nttime2string, dsdb
 from samba.dcerpc import drsuapi, misc
 import common
+from samba.join import join_clone
 
 def drsuapi_connect(ctx):
     '''make a DRSUAPI connection to the server'''
@@ -513,6 +515,49 @@ class cmd_drs_options(Command):
             self.message("New DSA options: " + ", ".join(cur_opts))
 
 
+class cmd_drs_clone_dc_database(Command):
+    """Replicate an initial clone of domain, but DO NOT JOIN it."""
+
+    synopsis = "%prog <dnsdomain> [options]"
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("--server", help="DC to join", type=str),
+        Option("--targetdir", help="where to store provision (required)", type=str),
+        Option("--quiet", help="Be quiet", action="store_true"),
+        Option("--include-secrets", help="Also replicate secret values", action="store_true"),
+        Option("--verbose", help="Be verbose", action="store_true")
+       ]
+
+    takes_args = ["domain"]
+
+    def run(self, domain, sambaopts=None, credopts=None,
+            versionopts=None, server=None, targetdir=None,
+            quiet=False, verbose=False, include_secrets=False):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp)
+
+        logger = self.get_logger()
+        if verbose:
+            logger.setLevel(logging.DEBUG)
+        elif quiet:
+            logger.setLevel(logging.WARNING)
+        else:
+            logger.setLevel(logging.INFO)
+
+        if targetdir is None:
+            raise CommandError("--targetdir option must be specified")
+
+
+        join_clone(logger=logger, server=server, creds=creds, lp=lp, domain=domain,
+                   targetdir=targetdir, include_secrets=include_secrets)
+
+
 class cmd_drs(SuperCommand):
     """Directory Replication Services (DRS) management."""
 
@@ -522,3 +567,4 @@ class cmd_drs(SuperCommand):
     subcommands["replicate"] = cmd_drs_replicate()
     subcommands["showrepl"] = cmd_drs_showrepl()
     subcommands["options"] = cmd_drs_options()
+    subcommands["clone-dc-database"] = cmd_drs_clone_dc_database()
diff --git a/python/samba/netcmd/main.py b/python/samba/netcmd/main.py
index 5f78823..471c6b4 100644
--- a/python/samba/netcmd/main.py
+++ b/python/samba/netcmd/main.py
@@ -37,7 +37,6 @@ from samba.netcmd.spn import cmd_spn
 from samba.netcmd.testparm import cmd_testparm
 from samba.netcmd.time import cmd_time
 from samba.netcmd.user import cmd_user
-from samba.netcmd.vampire import cmd_vampire
 from samba.netcmd.processes import cmd_processes
 
 
@@ -66,5 +65,4 @@ class cmd_sambatool(SuperCommand):
     subcommands["testparm"] =  cmd_testparm()
     subcommands["time"] = cmd_time()
     subcommands["user"] = cmd_user()
-    subcommands["vampire"] = cmd_vampire()
     subcommands["processes"] = cmd_processes()
diff --git a/python/samba/netcmd/ntacl.py b/python/samba/netcmd/ntacl.py
index dff1550..eaea0e7 100644
--- a/python/samba/netcmd/ntacl.py
+++ b/python/samba/netcmd/ntacl.py
@@ -19,7 +19,7 @@
 from samba.credentials import DONT_USE_KERBEROS
 import samba.getopt as options
 from samba.dcerpc import security, idmap
-from samba.ntacls import setntacl, getntacl
+from samba.ntacls import setntacl, getntacl,getdosinfo
 from samba import Ldb
 from samba.ndr import ndr_unpack, ndr_print
 from samba.samdb import SamDB
@@ -95,6 +95,27 @@ class cmd_ntacl_set(Command):
             logger.warning("Please note that POSIX permissions have NOT been changed, only the stored NT ACL")
 
 
+class cmd_dosinfo_get(Command):
+    """Get DOS info of a file from xattr."""
+    synopsis = "%prog <file> [options]"
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "credopts": options.CredentialsOptions,
+        "versionopts": options.VersionOptions,
+        }
+
+    takes_args = ["file"]
+
+    def run(self, file, credopts=None, sambaopts=None, versionopts=None):
+        lp = sambaopts.get_loadparm()
+        s3conf = s3param.get_context()
+        s3conf.load(lp.configfile)
+
+        dosinfo = getdosinfo(lp, file)
+        if dosinfo:
+            self.outf.write(ndr_print(dosinfo))
+
 class cmd_ntacl_get(Command):
     """Get ACLs of a file."""
     synopsis = "%prog <file> [options]"
@@ -257,4 +278,5 @@ class cmd_ntacl(SuperCommand):
     subcommands["get"] = cmd_ntacl_get()
     subcommands["sysvolreset"] = cmd_ntacl_sysvolreset()
     subcommands["sysvolcheck"] = cmd_ntacl_sysvolcheck()
+    subcommands["getdosinfo"] = cmd_dosinfo_get()
 
diff --git a/python/samba/netcmd/sites.py b/python/samba/netcmd/sites.py
index 09df55e..f0c792d 100644
--- a/python/samba/netcmd/sites.py
+++ b/python/samba/netcmd/sites.py
@@ -16,15 +16,15 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-import os
-from samba import sites
+from samba import sites, subnets
 from samba.samdb import SamDB
 import samba.getopt as options
 from samba.auth import system_session
 from samba.netcmd import (
     Command,
     CommandError,
-    SuperCommand
+    SuperCommand,
+    Option,
     )
 
 
@@ -41,26 +41,30 @@ class cmd_sites_create(Command):
         "credopts": options.CredentialsOptions,
     }
 
-    def run(self, sitename, sambaopts=None, credopts=None, versionopts=None):
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, sitename, H=None, sambaopts=None, credopts=None,
+            versionopts=None):
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp, fallback_machine=True)
-        url =  lp.private_path("sam.ldb")
-
-        if not os.path.exists(url):
-            raise CommandError("secret database not found at %s " % url)
-        samdb = SamDB(url=url, session_info=system_session(),
+        samdb = SamDB(url=H, session_info=system_session(),
                       credentials=creds, lp=lp)
 
         samdb.transaction_start()
         try:
-            ok = sites.create_site(samdb, samdb.get_config_basedn(), sitename)
+            sites.create_site(samdb, samdb.get_config_basedn(), sitename)
             samdb.transaction_commit()
         except sites.SiteAlreadyExistsException, e:
             samdb.transaction_cancel()
-            raise CommandError("Error while creating site %s, error: %s" % (sitename, str(e)))
+            raise CommandError("Error while creating site %s, error: %s" %
+                               (sitename, str(e)))
 
         self.outf.write("Site %s created !\n" % sitename)
 
+
 class cmd_sites_delete(Command):
     """Delete an existing site."""
 
@@ -74,19 +78,21 @@ class cmd_sites_delete(Command):
         "credopts": options.CredentialsOptions,
     }
 
-    def run(self, sitename, sambaopts=None, credopts=None, versionopts=None):
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, sitename, H=None, sambaopts=None, credopts=None,
+            versionopts=None):
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp, fallback_machine=True)
-        url =  lp.private_path("sam.ldb")
-
-        if not os.path.exists(url):
-            raise CommandError("secret database not found at %s " % url)
-        samdb = SamDB(url=url, session_info=system_session(),
-            credentials=creds, lp=lp)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
 
         samdb.transaction_start()
         try:
-            ok = sites.delete_site(samdb, samdb.get_config_basedn(), sitename)
+            sites.delete_site(samdb, samdb.get_config_basedn(), sitename)
             samdb.transaction_commit()
         except sites.SiteException, e:
             samdb.transaction_cancel()
@@ -96,10 +102,127 @@ class cmd_sites_delete(Command):
         self.outf.write("Site %s removed!\n" % sitename)
 
 
+class cmd_sites_subnet_create(Command):
+    """Create a new subnet."""
+    synopsis = "%prog <subnet> <site-of-subnet> [options]"
+    takes_args = ["subnetname", "site_of_subnet"]
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, subnetname, site_of_subnet, H=None, sambaopts=None,
+            credopts=None, versionopts=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        samdb.transaction_start()
+        try:
+            subnets.create_subnet(samdb, samdb.get_config_basedn(), subnetname,
+                                  site_of_subnet)
+            samdb.transaction_commit()
+        except subnets.SubnetException, e:
+            samdb.transaction_cancel()
+            raise CommandError("Error while creating subnet %s: %s" %
+                               (subnetname, e))
+
+        self.outf.write("Subnet %s created !\n" % subnetname)
+
+
+class cmd_sites_subnet_delete(Command):
+    """Delete an existing subnet."""
+
+    synopsis = "%prog <subnet> [options]"
+
+    takes_args = ["subnetname"]
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, subnetname, H=None, sambaopts=None, credopts=None,
+            versionopts=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        samdb.transaction_start()
+        try:
+            subnets.delete_subnet(samdb, samdb.get_config_basedn(), subnetname)
+            samdb.transaction_commit()
+        except subnets.SubnetException, e:
+            samdb.transaction_cancel()
+            raise CommandError("Error while removing subnet %s, error: %s" %
+                               (subnetname, e))
+
+        self.outf.write("Subnet %s removed!\n" % subnetname)
+
+
+class cmd_sites_subnet_set_site(Command):
+    """Assign a subnet to a site."""
+    synopsis = "%prog <subnet> <site-of-subnet> [options]"
+    takes_args = ["subnetname", "site_of_subnet"]
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, subnetname, site_of_subnet, H=None, sambaopts=None,
+            credopts=None, versionopts=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        samdb.transaction_start()
+        try:
+            subnets.set_subnet_site(samdb, samdb.get_config_basedn(),
+                                    subnetname, site_of_subnet)
+            samdb.transaction_commit()
+        except subnets.SubnetException, e:
+            samdb.transaction_cancel()
+            raise CommandError("Error assigning subnet %s to site %s: %s" %
+                               (subnetname, site_of_subnet, e))
+
+        print >> self.outf, ("Subnet %s shifted to site %s" %
+                             (subnet_name, site_of_subnet))
+
+
+class cmd_sites_subnet(SuperCommand):
+    """Subnet management subcommands."""
+    subcommands = {
+        "create": cmd_sites_subnet_create(),
+        "remove": cmd_sites_subnet_delete(),
+        "set-site": cmd_sites_subnet_set_site(),
+    }
 
 class cmd_sites(SuperCommand):
     """Sites management."""
-
     subcommands = {}
     subcommands["create"] = cmd_sites_create()
     subcommands["remove"] = cmd_sites_delete()
+    subcommands["subnet"] = cmd_sites_subnet()
diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py
index 2bc5522..cf640b0 100644
--- a/python/samba/netcmd/user.py
+++ b/python/samba/netcmd/user.py
@@ -52,17 +52,17 @@ Unix (RFC2307) attributes may be added to the user account. Attributes taken fro
 The command may be run from the root userid or another authorized userid.  The -H or --URL= option can be used to execute the command against a remote server.
 
 Example1:
-samba-tool user add User1 passw0rd --given-name=John --surname=Smith --must-change-at-next-login -H ldap://samba.samdom.example.com -Uadministrator%passw1rd
+samba-tool user create User1 passw0rd --given-name=John --surname=Smith --must-change-at-next-login -H ldap://samba.samdom.example.com -Uadministrator%passw1rd
 
 Example1 shows how to create a new user in the domain against a remote LDAP server.  The -H parameter is used to specify the remote target server.  The -U option is used to pass the userid and password authorized to issue the command remotely.
 
 Example2:
-sudo samba-tool user add User2 passw2rd --given-name=Jane --surname=Doe --must-change-at-next-login
+sudo samba-tool user create User2 passw2rd --given-name=Jane --surname=Doe --must-change-at-next-login
 
 Example2 shows how to create a new user in the domain against the local server.   sudo is used so a user may run the command as root.  In this example, after User2 is created, he/she will be forced to change their password when they logon.
 
 Example3:
-samba-tool user add User3 passw3rd --userou='OU=OrgUnit'
+samba-tool user create User3 passw3rd --userou='OU=OrgUnit'
 
 Example3 shows how to create a new user in the OrgUnit organizational unit.
 
@@ -72,7 +72,7 @@ samba-tool user create User4 passw4rd --rfc2307-from-nss --gecos 'some text'
 Example4 shows how to create a new user with Unix UID, GID and login-shell set from the local NSS and GECOS set to 'some text'.
 
 Example5:
-samba-tool user add User5 passw5rd --nis-domain=samdom --unix-home=/home/User5 \
+samba-tool user create User5 passw5rd --nis-domain=samdom --unix-home=/home/User5 \
            --uid-number=10005 --login-shell=/bin/false --gid-number=10000
 
 Example5 shows how to create an RFC2307/NIS domain enabled user account. If
@@ -426,7 +426,7 @@ Example2 shows how to set the account expiration of user User2 so it will never
 Example3:
 samba-tool user setexpiry --days=20 --filter=samaccountname=User3
 
-Example3 shows how to set the account expiration date to end of day 20 days from the current day.  The username or sAMAccountName is specified using the --filter= paramter and the username in this example is User3.
+Example3 shows how to set the account expiration date to end of day 20 days from the current day.  The username or sAMAccountName is specified using the --filter= parameter and the username in this example is User3.
 
 Example4:
 samba-tool user setexpiry --noexpiry User4
diff --git a/python/samba/netcmd/vampire.py b/python/samba/netcmd/vampire.py
deleted file mode 100644
index b12222e..0000000
--- a/python/samba/netcmd/vampire.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Vampire
-#
-# Copyright Jelmer Vernooij 2010 <jelmer at samba.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-import samba.getopt as options
-
-from samba.net import Net
-
-from samba.netcmd import (
-    Command,
-    Option,
-    SuperCommand,
-    CommandError
-    )
-
-
-class cmd_vampire(Command):
-    """Join and synchronise a remote AD domain to the local server."""
-    synopsis = "%prog [options] <domain>"
-
-    takes_optiongroups = {
-        "sambaopts": options.SambaOptions,
-        "credopts": options.CredentialsOptions,
-        "versionopts": options.VersionOptions,
-        }
-
-    takes_options = [
-        Option("--target-dir", help="Target directory.", type=str),
-        Option("--force", help="force run", action='store_true', default=False),
-        ]
-
-    takes_args = ["domain"]
-
-    def run(self, domain, target_dir=None, credopts=None, sambaopts=None, versionopts=None, force=False):
-        if not force:
-            raise CommandError("samba-tool vampire is deprecated, please use samba-tool domain join. Use --force to override")
-        lp = sambaopts.get_loadparm()
-        creds = credopts.get_credentials(lp)
-        net = Net(creds, lp, server=credopts.ipaddress)
-        (domain_name, domain_sid) = net.vampire(domain=domain, target_dir=target_dir)
-        self.outf.write("Vampired domain %s (%s)\n" % (domain_name, domain_sid))
diff --git a/python/samba/ntacls.py b/python/samba/ntacls.py
index 53438d8..0eeb497 100644
--- a/python/samba/ntacls.py
+++ b/python/samba/ntacls.py
@@ -54,6 +54,14 @@ def checkset_backend(lp, backend, eadbfile):
     else:
         raise XattrBackendError("Invalid xattr backend choice %s"%backend)
 
+def getdosinfo(lp, file):
+    try:
+        attribute = samba.xattr_native.wrap_getxattr(file,
+                                                     xattr.XATTR_DOSATTRIB_NAME_S3)
+    except Exception:
+        return
+
+    return ndr_unpack(xattr.DOSATTRIB, attribute)
 
 def getntacl(lp, file, backend=None, eadbfile=None, direct_db_access=True, service=None):
     if direct_db_access:
diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py
index 953bd0f..b36a7d2 100644
--- a/python/samba/provision/__init__.py
+++ b/python/samba/provision/__init__.py
@@ -276,16 +276,15 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf,
         names.domainlevel = int(res6[0]["msDS-Behavior-Version"][0])
 
     # policy guid
-    res7 = samdb.search(expression="(displayName=Default Domain Policy)",
+    res7 = samdb.search(expression="(name={%s})" % DEFAULT_POLICY_GUID,
                         base="CN=Policies,CN=System," + basedn,
                         scope=ldb.SCOPE_ONELEVEL, attrs=["cn","displayName"])
     names.policyid = str(res7[0]["cn"]).replace("{","").replace("}","")
     # dc policy guid
-    res8 = samdb.search(expression="(displayName=Default Domain Controllers"
-                                   " Policy)",
-                            base="CN=Policies,CN=System," + basedn,
-                            scope=ldb.SCOPE_ONELEVEL,
-                            attrs=["cn","displayName"])
+    res8 = samdb.search(expression="(name={%s})" % DEFAULT_DC_POLICY_GUID,
+                        base="CN=Policies,CN=System," + basedn,
+                        scope=ldb.SCOPE_ONELEVEL,
+                        attrs=["cn","displayName"])
     if len(res8) == 1:
         names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","")
     else:
diff --git a/python/samba/provision/sambadns.py b/python/samba/provision/sambadns.py
index b563932..a393181 100644
--- a/python/samba/provision/sambadns.py
+++ b/python/samba/provision/sambadns.py
@@ -35,7 +35,8 @@ from samba.dcerpc import dnsp, misc, security
 from samba.dsdb import (
     DS_DOMAIN_FUNCTION_2000,
     DS_DOMAIN_FUNCTION_2003,
-    DS_DOMAIN_FUNCTION_2008_R2
+    DS_DOMAIN_FUNCTION_2008_R2,
+    DS_DOMAIN_FUNCTION_2012_R2
     )
 from samba.descriptor import (
     get_domain_descriptor,
@@ -967,7 +968,7 @@ def is_valid_dns_backend(dns_backend):
 
 
 def is_valid_os_level(os_level):
-    return DS_DOMAIN_FUNCTION_2000 <= os_level <= DS_DOMAIN_FUNCTION_2008_R2
+    return DS_DOMAIN_FUNCTION_2000 <= os_level <= DS_DOMAIN_FUNCTION_2012_R2
 
 
 def create_dns_legacy(samdb, domainsid, forestdn, dnsadmins_sid):
@@ -1178,6 +1179,16 @@ def setup_bind9_dns(samdb, secretsdb, names, paths, lp, logger,
                         dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
                         key_version_number=key_version_number)
 
+    dns_keytab_path = os.path.join(paths.private_dir, paths.dns_keytab)
+    if os.path.isfile(dns_keytab_path) and paths.bind_gid is not None:
+        try:
+            os.chmod(dns_keytab_path, 0640)
+            os.chown(dns_keytab_path, -1, paths.bind_gid)
+        except OSError:
+            if not os.environ.has_key('SAMBA_SELFTEST'):
+                logger.info("Failed to chown %s to bind gid %u",
+                            dns_keytab_path, paths.bind_gid)
+
     create_dns_dir(logger, paths)
 
     if dns_backend == "BIND9_FLATFILE":
diff --git a/python/samba/remove_dc.py b/python/samba/remove_dc.py
new file mode 100644
index 0000000..055a516
--- /dev/null
+++ b/python/samba/remove_dc.py
@@ -0,0 +1,435 @@
+# Unix SMB/CIFS implementation.
+# Copyright Matthieu Patou <mat at matws.net> 2011
+# Copyright Andrew Bartlett <abartlet at samba.org> 2008-2015
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import uuid
+import ldb
+from ldb import LdbError
+from samba.ndr import ndr_unpack
+from samba.dcerpc import misc, dnsp
+from samba.dcerpc.dnsp import DNS_TYPE_NS, DNS_TYPE_A, DNS_TYPE_AAAA, \
+    DNS_TYPE_CNAME, DNS_TYPE_SRV, DNS_TYPE_PTR
+
+class DemoteException(Exception):
+    """Base element for demote errors"""
+
+    def __init__(self, value):
+        self.value = value
+
+    def __str__(self):
+        return "DemoteException: " + self.value
+
+
+def remove_sysvol_references(samdb, logger, dc_name):
+    # DNs under the Configuration DN:
+    realm = samdb.domain_dns_name()
+    for s in ("CN=Enterprise,CN=Microsoft System Volumes,CN=System",
+              "CN=%s,CN=Microsoft System Volumes,CN=System" % realm):
+        dn = ldb.Dn(samdb, s)
+
+        # This is verbose, but it is the safe, escape-proof way
+        # to add a base and add an arbitrary RDN.
+        if dn.add_base(samdb.get_config_basedn()) == False:
+            raise DemoteException("Failed constructing DN %s by adding base %s" \
+                                  % (dn, samdb.get_config_basedn()))
+        if dn.add_child("CN=X") == False:
+            raise DemoteException("Failed constructing DN %s by adding child CN=X"\
+                                      % (dn))
+        dn.set_component(0, "CN", dc_name)
+        try:
+            logger.info("Removing Sysvol reference: %s" % dn)
+            samdb.delete(dn)
+        except ldb.LdbError as (enum, estr):
+            if enum == ldb.ERR_NO_SUCH_OBJECT:
+                pass
+            else:
+                raise
+
+    # DNs under the Domain DN:
+    for s in ("CN=Domain System Volumes (SYSVOL share),CN=File Replication Service,CN=System",
+              "CN=Topology,CN=Domain System Volume,CN=DFSR-GlobalSettings,CN=System"):
+        # This is verbose, but it is the safe, escape-proof way
+        # to add a base and add an arbitrary RDN.
+        dn = ldb.Dn(samdb, s)
+        if dn.add_base(samdb.get_default_basedn()) == False:
+            raise DemoteException("Failed constructing DN %s by adding base" % \
+                                  (dn, samdb.get_default_basedn()))
+        if dn.add_child("CN=X") == False:
+            raise DemoteException("Failed constructing DN %s by adding child %s"\
+                                  % (dn, rdn))
+        dn.set_component(0, "CN", dc_name)
+
+        try:
+            logger.info("Removing Sysvol reference: %s" % dn)
+            samdb.delete(dn)
+        except ldb.LdbError as (enum, estr):
+            if enum == ldb.ERR_NO_SUCH_OBJECT:
+                pass
+            else:
+                raise
+
+
+def remove_dns_references(samdb, logger, dnsHostName):
+
+    # Check we are using in-database DNS
+    zones = samdb.search(base="", scope=ldb.SCOPE_SUBTREE,
+                         expression="(&(objectClass=dnsZone)(!(dc=RootDNSServers)))",
+                         attrs=[],
+                         controls=["search_options:0:2"])
+    if len(zones) == 0:
+        return
+
+    dnsHostNameUpper = dnsHostName.upper()
+
+    try:
+        primary_recs = samdb.dns_lookup(dnsHostName)
+    except RuntimeError as (enum, estr):
+        if enum == 0x000025F2: #WERR_DNS_ERROR_NAME_DOES_NOT_EXIST
+              return
+        raise DemoteException("lookup of %s failed: %s" % (dnsHostName, estr))
+    samdb.dns_replace(dnsHostName, [])
+
+    res = samdb.search("",
+                       scope=ldb.SCOPE_BASE, attrs=["namingContexts"])
+    assert len(res) == 1
+    ncs = res[0]["namingContexts"]
+
+    # Work out the set of names we will likely have an A record on by
+    # default.  This is by default all the partitions of type
+    # domainDNS.  By finding the canocial name of all the partitions,
+    # we find the likely candidates.  We only remove the record if it
+    # maches the IP that was used by the dnsHostName.  This avoids us
+    # needing to look a the dns_update_list file from in the demote
+    # script.
+
+    def dns_name_from_dn(dn):
+        # The canonical string of DC=example,DC=com is
+        # example.com/
+        #
+        # The canonical string of CN=Configuration,DC=example,DC=com
+        # is example.com/Configuration
+        return ldb.Dn(samdb, dn).canonical_str().split('/', 1)[0]
+
+    # By using a set here, duplicates via (eg) example.com/Configuration
+    # do not matter, they become just example.com
+    a_names_to_remove_from \
+        = set(dns_name_from_dn(dn) for dn in ncs)
+
+    def a_rec_to_remove(dnsRecord):
+        if dnsRecord.wType == DNS_TYPE_A or dnsRecord.wType == DNS_TYPE_AAAA:
+            for rec in primary_recs:
+                if rec.wType == dnsRecord.wType and rec.data == dnsRecord.data:
+                    return True
+        return False
+
+    for a_name in a_names_to_remove_from:
+        try:
+            logger.debug("checking for DNS records to remove on %s" % a_name)
+            a_recs = samdb.dns_lookup(a_name)
+        except RuntimeError as (enum, estr):
+            if enum == 0x000025F2: #WERR_DNS_ERROR_NAME_DOES_NOT_EXIST
+                return
+            raise DemoteException("lookup of %s failed: %s" % (a_name, estr))
+
+        orig_num_recs = len(a_recs)
+        a_recs = [ r for r in a_recs if not a_rec_to_remove(r) ]
+
+        if len(a_recs) != orig_num_recs:
+            logger.info("updating %s keeping %d values, removing %s values" % \
+                (a_name, len(a_recs), orig_num_recs - len(a_recs)))
+            samdb.dns_replace(a_name, a_recs)
+
+    # Find all the CNAME, NS, PTR and SRV records that point at the
+    # name we are removing
+
+    def to_remove(value):
+        dnsRecord = ndr_unpack(dnsp.DnssrvRpcRecord, value)
+        if dnsRecord.wType == DNS_TYPE_NS \
+           or dnsRecord.wType == DNS_TYPE_CNAME \
+           or dnsRecord.wType == DNS_TYPE_PTR:
+            if dnsRecord.data.upper() == dnsHostNameUpper:
+                return True
+        elif dnsRecord.wType == DNS_TYPE_SRV:
+            if dnsRecord.data.nameTarget.upper() == dnsHostNameUpper:
+                return True
+        return False
+
+    for zone in zones:
+        logger.debug("checking %s" % zone.dn)
+        records = samdb.search(base=zone.dn, scope=ldb.SCOPE_SUBTREE,
+                               expression="(&(objectClass=dnsNode)"
+                               "(!(dNSTombstoned=TRUE)))",
+                               attrs=["dnsRecord"])
+        for record in records:
+            try:
+                values = record["dnsRecord"]
+            except KeyError:
+                next
+            orig_num_values = len(values)
+
+            # Remove references to dnsHostName in A, AAAA, NS, CNAME and SRV
+            values = [ ndr_unpack(dnsp.DnssrvRpcRecord, v)
+                       for v in values if not to_remove(v) ]
+
+            if len(values) != orig_num_values:
+                logger.info("updating %s keeping %d values, removing %s values" \
+                            % (record.dn, len(values),
+                               orig_num_values - len(values)))
+
+                # This requires the values to be unpacked, so this
+                # has been done in the list comprehension above
+                samdb.dns_replace_by_dn(record.dn, values)
+
+def offline_remove_server(samdb, logger,
+                          server_dn,
+                          remove_computer_obj=False,
+                          remove_server_obj=False,
+                          remove_sysvol_obj=False,
+                          remove_dns_names=False,
+                          remove_dns_account=False):
+    res = samdb.search("",
+                       scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
+    assert len(res) == 1
+    my_serviceName = res[0]["dsServiceName"][0]
+
+    # Confirm this is really a server object
+    msgs = samdb.search(base=server_dn,
+                        attrs=["serverReference", "cn",
+                               "dnsHostName"],
+                        scope=ldb.SCOPE_BASE,
+                        expression="(objectClass=server)")
+    msg = msgs[0]
+    dc_name = str(msgs[0]["cn"][0])
+
+    try:
+        computer_dn = ldb.Dn(samdb, msgs[0]["serverReference"][0])
+    except KeyError:
+        computer_dn = None
+
+    try:
+        dnsHostName = msgs[0]["dnsHostName"][0]
+    except KeyError:
+        dnsHostName = None
+
+    if remove_server_obj:
+        # Remove the server DN
+        samdb.delete(server_dn)
+
+    if computer_dn is not None:
+        computer_msgs = samdb.search(base=computer_dn,
+                                     expression="objectclass=computer",
+                                     attrs=["msDS-KrbTgtLink",
+                                            "rIDSetReferences",
+                                            "cn"],
+                                     scope=ldb.SCOPE_BASE)
+        if "rIDSetReferences" in computer_msgs[0]:
+            rid_set_dn = str(computer_msgs[0]["rIDSetReferences"][0])
+            logger.info("Removing RID Set: %s" % rid_set_dn)
+            samdb.delete(rid_set_dn)
+        if "msDS-KrbTgtLink" in computer_msgs[0]:
+            krbtgt_link_dn = str(computer_msgs[0]["msDS-KrbTgtLink"][0])
+            logger.info("Removing RODC KDC account: %s" % krbtgt_link_dn)
+            samdb.delete(krbtgt_link_dn)
+
+        if remove_computer_obj:
+            # Delete the computer tree
+            logger.info("Removing computer account: %s (and any child objects)" % computer_dn)
+            samdb.delete(computer_dn, ["tree_delete:0"])
+
+        if "dnsHostName" in msgs[0]:
+            dnsHostName = msgs[0]["dnsHostName"][0]
+
+    if remove_dns_account:
+        res = samdb.search(expression="(&(objectclass=user)(cn=dns-%s)(servicePrincipalName=DNS/%s))" %
+                           (ldb.binary_encode(dc_name), dnsHostName),
+                           attrs=[], scope=ldb.SCOPE_SUBTREE,
+                           base=samdb.get_default_basedn())
+        if len(res) == 1:
+            logger.info("Removing Samba-specific DNS service account: %s" % res[0].dn)
+            samdb.delete(res[0].dn)
+
+    if dnsHostName is not None and remove_dns_names:
+        remove_dns_references(samdb, logger, dnsHostName)
+
+    if remove_sysvol_obj:
+        remove_sysvol_references(samdb, logger, dc_name)
+
+def offline_remove_ntds_dc(samdb,
+                           logger,
+                           ntds_dn,
+                           remove_computer_obj=False,
+                           remove_server_obj=False,
+                           remove_connection_obj=False,
+                           seize_stale_fsmo=False,
+                           remove_sysvol_obj=False,
+                           remove_dns_names=False,
+                           remove_dns_account=False):
+    res = samdb.search("",
+                       scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
+    assert len(res) == 1
+    my_serviceName = ldb.Dn(samdb, res[0]["dsServiceName"][0])
+    server_dn = ntds_dn.parent()
+
+    if my_serviceName == ntds_dn:
+        raise DemoteException("Refusing to demote our own DSA: %s " % my_serviceName)
+
+    try:
+        msgs = samdb.search(base=ntds_dn, expression="objectClass=ntdsDSA",
+                        attrs=["objectGUID"], scope=ldb.SCOPE_BASE)
+    except LdbError as (enum, estr):
+        if enum == ldb.ERR_NO_SUCH_OBJECT:
+              raise DemoteException("Given DN %s doesn't exist" % ntds_dn)
+        else:
+            raise
+    if (len(msgs) == 0):
+        raise DemoteException("%s is not an ntdsda in %s"
+                              % (ntds_dn, samdb.domain_dns_name()))
+
+    msg = msgs[0]
+    if (msg.dn.get_rdn_name() != "CN" or
+        msg.dn.get_rdn_value() != "NTDS Settings"):
+        raise DemoteException("Given DN (%s) wasn't the NTDS Settings DN" %
+                              ntds_dn)
+
+    ntds_guid = ndr_unpack(misc.GUID, msg["objectGUID"][0])
+
+    if remove_connection_obj:
+        # Find any nTDSConnection objects with that DC as the fromServer.
+        # We use the GUID to avoid issues with any () chars in a server
+        # name.
+        stale_connections = samdb.search(base=samdb.get_config_basedn(),
+                                         expression="(&(objectclass=nTDSConnection)"
+                                         "(fromServer=<GUID=%s>))" % ntds_guid)
+        for conn in stale_connections:
+            logger.info("Removing nTDSConnection: %s" % conn.dn)
+            samdb.delete(conn.dn)
+
+    if seize_stale_fsmo:
+        stale_fsmo_roles = samdb.search(base="", scope=ldb.SCOPE_SUBTREE,
+                                        expression="(fsmoRoleOwner=<GUID=%s>))"
+                                        % ntds_guid,
+                                        controls=["search_options:0:2"])
+        # Find any FSMO roles they have, give them to this server
+
+        for role in stale_fsmo_roles:
+            val = str(my_serviceName)
+            m = ldb.Message()
+            m.dn = role.dn
+            m['value'] = ldb.MessageElement(val, ldb.FLAG_MOD_REPLACE,
+                                            'fsmoRoleOwner')
+            logger.warning("Seizing FSMO role on: %s (now owned by %s)"
+                           % (role.dn, my_serviceName))
+            samdb.modify(m)
+
+    # Remove the NTDS setting tree
+    try:
+        logger.info("Removing nTDSDSA: %s (and any children)" % ntds_dn)
+        samdb.delete(ntds_dn, ["tree_delete:0"])
+    except LdbError as (enum, estr):
+        raise DemoteException("Failed to remove the DCs NTDS DSA object: %s"
+                              % estr)
+
+    offline_remove_server(samdb, logger, server_dn,
+                          remove_computer_obj=remove_computer_obj,
+                          remove_server_obj=remove_server_obj,
+                          remove_sysvol_obj=remove_sysvol_obj,
+                          remove_dns_names=remove_dns_names,
+                          remove_dns_account=remove_dns_account)
+
+
+def remove_dc(samdb, logger, dc_name):
+
+    # TODO: Check if this is the last server (covered mostly by
+    # refusing to remove our own name)
+
+    samdb.transaction_start()
+
+    server_dn = None
+
+    # Allow the name to be a the nTDS-DSA GUID
+    try:
+        ntds_guid = uuid.UUID(hex=dc_name)
+        ntds_dn = "<GUID=%s>" % ntds_guid
+    except ValueError:
+        try:
+            server_msgs = samdb.search(base=samdb.get_config_basedn(),
+                                       attrs=[],
+                                       expression="(&(objectClass=server)"
+                                       "(cn=%s))"
+                                    % ldb.binary_encode(dc_name))
+        except LdbError as (enum, estr):
+            raise DemoteException("Failure checking if %s is an server "
+                                  "object in %s: "
+                                  % (dc_name, samdb.domain_dns_name()), estr)
+
+        if (len(server_msgs) == 0):
+            raise DemoteException("%s is not an AD DC in %s"
+                                  % (dc_name, samdb.domain_dns_name()))
+        server_dn = server_msgs[0].dn
+
+        ntds_dn = ldb.Dn(samdb, "CN=NTDS Settings")
+        ntds_dn.add_base(server_dn)
+        pass
+
+    # Confirm this is really an ntdsDSA object
+    try:
+        ntds_msgs = samdb.search(base=ntds_dn, attrs=[], scope=ldb.SCOPE_BASE,
+                                 expression="(objectClass=ntdsdsa)")
+    except LdbError as (enum, estr):
+        if enum == ldb.ERR_NO_SUCH_OBJECT:
+            ntds_msgs = []
+            pass
+        else:
+            raise DemoteException("Failure checking if %s is an NTDS DSA in %s: "
+                                  % (ntds_dn, samdb.domain_dns_name()), estr)
+
+    # If the NTDS Settings child DN wasn't found or wasnt an ntdsDSA
+    # object, just remove the server object located above
+    if (len(ntds_msgs) == 0):
+        if server_dn is None:
+            raise DemoteException("%s is not an AD DC in %s"
+                                  % (dc_name, samdb.domain_dns_name()))
+
+        offline_remove_server(samdb, logger,
+                              server_dn,
+                              remove_computer_obj=True,
+                              remove_server_obj=True,
+                              remove_sysvol_obj=True,
+                              remove_dns_names=True,
+                              remove_dns_account=True)
+    else:
+        offline_remove_ntds_dc(samdb, logger,
+                               ntds_msgs[0].dn,
+                               remove_computer_obj=True,
+                               remove_server_obj=True,
+                               remove_connection_obj=True,
+                               seize_stale_fsmo=True,
+                               remove_sysvol_obj=True,
+                               remove_dns_names=True,
+                               remove_dns_account=True)
+
+    samdb.transaction_commit()
+
+
+
+def offline_remove_dc_RemoveDsServer(samdb, ntds_dn):
+
+    samdb.start_transaction()
+
+    offline_remove_ntds_dc(samdb, ntds_dn, None)
+
+    samdb.commit_transaction()
diff --git a/python/samba/samdb.py b/python/samba/samdb.py
index 817fbdb..5750291 100644
--- a/python/samba/samdb.py
+++ b/python/samba/samdb.py
@@ -27,7 +27,7 @@ import ldb
 import time
 import base64
 import os
-from samba import dsdb
+from samba import dsdb, dsdb_dns
 from samba.ndr import ndr_unpack, ndr_pack
 from samba.dcerpc import drsblobs, misc
 from samba.common import normalise_int32
@@ -921,3 +921,26 @@ accountExpires: %u
         '''get the server DN from the rootDSE'''
         res = self.search(base="", scope=ldb.SCOPE_BASE, attrs=["serverName"])
         return res[0]["serverName"][0]
+
+    def dns_lookup(self, dns_name):
+        '''Do a DNS lookup in the database, returns the NDR database structures'''
+        return dsdb_dns.lookup(self, dns_name)
+
+    def dns_extract(self, el):
+        '''Return the NDR database structures from a dnsRecord element'''
+        return dsdb_dns.extract(el)
+
+    def dns_replace(self, dns_name, new_records):
+        '''Do a DNS modification on the database, sets the NDR database
+        structures on a DNS name
+        '''
+        return dsdb_dns.replace(self, dns_name, new_records)
+
+    def dns_replace_by_dn(self, dn, new_records):
+        '''Do a DNS modification on the database, sets the NDR database
+        structures on a LDB DN
+
+        This routine is important because if the last record on the DN
+        is removed, this routine will put a tombstone in the record.
+        '''
+        return dsdb_dns.replace_by_dn(self, dn, new_records)
diff --git a/python/samba/sites.py b/python/samba/sites.py
index 76c57dd..7111cfa 100644
--- a/python/samba/sites.py
+++ b/python/samba/sites.py
@@ -18,7 +18,7 @@
 """Manipulating sites."""
 
 import ldb
-from ldb import FLAG_MOD_ADD
+from ldb import FLAG_MOD_ADD, LdbError
 
 
 class SiteException(Exception):
@@ -28,35 +28,20 @@ class SiteException(Exception):
         self.value = value
 
     def __str__(self):
-        return "SiteException: " + self.value
+        return "%s: %s" % (self.__class__.__name__, self.value)
 
 
 class SiteNotFoundException(SiteException):
     """Raised when the site is not found and it's expected to exists."""
 
-    def __init__(self, value):
-        self.value = value
-
-    def __str__(self):
-        return "SiteNotFoundException: " + self.value
 
 class SiteAlreadyExistsException(SiteException):
     """Raised when the site is not found and it's expected not to exists."""
 
-    def __init__(self, value):
-        self.value = value
-
-    def __str__(self):
-        return "SiteAlreadyExists: " + self.value
 
 class SiteServerNotEmptyException(SiteException):
     """Raised when the site still has servers attached."""
 
-    def __init__(self, value):
-        self.value = value
-
-    def __str__(self):
-        return "SiteServerNotEmpty: " + self.value
 
 def create_site(samdb, configDn, siteName):
     """
@@ -94,6 +79,7 @@ def create_site(samdb, configDn, siteName):
 
     return True
 
+
 def delete_site(samdb, configDn, siteName):
     """
     Delete a site
@@ -106,17 +92,27 @@ def delete_site(samdb, configDn, siteName):
     :raise SiteServerNotEmpty: if the site has still servers in it.
     """
 
-    dnsites = ldb.Dn(samdb, "CN=Sites,%s" % (str(configDn)))
-    dnsite = ldb.Dn(samdb, "Cn=%s,CN=Sites,%s" % (siteName, str(configDn)))
-    dnserver = ldb.Dn(samdb, "Cn=Servers,%s" % str(dnsite))
-
-    ret = samdb.search(base=dnsites, scope=ldb.SCOPE_ONELEVEL,
-                    expression='(dn=%s)' % str(dnsite))
-    if len(ret) != 1:
-        raise SiteNotFoundException('Site %s do not exists' % siteName)
-
-    ret = samdb.search(base=dnserver, scope=ldb.SCOPE_ONELEVEL,
-                    expression='(objectclass=server)')
+    dnsite = ldb.Dn(samdb, "CN=Sites")
+    if dnsite.add_base(configDn) == False:
+        raise SiteException("dnsites.add_base() failed")
+    if dnsite.add_child("CN=X") == False:
+        raise SiteException("dnsites.add_child() failed")
+    dnsite.set_component(0, "CN", siteName)
+
+    dnservers = ldb.Dn(samdb, "CN=Servers")
+    dnservers.add_base(dnsite)
+
+    try:
+        ret = samdb.search(base=dnsite, scope=ldb.SCOPE_BASE,
+                           expression="objectClass=site")
+        if len(ret) != 1:
+            raise SiteNotFoundException('Site %s does not exist' % siteName)
+    except LdbError as (enum, estr):
+        if enum == ldb.ERR_NO_SUCH_OBJECT:
+            raise SiteNotFoundException('Site %s does not exist' % siteName)
+
+    ret = samdb.search(base=dnservers, scope=ldb.SCOPE_ONELEVEL,
+                       expression='(objectclass=server)')
     if len(ret) != 0:
         raise SiteServerNotEmptyException('Site %s still has servers in it, move them before removal' % siteName)
 
diff --git a/python/samba/subnets.py b/python/samba/subnets.py
new file mode 100644
index 0000000..e859f06
--- /dev/null
+++ b/python/samba/subnets.py
@@ -0,0 +1,186 @@
+# Add/remove subnets to sites.
+#
+# Copyright (C) Catalyst.Net Ltd 2015
+# Copyright Matthieu Patou <mat at matws.net> 2011
+#
+# Catalyst.Net's contribution was written by Douglas Bagnall
+# <douglas.bagnall at catalyst.net.nz>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import ldb
+from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, LdbError
+from sites import SiteNotFoundException
+
+class SubnetException(Exception):
+    """Base element for Subnet errors"""
+    pass
+
+
+class SubnetNotFound(SubnetException):
+    """The subnet requested does not exist."""
+    pass
+
+
+class SubnetAlreadyExists(SubnetException):
+    """The subnet being added already exists."""
+    pass
+
+
+class SubnetInvalid(SubnetException):
+    """The subnet CIDR is invalid."""
+    pass
+
+
+class SiteNotFound(SubnetException):
+    """The site to be used for the subnet does not exist."""
+    pass
+
+
+def create_subnet(samdb, configDn, subnet_name, site_name):
+    """Create a subnet and associate it with a site.
+
+    :param samdb: A samdb connection
+    :param configDn: The DN of the configuration partition
+    :param subnet_name: name of the subnet to create (a CIDR range)
+    :return: None
+    :raise SubnetAlreadyExists: if the subnet to be created already exists.
+    :raise SiteNotFound: if the site does not exist.
+    """
+    ret = samdb.search(base=configDn, scope=ldb.SCOPE_SUBTREE,
+                       expression='(&(objectclass=Site)(cn=%s))' %
+                       ldb.binary_encode(site_name))
+    if len(ret) != 1:
+        raise SiteNotFound('A site with the name %s does not exist' %
+                           site_name)
+    dn_site = ret[0].dn
+
+    if not isinstance(subnet_name, str):
+        raise SubnetInvalid("%s is not a valid subnet (not a string)" % subnet_name)
+
+    dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
+    if dnsubnet.add_base(configDn) == False:
+        raise SubnetException("dnsubnet.add_base() failed")
+    if dnsubnet.add_child("CN=X") == False:
+        raise SubnetException("dnsubnet.add_child() failed")
+    dnsubnet.set_component(0, "CN", subnet_name)
+
+    try:
+        m = ldb.Message()
+        m.dn = dnsubnet
+        m["objectclass"] = ldb.MessageElement("subnet", FLAG_MOD_ADD,
+                                              "objectclass")
+        m["siteObject"] = ldb.MessageElement(str(dn_site), FLAG_MOD_ADD,
+                                             "siteObject")
+        samdb.add(m)
+    except ldb.LdbError as (enum, estr):
+        if enum == ldb.ERR_INVALID_DN_SYNTAX:
+            raise SubnetInvalid("%s is not a valid subnet: %s" % (subnet_name, estr))
+        elif enum == ldb.ERR_ENTRY_ALREADY_EXISTS:
+            # Subnet collisions are checked by exact match only, not
+            # overlapping range. This won't stop you creating
+            # 10.1.1.0/24 when there is already 10.1.0.0/16, or
+            # prevent you from having numerous IPv6 subnets that refer
+            # to the same range (e.g 5::0/16, 5::/16, 5:0:0::/16).
+            raise SubnetAlreadyExists('A subnet with the CIDR %s already exists'
+                                      % subnet_name)
+        else:
+            raise
+
+
+def delete_subnet(samdb, configDn, subnet_name):
+    """Delete a subnet.
+
+    :param samdb: A samdb connection
+    :param configDn: The DN of the configuration partition
+    :param subnet_name: Name of the subnet to delete
+    :return: None
+    :raise SubnetNotFound: if the subnet to be deleted does not exist.
+    """
+    dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
+    if dnsubnet.add_base(configDn) == False:
+        raise SubnetException("dnsubnet.add_base() failed")
+    if dnsubnet.add_child("CN=X") == False:
+        raise SubnetException("dnsubnet.add_child() failed")
+    dnsubnet.set_component(0, "CN", subnet_name)
+
+    try:
+        ret = samdb.search(base=dnsubnet, scope=ldb.SCOPE_BASE,
+                           expression="objectClass=subnet")
+        if len(ret) != 1:
+            raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
+    except LdbError as (enum, estr):
+        if enum == ldb.ERR_NO_SUCH_OBJECT:
+            raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
+
+    samdb.delete(dnsubnet)
+
+
+def set_subnet_site(samdb, configDn, subnet_name, site_name):
+    """Assign a subnet to a site.
+
+    This dissociates the subnet from its previous site.
+
+    :param samdb: A samdb connection
+    :param configDn: The DN of the configuration partition
+    :param subnet_name: Name of the subnet
+    :param site_name: Name of the site
+    :return: None
+    :raise SubnetNotFound: if the subnet does not exist.
+    :raise SiteNotFound: if the site does not exist.
+    """
+
+    dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
+    if dnsubnet.add_base(configDn) == False:
+        raise SubnetException("dnsubnet.add_base() failed")
+    if dnsubnet.add_child("CN=X") == False:
+        raise SubnetException("dnsubnet.add_child() failed")
+    dnsubnet.set_component(0, "CN", subnet_name)
+
+    try:
+        ret = samdb.search(base=dnsubnet, scope=ldb.SCOPE_BASE,
+                           expression="objectClass=subnet")
+        if len(ret) != 1:
+            raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
+    except LdbError as (enum, estr):
+        if enum == ldb.ERR_NO_SUCH_OBJECT:
+            raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
+
+    dnsite = ldb.Dn(samdb, "CN=Sites")
+    if dnsite.add_base(configDn) == False:
+        raise SubnetException("dnsites.add_base() failed")
+    if dnsite.add_child("CN=X") == False:
+        raise SubnetException("dnsites.add_child() failed")
+    dnsite.set_component(0, "CN", site_name)
+
+    dnservers = ldb.Dn(samdb, "CN=Servers")
+    dnservers.add_base(dnsite)
+
+    try:
+        ret = samdb.search(base=dnsite, scope=ldb.SCOPE_BASE,
+                           expression="objectClass=site")
+        if len(ret) != 1:
+            raise SiteNotFoundException('Site %s does not exist' % site_name)
+    except LdbError as (enum, estr):
+        if enum == ldb.ERR_NO_SUCH_OBJECT:
+            raise SiteNotFoundException('Site %s does not exist' % site_name)
+
+    siteDn = str(ret[0].dn)
+
+    m = ldb.Message()
+    m.dn = dnsubnet
+    m["siteObject"] = ldb.MessageElement(siteDn, FLAG_MOD_REPLACE,
+                                         "siteObject")
+    samdb.modify(m)
diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index b53c4ea..87b6943 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -253,7 +253,7 @@ class BlackboxProcessError(Exception):
         return "Command '%s'; exit status %d; stdout: '%s'; stderr: '%s'" % (self.cmd, self.returncode,
                                                                              self.stdout, self.stderr)
 
-class BlackboxTestCase(TestCase):
+class BlackboxTestCase(TestCaseInTempDir):
     """Base test case for blackbox tests."""
 
     def _make_cmdline(self, line):
diff --git a/python/samba/tests/blackbox/samba_tool_drs.py b/python/samba/tests/blackbox/samba_tool_drs.py
index 9b7106f..6056645 100644
--- a/python/samba/tests/blackbox/samba_tool_drs.py
+++ b/python/samba/tests/blackbox/samba_tool_drs.py
@@ -18,7 +18,9 @@
 """Blackbox tests for samba-tool drs."""
 
 import samba.tests
-
+import shutil
+import os
+import ldb
 
 class SambaToolDrsTests(samba.tests.BlackboxTestCase):
     """Blackbox test case for samba-tool drs."""
@@ -33,10 +35,10 @@ class SambaToolDrsTests(samba.tests.BlackboxTestCase):
         self.cmdline_creds = "-U%s/%s%%%s" % (creds.get_domain(),
                                               creds.get_username(), creds.get_password())
 
-    def _get_rootDSE(self, dc):
+    def _get_rootDSE(self, dc, ldap_only=True):
         samdb = samba.tests.connect_samdb(dc, lp=self.get_loadparm(),
                                           credentials=self.get_credentials(),
-                                          ldap_only=True)
+                                          ldap_only=ldap_only)
         return samdb.search(base="", scope=samba.tests.ldb.SCOPE_BASE)[0]
 
     def test_samba_tool_bind(self):
@@ -100,3 +102,164 @@ class SambaToolDrsTests(samba.tests.BlackboxTestCase):
                                                                           self.cmdline_creds))
         self.assertTrue("Replicate from" in out)
         self.assertTrue("was successful" in out)
+
+    def test_samba_tool_drs_clone_dc(self):
+        """Tests 'samba-tool drs clone-dc-database' command."""
+        server_rootdse = self._get_rootDSE(self.dc1)
+        server_nc_name = server_rootdse["defaultNamingContext"]
+        server_ds_name = server_rootdse["dsServiceName"]
+        server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+        server_realm = server_ldap_service_name.split(":")[0]
+        creds = self.get_credentials()
+        out = self.check_output("samba-tool drs clone-dc-database %s --server=%s %s --targetdir=%s"
+                                % (server_realm,
+                                   self.dc1,
+                                   self.cmdline_creds,
+                                   self.tempdir))
+        ldb_rootdse = self._get_rootDSE("tdb://" + os.path.join(self.tempdir, "private", "sam.ldb"), ldap_only=False)
+        nc_name = ldb_rootdse["defaultNamingContext"]
+        ds_name = ldb_rootdse["dsServiceName"]
+        ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+        self.assertEqual(nc_name, server_nc_name)
+        # The clone should pretend to be the source server
+        self.assertEqual(ds_name, server_ds_name)
+        self.assertEqual(ldap_service_name, server_ldap_service_name)
+
+        samdb = samba.tests.connect_samdb("tdb://" + os.path.join(self.tempdir, "private", "sam.ldb"),
+                                          ldap_only=False, lp=self.get_loadparm())
+        def get_krbtgt_pw():
+            krbtgt_pw = samdb.searchone("unicodePwd", "cn=krbtgt,CN=users,%s" % nc_name)
+        self.assertRaises(KeyError, get_krbtgt_pw)
+
+        server_dn = samdb.searchone("serverReferenceBL", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name))
+        ntds_guid = samdb.searchone("objectGUID", "cn=ntds settings,%s" % server_dn)
+
+        res = samdb.search(base=str(server_nc_name),
+                           expression="(&(objectclass=user)(cn=dns-%s))" % (self.dc2),
+                           attrs=[], scope=ldb.SCOPE_SUBTREE)
+        if len(res) == 1:
+            dns_obj = res[0]
+        else:
+            dns_obj = None
+
+        # While we have this cloned, try demoting the other server on the clone, by GUID
+        out = self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H %s/private/sam.ldb"
+                                % (ntds_guid,
+                                   self.tempdir))
+
+        # Check some of the objects that should have been removed
+        def check_machine_obj():
+            samdb.searchone("CN", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name))
+        self.assertRaises(ldb.LdbError, check_machine_obj)
+
+        def check_server_obj():
+            samdb.searchone("CN", server_dn)
+        self.assertRaises(ldb.LdbError, check_server_obj)
+
+        def check_ntds_guid():
+            samdb.searchone("CN", "<GUID=%s>" % ntds_guid)
+        self.assertRaises(ldb.LdbError, check_ntds_guid)
+
+        if dns_obj is not None:
+            # Check some of the objects that should have been removed
+            def check_dns_account_obj():
+                samdb.search(base=dns_obj.dn, scope=ldb.SCOPE_BASE,
+                             attrs=[])
+            self.assertRaises(ldb.LdbError, check_dns_account_obj)
+
+        shutil.rmtree(os.path.join(self.tempdir, "private"))
+        shutil.rmtree(os.path.join(self.tempdir, "etc"))
+        shutil.rmtree(os.path.join(self.tempdir, "msg.lock"))
+        os.remove(os.path.join(self.tempdir, "names.tdb"))
+        shutil.rmtree(os.path.join(self.tempdir, "state"))
+
+    def test_samba_tool_drs_clone_dc_secrets(self):
+        """Tests 'samba-tool drs clone-dc-database --include-secrets' command ."""
+        server_rootdse = self._get_rootDSE(self.dc1)
+        server_nc_name = server_rootdse["defaultNamingContext"]
+        server_ds_name = server_rootdse["dsServiceName"]
+        server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+        server_realm = server_ldap_service_name.split(":")[0]
+        creds = self.get_credentials()
+        out = self.check_output("samba-tool drs clone-dc-database %s --server=%s %s --targetdir=%s --include-secrets"
+                                % (server_realm,
+                                   self.dc1,
+                                   self.cmdline_creds,
+                                   self.tempdir))
+        ldb_rootdse = self._get_rootDSE("tdb://" + os.path.join(self.tempdir, "private", "sam.ldb"), ldap_only=False)
+        nc_name = ldb_rootdse["defaultNamingContext"]
+        config_nc_name = ldb_rootdse["configurationNamingContext"]
+        ds_name = ldb_rootdse["dsServiceName"]
+        ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+
+        samdb = samba.tests.connect_samdb("tdb://" + os.path.join(self.tempdir, "private", "sam.ldb"),
+                                          ldap_only=False, lp=self.get_loadparm())
+        krbtgt_pw = samdb.searchone("unicodePwd", "cn=krbtgt,CN=users,%s" % nc_name)
+        self.assertIsNotNone(krbtgt_pw)
+
+        self.assertEqual(nc_name, server_nc_name)
+        # The clone should pretend to be the source server
+        self.assertEqual(ds_name, server_ds_name)
+        self.assertEqual(ldap_service_name, server_ldap_service_name)
+
+        server_dn = samdb.searchone("serverReferenceBL", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name))
+        ntds_guid = samdb.searchone("objectGUID", "cn=ntds settings,%s" % server_dn)
+
+        res = samdb.search(base=str(server_nc_name),
+                           expression="(&(objectclass=user)(cn=dns-%s))" % (self.dc2),
+                           attrs=[], scope=ldb.SCOPE_SUBTREE)
+        if len(res) == 1:
+            dns_obj = res[0]
+        else:
+            dns_obj = None
+
+        def demote_self():
+            # While we have this cloned, try demoting the other server on the clone
+            out = self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H %s/private/sam.ldb"
+                                % (self.dc1,
+                                   self.tempdir))
+        self.assertRaises(samba.tests.BlackboxProcessError, demote_self)
+
+        # While we have this cloned, try demoting the other server on the clone
+        out = self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H %s/private/sam.ldb"
+                                % (self.dc2,
+                                   self.tempdir))
+
+        # Check some of the objects that should have been removed
+        def check_machine_obj():
+            samdb.searchone("CN", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name))
+        self.assertRaises(ldb.LdbError, check_machine_obj)
+
+        def check_server_obj():
+            samdb.searchone("CN", server_dn)
+        self.assertRaises(ldb.LdbError, check_server_obj)
+
+        def check_ntds_guid():
+            samdb.searchone("CN", "<GUID=%s>" % ntds_guid)
+        self.assertRaises(ldb.LdbError, check_ntds_guid)
+
+        if dns_obj is not None:
+            # Check some of the objects that should have been removed
+            def check_dns_account_obj():
+                samdb.search(base=dns_obj.dn, scope=ldb.SCOPE_BASE,
+                             attrs=[])
+            self.assertRaises(ldb.LdbError, check_dns_account_obj)
+
+        shutil.rmtree(os.path.join(self.tempdir, "private"))
+        shutil.rmtree(os.path.join(self.tempdir, "etc"))
+        shutil.rmtree(os.path.join(self.tempdir, "msg.lock"))
+        os.remove(os.path.join(self.tempdir, "names.tdb"))
+        shutil.rmtree(os.path.join(self.tempdir, "state"))
+
+    def test_samba_tool_drs_clone_dc_secrets_without_targetdir(self):
+        """Tests 'samba-tool drs clone-dc-database' command without --targetdir."""
+        server_rootdse = self._get_rootDSE(self.dc1)
+        server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+        server_realm = server_ldap_service_name.split(":")[0]
+        creds = self.get_credentials()
+        def attempt_clone():
+            out = self.check_output("samba-tool drs clone-dc-database %s --server=%s %s"
+                                    % (server_realm,
+                                       self.dc1,
+                                       self.cmdline_creds))
+        self.assertRaises(samba.tests.BlackboxProcessError, attempt_clone)
diff --git a/python/samba/tests/dcerpc/array.py b/python/samba/tests/dcerpc/array.py
new file mode 100644
index 0000000..80c53c6
--- /dev/null
+++ b/python/samba/tests/dcerpc/array.py
@@ -0,0 +1,171 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Andrew Bartlett <abartlet at samba.org> 2016
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""Tests for array handling in PIDL generated bindings samba.dcerpc.*"""
+
+from samba.dcerpc import drsblobs
+import samba.tests
+from samba.ndr import ndr_unpack, ndr_pack
+import talloc
+import gc
+
+class ArrayTests(samba.tests.TestCase):
+
+    def setUp(self):
+        super(ArrayTests, self).setUp()
+        talloc.enable_null_tracking()
+        self.startup_blocks = talloc.total_blocks()
+
+    def tearDown(self):
+        super(ArrayTests, self).tearDown()
+        self.assertEqual(talloc.total_blocks(), self.startup_blocks)
+        talloc.report_full()
+
+    def test_array_from_python(self):
+        rmd = drsblobs.replPropertyMetaDataBlob()
+
+        rmd.version = 1
+        rmd.ctr = drsblobs.replPropertyMetaDataCtr1()
+        rmd.ctr.count = 3
+
+        rmd1 = drsblobs.replPropertyMetaData1()
+        rmd1.attid = 1
+        rmd1.version = 2
+
+        rmd2 = drsblobs.replPropertyMetaData1()
+        rmd2.attid = 2
+        rmd2.version = 2
+
+        rmd3 = drsblobs.replPropertyMetaData1()
+        rmd3.attid = 3
+        rmd3.version = 2
+
+        rmd.ctr.array = [rmd1, rmd2, rmd3]
+        gc.collect()
+
+        self.assertIsNotNone(rmd)
+        self.assertEqual(rmd.version, 1)
+        self.assertIsNotNone(rmd.ctr)
+        self.assertEqual(rmd.ctr.count, 3)
+        self.assertEqual(len(rmd.ctr.array), rmd.ctr.count)
+        self.assertIsNotNone(rmd.ctr.array[0])
+        self.assertEqual(rmd.ctr.array[0].attid, 1)
+
+    def test_array_with_exception(self):
+        try:
+            rmd = drsblobs.replPropertyMetaDataBlob()
+
+            rmd.version = 1
+            rmd.ctr = drsblobs.replPropertyMetaDataCtr1()
+            rmd.ctr.count = 3
+
+            rmd1 = drsblobs.replPropertyMetaData1()
+            rmd1.attid = 1
+            rmd1.version = 2
+
+            rmd2 = drsblobs.replPropertyMetaData1()
+            rmd2.attid = 2
+            rmd2.version = 2
+
+            rmd3 = drsblobs.replPropertyMetaData1()
+            rmd3.attid = 3
+            rmd3.version = 2
+
+            rmd.ctr.array = [rmd1, rmd2, rmd3]
+
+            gc.collect()
+
+            self.assertIsNotNone(rmd)
+            self.assertEqual(rmd.version, 1)
+            self.assertIsNotNone(rmd.ctr)
+            self.assertEqual(rmd.ctr.count, 3)
+            self.assertEqual(len(rmd.ctr.array), rmd.ctr.count)
+            self.assertIsNotNone(rmd.ctr.array[0])
+            self.assertEqual(rmd.ctr.array[0].attid, 1)
+
+            raise Exception()
+        except:
+            pass
+
+    def test_array_from_python_function(self):
+        def get_rmd():
+            rmd = drsblobs.replPropertyMetaDataBlob()
+
+            rmd.version = 1
+            rmd.ctr = drsblobs.replPropertyMetaDataCtr1()
+            rmd.ctr.count = 3
+
+            rmd1 = drsblobs.replPropertyMetaData1()
+            rmd1.attid = 1
+            rmd1.version = 2
+
+            rmd2 = drsblobs.replPropertyMetaData1()
+            rmd2.attid = 2
+            rmd2.version = 2
+
+            rmd3 = drsblobs.replPropertyMetaData1()
+            rmd3.attid = 3
+            rmd3.version = 2
+
+            rmd.ctr.array = [rmd1, rmd2, rmd3]
+            return rmd
+
+        rmd = get_rmd()
+        gc.collect()
+        self.assertIsNotNone(rmd)
+        self.assertEqual(rmd.version, 1)
+        self.assertIsNotNone(rmd.ctr)
+        self.assertEqual(rmd.ctr.count, 3)
+        self.assertEqual(len(rmd.ctr.array), rmd.ctr.count)
+        self.assertIsNotNone(rmd.ctr.array[0])
+        self.assertEqual(rmd.ctr.array[0].attid, 1)
+
+    def test_array_from_ndr(self):
+        rmd = drsblobs.replPropertyMetaDataBlob()
+
+        rmd.version = 1
+        rmd.ctr = drsblobs.replPropertyMetaDataCtr1()
+        rmd.ctr.count = 3
+
+        rmd1 = drsblobs.replPropertyMetaData1()
+        rmd1.attid = 1
+        rmd1.version = 2
+
+        rmd2 = drsblobs.replPropertyMetaData1()
+        rmd2.attid = 2
+        rmd2.version = 2
+
+        rmd3 = drsblobs.replPropertyMetaData1()
+        rmd3.attid = 3
+        rmd3.version = 2
+
+        rmd.ctr.array = [rmd1, rmd2, rmd3]
+
+        packed = ndr_pack(rmd)
+        gc.collect()
+
+        rmd_unpacked = ndr_unpack(drsblobs.replPropertyMetaDataBlob, packed)
+        self.assertIsNotNone(rmd_unpacked)
+        self.assertEqual(rmd_unpacked.version, 1)
+        self.assertIsNotNone(rmd_unpacked.ctr)
+        self.assertEqual(rmd_unpacked.ctr.count, 3)
+        self.assertEqual(len(rmd_unpacked.ctr.array), rmd_unpacked.ctr.count)
+        self.assertIsNotNone(rmd_unpacked.ctr.array[0])
+        self.assertEqual(rmd_unpacked.ctr.array[0].attid, 1)
+
+        self.assertEqual(rmd.ctr.array[0].attid,
+                         rmd_unpacked.ctr.array[0].attid)
diff --git a/python/samba/tests/dcerpc/rpc_talloc.py b/python/samba/tests/dcerpc/rpc_talloc.py
index b1e2741..191e70c 100644
--- a/python/samba/tests/dcerpc/rpc_talloc.py
+++ b/python/samba/tests/dcerpc/rpc_talloc.py
@@ -51,25 +51,27 @@ class TallocTests(samba.tests.TestCase):
         '''get a list of attributes for RODC replication'''
         partial_attribute_set = drsuapi.DsPartialAttributeSet()
 
-        # we expect one block for the object, and one for the structure
-        self.check_blocks(partial_attribute_set, 2)
+        # we expect one block for the object
+        self.check_blocks(partial_attribute_set, 1)
 
         attids = [1, 2, 3]
         partial_attribute_set.version = 1
         partial_attribute_set.attids     = attids
         partial_attribute_set.num_attids = len(attids)
 
-        # we expect one block object, a structure, an ARRAY, and a
+        # we expect one block for the object, a structure, and a
         # reference to the array
-        self.check_blocks(partial_attribute_set, 3)
+        self.check_blocks(partial_attribute_set, 2)
 
         return partial_attribute_set
 
     def pas_test(self):
         pas = self.get_rodc_partial_attribute_set()
-        self.check_blocks(pas, 3)
+        self.check_blocks(pas, 2)
         req8 = drsuapi.DsGetNCChangesRequest8()
-        self.check_blocks(req8, 2)
+        self.check_blocks(req8, 1)
+
+        # We expect the pas and req8, plus one block for each python object
         self.check_blocks(None, 5)
         req8.partial_attribute_set = pas
         if req8.partial_attribute_set.attids[1] != 2:
diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py
index e0739d0..048cd03 100644
--- a/python/samba/tests/dns.py
+++ b/python/samba/tests/dns.py
@@ -352,23 +352,23 @@ class TestSimpleQueries(DNSTest):
             # request is formatted.
             pass
 
-# Only returns an authority section entry in BIND and Win DNS
-# FIXME: Enable one Samba implements this feature
-#    def test_soa_hostname_query(self):
-#        "create a SOA query for a hostname"
-#        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
-#        questions = []
-#
-#        name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
-#        q = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
-#        questions.append(q)
-#
-#        self.finish_name_packet(p, questions)
-#        response = self.dns_transaction_udp(p)
-#        self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
-#        self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
-#        # We don't get SOA records for single hosts
-#        self.assertEquals(response.ancount, 0)
+    def test_soa_hostname_query(self):
+        "create a SOA query for a hostname"
+        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
+        questions = []
+
+        name = "%s.%s" % (self.server, self.get_dns_domain())
+        q = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
+        questions.append(q)
+
+        self.finish_name_packet(p, questions)
+        response = self.dns_transaction_udp(p)
+        self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+        self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
+        # We don't get SOA records for single hosts
+        self.assertEquals(response.ancount, 0)
+        # But we do respond with an authority section
+        self.assertEqual(response.nscount, 1)
 
     def test_soa_domain_query(self):
         "create a SOA query for a domain"
diff --git a/python/samba/tests/docs.py b/python/samba/tests/docs.py
index 1b9b94a..e7123b6 100644
--- a/python/samba/tests/docs.py
+++ b/python/samba/tests/docs.py
@@ -31,6 +31,7 @@ class TestCase(samba.tests.TestCaseInTempDir):
 
     def _format_message(self, parameters, message):
         parameters = list(parameters)
+        parameters = map(str, parameters)
         parameters.sort()
         return message + '\n\n    %s' % ('\n    '.join(parameters))
 
@@ -58,9 +59,9 @@ def get_documented_parameters(sourcedir):
     p.close()
 
 
-def get_implementation_parameters(sourcedir):
+def get_param_table_full(sourcedir, filename="lib/param/param_table_static.c"):
     # Reading entries from source code
-    f = open(os.path.join(sourcedir, "lib/param/param_table.c"), "r")
+    f = open(os.path.join(sourcedir, filename), "r")
     try:
         # burn through the preceding lines
         while True:
@@ -69,18 +70,53 @@ def get_implementation_parameters(sourcedir):
                 break
 
         for l in f.readlines():
+
             if re.match("^\s*\}\;\s*$", l):
+                # end of the table reached
                 break
-            # pull in the param names only
-            m = re.match("\s*\.label\s*=\s*\"(.*)\".*", l)
+
+            if re.match("^\s*\{\s*$", l):
+                # start a new entry
+                _label = ""
+                _type = ""
+                _class = ""
+                _offset = ""
+                _special = ""
+                _enum_list = ""
+                _flags = ""
+                continue
+
+            if re.match("^\s*\},\s*$", l):
+                # finish the entry
+                yield _label, _type, _class, _offset, _special, _enum_list, _flags
+                continue
+
+            m = re.match("^\s*\.([^\s]+)\s*=\s*(.*),.*", l)
             if not m:
                 continue
 
-            name = m.group(1)
-            yield name
+            attrib = m.group(1)
+            value = m.group(2)
+
+            if attrib == "label":
+                _label = value
+            elif attrib == "type":
+                _type = value
+            elif attrib == "p_class":
+                _class = value
+            elif attrib == "offset":
+                _offset = value
+            elif attrib == "special":
+                _special = value
+            elif attrib == "enum_list":
+                _special = value
+            elif attrib == "flags":
+                _flags = value
+
     finally:
         f.close()
 
+
 def get_documented_tuples(sourcedir, omit_no_default=True):
     path = os.path.join(sourcedir, "bin", "default", "docs-xml", "smbdotconf")
     if not os.path.exists(os.path.join(path, "parameters.all.xml")):
@@ -151,37 +187,34 @@ class SmbDotConfTests(TestCase):
         finally:
             f.close()
 
-    def tearDown(self):
-        super(SmbDotConfTests, self).tearDown()
-        os.unlink(self.smbconf)
-        os.unlink(self.blankconf)
+        self.topdir = os.path.abspath(samba.source_tree_topdir())
+
+        try:
+            self.documented = set(get_documented_parameters(self.topdir))
+        except:
+            self.fail("Unable to load documented parameters")
+
+        try:
+            self.table_gen = set(get_param_table_full(self.topdir,
+                                 "bin/default/lib/param/param_table_gen.c"))
+        except:
+            self.fail("Unable to load generated parameter table")
 
-    def test_unknown(self):
-        topdir = os.path.abspath(samba.source_tree_topdir())
         try:
-            documented = set(get_documented_parameters(topdir))
-        except e:
+            self.defaults = set(get_documented_tuples(self.topdir))
+        except:
             self.fail("Unable to load parameters")
-        parameters = set(get_implementation_parameters(topdir))
-        # Filter out parametric options, since we can't find them in the parm
-        # table
-        documented = set([p for p in documented if not ":" in p])
-        unknown = documented.difference(parameters)
-        if len(unknown) > 0:
-            self.fail(self._format_message(unknown,
-                "Parameters that are documented but not in the implementation:"))
-
-    def test_undocumented(self):
-        topdir = os.path.abspath(samba.source_tree_topdir())
+
         try:
-            documented = set(get_documented_parameters(topdir))
+            self.defaults_all = set(get_documented_tuples(self.topdir, False))
         except:
             self.fail("Unable to load parameters")
-        parameters = set(get_implementation_parameters(topdir))
-        undocumented = parameters.difference(documented)
-        if len(undocumented) > 0:
-            self.fail(self._format_message(undocumented,
-                "Parameters that are in the implementation but undocumented:"))
+
+
+    def tearDown(self):
+        super(SmbDotConfTests, self).tearDown()
+        os.unlink(self.smbconf)
+        os.unlink(self.blankconf)
 
     def test_default_s3(self):
         self._test_default(['bin/testparm'])
@@ -203,16 +236,10 @@ class SmbDotConfTests(TestCase):
         self._test_empty(['bin/samba-tool', 'testparm'])
 
     def _test_default(self, program):
-        topdir = os.path.abspath(samba.source_tree_topdir())
-        try:
-            defaults = set(get_documented_tuples(topdir))
-        except:
-            self.fail("Unable to load parameters")
-        bindir = os.path.join(topdir, "bin")
         failset = set()
         count = 0
 
-        for tuples in defaults:
+        for tuples in self.defaults:
             param, default, context, param_type = tuples
             if param in self.special_cases:
                 continue
@@ -225,7 +252,7 @@ class SmbDotConfTests(TestCase):
                  self.fail("%s has no valid context" % param)
             p = subprocess.Popen(program + ["-s", self.smbconf,
                     "--section-name", section, "--parameter-name", param],
-                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=topdir).communicate()
+                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
             if p[0].upper().strip() != default.upper():
                 if not (p[0].upper().strip() == "" and default == '""'):
                     doc_triple = "%s\n      Expected: %s" % (param, default)
@@ -236,16 +263,10 @@ class SmbDotConfTests(TestCase):
                 "Parameters that do not have matching defaults:"))
 
     def _set_defaults(self, program):
-        topdir = os.path.abspath(samba.source_tree_topdir())
-        try:
-            defaults = set(get_documented_tuples(topdir))
-        except:
-            self.fail("Unable to load parameters")
-        bindir = os.path.join(topdir, "bin")
         failset = set()
         count = 0
 
-        for tuples in defaults:
+        for tuples in self.defaults:
             param, default, context, param_type = tuples
 
             if param in ['printing']:
@@ -261,7 +282,7 @@ class SmbDotConfTests(TestCase):
             p = subprocess.Popen(program + ["-s", self.smbconf,
                     "--section-name", section, "--parameter-name", param,
                     "--option", "%s = %s" % (param, default)],
-                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=topdir).communicate()
+                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
             if p[0].upper().strip() != default.upper():
                 if not (p[0].upper().strip() == "" and default == '""'):
                     doc_triple = "%s\n      Expected: %s" % (param, default)
@@ -273,19 +294,24 @@ class SmbDotConfTests(TestCase):
 
     def _set_arbitrary(self, program, exceptions=None):
         arbitrary = {'string': 'string', 'boolean': 'yes', 'integer': '5',
+                     'boolean-rev': 'yes',
+                     'cmdlist': 'a b c',
+                     'bytes': '10',
+                     'octal': '0123',
+                     'ustring': 'ustring',
                      'enum':'', 'boolean-auto': '', 'char': 'a', 'list': 'a, b, c'}
         opposite_arbitrary = {'string': 'string2', 'boolean': 'no', 'integer': '6',
+                              'boolean-rev': 'no',
+                              'cmdlist': 'd e f',
+                              'bytes': '11',
+                              'octal': '0567',
+                              'ustring': 'ustring2',
                               'enum':'', 'boolean-auto': '', 'char': 'b', 'list': 'd, e, f'}
-        topdir = os.path.abspath(samba.source_tree_topdir())
-        try:
-            defaults = set(get_documented_tuples(topdir, False))
-        except Exception,e:
-            self.fail("Unable to load parameters" + e)
-        bindir = os.path.join(topdir, "bin")
+
         failset = set()
         count = 0
 
-        for tuples in defaults:
+        for tuples in self.defaults_all:
             param, default, context, param_type = tuples
 
             if param in ['printing', 'copy', 'include', 'log level']:
@@ -314,7 +340,7 @@ class SmbDotConfTests(TestCase):
             p = subprocess.Popen(program + ["-s", self.smbconf,
                     "--section-name", section, "--parameter-name", param,
                     "--option", "%s = %s" % (param, value_to_use)],
-                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=topdir).communicate()
+                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
             if p[0].upper().strip() != value_to_use.upper():
                 # currently no way to distinguish command lists
                 if param_type == 'list':
@@ -344,7 +370,7 @@ class SmbDotConfTests(TestCase):
 
             p = subprocess.Popen(program + ["-s", tempconf, "--suppress-prompt",
                     "--option", "%s = %s" % (param, value_to_use)],
-                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=topdir).communicate()
+                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
 
             os.unlink(tempconf)
 
@@ -378,10 +404,8 @@ class SmbDotConfTests(TestCase):
                 "Parameters that were unexpectedly not set:"))
 
     def _test_empty(self, program):
-        topdir = os.path.abspath(samba.source_tree_topdir())
-
         p = subprocess.Popen(program + ["-s", self.blankconf, "--suppress-prompt"],
-                stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=topdir).communicate()
+                stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
         output = ""
 
         for line in p[0].splitlines():
diff --git a/python/samba/tests/kcc/ldif_import_export.py b/python/samba/tests/kcc/ldif_import_export.py
index 67bcd39..b94fbca 100644
--- a/python/samba/tests/kcc/ldif_import_export.py
+++ b/python/samba/tests/kcc/ldif_import_export.py
@@ -25,7 +25,7 @@ import time
 import shutil
 import sys
 import subprocess
-
+import logging
 import samba.tests
 from samba.kcc import ldif_import_export, KCC
 from samba import ldb
@@ -127,9 +127,28 @@ class LdifImportExportTests(samba.tests.TestCaseInTempDir):
             self.remove_files(dburl)
 
 
-    def samdb_to_ldif_file(self):
-        #samdb_to_ldif_file(samdb, dburl, lp, creds, ldif_file):
-        pass
+    def test_samdb_to_ldif_file(self):
+        dburl = os.path.join(self.tempdir, "ldap")
+        dburl2 = os.path.join(self.tempdir, "ldap_roundtrip")
+        ldif_file = os.path.join(self.tempdir, "ldif")
+        samdb = ldif_import_export.ldif_to_samdb(dburl, self.lp,
+                                                 MULTISITE_LDIF)
+        self.assertIsInstance(samdb, SamDB)
+        ldif_import_export.samdb_to_ldif_file(samdb, dburl,
+                                              lp=self.lp, creds=None,
+                                              ldif_file=ldif_file)
+        self.assertGreater(os.path.getsize(ldif_file), 1000,
+                           "LDIF should be larger than 1000 bytes")
+        samdb = ldif_import_export.ldif_to_samdb(dburl2, self.lp,
+                                                 ldif_file)
+        self.assertIsInstance(samdb, SamDB)
+        dsa = ("CN=WIN01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,"
+               "CN=Configuration,DC=ad,DC=samba,DC=example,DC=com")
+        res = samdb.search(ldb.Dn(samdb, "CN=NTDS Settings," + dsa),
+                           scope=ldb.SCOPE_BASE, attrs=["objectGUID"])
+        self.remove_files(dburl)
+        self.remove_files(dburl2)
+        self.remove_files(ldif_file)
 
 
 class KCCMultisiteLdifTests(samba.tests.TestCaseInTempDir):
@@ -150,7 +169,7 @@ class KCCMultisiteLdifTests(samba.tests.TestCaseInTempDir):
         my_kcc = KCC(unix_now, readonly=readonly, verify=verify,
                      dot_file_dir=dot_file_dir)
         tmpdb = os.path.join(self.tempdir, 'tmpdb')
-        my_kcc.import_ldif(tmpdb, self.lp, self.creds, MULTISITE_LDIF)
+        my_kcc.import_ldif(tmpdb, self.lp, MULTISITE_LDIF)
         self.remove_files(tmpdb)
         return my_kcc
 
@@ -166,9 +185,9 @@ class KCCMultisiteLdifTests(samba.tests.TestCaseInTempDir):
         """
         my_kcc = self._get_kcc('test-verify', verify=True)
         tmpdb = os.path.join(self.tempdir, 'verify-tmpdb')
-        my_kcc.import_ldif(tmpdb, self.lp, self.creds, MULTISITE_LDIF)
+        my_kcc.import_ldif(tmpdb, self.lp, MULTISITE_LDIF)
 
-        my_kcc.run("ldap://%s" % tmpdb,
+        my_kcc.run(None,
                    self.lp, self.creds,
                    attempt_live_connections=False)
         self.remove_files(tmpdb)
@@ -179,8 +198,8 @@ class KCCMultisiteLdifTests(samba.tests.TestCaseInTempDir):
         my_kcc = self._get_kcc('test-dotfiles', dot_file_dir=self.tempdir)
         tmpdb = os.path.join(self.tempdir, 'dotfile-tmpdb')
         files = [tmpdb]
-        my_kcc.import_ldif(tmpdb, self.lp, self.creds, MULTISITE_LDIF)
-        my_kcc.run("ldap://%s" % tmpdb,
+        my_kcc.import_ldif(tmpdb, self.lp, MULTISITE_LDIF)
+        my_kcc.run(None,
                    self.lp, self.creds,
                    attempt_live_connections=False)
 
diff --git a/python/samba/tests/provision.py b/python/samba/tests/provision.py
index 67f8c18..91c66d5 100644
--- a/python/samba/tests/provision.py
+++ b/python/samba/tests/provision.py
@@ -116,9 +116,6 @@ class Disabled(object):
     def test_join_domain(self):
         raise NotImplementedError(self.test_join_domain)
 
-    def test_vampire(self):
-        raise NotImplementedError(self.test_vampire)
-
 
 class SanitizeServerRoleTests(TestCase):
 
diff --git a/python/samba/tests/samba_tool/sites.py b/python/samba/tests/samba_tool/sites.py
new file mode 100644
index 0000000..ee28109
--- /dev/null
+++ b/python/samba/tests/samba_tool/sites.py
@@ -0,0 +1,136 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Catalyst.Net LTD 2015
+# Copyright (C) Sean Dague <sdague at linux.vnet.ibm.com> 2011
+#
+# Catalyst.Net's contribution was written by Douglas Bagnall
+# <douglas.bagnall at catalyst.net.nz>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import ldb
+from samba.tests.samba_tool.base import SambaToolCmdTest
+from samba import sites
+
+
+class BaseSitesCmdTestCase(SambaToolCmdTest):
+    """Tests for samba-tool sites subnets"""
+    def setUp(self):
+        super(BaseSitesCmdTestCase, self).setUp()
+        self.dburl = "ldap://%s" % os.environ["DC_SERVER"]
+        self.creds_string = "-U%s%%%s" % (os.environ["DC_USERNAME"],
+                                          os.environ["DC_PASSWORD"])
+
+        self.samdb = self.getSamDB("-H", self.dburl, self.creds_string)
+        self.config_dn = str(self.samdb.get_config_basedn())
+
+
+class SitesCmdTestCase(BaseSitesCmdTestCase):
+
+    def test_site_create(self):
+        sitename = 'new_site'
+
+        result, out, err = self.runsubcmd("sites", "create", sitename,
+                                          "-H", self.dburl, self.creds_string)
+        self.assertCmdSuccess(result)
+
+        dnsites = ldb.Dn(self.samdb, "CN=Sites,%s" % self.config_dn)
+        dnsite = ldb.Dn(self.samdb, "CN=%s,%s" % (sitename, dnsites))
+
+        ret = self.samdb.search(base=dnsites, scope=ldb.SCOPE_ONELEVEL,
+                                expression='(dn=%s)' % str(dnsite))
+        self.assertEquals(len(ret), 1)
+
+        # now delete it
+        self.samdb.delete(dnsite, ["tree_delete:0"])
+
+
+class SitesSubnetCmdTestCase(BaseSitesCmdTestCase):
+    def setUp(self):
+        super(SitesSubnetCmdTestCase, self).setUp()
+        self.sitename = "testsite"
+        self.sitename2 = "testsite2"
+        self.samdb.transaction_start()
+        sites.create_site(self.samdb, self.config_dn, self.sitename)
+        sites.create_site(self.samdb, self.config_dn, self.sitename2)
+        self.samdb.transaction_commit()
+
+    def tearDown(self):
+        self.samdb.transaction_start()
+        sites.delete_site(self.samdb, self.config_dn, self.sitename)
+        sites.delete_site(self.samdb, self.config_dn, self.sitename2)
+        self.samdb.transaction_commit()
+        super(SitesSubnetCmdTestCase, self).tearDown()
+
+    def test_site_subnet_create(self):
+        cidrs = (("10.9.8.0/24", self.sitename),
+                 ("50.60.0.0/16", self.sitename2),
+                 ("50.61.0.0/16", self.sitename2), # second subnet on the site
+                 ("50.0.0.0/8", self.sitename), # overlapping subnet, other site
+                 ("50.62.1.2/32", self.sitename), # single IP
+                 ("aaaa:bbbb:cccc:dddd:eeee:ffff:2222:1100/120",
+                  self.sitename2),
+             )
+
+        for cidr, sitename in cidrs:
+            result, out, err = self.runsubcmd("sites", "subnet", "create",
+                                              cidr, sitename,
+                                              "-H", self.dburl,
+                                              self.creds_string)
+            self.assertCmdSuccess(result)
+
+            ret = self.samdb.search(base=self.config_dn,
+                                    scope=ldb.SCOPE_SUBTREE,
+                                    expression=('(&(objectclass=subnet)(cn=%s))'
+                                                % cidr))
+            self.assertIsNotNone(ret)
+            self.assertEqual(len(ret), 1)
+
+        dnsubnets = ldb.Dn(self.samdb,
+                           "CN=Subnets,CN=Sites,%s" % self.config_dn)
+
+        for cidr, sitename in cidrs:
+            dnsubnet = ldb.Dn(self.samdb, ("Cn=%s,CN=Subnets,CN=Sites,%s" %
+                                           (cidr, self.config_dn)))
+
+            ret = self.samdb.search(base=dnsubnets, scope=ldb.SCOPE_ONELEVEL,
+                                    expression='(dn=%s)' % dnsubnet)
+            self.assertIsNotNone(ret)
+            self.assertEqual(len(ret), 1)
+            self.samdb.delete(dnsubnet, ["tree_delete:0"])
+
+    def test_site_subnet_create_should_fail(self):
+        cidrs = (("10.9.8.0/33", self.sitename),    # mask too big
+                 ("50.60.0.0/8", self.sitename2),   # insufficient zeros
+                 ("50.261.0.0/16", self.sitename2), # bad octet
+                 ("7.0.0.0.0/0", self.sitename),    # insufficient zeros
+                 ("aaaa:bbbb:cccc:dddd:eeee:ffff:2222:1100/119",
+                  self.sitename),                   # insufficient zeros
+             )
+
+        for cidr, sitename in cidrs:
+            result, out, err = self.runsubcmd("sites", "subnet", "create",
+                                              cidr, sitename,
+                                              "-H", self.dburl,
+                                              self.creds_string)
+            self.assertCmdFail(result)
+
+            ret = self.samdb.search(base=self.config_dn,
+                                    scope=ldb.SCOPE_SUBTREE,
+                                    expression=('(&(objectclass=subnet)(cn=%s))'
+                                                % cidr))
+
+            self.assertIsNotNone(ret)
+            self.assertEqual(len(ret), 0)
diff --git a/python/samba/upgradehelpers.py b/python/samba/upgradehelpers.py
index 3b664fe..9b2c1c2 100644
--- a/python/samba/upgradehelpers.py
+++ b/python/samba/upgradehelpers.py
@@ -197,7 +197,7 @@ def get_paths(param, targetdir=None, smbconf=None):
         smbconf = param.default_path()
 
     if not os.path.exists(smbconf):
-        raise ProvisioningError("Unable to find smb.conf")
+        raise ProvisioningError("Unable to find smb.conf at %s" % smbconf)
 
     lp = param.LoadParm()
     lp.load(smbconf)
diff --git a/python/uuidmodule.c b/python/uuidmodule.c
deleted file mode 100644
index 3bfe016..0000000
--- a/python/uuidmodule.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Samba utility functions
-   Copyright (C) Jelmer Vernooij <jelmer at samba.org> 2007
-   
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <Python.h>
-#include "includes.h"
-#include "librpc/ndr/libndr.h"
-
-static PyObject *uuid_random(PyObject *self, PyObject *args)
-{
-	struct GUID guid;
-	PyObject *pyobj;
-	char *str;
-
-	if (!PyArg_ParseTuple(args, ""))
-	        return NULL;
-
-	guid = GUID_random();
-
-	str = GUID_string(NULL, &guid);
-	if (str == NULL) {
-		PyErr_SetString(PyExc_TypeError, "can't convert uuid to string");
-		return NULL;
-	}
-
-	pyobj = PyString_FromString(str);
-
-	talloc_free(str);
-
-	return pyobj;
-}
-
-static PyMethodDef methods[] = {
-	{ "uuid4", (PyCFunction)uuid_random, METH_VARARGS, NULL},
-	{ NULL, NULL }
-};
-
-void inituuid(void)
-{
-	PyObject *mod = Py_InitModule3("uuid", methods, "UUID helper routines");
-	if (mod == NULL)
-		return;
-}
diff --git a/python/wscript_build b/python/wscript_build
index a40b583..01ac362 100644
--- a/python/wscript_build
+++ b/python/wscript_build
@@ -16,14 +16,6 @@ bld.SAMBA_SUBSYSTEM('LIBPYTHON',
 	)
 
 
-bld.SAMBA_PYTHON('python_uuid',
-	source='uuidmodule.c',
-	deps='ndr',
-	realname='uuid.so',
-	enabled = float(bld.env.PYTHON_VERSION) <= 2.4
-	)
-
-
 bld.SAMBA_PYTHON('python_glue',
 	source='pyglue.c',
 	deps='pyparam_util samba-util netif pytalloc-util',
diff --git a/script/autobuild.py b/script/autobuild.py
index c7ca632..9f0d893 100755
--- a/script/autobuild.py
+++ b/script/autobuild.py
@@ -26,6 +26,7 @@ builddirs = {
     "samba-xc" : ".",
     "samba-ctdb" : ".",
     "samba-libs"  : ".",
+    "samba-static"  : ".",
     "ldb"     : "lib/ldb",
     "tdb"     : "lib/tdb",
     "talloc"  : "lib/talloc",
@@ -37,10 +38,17 @@ builddirs = {
     "retry"   : "."
     }
 
-defaulttasks = [ "ctdb", "samba", "samba-xc", "samba-ctdb", "samba-libs", "ldb", "tdb", "talloc", "replace", "tevent", "pidl" ]
+defaulttasks = [ "ctdb", "samba", "samba-xc", "samba-ctdb", "samba-libs", "samba-static", "ldb", "tdb", "talloc", "replace", "tevent", "pidl" ]
 
 samba_configure_params = " --picky-developer ${PREFIX} --with-profiling-data"
 
+samba_libs_envvars =  "PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH"
+samba_libs_envvars += " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
+samba_libs_envvars += " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
+samba_libs_configure_base = samba_libs_envvars + " ./configure --abi-check --enable-debug --picky-developer -C ${PREFIX}"
+samba_libs_configure_libs = samba_libs_configure_base + " --bundled-libraries=NONE"
+samba_libs_configure_samba = samba_libs_configure_base + " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent"
+
 tasks = {
     "ctdb" : [ ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
                ("configure", "./configure ${PREFIX}", "text/plain"),
@@ -89,26 +97,48 @@ tasks = {
 
     "samba-libs" : [
                       ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
-                      ("talloc-configure", "cd lib/talloc && PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=NONE --abi-check --enable-debug -C ${PREFIX}", "text/plain"),
+                      ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs, "text/plain"),
                       ("talloc-make", "cd lib/talloc && make", "text/plain"),
                       ("talloc-install", "cd lib/talloc && make install", "text/plain"),
 
-                      ("tdb-configure", "cd lib/tdb && PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=NONE --abi-check --enable-debug -C ${PREFIX}", "text/plain"),
+                      ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs, "text/plain"),
                       ("tdb-make", "cd lib/tdb && make", "text/plain"),
                       ("tdb-install", "cd lib/tdb && make install", "text/plain"),
 
-                      ("tevent-configure", "cd lib/tevent && PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=NONE --abi-check --enable-debug -C ${PREFIX}", "text/plain"),
+                      ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs, "text/plain"),
                       ("tevent-make", "cd lib/tevent && make", "text/plain"),
                       ("tevent-install", "cd lib/tevent && make install", "text/plain"),
 
-                      ("ldb-configure", "cd lib/ldb && PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=NONE --abi-check --enable-debug -C ${PREFIX}", "text/plain"),
+                      ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs, "text/plain"),
                       ("ldb-make", "cd lib/ldb && make", "text/plain"),
                       ("ldb-install", "cd lib/ldb && make install", "text/plain"),
 
-                      ("configure", "PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=!talloc,!tdb,!pytdb,!ldb,!pyldb,!tevent,!pytevent --minimum-library-version=ldb:1.1.21,pyldb-util:1.1.21 --abi-check --enable-debug -C ${PREFIX}", "text/plain"),
-                      ("make", "make", "text/plain"),
-                      ("install", "make install", "text/plain"),
-                      ("dist", "make dist", "text/plain")],
+                      ("nondevel-configure", "./configure ${PREFIX}", "text/plain"),
+                      ("nondevel-make", "make -j", "text/plain"),
+                      ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0", "text/plain"),
+                      ("nondevel-install", "make install", "text/plain"),
+                      ("nondevel-dist", "make dist", "text/plain"),
+
+                      # retry with all modules shared
+                      ("allshared-distclean", "make distclean", "text/plain"),
+                      ("allshared-configure", samba_libs_configure_samba + " --with-shared-modules=ALL", "text/plain"),
+                      ("allshared-make", "make -j", "text/plain")],
+
+    "samba-static" : [
+                      ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
+                      # build with all modules static
+                      ("allstatic-configure", "./configure.developer " + samba_configure_params + " --with-static-modules=ALL", "text/plain"),
+                      ("allstatic-make", "make -j", "text/plain"),
+
+                      # retry without any required modules
+                      ("none-distclean", "make distclean", "text/plain"),
+                      ("none-configure", "./configure.developer " + samba_configure_params + " --with-static-modules=!FORCED,!DEFAULT --with-shared-modules=!FORCED,!DEFAULT", "text/plain"),
+                      ("none-make", "make -j", "text/plain"),
+
+                      # retry with nonshared smbd and smbtorture
+                      ("nonshared-distclean", "make distclean", "text/plain"),
+                      ("nonshared-configure", "./configure.developer " + samba_configure_params + " --bundled-libraries=talloc,tdb,pytdb,ldb,pyldb,tevent,pytevent --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd", "text/plain"),
+                      ("nonshared-make", "make -j", "text/plain")],
 
     "ldb" : [
               ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
@@ -192,7 +222,7 @@ def run_cmd(cmd, dir=".", show=None, output=False, checkfail=True):
 class builder(object):
     '''handle build of one directory'''
 
-    def __init__(self, name, sequence):
+    def __init__(self, name, sequence, cp=True):
         self.name = name
         self.dir = builddirs[name]
 
@@ -215,7 +245,10 @@ class builder(object):
         cleanup_list.append(self.prefix)
         os.makedirs(self.sdir)
         run_cmd("rm -rf %s" % self.sdir)
-        run_cmd("git clone --recursive --shared %s %s" % (test_master, self.sdir), dir=test_master, show=True)
+        if cp:
+            run_cmd("cp --recursive --link --archive %s %s" % (test_master, self.sdir), dir=test_master, show=True)
+        else:
+            run_cmd("git clone --recursive --shared %s %s" % (test_master, self.sdir), dir=test_master, show=True)
         self.start_next()
 
     def start_next(self):
@@ -254,7 +287,7 @@ class buildlist(object):
             os.environ['AUTOBUILD_RANDOM_SLEEP_OVERRIDE'] = '1'
 
         for n in tasknames:
-            b = builder(n, tasks[n])
+            b = builder(n, tasks[n], cp=n is not "pidl")
             self.tlist.append(b)
         if options.retry:
             rebase_remote = "rebaseon"
@@ -278,7 +311,7 @@ class buildlist(object):
                            ),
                            "test/plain" ) ]
 
-            self.retry = builder('retry', retry_task)
+            self.retry = builder('retry', retry_task, cp=False)
             self.need_retry = False
 
     def kill_kids(self):
@@ -335,6 +368,16 @@ class buildlist(object):
         self.kill_kids()
         return (0, None, None, None, "All OK")
 
+    def write_system_info(self):
+        filename = 'system-info.txt'
+        f = open(filename, 'w')
+        for cmd in ['uname -a', 'free', 'cat /proc/cpuinfo']:
+            print >>f, '### %s' % cmd
+            print >>f, run_cmd(cmd, output=True, checkfail=False)
+            print >>f
+        f.close()
+        return filename
+
     def tarlogs(self, fname):
         tar = tarfile.open(fname, "w:gz")
         for b in self.tlist:
@@ -342,6 +385,8 @@ class buildlist(object):
             tar.add(b.stderr_path, arcname="%s.stderr" % b.tag)
         if os.path.exists("autobuild.log"):
             tar.add("autobuild.log")
+        sys_info = self.write_system_info()
+        tar.add(sys_info)
         tar.close()
 
     def remove_logs(self):
@@ -680,6 +725,24 @@ blist.tarlogs("logs.tar.gz")
 if options.email is not None:
     email_failure(status, failed_task, failed_stage, failed_tag, errstr,
                   elapsed_time, log_base=options.log_base)
+else:
+    elapsed_minutes = elapsed_time / 60.0
+    print '''
+
+####################################################################
+
+AUTOBUILD FAILURE
+
+Your autobuild on %s failed after %.1f minutes
+when trying to test %s with the following error:
+
+   %s
+
+the autobuild has been abandoned. Please fix the error and resubmit.
+
+####################################################################
+
+''' % (platform.node(), elapsed_minutes, failed_task, errstr)
 
 cleanup()
 print(errstr)
diff --git a/script/generate_param.py b/script/generate_param.py
index d79c13c..611bafa 100644
--- a/script/generate_param.py
+++ b/script/generate_param.py
@@ -35,8 +35,8 @@ parser.add_option("-f", "--file", dest="filename",
                   help="input file", metavar="FILE")
 parser.add_option("-o", "--output", dest="output",
                   help='output file', metavar="FILE")
-parser.add_option("--mode", type="choice", metavar="<FUNCTIONS|S3PROTO|LIBPROTO|PARAMDEFS>",
-                 choices=["FUNCTIONS", "S3PROTO", "LIBPROTO", "PARAMDEFS"], default="FUNCTIONS")
+parser.add_option("--mode", type="choice", metavar="<FUNCTIONS|S3PROTO|LIBPROTO|PARAMDEFS|PARAMTABLE>",
+                 choices=["FUNCTIONS", "S3PROTO", "LIBPROTO", "PARAMDEFS", "PARAMTABLE"], default="FUNCTIONS")
 parser.add_option("--scope", metavar="<GLOBAL|LOCAL>",
                   choices = ["GLOBAL", "LOCAL"], default="GLOBAL")
 
@@ -69,26 +69,52 @@ def iterate_all(path):
         synonym = parameter.attrib.get("synonym")
         removed = parameter.attrib.get("removed")
         generated = parameter.attrib.get("generated_function")
-        if synonym == "1" or removed == "1" or generated == "0":
+        handler = parameter.attrib.get("handler")
+        enumlist = parameter.attrib.get("enumlist")
+        deprecated = parameter.attrib.get("deprecated")
+        synonyms = parameter.findall('synonym')
+
+        if removed == "1":
             continue
+
         constant = parameter.attrib.get("constant")
         parm = parameter.attrib.get("parm")
         if name is None or param_type is None or context is None:
             raise Exception("Error parsing parameter: " + name)
         if func is None:
             func = name.replace(" ", "_").lower()
+        if enumlist is None:
+            enumlist = "NULL"
+        if handler is None:
+            handler = "NULL"
         yield {'name': name,
                'type': param_type,
                'context': context,
                'function': func,
                'constant': (constant == '1'),
-               'parm': (parm == '1')}
+               'parm': (parm == '1'),
+               'synonym' : synonym,
+               'generated' : generated,
+               'enumlist' : enumlist,
+               'handler' : handler,
+               'deprecated' : deprecated,
+               'synonyms' : synonyms }
 
 # map doc attributes to a section of the generated function
 context_dict = {"G": "_GLOBAL", "S": "_LOCAL"}
-param_type_dict = {"boolean": "_BOOL", "list": "_LIST", "string": "_STRING",
-                   "integer": "_INTEGER", "enum": "_INTEGER", "char" : "_CHAR",
-                   "boolean-auto": "_INTEGER"}
+param_type_dict = {
+                    "boolean"      : "_BOOL",
+                    "list"         : "_LIST",
+                    "string"       : "_STRING",
+                    "integer"      : "_INTEGER",
+                    "enum"         : "_INTEGER",
+                    "char"         : "_CHAR",
+                    "boolean-auto" : "_INTEGER",
+                    "cmdlist"      : "_LIST",
+                    "bytes"        : "_INTEGER",
+                    "octal"        : "_INTEGER",
+                    "ustring"      : "_STRING",
+                  }
 
 def generate_functions(path_in, path_out):
     f = open(path_out, 'w')
@@ -98,6 +124,11 @@ def generate_functions(path_in, path_out):
             # filter out parameteric options
             if ':' in parameter['name']:
                 continue
+            if parameter['synonym'] == "1":
+                continue
+            if parameter['generated'] == "0":
+                continue
+
             output_string = "FN"
             temp = context_dict.get(parameter['context'])
             if temp is None: 
@@ -115,8 +146,19 @@ def generate_functions(path_in, path_out):
     finally:
         f.close()
 
-mapping = {'boolean': 'bool ', 'string': 'char *', 'integer': 'int ', 'char': 'char ',
-           'list': 'const char **', 'enum': 'int ', 'boolean-auto': 'int '}
+mapping = {
+            'boolean'      : 'bool ',
+            'string'       : 'char *',
+            'integer'      : 'int ',
+            'char'         : 'char ',
+            'list'         : 'const char **',
+            'enum'         : 'int ',
+            'boolean-auto' : 'int ',
+            'cmdlist'      : 'const char **',
+            'bytes'        : 'int ',
+            'octal'        : 'int ',
+            'ustring'      : 'char *',
+          }
 
 def make_s3_param_proto(path_in, path_out):
     file_out = open(path_out, 'w')
@@ -129,6 +171,10 @@ def make_s3_param_proto(path_in, path_out):
             # filter out parameteric options
             if ':' in parameter['name']:
                 continue
+            if parameter['synonym'] == "1":
+                continue
+            if parameter['generated'] == "0":
+                continue
 
             output_string = ""
             if parameter['constant']:
@@ -175,6 +221,10 @@ def make_lib_proto(path_in, path_out):
             # filter out parameteric options
             if ':' in parameter['name']:
                 continue
+            if parameter['synonym'] == "1":
+                continue
+            if parameter['generated'] == "0":
+                continue
 
             output_string = ""
             if parameter['constant']:
@@ -225,7 +275,6 @@ def make_param_defs(path_in, path_out, scope):
             file_out.write("struct loadparm_global \n")
             file_out.write("{\n")
             file_out.write("\tTALLOC_CTX *ctx; /* Context for talloced members */\n")
-            file_out.write("\tchar *  dnsdomain;\n")
         elif scope == "LOCAL":
             file_out.write("/**\n")
             file_out.write(" * This structure describes a single service.\n")
@@ -238,6 +287,8 @@ def make_param_defs(path_in, path_out, scope):
             # filter out parameteric options
             if ':' in parameter['name']:
                 continue
+            if parameter['synonym'] == "1":
+                continue
 
             if (scope == "GLOBAL" and parameter['context'] != "G" or
                 scope == "LOCAL" and parameter['context'] != "S"):
@@ -258,6 +309,92 @@ def make_param_defs(path_in, path_out, scope):
     finally:
         file_out.close()
 
+type_dict = {
+              "boolean"      : "P_BOOL",
+              "boolean-rev"  : "P_BOOLREV",
+              "boolean-auto" : "P_ENUM",
+              "list"         : "P_LIST",
+              "string"       : "P_STRING",
+              "integer"      : "P_INTEGER",
+              "enum"         : "P_ENUM",
+              "char"         : "P_CHAR",
+              "cmdlist"      : "P_CMDLIST",
+              "bytes"        : "P_BYTES",
+              "octal"        : "P_OCTAL",
+              "ustring"      : "P_USTRING",
+            }
+
+def make_param_table(path_in, path_out):
+    file_out = open(path_out, 'w')
+    try:
+        file_out.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n')
+        header = get_header(path_out)
+        file_out.write("#ifndef %s\n" % header)
+        file_out.write("#define %s\n\n" % header)
+
+        file_out.write("struct parm_struct parm_table[] = {\n")
+
+        for parameter in iterate_all(path_in):
+            # filter out parameteric options
+            if ':' in parameter['name']:
+                continue
+            if parameter['context'] == 'G':
+                p_class = "P_GLOBAL"
+            else:
+                p_class = "P_LOCAL"
+
+            p_type = type_dict.get(parameter['type'])
+
+            if parameter['context'] == 'G':
+                temp = "GLOBAL"
+            else:
+                temp = "LOCAL"
+            offset = "%s_VAR(%s)" % (temp, parameter['function'])
+
+            enumlist = parameter['enumlist']
+            handler = parameter['handler']
+            synonym = parameter['synonym']
+            deprecated = parameter['deprecated']
+            flags_list = []
+            if synonym == "1":
+                flags_list.append("FLAG_SYNONYM")
+            if deprecated == "1":
+                flags_list.append("FLAG_DEPRECATED")
+            flags = "|".join(flags_list)
+            synonyms = parameter['synonyms']
+
+            file_out.write("\t{\n")
+            file_out.write("\t\t.label\t\t= \"%s\",\n" % parameter['name'])
+            file_out.write("\t\t.type\t\t= %s,\n" % p_type)
+            file_out.write("\t\t.p_class\t= %s,\n" % p_class)
+            file_out.write("\t\t.offset\t\t= %s,\n" % offset)
+            file_out.write("\t\t.special\t= %s,\n" % handler)
+            file_out.write("\t\t.enum_list\t= %s,\n" % enumlist)
+            if flags != "":
+                file_out.write("\t\t.flags\t\t= %s,\n" % flags)
+            file_out.write("\t},\n")
+
+            if synonyms is not None:
+                # for synonyms, we only list the synonym flag:
+                flags = "FLAG_SYNONYM"
+                for syn in synonyms:
+                    file_out.write("\t{\n")
+                    file_out.write("\t\t.label\t\t= \"%s\",\n" % syn.text)
+                    file_out.write("\t\t.type\t\t= %s,\n" % p_type)
+                    file_out.write("\t\t.p_class\t= %s,\n" % p_class)
+                    file_out.write("\t\t.offset\t\t= %s,\n" % offset)
+                    file_out.write("\t\t.special\t= %s,\n" % handler)
+                    file_out.write("\t\t.enum_list\t= %s,\n" % enumlist)
+                    if flags != "":
+                        file_out.write("\t\t.flags\t\t= %s,\n" % flags)
+                    file_out.write("\t},\n")
+
+        file_out.write("\n\t{NULL,  P_BOOL,  P_NONE,  0,  NULL,  NULL,  0}\n");
+        file_out.write("};\n")
+        file_out.write("\n#endif /* %s */\n\n" % header)
+    finally:
+        file_out.close()
+
 if options.mode == 'FUNCTIONS':
     generate_functions(options.filename, options.output)
 elif options.mode == 'S3PROTO':
@@ -266,3 +403,5 @@ elif options.mode == 'LIBPROTO':
     make_lib_proto(options.filename, options.output)
 elif options.mode == 'PARAMDEFS':
     make_param_defs(options.filename, options.output, options.scope)
+elif options.mode == 'PARAMTABLE':
+    make_param_table(options.filename, options.output)
diff --git a/script/release.sh b/script/release.sh
index e5d93a7..7db4e53 100755
--- a/script/release.sh
+++ b/script/release.sh
@@ -216,6 +216,8 @@ verify_samba_stable() {
 
 	git tag -v "${oldtagname}" >${verify_out} 2>&1 || {
 		echo "failed to verify old tag[${oldtagname}]"
+		echo ""
+		cat "${verify_out}"
 		return 1
 	}
 
@@ -411,7 +413,9 @@ check_nopatch() {
 	echo "Verifying tagname: ${tagname}"
 
 	git tag -v "${tagname}" >${verify_out} 2>&1 || {
-		echo "failed to verify old tag[${oldtagname}]"
+		echo "failed to verify tag[${tagname}]"
+		echo ""
+		cat "${verify_out}"
 		return 1
 	}
 	grep -q "${GPG_KEYID}" "${verify_out}" || {
@@ -460,7 +464,9 @@ check_samba_stable() {
 	echo "Verifying tagname: ${tagname}"
 
 	git tag -v "${tagname}" >${verify_out} 2>&1 || {
-		echo "failed to verify old tag[${oldtagname}]"
+		echo "failed to verify tag[${tagname}]"
+		echo ""
+		cat "${verify_out}"
 		return 1
 	}
 	grep -q "${GPG_KEYID}" "${verify_out}" || {
@@ -704,6 +710,40 @@ announcement_samba_rc() {
 		echo "<!-- END: ${bodyfile} -->"
 	} > announce.${tagname}.body.html
 
+	local webrepo="${TMPDIR}/webrepo"
+
+	mkdir "${webrepo}" || {
+		return 1
+	}
+	git -C "${webrepo}" init || {
+		return 1
+	}
+
+	mkdir -p "$(dirname ${webrepo}/${headlinefile})" || {
+		return 1
+	}
+	cp -a "announce.${tagname}.headline.html" "${webrepo}/${headlinefile}" || {
+		return 1
+	}
+
+	mkdir -p "$(dirname ${webrepo}/${bodyfile})" || {
+		return 1
+	}
+	cp -a "announce.${tagname}.body.html" "${webrepo}/${bodyfile}" || {
+		return 1
+	}
+
+	git -C "${webrepo}" add "${headlinefile}" "${bodyfile}" || {
+		return 1
+	}
+	git -C "${webrepo}" commit --signoff --message "NEWS[${version}]: Samba ${version} Available for Download" || {
+		return 1
+	}
+	CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.patch.txt"
+	git -C "${webrepo}" format-patch --stdout -1 HEAD > announce.${tagname}.patch.txt || {
+		return 1
+	}
+
 	CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.todo.txt"
 	{
 		ls -lart announce.${tagname}.*
diff --git a/selftest/flapping b/selftest/flapping
index 8e13dc3..d9713cf 100644
--- a/selftest/flapping
+++ b/selftest/flapping
@@ -29,3 +29,5 @@
 ^samba4.drs.delete_object.python # flakey on sn-devel
 ^samba4.blackbox.samba_tool_demote # flakey on sn-devel
 ^samba4.blackbox.dbcheck # flakey on sn-devel
+^samba4.smb2.create.mkdir-dup\(ad_dc_ntvfs\) # This test (for bug 11486) involves a race, not always protected against in the NTVFS file server
+^samba4.winbind.struct.domain_info.ad_member # flakey on sn-devel-104 and sn-devel-144
diff --git a/selftest/knownfail b/selftest/knownfail
index d9e2823..77d186c 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -145,7 +145,6 @@
 ^samba4.raw.acls.*.create_file
 ^samba4.smb2.create.*.acldir
 ^samba4.smb2.create.*.impersonation
-^samba4.smb2.create.*.mkdir-dup # bug 11486
 ^samba4.smb2.acls.*.generic
 ^samba4.smb2.acls.*.inheritflags
 ^samba4.smb2.acls.*.owner
@@ -205,8 +204,6 @@
 ^samba3.smb2.setinfo.setinfo
 ^samba3.smb2.session.*reauth5 # some special anonymous checks?
 ^samba3.smb2.compound.interim2 # wrong return code (STATUS_CANCELLED)
-^samba3.smb2.replay.replay1
-^samba3.smb2.replay.replay2
 ^samba3.smb2.replay.replay3
 ^samba3.smb2.replay.replay4
 ^samba3.smb2.lock.*replay
@@ -295,19 +292,6 @@
 #
 ^samba4.ldap.acl.python\(.*\).__main__.AclUndeleteTests.test_undelete\(.*\)
 #
-# This fails because the code for transitive extended matching rule
-# LDAP_MATCH_RULE_TRANSITIVE_EVAL had to be disabled
-#
-^samba4.ldap.match_rules.python.__main__.MatchRulesTests.test_extended_dn
-^samba4.ldap.match_rules.python.__main__.MatchRulesTests.test_g1_member_of_g4
-^samba4.ldap.match_rules.python.__main__.MatchRulesTests.test_object_dn_binary
-^samba4.ldap.match_rules.python.__main__.MatchRulesTests.test_one_way_links
-^samba4.ldap.match_rules.python.__main__.MatchRulesTests.test_u1_groups
-^samba4.ldap.match_rules.python.__main__.MatchRulesTests.test_u1_member_of_g4
-^samba4.ldap.match_rules.python.__main__.MatchRulesTests.test_u2_groups
-^samba4.ldap.match_rules.python.__main__.MatchRulesTests.test_u3_groups
-^samba4.ldap.match_rules.python.__main__.MatchRulesTests.test_u4_groups
-#
 # This fails because our python bindings create python Lists, not a type
 # we can watch for set methods on.
 #
diff --git a/selftest/selftest.pl b/selftest/selftest.pl
index db5da05..db70246 100755
--- a/selftest/selftest.pl
+++ b/selftest/selftest.pl
@@ -415,7 +415,15 @@ my $testenv_default = "none";
 # must terminate in this time, and testenv will only stay alive this
 # long
 
-my $server_maxtime = 10800;
+my $server_maxtime;
+if ($opt_testenv) {
+    # 1 year should be enough :-)
+    $server_maxtime = 365 * 24 * 60 * 60;
+} else {
+    # make test should run under 4 hours
+    $server_maxtime = 4 * 60 * 60;
+}
+
 if (defined($ENV{SMBD_MAXTIME}) and $ENV{SMBD_MAXTIME} ne "") {
     $server_maxtime = $ENV{SMBD_MAXTIME};
 }
diff --git a/selftest/selftesthelpers.py b/selftest/selftesthelpers.py
index 0dfcf54..42499b0 100644
--- a/selftest/selftesthelpers.py
+++ b/selftest/selftesthelpers.py
@@ -183,3 +183,5 @@ scriptdir = os.path.join(srcdir(), "script/tests")
 wbinfo = binpath('wbinfo')
 dbwrap_tool = binpath('dbwrap_tool')
 vfstest = binpath('vfstest')
+smbcquotas = binpath('smbcquotas')
+smbget = binpath('smbget')
diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm
index 9937203..f1c4055 100644
--- a/selftest/target/Samba.pm
+++ b/selftest/target/Samba.pm
@@ -57,7 +57,7 @@ sub bindir_path($$) {
 
 	my $valpath = "$object->{bindir}/$path";
 
-	return $valpath if (-f $valpath);
+	return $valpath if (-f $valpath or -d $valpath);
 	return $path;
 }
 
@@ -180,8 +180,8 @@ sub get_interface($)
     $interfaces{"fileserver"} = 35;
 
     # update lib/socket_wrapper/socket_wrapper.c
-    #  #define MAX_WRAPPED_INTERFACES 32
-    # if you wish to have more than 32 interfaces
+    #  #define MAX_WRAPPED_INTERFACES 40
+    # if you wish to have more than 40 interfaces
 
     if (not defined($interfaces{$netbiosname})) {
 	die();
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index d16c440..6f7407a 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -593,6 +593,18 @@ sub setup_fileserver($$)
 	push(@dirs, "$dfree_share_dir/subdir1");
 	push(@dirs, "$dfree_share_dir/subdir2");
 
+	my $valid_users_sharedir="$share_dir/valid_users";
+	push(@dirs,$valid_users_sharedir);
+
+	my $offline_sharedir="$share_dir/offline";
+	push(@dirs,$offline_sharedir);
+
+	my $force_user_valid_users_dir = "$share_dir/force_user_valid_users";
+	push(@dirs, $force_user_valid_users_dir);
+
+	my $smbget_sharedir="$share_dir/smbget";
+	push(@dirs,$smbget_sharedir);
+
 	my $fileserver_options = "
 [lowercase]
 	path = $lower_case_share_dir
@@ -612,11 +624,32 @@ sub setup_fileserver($$)
 	path = $dfree_share_dir
 	comment = smb username is [%U]
 	dfree command = $srcdir_abs/testprogs/blackbox/dfree.sh
-	";
+[valid-users-access]
+	path = $valid_users_sharedir
+	valid users = +userdup
+[offline]
+	path = $offline_sharedir
+	vfs objects = offline
+
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=9878
+# RH BUG: https://bugzilla.redhat.com/show_bug.cgi?id=1077651
+[force_user_valid_users]
+	path = $force_user_valid_users_dir
+	comment = force user with valid users combination test share
+	valid users = +force_user
+	force user = force_user
+	force group = everyone
+	write list = force_user
+
+[smbget]
+	path = $smbget_sharedir
+	comment = smb username is [%U]
+	guest ok = yes
+";
 
 	my $vars = $self->provision($path,
 				    "FILESERVER",
-				    "fileserver_secret",
+				    "fileserver",
 				    $fileserver_options,
 				    undef,
 				    undef,
@@ -666,6 +699,17 @@ sub setup_fileserver($$)
 		close $fh;
 	}
 
+	##
+	## create a listable file in valid_users_share
+	##
+        my $valid_users_target = "$valid_users_sharedir/foo";
+        unless (open(VALID_USERS_TARGET, ">$valid_users_target")) {
+                warn("Unable to open $valid_users_target");
+                return undef;
+        }
+        close(VALID_USERS_TARGET);
+        chmod 0644, $valid_users_target;
+
 	return $vars;
 }
 
@@ -848,6 +892,7 @@ sub check_or_start($$$$$) {
 		$ENV{NSS_WRAPPER_HOSTNAME} = $env_vars->{NSS_WRAPPER_HOSTNAME};
 		$ENV{NSS_WRAPPER_MODULE_SO_PATH} = $env_vars->{NSS_WRAPPER_MODULE_SO_PATH};
 		$ENV{NSS_WRAPPER_MODULE_FN_PREFIX} = $env_vars->{NSS_WRAPPER_MODULE_FN_PREFIX};
+		$ENV{UID_WRAPPER_ROOT} = "1";
 
 		$ENV{ENVNAME} = "$ENV{ENVNAME}.nmbd";
 
@@ -911,6 +956,7 @@ sub check_or_start($$$$$) {
 		} else {
 			$ENV{RESOLV_WRAPPER_HOSTS} = $env_vars->{RESOLV_WRAPPER_HOSTS};
 		}
+		$ENV{UID_WRAPPER_ROOT} = "1";
 
 		$ENV{ENVNAME} = "$ENV{ENVNAME}.winbindd";
 
@@ -974,6 +1020,7 @@ sub check_or_start($$$$$) {
 		} else {
 			$ENV{RESOLV_WRAPPER_HOSTS} = $env_vars->{RESOLV_WRAPPER_HOSTS};
 		}
+		$ENV{UID_WRAPPER_ROOT} = "1";
 
 		$ENV{ENVNAME} = "$ENV{ENVNAME}.smbd";
 
@@ -1018,6 +1065,22 @@ sub check_or_start($$$$$) {
 	return $self->wait_for_start($env_vars, $nmbd, $winbindd, $smbd);
 }
 
+sub createuser($$$$)
+{
+	my ($self, $username, $password, $conffile) = @_;
+	my $cmd = "UID_WRAPPER_ROOT=1 " . Samba::bindir_path($self, "smbpasswd")." -c $conffile -L -s -a $username > /dev/null";
+	unless (open(PWD, "|$cmd")) {
+	    warn("Unable to set password for $username account\n$cmd");
+	    return undef;
+	}
+	print PWD "$password\n$password\n";
+	unless (close(PWD)) {
+	    warn("Unable to set password for $username account\n$cmd");
+	    return undef;
+	}
+	print "DONE\n";
+}
+
 sub provision($$$$$$$$)
 {
 	my ($self, $prefix, $server, $password, $extra_options, $dc_server_ip, $dc_server_ipv6, $no_delete_prefix) = @_;
@@ -1094,6 +1157,12 @@ sub provision($$$$$$$$)
 	my $manglenames_shrdir="$shrdir/manglenames";
 	push(@dirs,$manglenames_shrdir);
 
+	my $widelinks_shrdir="$shrdir/widelinks";
+	push(@dirs,$widelinks_shrdir);
+
+	my $widelinks_linkdir="$shrdir/widelinks_foo";
+	push(@dirs,$widelinks_linkdir);
+
 	my $shadow_tstdir="$shrdir/shadow";
 	push(@dirs,$shadow_tstdir);
 	my $shadow_mntdir="$shadow_tstdir/mount";
@@ -1192,7 +1261,27 @@ sub provision($$$$$$$$)
         my $manglename_target = "$manglenames_shrdir/foo:bar";
 	mkdir($manglename_target, 0777);
 
+	##
+	## create symlinks for widelinks tests.
+	##
+	my $widelinks_target = "$widelinks_linkdir/target";
+	unless (open(WIDELINKS_TARGET, ">$widelinks_target")) {
+		warn("Unable to open $widelinks_target");
+		return undef;
+	}
+	close(WIDELINKS_TARGET);
+	chmod 0666, $widelinks_target;
+	##
+	## This link should get ACCESS_DENIED
+	##
+	symlink "$widelinks_target", "$widelinks_shrdir/source";
+	##
+	## This link should be allowed
+	##
+	symlink "$widelinks_shrdir", "$widelinks_shrdir/dot";
+
 	my $conffile="$libdir/server.conf";
+	my $dfqconffile="$libdir/dfq.conf";
 
 	my $nss_wrapper_pl = "$ENV{PERL} $self->{srcdir}/lib/nss_wrapper/nss_wrapper.pl";
 	my $nss_wrapper_passwd = "$privatedir/passwd";
@@ -1212,12 +1301,15 @@ sub provision($$$$$$$$)
 	##
 
 	my ($max_uid, $max_gid);
-	my ($uid_nobody, $uid_root, $uid_pdbtest, $uid_pdbtest2);
+	my ($uid_nobody, $uid_root, $uid_pdbtest, $uid_pdbtest2, $uid_userdup);
 	my ($uid_pdbtest_wkn);
+	my ($uid_smbget);
+	my ($uid_force_user);
 	my ($gid_nobody, $gid_nogroup, $gid_root, $gid_domusers, $gid_domadmins);
-	my ($gid_everyone);
+	my ($gid_userdup, $gid_everyone);
+	my ($gid_force_user);
 
-	if ($unix_uid < 0xffff - 4) {
+	if ($unix_uid < 0xffff - 7) {
 		$max_uid = 0xffff;
 	} else {
 		$max_uid = $unix_uid;
@@ -1227,9 +1319,12 @@ sub provision($$$$$$$$)
 	$uid_nobody = $max_uid - 2;
 	$uid_pdbtest = $max_uid - 3;
 	$uid_pdbtest2 = $max_uid - 4;
+	$uid_userdup = $max_uid - 5;
 	$uid_pdbtest_wkn = $max_uid - 6;
+	$uid_force_user = $max_uid - 7;
+	$uid_smbget = $max_uid - 8;
 
-	if ($unix_gids[0] < 0xffff - 7) {
+	if ($unix_gids[0] < 0xffff - 8) {
 		$max_gid = 0xffff;
 	} else {
 		$max_gid = $unix_gids[0];
@@ -1240,7 +1335,9 @@ sub provision($$$$$$$$)
 	$gid_root = $max_gid - 3;
 	$gid_domusers = $max_gid - 4;
 	$gid_domadmins = $max_gid - 5;
+	$gid_userdup = $max_gid - 6;
 	$gid_everyone = $max_gid - 7;
+	$gid_force_user = $max_gid - 8;
 
 	##
 	## create conffile
@@ -1317,6 +1414,7 @@ sub provision($$$$$$$$)
 	create mask = 755
 	dos filemode = yes
 	strict rename = yes
+	strict sync = yes
 	vfs objects = acl_xattr fake_acls xattr_tdb streams_depot
 
 	printing = vlp
@@ -1498,6 +1596,11 @@ sub provision($$$$$$$$)
 	path = $shrdir/%R
 	guest ok = yes
 
+[widelinks_share]
+	path = $widelinks_shrdir
+	wide links = no
+	guest ok = yes
+
 [fsrvp_share]
 	path = $shrdir
 	comment = fake shapshots using rsync
@@ -1557,15 +1660,34 @@ sub provision($$$$$$$$)
 	shadow:mountpoint = $shadow_mntdir
 	shadow:snapdirseverywhere = yes
 
+[shadow8]
+	path = $shadow_shrdir
+	comment = previous versions using snapsharepath
+	vfs objects = shadow_copy2
+	shadow:mountpoint = $shadow_mntdir
+	shadow:snapdir = $shadow_tstdir/.snapshots
+	shadow:snapsharepath = share
+
 [shadow_wl]
 	path = $shadow_shrdir
 	comment = previous versions with wide links allowed
 	vfs objects = shadow_copy2
 	shadow:mountpoint = $shadow_mntdir
 	wide links = yes
+[dfq]
+	path = $shrdir/dfree
+	vfs objects = fake_dfq
+	admin users = $unix_name
+	include = $dfqconffile
 	";
 	close(CONF);
 
+	unless (open(DFQCONF, ">$dfqconffile")) {
+	        warn("Unable to open $dfqconffile");
+		return undef;
+	}
+	close(DFQCONF);
+
 	##
 	## create a test account
 	##
@@ -1578,7 +1700,10 @@ sub provision($$$$$$$$)
 $unix_name:x:$unix_uid:$unix_gids[0]:$unix_name gecos:$prefix_abs:/bin/false
 pdbtest:x:$uid_pdbtest:$gid_nogroup:pdbtest gecos:$prefix_abs:/bin/false
 pdbtest2:x:$uid_pdbtest2:$gid_nogroup:pdbtest gecos:$prefix_abs:/bin/false
+userdup:x:$uid_userdup:$gid_userdup:userdup gecos:$prefix_abs:/bin/false
 pdbtest_wkn:x:$uid_pdbtest_wkn:$gid_everyone:pdbtest_wkn gecos:$prefix_abs:/bin/false
+force_user:x:$uid_force_user:$gid_force_user:force user gecos:$prefix_abs:/bin/false
+smbget_user:x:$uid_smbget:$gid_domusers:smbget_user gecos:$prefix_abs:/bin/false
 ";
 	if ($unix_uid != 0) {
 		print PASSWD "root:x:$uid_root:$gid_root:root gecos:$prefix_abs:/bin/false
@@ -1595,7 +1720,9 @@ nogroup:x:$gid_nogroup:nobody
 $unix_name-group:x:$unix_gids[0]:
 domusers:X:$gid_domusers:
 domadmins:X:$gid_domadmins:
+userdup:x:$gid_userdup:$unix_name
 everyone:x:$gid_everyone:
+force_user:x:$gid_force_user:
 ";
 	if ($unix_gids[0] != 0) {
 		print GROUP "root:x:$gid_root:
@@ -1648,17 +1775,9 @@ everyone:x:$gid_everyone:
 		$ENV{RESOLV_WRAPPER_HOSTS} = $dns_host_file;
 	}
 
-        my $cmd = "UID_WRAPPER_ROOT=1 " . Samba::bindir_path($self, "smbpasswd")." -c $conffile -L -s -a $unix_name > /dev/null";
-	unless (open(PWD, "|$cmd")) {
-             warn("Unable to set password for test account\n$cmd");
-             return undef;
-        }
-	print PWD "$password\n$password\n";
-	unless (close(PWD)) {
-             warn("Unable to set password for test account\n$cmd");
-             return undef; 
-        }
-	print "DONE\n";
+	createuser($self, $unix_name, $password, $conffile) || die("Unable to create user");
+	createuser($self, "force_user", $password, $conffile) || die("Unable to create force_user");
+	createuser($self, "smbget_user", $password, $conffile) || die("Unable to create smbget_user");
 
 	open(DNS_UPDATE_LIST, ">$prefix/dns_update_list") or die("Unable to open $$prefix/dns_update_list");
 	print DNS_UPDATE_LIST "A $server. $server_ip\n";
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index 65308e2..fbefda7 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -89,7 +89,10 @@ sub check_or_start($$$)
         my ($self, $env_vars, $process_model) = @_;
 	my $STDIN_READER;
 
-	return 0 if $self->check_env($env_vars);
+	my $env_ok = $self->check_env($env_vars);
+	if ($env_ok) {
+	    return $env_vars->{SAMBA_PID};
+	}
 
 	# use a pipe for stdin in the child processes. This allows
 	# those processes to monitor the pipe for EOF to ensure they
@@ -132,6 +135,7 @@ sub check_or_start($$$)
 		}
 
 		$ENV{UID_WRAPPER} = "1";
+		$ENV{UID_WRAPPER_ROOT} = "1";
 
 		$ENV{MAKE_TEST_BINARY} = Samba::bindir_path($self, "samba");
 		my @preargs = ();
@@ -149,17 +153,28 @@ sub check_or_start($$$)
 		exec(@preargs, Samba::bindir_path($self, "samba"), "-M", $process_model, "-i", "--maximum-runtime=$self->{server_maxtime}", $env_vars->{CONFIGURATION}, @optargs) or die("Unable to start samba: $!");
 	}
 	$env_vars->{SAMBA_PID} = $pid;
-	print "DONE\n";
+	print "DONE ($pid)\n";
 
 	close($STDIN_READER);
 
+	if ($self->wait_for_start($env_vars) != 0) {
+	    warn("Samba $pid failed to start up");
+	    return undef;
+	}
+
 	return $pid;
 }
 
 sub wait_for_start($$)
 {
 	my ($self, $testenv_vars) = @_;
-	my $ret;
+	my $ret = 0;
+
+	if (not $self->check_env($testenv_vars)) {
+	    warn("unable to confirm Samba $testenv_vars->{SAMBA_PID} is running");
+	    return -1;
+	}
+
 	# give time for nbt server to register its names
 	print "delaying for nbt name registration\n";
 	sleep 2;
@@ -199,7 +214,7 @@ sub wait_for_start($$)
 	    while (system("$ldbsearch -H ldap://$testenv_vars->{SERVER} -U$testenv_vars->{USERNAME}%$testenv_vars->{PASSWORD} -s base -b \"$rid_set_dn\" rIDAllocationPool > /dev/null") != 0) {
 		$count++;
 		if ($count > 40) {
-		    $ret = 1;
+		    $ret = -1;
 		    last;
 		}
 		sleep(1);
@@ -2001,11 +2016,19 @@ sub check_env($$)
 	my ($self, $envvars) = @_;
 	my $samba_pid = $envvars->{SAMBA_PID};
 
-	return 1 if $samba_pid == -1;
+	if (not defined($samba_pid)) {
+	    return 0;
+	} elsif ($samba_pid > 0) {
+	    my $childpid = Samba::cleanup_child($samba_pid, "samba");
 
-	my $childpid = Samba::cleanup_child($samba_pid, "samba");
+	    if ($childpid == 0) {
+		return 1;
+	    }
+	    return 0;
+	} else {
+	    return 1;
+	}
 
-	return ($childpid == 0);
 }
 
 sub setup_env($$$)
@@ -2094,9 +2117,9 @@ sub setup_s4member($$$)
 	my $env = $self->provision_s4member($path, $dc_vars);
 
 	if (defined $env) {
-		$self->check_or_start($env, "single");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "single"))) {
+		        return undef;
+		}
 
 		$self->{vars}->{s4member} = $env;
 	}
@@ -2111,9 +2134,9 @@ sub setup_rpc_proxy($$$)
 	my $env = $self->provision_rpc_proxy($path, $dc_vars);
 
 	if (defined $env) {
-	        $self->check_or_start($env, "single");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "single"))) {
+		        return undef;
+		}
 
 		$self->{vars}->{rpc_proxy} = $env;
 	}
@@ -2126,9 +2149,10 @@ sub setup_ad_dc_ntvfs($$)
 
 	my $env = $self->provision_ad_dc_ntvfs($path);
 	if (defined $env) {
-		$self->check_or_start($env, "standard");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "standard"))) {
+		    warn("Failed to start ad_dc_ntvfs");
+		        return undef;
+		}
 
 		$self->{vars}->{ad_dc_ntvfs} = $env;
 	}
@@ -2141,9 +2165,9 @@ sub setup_chgdcpass($$)
 
 	my $env = $self->provision_chgdcpass($path);
 	if (defined $env) {
-		$self->check_or_start($env, "single");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "single"))) {
+		        return undef;
+		}
 
 		$self->{vars}->{chgdcpass} = $env;
 	}
@@ -2156,9 +2180,9 @@ sub setup_fl2000dc($$)
 
 	my $env = $self->provision_fl2000dc($path);
 	if (defined $env) {
-		$self->check_or_start($env, "single");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "single"))) {
+		        return undef;
+		}
 
 		$self->{vars}->{fl2000dc} = $env;
 	}
@@ -2173,9 +2197,9 @@ sub setup_fl2003dc($$$)
 	my $env = $self->provision_fl2003dc($path);
 
 	if (defined $env) {
-		$self->check_or_start($env, "single");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "single"))) {
+		        return undef;
+		}
 
 		$env = $self->setup_trust($env, $dc_vars, "external", "--no-aes-keys");
 
@@ -2191,9 +2215,9 @@ sub setup_fl2008r2dc($$$)
 	my $env = $self->provision_fl2008r2dc($path);
 
 	if (defined $env) {
-		$self->check_or_start($env, "single");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "single"))) {
+		        return undef;
+		}
 
 		my $upn_array = ["$env->{REALM}.upn"];
 		my $spn_array = ["$env->{REALM}.spn"];
@@ -2215,9 +2239,9 @@ sub setup_vampire_dc($$$)
 	my $env = $self->provision_vampire_dc($path, $dc_vars);
 
 	if (defined $env) {
-		$self->check_or_start($env, "single");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "single"))) {
+		        return undef;
+		}
 
 		$self->{vars}->{vampire_dc} = $env;
 
@@ -2278,9 +2302,9 @@ sub setup_promoted_dc($$$)
 	my $env = $self->provision_promoted_dc($path, $dc_vars);
 
 	if (defined $env) {
-		$self->check_or_start($env, "single");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "single"))) {
+		        return undef;
+		}
 
 		$self->{vars}->{promoted_dc} = $env;
 
@@ -2342,9 +2366,9 @@ sub setup_subdom_dc($$$)
 	my $env = $self->provision_subdom_dc($path, $dc_vars);
 
 	if (defined $env) {
-		$self->check_or_start($env, "single");
-
-		$self->wait_for_start($env);
+	        if (not defined($self->check_or_start($env, "single"))) {
+		        return undef;
+		}
 
 		$self->{vars}->{subdom_dc} = $env;
 
@@ -2398,9 +2422,9 @@ sub setup_rodc($$$)
 		return undef;
 	}
 
-	$self->check_or_start($env, "single");
-
-	$self->wait_for_start($env);
+	if (not defined($self->check_or_start($env, "single"))) {
+	    return undef;
+	}
 
 	# force source and replicated DC to update repsTo/repsFrom
 	# for vampired partitions
@@ -2471,9 +2495,9 @@ sub setup_ad_dc($$)
 		$env->{NSS_WRAPPER_MODULE_FN_PREFIX} = undef;
 	}
 
-	$self->check_or_start($env, "single");
-	
-	$self->wait_for_start($env);
+	if (not defined($self->check_or_start($env, "single"))) {
+	    return undef;
+	}
 
 	my $upn_array = ["$env->{REALM}.upn"];
 	my $spn_array = ["$env->{REALM}.spn"];
diff --git a/selftest/tests.py b/selftest/tests.py
index 2a07f9e..20eb63b 100644
--- a/selftest/tests.py
+++ b/selftest/tests.py
@@ -68,6 +68,10 @@ planpythontestsuite(
     extra_path=[os.path.join(samba4srcdir, "..", "buildtools"),
                 os.path.join(samba4srcdir, "..", "third_party", "waf", "wafadmin")])
 plantestsuite(
+    "samba4.blackbox.demote-saveddb", "none",
+    ["PYTHON=%s" % python, os.path.join(bbdir, "demote-saveddb.sh"),
+     '$PREFIX_ABS/demote', configuration])
+plantestsuite(
     "samba4.blackbox.dbcheck.alpha13", "none",
     ["PYTHON=%s" % python, os.path.join(bbdir, "dbcheck-oldrelease.sh"),
      '$PREFIX_ABS/provision', 'alpha13', configuration])
diff --git a/source3/auth/auth.c b/source3/auth/auth.c
index 00261f7..833eae9 100644
--- a/source3/auth/auth.c
+++ b/source3/auth/auth.c
@@ -436,7 +436,7 @@ static NTSTATUS make_auth_context_text_list(TALLOC_CTX *mem_ctx,
 
 	for (;*text_list; text_list++) { 
 		if (load_auth_module(*auth_context, *text_list, &t)) {
-		    DLIST_ADD_END(list, t, auth_methods *);
+		    DLIST_ADD_END(list, t);
 		}
 	}
 
diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c
index 0a80d17..e68c702 100644
--- a/source3/auth/auth_samba4.c
+++ b/source3/auth/auth_samba4.c
@@ -20,6 +20,7 @@
 
 #include "includes.h"
 #include "source3/include/auth.h"
+#include "source3/include/messages.h"
 #include "source4/auth/auth.h"
 #include "auth/auth_sam_reply.h"
 #include "param/param.h"
@@ -48,6 +49,7 @@ static int free_task_id(struct server_id *server_id)
  * (ie, use talloc_free()) */
 static struct server_id *new_server_id_task(TALLOC_CTX *mem_ctx)
 {
+	struct messaging_context *msg_ctx;
 	struct server_id *server_id;
 	int task_id;
 	if (!task_id_tree) {
@@ -57,12 +59,17 @@ static struct server_id *new_server_id_task(TALLOC_CTX *mem_ctx)
 		}
 	}
 
+	msg_ctx = server_messaging_context();
+	if (msg_ctx == NULL) {
+		return NULL;
+	}
+
 	server_id = talloc(mem_ctx, struct server_id);
 
 	if (!server_id) {
 		return NULL;
 	}
-	*server_id = procid_self();
+	*server_id = messaging_server_id(msg_ctx);
 
 	/* 0 is the default server_id, so we need to start with 1 */
 	task_id = idr_get_new_above(task_id_tree, server_id, 1, INT32_MAX);
diff --git a/source3/auth/pampass.c b/source3/auth/pampass.c
index 2a3195c..1a82fe7 100644
--- a/source3/auth/pampass.c
+++ b/source3/auth/pampass.c
@@ -237,7 +237,7 @@ static struct chat_struct *make_pw_chat(const char *p)
 
 		ZERO_STRUCTP(t);
 
-		DLIST_ADD_END(list, t, struct chat_struct*);
+		DLIST_ADD_END(list, t);
 
 		if (!next_token_talloc(frame, &p, &prompt, NULL)) {
 			break;
diff --git a/source3/client/clitar.c b/source3/client/clitar.c
index 7eb3fa0..8703f6b 100644
--- a/source3/client/clitar.c
+++ b/source3/client/clitar.c
@@ -720,7 +720,11 @@ out_close:
 		}
 	}
 out:
+#ifdef HAVE_ARCHIVE_READ_FREE
 	archive_write_free(t->archive);
+#else
+	archive_write_finish(t->archive);
+#endif
 	talloc_free(ctx);
 	return err;
 }
@@ -1002,7 +1006,9 @@ static int tar_extract(struct tar *t)
 
 	t->archive = archive_read_new();
 	archive_read_support_format_all(t->archive);
+#ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL
 	archive_read_support_filter_all(t->archive);
+#endif
 
 	if (strequal(t->tar_path, "-")) {
 		r = archive_read_open_fd(t->archive, STDIN_FILENO, bsize);
@@ -1053,7 +1059,11 @@ static int tar_extract(struct tar *t)
 	}
 
 out:
+#ifdef HAVE_ARCHIVE_READ_FREE
 	r = archive_read_free(t->archive);
+#else
+	r = archive_read_finish(t->archive);
+#endif
 	if (r != ARCHIVE_OK) {
 		DBG(0, ("Can't close %s : %s\n", t->tar_path,
 					archive_error_string(t->archive)));
@@ -1387,7 +1397,7 @@ static NTSTATUS tar_create_skip_path(struct tar *t,
 
 	if (!isdir) {
 
-		/* 1. if we dont want X and we have X, skip */
+		/* 1. if we don't want X and we have X, skip */
 		if (!t->mode.system && (mode & FILE_ATTRIBUTE_SYSTEM)) {
 			*_skip = true;
 			return NT_STATUS_OK;
diff --git a/source3/client/dnsbrowse.c b/source3/client/dnsbrowse.c
index 03f87af..be6eb88 100644
--- a/source3/client/dnsbrowse.c
+++ b/source3/client/dnsbrowse.c
@@ -168,7 +168,7 @@ int do_smb_browse(void)
 	for (;;)  {
 		int revents;
 
-		ret = poll_one_fd(mdnsfd, POLLIN|POLLHUP, &revents, 1000);
+		ret = poll_one_fd(mdnsfd, POLLIN|POLLHUP, 1000, &revents);
 		if (ret <= 0 && errno != EINTR) {
 			break;
 		}
diff --git a/source3/client/smbspool.c b/source3/client/smbspool.c
index 7161e86..e381822 100644
--- a/source3/client/smbspool.c
+++ b/source3/client/smbspool.c
@@ -346,8 +346,8 @@ get_exit_code(struct cli_state * cli,
 	};
 
 
-	fprintf(stderr, "DEBUG: get_exit_code(cli=%p, nt_status=%x)\n",
-		cli, NT_STATUS_V(nt_status));
+	fprintf(stderr, "DEBUG: get_exit_code(cli=%p, nt_status=%s [%x])\n",
+		cli, nt_errstr(nt_status), NT_STATUS_V(nt_status));
 
 	for (i = 0; i < ARRAY_SIZE(auth_errors); i++) {
 		if (!NT_STATUS_EQUAL(nt_status, auth_errors[i])) {
diff --git a/source3/include/MacExtensions.h b/source3/include/MacExtensions.h
index 5b00998..23dcde9 100644
--- a/source3/include/MacExtensions.h
+++ b/source3/include/MacExtensions.h
@@ -80,18 +80,18 @@ typedef struct _SambaAfpInfo
 */
 
 /*
-** These extentions are only supported with the NT LM 0.12 Dialect. These extentions
+** These extensions are only supported with the NT LM 0.12 Dialect. These extentions
 ** will be process on a share by share bases.
 */
 
 /*
-** Trans2_Query_FS_Information Call is used by the MacCIFS extentions for three reasons.
-** First to see if the remote server share supports the basic Macintosh CIFS extentions.
+** Trans2_Query_FS_Information Call is used by the MacCIFS extensions for three reasons.
+** First to see if the remote server share supports the basic Macintosh CIFS extensions.
 ** Second to return some basic need information about the share to the Macintosh.
-** Third to see if this share support any other Macintosh extentions.
+** Third to see if this share support any other Macintosh extensions.
 **
 ** We will be using infromation levels that are betwwen 0x300 and 0x399 for all Macintosh
-** extentions calls. The first of these will be the SMB_MAC_QUERY_FS_INFO level which
+** extensions calls. The first of these will be the SMB_MAC_QUERY_FS_INFO level which
 ** will allow the server to return the MacQueryFSInfo structure. All fields are Little
 ** Endian unless other wise specified.
 */
diff --git a/source3/include/ads.h b/source3/include/ads.h
index daea56d..cacb25c 100644
--- a/source3/include/ads.h
+++ b/source3/include/ads.h
@@ -32,8 +32,6 @@ typedef struct ads_struct {
 		char *realm;
 		char *workgroup;
 		char *ldap_server;
-		int foreign; /* set to 1 if connecting to a foreign
-			      * realm */
 		bool gc;     /* Is this a global catalog server? */
 	} server;
 
diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h
index b60a0e5..27993c7 100644
--- a/source3/include/ctdbd_conn.h
+++ b/source3/include/ctdbd_conn.h
@@ -26,76 +26,72 @@ struct ctdbd_connection;
 struct messaging_context;
 struct messaging_rec;
 
-NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx,
-				    struct ctdbd_connection **pconn);
+int ctdbd_messaging_connection(TALLOC_CTX *mem_ctx,
+			       const char *sockname, int timeout,
+			       struct ctdbd_connection **pconn);
 
 uint32_t ctdbd_vnn(const struct ctdbd_connection *conn);
-const char *lp_ctdbd_socket(void);
 
-NTSTATUS ctdbd_register_msg_ctx(struct ctdbd_connection *conn,
-				struct messaging_context *msg_ctx);
+int ctdbd_register_msg_ctx(struct ctdbd_connection *conn,
+			   struct messaging_context *msg_ctx,
+			   struct tevent_context *ev);
 struct messaging_context *ctdb_conn_msg_ctx(struct ctdbd_connection *conn);
 
 int ctdbd_conn_get_fd(struct ctdbd_connection *conn);
 
-NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
-				  uint32_t dst_vnn, uint64_t dst_srvid,
-				  const struct iovec *iov, int iovlen);
+int ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
+			     uint32_t dst_vnn, uint64_t dst_srvid,
+			     const struct iovec *iov, int iovlen);
 
 bool ctdbd_process_exists(struct ctdbd_connection *conn, uint32_t vnn,
 			  pid_t pid);
 bool ctdb_processes_exist(struct ctdbd_connection *conn,
 			  const struct server_id *pids, int num_pids,
 			  bool *results);
-bool ctdb_serverids_exist_supported(struct ctdbd_connection *conn);
-bool ctdb_serverids_exist(struct ctdbd_connection *conn,
-			  const struct server_id *pids, unsigned num_pids,
-			  bool *results);
 
 char *ctdbd_dbpath(struct ctdbd_connection *conn,
 		   TALLOC_CTX *mem_ctx, uint32_t db_id);
 
-NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, const char *name,
-			 uint32_t *db_id, int tdb_flags);
-
-NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id,
-		       TDB_DATA key);
-
-NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id,
-		     TDB_DATA key, bool local_copy,
-		     void (*parser)(TDB_DATA key, TDB_DATA data,
-				    void *private_data),
-		     void *private_data);
-
-NTSTATUS ctdbd_traverse(uint32_t db_id,
-			void (*fn)(TDB_DATA key, TDB_DATA data,
-				   void *private_data),
+int ctdbd_db_attach(struct ctdbd_connection *conn, const char *name,
+		    uint32_t *db_id, int tdb_flags);
+
+int ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key);
+
+int ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id,
+		TDB_DATA key, bool local_copy,
+		void (*parser)(TDB_DATA key, TDB_DATA data,
+			       void *private_data),
+		void *private_data);
+
+int ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id,
+		   void (*fn)(TDB_DATA key, TDB_DATA data,
+			      void *private_data),
+		   void *private_data);
+
+int ctdbd_register_ips(struct ctdbd_connection *conn,
+		       const struct sockaddr_storage *server,
+		       const struct sockaddr_storage *client,
+		       int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+				 uint64_t dst_srvid,
+				 const uint8_t *msg, size_t msglen,
+				 void *private_data),
+		       void *private_data);
+
+int ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode,
+			uint64_t srvid, uint32_t flags, TDB_DATA data,
+			TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
+			int *cstatus);
+int ctdb_watch_us(struct ctdbd_connection *conn);
+int ctdb_unwatch(struct ctdbd_connection *conn);
+
+struct ctdb_req_message_old;
+
+int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
+			int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+				  uint64_t dst_srvid,
+				  const uint8_t *msg, size_t msglen,
+				  void *private_data),
 			void *private_data);
-
-NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
-			    const struct sockaddr_storage *server,
-			    const struct sockaddr_storage *client,
-			    int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
-				      uint64_t dst_srvid,
-				      const uint8_t *msg, size_t msglen,
-				      void *private_data),
-			    void *private_data);
-
-NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode,
-			     uint64_t srvid, uint32_t flags, TDB_DATA data,
-			     TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
-			     int *cstatus);
-NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn);
-NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn);
-
-struct ctdb_req_message;
-
-NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
-			     int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
-				       uint64_t dst_srvid,
-				       const uint8_t *msg, size_t msglen,
-				       void *private_data),
-			     void *private_data);
-NTSTATUS ctdbd_probe(void);
+int ctdbd_probe(const char *sockname, int timeout);
 
 #endif /* _CTDBD_CONN_H */
diff --git a/source3/include/messages.h b/source3/include/messages.h
index c620f92..8bbe026 100644
--- a/source3/include/messages.h
+++ b/source3/include/messages.h
@@ -59,6 +59,8 @@
 #define MSG_SRVID_SAMBA 0x0000000100000000LL
 
 #include "librpc/gen_ndr/server_id.h"
+#include "lib/util/data_blob.h"
+#include "system/network.h"
 
 #define MSG_BROADCAST_PID_STR	"0:0"
 
@@ -74,9 +76,9 @@ struct messaging_backend {
 	void *private_data;
 };
 
-NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx,
-			      TALLOC_CTX *mem_ctx,
-			      struct messaging_backend **presult);
+int messaging_ctdbd_init(struct messaging_context *msg_ctx,
+			 TALLOC_CTX *mem_ctx,
+			 struct messaging_backend **presult);
 struct ctdbd_connection *messaging_ctdbd_connection(void);
 
 bool message_send_all(struct messaging_context *msg_ctx,
@@ -123,11 +125,11 @@ NTSTATUS messaging_send(struct messaging_context *msg_ctx,
 NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx,
 			    struct server_id server, uint32_t msg_type,
 			    const uint8_t *buf, size_t len);
-NTSTATUS messaging_send_iov_from(struct messaging_context *msg_ctx,
-				 struct server_id src, struct server_id dst,
-				 uint32_t msg_type,
-				 const struct iovec *iov, int iovlen,
-				 const int *fds, size_t num_fds);
+int messaging_send_iov_from(struct messaging_context *msg_ctx,
+			    struct server_id src, struct server_id dst,
+			    uint32_t msg_type,
+			    const struct iovec *iov, int iovlen,
+			    const int *fds, size_t num_fds);
 NTSTATUS messaging_send_iov(struct messaging_context *msg_ctx,
 			    struct server_id server, uint32_t msg_type,
 			    const struct iovec *iov, int iovlen,
diff --git a/source3/include/ntquotas.h b/source3/include/ntquotas.h
index d8a0dc3..6fbbbb9 100644
--- a/source3/include/ntquotas.h
+++ b/source3/include/ntquotas.h
@@ -63,7 +63,7 @@ enum SMB_QUOTA_TYPE {
 	SMB_USER_FS_QUOTA_TYPE = 1,
 	SMB_USER_QUOTA_TYPE = 2,
 	SMB_GROUP_FS_QUOTA_TYPE = 3,/* not used yet */
-	SMB_GROUP_QUOTA_TYPE = 4 /* not in use yet, maybe for disk_free queries */
+	SMB_GROUP_QUOTA_TYPE = 4 /* used by disk_free queries */
 };
 
 typedef struct _SMB_NTQUOTA_STRUCT {
diff --git a/source3/include/passdb.h b/source3/include/passdb.h
index 893d0d0..8175829 100644
--- a/source3/include/passdb.h
+++ b/source3/include/passdb.h
@@ -688,7 +688,6 @@ bool login_cache_delentry(const struct samu *sampass);
 
 /* The following definitions come from passdb/passdb.c  */
 
-const char *my_sam_name(void);
 struct samu *samu_new( TALLOC_CTX *ctx );
 NTSTATUS samu_set_unix(struct samu *user, const struct passwd *pwd);
 NTSTATUS samu_alloc_rid_unix(struct pdb_methods *methods,
@@ -811,6 +810,7 @@ bool pdb_set_nt_passwd(struct samu *sampass, const uint8_t pwd[NT_HASH_LEN], enu
 bool pdb_set_lanman_passwd(struct samu *sampass, const uint8_t pwd[LM_HASH_LEN], enum pdb_value_state flag);
 bool pdb_set_pw_history(struct samu *sampass, const uint8_t *pwd, uint32_t historyLen, enum pdb_value_state flag);
 bool pdb_set_plaintext_pw_only(struct samu *sampass, const char *password, enum pdb_value_state flag);
+bool pdb_update_history(struct samu *sampass, const uint8_t new_nt[NT_HASH_LEN]);
 bool pdb_set_bad_password_count(struct samu *sampass, uint16_t bad_password_count, enum pdb_value_state flag);
 bool pdb_set_logon_count(struct samu *sampass, uint16_t logon_count, enum pdb_value_state flag);
 bool pdb_set_country_code(struct samu *sampass, uint16_t country_code,
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 4b86db0..e18aaf4 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -88,26 +88,7 @@ int map_errno_from_nt_status(NTSTATUS status);
 
 struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_STAT *sbuf);
 
-/* The following definitions come from lib/gencache.c  */
-
-bool gencache_set(const char *keystr, const char *value, time_t timeout);
-bool gencache_del(const char *keystr);
-bool gencache_get(const char *keystr, TALLOC_CTX *mem_ctx, char **value,
-		  time_t *ptimeout);
-bool gencache_parse(const char *keystr,
-		    void (*parser)(time_t timeout, DATA_BLOB blob,
-				   void *private_data),
-		    void *private_data);
-bool gencache_get_data_blob(const char *keystr, TALLOC_CTX *mem_ctx,
-			    DATA_BLOB *blob,
-			    time_t *timeout, bool *was_expired);
-bool gencache_stabilize(void);
-bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob, time_t timeout);
-void gencache_iterate_blobs(void (*fn)(const char *key, DATA_BLOB value,
-				       time_t timeout, void *private_data),
-			    void *private_data, const char *pattern);
-void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout, void* dptr),
-                      void* data, const char* keystr_pattern);
+#include "lib/gencache.h"
 
 /* The following definitions come from lib/interface.c  */
 
@@ -347,6 +328,7 @@ struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user);
 
 /* The following definitions come from lib/util_names.c  */
 const char *get_global_sam_name(void);
+const char *my_sam_name(void);
 
 /* The following definitions come from lib/util.c  */
 
@@ -376,10 +358,12 @@ int set_blocking(int fd, bool set);
 NTSTATUS init_before_fork(void);
 NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
 			   struct tevent_context *ev_ctx,
-			   bool parent_longlived);
+			   bool parent_longlived,
+			   const char *comment);
 NTSTATUS smbd_reinit_after_fork(struct messaging_context *msg_ctx,
 				struct tevent_context *ev_ctx,
-				bool parent_longlived);
+				bool parent_longlived,
+				const char *comment);
 void *malloc_(size_t size);
 void *Realloc(void *p, size_t size, bool free_old_on_error);
 void add_to_large_array(TALLOC_CTX *mem_ctx, size_t element_size,
@@ -417,9 +401,7 @@ int smb_mkstemp(char *name_template);
 void *smb_xmalloc_array(size_t size, unsigned int count);
 char *myhostname(void);
 char *myhostname_upper(void);
-char *lock_path(const char *name);
-char *state_path(const char *name);
-char *cache_path(const char *name);
+#include "lib/util_path.h"
 bool parent_dirname(TALLOC_CTX *mem_ctx, const char *dir, char **parent,
 		    const char **name);
 bool ms_has_wild(const char *s);
@@ -429,19 +411,12 @@ bool mask_match_search(const char *string, const char *pattern, bool is_case_sen
 bool mask_match_list(const char *string, char **list, int listLen, bool is_case_sensitive);
 bool unix_wild_match(const char *pattern, const char *string);
 bool name_to_fqdn(fstring fqdn, const char *name);
-void *talloc_append_blob(TALLOC_CTX *mem_ctx, void *buf, DATA_BLOB blob);
 uint32_t map_share_mode_to_deny_mode(uint32_t share_access, uint32_t private_options);
-pid_t procid_to_pid(const struct server_id *proc);
-void set_my_vnn(uint32_t vnn);
-uint32_t get_my_vnn(void);
-void set_my_unique_id(uint64_t unique_id);
-struct server_id pid_to_procid(pid_t pid);
-struct server_id procid_self(void);
+
+#include "lib/util_procid.h"
+
 #define serverid_equal(p1, p2) server_id_equal(p1,p2)
-bool procid_is_me(const struct server_id *pid);
 struct server_id interpret_pid(const char *pid_string);
-bool procid_valid(const struct server_id *pid);
-bool procid_is_local(const struct server_id *pid);
 bool is_offset_safe(const char *buf_base, size_t buf_len, char *ptr, size_t off);
 char *get_safe_ptr(const char *buf_base, size_t buf_len, char *ptr, size_t off);
 char *get_safe_str_ptr(const char *buf_base, size_t buf_len, char *ptr, size_t off);
@@ -525,7 +500,7 @@ char *sid_to_fstring(fstring sidstr_out, const struct dom_sid *sid);
 char *sid_string_talloc(TALLOC_CTX *mem_ctx, const struct dom_sid *sid);
 char *sid_string_dbg(const struct dom_sid *sid);
 char *sid_string_tos(const struct dom_sid *sid);
-bool sid_linearize(char *outbuf, size_t len, const struct dom_sid *sid);
+bool sid_linearize(uint8_t *outbuf, size_t len, const struct dom_sid *sid);
 bool non_mappable_sid(struct dom_sid *sid);
 char *sid_binstring_hex_talloc(TALLOC_CTX *mem_ctx, const struct dom_sid *sid);
 struct netr_SamInfo3;
@@ -626,17 +601,6 @@ struct tevent_req *getaddrinfo_send(TALLOC_CTX *mem_ctx,
 int getaddrinfo_recv(struct tevent_req *req, struct addrinfo **res);
 int poll_one_fd(int fd, int events, int timeout, int *revents);
 int poll_intr_one_fd(int fd, int events, int timeout, int *revents);
-struct tstream_context;
-struct tevent_req *tstream_read_packet_send(TALLOC_CTX *mem_ctx,
-					    struct tevent_context *ev,
-					    struct tstream_context *stream,
-					    size_t initial,
-					    ssize_t (*more)(uint8_t *buf,
-							    size_t buflen,
-							    void *private_data),
-					    void *private_data);
-ssize_t tstream_read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-				 uint8_t **pbuf, int *perrno);
 
 /* The following definitions come from lib/util_str.c  */
 
@@ -768,7 +732,6 @@ void flush_negative_conn_cache_for_domain(const char *domain);
 
 struct netr_DsRGetDCNameInfo;
 
-void debug_dsdcinfo_flags(int lvl, uint32_t flags);
 NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
 		     struct messaging_context *msg_ctx,
 		     const char *domain_name,
@@ -1003,6 +966,9 @@ const char *lp_parm_const_string_service(struct loadparm_service *service, const
 const char **lp_parm_string_list(int snum, const char *type, const char *option, const char **def);
 int lp_parm_int(int snum, const char *type, const char *option, int def);
 unsigned long lp_parm_ulong(int snum, const char *type, const char *option, unsigned long def);
+unsigned long long lp_parm_ulonglong(int snum, const char *type,
+				     const char *option,
+				     unsigned long long def);
 bool lp_parm_bool(int snum, const char *type, const char *option, bool def);
 struct enum_list;
 int lp_parm_enum(int snum, const char *type, const char *option,
@@ -1212,6 +1178,11 @@ bool sid_check_is_in_unix_groups(const struct dom_sid *sid);
 const char *unix_groups_domain_name(void);
 bool lookup_unix_group_name(const char *name, struct dom_sid *sid);
 
+/* The following definitions come from lib/util_specialsids.c  */
+bool sid_check_is_asserted_identity(const struct dom_sid *sid);
+bool sid_check_is_in_asserted_identity(const struct dom_sid *sid);
+const char *asserted_identity_domain_name(void);
+
 /* The following definitions come from lib/filename_util.c */
 
 NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_fname,
diff --git a/source3/include/samba_linux_quota.h b/source3/include/samba_linux_quota.h
index 8dbbec2..51acc20 100644
--- a/source3/include/samba_linux_quota.h
+++ b/source3/include/samba_linux_quota.h
@@ -227,7 +227,7 @@ struct if_dqinfo {
 	#endif
 #endif
 
-long quotactl __P((int, const char *, qid_t, caddr_t));
+long quotactl(int, const char *, qid_t, caddr_t);
 
 #endif /* _QUOTA_LINUX */
 
diff --git a/source3/include/secrets.h b/source3/include/secrets.h
index 350bdc6..f397129 100644
--- a/source3/include/secrets.h
+++ b/source3/include/secrets.h
@@ -113,6 +113,7 @@ bool secrets_delete_machine_password_ex(const char *domain);
 bool secrets_delete_domain_sid(const char *domain);
 bool secrets_store_machine_password(const char *pass, const char *domain, enum netr_SchannelType sec_channel);
 char *secrets_fetch_prev_machine_password(const char *domain);
+time_t secrets_fetch_pass_last_set_time(const char *domain);
 char *secrets_fetch_machine_password(const char *domain,
 				     time_t *pass_last_set_time,
 				     enum netr_SchannelType *channel);
diff --git a/source3/include/serverid.h b/source3/include/serverid.h
index d1d405a..5db61b9 100644
--- a/source3/include/serverid.h
+++ b/source3/include/serverid.h
@@ -20,7 +20,7 @@
 #ifndef __SERVERID_H__
 #define __SERVERID_H__
 
-#include "includes.h"
+#include "replace.h"
 #include "lib/dbwrap/dbwrap.h"
 
 /*
@@ -39,11 +39,6 @@ bool serverid_deregister(const struct server_id id);
 bool serverid_exists(const struct server_id *id);
 
 /*
- * Check existence of a list of server ids
- */
-bool serverids_exist(const struct server_id *ids, int num_ids, bool *results);
-
-/*
  * Walk the list of server_ids registered
  */
 bool serverid_traverse(int (*fn)(struct db_record *rec,
@@ -64,10 +59,4 @@ bool serverid_traverse_read(int (*fn)(const struct server_id *id,
  */
 bool serverid_parent_init(TALLOC_CTX *mem_ctx);
 
-/*
- * Get a random unique_id and make sure that it is not
- * SERVERID_UNIQUE_ID_NOT_TO_VERIFY
- */
-uint64_t serverid_get_random_unique_id(void);
-
 #endif
diff --git a/source3/include/session.h b/source3/include/session.h
index fe41954..c32c8b0 100644
--- a/source3/include/session.h
+++ b/source3/include/session.h
@@ -38,6 +38,9 @@ struct sessionid {
 	struct server_id pid;
 	fstring ip_addr_str;
 	time_t connect_start;
-	fstring protocol_ver;
+	uint16_t connection_dialect;
+	uint8_t encryption_flags;
+	uint16_t cipher;
+	uint8_t signing_flags;
 };
 
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 751b0e6..7eeef88 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -30,7 +30,7 @@
 #include "libds/common/roles.h"
 
 /* logged when starting the various Samba daemons */
-#define COPYRIGHT_STARTUP_MESSAGE	"Copyright Andrew Tridgell and the Samba Team 1992-2015"
+#define COPYRIGHT_STARTUP_MESSAGE	"Copyright Andrew Tridgell and the Samba Team 1992-2016"
 
 #define SAFETY_MARGIN 1024
 #define LARGE_WRITEX_HDR_SIZE 65
@@ -181,6 +181,9 @@ struct interface {
 	struct sockaddr_storage ip;
 	struct sockaddr_storage netmask;
 	struct sockaddr_storage bcast;
+	uint32_t if_index;
+	uint64_t linkspeed;
+	uint32_t capability;
 };
 
 #define SHARE_MODE_FLAG_POSIX_OPEN	0x1
@@ -484,11 +487,6 @@ Offset  Data			length.
 
 #define SMB_SUCCESS 0  /* The request was successful. */
 
-#ifdef WITH_DFS
-void dfs_unlogin(void);
-extern int dcelogin_atmost_once;
-#endif
-
 #ifdef NOSTRDUP
 char *strdup(char *s);
 #endif
diff --git a/source3/include/smb_ldap.h b/source3/include/smb_ldap.h
index eaa1276..19e4be5 100644
--- a/source3/include/smb_ldap.h
+++ b/source3/include/smb_ldap.h
@@ -78,7 +78,7 @@ struct ldapsam_privates;
 
 #define LDAP_DEFAULT_TIMEOUT   15
 #define LDAP_CONNECTION_DEFAULT_TIMEOUT 2
-#define LDAP_PAGE_SIZE 1024
+#define LDAP_PAGE_SIZE 1000
 
 #define ADS_PAGE_CTL_OID 	"1.2.840.113556.1.4.319"
 
diff --git a/source3/include/smbprofile.h b/source3/include/smbprofile.h
index 76d9d2b..c771fd4 100644
--- a/source3/include/smbprofile.h
+++ b/source3/include/smbprofile.h
@@ -533,7 +533,7 @@ static inline bool smbprofile_dump_pending(void)
 
 void smbprofile_dump(void);
 
-void smbprofile_cleanup(pid_t pid);
+void smbprofile_cleanup(pid_t pid, pid_t dst);
 void smbprofile_stats_accumulate(struct profile_stats *acc,
 				 const struct profile_stats *add);
 void smbprofile_collect(struct profile_stats *stats);
@@ -610,7 +610,7 @@ static inline void smbprofile_dump(void)
 	return;
 }
 
-static inline void smbprofile_cleanup(pid_t pid)
+static inline void smbprofile_cleanup(pid_t pid, pid_t dst)
 {
 	return;
 }
diff --git a/source3/include/tldap.h b/source3/include/tldap.h
index 36cbdce..1c704b4 100644
--- a/source3/include/tldap.h
+++ b/source3/include/tldap.h
@@ -22,6 +22,7 @@
 
 #include <talloc.h>
 #include <tevent.h>
+#include "lib/util/data_blob.h"
 
 struct tldap_context;
 struct tldap_message;
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index d839be4..c18ea59 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -167,8 +167,11 @@
 /* Version 33 - Add snapshot create/delete calls */
 /* Version 33 - Add OS X SMB2 AAPL copyfile extension flag to fsp */
 /* Version 33 - Remove notify_watch_fn */
+/* Bump to version 34 - Samba 4.4 will ship with that */
+/* Version 34 - Remove bool posix_open, add uint64_t posix_flags */
+/* Version 34 - Added bool posix_pathnames to struct smb_request */
 
-#define SMB_VFS_INTERFACE_VERSION 33
+#define SMB_VFS_INTERFACE_VERSION 34
 
 /*
     All intercepted VFS operations must be declared as static functions inside module source
@@ -218,9 +221,6 @@ struct fsp_lease {
 	struct smb2_lease lease;
 };
 
-/* VFS ABI stability hack */
-#define posix_flags posix_open
-
 typedef struct files_struct {
 	struct files_struct *next, *prev;
 	uint64_t fnum;
@@ -258,7 +258,7 @@ typedef struct files_struct {
 	bool aio_write_behind;
 	bool initial_delete_on_close; /* Only set at NTCreateX if file was created. */
 	bool delete_on_close;
-	uint8_t posix_flags;
+	uint64_t posix_flags;
 	bool is_sparse;
 	bool backup_intent; /* Handle was successfully opened with backup intent
 				and opener has privilege to do so. */
@@ -302,9 +302,11 @@ typedef struct files_struct {
 
 #define FSP_POSIX_FLAGS_OPEN		0x01
 #define FSP_POSIX_FLAGS_RENAME		0x02
+#define FSP_POSIX_FLAGS_PATHNAMES	0x04
 
 #define FSP_POSIX_FLAGS_ALL			\
 	(FSP_POSIX_FLAGS_OPEN |			\
+	 FSP_POSIX_FLAGS_PATHNAMES |		\
 	 FSP_POSIX_FLAGS_RENAME)
 
 struct vuid_cache_entry {
@@ -463,6 +465,8 @@ struct smb_request {
 	struct smb_request **chain;
 
 	struct timeval request_time;
+
+	bool posix_pathnames;
 };
 
 /*
@@ -522,7 +526,9 @@ struct vfs_fn_pointers {
 	void (*disconnect_fn)(struct vfs_handle_struct *handle);
 	uint64_t (*disk_free_fn)(struct vfs_handle_struct *handle, const char *path, uint64_t *bsize,
 			      uint64_t *dfree, uint64_t *dsize);
-	int (*get_quota_fn)(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt);
+	int (*get_quota_fn)(struct vfs_handle_struct *handle, const char *path,
+			    enum SMB_QUOTA_TYPE qtype, unid_t id,
+			    SMB_DISK_QUOTA *qt);
 	int (*set_quota_fn)(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt);
 	int (*get_shadow_copy_data_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, struct shadow_copy_data *shadow_copy_data, bool labels);
 	int (*statvfs_fn)(struct vfs_handle_struct *handle, const char *path, struct vfs_statvfs_struct *statbuf);
@@ -927,7 +933,7 @@ void smb_vfs_call_disconnect(struct vfs_handle_struct *handle);
 uint64_t smb_vfs_call_disk_free(struct vfs_handle_struct *handle,
 				const char *path, uint64_t *bsize,
 				uint64_t *dfree, uint64_t *dsize);
-int smb_vfs_call_get_quota(struct vfs_handle_struct *handle,
+int smb_vfs_call_get_quota(struct vfs_handle_struct *handle, const char *path,
 			   enum SMB_QUOTA_TYPE qtype, unid_t id,
 			   SMB_DISK_QUOTA *qt);
 int smb_vfs_call_set_quota(struct vfs_handle_struct *handle,
diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
index eaf0c19..16d5bfd 100644
--- a/source3/include/vfs_macros.h
+++ b/source3/include/vfs_macros.h
@@ -44,10 +44,10 @@
 #define SMB_VFS_NEXT_DISK_FREE(handle, path, bsize, dfree ,dsize)\
 	smb_vfs_call_disk_free((handle)->next, (path), (bsize), (dfree), (dsize))
 
-#define SMB_VFS_GET_QUOTA(conn, qtype, id, qt) \
-	smb_vfs_call_get_quota((conn)->vfs_handles, (qtype), (id), (qt))
-#define SMB_VFS_NEXT_GET_QUOTA(handle, qtype, id, qt) \
-	smb_vfs_call_get_quota((handle)->next, (qtype), (id), (qt))
+#define SMB_VFS_GET_QUOTA(conn, path, qtype, id, qt)                           \
+	smb_vfs_call_get_quota((conn)->vfs_handles, (path), (qtype), (id), (qt))
+#define SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, qt)                    \
+	smb_vfs_call_get_quota((handle)->next, (path), (qtype), (id), (qt))
 
 #define SMB_VFS_SET_QUOTA(conn, qtype, id, qt) \
 	smb_vfs_call_set_quota((conn)->vfs_handles, (qtype), (id), (qt))
diff --git a/source3/lib/background.c b/source3/lib/background.c
index 4ea1282..3c8eb58 100644
--- a/source3/lib/background.c
+++ b/source3/lib/background.c
@@ -176,7 +176,7 @@ static void background_job_waited(struct tevent_req *subreq)
 
 		close(fds[0]);
 
-		status = reinit_after_fork(state->msg, state->ev, true);
+		status = reinit_after_fork(state->msg, state->ev, true, NULL);
 		if (NT_STATUS_IS_OK(status)) {
 			res = state->fn(state->private_data);
 		} else {
diff --git a/source3/lib/cluster_support.c b/source3/lib/cluster_support.c
index b8925aa..c11b1f7 100644
--- a/source3/lib/cluster_support.c
+++ b/source3/lib/cluster_support.c
@@ -54,3 +54,19 @@ const char *cluster_support_features(void)
 
 	return v;
 }
+
+const char *lp_ctdbd_socket(void)
+{
+	const char *ret;
+
+	ret = lp__ctdbd_socket();
+	if (ret != NULL && strlen(ret) > 0) {
+		return ret;
+	}
+
+#ifdef CTDB_SOCKET
+	return CTDB_SOCKET;
+#else
+	return "";
+#endif
+}
diff --git a/source3/lib/cluster_support.h b/source3/lib/cluster_support.h
index 0a03d2b..5e040bb 100644
--- a/source3/lib/cluster_support.h
+++ b/source3/lib/cluster_support.h
@@ -18,3 +18,4 @@
 
 bool cluster_support_available(void);
 const char *cluster_support_features(void);
+const char *lp_ctdbd_socket(void);
diff --git a/source3/lib/conn_tdb.c b/source3/lib/conn_tdb.c
index bf66d7d..36d5fae 100644
--- a/source3/lib/conn_tdb.c
+++ b/source3/lib/conn_tdb.c
@@ -41,6 +41,9 @@ struct connections_forall_session {
 	gid_t gid;
 	fstring machine;
 	fstring addr;
+	uint16_t cipher;
+	uint16_t dialect;
+	uint8_t signing_flags;
 };
 
 static int collect_sessions_fn(struct smbXsrv_session_global0 *global,
@@ -62,6 +65,9 @@ static int collect_sessions_fn(struct smbXsrv_session_global0 *global,
 	}
 	fstrcpy(sess.machine, global->channels[0].remote_name);
 	fstrcpy(sess.addr, global->channels[0].remote_address);
+	sess.cipher = global->channels[0].encryption_cipher;
+	sess.dialect = global->connection_dialect;
+	sess.signing_flags = global->signing_flags;
 
 	status = dbwrap_store(state->session_by_pid,
 			      make_tdb_data((void*)&id, sizeof(id)),
@@ -123,6 +129,10 @@ static int traverse_tcon_fn(struct smbXsrv_tcon_global0 *global,
 	fstrcpy(data.addr, sess.addr);
 	fstrcpy(data.machine, sess.machine);
 	data.start = nt_time_to_unix(global->creation_time);
+	data.encryption_flags = global->encryption_flags;
+	data.cipher = sess.cipher;
+	data.dialect = sess.dialect;
+	data.signing_flags = global->signing_flags;
 
 	state->count++;
 
diff --git a/source3/lib/conn_tdb.h b/source3/lib/conn_tdb.h
index 217814f..34f0019 100644
--- a/source3/lib/conn_tdb.h
+++ b/source3/lib/conn_tdb.h
@@ -33,6 +33,10 @@ struct connections_data {
 	fstring addr;
 	fstring machine;
 	time_t start;
+	uint8_t encryption_flags;
+	uint16_t cipher;
+	uint16_t dialect;
+	uint8_t signing_flags;
 };
 
 /* The following definitions come from lib/conn_tdb.c  */
diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index df05de7..5162242 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -24,60 +24,48 @@
 #include "lib/dbwrap/dbwrap_ctdb.h"
 #include "torture/proto.h"
 
-NTSTATUS ctdbd_probe(void)
+int ctdbd_probe(const char *sockname, int timeout)
 {
-	return NT_STATUS_NOT_IMPLEMENTED;
+	return ENOSYS;
 }
 
-NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
-				  uint32_t dst_vnn, uint64_t dst_srvid,
-				  const struct iovec *iov, int iovlen)
+int ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
+			     uint32_t dst_vnn, uint64_t dst_srvid,
+			     const struct iovec *iov, int iovlen)
 {
-	return NT_STATUS_NOT_IMPLEMENTED;
+	return ENOSYS;
 }
 
-NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
-			     int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
-				       uint64_t dst_srvid,
-				       const uint8_t *msg, size_t msglen,
-				       void *private_data),
-			     void *private_data)
+int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
+			int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+				  uint64_t dst_srvid,
+				  const uint8_t *msg, size_t msglen,
+				  void *private_data),
+			void *private_data)
 {
-	return NT_STATUS_NOT_IMPLEMENTED;
+	return ENOSYS;
 }
 
-NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
-			    const struct sockaddr_storage *_server,
-			    const struct sockaddr_storage *_client,
-			    int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
-				      uint64_t dst_srvid,
-				      const uint8_t *msg, size_t msglen,
-				      void *private_data),
-			    void *private_data)
+int ctdbd_register_ips(struct ctdbd_connection *conn,
+		       const struct sockaddr_storage *_server,
+		       const struct sockaddr_storage *_client,
+		       int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+				 uint64_t dst_srvid,
+				 const uint8_t *msg, size_t msglen,
+				 void *private_data),
+		       void *private_data)
 {
-	return NT_STATUS_NOT_IMPLEMENTED;
+	return ENOSYS;
 }
 
-const char *lp_ctdbd_socket(void)
-{
-	return "";
-}
-
-bool ctdb_serverids_exist_supported(struct ctdbd_connection *conn)
-{
-	return false;
-}
-
-bool ctdb_serverids_exist(struct ctdbd_connection *conn,
-			  const struct server_id *pids, unsigned num_pids,
+bool ctdb_processes_exist(struct ctdbd_connection *conn,
+			  const struct server_id *pids, int num_pids,
 			  bool *results)
 {
 	return false;
 }
 
-bool ctdb_processes_exist(struct ctdbd_connection *conn,
-			  const struct server_id *pids, int num_pids,
-			  bool *results)
+bool ctdbd_process_exists(struct ctdbd_connection *conn, uint32_t vnn, pid_t pid)
 {
 	return false;
 }
@@ -93,11 +81,11 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 	return NULL;
 }
 
-NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx,
-			      TALLOC_CTX *mem_ctx,
+int messaging_ctdbd_init(struct messaging_context *msg_ctx,
+			 TALLOC_CTX *mem_ctx,
 			      struct messaging_backend **presult)
 {
-	return NT_STATUS_NOT_IMPLEMENTED;
+	return ENOSYS;
 }
 
 struct ctdbd_connection *messaging_ctdbd_connection(void)
diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
index c19b6e5..04f6f2f 100644
--- a/source3/lib/ctdbd_conn.c
+++ b/source3/lib/ctdbd_conn.c
@@ -23,14 +23,13 @@
 #include "serverid.h"
 #include "ctdbd_conn.h"
 #include "system/select.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 #include "lib/util/iov_buf.h"
 
 #include "messages.h"
 
 /* paths to these include files come from --with-ctdb= in configure */
 
-#include "ctdb.h"
 #include "ctdb_private.h"
 
 struct ctdbd_srvid_cb {
@@ -43,6 +42,7 @@ struct ctdbd_srvid_cb {
 };
 
 struct ctdbd_connection {
+	const char *sockname;	/* Needed in ctdbd_traverse */
 	struct messaging_context *msg_ctx;
 	uint32_t reqid;
 	uint32_t our_vnn;
@@ -50,6 +50,7 @@ struct ctdbd_connection {
 	struct ctdbd_srvid_cb *callbacks;
 	int fd;
 	struct tevent_fd *fde;
+	int timeout;
 };
 
 static uint32_t ctdbd_next_reqid(struct ctdbd_connection *conn)
@@ -61,11 +62,12 @@ static uint32_t ctdbd_next_reqid(struct ctdbd_connection *conn)
 	return conn->reqid;
 }
 
-static NTSTATUS ctdbd_control(struct ctdbd_connection *conn,
-			      uint32_t vnn, uint32_t opcode,
-			      uint64_t srvid, uint32_t flags, TDB_DATA data,
-			      TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
-			      int *cstatus);
+static int ctdbd_control(struct ctdbd_connection *conn,
+			 uint32_t vnn, uint32_t opcode,
+			 uint64_t srvid, uint32_t flags,
+			 TDB_DATA data,
+			 TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
+			 int *cstatus);
 
 /*
  * exit on fatal communications errors with the ctdbd daemon
@@ -97,24 +99,23 @@ static void ctdb_packet_dump(struct ctdb_req_header *hdr)
 /*
  * Register a srvid with ctdbd
  */
-NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
-			     int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
-				       uint64_t dst_srvid,
-				       const uint8_t *msg, size_t msglen,
-				       void *private_data),
-			     void *private_data)
+int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
+			int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+				  uint64_t dst_srvid,
+				  const uint8_t *msg, size_t msglen,
+				  void *private_data),
+			void *private_data)
 {
 
-	NTSTATUS status;
-	int cstatus;
+	int ret, cstatus;
 	size_t num_callbacks;
 	struct ctdbd_srvid_cb *tmp;
 
-	status = ctdbd_control(conn, CTDB_CURRENT_NODE,
-			       CTDB_CONTROL_REGISTER_SRVID, srvid, 0,
-			       tdb_null, NULL, NULL, &cstatus);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	ret = ctdbd_control(conn, CTDB_CURRENT_NODE,
+			    CTDB_CONTROL_REGISTER_SRVID, srvid, 0,
+			    tdb_null, NULL, NULL, &cstatus);
+	if (ret != 0) {
+		return ret;
 	}
 
 	num_callbacks = talloc_array_length(conn->callbacks);
@@ -122,7 +123,7 @@ NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
 	tmp = talloc_realloc(conn, conn->callbacks, struct ctdbd_srvid_cb,
 			     num_callbacks + 1);
 	if (tmp == NULL) {
-		return NT_STATUS_NO_MEMORY;
+		return ENOMEM;
 	}
 	conn->callbacks = tmp;
 
@@ -130,22 +131,22 @@ NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
 		.srvid = srvid, .cb = cb, .private_data = private_data
 	};
 
-	return NT_STATUS_OK;
+	return 0;
 }
 
 static int ctdbd_msg_call_back(struct ctdbd_connection *conn,
-			       struct ctdb_req_message *msg)
+			       struct ctdb_req_message_old *msg)
 {
 	size_t msg_len;
 	size_t i, num_callbacks;
 
 	msg_len = msg->hdr.length;
-	if (msg_len < offsetof(struct ctdb_req_message, data)) {
+	if (msg_len < offsetof(struct ctdb_req_message_old, data)) {
 		DEBUG(10, ("%s: len %u too small\n", __func__,
 			   (unsigned)msg_len));
 		return 0;
 	}
-	msg_len -= offsetof(struct ctdb_req_message, data);
+	msg_len -= offsetof(struct ctdb_req_message_old, data);
 
 	if (msg_len < msg->datalen) {
 		DEBUG(10, ("%s: msg_len=%u < msg->datalen=%u\n", __func__,
@@ -175,19 +176,19 @@ static int ctdbd_msg_call_back(struct ctdbd_connection *conn,
 /*
  * get our vnn from the cluster
  */
-static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn)
+static int get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn)
 {
 	int32_t cstatus=-1;
-	NTSTATUS status;
-	status = ctdbd_control(conn,
-			       CTDB_CURRENT_NODE, CTDB_CONTROL_GET_PNN, 0, 0,
-			       tdb_null, NULL, NULL, &cstatus);
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(1, ("ctdbd_control failed: %s\n", nt_errstr(status)));
-		return status;
+	int ret;
+	ret = ctdbd_control(conn,
+			    CTDB_CURRENT_NODE, CTDB_CONTROL_GET_PNN, 0, 0,
+			    tdb_null, NULL, NULL, &cstatus);
+	if (ret != 0) {
+		DEBUG(1, ("ctdbd_control failed: %s\n", strerror(ret)));
+		return ret;
 	}
 	*vnn = (uint32_t)cstatus;
-	return status;
+	return ret;
 }
 
 /*
@@ -196,18 +197,17 @@ static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn)
 static bool ctdbd_working(struct ctdbd_connection *conn, uint32_t vnn)
 {
 	int32_t cstatus=-1;
-	NTSTATUS status;
 	TDB_DATA outdata;
-	struct ctdb_node_map *m;
+	struct ctdb_node_map_old *m;
 	uint32_t failure_flags;
-	bool ret = false;
-	int i;
-
-	status = ctdbd_control(conn, CTDB_CURRENT_NODE,
-			       CTDB_CONTROL_GET_NODEMAP, 0, 0,
-			       tdb_null, talloc_tos(), &outdata, &cstatus);
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(1, ("ctdbd_control failed: %s\n", nt_errstr(status)));
+	bool ok = false;
+	int i, ret;
+
+	ret = ctdbd_control(conn, CTDB_CURRENT_NODE,
+			    CTDB_CONTROL_GET_NODEMAP, 0, 0,
+			    tdb_null, talloc_tos(), &outdata, &cstatus);
+	if (ret != 0) {
+		DEBUG(1, ("ctdbd_control failed: %s\n", strerror(ret)));
 		return false;
 	}
 	if ((cstatus != 0) || (outdata.dptr == NULL)) {
@@ -215,7 +215,7 @@ static bool ctdbd_working(struct ctdbd_connection *conn, uint32_t vnn)
 		return false;
 	}
 
-	m = (struct ctdb_node_map *)outdata.dptr;
+	m = (struct ctdb_node_map_old *)outdata.dptr;
 
 	for (i=0; i<m->num; i++) {
 		if (vnn == m->nodes[i].pnn) {
@@ -238,10 +238,10 @@ static bool ctdbd_working(struct ctdbd_connection *conn, uint32_t vnn)
 		goto fail;
 	}
 
-	ret = true;
+	ok = true;
 fail:
 	TALLOC_FREE(outdata.dptr);
-	return ret;
+	return ok;
 }
 
 uint32_t ctdbd_vnn(const struct ctdbd_connection *conn)
@@ -249,25 +249,12 @@ uint32_t ctdbd_vnn(const struct ctdbd_connection *conn)
 	return conn->our_vnn;
 }
 
-const char *lp_ctdbd_socket(void)
-{
-	const char *ret;
-
-	ret = lp__ctdbd_socket();
-	if (ret != NULL && strlen(ret) > 0) {
-		return ret;
-	}
-
-	return CTDB_SOCKET;
-}
-
 /*
  * Get us a ctdb connection
  */
 
-static int ctdbd_connect(int *pfd)
+static int ctdbd_connect(const char *sockname, int *pfd)
 {
-	const char *sockname = lp_ctdbd_socket();
 	struct sockaddr_un addr = { 0, };
 	int fd;
 	socklen_t salen;
@@ -304,21 +291,16 @@ static int ctdbd_connect(int *pfd)
 	return 0;
 }
 
-static int ctdb_read_packet(int fd, TALLOC_CTX *mem_ctx,
+static int ctdb_read_packet(int fd, int timeout, TALLOC_CTX *mem_ctx,
 			    struct ctdb_req_header **result)
 {
-	int timeout = lp_ctdb_timeout();
 	struct ctdb_req_header *req;
 	int ret, revents;
 	uint32_t msglen;
 	ssize_t nread;
 
-	if (timeout == 0) {
-		timeout = -1;
-	}
-
 	if (timeout != -1) {
-		ret = poll_one_fd(fd, POLLIN, timeout, &revents);
+		ret = poll_intr_one_fd(fd, POLLIN, timeout, &revents);
 		if (ret == -1) {
 			return errno;
 		}
@@ -353,9 +335,11 @@ static int ctdb_read_packet(int fd, TALLOC_CTX *mem_ctx,
 	nread = read_data(fd, ((char *)req) + sizeof(msglen),
 			  msglen - sizeof(msglen));
 	if (nread == -1) {
+		TALLOC_FREE(req);
 		return errno;
 	}
 	if (nread == 0) {
+		TALLOC_FREE(req);
 		return EIO;
 	}
 
@@ -376,7 +360,7 @@ static int ctdb_read_req(struct ctdbd_connection *conn, uint32_t reqid,
 
  next_pkt:
 
-	ret = ctdb_read_packet(conn->fd, mem_ctx, &hdr);
+	ret = ctdb_read_packet(conn->fd, conn->timeout, mem_ctx, &hdr);
 	if (ret != 0) {
 		DEBUG(0, ("ctdb_read_packet failed: %s\n", strerror(ret)));
 		cluster_fatal("ctdbd died\n");
@@ -386,7 +370,7 @@ static int ctdb_read_req(struct ctdbd_connection *conn, uint32_t reqid,
 	ctdb_packet_dump(hdr);
 
 	if (hdr->operation == CTDB_REQ_MESSAGE) {
-		struct ctdb_req_message *msg = (struct ctdb_req_message *)hdr;
+		struct ctdb_req_message_old *msg = (struct ctdb_req_message_old *)hdr;
 
 		if (conn->msg_ctx == NULL) {
 			DEBUG(1, ("Got a message without having a msg ctx, "
@@ -432,85 +416,98 @@ static int ctdbd_connection_destructor(struct ctdbd_connection *c)
  * Get us a ctdbd connection
  */
 
-static NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,
-				      struct ctdbd_connection **pconn)
+static int ctdbd_init_connection(TALLOC_CTX *mem_ctx,
+				 const char *sockname, int timeout,
+				 struct ctdbd_connection **pconn)
 {
 	struct ctdbd_connection *conn;
 	int ret;
-	NTSTATUS status;
 
 	if (!(conn = talloc_zero(mem_ctx, struct ctdbd_connection))) {
 		DEBUG(0, ("talloc failed\n"));
-		return NT_STATUS_NO_MEMORY;
+		return ENOMEM;
+	}
+
+	conn->sockname = talloc_strdup(conn, sockname);
+	if (conn->sockname == NULL) {
+		DBG_ERR("talloc failed\n");
+		ret = ENOMEM;
+		goto fail;
+	}
+
+	conn->timeout = timeout;
+
+	if (conn->timeout == 0) {
+		conn->timeout = -1;
 	}
 
-	ret = ctdbd_connect(&conn->fd);
+	ret = ctdbd_connect(conn->sockname, &conn->fd);
 	if (ret != 0) {
-		status = map_nt_error_from_unix(ret);
 		DEBUG(1, ("ctdbd_connect failed: %s\n", strerror(ret)));
 		goto fail;
 	}
 	talloc_set_destructor(conn, ctdbd_connection_destructor);
 
-	status = get_cluster_vnn(conn, &conn->our_vnn);
+	ret = get_cluster_vnn(conn, &conn->our_vnn);
 
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10, ("get_cluster_vnn failed: %s\n", nt_errstr(status)));
+	if (ret != 0) {
+		DEBUG(10, ("get_cluster_vnn failed: %s\n", strerror(ret)));
 		goto fail;
 	}
 
 	if (!ctdbd_working(conn, conn->our_vnn)) {
 		DEBUG(2, ("Node is not working, can not connect\n"));
-		status = NT_STATUS_INTERNAL_DB_ERROR;
+		ret = EIO;
 		goto fail;
 	}
 
 	generate_random_buffer((unsigned char *)&conn->rand_srvid,
 			       sizeof(conn->rand_srvid));
 
-	status = register_with_ctdbd(conn, conn->rand_srvid, NULL, NULL);
+	ret = register_with_ctdbd(conn, conn->rand_srvid, NULL, NULL);
 
-	if (!NT_STATUS_IS_OK(status)) {
+	if (ret != 0) {
 		DEBUG(5, ("Could not register random srvid: %s\n",
-			  nt_errstr(status)));
+			  strerror(ret)));
 		goto fail;
 	}
 
 	*pconn = conn;
-	return NT_STATUS_OK;
+	return 0;
 
  fail:
 	TALLOC_FREE(conn);
-	return status;
+	return ret;
 }
 
 /*
  * Get us a ctdbd connection and register us as a process
  */
 
-NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx,
-				    struct ctdbd_connection **pconn)
+int ctdbd_messaging_connection(TALLOC_CTX *mem_ctx,
+			       const char *sockname, int timeout,
+			       struct ctdbd_connection **pconn)
 {
         struct ctdbd_connection *conn;
-	NTSTATUS status;
+	int ret;
 
-	status = ctdbd_init_connection(mem_ctx, &conn);
+	ret = ctdbd_init_connection(mem_ctx, sockname, timeout, &conn);
 
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	if (ret != 0) {
+		return ret;
 	}
 
-	status = register_with_ctdbd(conn, MSG_SRVID_SAMBA, NULL, NULL);
-	if (!NT_STATUS_IS_OK(status)) {
+	ret = register_with_ctdbd(conn, MSG_SRVID_SAMBA, NULL, NULL);
+	if (ret != 0) {
 		goto fail;
 	}
 
 	*pconn = conn;
-	return NT_STATUS_OK;
+	return 0;
 
  fail:
 	TALLOC_FREE(conn);
-	return status;
+	return ret;
 }
 
 struct messaging_context *ctdb_conn_msg_ctx(struct ctdbd_connection *conn)
@@ -529,7 +526,7 @@ int ctdbd_conn_get_fd(struct ctdbd_connection *conn)
 static int ctdb_handle_message(struct ctdbd_connection *conn,
 			       struct ctdb_req_header *hdr)
 {
-	struct ctdb_req_message *msg;
+	struct ctdb_req_message_old *msg;
 
 	if (hdr->operation != CTDB_REQ_MESSAGE) {
 		DEBUG(0, ("Received async msg of type %u, discarding\n",
@@ -537,7 +534,7 @@ static int ctdb_handle_message(struct ctdbd_connection *conn,
 		return EINVAL;
 	}
 
-	msg = (struct ctdb_req_message *)hdr;
+	msg = (struct ctdb_req_message_old *)hdr;
 
 	ctdbd_msg_call_back(conn, msg);
 
@@ -558,7 +555,7 @@ static void ctdbd_socket_handler(struct tevent_context *event_ctx,
 	struct ctdb_req_header *hdr = NULL;
 	int ret;
 
-	ret = ctdb_read_packet(conn->fd, talloc_tos(), &hdr);
+	ret = ctdb_read_packet(conn->fd, conn->timeout, talloc_tos(), &hdr);
 	if (ret != 0) {
 		DEBUG(0, ("ctdb_read_packet failed: %s\n", strerror(ret)));
 		cluster_fatal("ctdbd died\n");
@@ -578,37 +575,35 @@ static void ctdbd_socket_handler(struct tevent_context *event_ctx,
  * Prepare a ctdbd connection to receive messages
  */
 
-NTSTATUS ctdbd_register_msg_ctx(struct ctdbd_connection *conn,
-				struct messaging_context *msg_ctx)
+int ctdbd_register_msg_ctx(struct ctdbd_connection *conn,
+			   struct messaging_context *msg_ctx,
+			   struct tevent_context *ev)
 {
 	SMB_ASSERT(conn->msg_ctx == NULL);
 	SMB_ASSERT(conn->fde == NULL);
 
-	if (!(conn->fde = tevent_add_fd(messaging_tevent_context(msg_ctx),
-				       conn,
-				       conn->fd,
-				       TEVENT_FD_READ,
-				       ctdbd_socket_handler,
-				       conn))) {
+	conn->fde = tevent_add_fd(ev, conn, conn->fd, TEVENT_FD_READ,
+				  ctdbd_socket_handler, conn);
+	if (conn->fde == NULL) {
 		DEBUG(0, ("event_add_fd failed\n"));
-		return NT_STATUS_NO_MEMORY;
+		return ENOMEM;
 	}
 
 	conn->msg_ctx = msg_ctx;
 
-	return NT_STATUS_OK;
+	return 0;
 }
 
-NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
-				  uint32_t dst_vnn, uint64_t dst_srvid,
-				  const struct iovec *iov, int iovlen)
+int ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
+			     uint32_t dst_vnn, uint64_t dst_srvid,
+			     const struct iovec *iov, int iovlen)
 {
-	struct ctdb_req_message r;
+	struct ctdb_req_message_old r;
 	struct iovec iov2[iovlen+1];
 	size_t buflen = iov_buflen(iov, iovlen);
 	ssize_t nwritten;
 
-	r.hdr.length = offsetof(struct ctdb_req_message, data) + buflen;
+	r.hdr.length = offsetof(struct ctdb_req_message_old, data) + buflen;
 	r.hdr.ctdb_magic = CTDB_MAGIC;
 	r.hdr.ctdb_version = CTDB_PROTOCOL;
 	r.hdr.generation = 1;
@@ -623,7 +618,7 @@ NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
 	ctdb_packet_dump(&r.hdr);
 
 	iov2[0].iov_base = &r;
-	iov2[0].iov_len = offsetof(struct ctdb_req_message, data);
+	iov2[0].iov_len = offsetof(struct ctdb_req_message_old, data);
 	memcpy(&iov2[1], iov, iovlen * sizeof(struct iovec));
 
 	nwritten = write_data_iov(conn->fd, iov2, iovlen+1);
@@ -632,42 +627,28 @@ NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
 		cluster_fatal("cluster dispatch daemon msg write error\n");
 	}
 
-	return NT_STATUS_OK;
+	return 0;
 }
 
 /*
  * send/recv a generic ctdb control message
  */
-static NTSTATUS ctdbd_control(struct ctdbd_connection *conn,
-			      uint32_t vnn, uint32_t opcode,
-			      uint64_t srvid, uint32_t flags,
-			      TDB_DATA data,
-			      TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
-			      int *cstatus)
+static int ctdbd_control(struct ctdbd_connection *conn,
+			 uint32_t vnn, uint32_t opcode,
+			 uint64_t srvid, uint32_t flags,
+			 TDB_DATA data,
+			 TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
+			 int *cstatus)
 {
-	struct ctdb_req_control req;
+	struct ctdb_req_control_old req;
 	struct ctdb_req_header *hdr;
-	struct ctdb_reply_control *reply = NULL;
-	struct ctdbd_connection *new_conn = NULL;
+	struct ctdb_reply_control_old *reply = NULL;
 	struct iovec iov[2];
 	ssize_t nwritten;
-	NTSTATUS status;
 	int ret;
 
-	if (conn == NULL) {
-		status = ctdbd_init_connection(NULL, &new_conn);
-
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(10, ("Could not init temp connection: %s\n",
-				   nt_errstr(status)));
-			goto fail;
-		}
-
-		conn = new_conn;
-	}
-
 	ZERO_STRUCT(req);
-	req.hdr.length = offsetof(struct ctdb_req_control, data) + data.dsize;
+	req.hdr.length = offsetof(struct ctdb_req_control_old, data) + data.dsize;
 	req.hdr.ctdb_magic   = CTDB_MAGIC;
 	req.hdr.ctdb_version = CTDB_PROTOCOL;
 	req.hdr.operation    = CTDB_REQ_CONTROL;
@@ -682,7 +663,7 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn,
 	ctdb_packet_dump(&req.hdr);
 
 	iov[0].iov_base = &req;
-	iov[0].iov_len = offsetof(struct ctdb_req_control, data);
+	iov[0].iov_len = offsetof(struct ctdb_req_control_old, data);
 	iov[1].iov_base = data.dptr;
 	iov[1].iov_len = data.dsize;
 
@@ -693,31 +674,30 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn,
 	}
 
 	if (flags & CTDB_CTRL_FLAG_NOREPLY) {
-		TALLOC_FREE(new_conn);
 		if (cstatus) {
 			*cstatus = 0;
 		}
-		return NT_STATUS_OK;
+		return 0;
 	}
 
 	ret = ctdb_read_req(conn, req.hdr.reqid, NULL, &hdr);
 	if (ret != 0) {
 		DEBUG(10, ("ctdb_read_req failed: %s\n", strerror(ret)));
-		status = map_nt_error_from_unix(ret);
-		goto fail;
+		return ret;
 	}
 
 	if (hdr->operation != CTDB_REPLY_CONTROL) {
 		DEBUG(0, ("received invalid reply\n"));
-		goto fail;
+		TALLOC_FREE(hdr);
+		return EIO;
 	}
-	reply = (struct ctdb_reply_control *)hdr;
+	reply = (struct ctdb_reply_control_old *)hdr;
 
 	if (outdata) {
 		if (!(outdata->dptr = (uint8_t *)talloc_memdup(
 			      mem_ctx, reply->data, reply->datalen))) {
 			TALLOC_FREE(reply);
-			return NT_STATUS_NO_MEMORY;
+			return ENOMEM;
 		}
 		outdata->dsize = reply->datalen;
 	}
@@ -725,12 +705,8 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn,
 		(*cstatus) = reply->status;
 	}
 
-	status = NT_STATUS_OK;
-
- fail:
-	TALLOC_FREE(new_conn);
 	TALLOC_FREE(reply);
-	return status;
+	return ret;
 }
 
 /*
@@ -766,7 +742,7 @@ bool ctdb_processes_exist(struct ctdbd_connection *conn,
 	}
 
 	for (i=0; i<num_pids; i++) {
-		struct ctdb_req_control req;
+		struct ctdb_req_control_old req;
 		pid_t pid;
 		struct iovec iov[2];
 		ssize_t nwritten;
@@ -786,7 +762,7 @@ bool ctdb_processes_exist(struct ctdbd_connection *conn,
 			   (int)pids[i].vnn, (int)pid,
 			   (int)reqids[i]));
 
-		req.hdr.length = offsetof(struct ctdb_req_control, data);
+		req.hdr.length = offsetof(struct ctdb_req_control_old, data);
 		req.hdr.length += sizeof(pid);
 		req.hdr.ctdb_magic   = CTDB_MAGIC;
 		req.hdr.ctdb_version = CTDB_PROTOCOL;
@@ -802,7 +778,7 @@ bool ctdb_processes_exist(struct ctdbd_connection *conn,
 		ctdb_packet_dump(&req.hdr);
 
 		iov[0].iov_base = &req;
-		iov[0].iov_len = offsetof(struct ctdb_req_control, data);
+		iov[0].iov_len = offsetof(struct ctdb_req_control_old, data);
 		iov[1].iov_base = &pid;
 		iov[1].iov_len = sizeof(pid);
 
@@ -818,7 +794,7 @@ bool ctdb_processes_exist(struct ctdbd_connection *conn,
 
 	while (num_received < num_pids) {
 		struct ctdb_req_header *hdr;
-		struct ctdb_reply_control *reply;
+		struct ctdb_reply_control_old *reply;
 		uint32_t reqid;
 		int ret;
 
@@ -833,7 +809,7 @@ bool ctdb_processes_exist(struct ctdbd_connection *conn,
 			DEBUG(10, ("Received invalid reply\n"));
 			goto fail;
 		}
-		reply = (struct ctdb_reply_control *)hdr;
+		reply = (struct ctdb_reply_control_old *)hdr;
 
 		reqid = reply->hdr.reqid;
 
@@ -860,256 +836,13 @@ fail:
 	return result;
 }
 
-struct ctdb_vnn_list {
-	uint32_t vnn;
-	uint32_t reqid;
-	unsigned num_srvids;
-	unsigned num_filled;
-	uint64_t *srvids;
-	unsigned *pid_indexes;
-};
-
-/*
- * Get a list of all vnns mentioned in a list of
- * server_ids. vnn_indexes tells where in the vnns array we have to
- * place the pids.
- */
-static bool ctdb_collect_vnns(TALLOC_CTX *mem_ctx,
-			      const struct server_id *pids, unsigned num_pids,
-			      struct ctdb_vnn_list **pvnns,
-			      unsigned *pnum_vnns)
-{
-	struct ctdb_vnn_list *vnns = NULL;
-	unsigned *vnn_indexes = NULL;
-	unsigned i, num_vnns = 0;
-
-	vnn_indexes = talloc_array(mem_ctx, unsigned, num_pids);
-	if (vnn_indexes == NULL) {
-		DEBUG(1, ("talloc_array failed\n"));
-		goto fail;
-	}
-
-	for (i=0; i<num_pids; i++) {
-		unsigned j;
-		uint32_t vnn = pids[i].vnn;
-
-		for (j=0; j<num_vnns; j++) {
-			if (vnn == vnns[j].vnn) {
-				break;
-			}
-		}
-		vnn_indexes[i] = j;
-
-		if (j < num_vnns) {
-			/*
-			 * Already in the array
-			 */
-			vnns[j].num_srvids += 1;
-			continue;
-		}
-		vnns = talloc_realloc(mem_ctx, vnns, struct ctdb_vnn_list,
-				      num_vnns+1);
-		if (vnns == NULL) {
-			DEBUG(1, ("talloc_realloc failed\n"));
-			goto fail;
-		}
-		vnns[num_vnns].vnn = vnn;
-		vnns[num_vnns].num_srvids = 1;
-		vnns[num_vnns].num_filled = 0;
-		num_vnns += 1;
-	}
-	for (i=0; i<num_vnns; i++) {
-		struct ctdb_vnn_list *vnn = &vnns[i];
-
-		vnn->srvids = talloc_array(vnns, uint64_t, vnn->num_srvids);
-		if (vnn->srvids == NULL) {
-			DEBUG(1, ("talloc_array failed\n"));
-			goto fail;
-		}
-		vnn->pid_indexes = talloc_array(vnns, unsigned,
-						vnn->num_srvids);
-		if (vnn->pid_indexes == NULL) {
-			DEBUG(1, ("talloc_array failed\n"));
-			goto fail;
-		}
-	}
-	for (i=0; i<num_pids; i++) {
-		struct ctdb_vnn_list *vnn = &vnns[vnn_indexes[i]];
-		vnn->srvids[vnn->num_filled] = pids[i].unique_id;
-		vnn->pid_indexes[vnn->num_filled] = i;
-		vnn->num_filled += 1;
-	}
-
-	TALLOC_FREE(vnn_indexes);
-	*pvnns = vnns;
-	*pnum_vnns = num_vnns;
-	return true;
-fail:
-	TALLOC_FREE(vnns);
-	TALLOC_FREE(vnn_indexes);
-	return false;
-}
-
-bool ctdb_serverids_exist_supported(struct ctdbd_connection *conn)
-{
-	return true;
-}
-
-bool ctdb_serverids_exist(struct ctdbd_connection *conn,
-			  const struct server_id *pids, unsigned num_pids,
-			  bool *results)
-{
-	unsigned i, num_received;
-	struct ctdb_vnn_list *vnns = NULL;
-	unsigned num_vnns;
-
-	if (!ctdb_collect_vnns(talloc_tos(), pids, num_pids,
-			       &vnns, &num_vnns)) {
-		DEBUG(1, ("ctdb_collect_vnns failed\n"));
-		goto fail;
-	}
-
-	for (i=0; i<num_vnns; i++) {
-		struct ctdb_vnn_list *vnn = &vnns[i];
-		struct ctdb_req_control req;
-		struct iovec iov[2];
-		ssize_t nwritten;
-
-		vnn->reqid = ctdbd_next_reqid(conn);
-
-		ZERO_STRUCT(req);
-
-		DEBUG(10, ("Requesting VNN %d, reqid=%d, num_srvids=%u\n",
-			   (int)vnn->vnn, (int)vnn->reqid, vnn->num_srvids));
-
-		req.hdr.length = offsetof(struct ctdb_req_control, data);
-		req.hdr.ctdb_magic   = CTDB_MAGIC;
-		req.hdr.ctdb_version = CTDB_PROTOCOL;
-		req.hdr.operation    = CTDB_REQ_CONTROL;
-		req.hdr.reqid        = vnn->reqid;
-		req.hdr.destnode     = vnn->vnn;
-		req.opcode           = CTDB_CONTROL_CHECK_SRVIDS;
-		req.srvid            = 0;
-		req.datalen          = sizeof(uint64_t) * vnn->num_srvids;
-		req.hdr.length	    += req.datalen;
-		req.flags            = 0;
-
-		DEBUG(10, ("ctdbd_control: Sending ctdb packet\n"));
-		ctdb_packet_dump(&req.hdr);
-
-		iov[0].iov_base = &req;
-		iov[0].iov_len = offsetof(struct ctdb_req_control, data);
-		iov[1].iov_base = vnn->srvids;
-		iov[1].iov_len = req.datalen;
-
-		nwritten = write_data_iov(conn->fd, iov, ARRAY_SIZE(iov));
-		if (nwritten == -1) {
-			DEBUG(10, ("write_data_iov failed: %s\n",
-				   strerror(errno)));
-			goto fail;
-		}
-	}
-
-	num_received = 0;
-
-	while (num_received < num_vnns) {
-		struct ctdb_req_header *hdr;
-		struct ctdb_reply_control *reply;
-		struct ctdb_vnn_list *vnn;
-		uint32_t reqid;
-		uint8_t *reply_data;
-		int ret;
-
-		ret = ctdb_read_req(conn, 0, talloc_tos(), &hdr);
-		if (ret != 0) {
-			DEBUG(10, ("ctdb_read_req failed: %s\n",
-				   strerror(ret)));
-			goto fail;
-		}
-
-		if (hdr->operation != CTDB_REPLY_CONTROL) {
-			DEBUG(1, ("Received invalid reply %u\n",
-				  (unsigned)hdr->operation));
-			goto fail;
-		}
-		reply = (struct ctdb_reply_control *)hdr;
-
-		reqid = reply->hdr.reqid;
-
-		DEBUG(10, ("Received reqid %d\n", (int)reqid));
-
-		for (i=0; i<num_vnns; i++) {
-			if (reqid == vnns[i].reqid) {
-				break;
-			}
-		}
-		if (i == num_vnns) {
-			DEBUG(1, ("Received unknown reqid number %u\n",
-				  (unsigned)reqid));
-			goto fail;
-		}
-
-		DEBUG(10, ("Found index %u\n", i));
-
-		vnn = &vnns[i];
-
-		DEBUG(10, ("Received vnn %u, vnn->num_srvids %u, datalen %u\n",
-			   (unsigned)vnn->vnn, vnn->num_srvids,
-			   (unsigned)reply->datalen));
-
-		if (reply->datalen >= ((vnn->num_srvids+7)/8)) {
-			/*
-			 * Got a real reply
-			 */
-			reply_data = reply->data;
-		} else {
-			/*
-			 * Got an error reply
-			 */
-			DEBUG(5, ("Received short reply len %d, status %u, "
-				  "errorlen %u\n",
-				  (unsigned)reply->datalen,
-				  (unsigned)reply->status,
-				  (unsigned)reply->errorlen));
-			dump_data(5, reply->data, reply->errorlen);
-
-			/*
-			 * This will trigger everything set to false
-			 */
-			reply_data = NULL;
-		}
-
-		for (i=0; i<vnn->num_srvids; i++) {
-			int idx = vnn->pid_indexes[i];
-
-			if (pids[i].unique_id ==
-			    SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
-				results[idx] = true;
-				continue;
-			}
-			results[idx] =
-				(reply_data != NULL) &&
-				((reply_data[i/8] & (1<<(i%8))) != 0);
-		}
-
-		TALLOC_FREE(reply);
-		num_received += 1;
-	}
-
-	TALLOC_FREE(vnns);
-	return true;
-fail:
-	cluster_fatal("serverids_exist failed");
-	return false;
-}
-
 /*
  * Get a db path
  */
 char *ctdbd_dbpath(struct ctdbd_connection *conn,
 		   TALLOC_CTX *mem_ctx, uint32_t db_id)
 {
-	NTSTATUS status;
+	int ret;
 	TDB_DATA data;
 	TDB_DATA rdata = {0};
 	int32_t cstatus = 0;
@@ -1117,11 +850,12 @@ char *ctdbd_dbpath(struct ctdbd_connection *conn,
 	data.dptr = (uint8_t*)&db_id;
 	data.dsize = sizeof(db_id);
 
-	status = ctdbd_control(conn, CTDB_CURRENT_NODE,
-			       CTDB_CONTROL_GETDBPATH, 0, 0, data,
-			       mem_ctx, &rdata, &cstatus);
-	if (!NT_STATUS_IS_OK(status) || cstatus != 0) {
-		DEBUG(0,(__location__ " ctdb_control for getdbpath failed\n"));
+	ret = ctdbd_control(conn, CTDB_CURRENT_NODE,
+			    CTDB_CONTROL_GETDBPATH, 0, 0, data,
+			    mem_ctx, &rdata, &cstatus);
+	if ((ret != 0) || cstatus != 0) {
+		DEBUG(0, (__location__ " ctdb_control for getdbpath failed: %s\n",
+			  strerror(ret)));
 		return NULL;
 	}
 
@@ -1131,71 +865,68 @@ char *ctdbd_dbpath(struct ctdbd_connection *conn,
 /*
  * attach to a ctdb database
  */
-NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn,
-			 const char *name, uint32_t *db_id, int tdb_flags)
+int ctdbd_db_attach(struct ctdbd_connection *conn,
+		    const char *name, uint32_t *db_id, int tdb_flags)
 {
-	NTSTATUS status;
+	int ret;
 	TDB_DATA data;
 	int32_t cstatus;
 	bool persistent = (tdb_flags & TDB_CLEAR_IF_FIRST) == 0;
 
 	data = string_term_tdb_data(name);
 
-	status = ctdbd_control(conn, CTDB_CURRENT_NODE,
-			       persistent
-			       ? CTDB_CONTROL_DB_ATTACH_PERSISTENT
-			       : CTDB_CONTROL_DB_ATTACH,
-			       tdb_flags, 0, data, NULL, &data, &cstatus);
-	if (!NT_STATUS_IS_OK(status)) {
+	ret = ctdbd_control(conn, CTDB_CURRENT_NODE,
+			    persistent
+			    ? CTDB_CONTROL_DB_ATTACH_PERSISTENT
+			    : CTDB_CONTROL_DB_ATTACH,
+			    tdb_flags, 0, data, NULL, &data, &cstatus);
+	if (ret != 0) {
 		DEBUG(0, (__location__ " ctdb_control for db_attach "
-			  "failed: %s\n", nt_errstr(status)));
-		return status;
+			  "failed: %s\n", strerror(ret)));
+		return ret;
 	}
 
 	if (cstatus != 0 || data.dsize != sizeof(uint32_t)) {
 		DEBUG(0,(__location__ " ctdb_control for db_attach failed\n"));
-		return NT_STATUS_INTERNAL_ERROR;
+		return EIO;
 	}
 
 	*db_id = *(uint32_t *)data.dptr;
 	talloc_free(data.dptr);
 
 	if (!(tdb_flags & TDB_SEQNUM)) {
-		return NT_STATUS_OK;
+		return 0;
 	}
 
 	data.dptr = (uint8_t *)db_id;
 	data.dsize = sizeof(*db_id);
 
-	status = ctdbd_control(conn, CTDB_CURRENT_NODE,
-			       CTDB_CONTROL_ENABLE_SEQNUM, 0, 0, data,
-			       NULL, NULL, &cstatus);
-	if (!NT_STATUS_IS_OK(status) || cstatus != 0) {
-		DEBUG(0,(__location__ " ctdb_control for enable seqnum "
-			 "failed\n"));
-		return NT_STATUS_IS_OK(status) ? NT_STATUS_INTERNAL_ERROR :
-			status;
+	ret = ctdbd_control(conn, CTDB_CURRENT_NODE,
+			    CTDB_CONTROL_ENABLE_SEQNUM, 0, 0, data,
+			    NULL, NULL, &cstatus);
+	if ((ret != 0) || cstatus != 0) {
+		DEBUG(0, (__location__ " ctdb_control for enable seqnum "
+			  "failed: %s\n", strerror(ret)));
+		return (ret == 0) ? EIO : ret;
 	}
 
-	return NT_STATUS_OK;
+	return 0;
 }
 
 /*
  * force the migration of a record to this node
  */
-NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id,
-		       TDB_DATA key)
+int ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key)
 {
-	struct ctdb_req_call req;
+	struct ctdb_req_call_old req;
 	struct ctdb_req_header *hdr;
 	struct iovec iov[2];
 	ssize_t nwritten;
-	NTSTATUS status;
 	int ret;
 
 	ZERO_STRUCT(req);
 
-	req.hdr.length = offsetof(struct ctdb_req_call, data) + key.dsize;
+	req.hdr.length = offsetof(struct ctdb_req_call_old, data) + key.dsize;
 	req.hdr.ctdb_magic   = CTDB_MAGIC;
 	req.hdr.ctdb_version = CTDB_PROTOCOL;
 	req.hdr.operation    = CTDB_REQ_CALL;
@@ -1209,7 +940,7 @@ NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id,
 	ctdb_packet_dump(&req.hdr);
 
 	iov[0].iov_base = &req;
-	iov[0].iov_len = offsetof(struct ctdb_req_call, data);
+	iov[0].iov_len = offsetof(struct ctdb_req_call_old, data);
 	iov[1].iov_base = key.dptr;
 	iov[1].iov_len = key.dsize;
 
@@ -1222,38 +953,34 @@ NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id,
 	ret = ctdb_read_req(conn, req.hdr.reqid, NULL, &hdr);
 	if (ret != 0) {
 		DEBUG(10, ("ctdb_read_req failed: %s\n", strerror(ret)));
-		status = map_nt_error_from_unix(ret);
 		goto fail;
 	}
 
 	if (hdr->operation != CTDB_REPLY_CALL) {
 		DEBUG(0, ("received invalid reply\n"));
-		status = NT_STATUS_INTERNAL_ERROR;
 		goto fail;
 	}
 
-	status = NT_STATUS_OK;
  fail:
 
 	TALLOC_FREE(hdr);
-	return status;
+	return ret;
 }
 
 /*
  * Fetch a record and parse it
  */
-NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id,
-		     TDB_DATA key, bool local_copy,
-		     void (*parser)(TDB_DATA key, TDB_DATA data,
-				    void *private_data),
-		     void *private_data)
+int ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id,
+		TDB_DATA key, bool local_copy,
+		void (*parser)(TDB_DATA key, TDB_DATA data,
+			       void *private_data),
+		void *private_data)
 {
-	struct ctdb_req_call req;
+	struct ctdb_req_call_old req;
 	struct ctdb_req_header *hdr = NULL;
-	struct ctdb_reply_call *reply;
+	struct ctdb_reply_call_old *reply;
 	struct iovec iov[2];
 	ssize_t nwritten;
-	NTSTATUS status;
 	uint32_t flags;
 	int ret;
 
@@ -1261,7 +988,7 @@ NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id,
 
 	ZERO_STRUCT(req);
 
-	req.hdr.length = offsetof(struct ctdb_req_call, data) + key.dsize;
+	req.hdr.length = offsetof(struct ctdb_req_call_old, data) + key.dsize;
 	req.hdr.ctdb_magic   = CTDB_MAGIC;
 	req.hdr.ctdb_version = CTDB_PROTOCOL;
 	req.hdr.operation    = CTDB_REQ_CALL;
@@ -1272,7 +999,7 @@ NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id,
 	req.keylen           = key.dsize;
 
 	iov[0].iov_base = &req;
-	iov[0].iov_len = offsetof(struct ctdb_req_call, data);
+	iov[0].iov_len = offsetof(struct ctdb_req_call_old, data);
 	iov[1].iov_base = key.dptr;
 	iov[1].iov_len = key.dsize;
 
@@ -1285,32 +1012,31 @@ NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id,
 	ret = ctdb_read_req(conn, req.hdr.reqid, NULL, &hdr);
 	if (ret != 0) {
 		DEBUG(10, ("ctdb_read_req failed: %s\n", strerror(ret)));
-		status = map_nt_error_from_unix(ret);
 		goto fail;
 	}
 
 	if ((hdr == NULL) || (hdr->operation != CTDB_REPLY_CALL)) {
 		DEBUG(0, ("received invalid reply\n"));
-		status = NT_STATUS_INTERNAL_ERROR;
+		ret = EIO;
 		goto fail;
 	}
-	reply = (struct ctdb_reply_call *)hdr;
+	reply = (struct ctdb_reply_call_old *)hdr;
 
 	if (reply->datalen == 0) {
 		/*
 		 * Treat an empty record as non-existing
 		 */
-		status = NT_STATUS_NOT_FOUND;
+		ret = ENOENT;
 		goto fail;
 	}
 
 	parser(key, make_tdb_data(&reply->data[0], reply->datalen),
 	       private_data);
 
-	status = NT_STATUS_OK;
+	ret = 0;
  fail:
 	TALLOC_FREE(hdr);
-	return status;
+	return ret;
 }
 
 /*
@@ -1319,25 +1045,25 @@ NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id,
   everything in-line.
 */
 
-NTSTATUS ctdbd_traverse(uint32_t db_id,
+int ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id,
 			void (*fn)(TDB_DATA key, TDB_DATA data,
 				   void *private_data),
 			void *private_data)
 {
 	struct ctdbd_connection *conn;
-	NTSTATUS status;
-
+	int ret;
 	TDB_DATA key, data;
 	struct ctdb_traverse_start t;
 	int cstatus;
 
 	become_root();
-	status = ctdbd_init_connection(NULL, &conn);
+	ret = ctdbd_init_connection(NULL, master->sockname, master->timeout,
+				    &conn);
 	unbecome_root();
-	if (!NT_STATUS_IS_OK(status)) {
+	if (ret != 0) {
 		DEBUG(0, ("ctdbd_init_connection failed: %s\n",
-			  nt_errstr(status)));
-		return status;
+			  strerror(ret)));
+		return ret;
 	}
 
 	t.db_id = db_id;
@@ -1347,32 +1073,30 @@ NTSTATUS ctdbd_traverse(uint32_t db_id,
 	data.dptr = (uint8_t *)&t;
 	data.dsize = sizeof(t);
 
-	status = ctdbd_control(conn, CTDB_CURRENT_NODE,
-			       CTDB_CONTROL_TRAVERSE_START, conn->rand_srvid, 0,
-			       data, NULL, NULL, &cstatus);
-
-	if (!NT_STATUS_IS_OK(status) || (cstatus != 0)) {
+	ret = ctdbd_control(conn, CTDB_CURRENT_NODE,
+			    CTDB_CONTROL_TRAVERSE_START, conn->rand_srvid,
+			    0, data, NULL, NULL, &cstatus);
 
-		DEBUG(0,("ctdbd_control failed: %s, %d\n", nt_errstr(status),
+	if ((ret != 0) || (cstatus != 0)) {
+		DEBUG(0,("ctdbd_control failed: %s, %d\n", strerror(ret),
 			 cstatus));
 
-		if (NT_STATUS_IS_OK(status)) {
+		if (ret == 0) {
 			/*
 			 * We need a mapping here
 			 */
-			status = NT_STATUS_UNSUCCESSFUL;
+			ret = EIO;
 		}
 		TALLOC_FREE(conn);
-		return status;
+		return ret;
 	}
 
 	while (True) {
 		struct ctdb_req_header *hdr = NULL;
-		struct ctdb_req_message *m;
-		struct ctdb_rec_data *d;
-		int ret;
+		struct ctdb_req_message_old *m;
+		struct ctdb_rec_data_old *d;
 
-		ret = ctdb_read_packet(conn->fd, conn, &hdr);
+		ret = ctdb_read_packet(conn->fd, conn->timeout, conn, &hdr);
 		if (ret != 0) {
 			DEBUG(0, ("ctdb_read_packet failed: %s\n",
 				  strerror(ret)));
@@ -1383,16 +1107,16 @@ NTSTATUS ctdbd_traverse(uint32_t db_id,
 			DEBUG(0, ("Got operation %u, expected a message\n",
 				  (unsigned)hdr->operation));
 			TALLOC_FREE(conn);
-			return NT_STATUS_UNEXPECTED_IO_ERROR;
+			return EIO;
 		}
 
-		m = (struct ctdb_req_message *)hdr;
-		d = (struct ctdb_rec_data *)&m->data[0];
+		m = (struct ctdb_req_message_old *)hdr;
+		d = (struct ctdb_rec_data_old *)&m->data[0];
 		if (m->datalen < sizeof(uint32_t) || m->datalen != d->length) {
 			DEBUG(0, ("Got invalid traverse data of length %d\n",
 				  (int)m->datalen));
 			TALLOC_FREE(conn);
-			return NT_STATUS_UNEXPECTED_IO_ERROR;
+			return EIO;
 		}
 
 		key.dsize = d->keylen;
@@ -1403,14 +1127,14 @@ NTSTATUS ctdbd_traverse(uint32_t db_id,
 		if (key.dsize == 0 && data.dsize == 0) {
 			/* end of traverse */
 			TALLOC_FREE(conn);
-			return NT_STATUS_OK;
+			return 0;
 		}
 
 		if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
 			DEBUG(0, ("Got invalid ltdb header length %d\n",
 				  (int)data.dsize));
 			TALLOC_FREE(conn);
-			return NT_STATUS_UNEXPECTED_IO_ERROR;
+			return EIO;
 		}
 		data.dsize -= sizeof(struct ctdb_ltdb_header);
 		data.dptr += sizeof(struct ctdb_ltdb_header);
@@ -1419,7 +1143,7 @@ NTSTATUS ctdbd_traverse(uint32_t db_id,
 			fn(key, data, private_data);
 		}
 	}
-	return NT_STATUS_OK;
+	return 0;
 }
 
 /*
@@ -1453,18 +1177,18 @@ static void smbd_ctdb_canonicalize_ip(const struct sockaddr_storage *in,
  * Register us as a server for a particular tcp connection
  */
 
-NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
-			    const struct sockaddr_storage *_server,
-			    const struct sockaddr_storage *_client,
-			    int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
-				      uint64_t dst_srvid,
-				      const uint8_t *msg, size_t msglen,
-				      void *private_data),
-			    void *private_data)
+int ctdbd_register_ips(struct ctdbd_connection *conn,
+		       const struct sockaddr_storage *_server,
+		       const struct sockaddr_storage *_client,
+		       int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+				 uint64_t dst_srvid,
+				 const uint8_t *msg, size_t msglen,
+				 void *private_data),
+		       void *private_data)
 {
-	struct ctdb_control_tcp_addr p;
+	struct ctdb_connection p;
 	TDB_DATA data = { .dptr = (uint8_t *)&p, .dsize = sizeof(p) };
-	NTSTATUS status;
+	int ret;
 	struct sockaddr_storage client;
 	struct sockaddr_storage server;
 
@@ -1477,25 +1201,25 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
 
 	switch (client.ss_family) {
 	case AF_INET:
-		memcpy(&p.dest.ip, &server, sizeof(p.dest.ip));
+		memcpy(&p.dst.ip, &server, sizeof(p.dst.ip));
 		memcpy(&p.src.ip, &client, sizeof(p.src.ip));
 		break;
 	case AF_INET6:
-		memcpy(&p.dest.ip6, &server, sizeof(p.dest.ip6));
+		memcpy(&p.dst.ip6, &server, sizeof(p.dst.ip6));
 		memcpy(&p.src.ip6, &client, sizeof(p.src.ip6));
 		break;
 	default:
-		return NT_STATUS_INTERNAL_ERROR;
+		return EIO;
 	}
 
 	/*
 	 * We want to be told about IP releases
 	 */
 
-	status = register_with_ctdbd(conn, CTDB_SRVID_RELEASE_IP,
-				     cb, private_data);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	ret = register_with_ctdbd(conn, CTDB_SRVID_RELEASE_IP,
+				  cb, private_data);
+	if (ret != 0) {
+		return ret;
 	}
 
 	/*
@@ -1503,81 +1227,86 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
 	 * can send an extra ack to trigger a reset for our client, so it
 	 * immediately reconnects
 	 */
-	return ctdbd_control(conn, CTDB_CURRENT_NODE,
-			     CTDB_CONTROL_TCP_CLIENT, 0,
-			     CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL, NULL);
+	ret = ctdbd_control(conn, CTDB_CURRENT_NODE,
+			    CTDB_CONTROL_TCP_CLIENT, 0,
+			    CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL,
+			    NULL);
+	if (ret != 0) {
+		return ret;
+	}
+	return 0;
 }
 
 /*
   call a control on the local node
  */
-NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode,
-			     uint64_t srvid, uint32_t flags, TDB_DATA data,
-			     TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
-			     int *cstatus)
+int ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode,
+			uint64_t srvid, uint32_t flags, TDB_DATA data,
+			TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
+			int *cstatus)
 {
-	return ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, mem_ctx, outdata, cstatus);
+	return ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data,
+			     mem_ctx, outdata, cstatus);
 }
 
-NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn)
+int ctdb_watch_us(struct ctdbd_connection *conn)
 {
-	struct ctdb_client_notify_register reg_data;
+	struct ctdb_notify_data_old reg_data;
 	size_t struct_len;
-	NTSTATUS status;
+	int ret;
 	int cstatus;
 
 	reg_data.srvid = CTDB_SRVID_SAMBA_NOTIFY;
 	reg_data.len = 1;
 	reg_data.notify_data[0] = 0;
 
-	struct_len = offsetof(struct ctdb_client_notify_register,
+	struct_len = offsetof(struct ctdb_notify_data_old,
 			      notify_data) + reg_data.len;
 
-	status = ctdbd_control_local(
+	ret = ctdbd_control_local(
 		conn, CTDB_CONTROL_REGISTER_NOTIFY, conn->rand_srvid, 0,
 		make_tdb_data((uint8_t *)&reg_data, struct_len),
 		NULL, NULL, &cstatus);
-	if (!NT_STATUS_IS_OK(status)) {
+	if (ret != 0) {
 		DEBUG(1, ("ctdbd_control_local failed: %s\n",
-			  nt_errstr(status)));
+			  strerror(ret)));
 	}
-	return status;
+	return ret;
 }
 
-NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn)
+int ctdb_unwatch(struct ctdbd_connection *conn)
 {
-	struct ctdb_client_notify_deregister dereg_data;
-	NTSTATUS status;
+	uint64_t srvid = CTDB_SRVID_SAMBA_NOTIFY;
+	int ret;
 	int cstatus;
 
-	dereg_data.srvid = CTDB_SRVID_SAMBA_NOTIFY;
-
-	status = ctdbd_control_local(
+	ret = ctdbd_control_local(
 		conn, CTDB_CONTROL_DEREGISTER_NOTIFY, conn->rand_srvid, 0,
-		make_tdb_data((uint8_t *)&dereg_data, sizeof(dereg_data)),
+		make_tdb_data((uint8_t *)&srvid, sizeof(srvid)),
 		NULL, NULL, &cstatus);
-	if (!NT_STATUS_IS_OK(status)) {
+	if (ret != 0) {
 		DEBUG(1, ("ctdbd_control_local failed: %s\n",
-			  nt_errstr(status)));
+			  strerror(ret)));
 	}
-	return status;
+	return ret;
 }
 
-NTSTATUS ctdbd_probe(void)
+int ctdbd_probe(const char *sockname, int timeout)
 {
 	/*
 	 * Do a very early check if ctdbd is around to avoid an abort and core
 	 * later
 	 */
 	struct ctdbd_connection *conn = NULL;
-	NTSTATUS status;
+	int ret;
 
-	status = ctdbd_messaging_connection(talloc_tos(), &conn);
+	ret = ctdbd_messaging_connection(talloc_tos(), sockname, timeout,
+					 &conn);
 
 	/*
 	 * We only care if we can connect.
 	 */
 	TALLOC_FREE(conn);
 
-	return status;
+	return ret;
 }
diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c
index f37bfd8..93df7ef 100644
--- a/source3/lib/dbwrap/dbwrap_ctdb.c
+++ b/source3/lib/dbwrap/dbwrap_ctdb.c
@@ -27,7 +27,6 @@
 #include "dbwrap/dbwrap_rbt.h"
 #include "lib/param/param.h"
 
-#include "ctdb.h"
 #include "ctdb_private.h"
 #include "ctdbd_conn.h"
 #include "dbwrap/dbwrap.h"
@@ -35,6 +34,7 @@
 #include "dbwrap/dbwrap_ctdb.h"
 #include "g_lock.h"
 #include "messages.h"
+#include "lib/cluster_support.h"
 
 struct db_ctdb_transaction_handle {
 	struct db_ctdb_ctx *ctx;
@@ -152,17 +152,17 @@ static NTSTATUS db_ctdb_ltdb_store(struct db_ctdb_ctx *db,
 /*
   form a ctdb_rec_data record from a key/data pair
  */
-static struct ctdb_rec_data *db_ctdb_marshall_record(TALLOC_CTX *mem_ctx, uint32_t reqid,
+static struct ctdb_rec_data_old *db_ctdb_marshall_record(TALLOC_CTX *mem_ctx, uint32_t reqid,
 						  TDB_DATA key,
 						  struct ctdb_ltdb_header *header,
 						  TDB_DATA data)
 {
 	size_t length;
-	struct ctdb_rec_data *d;
+	struct ctdb_rec_data_old *d;
 
-	length = offsetof(struct ctdb_rec_data, data) + key.dsize +
+	length = offsetof(struct ctdb_rec_data_old, data) + key.dsize +
 		data.dsize + sizeof(*header);
-	d = (struct ctdb_rec_data *)talloc_size(mem_ctx, length);
+	d = (struct ctdb_rec_data_old *)talloc_size(mem_ctx, length);
 	if (d == NULL) {
 		return NULL;
 	}
@@ -187,7 +187,7 @@ static struct ctdb_marshall_buffer *db_ctdb_marshall_add(TALLOC_CTX *mem_ctx,
 					       struct ctdb_ltdb_header *header,
 					       TDB_DATA data)
 {
-	struct ctdb_rec_data *r;
+	struct ctdb_rec_data_old *r;
 	size_t m_size, r_size;
 	struct ctdb_marshall_buffer *m2 = NULL;
 
@@ -240,13 +240,13 @@ static TDB_DATA db_ctdb_marshall_finish(struct ctdb_marshall_buffer *m)
      - pass r==NULL to start
      - loop the number of times indicated by m->count
 */
-static struct ctdb_rec_data *db_ctdb_marshall_loop_next_key(
-	struct ctdb_marshall_buffer *m, struct ctdb_rec_data *r, TDB_DATA *key)
+static struct ctdb_rec_data_old *db_ctdb_marshall_loop_next_key(
+	struct ctdb_marshall_buffer *m, struct ctdb_rec_data_old *r, TDB_DATA *key)
 {
 	if (r == NULL) {
-		r = (struct ctdb_rec_data *)&m->data[0];
+		r = (struct ctdb_rec_data_old *)&m->data[0];
 	} else {
-		r = (struct ctdb_rec_data *)(r->length + (uint8_t *)r);
+		r = (struct ctdb_rec_data_old *)(r->length + (uint8_t *)r);
 	}
 
 	key->dptr   = &r->data[0];
@@ -255,7 +255,7 @@ static struct ctdb_rec_data *db_ctdb_marshall_loop_next_key(
 }
 
 static bool db_ctdb_marshall_buf_parse(
-	struct ctdb_rec_data *r, uint32_t *reqid,
+	struct ctdb_rec_data_old *r, uint32_t *reqid,
 	struct ctdb_ltdb_header **header, TDB_DATA *data)
 {
 	if (r->datalen < sizeof(struct ctdb_ltdb_header)) {
@@ -354,7 +354,7 @@ static bool parse_newest_in_marshall_buffer(
 		       TDB_DATA data, void *private_data),
 	void *private_data)
 {
-	struct ctdb_rec_data *rec = NULL;
+	struct ctdb_rec_data_old *rec = NULL;
 	struct ctdb_ltdb_header *h = NULL;
 	TDB_DATA data;
 	int i;
@@ -760,12 +760,12 @@ static int db_ctdb_transaction_commit(struct db_context *db)
 
 again:
 	/* tell ctdbd to commit to the other nodes */
-	rets = ctdbd_control_local(messaging_ctdbd_connection(),
-				   CTDB_CONTROL_TRANS3_COMMIT,
-				   h->ctx->db_id, 0,
-				   db_ctdb_marshall_finish(h->m_write),
-				   NULL, NULL, &status);
-	if (!NT_STATUS_IS_OK(rets) || status != 0) {
+	ret = ctdbd_control_local(messaging_ctdbd_connection(),
+				  CTDB_CONTROL_TRANS3_COMMIT,
+				  h->ctx->db_id, 0,
+				  db_ctdb_marshall_finish(h->m_write),
+				  NULL, NULL, &status);
+	if ((ret != 0) || status != 0) {
 		/*
 		 * The TRANS3_COMMIT control should only possibly fail when a
 		 * recovery has been running concurrently. In any case, the db
@@ -851,7 +851,8 @@ static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag)
 
 static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec)
 {
-	NTSTATUS status;
+	NTSTATUS status = NT_STATUS_OK;
+	int ret;
 	struct ctdb_control_schedule_for_deletion *dd;
 	TDB_DATA indata;
 	int cstatus;
@@ -871,21 +872,23 @@ static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec)
 	dd->keylen = rec->key.dsize;
 	memcpy(dd->key, rec->key.dptr, rec->key.dsize);
 
-	status = ctdbd_control_local(messaging_ctdbd_connection(),
-				     CTDB_CONTROL_SCHEDULE_FOR_DELETION,
-				     crec->ctdb_ctx->db_id,
-				     CTDB_CTRL_FLAG_NOREPLY, /* flags */
-				     indata,
-				     NULL, /* outdata */
-				     NULL, /* errmsg */
-				     &cstatus);
+	ret = ctdbd_control_local(messaging_ctdbd_connection(),
+				  CTDB_CONTROL_SCHEDULE_FOR_DELETION,
+				  crec->ctdb_ctx->db_id,
+				  CTDB_CTRL_FLAG_NOREPLY, /* flags */
+				  indata,
+				  NULL, /* outdata */
+				  NULL, /* errmsg */
+				  &cstatus);
 	talloc_free(indata.dptr);
 
-	if (!NT_STATUS_IS_OK(status) || cstatus != 0) {
+	if ((ret != 0) || cstatus != 0) {
 		DEBUG(1, (__location__ " Error sending local control "
 			  "SCHEDULE_FOR_DELETION: %s, cstatus = %d\n",
-			  nt_errstr(status), cstatus));
-		if (NT_STATUS_IS_OK(status)) {
+			  strerror(ret), cstatus));
+		if (ret != 0) {
+			status = map_nt_error_from_unix(ret);
+		} else {
 			status = NT_STATUS_UNSUCCESSFUL;
 		}
 	}
@@ -1008,7 +1011,6 @@ static struct db_record *fetch_locked_internal(struct db_ctdb_ctx *ctx,
 {
 	struct db_record *result;
 	struct db_ctdb_rec *crec;
-	NTSTATUS status;
 	TDB_DATA ctdb_data;
 	int migrate_attempts;
 	struct timeval migrate_start;
@@ -1018,6 +1020,7 @@ static struct db_record *fetch_locked_internal(struct db_ctdb_ctx *ctx,
 	double ctdb_time = 0;
 	int duration_msecs;
 	int lockret;
+	int ret;
 
 	if (!(result = talloc(mem_ctx, struct db_record))) {
 		DEBUG(0, ("talloc failed\n"));
@@ -1104,13 +1107,13 @@ again:
 			   ((struct ctdb_ltdb_header *)ctdb_data.dptr)->flags : 0));
 
 		GetTimeOfDay(&ctdb_start_time);
-		status = ctdbd_migrate(messaging_ctdbd_connection(), ctx->db_id,
-				       key);
+		ret = ctdbd_migrate(messaging_ctdbd_connection(), ctx->db_id,
+				    key);
 		ctdb_time += timeval_elapsed(&ctdb_start_time);
 
-		if (!NT_STATUS_IS_OK(status)) {
+		if (ret != 0) {
 			DEBUG(5, ("ctdb_migrate failed: %s\n",
-				  nt_errstr(status)));
+				  strerror(ret)));
 			TALLOC_FREE(result);
 			return NULL;
 		}
@@ -1254,6 +1257,7 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key,
 		db->private_data, struct db_ctdb_ctx);
 	struct db_ctdb_parse_record_state state;
 	NTSTATUS status;
+	int ret;
 
 	state.parser = parser;
 	state.private_data = private_data;
@@ -1291,8 +1295,12 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key,
 		return NT_STATUS_OK;
 	}
 
-	return ctdbd_parse(messaging_ctdbd_connection(), ctx->db_id, key,
-			   state.ask_for_readonly_copy, parser, private_data);
+	ret = ctdbd_parse(messaging_ctdbd_connection(), ctx->db_id, key,
+			  state.ask_for_readonly_copy, parser, private_data);
+	if (ret != 0) {
+		return map_nt_error_from_unix(ret);
+	}
+	return NT_STATUS_OK;
 }
 
 struct traverse_state {
@@ -1356,7 +1364,7 @@ static int db_ctdb_traverse(struct db_context *db,
 				      void *private_data),
 			    void *private_data)
 {
-	NTSTATUS status;
+	int ret;
         struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
                                                         struct db_ctdb_ctx);
 	struct traverse_state state;
@@ -1368,7 +1376,6 @@ static int db_ctdb_traverse(struct db_context *db,
 
 	if (db->persistent) {
 		struct tdb_context *ltdb = ctx->wtdb->tdb;
-		int ret;
 
 		/* for persistent databases we don't need to do a ctdb traverse,
 		   we can do a faster local traverse */
@@ -1383,9 +1390,10 @@ static int db_ctdb_traverse(struct db_context *db,
 			 */
 			struct db_context *newkeys = db_open_rbt(talloc_tos());
 			struct ctdb_marshall_buffer *mbuf = ctx->transaction->m_write;
-			struct ctdb_rec_data *rec=NULL;
+			struct ctdb_rec_data_old *rec=NULL;
 			int i;
 			int count = 0;
+			NTSTATUS status;
 
 			if (newkeys == NULL) {
 				return -1;
@@ -1414,8 +1422,9 @@ static int db_ctdb_traverse(struct db_context *db,
 		return ret;
 	}
 
-	status = ctdbd_traverse(ctx->db_id, traverse_callback, &state);
-	if (!NT_STATUS_IS_OK(status)) {
+	ret = ctdbd_traverse(messaging_ctdbd_connection(), ctx->db_id,
+			     traverse_callback, &state);
+	if (ret != 0) {
 		return -1;
 	}
 	return state.count;
@@ -1487,7 +1496,7 @@ static int db_ctdb_traverse_read(struct db_context *db,
 					   void *private_data),
 				 void *private_data)
 {
-	NTSTATUS status;
+	int ret;
         struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
                                                         struct db_ctdb_ctx);
 	struct traverse_state state;
@@ -1503,8 +1512,9 @@ static int db_ctdb_traverse_read(struct db_context *db,
 		return tdb_traverse_read(ctx->wtdb->tdb, traverse_persistent_callback_read, &state);
 	}
 
-	status = ctdbd_traverse(ctx->db_id, traverse_read_callback, &state);
-	if (!NT_STATUS_IS_OK(status)) {
+	ret = ctdbd_traverse(messaging_ctdbd_connection(), ctx->db_id,
+			     traverse_read_callback, &state);
+	if (ret != 0) {
 		return -1;
 	}
 	return state.count;
@@ -1517,14 +1527,16 @@ static int db_ctdb_get_seqnum(struct db_context *db)
 	return tdb_get_seqnum(ctx->wtdb->tdb);
 }
 
-static void db_ctdb_id(struct db_context *db, const uint8_t **id,
-		       size_t *idlen)
+static size_t db_ctdb_id(struct db_context *db, uint8_t *id, size_t idlen)
 {
 	struct db_ctdb_ctx *ctx = talloc_get_type_abort(
 		db->private_data, struct db_ctdb_ctx);
 
-	*id = (uint8_t *)&ctx->db_id;
-	*idlen = sizeof(ctx->db_id);
+	if (idlen >= sizeof(ctx->db_id)) {
+		memcpy(id, &ctx->db_id, sizeof(ctx->db_id));
+	}
+
+	return sizeof(ctx->db_id);
 }
 
 struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
@@ -1540,8 +1552,8 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 	struct ctdbd_connection *conn;
 	struct loadparm_context *lp_ctx;
 	struct ctdb_db_priority prio;
-	NTSTATUS status;
 	int cstatus;
+	int ret;
 
 	if (!lp_clustering()) {
 		DEBUG(10, ("Clustering disabled -- no ctdb\n"));
@@ -1577,8 +1589,10 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 
-	if (!NT_STATUS_IS_OK(ctdbd_db_attach(conn, name, &db_ctdb->db_id, tdb_flags))) {
-		DEBUG(0, ("ctdbd_db_attach failed for %s\n", name));
+	ret = ctdbd_db_attach(conn, name, &db_ctdb->db_id, tdb_flags);
+	if (ret != 0) {
+		DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name,
+			  strerror(ret)));
 		TALLOC_FREE(result);
 		return NULL;
 	}
@@ -1592,22 +1606,17 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 	tdb_flags &= TDB_SEQNUM|TDB_VOLATILE|
 		TDB_MUTEX_LOCKING|TDB_CLEAR_IF_FIRST;
 
-	/* honor permissions if user has specified O_CREAT */
-	if (open_flags & O_CREAT) {
-		chmod(db_path, mode);
-	}
-
 	prio.db_id = db_ctdb->db_id;
 	prio.priority = lock_order;
 
-	status = ctdbd_control_local(
+	ret = ctdbd_control_local(
 		conn, CTDB_CONTROL_SET_DB_PRIORITY, 0, 0,
 		make_tdb_data((uint8_t *)&prio, sizeof(prio)),
 		NULL, NULL, &cstatus);
 
-	if (!NT_STATUS_IS_OK(status) || (cstatus != 0)) {
+	if ((ret != 0) || (cstatus != 0)) {
 		DEBUG(1, ("CTDB_CONTROL_SET_DB_PRIORITY failed: %s, %d\n",
-			  nt_errstr(status), cstatus));
+			  strerror(ret), cstatus));
 		TALLOC_FREE(result);
 		return NULL;
 	}
@@ -1620,12 +1629,12 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 		indata = make_tdb_data((uint8_t *)&db_ctdb->db_id,
 				       sizeof(db_ctdb->db_id));
 
-		status = ctdbd_control_local(
+		ret = ctdbd_control_local(
 			conn, CTDB_CONTROL_SET_DB_READONLY, 0, 0, indata,
 			NULL, NULL, &cstatus);
-		if (!NT_STATUS_IS_OK(status) || (cstatus != 0)) {
+		if ((ret != 0) || (cstatus != 0)) {
 			DEBUG(1, ("CTDB_CONTROL_SET_DB_READONLY failed: "
-				  "%s, %d\n", nt_errstr(status), cstatus));
+				  "%s, %d\n", strerror(ret), cstatus));
 			TALLOC_FREE(result);
 			return NULL;
 		}
@@ -1648,6 +1657,19 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 	}
 	talloc_free(db_path);
 
+	/* honor permissions if user has specified O_CREAT */
+	if (open_flags & O_CREAT) {
+		int fd;
+		fd = tdb_fd(db_ctdb->wtdb->tdb);
+		ret = fchmod(fd, mode);
+		if (ret == -1) {
+			DBG_WARNING("fchmod failed: %s\n",
+				    strerror(errno));
+			TALLOC_FREE(result);
+			return NULL;
+		}
+	}
+
 	if (result->persistent) {
 		db_ctdb->lock_ctx = g_lock_ctx_init(db_ctdb,
 						    ctdb_conn_msg_ctx(conn));
diff --git a/source3/lib/dbwrap/dbwrap_open.c b/source3/lib/dbwrap/dbwrap_open.c
index 64f484e..59fb3e4 100644
--- a/source3/lib/dbwrap/dbwrap_open.c
+++ b/source3/lib/dbwrap/dbwrap_open.c
@@ -25,6 +25,7 @@
 #include "dbwrap/dbwrap_tdb.h"
 #include "dbwrap/dbwrap_ctdb.h"
 #include "lib/param/param.h"
+#include "lib/cluster_support.h"
 #include "util_tdb.h"
 #include "ctdbd_conn.h"
 
diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
index da1a9cc..09e67fb 100644
--- a/source3/lib/dbwrap/dbwrap_watch.c
+++ b/source3/lib/dbwrap/dbwrap_watch.c
@@ -45,33 +45,29 @@ static struct db_context *dbwrap_record_watchers_db(void)
 	return watchers_db;
 }
 
-static TDB_DATA dbwrap_record_watchers_key(TALLOC_CTX *mem_ctx,
-					   struct db_context *db,
-					   struct db_record *rec,
-					   TDB_DATA *rec_key)
+static size_t dbwrap_record_watchers_key(struct db_context *db,
+					 struct db_record *rec,
+					 uint8_t *wkey, size_t wkey_len)
 {
-	const uint8_t *db_id;
-	size_t db_id_len;
-	TDB_DATA key, wkey;
+	size_t db_id_len = dbwrap_db_id(db, NULL, 0);
+	uint8_t db_id[db_id_len];
+	size_t needed;
+	TDB_DATA key;
+
+	dbwrap_db_id(db, db_id, db_id_len);
 
-	dbwrap_db_id(db, &db_id, &db_id_len);
 	key = dbwrap_record_get_key(rec);
 
-	wkey.dsize = sizeof(uint32_t) + db_id_len + key.dsize;
-	wkey.dptr = talloc_array(mem_ctx, uint8_t, wkey.dsize);
-	if (wkey.dptr == NULL) {
-		return make_tdb_data(NULL, 0);
-	}
-	SIVAL(wkey.dptr, 0, db_id_len);
-	memcpy(wkey.dptr + sizeof(uint32_t), db_id, db_id_len);
-	memcpy(wkey.dptr + sizeof(uint32_t) + db_id_len, key.dptr, key.dsize);
+	needed = sizeof(uint32_t) + db_id_len + key.dsize;
 
-	if (rec_key != NULL) {
-		rec_key->dptr = wkey.dptr + sizeof(uint32_t) + db_id_len;
-		rec_key->dsize = key.dsize;
+	if (wkey_len >= needed) {
+		SIVAL(wkey, 0, db_id_len);
+		memcpy(wkey + sizeof(uint32_t), db_id, db_id_len);
+		memcpy(wkey + sizeof(uint32_t) + db_id_len,
+		       key.dptr, key.dsize);
 	}
 
-	return wkey;
+	return needed;
 }
 
 static bool dbwrap_record_watchers_key_parse(
@@ -89,10 +85,16 @@ static bool dbwrap_record_watchers_key_parse(
 			  "db_id_len=%d\n", (int)wkey.dsize, (int)db_id_len));
 		return false;
 	}
-	*p_db_id = wkey.dptr + sizeof(uint32_t);
-	*p_db_id_len = db_id_len;
-	key->dptr = wkey.dptr + sizeof(uint32_t) + db_id_len;
-	key->dsize = wkey.dsize - sizeof(uint32_t) - db_id_len;
+	if (p_db_id != NULL) {
+		*p_db_id = wkey.dptr + sizeof(uint32_t);
+	}
+	if (p_db_id_len != NULL) {
+		*p_db_id_len = db_id_len;
+	}
+	if (key != NULL) {
+		key->dptr = wkey.dptr + sizeof(uint32_t) + db_id_len;
+		key->dsize = wkey.dsize - sizeof(uint32_t) - db_id_len;
+	}
 	return true;
 }
 
@@ -191,53 +193,11 @@ done:
 	return status;
 }
 
-static NTSTATUS dbwrap_record_get_watchers(struct db_context *db,
-					   struct db_record *rec,
-					   TALLOC_CTX *mem_ctx,
-					   struct server_id **p_ids,
-					   size_t *p_num_ids)
-{
-	struct db_context *w_db;
-	TDB_DATA key = { 0, };
-	TDB_DATA value = { 0, };
-	struct server_id *ids;
-	NTSTATUS status;
-
-	key = dbwrap_record_watchers_key(talloc_tos(), db, rec, NULL);
-	if (key.dptr == NULL) {
-		status = NT_STATUS_NO_MEMORY;
-		goto fail;
-	}
-	w_db = dbwrap_record_watchers_db();
-	if (w_db == NULL) {
-		status = NT_STATUS_INTERNAL_ERROR;
-		goto fail;
-	}
-	status = dbwrap_fetch(w_db, mem_ctx, key, &value);
-	TALLOC_FREE(key.dptr);
-	if (!NT_STATUS_IS_OK(status)) {
-		goto fail;
-	}
-	if ((value.dsize % sizeof(struct server_id)) != 0) {
-		status = NT_STATUS_INTERNAL_DB_CORRUPTION;
-		goto fail;
-	}
-	ids = (struct server_id *)value.dptr;
-	*p_ids = talloc_move(mem_ctx, &ids);
-	*p_num_ids = value.dsize / sizeof(struct server_id);
-	return NT_STATUS_OK;
-fail:
-	TALLOC_FREE(key.dptr);
-	TALLOC_FREE(value.dptr);
-	return status;
-}
-
 struct dbwrap_record_watch_state {
 	struct tevent_context *ev;
 	struct db_context *db;
 	struct tevent_req *req;
 	struct messaging_context *msg;
-	TDB_DATA key;
 	TDB_DATA w_key;
 };
 
@@ -273,11 +233,15 @@ struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	state->w_key = dbwrap_record_watchers_key(state, state->db, rec,
-						  &state->key);
+	state->w_key.dsize = dbwrap_record_watchers_key(
+		state->db, rec, NULL, 0);
+
+	state->w_key.dptr = talloc_array(state, uint8_t, state->w_key.dsize);
 	if (tevent_req_nomem(state->w_key.dptr, req)) {
 		return tevent_req_post(req, ev);
 	}
+	dbwrap_record_watchers_key(
+		state->db, rec, state->w_key.dptr, state->w_key.dsize);
 
 	subreq = messaging_filtered_read_send(
 		state, ev, state->msg, dbwrap_record_watch_filter, state);
@@ -324,48 +288,66 @@ static int dbwrap_record_watch_state_destructor(
 	return 0;
 }
 
+static void dbwrap_watch_record_stored_fn(TDB_DATA key, TDB_DATA data,
+					  void *private_data)
+{
+	struct messaging_context *msg = private_data;
+	size_t i, num_ids;
+
+	if ((data.dsize % sizeof(struct server_id)) != 0) {
+		DBG_WARNING("Invalid data size: %zu\n", data.dsize);
+		return;
+	}
+	num_ids = data.dsize / sizeof(struct server_id);
+
+	for (i=0; i<num_ids; i++) {
+		struct server_id dst;
+		NTSTATUS status;
+
+		memcpy(&dst, data.dptr + i * sizeof(struct server_id),
+		       sizeof(struct server_id));
+
+		status = messaging_send_buf(msg, dst, MSG_DBWRAP_MODIFIED,
+					    key.dptr, key.dsize);
+		if (!NT_STATUS_IS_OK(status)) {
+			struct server_id_buf tmp;
+			DBG_WARNING("messaging_send to %s failed: %s\n",
+				    server_id_str_buf(dst, &tmp),
+				    nt_errstr(status));
+		}
+	}
+}
+
 static void dbwrap_watch_record_stored(struct db_context *db,
 				       struct db_record *rec,
 				       void *private_data)
 {
 	struct messaging_context *msg = talloc_get_type_abort(
 		private_data, struct messaging_context);
-	struct server_id *ids = NULL;
-	size_t num_ids = 0;
-	TDB_DATA w_key = { 0, };
+	struct db_context *watchers_db;
+
+	size_t wkey_len = dbwrap_record_watchers_key(db, rec, NULL, 0);
+	uint8_t wkey_buf[wkey_len];
+	TDB_DATA wkey = { .dptr = wkey_buf, .dsize = wkey_len };
+
 	NTSTATUS status;
-	uint32_t i;
 
-	status = dbwrap_record_get_watchers(db, rec, talloc_tos(),
-					    &ids, &num_ids);
+	watchers_db = dbwrap_record_watchers_db();
+	if (watchers_db == NULL) {
+		return;
+	}
+
+	dbwrap_record_watchers_key(db, rec, wkey_buf, wkey_len);
+
+	status = dbwrap_parse_record(watchers_db, wkey,
+				     dbwrap_watch_record_stored_fn, msg);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
-		goto done;
+		return;
 	}
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(1, ("dbwrap_record_get_watchers failed: %s\n",
-			  nt_errstr(status)));
-		goto done;
-	}
-	w_key = dbwrap_record_watchers_key(talloc_tos(), db, rec, NULL);
-	if (w_key.dptr == NULL) {
-		DEBUG(1, ("dbwrap_record_watchers_key failed\n"));
-		goto done;
-	}
-
-	for (i=0; i<num_ids; i++) {
-		status = messaging_send_buf(msg, ids[i], MSG_DBWRAP_MODIFIED,
-					    w_key.dptr, w_key.dsize);
-		if (!NT_STATUS_IS_OK(status)) {
-			struct server_id_buf tmp;
-			DEBUG(1, ("messaging_send to %s failed: %s\n",
-				  server_id_str_buf(ids[i], &tmp),
-				  nt_errstr(status)));
-		}
+		DBG_WARNING("dbwrap_parse_record failed: %s\n",
+			    nt_errstr(status));
 	}
-done:
-	TALLOC_FREE(w_key.dptr);
-	TALLOC_FREE(ids);
-	return;
 }
 
 void dbwrap_watch_db(struct db_context *db, struct messaging_context *msg)
@@ -396,7 +378,9 @@ NTSTATUS dbwrap_record_watch_recv(struct tevent_req *req,
 	struct dbwrap_record_watch_state *state = tevent_req_data(
 		req, struct dbwrap_record_watch_state);
 	NTSTATUS status;
+	TDB_DATA key;
 	struct db_record *rec;
+	bool ok;
 
 	if (tevent_req_is_nterror(req, &status)) {
 		return status;
@@ -404,7 +388,13 @@ NTSTATUS dbwrap_record_watch_recv(struct tevent_req *req,
 	if (prec == NULL) {
 		return NT_STATUS_OK;
 	}
-	rec = dbwrap_fetch_locked(state->db, mem_ctx, state->key);
+
+	ok = dbwrap_record_watchers_key_parse(state->w_key, NULL, NULL, &key);
+	if (!ok) {
+		return NT_STATUS_INTERNAL_DB_ERROR;
+	}
+
+	rec = dbwrap_fetch_locked(state->db, mem_ctx, key);
 	if (rec == NULL) {
 		return NT_STATUS_INTERNAL_DB_ERROR;
 	}
diff --git a/source3/lib/dummyparam.c b/source3/lib/dummyparam.c
deleted file mode 100644
index 91dda65..0000000
--- a/source3/lib/dummyparam.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-   RPC pipe client
-
-   Copyright (C) Gerald (Jerry) Carter          2004.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/* Stupid dummy functions required due to the horrible dependency mess
-   in Samba. */
-
-#include "includes.h"
-
-int find_service(TALLOC_CTX *ctx, const char *service_in, char **p_service_out)
-{
-	return -1;
-}
-
diff --git a/source3/lib/events.c b/source3/lib/events.c
index 0bc56e4..2e862ca 100644
--- a/source3/lib/events.c
+++ b/source3/lib/events.c
@@ -253,7 +253,7 @@ bool run_events_poll(struct tevent_context *ev, int pollrtn,
 			flags |= TEVENT_FD_WRITE;
 		}
 		if (flags & fde->flags) {
-			DLIST_DEMOTE(ev->fd_events, fde, struct tevent_fd);
+			DLIST_DEMOTE(ev->fd_events, fde);
 			fde->handler(ev, fde, flags, fde->private_data);
 			return true;
 		}
diff --git a/source3/lib/gencache.c b/source3/lib/gencache.c
index 90eafaa..ed16d79 100644
--- a/source3/lib/gencache.c
+++ b/source3/lib/gencache.c
@@ -63,7 +63,9 @@ static bool gencache_init(void)
 	int open_flags = O_RDWR|O_CREAT;
 
 	/* skip file open if it's already opened */
-	if (cache) return True;
+	if (cache) {
+		return true;
+	}
 
 	cache_fname = cache_path("gencache.tdb");
 	if (cache_fname == NULL) {
@@ -112,7 +114,7 @@ static bool gencache_init(void)
 
 	if (!cache) {
 		DEBUG(5, ("Attempt to open gencache.tdb has failed.\n"));
-		return False;
+		return false;
 	}
 
 	cache_fname = lock_path("gencache_notrans.tdb");
@@ -139,7 +141,7 @@ static bool gencache_init(void)
 	}
 	TALLOC_FREE(cache_fname);
 
-	return True;
+	return true;
 }
 
 static TDB_DATA last_stabilize_key(void)
@@ -281,6 +283,8 @@ bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
 			    time_t timeout)
 {
 	int ret;
+	fstring hdr;
+	int hdr_len;
 	char* val;
 	time_t last_stabilize;
 	static int writecount;
@@ -295,7 +299,9 @@ bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
 		return false;
 	}
 
-	if (!gencache_init()) return False;
+	if (!gencache_init()) {
+		return false;
+	}
 
 	if (gencache_have_val(keystr, blob, timeout)) {
 		DEBUG(10, ("Did not store value for %s, we already got it\n",
@@ -303,19 +309,23 @@ bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
 		return true;
 	}
 
-	val = talloc_asprintf(talloc_tos(), CACHE_DATA_FMT, (int)timeout);
-	if (val == NULL) {
-		return False;
+	hdr_len = fstr_sprintf(hdr, CACHE_DATA_FMT, (int)timeout);
+
+	if (hdr_len == -1) {
+		return false;
 	}
-	val = talloc_realloc(NULL, val, char, talloc_array_length(val)-1);
-	if (val == NULL) {
+	if ((blob->length + (size_t)hdr_len) < blob->length) {
 		return false;
 	}
-	val = (char *)talloc_append_blob(NULL, val, *blob);
+
+	val = talloc_array(talloc_tos(), char, hdr_len + blob->length);
 	if (val == NULL) {
 		return false;
 	}
 
+	memcpy(val, hdr, hdr_len);
+	memcpy(val+hdr_len, blob->data, blob->length);
+
 	DEBUG(10, ("Adding cache entry with key=[%s] and timeout="
 	           "[%s] (%d seconds %s)\n", keystr,
 		   timestring(talloc_tos(), timeout),
@@ -383,7 +393,9 @@ bool gencache_del(const char *keystr)
 		return false;
 	}
 
-	if (!gencache_init()) return False;	
+	if (!gencache_init()) {
+		return false;
+	}
 
 	DEBUG(10, ("Deleting cache entry (key=[%s])\n", keystr));
 
@@ -569,7 +581,7 @@ static void gencache_get_data_blob_parser(time_t timeout, DATA_BLOB blob,
  *        timeout
  *
  * @retval true when entry is successfuly fetched
- * @retval False for failure
+ * @retval false for failure
  **/
 
 bool gencache_get_data_blob(const char *keystr, TALLOC_CTX *mem_ctx,
@@ -604,7 +616,7 @@ bool gencache_get_data_blob(const char *keystr, TALLOC_CTX *mem_ctx,
 		*timeout = state.timeout;
 	}
 
-	return True;
+	return true;
 
 fail:
 	if (was_expired != NULL) {
@@ -793,14 +805,14 @@ static int wipe_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA val,
  *        timeout
  *
  * @retval true when entry is successfuly fetched
- * @retval False for failure
+ * @retval false for failure
  **/
 
 bool gencache_get(const char *keystr, TALLOC_CTX *mem_ctx, char **value,
 		  time_t *ptimeout)
 {
 	DATA_BLOB blob;
-	bool ret = False;
+	bool ret = false;
 
 	ret = gencache_get_data_blob(keystr, mem_ctx, &blob, ptimeout, NULL);
 	if (!ret) {
diff --git a/source3/lib/gencache.h b/source3/lib/gencache.h
new file mode 100644
index 0000000..4371835
--- /dev/null
+++ b/source3/lib/gencache.h
@@ -0,0 +1,52 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Generic, persistent and shared between processes cache mechanism for use
+ * by various parts of the Samba code
+ *
+ * Copyright (C) Rafal Szczesniak    2002
+ * Copyright (C) Volker Lendecke     2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_GENCACHE_H__
+#define __LIB_GENCACHE_H__
+
+#include "replace.h"
+#include "system/time.h"
+#include "lib/util/data_blob.h"
+
+bool gencache_set(const char *keystr, const char *value, time_t timeout);
+bool gencache_del(const char *keystr);
+bool gencache_get(const char *keystr, TALLOC_CTX *mem_ctx, char **value,
+		  time_t *ptimeout);
+bool gencache_parse(const char *keystr,
+		    void (*parser)(time_t timeout, DATA_BLOB blob,
+				   void *private_data),
+		    void *private_data);
+bool gencache_get_data_blob(const char *keystr, TALLOC_CTX *mem_ctx,
+			    DATA_BLOB *blob,
+			    time_t *timeout, bool *was_expired);
+bool gencache_stabilize(void);
+bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
+			    time_t timeout);
+void gencache_iterate_blobs(void (*fn)(const char *key, DATA_BLOB value,
+				       time_t timeout, void *private_data),
+			    void *private_data, const char *pattern);
+void gencache_iterate(void (*fn)(const char* key, const char *value,
+				 time_t timeout, void* dptr),
+                      void* data, const char* keystr_pattern);
+
+#endif
diff --git a/source3/lib/interface.c b/source3/lib/interface.c
index 3edeae5..a3bc5d2 100644
--- a/source3/lib/interface.c
+++ b/source3/lib/interface.c
@@ -20,6 +20,7 @@
 
 #include "includes.h"
 #include "lib/socket/interfaces.h"
+#include "librpc/gen_ndr/ioctl.h"
 
 static struct iface_struct *probed_ifaces;
 static int total_probed;
@@ -333,6 +334,9 @@ static void add_interface(const struct iface_struct *ifs)
 	iface->ip = ifs->ip;
 	iface->netmask = ifs->netmask;
 	iface->bcast = ifs->bcast;
+	iface->linkspeed = ifs->linkspeed;
+	iface->capability = ifs->capability;
+	iface->if_index = ifs->if_index;
 
 	DLIST_ADD(local_interfaces, iface);
 
@@ -347,6 +351,45 @@ static void add_interface(const struct iface_struct *ifs)
 			&iface->netmask) ));
 }
 
+
+static void parse_extra_info(char *key, uint64_t *speed, uint32_t *cap,
+			     uint32_t *if_index)
+{
+	while (key != NULL && *key != '\0') {
+		char *next_key;
+		char *val;
+
+		next_key = strchr_m(key, ',');
+		if (next_key != NULL) {
+			*next_key++ = 0;
+		}
+
+		val = strchr_m(key, '=');
+		if (val != NULL) {
+			*val++ = 0;
+
+			if (strequal_m(key, "speed")) {
+				*speed = (uint64_t)strtoull(val, NULL, 0);
+			} else if (strequal_m(key, "capability")) {
+				if (strequal_m(val, "RSS")) {
+					*cap |= FSCTL_NET_IFACE_RSS_CAPABLE;
+				} else if (strequal(val, "RDMA")) {
+					*cap |= FSCTL_NET_IFACE_RDMA_CAPABLE;
+				} else {
+					DBG_WARNING("Capability unknown: "
+						    "'%s'\n", val);
+				}
+			} else if (strequal_m(key, "if_index")) {
+				*if_index = (uint32_t)strtoul(val, NULL, 0);
+			} else {
+				DBG_DEBUG("Key unknown: '%s'\n", key);
+			}
+		}
+
+		key = next_key;
+	}
+}
+
 /****************************************************************************
  Interpret a single element from a interfaces= config line.
 
@@ -357,6 +400,20 @@ static void add_interface(const struct iface_struct *ifs)
  3) IP/masklen
  4) ip/mask
  5) bcast/mask
+
+ Additional information for an interface can be specified with
+ this extended syntax:
+
+    interface[;key1=value1[,key2=value2[...]]]
+
+ where
+ - keys known: 'speed', 'capability', 'if_index'
+ - speed is in bits per second
+ - capabilites known: 'RSS', 'RDMA'
+ - if_index should be used with care, because
+   these indexes should not conicide with indexes
+   the kernel sets...
+
 ****************************************************************************/
 
 static void interpret_interface(char *token)
@@ -370,6 +427,12 @@ static void interpret_interface(char *token)
 	int i;
 	bool added=false;
 	bool goodaddr = false;
+	uint64_t speed = 0;
+	uint32_t cap = FSCTL_NET_IFACE_NONE_CAPABLE;
+	uint32_t if_index = 0;
+	bool speed_set = false;
+	bool cap_set = false;
+	bool if_index_set = false;
 
 	/* first check if it is an interface name */
 	for (i=0;i<total_probed;i++) {
@@ -382,7 +445,24 @@ static void interpret_interface(char *token)
 		return;
 	}
 
-	/* maybe it is a DNS name */
+	/*
+	 * extract speed / capability information if present
+	 */
+	p = strchr_m(token, ';');
+	if (p != NULL) {
+		*p++ = 0;
+		parse_extra_info(p, &speed, &cap, &if_index);
+		if (speed != 0) {
+			speed_set = true;
+		}
+		if (cap != FSCTL_NET_IFACE_NONE_CAPABLE) {
+			cap_set = true;
+		}
+		if (if_index != 0) {
+			if_index_set = true;
+		}
+	}
+
 	p = strchr_m(token,'/');
 	if (p == NULL) {
 		if (!interpret_string_addr(&ss, token, 0)) {
@@ -392,7 +472,18 @@ static void interpret_interface(char *token)
 		}
 
 		for (i=0;i<total_probed;i++) {
-			if (sockaddr_equal((struct sockaddr *)&ss, (struct sockaddr *)&probed_ifaces[i].ip)) {
+			if (sockaddr_equal((struct sockaddr *)&ss,
+				(struct sockaddr *)&probed_ifaces[i].ip))
+			{
+				if (speed_set) {
+					probed_ifaces[i].linkspeed = speed;
+				}
+				if (cap_set) {
+					probed_ifaces[i].capability = cap;
+				}
+				if (if_index_set) {
+					probed_ifaces[i].if_index = if_index;
+				}
 				add_interface(&probed_ifaces[i]);
 				return;
 			}
@@ -462,6 +553,15 @@ static void interpret_interface(char *token)
 					"config file on interface %s\n",
 					p,
 					probed_ifaces[i].name));
+				if (speed_set) {
+					probed_ifaces[i].linkspeed = speed;
+				}
+				if (cap_set) {
+					probed_ifaces[i].capability = cap;
+				}
+				if (if_index_set) {
+					probed_ifaces[i].if_index = if_index;
+				}
 				add_interface(&probed_ifaces[i]);
 				probed_ifaces[i].netmask = saved_mask;
 				return;
@@ -484,6 +584,15 @@ static void interpret_interface(char *token)
 	ifs.ip = ss;
 	ifs.netmask = ss_mask;
 	ifs.bcast = ss_bcast;
+	if (if_index_set) {
+		probed_ifaces[i].if_index = if_index;
+	}
+	if (speed_set) {
+		ifs.linkspeed = speed;
+	} else {
+		ifs.linkspeed = 1000 * 1000 * 1000;
+	}
+	ifs.capability = cap;
 	add_interface(&ifs);
 }
 
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 07d1c83..ef8e83d 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -291,7 +291,6 @@ struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx,
 					 struct tevent_context *ev)
 {
 	struct messaging_context *ctx;
-	NTSTATUS status;
 	int ret;
 	const char *lck_path;
 	const char *priv_path;
@@ -301,7 +300,10 @@ struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 
-	ctx->id = procid_self();
+	ctx->id = (struct server_id) {
+		.pid = getpid(), .vnn = NONCLUSTER_VNN
+	};
+
 	ctx->event_ctx = ev;
 
 	sec_init();
@@ -337,7 +339,7 @@ struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx,
 	}
 
 	ctx->msg_dgm_ref = messaging_dgm_ref(
-		ctx, ctx->event_ctx, ctx->id.unique_id,
+		ctx, ctx->event_ctx, &ctx->id.unique_id,
 		priv_path, lck_path, messaging_recv_cb, ctx, &ret);
 
 	if (ctx->msg_dgm_ref == NULL) {
@@ -349,11 +351,11 @@ struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx,
 	talloc_set_destructor(ctx, messaging_context_destructor);
 
 	if (lp_clustering()) {
-		status = messaging_ctdbd_init(ctx, ctx, &ctx->remote);
+		ret = messaging_ctdbd_init(ctx, ctx, &ctx->remote);
 
-		if (!NT_STATUS_IS_OK(status)) {
+		if (ret != 0) {
 			DEBUG(2, ("messaging_ctdbd_init failed: %s\n",
-				  nt_errstr(status)));
+				  strerror(ret)));
 			TALLOC_FREE(ctx);
 			return NULL;
 		}
@@ -390,15 +392,16 @@ struct server_id messaging_server_id(const struct messaging_context *msg_ctx)
  */
 NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
 {
-	NTSTATUS status;
 	int ret;
 
 	TALLOC_FREE(msg_ctx->msg_dgm_ref);
 
-	msg_ctx->id = procid_self();
+	msg_ctx->id = (struct server_id) {
+		.pid = getpid(), .vnn = msg_ctx->id.vnn
+	};
 
 	msg_ctx->msg_dgm_ref = messaging_dgm_ref(
-		msg_ctx, msg_ctx->event_ctx, msg_ctx->id.unique_id,
+		msg_ctx, msg_ctx->event_ctx, &msg_ctx->id.unique_id,
 		private_path("msg.sock"), lock_path("msg.lock"),
 		messaging_recv_cb, msg_ctx, &ret);
 
@@ -410,13 +413,13 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
 	TALLOC_FREE(msg_ctx->remote);
 
 	if (lp_clustering()) {
-		status = messaging_ctdbd_init(msg_ctx, msg_ctx,
-					      &msg_ctx->remote);
+		ret = messaging_ctdbd_init(msg_ctx, msg_ctx,
+					   &msg_ctx->remote);
 
-		if (!NT_STATUS_IS_OK(status)) {
+		if (ret != 0) {
 			DEBUG(1, ("messaging_ctdbd_init failed: %s\n",
-				  nt_errstr(status)));
-			return status;
+				  strerror(ret)));
+			return map_nt_error_from_unix(ret);
 		}
 	}
 
@@ -520,37 +523,34 @@ NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx,
 	return messaging_send(msg_ctx, server, msg_type, &blob);
 }
 
-NTSTATUS messaging_send_iov_from(struct messaging_context *msg_ctx,
-				 struct server_id src, struct server_id dst,
-				 uint32_t msg_type,
-				 const struct iovec *iov, int iovlen,
-				 const int *fds, size_t num_fds)
+int messaging_send_iov_from(struct messaging_context *msg_ctx,
+			    struct server_id src, struct server_id dst,
+			    uint32_t msg_type,
+			    const struct iovec *iov, int iovlen,
+			    const int *fds, size_t num_fds)
 {
 	int ret;
 	uint8_t hdr[MESSAGE_HDR_LENGTH];
 	struct iovec iov2[iovlen+1];
 
 	if (server_id_is_disconnected(&dst)) {
-		return NT_STATUS_INVALID_PARAMETER_MIX;
+		return EINVAL;
 	}
 
 	if (num_fds > INT8_MAX) {
-		return NT_STATUS_INVALID_PARAMETER_MIX;
+		return EINVAL;
 	}
 
 	if (!procid_is_local(&dst)) {
 		if (num_fds > 0) {
-			return NT_STATUS_NOT_SUPPORTED;
+			return ENOSYS;
 		}
 
 		ret = msg_ctx->remote->send_fn(src, dst,
 					       msg_type, iov, iovlen,
 					       NULL, 0,
 					       msg_ctx->remote);
-		if (ret != 0) {
-			return map_nt_error_from_unix(ret);
-		}
-		return NT_STATUS_OK;
+		return ret;
 	}
 
 	message_hdr_put(hdr, msg_type, src, dst);
@@ -561,10 +561,7 @@ NTSTATUS messaging_send_iov_from(struct messaging_context *msg_ctx,
 	ret = messaging_dgm_send(dst.pid, iov2, iovlen+1, fds, num_fds);
 	unbecome_root();
 
-	if (ret != 0) {
-		return map_nt_error_from_unix(ret);
-	}
-	return NT_STATUS_OK;
+	return ret;
 }
 
 NTSTATUS messaging_send_iov(struct messaging_context *msg_ctx,
@@ -572,8 +569,14 @@ NTSTATUS messaging_send_iov(struct messaging_context *msg_ctx,
 			    const struct iovec *iov, int iovlen,
 			    const int *fds, size_t num_fds)
 {
-	return messaging_send_iov_from(msg_ctx, msg_ctx->id, dst, msg_type,
-				       iov, iovlen, fds, num_fds);
+	int ret;
+
+	ret = messaging_send_iov_from(msg_ctx, msg_ctx->id, dst, msg_type,
+				      iov, iovlen, fds, num_fds);
+	if (ret != 0) {
+		return map_nt_error_from_unix(ret);
+	}
+	return NT_STATUS_OK;
 }
 
 static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx,
@@ -644,7 +647,7 @@ struct tevent_req *messaging_filtered_read_send(
 
 	state->tevent_handle = messaging_dgm_register_tevent_context(
 		state, ev);
-	if (tevent_req_nomem(state, req)) {
+	if (tevent_req_nomem(state->tevent_handle, req)) {
 		return tevent_req_post(req, ev);
 	}
 
diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
index 294debe..48563a8 100644
--- a/source3/lib/messages_ctdbd.c
+++ b/source3/lib/messages_ctdbd.c
@@ -23,6 +23,7 @@
 #include "lib/util/iov_buf.h"
 #include "lib/messages_util.h"
 #include "ctdbd_conn.h"
+#include "lib/cluster_support.h"
 
 
 struct messaging_ctdbd_context {
@@ -81,7 +82,6 @@ static int messaging_ctdb_send(struct server_id src,
 		backend->private_data, struct messaging_ctdbd_context);
 	uint8_t hdr[MESSAGE_HDR_LENGTH];
 	struct iovec iov2[iovlen+1];
-	NTSTATUS status;
 
 	if (num_fds > 0) {
 		return ENOSYS;
@@ -91,12 +91,8 @@ static int messaging_ctdb_send(struct server_id src,
 	iov2[0] = (struct iovec){ .iov_base = hdr, .iov_len = sizeof(hdr) };
 	memcpy(&iov2[1], iov, iovlen * sizeof(*iov));
 
-	status = ctdbd_messaging_send_iov(ctx->conn, pid.vnn, pid.pid,
-					  iov2, iovlen+1);
-	if (NT_STATUS_IS_OK(status)) {
-		return 0;
-	}
-	return map_errno_from_nt_status(status);
+	return ctdbd_messaging_send_iov(ctx->conn, pid.vnn, pid.pid,
+					iov2, iovlen+1);
 }
 
 static int messaging_ctdbd_destructor(struct messaging_ctdbd_context *ctx)
@@ -116,7 +112,7 @@ static int messaging_ctdb_recv(
 	struct messaging_context *msg_ctx = talloc_get_type_abort(
 		private_data, struct messaging_context);
 	struct server_id me = messaging_server_id(msg_ctx);
-	NTSTATUS status;
+	int ret;
 	struct iovec iov;
 	struct server_id src, dst;
 	enum messaging_type msg_type;
@@ -152,56 +148,64 @@ static int messaging_ctdb_recv(
 	 * Go through the event loop
 	 */
 
-	status = messaging_send_iov_from(msg_ctx, src, dst, msg_type,
-					 &iov, 1, NULL, 0);
+	ret = messaging_send_iov_from(msg_ctx, src, dst, msg_type,
+				      &iov, 1, NULL, 0);
 
-	if (!NT_STATUS_IS_OK(status)) {
+	if (ret != 0) {
 		DEBUG(10, ("%s: messaging_send_iov_from failed: %s\n",
-			   __func__, nt_errstr(status)));
+			   __func__, strerror(ret)));
 	}
 
 	return 0;
 }
 
-NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx,
-			      TALLOC_CTX *mem_ctx,
-			      struct messaging_backend **presult)
+int messaging_ctdbd_init(struct messaging_context *msg_ctx,
+			 TALLOC_CTX *mem_ctx,
+			 struct messaging_backend **presult)
 {
 	struct messaging_backend *result;
 	struct messaging_ctdbd_context *ctx;
-	NTSTATUS status;
+	int ret;
 
 	if (!(result = talloc(mem_ctx, struct messaging_backend))) {
 		DEBUG(0, ("talloc failed\n"));
-		return NT_STATUS_NO_MEMORY;
+		return ENOMEM;
 	}
 
 	if (!(ctx = talloc(result, struct messaging_ctdbd_context))) {
 		DEBUG(0, ("talloc failed\n"));
 		TALLOC_FREE(result);
-		return NT_STATUS_NO_MEMORY;
+		return ENOMEM;
 	}
 
-	status = ctdbd_messaging_connection(ctx, &ctx->conn);
+	ret = ctdbd_messaging_connection(ctx, lp_ctdbd_socket(),
+					 lp_ctdb_timeout(), &ctx->conn);
 
-	if (!NT_STATUS_IS_OK(status)) {
+	if (ret != 0) {
 		DEBUG(10, ("ctdbd_messaging_connection failed: %s\n",
-			   nt_errstr(status)));
+			   strerror(ret)));
 		TALLOC_FREE(result);
-		return status;
+		return ret;
 	}
 
-	status = ctdbd_register_msg_ctx(ctx->conn, msg_ctx);
+	ret = ctdbd_register_msg_ctx(ctx->conn, msg_ctx,
+				     messaging_tevent_context(msg_ctx));
 
-	if (!NT_STATUS_IS_OK(status)) {
+	if (ret != 0) {
 		DEBUG(10, ("ctdbd_register_msg_ctx failed: %s\n",
-			   nt_errstr(status)));
+			   strerror(ret)));
 		TALLOC_FREE(result);
-		return status;
+		return ret;
 	}
 
-	status = register_with_ctdbd(ctx->conn, getpid(),
-				     messaging_ctdb_recv, msg_ctx);
+	ret = register_with_ctdbd(ctx->conn, getpid(),
+				  messaging_ctdb_recv, msg_ctx);
+	if (ret != 0) {
+		DEBUG(10, ("register_with_ctdbd failed: %s\n",
+			   strerror(ret)));
+		TALLOC_FREE(result);
+		return ret;
+	}
 
 	global_ctdb_connection_pid = getpid();
 	global_ctdbd_connection = ctx->conn;
@@ -213,5 +217,5 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx,
 	result->private_data = (void *)ctx;
 
 	*presult = result;
-	return NT_STATUS_OK;
+	return 0;
 }
diff --git a/source3/lib/messages_dgm.c b/source3/lib/messages_dgm.c
index 1602caf..a802882 100644
--- a/source3/lib/messages_dgm.c
+++ b/source3/lib/messages_dgm.c
@@ -17,7 +17,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "includes.h"
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include <dirent.h>
 #include "lib/util/data_blob.h"
 #include "lib/util/debug.h"
 #include "lib/unix_msg/unix_msg.h"
@@ -26,6 +29,7 @@
 #include "lib/param/param.h"
 #include "poll_funcs/poll_funcs_tevent.h"
 #include "unix_msg/unix_msg.h"
+#include "lib/util/genrand.h"
 
 struct sun_path_buf {
 	/*
@@ -64,25 +68,46 @@ static int messaging_dgm_context_destructor(struct messaging_dgm_context *c);
 
 static int messaging_dgm_lockfile_create(struct messaging_dgm_context *ctx,
 					 pid_t pid, int *plockfile_fd,
-					 uint64_t unique)
+					 uint64_t *punique)
 {
-	fstring buf;
+	char buf[64];
 	int lockfile_fd;
 	struct sun_path_buf lockfile_name;
 	struct flock lck;
+	uint64_t unique;
 	int unique_len, ret;
 	ssize_t written;
 
 	ret = snprintf(lockfile_name.buf, sizeof(lockfile_name.buf),
-		       "%s/%u", ctx->lockfile_dir.buf, (int)pid);
+		       "%s/%u", ctx->lockfile_dir.buf, (unsigned)pid);
 	if (ret >= sizeof(lockfile_name.buf)) {
 		return ENAMETOOLONG;
 	}
 
 	/* no O_EXCL, existence check is via the fcntl lock */
 
-	lockfile_fd = open(lockfile_name.buf, O_NONBLOCK|O_CREAT|O_WRONLY,
+	lockfile_fd = open(lockfile_name.buf, O_NONBLOCK|O_CREAT|O_RDWR,
 			   0644);
+
+        if ((lockfile_fd == -1) &&
+	    ((errno == ENXIO) /* Linux */ ||
+	     (errno == ENODEV) /* Linux kernel bug */ ||
+	     (errno == EOPNOTSUPP) /* FreeBSD */)) {
+		/*
+                 * Huh -- a socket? This might be a stale socket from
+                 * an upgrade of Samba. Just unlink and retry, nobody
+                 * else is supposed to be here at this time.
+                 *
+                 * Yes, this is racy, but I don't see a way to deal
+                 * with this properly.
+                 */
+		unlink(lockfile_name.buf);
+
+		lockfile_fd = open(lockfile_name.buf,
+				   O_NONBLOCK|O_CREAT|O_WRONLY,
+				   0644);
+	}
+
 	if (lockfile_fd == -1) {
 		ret = errno;
 		DEBUG(1, ("%s: open failed: %s\n", __func__, strerror(errno)));
@@ -101,6 +126,19 @@ static int messaging_dgm_lockfile_create(struct messaging_dgm_context *ctx,
 		goto fail_close;
 	}
 
+	/*
+	 * Directly using the binary value for
+	 * SERVERID_UNIQUE_ID_NOT_TO_VERIFY is a layering
+	 * violation. But including all of ndr here just for this
+	 * seems to be a bit overkill to me. Also, messages_dgm might
+	 * be replaced sooner or later by something streams-based,
+	 * where unique_id generation will be handled differently.
+	 */
+
+	do {
+		generate_random_buffer((uint8_t *)&unique, sizeof(unique));
+	} while (unique == UINT64_C(0xFFFFFFFFFFFFFFFF));
+
 	unique_len = snprintf(buf, sizeof(buf), "%ju\n", (uintmax_t)unique);
 
 	/* shorten a potentially preexisting file */
@@ -121,6 +159,7 @@ static int messaging_dgm_lockfile_create(struct messaging_dgm_context *ctx,
 	}
 
 	*plockfile_fd = lockfile_fd;
+	*punique = unique;
 	return 0;
 
 fail_unlink:
@@ -131,7 +170,7 @@ fail_close:
 }
 
 int messaging_dgm_init(struct tevent_context *ev,
-		       uint64_t unique,
+		       uint64_t *punique,
 		       const char *socket_dir,
 		       const char *lockfile_dir,
 		       void (*recv_cb)(const uint8_t *msg,
@@ -183,7 +222,7 @@ int messaging_dgm_init(struct tevent_context *ev,
 	}
 
 	ret = messaging_dgm_lockfile_create(ctx, ctx->pid, &ctx->lockfile_fd,
-					    unique);
+					    punique);
 	if (ret != 0) {
 		DEBUG(1, ("%s: messaging_dgm_create_lockfile failed: %s\n",
 			  __func__, strerror(ret)));
@@ -300,6 +339,66 @@ static void messaging_dgm_recv(struct unix_msg_ctx *ctx,
 			 dgm_ctx->recv_cb_private_data);
 }
 
+static int messaging_dgm_read_unique(int fd, uint64_t *punique)
+{
+	char buf[25];
+	ssize_t rw_ret;
+	unsigned long long unique;
+	char *endptr;
+
+	rw_ret = pread(fd, buf, sizeof(buf)-1, 0);
+	if (rw_ret == -1) {
+		return errno;
+	}
+	buf[rw_ret] = '\0';
+
+	unique = strtoull(buf, &endptr, 10);
+	if ((unique == 0) && (errno == EINVAL)) {
+		return EINVAL;
+	}
+	if ((unique == ULLONG_MAX) && (errno == ERANGE)) {
+		return ERANGE;
+	}
+	if (endptr[0] != '\n') {
+		return EINVAL;
+	}
+	*punique = unique;
+	return 0;
+}
+
+int messaging_dgm_get_unique(pid_t pid, uint64_t *unique)
+{
+	struct messaging_dgm_context *ctx = global_dgm_context;
+	struct sun_path_buf lockfile_name;
+	int ret, fd;
+
+	if (ctx == NULL) {
+		return EBADF;
+	}
+
+	if (pid == getpid()) {
+		/*
+		 * Protect against losing our own lock
+		 */
+		return messaging_dgm_read_unique(ctx->lockfile_fd, unique);
+	}
+
+	ret = snprintf(lockfile_name.buf, sizeof(lockfile_name.buf),
+		       "%s/%u", ctx->lockfile_dir.buf, (int)pid);
+	if (ret >= sizeof(lockfile_name.buf)) {
+		return ENAMETOOLONG;
+	}
+
+	fd = open(lockfile_name.buf, O_NONBLOCK|O_RDONLY, 0);
+	if (fd == -1) {
+		return errno;
+	}
+
+	ret = messaging_dgm_read_unique(fd, unique);
+	close(fd);
+	return ret;
+}
+
 int messaging_dgm_cleanup(pid_t pid)
 {
 	struct messaging_dgm_context *ctx = global_dgm_context;
diff --git a/source3/lib/messages_dgm.h b/source3/lib/messages_dgm.h
index c9c9c61..a9cbd81 100644
--- a/source3/lib/messages_dgm.h
+++ b/source3/lib/messages_dgm.h
@@ -25,7 +25,7 @@
 #include <tevent.h>
 
 int messaging_dgm_init(struct tevent_context *ev,
-		       uint64_t unique,
+		       uint64_t *unique,
 		       const char *socket_dir,
 		       const char *lockfile_dir,
 		       void (*recv_cb)(const uint8_t *msg,
@@ -35,6 +35,7 @@ int messaging_dgm_init(struct tevent_context *ev,
 				       void *private_data),
 		       void *recv_cb_private_data);
 void messaging_dgm_destroy(void);
+int messaging_dgm_get_unique(pid_t pid, uint64_t *unique);
 int messaging_dgm_send(pid_t pid,
 		       const struct iovec *iov, int iovlen,
 		       const int *fds, size_t num_fds);
diff --git a/source3/lib/messages_dgm_ref.c b/source3/lib/messages_dgm_ref.c
index 0a6cbf7..3ea8b9d 100644
--- a/source3/lib/messages_dgm_ref.c
+++ b/source3/lib/messages_dgm_ref.c
@@ -40,7 +40,7 @@ static void msg_dgm_ref_recv(const uint8_t *msg, size_t msg_len,
 			     int *fds, size_t num_fds, void *private_data);
 
 void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-			uint64_t unique,
+			uint64_t *unique,
 			const char *socket_dir,
 			const char *lockfile_dir,
 			void (*recv_cb)(const uint8_t *msg, size_t msg_len,
@@ -73,6 +73,7 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 
 		ret = messaging_dgm_init(ev, unique, socket_dir, lockfile_dir,
 					 msg_dgm_ref_recv, NULL);
+		DBG_DEBUG("messaging_dgm_init returned %s\n", strerror(ret));
 		if (ret != 0) {
 			DEBUG(10, ("messaging_dgm_init failed: %s\n",
 				   strerror(ret)));
@@ -82,6 +83,16 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 		}
 		dgm_pid = getpid();
 	} else {
+		int ret;
+		ret = messaging_dgm_get_unique(getpid(), unique);
+		DBG_DEBUG("messaging_dgm_get_unique returned %s\n",
+			  strerror(ret));
+		if (ret != 0) {
+			TALLOC_FREE(result);
+			*err = ret;
+			return NULL;
+		}
+
 		result->tevent_handle = messaging_dgm_register_tevent_context(
 			result, ev);
 		if (result->tevent_handle == NULL) {
@@ -91,6 +102,8 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 		}
 	}
 
+	DBG_DEBUG("unique = %"PRIu64"\n", *unique);
+
 	refs = tmp_refs;
 
 	result->recv_cb = recv_cb;
@@ -126,6 +139,8 @@ static int msg_dgm_ref_destructor(struct msg_dgm_ref *r)
 
 	TALLOC_FREE(r->tevent_handle);
 
+	DBG_DEBUG("refs=%p\n", refs);
+
 	if (refs == NULL) {
 		messaging_dgm_destroy();
 	}
diff --git a/source3/lib/messages_dgm_ref.h b/source3/lib/messages_dgm_ref.h
index 3df0c06..8f0aff8 100644
--- a/source3/lib/messages_dgm_ref.h
+++ b/source3/lib/messages_dgm_ref.h
@@ -25,7 +25,7 @@
 #include "replace.h"
 
 void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-			uint64_t unique,
+			uint64_t *unique,
 			const char *socket_dir,
 			const char *lockfile_dir,
 			void (*recv_cb)(const uint8_t *msg, size_t msg_len,
diff --git a/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c b/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c
index a2582a1..1e5d577 100644
--- a/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c
+++ b/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c
@@ -1171,7 +1171,7 @@ static void callback_do_change(GtkWidget *widget,
 	box1 = gtk_vbox_new(FALSE, 0);
 	gtk_container_add(GTK_CONTAINER(window), box1);
 
-	label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
+	label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network resources.");
 	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
 	gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
diff --git a/source3/lib/poll_funcs/poll_funcs_tevent.c b/source3/lib/poll_funcs/poll_funcs_tevent.c
index 565cdaf..8fdf080 100644
--- a/source3/lib/poll_funcs/poll_funcs_tevent.c
+++ b/source3/lib/poll_funcs/poll_funcs_tevent.c
@@ -19,7 +19,7 @@
 #include "poll_funcs_tevent.h"
 #include "tevent.h"
 #include "system/select.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
 
 /*
  * A poll_watch is asked for by the engine using this library via
diff --git a/source3/lib/popt_common.c b/source3/lib/popt_common.c
index c2a95d7..b685b65 100644
--- a/source3/lib/popt_common.c
+++ b/source3/lib/popt_common.c
@@ -508,7 +508,7 @@ struct poptOption popt_common_credentials[] = {
 	{ "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" },
 	{ "signing", 'S', POPT_ARG_STRING, NULL, 'S', "Set the client signing state", "on|off|required" },
 	{"machine-pass", 'P', POPT_ARG_NONE, NULL, 'P', "Use stored machine account password" },
-	{"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },
+	{"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport" },
 	{"use-ccache", 'C', POPT_ARG_NONE, NULL, 'C',
 	 "Use the winbind ccache for authentication" },
 	{"pw-nt-hash", '\0', POPT_ARG_NONE, NULL, 'H',
diff --git a/source3/lib/privileges.c b/source3/lib/privileges.c
index 19ee688..d3509c2 100644
--- a/source3/lib/privileges.c
+++ b/source3/lib/privileges.c
@@ -271,7 +271,7 @@ static int priv_traverse_fn(struct db_record *rec, void *state)
 }
 
 /*********************************************************************
- Retreive list of privileged SIDs (for _lsa_enumerate_accounts()
+ Retrieve list of privileged SIDs (for _lsa_enumerate_accounts()
 *********************************************************************/
 
 NTSTATUS privilege_enumerate_accounts(struct dom_sid **sids, int *num_sids)
diff --git a/source3/lib/pthreadpool/pthreadpool.c b/source3/lib/pthreadpool/pthreadpool.c
index d683578..4b745e4 100644
--- a/source3/lib/pthreadpool/pthreadpool.c
+++ b/source3/lib/pthreadpool/pthreadpool.c
@@ -274,7 +274,16 @@ static void pthreadpool_join_children(struct pthreadpool *pool)
 	int i;
 
 	for (i=0; i<pool->num_exited; i++) {
-		pthread_join(pool->exited[i], NULL);
+		int ret;
+
+		ret = pthread_join(pool->exited[i], NULL);
+		if (ret != 0) {
+			/*
+			 * Severe internal error, we can't do much but
+			 * abort here.
+			 */
+			abort();
+		}
 	}
 	pool->num_exited = 0;
 
diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c
index 403d5e8..e1eb241 100644
--- a/source3/lib/recvfile.c
+++ b/source3/lib/recvfile.c
@@ -25,7 +25,7 @@
 
 #include "includes.h"
 #include "system/filesys.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 
 /* Do this on our own in TRANSFER_BUF_SIZE chunks.
  * It's safe to make direct syscalls to lseek/write here
diff --git a/source3/lib/server_id_db_util.c b/source3/lib/server_id_db_util.c
index ead9ed3..98ee07d 100644
--- a/source3/lib/server_id_db_util.c
+++ b/source3/lib/server_id_db_util.c
@@ -20,6 +20,7 @@
 #include "replace.h"
 #include "server_id_db_util.h"
 #include "serverid.h"
+#include "lib/util/samba_util.h"
 
 static int server_id_db_check_exclusive(
 	struct server_id_db *db, const char *name,
@@ -71,15 +72,8 @@ static int server_id_db_check_exclusive(
 	unsigned num_servers, struct server_id *servers)
 {
 	struct server_id me = server_id_db_pid(db);
-	bool exists[num_servers];
-	bool ok;
 	int i;
 
-	ok = serverids_exist(servers, num_servers, exists);
-	if (!ok) {
-		return ENOMEM;
-	}
-
 	for (i=0; i<num_servers; i++) {
 		int ret;
 
@@ -90,7 +84,7 @@ static int server_id_db_check_exclusive(
 			continue;
 		}
 
-		if (exists[i]) {
+		if (serverid_exists(&servers[i])) {
 			return EEXIST;
 		}
 
diff --git a/source3/lib/serverid.c b/source3/lib/serverid.c
index 39c733c..5c2fa65 100644
--- a/source3/lib/serverid.c
+++ b/source3/lib/serverid.c
@@ -27,6 +27,7 @@
 #include "lib/param/param.h"
 #include "ctdbd_conn.h"
 #include "messages.h"
+#include "lib/messages_dgm.h"
 
 struct serverid_key {
 	pid_t pid;
@@ -120,9 +121,7 @@ bool serverid_register(const struct server_id id, uint32_t msg_flags)
 		goto done;
 	}
 
-	if (lp_clustering() &&
-	    ctdb_serverids_exist_supported(messaging_ctdbd_connection()))
-	{
+	if (lp_clustering()) {
 		register_with_ctdbd(messaging_ctdbd_connection(), id.unique_id,
 				    NULL, NULL);
 	}
@@ -168,228 +167,40 @@ done:
 	return ret;
 }
 
-struct serverid_exists_state {
-	const struct server_id *id;
-	bool exists;
-};
-
-static void server_exists_parse(TDB_DATA key, TDB_DATA data, void *priv)
+static bool serverid_exists_local(const struct server_id *id)
 {
-	struct serverid_exists_state *state =
-		(struct serverid_exists_state *)priv;
+	bool exists = process_exists_by_pid(id->pid);
+	uint64_t unique;
+	int ret;
 
-	if (data.dsize != sizeof(struct serverid_data)) {
-		state->exists = false;
-		return;
+	if (!exists) {
+		return false;
 	}
 
-	/*
-	 * Use memcmp, not direct compare. data.dptr might not be
-	 * aligned.
-	 */
-	state->exists = (memcmp(&state->id->unique_id, data.dptr,
-				sizeof(state->id->unique_id)) == 0);
-}
-
-bool serverid_exists(const struct server_id *id)
-{
-	bool result = false;
-	bool ok = false;
+	if (id->unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
+		return true;
+	}
 
-	ok = serverids_exist(id, 1, &result);
-	if (!ok) {
+	ret = messaging_dgm_get_unique(id->pid, &unique);
+	if (ret != 0) {
 		return false;
 	}
 
-	return result;
+	return (unique == id->unique_id);
 }
 
-bool serverids_exist(const struct server_id *ids, int num_ids, bool *results)
+bool serverid_exists(const struct server_id *id)
 {
-	int *todo_idx = NULL;
-	struct server_id *todo_ids = NULL;
-	bool *todo_results = NULL;
-	int todo_num = 0;
-	int *remote_idx = NULL;
-	int remote_num = 0;
-	int *verify_idx = NULL;
-	int verify_num = 0;
-	int t, idx;
-	bool result = false;
-	struct db_context *db;
-
-	db = serverid_db();
-	if (db == NULL) {
-		return false;
-	}
-
-	todo_idx = talloc_array(talloc_tos(), int, num_ids);
-	if (todo_idx == NULL) {
-		goto fail;
-	}
-	todo_ids = talloc_array(talloc_tos(), struct server_id, num_ids);
-	if (todo_ids == NULL) {
-		goto fail;
-	}
-	todo_results = talloc_array(talloc_tos(), bool, num_ids);
-	if (todo_results == NULL) {
-		goto fail;
+	if (procid_is_local(id)) {
+		return serverid_exists_local(id);
 	}
 
-	remote_idx = talloc_array(talloc_tos(), int, num_ids);
-	if (remote_idx == NULL) {
-		goto fail;
-	}
-	verify_idx = talloc_array(talloc_tos(), int, num_ids);
-	if (verify_idx == NULL) {
-		goto fail;
+	if (lp_clustering()) {
+		return ctdbd_process_exists(messaging_ctdbd_connection(),
+					    id->vnn, id->pid);
 	}
 
-	for (idx=0; idx<num_ids; idx++) {
-		results[idx] = false;
-
-		if (server_id_is_disconnected(&ids[idx])) {
-			continue;
-		}
-
-		if (procid_is_me(&ids[idx])) {
-			results[idx] = true;
-			continue;
-		}
-
-		if (procid_is_local(&ids[idx])) {
-			bool exists = process_exists_by_pid(ids[idx].pid);
-
-			if (!exists) {
-				continue;
-			}
-
-			if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
-				results[idx] = true;
-				continue;
-			}
-
-			verify_idx[verify_num] = idx;
-			verify_num += 1;
-			continue;
-		}
-
-		if (!lp_clustering()) {
-			continue;
-		}
-
-		remote_idx[remote_num] = idx;
-		remote_num += 1;
-	}
-
-	if (remote_num != 0 &&
-	    ctdb_serverids_exist_supported(messaging_ctdbd_connection()))
-	{
-		int old_remote_num = remote_num;
-
-		remote_num = 0;
-		todo_num = 0;
-
-		for (t=0; t<old_remote_num; t++) {
-			idx = remote_idx[t];
-
-			if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
-				remote_idx[remote_num] = idx;
-				remote_num += 1;
-				continue;
-			}
-
-			todo_idx[todo_num] = idx;
-			todo_ids[todo_num] = ids[idx];
-			todo_results[todo_num] = false;
-			todo_num += 1;
-		}
-
-		/*
-		 * Note: this only uses CTDB_CONTROL_CHECK_SRVIDS
-		 * to verify that the server_id still exists,
-		 * which means only the server_id.unique_id and
-		 * server_id.vnn are verified, while server_id.pid
-		 * is not verified at all.
-		 *
-		 * TODO: do we want to verify server_id.pid somehow?
-		 */
-		if (!ctdb_serverids_exist(messaging_ctdbd_connection(),
-					  todo_ids, todo_num, todo_results))
-		{
-			goto fail;
-		}
-
-		for (t=0; t<todo_num; t++) {
-			idx = todo_idx[t];
-
-			results[idx] = todo_results[t];
-		}
-	}
-
-	if (remote_num != 0) {
-		todo_num = 0;
-
-		for (t=0; t<remote_num; t++) {
-			idx = remote_idx[t];
-			todo_idx[todo_num] = idx;
-			todo_ids[todo_num] = ids[idx];
-			todo_results[todo_num] = false;
-			todo_num += 1;
-		}
-
-		if (!ctdb_processes_exist(messaging_ctdbd_connection(),
-					  todo_ids, todo_num,
-					  todo_results)) {
-			goto fail;
-		}
-
-		for (t=0; t<todo_num; t++) {
-			idx = todo_idx[t];
-
-			if (!todo_results[t]) {
-				continue;
-			}
-
-			if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
-				results[idx] = true;
-				continue;
-			}
-
-			verify_idx[verify_num] = idx;
-			verify_num += 1;
-		}
-	}
-
-	for (t=0; t<verify_num; t++) {
-		struct serverid_exists_state state;
-		struct serverid_key key;
-		TDB_DATA tdbkey;
-		NTSTATUS status;
-
-		idx = verify_idx[t];
-
-		serverid_fill_key(&ids[idx], &key);
-		tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
-
-		state.id = &ids[idx];
-		state.exists = false;
-		status = dbwrap_parse_record(db, tdbkey, server_exists_parse, &state);
-		if (!NT_STATUS_IS_OK(status)) {
-			results[idx] = false;
-			continue;
-		}
-		results[idx] = state.exists;
-	}
-
-	result = true;
-fail:
-	TALLOC_FREE(verify_idx);
-	TALLOC_FREE(remote_idx);
-	TALLOC_FREE(todo_results);
-	TALLOC_FREE(todo_ids);
-	TALLOC_FREE(todo_idx);
-	return result;
+	return false;
 }
 
 static bool serverid_rec_parse(const struct db_record *rec,
@@ -502,15 +313,3 @@ bool serverid_traverse(int (*fn)(struct db_record *rec,
 	status = dbwrap_traverse(db, serverid_traverse_fn, &state, NULL);
 	return NT_STATUS_IS_OK(status);
 }
-
-uint64_t serverid_get_random_unique_id(void)
-{
-	uint64_t unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
-
-	while (unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
-		generate_random_buffer((uint8_t *)&unique_id,
-				       sizeof(unique_id));
-	}
-
-	return unique_id;
-}
diff --git a/source3/lib/sessionid_tdb.c b/source3/lib/sessionid_tdb.c
index fd6cf75..cac0730 100644
--- a/source3/lib/sessionid_tdb.c
+++ b/source3/lib/sessionid_tdb.c
@@ -43,36 +43,9 @@ static int sessionid_traverse_read_fn(struct smbXsrv_session_global0 *global,
 		.id_num = global->session_global_id,
 		.connect_start = nt_time_to_unix(global->creation_time),
 		.pid = global->channels[0].server_id,
+		.connection_dialect = global->connection_dialect,
 	};
 
-	switch(global->connection_dialect){
-	case SMB2_DIALECT_REVISION_000:
-		fstrcpy(session.protocol_ver, "NT1");
-		break;
-	case SMB2_DIALECT_REVISION_202:
-		fstrcpy(session.protocol_ver, "SMB2_02");
-		break;
-	case SMB2_DIALECT_REVISION_210:
-		fstrcpy(session.protocol_ver, "SMB2_10");
-		break;
-	case SMB2_DIALECT_REVISION_222:
-		fstrcpy(session.protocol_ver, "SMB2_22");
-		break;
-	case SMB2_DIALECT_REVISION_224:
-		fstrcpy(session.protocol_ver, "SMB2_24");
-		break;
-	case SMB3_DIALECT_REVISION_300:
-		fstrcpy(session.protocol_ver, "SMB3_00");
-		break;
-	case SMB3_DIALECT_REVISION_302:
-		fstrcpy(session.protocol_ver, "SMB3_02");
-		break;
-	default:
-		fstr_sprintf(session.protocol_ver, "Unknown (0x%04x)",
-			     global->connection_dialect);
-		break;
-	}
-
 	if (session_info != NULL) {
 		session.uid = session_info->unix_token->uid;
 		session.gid = session_info->unix_token->gid;
@@ -96,6 +69,10 @@ static int sessionid_traverse_read_fn(struct smbXsrv_session_global0 *global,
 		global->channels[0].remote_address,
 		sizeof(fstring)-1);
 
+	session.encryption_flags = global->encryption_flags;
+	session.cipher = global->channels[0].encryption_cipher;
+	session.signing_flags = global->signing_flags;
+
 	return state->fn(NULL, &session, state->private_data);
 }
 
diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c
index f2d58a5..5a876e0 100644
--- a/source3/lib/smbldap.c
+++ b/source3/lib/smbldap.c
@@ -237,7 +237,7 @@
 					&blob)) {
 		return false;
 	}
-	ret = sid_parse((char *)blob.data, blob.length, sid);
+	ret = sid_parse(blob.data, blob.length, sid);
 	TALLOC_FREE(blob.data);
 	return ret;
 }
@@ -301,7 +301,7 @@ static void smbldap_set_mod_internal(LDAPMod *** modlist, int modop, const char
 		return;	
 	}
 
-#if 0	/* commented out after discussion with abartlet.  Do not reenable.
+#if 0	/* commented out after discussion with abartlet.  Do not re-enable.
 	   left here so other do not re-add similar code   --jerry */
        	if (value == NULL || *value == '\0')
 		return;
@@ -545,7 +545,7 @@ static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
 	t = SMB_XMALLOC_P(struct smbldap_state_lookup);
 	ZERO_STRUCTP(t);
 
-	DLIST_ADD_END(smbldap_state_lookup_list, t, struct smbldap_state_lookup *);
+	DLIST_ADD_END(smbldap_state_lookup_list, t);
 	t->ld = ld;
 	t->smbldap_state = smbldap_state;
 }
diff --git a/source3/lib/substitute.c b/source3/lib/substitute.c
index ce4fbba..4e2ce9b 100644
--- a/source3/lib/substitute.c
+++ b/source3/lib/substitute.c
@@ -500,7 +500,9 @@ char *talloc_sub_basic(TALLOC_CTX *mem_ctx,
 		case 'G' : {
 			struct passwd *pass;
 
-			if (domain_name != NULL && domain_name[0] != '\0') {
+			if (domain_name != NULL && domain_name[0] != '\0' &&
+			    !strequal(domain_name, my_sam_name()))
+			{
 				r = talloc_asprintf(tmp_ctx,
 						    "%s%c%s",
 						    domain_name,
diff --git a/source3/lib/sys_rw.c b/source3/lib/sys_rw.c
deleted file mode 100644
index 6d8f149..0000000
--- a/source3/lib/sys_rw.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * Samba system utilities
- * Copyright (C) Andrew Tridgell 1992-1998
- * Copyright (C) Jeremy Allison  1998-2005
- * Copyright (C) Timur Bakeyev        2005
- * Copyright (C) Bjoern Jacke    2006-2007
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "replace.h"
-#include "system/filesys.h"
-#include "lib/sys_rw.h"
-
-/*******************************************************************
-A read wrapper that will deal with EINTR/EWOULDBLOCK
-********************************************************************/
-
-ssize_t sys_read(int fd, void *buf, size_t count)
-{
-	ssize_t ret;
-
-	do {
-		ret = read(fd, buf, count);
-	} while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
-			       errno == EWOULDBLOCK));
-
-	return ret;
-}
-
-/*******************************************************************
-A write wrapper that will deal with EINTR/EWOULDBLOCK.
-********************************************************************/
-
-ssize_t sys_write(int fd, const void *buf, size_t count)
-{
-	ssize_t ret;
-
-	do {
-		ret = write(fd, buf, count);
-	} while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
-			       errno == EWOULDBLOCK));
-
-	return ret;
-}
-
-/*******************************************************************
-A writev wrapper that will deal with EINTR.
-********************************************************************/
-
-ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
-{
-	ssize_t ret;
-
-	do {
-		ret = writev(fd, iov, iovcnt);
-	} while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
-			       errno == EWOULDBLOCK));
-
-	return ret;
-}
-
-/*******************************************************************
-A pread wrapper that will deal with EINTR
-********************************************************************/
-
-ssize_t sys_pread(int fd, void *buf, size_t count, off_t off)
-{
-	ssize_t ret;
-
-	do {
-		ret = pread(fd, buf, count, off);
-	} while (ret == -1 && errno == EINTR);
-	return ret;
-}
-
-/*******************************************************************
-A write wrapper that will deal with EINTR
-********************************************************************/
-
-ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off)
-{
-	ssize_t ret;
-
-	do {
-		ret = pwrite(fd, buf, count, off);
-	} while (ret == -1 && errno == EINTR);
-	return ret;
-}
diff --git a/source3/lib/sys_rw_data.c b/source3/lib/sys_rw_data.c
deleted file mode 100644
index e3f934d..0000000
--- a/source3/lib/sys_rw_data.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * Samba system utilities
- * Copyright (C) Andrew Tridgell 1992-1998
- * Copyright (C) Jeremy Allison  1998-2005
- * Copyright (C) Timur Bakeyev        2005
- * Copyright (C) Bjoern Jacke    2006-2007
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "replace.h"
-#include "system/filesys.h"
-#include "lib/sys_rw_data.h"
-#include "lib/sys_rw.h"
-#include "lib/util/iov_buf.h"
-
-/****************************************************************************
- Write all data from an iov array
- NB. This can be called with a non-socket fd, don't add dependencies
- on socket calls.
-****************************************************************************/
-
-ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt)
-{
-	ssize_t to_send;
-	ssize_t thistime;
-	size_t sent;
-	struct iovec iov_copy[iovcnt];
-	struct iovec *iov;
-
-	to_send = iov_buflen(orig_iov, iovcnt);
-	if (to_send == -1) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	thistime = sys_writev(fd, orig_iov, iovcnt);
-	if ((thistime <= 0) || (thistime == to_send)) {
-		return thistime;
-	}
-	sent = thistime;
-
-	/*
-	 * We could not send everything in one call. Make a copy of iov that
-	 * we can mess with.
-	 */
-
-	memcpy(iov_copy, orig_iov, sizeof(struct iovec) * iovcnt);
-	iov = iov_copy;
-
-	while (sent < to_send) {
-		bool ok;
-
-		ok = iov_advance(&iov, &iovcnt, thistime);
-		if (!ok) {
-			errno = EIO;
-			return -1;
-		}
-
-		thistime = sys_writev(fd, iov, iovcnt);
-		if (thistime <= 0) {
-			break;
-		}
-		sent += thistime;
-	}
-
-	return sent;
-}
-
-/****************************************************************************
- Write data to a fd.
- NB. This can be called with a non-socket fd, don't add dependencies
- on socket calls.
-****************************************************************************/
-
-ssize_t write_data(int fd, const void *buffer, size_t n)
-{
-	struct iovec iov;
-
-	iov.iov_base = discard_const_p(void, buffer);
-	iov.iov_len = n;
-	return write_data_iov(fd, &iov, 1);
-}
-
-/*
- * Blocking read n bytes from a fd
- */
-
-ssize_t read_data(int fd, void *buffer, size_t n)
-{
-	ssize_t nread;
-
-	nread = 0;
-
-	while (nread < n) {
-		ssize_t ret;
-		ret = sys_read(fd, ((char *)buffer) + nread, n - nread);
-		if (ret <= 0) {
-			return ret;
-		}
-		nread += ret;
-	}
-
-	return nread;
-}
diff --git a/source3/lib/sysquotas_nfs.c b/source3/lib/sysquotas_nfs.c
index 58eedf0..4b37e34 100644
--- a/source3/lib/sysquotas_nfs.c
+++ b/source3/lib/sysquotas_nfs.c
@@ -211,19 +211,12 @@ int sys_get_nfs_quota(const char *path, const char *bdev,
 
 	/*
 	 * gqr.status returns
-	 *   0 if the rpc call fails,
 	 *   1 if quotas exist,
 	 *   2 if there is no quota set, and
 	 *   3 if no permission to get the quota.
 	 */
 
 	switch (gq_rslt.GQR_STATUS) {
-	case 0:
-		DEBUG(3, ("sys_get_nfs_quotas: Remote Quotas Failed! "
-			  "Error '%i'\n", gq_rslt.GQR_STATUS));
-		ret = -1;
-		goto out;
-
 	case 1:
 		DEBUG(10, ("sys_get_nfs_quotas: Good quota data\n"));
 		dp->bsize = (uint64_t)gq_rslt.GQR_RQUOTA.rq_bsize;
diff --git a/source3/lib/talloc_dict.c b/source3/lib/talloc_dict.c
index 71ab899..7594679 100644
--- a/source3/lib/talloc_dict.c
+++ b/source3/lib/talloc_dict.c
@@ -72,7 +72,7 @@ bool talloc_dict_set(struct talloc_dict *dict, DATA_BLOB key, void *pdata)
 			TALLOC_FREE(rec);
 			return false;
 		}
-		old_data = *(void **)(value.dptr);
+		memcpy(&old_data, value.dptr, sizeof(old_data));
 		TALLOC_FREE(old_data);
 		if (data == NULL) {
 			status = dbwrap_record_delete(rec);
@@ -138,6 +138,7 @@ static int talloc_dict_traverse_fn(struct db_record *rec, void *private_data)
 	TDB_DATA value;
 	struct talloc_dict_traverse_state *state =
 		(struct talloc_dict_traverse_state *)private_data;
+	void *p;
 
 	key = dbwrap_record_get_key(rec);
 	value = dbwrap_record_get_value(rec);
@@ -145,8 +146,10 @@ static int talloc_dict_traverse_fn(struct db_record *rec, void *private_data)
 	if (value.dsize != sizeof(void *)) {
 		return -1;
 	}
+
+	memcpy(&p, value.dptr, sizeof(p));
 	return state->fn(data_blob_const(key.dptr, key.dsize),
-			 *(void **)value.dptr, state->private_data);
+			 p, state->private_data);
 }
 
 /*
diff --git a/source3/lib/tldap.c b/source3/lib/tldap.c
index 5d3773e..d8b4f24 100644
--- a/source3/lib/tldap.c
+++ b/source3/lib/tldap.c
@@ -17,8 +17,13 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "tldap.h"
+#include "system/network.h"
+#include "system/locale.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/samba_util.h"
+#include "lib/util_tsock.h"
 #include "../lib/util/asn1.h"
 #include "../lib/tsocket/tsocket.h"
 #include "../lib/util/tevent_unix.h"
@@ -57,9 +62,6 @@ struct tldap_ctx_attribute {
 
 struct tldap_context {
 	int ld_version;
-	int ld_deref;
-	int ld_sizelimit;
-	int ld_timelimit;
 	struct tstream_context *conn;
 	bool server_down;
 	int msgid;
@@ -171,7 +173,7 @@ bool tldap_connection_ok(struct tldap_context *ld)
 static struct tldap_ctx_attribute *tldap_context_findattr(
 	struct tldap_context *ld, const char *name)
 {
-	int i, num_attrs;
+	size_t i, num_attrs;
 
 	num_attrs = talloc_array_length(ld->ctx_attrs);
 
@@ -485,7 +487,6 @@ static void tldap_msg_unset_pending(struct tevent_req *req)
 	 */
 	ld->pending = talloc_realloc(NULL, ld->pending, struct tevent_req *,
 				     num_pending - 1);
-	return;
 }
 
 static void tldap_msg_cleanup(struct tevent_req *req,
@@ -723,12 +724,10 @@ static struct tevent_req *tldap_req_create(TALLOC_CTX *mem_ctx,
 	if (req == NULL) {
 		return NULL;
 	}
-	ZERO_STRUCTP(state);
 	state->out = asn1_init(state);
 	if (state->out == NULL) {
 		goto err;
 	}
-	state->result = NULL;
 	state->id = tldap_next_msgid(ld);
 
 	if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
@@ -1315,7 +1314,7 @@ done:
 	}
 	s++;
 
-	if (data->has_error) {
+	if (asn1_has_error(data)) {
 		return false;
 	}
 
@@ -1529,7 +1528,7 @@ static bool tldap_push_filter_basic(struct tldap_context *ld,
 		if (!asn1_write_OctetString(data, uval, uval_len)) return false;
 	}
 
-	if (data->has_error) {
+	if (asn1_has_error(data)) {
 		return false;
 	}
 	return asn1_pop_tag(data);
@@ -1841,11 +1840,9 @@ int tldap_search(struct tldap_context *ld,
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct tevent_context *ev;
 	struct tevent_req *req;
-	struct tldap_sync_search_state state;
-
-	ZERO_STRUCT(state);
-	state.mem_ctx = mem_ctx;
-	state.rc = TLDAP_SUCCESS;
+	struct tldap_sync_search_state state = {
+		.mem_ctx = mem_ctx, .rc = TLDAP_SUCCESS
+	};
 
 	ev = samba_tevent_context_init(frame);
 	if (ev == NULL) {
@@ -2019,7 +2016,7 @@ static bool tldap_decode_controls(struct tldap_req_state *state)
 
 		if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto out;
 		if (!asn1_read_OctetString_talloc(msg, data, &oid)) goto out;
-		if ((data->has_error) || (oid == NULL)) {
+		if (asn1_has_error(data) || (oid == NULL)) {
 			goto out;
 		}
 		c->oid = oid;
diff --git a/source3/lib/tldap_util.c b/source3/lib/tldap_util.c
index 45bf19f..de1d4ba 100644
--- a/source3/lib/tldap_util.c
+++ b/source3/lib/tldap_util.c
@@ -93,7 +93,7 @@ bool tldap_pull_binsid(struct tldap_message *msg, const char *attribute,
 	if (!tldap_get_single_valueblob(msg, attribute, &val)) {
 		return false;
 	}
-	return sid_parse((char *)val.data, val.length, sid);
+	return sid_parse(val.data, val.length, sid);
 }
 
 bool tldap_pull_guid(struct tldap_message *msg, const char *attribute,
diff --git a/source3/lib/unix_msg/unix_msg.c b/source3/lib/unix_msg/unix_msg.c
index 3221133..bcfef28 100644
--- a/source3/lib/unix_msg/unix_msg.c
+++ b/source3/lib/unix_msg/unix_msg.c
@@ -21,7 +21,7 @@
 #include "system/select.h"
 #include "system/time.h"
 #include "system/network.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
 #include "pthreadpool/pthreadpool.h"
 #include "lib/util/iov_buf.h"
 #include "lib/msghdr.h"
@@ -495,7 +495,7 @@ static int queue_msg(struct unix_dgram_send_queue *q,
 	msghdr_copy(hdr, msghdrlen, NULL, 0, iov, iovcnt,
 		    fds_copy, num_fds);
 
-	DLIST_ADD_END(q->msgs, msg, struct unix_dgram_msg);
+	DLIST_ADD_END(q->msgs, msg);
 	return 0;
 fail:
 	close_fd_array(fds_copy, num_fds);
diff --git a/source3/lib/util.c b/source3/lib/util.c
index d38d53a..2895c14 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -28,10 +28,12 @@
 #include "ctdbd_conn.h"
 #include "../lib/util/util_pw.h"
 #include "messages.h"
+#include "messages_dgm.h"
 #include "libcli/security/security.h"
 #include "serverid.h"
-#include "lib/sys_rw.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/sys_rw_data.h"
+#include "lib/util/util_process.h"
 
 #ifdef HAVE_SYS_PRCTL_H
 #include <sys/prctl.h>
@@ -430,7 +432,8 @@ static void reinit_after_fork_pipe_handler(struct tevent_context *ev,
 
 NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
 			   struct tevent_context *ev_ctx,
-			   bool parent_longlived)
+			   bool parent_longlived,
+			   const char *comment)
 {
 	NTSTATUS status = NT_STATUS_OK;
 
@@ -439,12 +442,6 @@ NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
 		reinit_after_fork_pipe[1] = -1;
 	}
 
-	/* Reset the state of the random
-	 * number generation system, so
-	 * children do not get the same random
-	 * numbers as each other */
-	set_need_random_reseed();
-
 	/* tdb needs special fork handling */
 	if (tdb_reopen_all(parent_longlived ? 1 : 0) != 0) {
 		DEBUG(0,("tdb_reopen_all failed.\n"));
@@ -481,6 +478,11 @@ NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
 				 nt_errstr(status)));
 		}
 	}
+
+	if (comment) {
+		prctl_set_comment(comment);
+	}
+
  done:
 	return status;
 }
@@ -1494,78 +1496,6 @@ char *myhostname_upper(void)
 	return ret;
 }
 
-/**
- * @brief Returns an absolute path to a file concatenating the provided
- * @a rootpath and @a basename
- *
- * @param name Filename, relative to @a rootpath
- *
- * @retval Pointer to a string containing the full path.
- **/
-
-static char *xx_path(const char *name, const char *rootpath)
-{
-	char *fname = NULL;
-
-	fname = talloc_strdup(talloc_tos(), rootpath);
-	if (!fname) {
-		return NULL;
-	}
-	trim_string(fname,"","/");
-
-	if (!directory_exist(fname)) {
-		if (mkdir(fname,0755) == -1) {
-			/* Did someone else win the race ? */
-			if (errno != EEXIST) {
-				DEBUG(1, ("Unable to create directory %s for file %s. "
-					"Error was %s\n", fname, name, strerror(errno)));
-				return NULL;
-			}
-		}
-	}
-
-	return talloc_asprintf_append(fname, "/%s", name);
-}
-
-/**
- * @brief Returns an absolute path to a file in the Samba lock directory.
- *
- * @param name File to find, relative to LOCKDIR.
- *
- * @retval Pointer to a talloc'ed string containing the full path.
- **/
-
-char *lock_path(const char *name)
-{
-	return xx_path(name, lp_lock_directory());
-}
-
-/**
- * @brief Returns an absolute path to a file in the Samba state directory.
- *
- * @param name File to find, relative to STATEDIR.
- *
- * @retval Pointer to a talloc'ed string containing the full path.
- **/
-
-char *state_path(const char *name)
-{
-	return xx_path(name, lp_state_directory());
-}
-
-/**
- * @brief Returns an absolute path to a file in the Samba cache directory.
- *
- * @param name File to find, relative to CACHEDIR.
- *
- * @retval Pointer to a talloc'ed string containing the full path.
- **/
-
-char *cache_path(const char *name)
-{
-	return xx_path(name, lp_cache_directory());
-}
-
 /*******************************************************************
  Given a filename - get its directory name
 ********************************************************************/
@@ -1609,11 +1539,6 @@ bool ms_has_wild(const char *s)
 {
 	char c;
 
-	if (lp_posix_pathnames()) {
-		/* With posix pathnames no characters are wild. */
-		return False;
-	}
-
 	while ((c = *s++)) {
 		switch (c) {
 		case '*':
@@ -1893,32 +1818,6 @@ bool name_to_fqdn(fstring fqdn, const char *name)
 	return true;
 }
 
-/**********************************************************************
- Append a DATA_BLOB to a talloc'ed object
-***********************************************************************/
-
-void *talloc_append_blob(TALLOC_CTX *mem_ctx, void *buf, DATA_BLOB blob)
-{
-	size_t old_size = 0;
-	char *result;
-
-	if (blob.length == 0) {
-		return buf;
-	}
-
-	if (buf != NULL) {
-		old_size = talloc_get_size(buf);
-	}
-
-	result = (char *)TALLOC_REALLOC(mem_ctx, buf, old_size + blob.length);
-	if (result == NULL) {
-		return NULL;
-	}
-
-	memcpy(result + old_size, blob.data, blob.length);
-	return result;
-}
-
 uint32_t map_share_mode_to_deny_mode(uint32_t share_access, uint32_t private_options)
 {
 	switch (share_access & ~FILE_SHARE_DELETE) {
@@ -1940,72 +1839,11 @@ uint32_t map_share_mode_to_deny_mode(uint32_t share_access, uint32_t private_opt
 	return (uint32_t)-1;
 }
 
-pid_t procid_to_pid(const struct server_id *proc)
-{
-	return proc->pid;
-}
-
-static uint32_t my_vnn = NONCLUSTER_VNN;
-
-void set_my_vnn(uint32_t vnn)
-{
-	DEBUG(10, ("vnn pid %d = %u\n", (int)getpid(), (unsigned int)vnn));
-	my_vnn = vnn;
-}
-
-uint32_t get_my_vnn(void)
-{
-	return my_vnn;
-}
-
-static uint64_t my_unique_id = 0;
-
-void set_my_unique_id(uint64_t unique_id)
-{
-	my_unique_id = unique_id;
-}
-
-struct server_id pid_to_procid(pid_t pid)
-{
-	struct server_id result;
-	result.pid = pid;
-	result.task_id = 0;
-	result.unique_id = my_unique_id;
-	result.vnn = my_vnn;
-	return result;
-}
-
-struct server_id procid_self(void)
-{
-	return pid_to_procid(getpid());
-}
-
-bool procid_is_me(const struct server_id *pid)
-{
-	if (pid->pid != getpid())
-		return False;
-	if (pid->task_id != 0)
-		return False;
-	if (pid->vnn != my_vnn)
-		return False;
-	return True;
-}
-
 struct server_id interpret_pid(const char *pid_string)
 {
 	return server_id_from_string(get_my_vnn(), pid_string);
 }
 
-bool procid_valid(const struct server_id *pid)
-{
-	return (pid->pid != (uint64_t)-1);
-}
-
-bool procid_is_local(const struct server_id *pid)
-{
-	return pid->vnn == my_vnn;
-}
-
 /****************************************************************
  Check if an offset into a buffer is safe.
  If this returns True it's safe to indirect into the byte at
diff --git a/source3/lib/util_cluster.c b/source3/lib/util_cluster.c
index ef79c8b..bfa1154 100644
--- a/source3/lib/util_cluster.c
+++ b/source3/lib/util_cluster.c
@@ -21,16 +21,17 @@
 #include "includes.h"
 #include "ctdbd_conn.h"
 #include "util_cluster.h"
+#include "lib/cluster_support.h"
 
 bool cluster_probe_ok(void)
 {
 	if (lp_clustering()) {
-		NTSTATUS status;
+		int ret;
 
-		status = ctdbd_probe();
-		if (!NT_STATUS_IS_OK(status)) {
+		ret = ctdbd_probe(lp_ctdbd_socket(), lp_ctdb_timeout());
+		if (ret != 0) {
 			DEBUG(0, ("clustering=yes but ctdbd connect failed: "
-				  "%s\n", nt_errstr(status)));
+				  "%s\n", strerror(ret)));
 			return false;
 		}
 	}
diff --git a/source3/lib/util_ea.c b/source3/lib/util_ea.c
index e980e69..136291b 100644
--- a/source3/lib/util_ea.c
+++ b/source3/lib/util_ea.c
@@ -103,7 +103,7 @@ struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t
 			return NULL;
 		}
 
-		DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+		DLIST_ADD_END(ea_list_head, eal);
 		if (next_offset == 0) {
 			break;
 		}
diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c
index a603f01..5584d91 100644
--- a/source3/lib/util_file.c
+++ b/source3/lib/util_file.c
@@ -18,7 +18,7 @@
  */
 
 #include "includes.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 
 /**
  Load from a pipe into memory.
diff --git a/source3/lib/util_names.c b/source3/lib/util_names.c
index 1392b48..dc5c530 100644
--- a/source3/lib/util_names.c
+++ b/source3/lib/util_names.c
@@ -171,3 +171,17 @@ const char *get_global_sam_name(void)
 	return lp_netbios_name();
 }
 
+
+/******************************************************************
+ Get the default domain/netbios name to be used when
+ testing authentication.
+******************************************************************/
+
+const char *my_sam_name(void)
+{
+	if (lp_server_role() == ROLE_STANDALONE) {
+		return lp_netbios_name();
+	}
+
+	return lp_workgroup();
+}
diff --git a/source3/lib/util_path.c b/source3/lib/util_path.c
new file mode 100644
index 0000000..509ba5f
--- /dev/null
+++ b/source3/lib/util_path.c
@@ -0,0 +1,95 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba utility functions
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison 2001-2007
+ * Copyright (C) Simo Sorce 2001
+ * Copyright (C) Jim McDonough <jmcd at us.ibm.com> 2003
+ * Copyright (C) James Peach 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/samba_util.h"
+#include "lib/util_path.h"
+
+struct share_params;
+#include "source3/param/param_proto.h"
+
+/**
+ * @brief Returns an absolute path to a file concatenating the provided
+ * @a rootpath and @a basename
+ *
+ * @param name Filename, relative to @a rootpath
+ *
+ * @retval Pointer to a string containing the full path.
+ **/
+
+static char *xx_path(const char *name, const char *rootpath)
+{
+	char *fname = NULL;
+
+	fname = talloc_strdup(talloc_tos(), rootpath);
+	if (!fname) {
+		return NULL;
+	}
+	trim_string(fname,"","/");
+
+	if (!directory_create_or_exist(fname, 0755)) {
+		return NULL;
+	}
+
+	return talloc_asprintf_append(fname, "/%s", name);
+}
+
+/**
+ * @brief Returns an absolute path to a file in the Samba lock directory.
+ *
+ * @param name File to find, relative to LOCKDIR.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+
+char *lock_path(const char *name)
+{
+	return xx_path(name, lp_lock_directory());
+}
+
+/**
+ * @brief Returns an absolute path to a file in the Samba state directory.
+ *
+ * @param name File to find, relative to STATEDIR.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+
+char *state_path(const char *name)
+{
+	return xx_path(name, lp_state_directory());
+}
+
+/**
+ * @brief Returns an absolute path to a file in the Samba cache directory.
+ *
+ * @param name File to find, relative to CACHEDIR.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+
+char *cache_path(const char *name)
+{
+	return xx_path(name, lp_cache_directory());
+}
diff --git a/source3/lib/util_path.h b/source3/lib/util_path.h
new file mode 100644
index 0000000..118a4be
--- /dev/null
+++ b/source3/lib/util_path.h
@@ -0,0 +1,31 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba utility functions
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison 2001-2007
+ * Copyright (C) Simo Sorce 2001
+ * Copyright (C) Jim McDonough <jmcd at us.ibm.com> 2003
+ * Copyright (C) James Peach 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_UTIL_PATH_H__
+#define __LIB_UTIL_PATH_H__
+
+char *lock_path(const char *name);
+char *state_path(const char *name);
+char *cache_path(const char *name);
+
+#endif
diff --git a/source3/lib/util_procid.c b/source3/lib/util_procid.c
new file mode 100644
index 0000000..0ae99cc
--- /dev/null
+++ b/source3/lib/util_procid.c
@@ -0,0 +1,69 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba utility functions
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison 2001-2007
+ * Copyright (C) Simo Sorce 2001
+ * Copyright (C) Jim McDonough <jmcd at us.ibm.com> 2003
+ * Copyright (C) James Peach 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "util_procid.h"
+#include "lib/util/debug.h"
+#include "lib/messages_dgm.h"
+
+pid_t procid_to_pid(const struct server_id *proc)
+{
+	return proc->pid;
+}
+
+static uint32_t my_vnn = NONCLUSTER_VNN;
+
+void set_my_vnn(uint32_t vnn)
+{
+	DEBUG(10, ("vnn pid %d = %u\n", (int)getpid(), (unsigned int)vnn));
+	my_vnn = vnn;
+}
+
+uint32_t get_my_vnn(void)
+{
+	return my_vnn;
+}
+
+struct server_id pid_to_procid(pid_t pid)
+{
+	uint64_t unique = 0;
+	int ret;
+
+	ret = messaging_dgm_get_unique(pid, &unique);
+	if (ret != 0) {
+		DBG_NOTICE("messaging_dgm_get_unique failed: %s\n",
+			   strerror(ret));
+	}
+
+	return (struct server_id) {
+		.pid = pid, .unique_id = unique, .vnn = my_vnn };
+}
+
+bool procid_valid(const struct server_id *pid)
+{
+	return (pid->pid != (uint64_t)-1);
+}
+
+bool procid_is_local(const struct server_id *pid)
+{
+	return pid->vnn == my_vnn;
+}
diff --git a/source3/lib/util_procid.h b/source3/lib/util_procid.h
new file mode 100644
index 0000000..9637363
--- /dev/null
+++ b/source3/lib/util_procid.h
@@ -0,0 +1,37 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba utility functions
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison 2001-2007
+ * Copyright (C) Simo Sorce 2001
+ * Copyright (C) Jim McDonough <jmcd at us.ibm.com> 2003
+ * Copyright (C) James Peach 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_UTIL_PROCID_H__
+#define __LIB_UTIL_PROCID_H__
+
+#include "replace.h"
+#include "librpc/gen_ndr/server_id.h"
+
+pid_t procid_to_pid(const struct server_id *proc);
+void set_my_vnn(uint32_t vnn);
+uint32_t get_my_vnn(void);
+struct server_id pid_to_procid(pid_t pid);
+bool procid_valid(const struct server_id *pid);
+bool procid_is_local(const struct server_id *pid);
+
+#endif
diff --git a/source3/lib/util_sec.c b/source3/lib/util_sec.c
index 9ccd04e..760f8b0 100644
--- a/source3/lib/util_sec.c
+++ b/source3/lib/util_sec.c
@@ -60,8 +60,22 @@ void sec_init(void)
 	static int initialized;
 
 	if (!initialized) {
+
+#ifndef AUTOCONF_TEST
+		if (uid_wrapper_enabled()) {
+			setenv("UID_WRAPPER_MYUID", "1", 1);
+		}
+#endif
+
 		initial_uid = geteuid();
 		initial_gid = getegid();
+
+#ifndef AUTOCONF_TEST
+		if (uid_wrapper_enabled()) {
+			unsetenv("UID_WRAPPER_MYUID");
+		}
+#endif
+
 		initialized = 1;
 	}
 }
diff --git a/source3/lib/util_sid.c b/source3/lib/util_sid.c
index e336510..4d57a92 100644
--- a/source3/lib/util_sid.c
+++ b/source3/lib/util_sid.c
@@ -72,7 +72,7 @@ char *sid_string_tos(const struct dom_sid *sid)
  Write a sid out into on-the-wire format.
 *****************************************************************/  
 
-bool sid_linearize(char *outbuf, size_t len, const struct dom_sid *sid)
+bool sid_linearize(uint8_t *outbuf, size_t len, const struct dom_sid *sid)
 {
 	size_t i;
 
@@ -116,9 +116,9 @@ bool non_mappable_sid(struct dom_sid *sid)
 char *sid_binstring_hex_talloc(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
 {
 	int len = ndr_size_dom_sid(sid, 0);
-	char buf[len];
+	uint8_t buf[len];
 	sid_linearize(buf, len, sid);
-	return hex_encode_talloc(mem_ctx, (const unsigned char *)buf, len);
+	return hex_encode_talloc(mem_ctx, buf, len);
 }
 
 NTSTATUS sid_array_from_info3(TALLOC_CTX *mem_ctx,
@@ -185,6 +185,11 @@ NTSTATUS sid_array_from_info3(TALLOC_CTX *mem_ctx,
          */
 
 	for (i = 0; i < info3->sidcount; i++) {
+
+		if (sid_check_is_in_asserted_identity(info3->sids[i].sid)) {
+			continue;
+		}
+
 		status = add_sid_to_array(mem_ctx, info3->sids[i].sid,
 				      &sid_array, &num_sids);
 		if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
index cb57f84..0e1a66c 100644
--- a/source3/lib/util_sock.c
+++ b/source3/lib/util_sock.c
@@ -28,8 +28,8 @@
 #include "../lib/util/tevent_unix.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "../lib/tsocket/tsocket.h"
-#include "lib/sys_rw.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/sys_rw_data.h"
 
 const char *client_addr(int fd, char *addr, size_t addrlen)
 {
@@ -1070,7 +1070,7 @@ int get_remote_hostname(const struct tsocket_address *remote_address,
 	lookup_nc(&nc);
 
 	if (nc.name == NULL) {
-		*name = talloc_strdup(mem_ctx, "UNKOWN");
+		*name = talloc_strdup(mem_ctx, "UNKNOWN");
 	} else {
 		*name = talloc_strdup(mem_ctx, nc.name);
 	}
diff --git a/source3/lib/util_specialsids.c b/source3/lib/util_specialsids.c
new file mode 100644
index 0000000..4c402d6
--- /dev/null
+++ b/source3/lib/util_specialsids.c
@@ -0,0 +1,40 @@
+/*
+   Unix SMB/CIFS implementation.
+   Copyright (C) Guenther Deschner 2016
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../libcli/security/security.h"
+
+bool sid_check_is_asserted_identity(const struct dom_sid *sid)
+{
+	return dom_sid_equal(sid, &global_sid_Asserted_Identity);
+}
+
+bool sid_check_is_in_asserted_identity(const struct dom_sid *sid)
+{
+	struct dom_sid dom_sid;
+
+	sid_copy(&dom_sid, sid);
+	sid_split_rid(&dom_sid, NULL);
+
+	return sid_check_is_asserted_identity(&dom_sid);
+}
+
+const char *asserted_identity_domain_name(void)
+{
+	return "Asserted Identity";
+}
diff --git a/source3/lib/util_transfer_file.c b/source3/lib/util_transfer_file.c
index 91f4f6f..5653906 100644
--- a/source3/lib/util_transfer_file.c
+++ b/source3/lib/util_transfer_file.c
@@ -22,7 +22,7 @@
 
 #include <includes.h>
 #include "transfer_file.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 
 /****************************************************************************
  Transfer some data between two fd's.
diff --git a/source3/lib/util_tsock.c b/source3/lib/util_tsock.c
index 03380ef..6432ce4 100644
--- a/source3/lib/util_tsock.c
+++ b/source3/lib/util_tsock.c
@@ -17,7 +17,10 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/util_tsock.h"
 #include "../lib/tsocket/tsocket.h"
 #include "../lib/util/tevent_unix.h"
 
diff --git a/source3/lib/util_tsock.h b/source3/lib/util_tsock.h
new file mode 100644
index 0000000..de4381a
--- /dev/null
+++ b/source3/lib/util_tsock.h
@@ -0,0 +1,38 @@
+/*
+   Unix SMB/CIFS implementation.
+   Utilities around tsocket
+   Copyright (C) Volker Lendecke 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __UTIL_TSOCK_H__
+#define __UTIL_TSOCK_H__
+
+#include "replace.h"
+#include <tevent.h>
+
+struct tstream_context;
+struct tevent_req *tstream_read_packet_send(TALLOC_CTX *mem_ctx,
+					    struct tevent_context *ev,
+					    struct tstream_context *stream,
+					    size_t initial,
+					    ssize_t (*more)(uint8_t *buf,
+							    size_t buflen,
+							    void *private_data),
+					    void *private_data);
+ssize_t tstream_read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+				 uint8_t **pbuf, int *perrno);
+
+#endif
diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h
index 224d992..eb0dea9 100644
--- a/source3/libads/ads_proto.h
+++ b/source3/libads/ads_proto.h
@@ -98,8 +98,10 @@ ADS_STATUS ads_get_service_principal_names(TALLOC_CTX *mem_ctx,
 ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machine_name);
 ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_name,
                                           const char *my_fqdn, const char *spn);
-ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name,
-                                   const char *org_unit);
+ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
+				   const char *machine_name,
+				   const char *org_unit,
+				   uint32_t etype_list);
 ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name,
                                  const char *org_unit, bool *moved);
 int ads_count_replies(ADS_STRUCT *ads, void *res);
diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c
index 30d433e..0dc7b11 100644
--- a/source3/libads/ads_struct.c
+++ b/source3/libads/ads_struct.c
@@ -144,14 +144,6 @@ ADS_STRUCT *ads_init(const char *realm,
 	ads->server.workgroup = workgroup ? SMB_STRDUP(workgroup) : NULL;
 	ads->server.ldap_server = ldap_server? SMB_STRDUP(ldap_server) : NULL;
 
-	/* we need to know if this is a foreign realm */
-	if (realm && *realm && !strequal(lp_realm(), realm)) {
-		ads->server.foreign = 1;
-	}
-	if (workgroup && *workgroup && !strequal(lp_workgroup(), workgroup)) {
-		ads->server.foreign = 1;
-	}
-
 	/* the caller will own the memory by default */
 	ads->is_mine = 1;
 
@@ -162,9 +154,9 @@ ADS_STRUCT *ads_init(const char *realm,
 
 	ads->auth.flags = wrap_flags;
 
-	/* Start with a page size of 1000 when the connection is new,
+	/* Start with the configured page size when the connection is new,
 	 * we will drop it by half we get a timeout.   */
-	ads->config.ldap_page_size     = 1000;
+	ads->config.ldap_page_size     = lp_ldap_page_size();
 
 	return ads;
 }
diff --git a/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c
index 5b33e2e..c633495 100644
--- a/source3/libads/krb5_setpw.c
+++ b/source3/libads/krb5_setpw.c
@@ -98,7 +98,10 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *principal,
 		return ADS_ERROR_KRB5(ret);
 	}
 
-	ret = krb5_set_password_using_ccache(context, ccache, newpw, princ,
+	ret = krb5_set_password_using_ccache(context,
+					     ccache,
+					     discard_const_p(char, newpw),
+					     princ,
 					     &result_code,
 					     &result_code_string,
 					     &result_string);
@@ -236,8 +239,12 @@ static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
 	return ADS_ERROR_KRB5(ret);
     }
 
-    ret = krb5_change_password(context, &creds, newpw, &result_code,
-			       &result_code_string, &result_string);
+    ret = krb5_change_password(context,
+			       &creds,
+			       discard_const_p(char, newpw),
+			       &result_code,
+			       &result_code_string,
+			       &result_string);
     if (ret) {
 	DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret)));
 	aret = ADS_ERROR_KRB5(ret);
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 2e38df1..6735072 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -29,6 +29,7 @@
 #include "../libds/common/flags.h"
 #include "smbldap.h"
 #include "../libcli/security/security.h"
+#include "../librpc/gen_ndr/netlogon.h"
 #include "lib/param/loadparm.h"
 
 #ifdef HAVE_LDAP
@@ -1477,7 +1478,7 @@ char *ads_parent_dn(const char *dn)
 {
 	ADS_STATUS status;
 	char *expr;
-	const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
+	const char *attrs[] = {"*", "msDS-SupportedEncryptionTypes", "nTSecurityDescriptor", NULL};
 
 	*res = NULL;
 
@@ -1627,6 +1628,17 @@ static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods,
 }
 #endif
 
+static void ads_print_error(int ret, LDAP *ld)
+{
+	if (ret != 0) {
+		char *ld_error = NULL;
+		ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &ld_error);
+		DEBUG(10,("AD LDAP failure %d (%s):\n%s\n", ret,
+			ldap_err2string(ret), ld_error));
+		SAFE_FREE(ld_error);
+	}
+}
+
 /**
  * Perform an ldap modify
  * @param ads connection to ads server
@@ -1662,6 +1674,7 @@ ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods)
 	mods[i] = NULL;
 	ret = ldap_modify_ext_s(ads->ldap.ld, utf8_dn,
 				(LDAPMod **) mods, controls, NULL);
+	ads_print_error(ret, ads->ldap.ld);
 	TALLOC_FREE(utf8_dn);
 	return ADS_ERROR(ret);
 }
@@ -1690,6 +1703,7 @@ ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods)
 	mods[i] = NULL;
 
 	ret = ldap_add_s(ads->ldap.ld, utf8_dn, (LDAPMod**)mods);
+	ads_print_error(ret, ads->ldap.ld);
 	TALLOC_FREE(utf8_dn);
 	return ADS_ERROR(ret);
 }
@@ -1711,6 +1725,7 @@ ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
 	}
 
 	ret = ldap_delete_s(ads->ldap.ld, utf8_dn);
+	ads_print_error(ret, ads->ldap.ld);
 	TALLOC_FREE(utf8_dn);
 	return ADS_ERROR(ret);
 }
@@ -2196,8 +2211,10 @@ ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_n
  * @return 0 upon success, or non-zero otherwise
 **/
 
-ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, 
-                                   const char *org_unit)
+ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
+				   const char *machine_name,
+				   const char *org_unit,
+				   uint32_t etype_list)
 {
 	ADS_STATUS ret;
 	char *samAccountName, *controlstr;
@@ -2211,6 +2228,12 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name,
 	uint32_t acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
 	                        UF_DONT_EXPIRE_PASSWD |\
 			        UF_ACCOUNTDISABLE );
+	uint32_t func_level = 0;
+
+	ret = ads_domain_func_level(ads, &func_level);
+	if (!ADS_ERR_OK(ret)) {
+		return ret;
+	}
 
 	if (!(ctx = talloc_init("ads_add_machine_acct")))
 		return ADS_ERROR(LDAP_NO_MEMORY);
@@ -2246,6 +2269,17 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name,
 	ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
 	ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
 
+	if (func_level >= DS_DOMAIN_FUNCTION_2008) {
+		const char *etype_list_str;
+
+		etype_list_str = talloc_asprintf(ctx, "%d", (int)etype_list);
+		if (etype_list_str == NULL) {
+			goto done;
+		}
+		ads_mod_str(ctx, &mods, "msDS-SupportedEncryptionTypes",
+			    etype_list_str);
+	}
+
 	ret = ads_gen_add(ads, new_dn, mods);
 
 done:
@@ -2368,7 +2402,8 @@ static void dump_sid(ADS_STRUCT *ads, const char *field, struct berval **values)
 	for (i=0; values[i]; i++) {
 		struct dom_sid sid;
 		fstring tmp;
-		if (!sid_parse(values[i]->bv_val, values[i]->bv_len, &sid)) {
+		if (!sid_parse((const uint8_t *)values[i]->bv_val,
+			       values[i]->bv_len, &sid)) {
 			return;
 		}
 		printf("%s: %s\n", field, sid_to_fstring(tmp, &sid));
@@ -2898,7 +2933,8 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
 
 	count = 0;
 	for (i=0; values[i]; i++) {
-		ret = sid_parse(values[i]->bv_val, values[i]->bv_len, &(*sids)[count]);
+		ret = sid_parse((const uint8_t *)values[i]->bv_val,
+				values[i]->bv_len, &(*sids)[count]);
 		if (ret) {
 			DEBUG(10, ("pulling SID: %s\n",
 				   sid_string_dbg(&(*sids)[count])));
@@ -3463,7 +3499,7 @@ ADS_STATUS ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
 			return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 		}
 
-		if (!sid_parse(buf, buf_len, sid)) {
+		if (!sid_parse((const uint8_t *)buf, buf_len, sid)) {
 			DEBUG(10,("failed to parse sid\n"));
 			return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 		}
@@ -4037,10 +4073,16 @@ ADS_STATUS ads_check_ou_dn(TALLOC_CTX *mem_ctx,
 	const char *name;
 	char *ou_string;
 
-	exploded_dn = ldap_explode_dn(*account_ou, 0);
-	if (exploded_dn) {
-		ldap_value_free(exploded_dn);
-		return ADS_SUCCESS;
+	if (account_ou == NULL) {
+		return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+	}
+
+	if (*account_ou != NULL) {
+		exploded_dn = ldap_explode_dn(*account_ou, 0);
+		if (exploded_dn) {
+			ldap_value_free(exploded_dn);
+			return ADS_SUCCESS;
+		}
 	}
 
 	ou_string = ads_ou_string(ads, *account_ou);
diff --git a/source3/libads/ldap_utils.c b/source3/libads/ldap_utils.c
index 157f694..a4adbc0 100644
--- a/source3/libads/ldap_utils.c
+++ b/source3/libads/ldap_utils.c
@@ -85,7 +85,9 @@ static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind
 
 	while (--count) {
 
-		if (NT_STATUS_EQUAL(ads_ntstatus(status), NT_STATUS_IO_TIMEOUT) && ads->config.ldap_page_size >= 250) {
+		if (NT_STATUS_EQUAL(ads_ntstatus(status), NT_STATUS_IO_TIMEOUT) &&
+		    ads->config.ldap_page_size >= (lp_ldap_page_size() / 4) &&
+		    lp_ldap_page_size() > 4) {
 			int new_page_size = (ads->config.ldap_page_size / 2);
 			DEBUG(1, ("Reducing LDAP page size from %d to %d due to IO_TIMEOUT\n",
 				  ads->config.ldap_page_size, new_page_size));
diff --git a/source3/libads/ndr.c b/source3/libads/ndr.c
index fd0b63e..957c0fa 100644
--- a/source3/libads/ndr.c
+++ b/source3/libads/ndr.c
@@ -37,6 +37,7 @@ static void ndr_print_ads_auth_flags(struct ndr_print *ndr, const char *name, ui
 	ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_SASL_SIGN", ADS_AUTH_SASL_SIGN, r);
 	ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_SASL_SEAL", ADS_AUTH_SASL_SEAL, r);
 	ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_SASL_FORCE", ADS_AUTH_SASL_FORCE, r);
+	ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_USER_CREDS", ADS_AUTH_USER_CREDS, r);
 	ndr->depth--;
 }
 
@@ -50,7 +51,6 @@ void ndr_print_ads_struct(struct ndr_print *ndr, const char *name, const struct
 	ndr_print_string(ndr, "realm", r->server.realm);
 	ndr_print_string(ndr, "workgroup", r->server.workgroup);
 	ndr_print_string(ndr, "ldap_server", r->server.ldap_server);
-	ndr_print_bool(ndr, "foreign", r->server.foreign);
 	ndr->depth--;
 	ndr_print_struct(ndr, name, "auth");
 	ndr->depth++;
diff --git a/source3/libnet/libnet_dssync.c b/source3/libnet/libnet_dssync.c
index 94f0628..267709e 100644
--- a/source3/libnet/libnet_dssync.c
+++ b/source3/libnet/libnet_dssync.c
@@ -113,6 +113,7 @@ static void libnet_dssync_decrypt_attributes(TALLOC_CTX *mem_ctx,
 			drsuapi_decrypt_attribute(mem_ctx,
 						  session_key,
 						  rid,
+						  0,
 						  attr);
 		}
 	}
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 3e58b18..235592c 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -42,6 +42,7 @@
 #include "lib/param/loadparm.h"
 #include "libcli/auth/netlogon_creds_cli.h"
 #include "auth/credentials/credentials.h"
+#include "krb5_env.h"
 
 /****************************************************************
 ****************************************************************/
@@ -118,6 +119,7 @@ static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
 				     const char *dc_name,
 				     const char *user_name,
 				     const char *password,
+				     const char *ccname,
 				     ADS_STRUCT **ads)
 {
 	ADS_STATUS status;
@@ -150,6 +152,12 @@ static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
 		my_ads->auth.password = SMB_STRDUP(password);
 	}
 
+	if (ccname != NULL) {
+		SAFE_FREE(my_ads->auth.ccache_name);
+		my_ads->auth.ccache_name = SMB_STRDUP(ccname);
+		setenv(KRB5_ENV_CCNAME, my_ads->auth.ccache_name, 1);
+	}
+
 	status = ads_connect_user_creds(my_ads);
 	if (!ADS_ERR_OK(status)) {
 		ads_destroy(&my_ads);
@@ -164,15 +172,51 @@ static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
 ****************************************************************/
 
 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
-					  struct libnet_JoinCtx *r)
+					  struct libnet_JoinCtx *r,
+					  bool use_machine_creds)
 {
 	ADS_STATUS status;
+	const char *username;
+	const char *password;
+	const char *ccname = NULL;
+
+	if (use_machine_creds) {
+		if (r->in.machine_name == NULL ||
+		    r->in.machine_password == NULL) {
+			return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+		}
+		username = talloc_strdup(mem_ctx, r->in.machine_name);
+		if (username == NULL) {
+			return ADS_ERROR(LDAP_NO_MEMORY);
+		}
+		if (username[strlen(username)] != '$') {
+			username = talloc_asprintf(username, "%s$", username);
+			if (username == NULL) {
+				return ADS_ERROR(LDAP_NO_MEMORY);
+			}
+		}
+		password = r->in.machine_password;
+		ccname = "MEMORY:libnet_join_machine_creds";
+	} else {
+		username = r->in.admin_account;
+		password = r->in.admin_password;
+
+		/*
+		 * when r->in.use_kerberos is set to allow "net ads join -k" we
+		 * may not override the provided credential cache - gd
+		 */
+
+		if (!r->in.use_kerberos) {
+			ccname = "MEMORY:libnet_join_user_creds";
+		}
+	}
 
 	status = libnet_connect_ads(r->out.dns_domain_name,
 				    r->out.netbios_domain_name,
 				    r->in.dc_name,
-				    r->in.admin_account,
-				    r->in.admin_password,
+				    username,
+				    password,
+				    ccname,
 				    &r->in.ads);
 	if (!ADS_ERR_OK(status)) {
 		libnet_join_set_error_string(mem_ctx, r,
@@ -201,6 +245,24 @@ static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
 /****************************************************************
 ****************************************************************/
 
+static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
+					       struct libnet_JoinCtx *r)
+{
+	return libnet_join_connect_ads(mem_ctx, r, false);
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
+						  struct libnet_JoinCtx *r)
+{
+	return libnet_join_connect_ads(mem_ctx, r, true);
+}
+
+/****************************************************************
+****************************************************************/
+
 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
 					    struct libnet_UnjoinCtx *r)
 {
@@ -211,6 +273,7 @@ static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
 				    r->in.dc_name,
 				    r->in.admin_account,
 				    r->in.admin_password,
+				    NULL,
 				    &r->in.ads);
 	if (!ADS_ERR_OK(status)) {
 		libnet_unjoin_set_error_string(mem_ctx, r,
@@ -255,7 +318,8 @@ static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
 
 	status = ads_create_machine_acct(r->in.ads,
 					 r->in.machine_name,
-					 r->in.account_ou);
+					 r->in.account_ou,
+					 r->in.desired_encryption_types);
 
 	if (ADS_ERR_OK(status)) {
 		DEBUG(1,("machine account creation created\n"));
@@ -353,6 +417,11 @@ static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
 		goto done;
 	}
 
+	if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
+			     &r->out.set_encryption_types)) {
+		r->out.set_encryption_types = 0;
+	}
+
  done:
 	ads_msgfree(r->in.ads, res);
 	TALLOC_FREE(dn);
@@ -621,17 +690,10 @@ static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
 {
 	ADS_STATUS status;
 	ADS_MODLIST mods;
-	uint32_t etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
 	const char *etype_list_str;
 
-#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
-	etype_list |= ENC_HMAC_SHA1_96_AES128;
-#endif
-#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
-	etype_list |= ENC_HMAC_SHA1_96_AES256;
-#endif
-
-	etype_list_str = talloc_asprintf(mem_ctx, "%d", etype_list);
+	etype_list_str = talloc_asprintf(mem_ctx, "%d",
+					 r->in.desired_encryption_types);
 	if (!etype_list_str) {
 		return ADS_ERROR(LDAP_NO_MEMORY);
 	}
@@ -643,6 +705,10 @@ static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
 		return status;
 	}
 
+	if (r->in.desired_encryption_types == r->out.set_encryption_types) {
+		return ADS_SUCCESS;
+	}
+
 	/* now do the mods */
 
 	mods = ads_init_mods(mem_ctx);
@@ -656,7 +722,14 @@ static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
 		return status;
 	}
 
-	return ads_gen_mod(r->in.ads, r->out.dn, mods);
+	status = ads_gen_mod(r->in.ads, r->out.dn, mods);
+	if (!ADS_ERR_OK(status)) {
+		return status;
+	}
+
+	r->out.set_encryption_types = r->in.desired_encryption_types;
+
+	return ADS_SUCCESS;
 }
 
 /****************************************************************
@@ -736,10 +809,10 @@ static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
 						  struct libnet_JoinCtx *r)
 {
 	ADS_STATUS status;
-	uint32_t func_level = 0;
+	bool need_etype_update = false;
 
 	if (!r->in.ads) {
-		status = libnet_join_connect_ads(mem_ctx, r);
+		status = libnet_join_connect_ads_user(mem_ctx, r);
 		if (!ADS_ERR_OK(status)) {
 			return status;
 		}
@@ -771,15 +844,47 @@ static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
 		return status;
 	}
 
-	status = ads_domain_func_level(r->in.ads, &func_level);
+	status = libnet_join_find_machine_acct(mem_ctx, r);
 	if (!ADS_ERR_OK(status)) {
-		libnet_join_set_error_string(mem_ctx, r,
-			"failed to query domain controller functional level: %s",
-			ads_errstr(status));
 		return status;
 	}
 
-	if (func_level >= DS_DOMAIN_FUNCTION_2008) {
+	if (r->in.desired_encryption_types != r->out.set_encryption_types) {
+		uint32_t func_level = 0;
+
+		status = ads_domain_func_level(r->in.ads, &func_level);
+		if (!ADS_ERR_OK(status)) {
+			libnet_join_set_error_string(mem_ctx, r,
+				"failed to query domain controller functional level: %s",
+				ads_errstr(status));
+			return status;
+		}
+
+		if (func_level >= DS_DOMAIN_FUNCTION_2008) {
+			need_etype_update = true;
+		}
+	}
+
+	if (need_etype_update) {
+		/*
+		 * We need to reconnect as machine account in order
+		 * to update msDS-SupportedEncryptionTypes reliable
+		 */
+
+		if (r->in.ads->auth.ccache_name != NULL) {
+			ads_kdestroy(r->in.ads->auth.ccache_name);
+		}
+
+		ads_destroy(&r->in.ads);
+
+		status = libnet_join_connect_ads_machine(mem_ctx, r);
+		if (!ADS_ERR_OK(status)) {
+			libnet_join_set_error_string(mem_ctx, r,
+				"Failed to connect as machine account: %s",
+				ads_errstr(status));
+			return status;
+		}
+
 		status = libnet_join_set_etypes(mem_ctx, r);
 		if (!ADS_ERR_OK(status)) {
 			libnet_join_set_error_string(mem_ctx, r,
@@ -2091,6 +2196,16 @@ WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
 
 	ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
 
+	ctx->in.desired_encryption_types = ENC_CRC32 |
+					   ENC_RSA_MD5 |
+					   ENC_RC4_HMAC_MD5;
+#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+	ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
+#endif
+#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+	ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
+#endif
+
 	*r = ctx;
 
 	return WERR_OK;
@@ -2222,6 +2337,17 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
 #ifdef HAVE_ADS
 	ADS_STATUS ads_status;
 #endif /* HAVE_ADS */
+	const char *pre_connect_realm = NULL;
+	const char *numeric_dcip = NULL;
+	const char *sitename = NULL;
+
+	/* Before contacting a DC, we can securely know
+	 * the realm only if the user specifies it.
+	 */
+	if (r->in.use_kerberos &&
+	    r->in.domain_name_type == JoinDomNameTypeDNS) {
+		pre_connect_realm = r->in.domain_name;
+	}
 
 	if (!r->in.dc_name) {
 		struct netr_DsRGetDCNameInfo *info;
@@ -2254,6 +2380,47 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
 		dc = strip_hostname(info->dc_unc);
 		r->in.dc_name = talloc_strdup(mem_ctx, dc);
 		W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
+
+		if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
+		    info->dc_address[1] != '\\') {
+			DBG_ERR("ill-formed DC address '%s'\n",
+				info->dc_address);
+			return WERR_DCNOTFOUND;
+		}
+
+		numeric_dcip = info->dc_address + 2;
+		sitename = info->dc_site_name;
+		/* info goes out of scope but the memory stays
+		   allocated on the talloc context */
+	}
+
+	if (pre_connect_realm != NULL) {
+		struct sockaddr_storage ss = {0};
+
+		if (numeric_dcip != NULL) {
+			if (!interpret_string_addr(&ss, numeric_dcip,
+						   AI_NUMERICHOST)) {
+				DBG_ERR(
+				    "cannot parse IP address '%s' of DC '%s'\n",
+				    numeric_dcip, r->in.dc_name);
+				return WERR_DCNOTFOUND;
+			}
+		} else {
+			if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
+				DBG_WARNING(
+				    "cannot resolve IP address of DC '%s'\n",
+				    r->in.dc_name);
+				return WERR_DCNOTFOUND;
+			}
+		}
+
+		/* The domain parameter is only used as modifier
+		 * to krb5.conf file name. .JOIN is is not a valid
+		 * NetBIOS name so it cannot clash with another domain
+		 * -- Uri.
+		 */
+		create_local_private_krb5_conf_for_domain(
+		    pre_connect_realm, ".JOIN", sitename, &ss);
 	}
 
 	status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
@@ -2275,16 +2442,36 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
 		r->out.dns_domain_name, r->out.netbios_domain_name,
 		NULL, smbXcli_conn_remote_sockaddr(cli->conn));
 
-	if (r->out.domain_is_ad && r->in.account_ou &&
+	if (r->out.domain_is_ad &&
 	    !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
 
-		ads_status = libnet_join_connect_ads(mem_ctx, r);
+		const char *initial_account_ou = r->in.account_ou;
+
+		/*
+		 * we want to create the msDS-SupportedEncryptionTypes attribute
+		 * as early as possible so always try an LDAP create as the user
+		 * first. We copy r->in.account_ou because it may be changed
+		 * during the machine pre-creation.
+		 */
+
+		ads_status = libnet_join_connect_ads_user(mem_ctx, r);
 		if (!ADS_ERR_OK(ads_status)) {
 			return WERR_DEFAULT_JOIN_REQUIRED;
 		}
 
 		ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
-		if (!ADS_ERR_OK(ads_status)) {
+		if (ADS_ERR_OK(ads_status)) {
+
+			/*
+			 * LDAP object create succeeded, now go to the rpc
+			 * password set routines
+			 */
+
+			r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
+			goto rpc_join;
+		}
+
+		if (initial_account_ou != NULL) {
 			libnet_join_set_error_string(mem_ctx, r,
 				"failed to precreate account in ou %s: %s",
 				r->in.account_ou,
@@ -2292,10 +2479,12 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
 			return WERR_DEFAULT_JOIN_REQUIRED;
 		}
 
-		r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
+		DEBUG(5, ("failed to precreate account in ou %s: %s",
+			r->in.account_ou, ads_errstr(ads_status)));
 	}
 #endif /* HAVE_ADS */
 
+ rpc_join:
 	if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
 	    (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
 		status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index 33a32c3..9c4cce2 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -475,8 +475,17 @@ static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
 						GSS_C_NO_BUFFER);
 		}
 
-		status = NT_STATUS_LOGON_FAILURE;
-		goto done;
+		/*
+		 * If we got an output token, make Windows aware of it
+		 * by telling it that more processing is needed
+		 */
+		if (out_data.length > 0) {
+			status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+			/* Fall through to handle the out token */
+		} else {
+			status = NT_STATUS_LOGON_FAILURE;
+			goto done;
+		}
 	}
 
 	/* we may be told to return nothing */
diff --git a/source3/librpc/idl/libnet_join.idl b/source3/librpc/idl/libnet_join.idl
index 61c117e..63ea1df 100644
--- a/source3/librpc/idl/libnet_join.idl
+++ b/source3/librpc/idl/libnet_join.idl
@@ -43,6 +43,7 @@ interface libnetjoin
 		[in] boolean8 use_kerberos,
 		[in] netr_SchannelType secure_channel_type,
 		[in,noprint] messaging_context *msg_ctx,
+		[in] uint32 desired_encryption_types,
 		[out] string account_name,
 		[out] string netbios_domain_name,
 		[out] string dns_domain_name,
@@ -51,7 +52,8 @@ interface libnetjoin
 		[out] dom_sid *domain_sid,
 		[out] boolean8 modified_config,
 		[out] string error_string,
-		[out] boolean8 domain_is_ad
+		[out] boolean8 domain_is_ad,
+		[out] uint32 set_encryption_types
 		);
 
 	[nopush,nopull,noopnum] WERROR libnet_UnjoinCtx(
diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl
index 77959ce..4c6895a 100644
--- a/source3/librpc/idl/smbXsrv.idl
+++ b/source3/librpc/idl/smbXsrv.idl
@@ -79,10 +79,39 @@ interface smbXsrv
 
 	/* client */
 
+	typedef struct {
+		[ignore] db_record 			*db_rec;
+		server_id				server_id;
+		[charset(UTF8),string] char		local_address[];
+		[charset(UTF8),string] char		remote_address[];
+		[charset(UTF8),string] char		remote_name[];
+		NTTIME					initial_connect_time;
+		GUID					client_guid;
+		boolean8				stored;
+	} smbXsrv_client_global0;
+
+	typedef union {
+		[case(0)] smbXsrv_client_global0	*info0;
+		[default] hyper				*dummy;
+	} smbXsrv_client_globalU;
+
+	typedef [public] struct {
+		smbXsrv_version_values			version;
+		uint32					seqnum;
+		[switch_is(version)] smbXsrv_client_globalU info;
+	} smbXsrv_client_globalB;
+
+	void smbXsrv_client_global_decode(
+		[in] smbXsrv_client_globalB blob
+		);
+
 	typedef [public] struct {
+		[ignore] smbXsrv_client_table		*table;
 		[ignore] struct tevent_context		*ev_ctx;
 		[ignore] struct messaging_context	*msg_ctx;
 
+		[ref] smbXsrv_client_global0		*global;
+
 		/*
 		 * There's just one 'sconn' per client.
 		 * It holds the FSA layer details, which are global
@@ -112,10 +141,64 @@ interface smbXsrv
 		 * one in future.
 		 */
 		[ignore] struct smbXsrv_connection	*connections;
+		boolean8		server_multi_channel_enabled;
 	} smbXsrv_client;
 
+	typedef union {
+		[case(0)] smbXsrv_client		*info0;
+		[default] hyper				*dummy;
+	} smbXsrv_clientU;
+
+	typedef [public] struct {
+		smbXsrv_version_values			version;
+		[value(0)] uint32			reserved;
+		[switch_is(version)] smbXsrv_clientU	info;
+	} smbXsrv_clientB;
+
+	void smbXsrv_client_decode(
+		[in] smbXsrv_clientB blob
+		);
+
+	/*
+	 * smbXsrv_connection_pass is used in the MSG_SMBXSRV_CONNECTION_PASS
+	 * message
+	 */
+	typedef struct {
+		NTTIME					initial_connect_time;
+		GUID					client_guid;
+		DATA_BLOB 				negotiate_request;
+	} smbXsrv_connection_pass0;
+
+	typedef union {
+		[case(0)] smbXsrv_connection_pass0	*info0;
+		[default] hyper				*dummy;
+	} smbXsrv_connection_passU;
+
+	typedef [public] struct {
+		smbXsrv_version_values			version;
+		[value(0)] uint32			reserved;
+		[switch_is(version)] smbXsrv_connection_passU	info;
+	} smbXsrv_connection_passB;
+
+	void smbXsrv_connection_pass_decode(
+		[in] smbXsrv_connection_passB blob
+		);
+
 	/* sessions */
 
+	typedef [public,bitmap8bit] bitmap {
+		SMBXSRV_ENCRYPTION_REQUIRED		= 0x01,
+		SMBXSRV_ENCRYPTION_DESIRED		= 0x02,
+		SMBXSRV_PROCESSED_ENCRYPTED_PACKET	= 0x04,
+		SMBXSRV_PROCESSED_UNENCRYPTED_PACKET	= 0x08
+	} smbXsrv_encrpytion_flags;
+
+	typedef [public,bitmap8bit] bitmap {
+		SMBXSRV_SIGNING_REQUIRED		= 0x01,
+		SMBXSRV_PROCESSED_SIGNED_PACKET		= 0x02,
+		SMBXSRV_PROCESSED_UNSIGNED_PACKET	= 0x04
+	} smbXsrv_signing_flags;
+
 	typedef struct {
 		server_id				server_id;
 		[charset(UTF8),string] char		local_address[];
@@ -124,6 +207,7 @@ interface smbXsrv
 		[noprint] DATA_BLOB			signing_key;
 		uint32					auth_session_info_seqnum;
 		[ignore] smbXsrv_connection		*connection;
+		uint16					encryption_cipher;
 	} smbXsrv_channel_global0;
 
 	typedef struct {
@@ -140,8 +224,8 @@ interface smbXsrv
 		uint32					auth_session_info_seqnum;
 		auth_session_info			*auth_session_info;
 		uint16					connection_dialect;
-		boolean8				signing_required;
-		boolean8				encryption_required;
+		smbXsrv_signing_flags			signing_flags;
+		smbXsrv_encrpytion_flags		encryption_flags;
 		[noprint] DATA_BLOB			signing_key;
 		[noprint] DATA_BLOB			encryption_key;
 		[noprint] DATA_BLOB			decryption_key;
@@ -177,6 +261,20 @@ interface smbXsrv
 	 * smbXsrv_session for version 1
 	 * and could implement transparent mapping.
 	 */
+
+	typedef struct {
+		[ignore] smbXsrv_session_auth0		*prev;
+		smbXsrv_session_auth0			*next;
+		[ignore] smbXsrv_session		*session;
+		[ignore] smbXsrv_connection		*connection;
+		[ignore] gensec_security		*gensec;
+		[ignore] smbXsrv_preauth		*preauth;
+		uint8					in_flags;
+		uint8					in_security_mode;
+		NTTIME					creation_time;
+		NTTIME					idle_time;
+	} smbXsrv_session_auth0;
+
 	typedef struct {
 		[ignore] smbXsrv_session_table		*table;
 		[ignore] db_record 			*db_rec;
@@ -189,11 +287,9 @@ interface smbXsrv
 		hyper					nonce_high_max;
 		hyper					nonce_high;
 		hyper					nonce_low;
-		[ignore] gensec_security		*gensec;
 		[ignore] user_struct			*compat;
 		[ignore] smbXsrv_tcon_table		*tcon_table;
-		[ignore] smbXsrv_preauth		*preauth;
-		boolean8				encryption_desired;
+		smbXsrv_session_auth0			*pending_auth;
 	} smbXsrv_session;
 
 	typedef union {
@@ -246,11 +342,12 @@ interface smbXsrv
 		server_id				server_id;
 		NTTIME					creation_time;
 		[charset(UTF8),string] char		share_name[];
-		boolean8				encryption_required;
+		smbXsrv_encrpytion_flags		encryption_flags;
 		/*
 		 * for SMB1 this is the session that the tcon was opened on
 		 */
 		uint32					session_global_id;
+		smbXsrv_signing_flags                   signing_flags;
 	} smbXsrv_tcon_global0;
 
 	typedef union {
@@ -288,7 +385,6 @@ interface smbXsrv
 		NTSTATUS				status;
 		NTTIME					idle_time;
 		[ignore] connection_struct		*compat;
-		boolean8				encryption_desired;
 	} smbXsrv_tcon;
 
 	typedef union {
@@ -308,6 +404,11 @@ interface smbXsrv
 
 	/* open files */
 
+	typedef [public,bitmap8bit] bitmap {
+		SMBXSRV_OPEN_NEED_REPLAY_CACHE		= 0x01,
+		SMBXSRV_OPEN_HAVE_REPLAY_CACHE		= 0x02
+	} smbXsrv_open_flags;
+
 	typedef struct {
 		[ignore] db_record 			*db_rec;
 		server_id				server_id;
@@ -367,6 +468,8 @@ interface smbXsrv
 		NTSTATUS				status;
 		NTTIME					idle_time;
 		[ignore] files_struct			*compat;
+		smbXsrv_open_flags			flags;
+		uint32					create_action;
 	} smbXsrv_open;
 
 	typedef union {
diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c
index d3b0580..d2a4c19 100644
--- a/source3/libsmb/clidfs.c
+++ b/source3/libsmb/clidfs.c
@@ -329,7 +329,7 @@ static NTSTATUS cli_cm_connect(TALLOC_CTX *ctx,
 
 	/* Enter into the list. */
 	if (referring_cli) {
-		DLIST_ADD_END(referring_cli, cli, struct cli_state *);
+		DLIST_ADD_END(referring_cli, cli);
 	}
 
 	if (referring_cli && referring_cli->requested_posix_capabilities) {
diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c
index 907d1d2..6d5a86c 100644
--- a/source3/libsmb/clifsinfo.c
+++ b/source3/libsmb/clifsinfo.c
@@ -21,8 +21,6 @@
 
 #include "includes.h"
 #include "libsmb/libsmb.h"
-#include "../libcli/auth/spnego.h"
-#include "../auth/ntlmssp/ntlmssp.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "async_smb.h"
 #include "../libcli/smb/smb_seal.h"
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 21dc72e..875c419 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -89,7 +89,7 @@ static bool parse_user_quota_record(const uint8_t *rdata,
 	/* the hard quotas 8 bytes (uint64_t)*/
 	qt.hardlim = BVAL(rdata,32);
 
-	if (!sid_parse((const char *)rdata+40,sid_len,&qt.sid)) {
+	if (!sid_parse(rdata+40,sid_len,&qt.sid)) {
 		return false;
 	}
 
@@ -129,7 +129,7 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
 	data_len = sid_len+8;
 	SIVAL(data, 0, 0x00000000);
 	SIVAL(data, 4, sid_len);
-	sid_linearize((char *)data+8, sid_len, &pqt->sid);
+	sid_linearize(data+8, sid_len, &pqt->sid);
 
 	status = cli_trans(talloc_tos(), cli, SMBnttrans,
 			   NULL, -1, /* name, fid */
@@ -183,7 +183,7 @@ NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
 	SBIG_UINT(data,16,pqt->usedspace);
 	SBIG_UINT(data,24,pqt->softlim);
 	SBIG_UINT(data,32,pqt->hardlim);
-	sid_linearize((char *)data+40, sid_len, &pqt->sid);
+	sid_linearize(data+40, sid_len, &pqt->sid);
 
 	status = cli_trans(talloc_tos(), cli, SMBnttrans,
 			   NULL, -1, /* name, fid */
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
index f0cb7ad..3514154 100644
--- a/source3/libsmb/clireadwrite.c
+++ b/source3/libsmb/clireadwrite.c
@@ -296,7 +296,7 @@ struct cli_pull_state {
 	 * The maximum is 256:
 	 * - which would be a window of 256 MByte
 	 *   for SMB2 with multi-credit
-	 *   or smb1 unix extentions.
+	 *   or smb1 unix extensions.
 	 */
 	uint16_t max_chunks;
 	uint16_t num_chunks;
@@ -437,7 +437,7 @@ static void cli_pull_setup_chunks(struct tevent_req *req)
 		state->next_offset += chunk->total_size;
 		state->remaining -= chunk->total_size;
 
-		DLIST_ADD_END(state->chunks, chunk, NULL);
+		DLIST_ADD_END(state->chunks, chunk);
 		state->num_chunks++;
 		state->num_waiting++;
 
@@ -1111,7 +1111,7 @@ struct cli_push_state {
 	 * The maximum is 256:
 	 * - which would be a window of 256 MByte
 	 *   for SMB2 with multi-credit
-	 *   or smb1 unix extentions.
+	 *   or smb1 unix extensions.
 	 */
 	uint16_t max_chunks;
 	uint16_t num_chunks;
@@ -1250,7 +1250,7 @@ static void cli_push_setup_chunks(struct tevent_req *req)
 		}
 		state->next_offset += chunk->total_size;
 
-		DLIST_ADD_END(state->chunks, chunk, NULL);
+		DLIST_ADD_END(state->chunks, chunk);
 		state->num_chunks++;
 		state->num_waiting++;
 
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index 52c19a9..82f13b7 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -79,15 +79,23 @@ DATA_BLOB spnego_gen_negTokenInit(TALLOC_CTX *ctx,
 
 	if (!asn1_pop_tag(data)) goto err;
 
-	ret = data_blob_talloc(ctx, data->data, data->length);
+	if (!asn1_extract_blob(data, ctx, &ret)) {
+		goto err;
+	}
+
+	asn1_free(data);
+	data = NULL;
 
   err:
 
-	if (data->has_error) {
-		DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data->ofs));
-	}
+	if (data != NULL) {
+		if (asn1_has_error(data)) {
+			DEBUG(1, ("Failed to build negTokenInit at offset %d\n",
+				  (int)asn1_current_ofs(data)));
+		}
 
-	asn1_free(data);
+		asn1_free(data);
+	}
 
 	return ret;
 }
@@ -143,7 +151,7 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
 		if (!asn1_read_OID(data,ctx, &OIDs[i])) {
 			goto err;
 		}
-		if (data->has_error) {
+		if (asn1_has_error(data)) {
 			goto err;
 		}
 	}
@@ -209,11 +217,11 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
 
 	if (!asn1_end_tag(data)) goto err;
 
-	ret = !data->has_error;
+	ret = !asn1_has_error(data);
 
   err:
 
-	if (data->has_error) {
+	if (asn1_has_error(data)) {
 		int j;
 		if (principal) {
 			TALLOC_FREE(*principal);
@@ -250,15 +258,23 @@ DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const ui
 	if (!asn1_write(data, ticket.data, ticket.length)) goto err;
 	if (!asn1_pop_tag(data)) goto err;
 
-	ret = data_blob_talloc(ctx, data->data, data->length);
+	if (!asn1_extract_blob(data, ctx, &ret)) {
+		goto err;
+	}
+
+	asn1_free(data);
+	data = NULL;
 
   err:
 
-	if (data->has_error) {
-		DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs));
-	}
+	if (data != NULL) {
+		if (asn1_has_error(data)) {
+			DEBUG(1, ("Failed to build krb5 wrapper at offset %d\n",
+				  (int)asn1_current_ofs(data)));
+		}
 
-	asn1_free(data);
+		asn1_free(data);
+	}
 
 	return ret;
 }
@@ -342,11 +358,11 @@ bool spnego_parse_challenge(TALLOC_CTX *ctx, const DATA_BLOB blob,
 	if (!asn1_end_tag(data)) goto err;
 	if (!asn1_end_tag(data)) goto err;
 
-	ret = !data->has_error;
+	ret = !asn1_has_error(data);
 
   err:
 
-	if (data->has_error) {
+	if (asn1_has_error(data)) {
 		data_blob_free(chal1);
 		data_blob_free(chal2);
 	}
@@ -377,7 +393,9 @@ DATA_BLOB spnego_gen_auth(TALLOC_CTX *ctx, DATA_BLOB blob)
 	if (!asn1_pop_tag(data)) goto err;
 	if (!asn1_pop_tag(data)) goto err;
 
-	ret = data_blob_talloc(ctx, data->data, data->length);
+	if (!asn1_extract_blob(data, ctx, &ret)) {
+		goto err;
+	}
 
  err:
 
@@ -431,7 +449,7 @@ bool spnego_parse_auth_response(TALLOC_CTX *ctx,
 			if (!asn1_end_tag(data)) goto err;
 		}
 	} else if (negResult == SPNEGO_ACCEPT_INCOMPLETE) {
-		data->has_error = 1;
+		asn1_set_error(data);
 		goto err;
 	}
 
@@ -452,12 +470,13 @@ bool spnego_parse_auth_response(TALLOC_CTX *ctx,
 	if (!asn1_end_tag(data)) goto err;
 	if (!asn1_end_tag(data)) goto err;
 
-	ret = !data->has_error;
+	ret = !asn1_has_error(data);
 
   err:
 
-	if (data->has_error) {
-		DEBUG(3,("spnego_parse_auth_response failed at %d\n", (int)data->ofs));
+	if (asn1_has_error(data)) {
+		DEBUG(3, ("spnego_parse_auth_response failed at %d\n",
+			  (int)asn1_current_ofs(data)));
 		asn1_free(data);
 		data_blob_free(auth);
 		return false;
diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
index ac3bfd6..b5bc51df 100644
--- a/source3/libsmb/dsgetdcname.c
+++ b/source3/libsmb/dsgetdcname.c
@@ -44,7 +44,7 @@ static NTSTATUS make_dc_info_from_cldap_reply(TALLOC_CTX *mem_ctx,
 /****************************************************************
 ****************************************************************/
 
-void debug_dsdcinfo_flags(int lvl, uint32_t flags)
+static void debug_dsdcinfo_flags(int lvl, uint32_t flags)
 {
 	DEBUG(lvl,("debug_dsdcinfo_flags: 0x%08x\n\t", flags));
 
@@ -284,7 +284,7 @@ static uint32_t get_cldap_reply_server_flags(struct netlogon_samlogon_response *
 static bool check_cldap_reply_required_flags(uint32_t ret_flags,
 					     uint32_t req_flags)
 {
-	if (ret_flags == 0) {
+	if (req_flags == 0) {
 		return true;
 	}
 
@@ -483,10 +483,6 @@ static NTSTATUS discover_dc_netbios(TALLOC_CTX *mem_ctx,
 	*returned_dclist = NULL;
 	*returned_count = 0;
 
-	if (lp_disable_netbios()) {
-		return NT_STATUS_NOT_SUPPORTED;
-	}
-
 	if (flags & DS_PDC_REQUIRED) {
 		name_type = NBT_NAME_PDC;
 	}
@@ -547,7 +543,6 @@ static NTSTATUS discover_dc_dns(TALLOC_CTX *mem_ctx,
 	int numaddrs = 0;
 	struct ip_service_name *dclist = NULL;
 	int count = 0;
-	char *guid_string;
 
 	if (flags & DS_PDC_REQUIRED) {
 		status = ads_dns_query_pdc(mem_ctx,
@@ -573,17 +568,14 @@ static NTSTATUS discover_dc_dns(TALLOC_CTX *mem_ctx,
 					   &dcs,
 					   &numdcs);
 	} else if (domain_guid) {
-		guid_string = GUID_string(mem_ctx, domain_guid);
-		if (!guid_string) {
-			return NT_STATUS_NO_MEMORY;
-		}
+		struct GUID_txt_buf buf;
+		GUID_buf_string(domain_guid, &buf);
 
 		status = ads_dns_query_dcs_guid(mem_ctx,
 						domain_name,
-						guid_string,
+						buf.buf,
 						&dcs,
 						&numdcs);
-		TALLOC_FREE(guid_string);
 	} else {
 		status = ads_dns_query_dcs(mem_ctx,
 					   domain_name,
@@ -800,14 +792,14 @@ static NTSTATUS make_dc_info_from_cldap_reply(TALLOC_CTX *mem_ctx,
 		print_sockaddr(addr, sizeof(addr), ss);
 		dc_address = addr;
 		dc_address_type = DS_ADDRESS_TYPE_INET;
-	}
-
-	if (!ss && r->sockaddr.pdc_ip) {
-		dc_address	= r->sockaddr.pdc_ip;
-		dc_address_type	= DS_ADDRESS_TYPE_INET;
 	} else {
-		dc_address      = r->pdc_name;
-		dc_address_type = DS_ADDRESS_TYPE_NETBIOS;
+		if (r->sockaddr.pdc_ip) {
+			dc_address	= r->sockaddr.pdc_ip;
+			dc_address_type	= DS_ADDRESS_TYPE_INET;
+		} else {
+			dc_address      = r->pdc_name;
+			dc_address_type = DS_ADDRESS_TYPE_NETBIOS;
+		}
 	}
 
 	map_dc_and_domain_names(flags,
@@ -1046,6 +1038,10 @@ static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
 
 	if (flags & DS_IS_FLAT_NAME) {
 
+		if (lp_disable_netbios()) {
+			return NT_STATUS_NOT_SUPPORTED;
+		}
+
 		status = discover_dc_netbios(mem_ctx, domain_name, flags,
 					     &dclist, &num_dcs);
 		NT_STATUS_NOT_OK_RETURN(status);
@@ -1076,6 +1072,10 @@ static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
 		}
 	}
 
+	if (lp_disable_netbios()) {
+		return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+	}
+
 	status = discover_dc_netbios(mem_ctx, domain_name, flags, &dclist,
 				     &num_dcs);
 	NT_STATUS_NOT_OK_RETURN(status);
diff --git a/source3/libsmb/libsmb_printjob.c b/source3/libsmb/libsmb_printjob.c
index 62e54f4..813841a 100644
--- a/source3/libsmb/libsmb_printjob.c
+++ b/source3/libsmb/libsmb_printjob.c
@@ -125,7 +125,7 @@ SMBC_print_file_ctx(SMBCCTX *c_file,
 	}
 
 	fid1 = f_open1(c_file, fname, O_RDONLY, 0666);
-	if (fid1 < 0) {
+	if (fid1 == NULL) {
 		DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
 		TALLOC_FREE(frame);
 		return -1;  /* smbc_open sets errno */
@@ -140,7 +140,7 @@ SMBC_print_file_ctx(SMBCCTX *c_file,
 	}
 
 	fid2 = f_open_pj2(c_print, printq);
-	if (fid2 < 0) {
+	if (fid2 == NULL) {
                 saverr = errno;  /* Save errno */
                 smbc_getFunctionClose(c_file)(c_file, fid1);
                 errno = saverr;
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 7eb5dff..4709c03 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -2275,59 +2275,12 @@ fail:
 }
 
 /********************************************************
- Resolve via "lmhosts" method.
-*********************************************************/
-
-static NTSTATUS resolve_lmhosts(const char *name, int name_type,
-				struct ip_service **return_iplist,
-				int *return_count)
-{
-	/*
-	 * "lmhosts" means parse the local lmhosts file.
-	 */
-	struct sockaddr_storage *ss_list;
-	NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
-	TALLOC_CTX *ctx = NULL;
-
-	*return_iplist = NULL;
-	*return_count = 0;
-
-	DEBUG(3,("resolve_lmhosts: "
-		"Attempting lmhosts lookup for name %s<0x%x>\n",
-		name, name_type));
-
-	ctx = talloc_init("resolve_lmhosts");
-	if (!ctx) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	status = resolve_lmhosts_file_as_sockaddr(get_dyn_LMHOSTSFILE(), 
-						  name, name_type, 
-						  ctx, 
-						  &ss_list, 
-						  return_count);
-	if (NT_STATUS_IS_OK(status)) {
-		if (convert_ss2service(return_iplist, 
-				       ss_list,
-				       return_count)) {
-			talloc_free(ctx);
-			return NT_STATUS_OK;
-		} else {
-			talloc_free(ctx);
-			return NT_STATUS_NO_MEMORY;
-		}
-	}
-	talloc_free(ctx);
-	return status;
-}
-
-
-/********************************************************
  Resolve via "hosts" method.
 *********************************************************/
 
 static NTSTATUS resolve_hosts(const char *name, int name_type,
-			      struct ip_service **return_iplist,
+			      TALLOC_CTX *mem_ctx,
+			      struct sockaddr_storage **return_iplist,
 			      int *return_count)
 {
 	/*
@@ -2388,16 +2341,15 @@ static NTSTATUS resolve_hosts(const char *name, int name_type,
 
 		*return_count += 1;
 
-		*return_iplist = SMB_REALLOC_ARRAY(*return_iplist,
-						struct ip_service,
-						*return_count);
+		*return_iplist = talloc_realloc(
+			mem_ctx, *return_iplist, struct sockaddr_storage,
+			*return_count);
 		if (!*return_iplist) {
 			DEBUG(3,("resolve_hosts: malloc fail !\n"));
 			freeaddrinfo(ailist);
 			return NT_STATUS_NO_MEMORY;
 		}
-		(*return_iplist)[i].ss = ss;
-		(*return_iplist)[i].port = PORT_NONE;
+		(*return_iplist)[i] = ss;
 		i++;
 	}
 	if (ailist) {
@@ -2715,9 +2667,16 @@ NTSTATUS internal_resolve_name(const char *name,
 		tok = resolve_order[i];
 
 		if((strequal(tok, "host") || strequal(tok, "hosts"))) {
-			status = resolve_hosts(name, name_type, return_iplist,
+			struct sockaddr_storage *ss_list;
+			status = resolve_hosts(name, name_type,
+					       talloc_tos(), &ss_list,
 					       return_count);
 			if (NT_STATUS_IS_OK(status)) {
+				if (!convert_ss2service(return_iplist,
+							ss_list,
+							return_count)) {
+					status = NT_STATUS_NO_MEMORY;
+				}
 				goto done;
 			}
 		} else if(strequal( tok, "kdc")) {
@@ -2740,9 +2699,16 @@ NTSTATUS internal_resolve_name(const char *name,
 				goto done;
 			}
 		} else if (strequal(tok, "lmhosts")) {
-			status = resolve_lmhosts(name, name_type,
-						 return_iplist, return_count);
+			struct sockaddr_storage *ss_list;
+			status = resolve_lmhosts_file_as_sockaddr(
+				get_dyn_LMHOSTSFILE(), name, name_type,
+				talloc_tos(), &ss_list, return_count);
 			if (NT_STATUS_IS_OK(status)) {
+				if (!convert_ss2service(return_iplist,
+							ss_list,
+							return_count)) {
+					status = NT_STATUS_NO_MEMORY;
+				}
 				goto done;
 			}
 		} else if (strequal(tok, "wins")) {
diff --git a/source3/libsmb/pylibsmb.c b/source3/libsmb/pylibsmb.c
index 2d6853a..0c5d7e9 100644
--- a/source3/libsmb/pylibsmb.c
+++ b/source3/libsmb/pylibsmb.c
@@ -650,7 +650,7 @@ static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
 	int fnum;
 	unsigned mode = 0;
 	char *buf;
-	int buflen;
+	Py_ssize_t buflen;
 	unsigned long long offset;
 	struct tevent_req *req;
 	NTSTATUS status;
diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index 013d798..c645fbc 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -20,9 +20,10 @@
 
 #include "includes.h"
 #include "../lib/util/tevent_ntstatus.h"
+#include "lib/util_tsock.h"
 #include "lib/tsocket/tsocket.h"
 #include "libsmb/nmblib.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 
 static const char *nmbd_socket_dir(void)
 {
diff --git a/source3/locale/net/de.po b/source3/locale/net/de.po
index 4b40ef0..904052b 100644
--- a/source3/locale/net/de.po
+++ b/source3/locale/net/de.po
@@ -495,8 +495,8 @@ msgid "  Use 'net help help' to list usage information for 'net' commands."
 msgstr ""
 
 #: ../../utils/net.c:759
-msgid "Encrypt SMB transport (UNIX extended servers only)"
-msgstr "SMB Übertragung verschlüsseln (nur UNIX erweiterte Server)"
+msgid "Encrypt SMB transport"
+msgstr "SMB Übertragung verschlüsseln"
 
 #: ../../utils/net.c:827
 msgid ""
@@ -3061,8 +3061,8 @@ msgid "\t-P or --machine-pass\t\tAuthenticate as machine account\n"
 msgstr "\t-P oder --machine-pass\t\tMit Rechnerkonto authentifizieren\n"
 
 #: ../../utils/net_help_common.c:52
-msgid "\t-e or --encrypt\t\t\tEncrypt SMB transport (UNIX extended servers only)\n"
-msgstr "\t-e oder --encrypt\t\t\tSMB Übertragung verschlüsseln  (nur UNIX erweiterte Server)\n"
+msgid "\t-e or --encrypt\t\t\tEncrypt SMB transport\n"
+msgstr "\t-e oder --encrypt\t\t\tSMB Übertragung verschlüsseln\n"
 
 #: ../../utils/net_help_common.c:54
 msgid "\t-k or --kerberos\t\tUse kerberos (active directory) authentication\n"
diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c
index 9475248..26a98b7 100644
--- a/source3/modules/nfs4_acls.c
+++ b/source3/modules/nfs4_acls.c
@@ -37,23 +37,19 @@
 
 extern const struct generic_mapping file_generic_mapping;
 
-#define SMB_ACE4_INT_MAGIC 0x76F8A967
-typedef struct _SMB_ACE4_INT_T
+struct SMB4ACE_T
 {
-	uint32_t magic;
 	SMB_ACE4PROP_T	prop;
-	void	*next;
-} SMB_ACE4_INT_T;
+	struct SMB4ACE_T *next;
+};
 
-#define SMB_ACL4_INT_MAGIC 0x29A3E792
-typedef struct _SMB_ACL4_INT_T
+struct SMB4ACL_T
 {
-	uint32_t magic;
 	uint16_t controlflags;
 	uint32_t naces;
-	SMB_ACE4_INT_T	*first;
-	SMB_ACE4_INT_T	*last;
-} SMB_ACL4_INT_T;
+	struct SMB4ACE_T	*first;
+	struct SMB4ACE_T	*last;
+};
 
 enum smbacl4_mode_enum {e_simple=0, e_special=1};
 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
@@ -69,7 +65,6 @@ typedef struct _smbacl4_vfs_params {
  * Gather special parameters for NFS4 ACL handling
  */
 static int smbacl4_get_vfs_params(
-	const char *type_name,
 	struct connection_struct *conn,
 	smbacl4_vfs_params *params
 )
@@ -88,23 +83,25 @@ static int smbacl4_get_vfs_params(
 	};
 	int enumval;
 
-	memset(params, 0, sizeof(smbacl4_vfs_params));
+	ZERO_STRUCTP(params);
 
-	enumval = lp_parm_enum(SNUM(conn), type_name, "mode",
+	enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
 			       enum_smbacl4_modes, e_simple);
 	if (enumval == -1) {
-		DEBUG(10, ("value for %s:mode unknown\n", type_name));
+		DEBUG(10, ("value for %s:mode unknown\n",
+			   SMBACL4_PARAM_TYPE_NAME));
 		return -1;
 	}
 	params->mode = (enum smbacl4_mode_enum)enumval;
 
-	params->do_chown = lp_parm_bool(SNUM(conn), type_name,
+	params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
 		"chown", true);
 
-	enumval = lp_parm_enum(SNUM(conn), type_name, "acedup",
+	enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
 			       enum_smbacl4_acedups, e_dontcare);
 	if (enumval == -1) {
-		DEBUG(10, ("value for %s:acedup unknown\n", type_name));
+		DEBUG(10, ("value for %s:acedup unknown\n",
+			   SMBACL4_PARAM_TYPE_NAME));
 		return -1;
 	}
 	params->acedup = (enum smbacl4_acedup_enum)enumval;
@@ -172,140 +169,101 @@ static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
 	return nfs4_ace_flags;
 }
 
-static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
+struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
 {
-	SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
-	if (theacl==NULL)
-	{
-		DEBUG(2, ("acl is NULL\n"));
-		errno = EINVAL;
-		return NULL;
-	}
-	if (aclint->magic!=SMB_ACL4_INT_MAGIC)
-	{
-		DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
-		errno = EINVAL;
-		return NULL;
-	}
-	return aclint;
-}
-
-static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
-{
-	SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
-	if (ace==NULL)
-	{
-		DEBUG(2, ("ace is NULL\n"));
-		errno = EINVAL;
-		return NULL;
-	}
-	if (aceint->magic!=SMB_ACE4_INT_MAGIC)
-	{
-		DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
-		errno = EINVAL;
-		return NULL;
-	}
-	return aceint;
-}
+	struct SMB4ACL_T *theacl;
 
-SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
-{
-	SMB_ACL4_INT_T	*theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
-		mem_ctx, sizeof(SMB_ACL4_INT_T));
+	theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
 	if (theacl==NULL)
 	{
 		DEBUG(0, ("TALLOC_SIZE failed\n"));
 		errno = ENOMEM;
 		return NULL;
 	}
-	theacl->magic = SMB_ACL4_INT_MAGIC;
 	theacl->controlflags = SEC_DESC_SELF_RELATIVE;
 	/* theacl->first, last = NULL not needed */
-	return (SMB4ACL_T *)theacl;
+	return theacl;
 }
 
-SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
+struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
 {
-	SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
-	SMB_ACE4_INT_T *ace;
+	struct SMB4ACE_T *ace;
 
-	ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
-		theacl, sizeof(SMB_ACE4_INT_T));
+	ace = talloc_zero(acl, struct SMB4ACE_T);
 	if (ace==NULL)
 	{
 		DEBUG(0, ("TALLOC_SIZE failed\n"));
 		errno = ENOMEM;
 		return NULL;
 	}
-	ace->magic = SMB_ACE4_INT_MAGIC;
 	/* ace->next = NULL not needed */
 	memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
 
-	if (aclint->first==NULL)
+	if (acl->first==NULL)
 	{
-		aclint->first = ace;
-		aclint->last = ace;
+		acl->first = ace;
+		acl->last = ace;
 	} else {
-		aclint->last->next = (void *)ace;
-		aclint->last = ace;
+		acl->last->next = ace;
+		acl->last = ace;
 	}
-	aclint->naces++;
+	acl->naces++;
 
-	return (SMB4ACE_T *)ace;
+	return ace;
 }
 
-SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
+SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
 {
-	SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
-	if (aceint==NULL)
+	if (ace == NULL) {
 		return NULL;
+	}
 
-	return &aceint->prop;
+	return &ace->prop;
 }
 
-SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
+struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
 {
-	SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
-	if (aceint==NULL)
+	if (ace == NULL) {
 		return NULL;
+	}
 
-	return (SMB4ACE_T *)aceint->next;
+	return ace->next;
 }
 
-SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
+struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
 {
-	SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
-	if (aclint==NULL)
+	if (acl == NULL) {
 		return NULL;
+	}
 
-	return (SMB4ACE_T *)aclint->first;
+	return acl->first;
 }
 
-uint32_t smb_get_naces(SMB4ACL_T *theacl)
+uint32_t smb_get_naces(struct SMB4ACL_T *acl)
 {
-	SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
-	if (aclint==NULL)
+	if (acl == NULL) {
 		return 0;
+	}
 
-	return aclint->naces;
+	return acl->naces;
 }
 
-uint16_t smbacl4_get_controlflags(SMB4ACL_T *theacl)
+uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
 {
-	SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
-	if (aclint==NULL)
+	if (acl == NULL) {
 		return 0;
+	}
 
-	return aclint->controlflags;
+	return acl->controlflags;
 }
 
-bool smbacl4_set_controlflags(SMB4ACL_T *theacl, uint16_t controlflags)
+bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
 {
-	SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
-	if (aclint==NULL)
+	if (acl == NULL) {
 		return false;
+	}
 
-	aclint->controlflags = controlflags;
+	acl->controlflags = controlflags;
 	return true;
 }
 
@@ -313,7 +271,7 @@ static int smbacl4_GetFileOwner(struct connection_struct *conn,
 				const char *filename,
 				SMB_STRUCT_STAT *psbuf)
 {
-	memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
+	ZERO_STRUCTP(psbuf);
 
 	/* Get the stat struct for the owner info. */
 	if (vfs_stat_smb_basename(conn, filename, psbuf) != 0)
@@ -328,7 +286,7 @@ static int smbacl4_GetFileOwner(struct connection_struct *conn,
 
 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
 {
-	memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
+	ZERO_STRUCTP(psbuf);
 
 	if (fsp->fh->fd == -1) {
 		return smbacl4_GetFileOwner(fsp->conn,
@@ -346,7 +304,7 @@ static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
 
 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
 	smbacl4_vfs_params *params,
-	SMB4ACL_T *theacl, /* in */
+	struct SMB4ACL_T *acl, /* in */
 	struct dom_sid *psid_owner, /* in */
 	struct dom_sid *psid_group, /* in */
 	bool is_directory, /* in */
@@ -354,42 +312,32 @@ static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
 	int *pgood_aces /* out */
 )
 {
-	SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
-	SMB_ACE4_INT_T *aceint;
+	struct SMB4ACE_T *aceint;
 	struct security_ace *nt_ace_list = NULL;
 	int good_aces = 0;
 
 	DEBUG(10, ("%s entered\n", __func__));
 
-	aclint = get_validated_aclint(theacl);
-	/* We do not check for theacl being NULL here
-	   because this is already checked in smb_get_nt_acl_nfs4().
-	   We reserve twice the number of input aces because one nfs4
-	   ace might result in 2 nt aces.*/
-	nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
-		mem_ctx, 2 * aclint->naces * sizeof(struct security_ace));
+	nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
+					2 * acl->naces);
 	if (nt_ace_list==NULL)
 	{
-		DEBUG(10, ("talloc error with %d aces", aclint->naces));
+		DEBUG(10, ("talloc error with %d aces", acl->naces));
 		errno = ENOMEM;
 		return false;
 	}
 
-	for (aceint=aclint->first;
-	     aceint!=NULL;
-	     aceint=(SMB_ACE4_INT_T *)aceint->next) {
+	for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
 		uint32_t mask;
 		struct dom_sid sid;
 		SMB_ACE4PROP_T	*ace = &aceint->prop;
 		uint32_t win_ace_flags;
 
-		DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
+		DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
 			   "mask: %x, who: %d\n",
-			   aceint->magic, ace->aceType, ace->flags,
+			   ace->aceType, ace->flags,
 			   ace->aceFlags, ace->aceMask, ace->who.id));
 
-		SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
-
 		if (ace->flags & SMB_ACE4_ID_SPECIAL) {
 			switch (ace->who.special_id) {
 			case SMB_ACE4_WHO_OWNER:
@@ -507,9 +455,9 @@ static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	nt_ace_list = (struct security_ace *)
-		TALLOC_REALLOC(mem_ctx, nt_ace_list,
-				       good_aces * sizeof(struct security_ace));
+	nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
+				     good_aces);
+
 	/* returns a NULL ace list when good_aces is zero. */
 	if (good_aces && nt_ace_list == NULL) {
 		DEBUG(10, ("realloc error with %d aces", good_aces));
@@ -528,7 +476,7 @@ static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
 					   uint32_t security_info,
 					   TALLOC_CTX *mem_ctx,
 					   struct security_descriptor **ppdesc,
-					   SMB4ACL_T *theacl)
+					   struct SMB4ACL_T *theacl)
 {
 	int good_aces = 0;
 	struct dom_sid sid_owner, sid_group;
@@ -536,6 +484,7 @@ static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
 	struct security_ace *nt_ace_list = NULL;
 	struct security_acl *psa = NULL;
 	TALLOC_CTX *frame = talloc_stackframe();
+	bool ok;
 
 	if (theacl==NULL) {
 		TALLOC_FREE(frame);
@@ -547,9 +496,10 @@ static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
 	uid_to_sid(&sid_owner, sbuf->st_ex_uid);
 	gid_to_sid(&sid_group, sbuf->st_ex_gid);
 
-	if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
-			     S_ISDIR(sbuf->st_ex_mode),
-			     &nt_ace_list, &good_aces)==false) {
+	ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
+			      S_ISDIR(sbuf->st_ex_mode),
+			      &nt_ace_list, &good_aces);
+	if (!ok) {
 		DEBUG(8,("smbacl4_nfs42win failed\n"));
 		TALLOC_FREE(frame);
 		return map_nt_error_from_unix(errno);
@@ -586,7 +536,7 @@ NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
 			      uint32_t security_info,
 			      TALLOC_CTX *mem_ctx,
 			      struct security_descriptor **ppdesc,
-			      SMB4ACL_T *theacl)
+			      struct SMB4ACL_T *theacl)
 {
 	SMB_STRUCT_STAT sbuf;
 	smbacl4_vfs_params params;
@@ -598,7 +548,7 @@ NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
 	}
 
 	/* Special behaviours */
-	if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, &params)) {
+	if (smbacl4_get_vfs_params(fsp->conn, &params)) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
@@ -611,7 +561,7 @@ NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
 			     uint32_t security_info,
 			     TALLOC_CTX *mem_ctx,
 			     struct security_descriptor **ppdesc,
-			     SMB4ACL_T *theacl)
+			     struct SMB4ACL_T *theacl)
 {
 	SMB_STRUCT_STAT sbuf;
 	smbacl4_vfs_params params;
@@ -623,7 +573,7 @@ NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
 	}
 
 	/* Special behaviours */
-	if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, &params)) {
+	if (smbacl4_get_vfs_params(conn, &params)) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
@@ -631,16 +581,13 @@ NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
 					  mem_ctx, ppdesc, theacl);
 }
 
-static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
+static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
 {
-	SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
-	SMB_ACE4_INT_T *aceint;
+	struct SMB4ACE_T *aceint;
 
-	DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
+	DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
 
-	for (aceint = aclint->first;
-	     aceint!=NULL;
-	     aceint=(SMB_ACE4_INT_T *)aceint->next) {
+	for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
 		SMB_ACE4PROP_T *ace = &aceint->prop;
 
 		DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
@@ -658,14 +605,12 @@ static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
  * return ace if found matching; otherwise NULL
  */
 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
-	SMB4ACL_T *theacl,
+	struct SMB4ACL_T *acl,
 	SMB_ACE4PROP_T *aceNew)
 {
-	SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
-	SMB_ACE4_INT_T *aceint;
+	struct SMB4ACE_T *aceint;
 
-	for (aceint = aclint->first; aceint != NULL;
-	     aceint=(SMB_ACE4_INT_T *)aceint->next) {
+	for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
 		SMB_ACE4PROP_T *ace = &aceint->prop;
 
 		DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
@@ -711,7 +656,7 @@ static bool smbacl4_fill_ace4(
 {
 	DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
 
-	memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
+	ZERO_STRUCTP(ace_v4);
 
 	/* only ACCESS|DENY supported right now */
 	ace_v4->aceType = ace_nt->type;
@@ -795,7 +740,7 @@ static bool smbacl4_fill_ace4(
 
 static int smbacl4_MergeIgnoreReject(
 	enum smbacl4_acedup_enum acedup,
-	SMB4ACL_T *theacl, /* may modify it */
+	struct SMB4ACL_T *theacl, /* may modify it */
 	SMB_ACE4PROP_T *ace, /* the "new" ACE */
 	bool	*paddNewACE,
 	int	i
@@ -828,15 +773,14 @@ static int smbacl4_MergeIgnoreReject(
 }
 
 static int smbacl4_substitute_special(
-	SMB4ACL_T *theacl,
+	struct SMB4ACL_T *acl,
 	uid_t ownerUID,
 	gid_t ownerGID
 )
 {
-	SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
-	SMB_ACE4_INT_T *aceint;
+	struct SMB4ACE_T *aceint;
 
-	for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
+	for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
 		SMB_ACE4PROP_T *ace = &aceint->prop;
 
 		DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
@@ -864,15 +808,14 @@ static int smbacl4_substitute_special(
 }
 
 static int smbacl4_substitute_simple(
-	SMB4ACL_T *theacl,
+	struct SMB4ACL_T *acl,
 	uid_t ownerUID,
 	gid_t ownerGID
 )
 {
-	SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
-	SMB_ACE4_INT_T *aceint;
+	struct SMB4ACE_T *aceint;
 
-	for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
+	for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
 		SMB_ACE4PROP_T *ace = &aceint->prop;
 
 		DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
@@ -905,7 +848,7 @@ static int smbacl4_substitute_simple(
 	return true; /* OK */
 }
 
-static SMB4ACL_T *smbacl4_win2nfs4(
+static struct SMB4ACL_T *smbacl4_win2nfs4(
 	TALLOC_CTX *mem_ctx,
 	const files_struct *fsp,
 	const struct security_acl *dacl,
@@ -914,7 +857,7 @@ static SMB4ACL_T *smbacl4_win2nfs4(
 	gid_t ownerGID
 )
 {
-	SMB4ACL_T *theacl;
+	struct SMB4ACL_T *theacl;
 	uint32_t i;
 	const char *filename = fsp->fsp_name->base_name;
 
@@ -964,7 +907,7 @@ NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
 	set_nfs4acl_native_fn_t set_nfs4_native)
 {
 	smbacl4_vfs_params params;
-	SMB4ACL_T *theacl = NULL;
+	struct SMB4ACL_T *theacl = NULL;
 	bool	result;
 
 	SMB_STRUCT_STAT sbuf;
@@ -987,8 +930,7 @@ NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
 	}
 
 	/* Special behaviours */
-	if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
-				   fsp->conn, &params)) {
+	if (smbacl4_get_vfs_params(fsp->conn, &params)) {
 		TALLOC_FREE(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
diff --git a/source3/modules/nfs4_acls.h b/source3/modules/nfs4_acls.h
index 1922010..e11845e 100644
--- a/source3/modules/nfs4_acls.h
+++ b/source3/modules/nfs4_acls.h
@@ -107,47 +107,45 @@ typedef struct _SMB_ACE4PROP_T {
 | SMB_ACE4_WRITE_ACL | SMB_ACE4_WRITE_OWNER | SMB_ACE4_SYNCHRONIZE )
 } SMB_ACE4PROP_T;
 
-/*
- * Never allocate these structures on your own
- * use create_smb4acl instead
- */
-typedef struct _SMB4ACL_T {char dontuse;} SMB4ACL_T;
-typedef struct _SMB4ACE_T {char dontuse;} SMB4ACE_T;
+struct SMB4ACL_T;
+struct SMB4ACE_T;
 
-SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx);
+struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx);
 
 /* prop's contents are copied */
 /* it doesn't change the order, appends */
-SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop);
+struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop);
 
-SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace);
+SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace);
 
 /* Returns NULL if none - or error */
-SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl);
+struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *theacl);
 
 /* Returns NULL in the end - or error */
-SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace);
+struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace);
 
-uint32_t smb_get_naces(SMB4ACL_T *theacl);
+uint32_t smb_get_naces(struct SMB4ACL_T *theacl);
 
-uint16_t smbacl4_get_controlflags(SMB4ACL_T *theacl);
+uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *theacl);
 
-bool smbacl4_set_controlflags(SMB4ACL_T *theacl, uint16_t controlflags);
+bool smbacl4_set_controlflags(struct SMB4ACL_T *theacl, uint16_t controlflags);
 
 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
 	uint32_t security_info,
 	TALLOC_CTX *mem_ctx,
-	struct security_descriptor **ppdesc, SMB4ACL_T *theacl);
+	struct security_descriptor **ppdesc, struct SMB4ACL_T *theacl);
 
 NTSTATUS smb_get_nt_acl_nfs4(connection_struct *conn,
 	const char *name,
 	uint32_t security_info,
 	TALLOC_CTX *mem_ctx,
-	struct security_descriptor **ppdesc, SMB4ACL_T *theacl);
+	struct security_descriptor **ppdesc, struct SMB4ACL_T *theacl);
 
 /* Callback function needed to set the native acl
  * when applicable */
-typedef bool (*set_nfs4acl_native_fn_t)(vfs_handle_struct *handle, files_struct *, SMB4ACL_T *);
+typedef bool (*set_nfs4acl_native_fn_t)(vfs_handle_struct *handle,
+					files_struct *,
+					struct SMB4ACL_T *);
 
 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
 	uint32_t security_info_sent,
diff --git a/source3/modules/perfcount_test.c b/source3/modules/perfcount_test.c
index 0dc073c..ccc74dd 100644
--- a/source3/modules/perfcount_test.c
+++ b/source3/modules/perfcount_test.c
@@ -385,6 +385,7 @@ static struct smb_perfcount_handlers perfcount_test_handlers = {
 	perfcount_test_end
 };
 
+static_decl_perfcount;
 NTSTATUS perfcount_test_init(void)
 {
 	return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION,
diff --git a/source3/modules/vfs_acl_tdb.c b/source3/modules/vfs_acl_tdb.c
index 1537ba3..62559a2 100644
--- a/source3/modules/vfs_acl_tdb.c
+++ b/source3/modules/vfs_acl_tdb.c
@@ -23,7 +23,7 @@
 #include "system/filesys.h"
 #include "librpc/gen_ndr/xattr.h"
 #include "librpc/gen_ndr/ndr_xattr.h"
-#include "../lib/crypto/crypto.h"
+#include "../lib/crypto/sha256.h"
 #include "dbwrap/dbwrap.h"
 #include "dbwrap/dbwrap_open.h"
 #include "auth.h"
@@ -403,6 +403,7 @@ static struct vfs_fn_pointers vfs_acl_tdb_fns = {
 	.sys_acl_set_fd_fn = sys_acl_set_fd_tdb
 };
 
+static_decl_vfs;
 NTSTATUS vfs_acl_tdb_init(void)
 {
 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_tdb",
diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c
index c1b0a60..2338798 100644
--- a/source3/modules/vfs_acl_xattr.c
+++ b/source3/modules/vfs_acl_xattr.c
@@ -22,7 +22,7 @@
 #include "smbd/smbd.h"
 #include "librpc/gen_ndr/xattr.h"
 #include "librpc/gen_ndr/ndr_xattr.h"
-#include "../lib/crypto/crypto.h"
+#include "../lib/crypto/sha256.h"
 #include "auth.h"
 
 #undef DBGC_CLASS
@@ -214,6 +214,7 @@ static struct vfs_fn_pointers vfs_acl_xattr_fns = {
 	.sys_acl_set_fd_fn = sys_acl_set_fd_xattr
 };
 
+static_decl_vfs;
 NTSTATUS vfs_acl_xattr_init(void)
 {
 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_xattr",
diff --git a/source3/modules/vfs_aio_fork.c b/source3/modules/vfs_aio_fork.c
index 5b398b2e..472ef0c 100644
--- a/source3/modules/vfs_aio_fork.c
+++ b/source3/modules/vfs_aio_fork.c
@@ -26,8 +26,8 @@
 #include "smbd/globals.h"
 #include "lib/async_req/async_sock.h"
 #include "lib/util/tevent_unix.h"
-#include "lib/sys_rw.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/sys_rw_data.h"
 #include "lib/msghdr.h"
 
 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && !defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
@@ -899,17 +899,6 @@ static int aio_fork_connect(vfs_handle_struct *handle, const char *service,
 				NULL, struct aio_fork_config,
 				return -1);
 
-	/*********************************************************************
-	 * How many threads to initialize ?
-	 * 100 per process seems insane as a default until you realize that
-	 * (a) Threads terminate after 1 second when idle.
-	 * (b) Throttling is done in SMB2 via the crediting algorithm.
-	 * (c) SMB1 clients are limited to max_mux (50) outstanding
-	 *     requests and Windows clients don't use this anyway.
-	 * Essentially we want this to be unlimited unless smb.conf
-	 * says different.
-	 *********************************************************************/
-	aio_pending_size = 100;
 	return 0;
 }
 
diff --git a/source3/modules/vfs_aio_linux.c b/source3/modules/vfs_aio_linux.c
index 5b515d8..4f6230a 100644
--- a/source3/modules/vfs_aio_linux.c
+++ b/source3/modules/vfs_aio_linux.c
@@ -24,7 +24,7 @@
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
 #include "lib/util/tevent_unix.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 #include <sys/eventfd.h>
 #include <libaio.h>
 
@@ -113,12 +113,12 @@ static bool init_aio_linux(struct vfs_handle_struct *handle)
 		goto fail;
 	}
 
-	if (io_queue_init(aio_pending_size, &io_ctx)) {
+	if (io_queue_init(lp_aio_max_threads(), &io_ctx)) {
 		goto fail;
 	}
 
 	DEBUG(10,("init_aio_linux: initialized with up to %d events\n",
-		  aio_pending_size));
+		  (int)lp_aio_max_threads()));
 
 	return true;
 
@@ -321,25 +321,7 @@ static int aio_linux_int_recv(struct tevent_req *req, int *err)
 	return aio_linux_recv(req, err);
 }
 
-static int aio_linux_connect(vfs_handle_struct *handle, const char *service,
-			       const char *user)
-{
-	/*********************************************************************
-	 * How many io_events to initialize ?
-	 * 128 per process seems insane as a default until you realize that
-	 * (a) Throttling is done in SMB2 via the crediting algorithm.
-	 * (b) SMB1 clients are limited to max_mux (50) outstanding
-	 *     requests and Windows clients don't use this anyway.
-	 * Essentially we want this to be unlimited unless smb.conf
-	 * says different.
-	 *********************************************************************/
-	aio_pending_size = lp_parm_int(
-		SNUM(handle->conn), "aio_linux", "aio num events", 128);
-	return SMB_VFS_NEXT_CONNECT(handle, service, user);
-}
-
 static struct vfs_fn_pointers vfs_aio_linux_fns = {
-	.connect_fn = aio_linux_connect,
 	.pread_send_fn = aio_linux_pread_send,
 	.pread_recv_fn = aio_linux_recv,
 	.pwrite_send_fn = aio_linux_pwrite_send,
@@ -348,6 +330,7 @@ static struct vfs_fn_pointers vfs_aio_linux_fns = {
 	.fsync_recv_fn = aio_linux_int_recv,
 };
 
+static_decl_vfs;
 NTSTATUS vfs_aio_linux_init(void)
 {
 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
diff --git a/source3/modules/vfs_aio_posix.c b/source3/modules/vfs_aio_posix.c
deleted file mode 100644
index ef5f706..0000000
--- a/source3/modules/vfs_aio_posix.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Simulate pread_send/recv and pwrite_send/recv using posix aio
- *
- * Copyright (C) Volker Lendecke 2012
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "includes.h"
-#include "system/filesys.h"
-#include "system/shmem.h"
-#include "smbd/smbd.h"
-#include "smbd/globals.h"
-#include "lib/util/tevent_unix.h"
-#include "lib/sys_rw.h"
-#include <aio.h>
-
-/* The signal we'll use to signify aio done. */
-#ifndef RT_SIGNAL_AIO
-#define RT_SIGNAL_AIO	(SIGRTMIN+3)
-#endif
-
-#ifndef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIVAL_PTR
-#ifdef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIGVAL_PTR
-#define sival_int	sigval_int
-#define sival_ptr	sigval_ptr
-#endif
-#endif
-
-static struct tevent_signal *aio_signal_event = NULL;
-
-struct aio_posix_state {
-	struct aiocb acb;
-	ssize_t ret;
-	int err;
-};
-
-static int aio_posix_state_destructor(struct aio_posix_state *s)
-{
-	int ret;
-
-	/*
-	 * We could do better here. This destructor is run when a
-	 * request is prematurely cancelled. We wait for the aio to
-	 * complete, so that we do not have to maintain aiocb structs
-	 * beyond the life of an aio_posix_state. Possible, but not
-	 * sure the effort is worth it right now.
-	 */
-
-	do {
-		const struct aiocb *a = &s->acb;
-		ret = aio_suspend(&a, 1, NULL);
-	} while ((ret == -1) && (errno == EINTR));
-
-	return 0;
-}
-
-static struct tevent_req *aio_posix_pread_send(
-	struct vfs_handle_struct *handle,
-	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-	struct files_struct *fsp, void *data, size_t n, off_t offset)
-{
-	struct tevent_req *req;
-	struct aio_posix_state *state;
-	struct aiocb *a;
-	int ret;
-
-	req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	a = &state->acb;
-
-	a->aio_fildes = fsp->fh->fd;
-	a->aio_buf = data;
-	a->aio_nbytes = n;
-	a->aio_offset = offset;
-	a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
-	a->aio_sigevent.sigev_signo  = RT_SIGNAL_AIO;
-	a->aio_sigevent.sigev_value.sival_ptr = req;
-
-	ret = aio_read(a);
-	if (ret == 0) {
-		talloc_set_destructor(state, aio_posix_state_destructor);
-		return req;
-	}
-
-	if (errno == EAGAIN) {
-		/*
-		 * aio overloaded, do the sync fallback
-		 */
-		state->ret = sys_pread(fsp->fh->fd, data, n, offset);
-		if (state->ret == -1) {
-			state->err = errno;
-		}
-		tevent_req_done(req);
-		return tevent_req_post(req, ev);
-	}
-
-	tevent_req_error(req, errno);
-	return tevent_req_post(req, ev);
-}
-
-static struct tevent_req *aio_posix_pwrite_send(
-	struct vfs_handle_struct *handle,
-	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-	struct files_struct *fsp, const void *data, size_t n, off_t offset)
-{
-	struct tevent_req *req;
-	struct aio_posix_state *state;
-	struct aiocb *a;
-	int ret;
-
-	req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	a = &state->acb;
-
-	a->aio_fildes = fsp->fh->fd;
-	a->aio_buf = discard_const(data);
-	a->aio_nbytes = n;
-	a->aio_offset = offset;
-	a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
-	a->aio_sigevent.sigev_signo  = RT_SIGNAL_AIO;
-	a->aio_sigevent.sigev_value.sival_ptr = req;
-
-	ret = aio_write(a);
-	if (ret == 0) {
-		talloc_set_destructor(state, aio_posix_state_destructor);
-		return req;
-	}
-
-	if (errno == EAGAIN) {
-		/*
-		 * aio overloaded, do the sync fallback
-		 */
-		state->ret = sys_pwrite(fsp->fh->fd, data, n, offset);
-		if (state->ret == -1) {
-			state->err = errno;
-		}
-		tevent_req_done(req);
-		return tevent_req_post(req, ev);
-	}
-
-	tevent_req_error(req, errno);
-	return tevent_req_post(req, ev);
-}
-
-static void aio_posix_signal_handler(struct tevent_context *ev,
-				     struct tevent_signal *se,
-				     int signum, int count,
-				     void *_info, void *private_data)
-{
-	siginfo_t *info;
-	struct tevent_req *req;
-	struct aio_posix_state *state;
-	int err;
-
-	info = (siginfo_t *)_info;
-	req = talloc_get_type_abort(info->si_value.sival_ptr,
-				    struct tevent_req);
-	state = tevent_req_data(req, struct aio_posix_state);
-
-	err = aio_error(&state->acb);
-	if (err == EINPROGRESS) {
-		DEBUG(10, ("aio_posix_signal_handler: operation req %p "
-			   "still in progress\n", req));
-		return;
-	}
-	if (err == ECANCELED) {
-		DEBUG(10, ("aio_posix_signal_handler: operation req %p "
-			   "canceled\n", req));
-		return;
-	}
-
-	/*
-	 * No need to suspend for this in the destructor anymore
-	 */
-	talloc_set_destructor(state, NULL);
-
-	state->ret = aio_return(&state->acb);
-	state->err = err;
-	tevent_req_done(req);
-}
-
-static ssize_t aio_posix_recv(struct tevent_req *req, int *err)
-{
-	struct aio_posix_state *state = tevent_req_data(
-		req, struct aio_posix_state);
-
-	if (tevent_req_is_unix_error(req, err)) {
-		return -1;
-	}
-	*err = state->err;
-	return state->ret;
-}
-
-static struct tevent_req *aio_posix_fsync_send(
-	struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
-	struct tevent_context *ev, struct files_struct *fsp)
-{
-	struct tevent_req *req;
-	struct aio_posix_state *state;
-	struct aiocb *a;
-	int ret;
-
-	req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	a = &state->acb;
-
-	a->aio_fildes = fsp->fh->fd;
-	a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
-	a->aio_sigevent.sigev_signo  = RT_SIGNAL_AIO;
-	a->aio_sigevent.sigev_value.sival_ptr = req;
-
-	ret = aio_fsync(O_SYNC, a);
-	if (ret == 0) {
-		talloc_set_destructor(state, aio_posix_state_destructor);
-		return req;
-	}
-
-	if (errno == EAGAIN) {
-		/*
-		 * aio overloaded, do the sync fallback
-		 */
-		state->ret = fsync(fsp->fh->fd);
-		if (state->ret == -1) {
-			state->err = errno;
-		}
-		tevent_req_done(req);
-		return tevent_req_post(req, ev);
-	}
-
-	tevent_req_error(req, errno);
-	return tevent_req_post(req, ev);
-}
-
-static int aio_posix_int_recv(struct tevent_req *req, int *err)
-{
-	struct aio_posix_state *state = tevent_req_data(
-		req, struct aio_posix_state);
-
-	if (tevent_req_is_unix_error(req, err)) {
-		return -1;
-	}
-	*err = state->err;
-	return state->ret;
-}
-
-static int aio_posix_connect(vfs_handle_struct *handle, const char *service,
-			     const char *user)
-{
-	if (aio_signal_event == NULL) {
-		struct tevent_context *ev = handle->conn->sconn->ev_ctx;
-
-		aio_signal_event = tevent_add_signal(
-			ev, ev, RT_SIGNAL_AIO, SA_SIGINFO,
-			aio_posix_signal_handler, NULL);
-
-		if (aio_signal_event == NULL) {
-			DEBUG(1, ("tevent_add_signal failed\n"));
-			return -1;
-		}
-	}
-	return SMB_VFS_NEXT_CONNECT(handle, service, user);
-}
-
-static struct vfs_fn_pointers vfs_aio_posix_fns = {
-	.connect_fn = aio_posix_connect,
-	.pread_send_fn = aio_posix_pread_send,
-	.pread_recv_fn = aio_posix_recv,
-	.pwrite_send_fn = aio_posix_pwrite_send,
-	.pwrite_recv_fn = aio_posix_recv,
-	.fsync_send_fn = aio_posix_fsync_send,
-	.fsync_recv_fn = aio_posix_int_recv,
-};
-
-NTSTATUS vfs_aio_posix_init(void);
-NTSTATUS vfs_aio_posix_init(void)
-{
-	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
-				"aio_posix", &vfs_aio_posix_fns);
-}
diff --git a/source3/modules/vfs_aio_pthread.c b/source3/modules/vfs_aio_pthread.c
index 059d745..7037b63 100644
--- a/source3/modules/vfs_aio_pthread.c
+++ b/source3/modules/vfs_aio_pthread.c
@@ -51,7 +51,7 @@ static bool init_aio_threadpool(struct tevent_context *ev_ctx,
 		return true;
 	}
 
-	ret = pthreadpool_init(aio_pending_size, pp_pool);
+	ret = pthreadpool_init(lp_aio_max_threads(), pp_pool);
 	if (ret) {
 		errno = ret;
 		return false;
@@ -69,7 +69,7 @@ static bool init_aio_threadpool(struct tevent_context *ev_ctx,
 	}
 
 	DEBUG(10,("init_aio_threadpool: initialized with up to %d threads\n",
-		  aio_pending_size));
+		  (int)lp_aio_max_threads()));
 
 	return true;
 }
@@ -341,7 +341,7 @@ static struct aio_open_private_data *create_private_open_data(const files_struct
 	}
 
 	talloc_set_destructor(opd, opd_destructor);
-	DLIST_ADD_END(open_pd_list, opd, struct aio_open_private_data *);
+	DLIST_ADD_END(open_pd_list, opd);
 	return opd;
 }
 
diff --git a/source3/modules/vfs_aixacl2.c b/source3/modules/vfs_aixacl2.c
index 557f950..a70013d 100644
--- a/source3/modules/vfs_aixacl2.c
+++ b/source3/modules/vfs_aixacl2.c
@@ -94,7 +94,7 @@ static AIXJFS2_ACL_T *aixjfs2_getacl_alloc(const char *fname, acl_type_t *type)
 }
 
 static bool aixjfs2_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *name,
-	SMB4ACL_T **ppacl, bool *pretryPosix)
+	struct SMB4ACL_T **ppacl, bool *pretryPosix)
 {
 	int32_t i;
 	
@@ -159,7 +159,7 @@ static NTSTATUS aixjfs2_fget_nt_acl(vfs_handle_struct *handle,
 	struct security_descriptor **ppdesc)
 {
 	NTSTATUS status;
-	SMB4ACL_T *pacl = NULL;
+	struct SMB4ACL_T *pacl = NULL;
 	bool	result;
 	bool	retryPosix = False;
 	TALLOC_CTX *frame = talloc_stackframe();
@@ -191,7 +191,7 @@ static NTSTATUS aixjfs2_get_nt_acl(vfs_handle_struct *handle,
 	TALLOC_CTX *mem_ctx,
 	struct security_descriptor **ppdesc)
 {
-	SMB4ACL_T *pacl = NULL;
+	struct SMB4ACL_T *pacl = NULL;
 	bool	result;
 	bool	retryPosix = False;
 
@@ -213,7 +213,7 @@ static NTSTATUS aixjfs2_get_nt_acl(vfs_handle_struct *handle,
 
 static int aixjfs2_sys_acl_blob_get_file(vfs_handle_struct *handle, const char *path_p, TALLOC_CTX *mem_ctx, char **blob_description, DATA_BLOB *blob)
 {
-	SMB4ACL_T *pacl = NULL;
+	struct SMB4ACL_T *pacl = NULL;
 	bool	result;
 	bool	retryPosix = False;
 
@@ -230,7 +230,7 @@ static int aixjfs2_sys_acl_blob_get_file(vfs_handle_struct *handle, const char *
 
 static int aixjfs2_sys_acl_blob_get_fd(vfs_handle_struct *handle, files_struct *fsp, TALLOC_CTX *mem_ctx, char **blob_description, DATA_BLOB *blob)
 {
-	SMB4ACL_T *pacl = NULL;
+	struct SMB4ACL_T *pacl = NULL;
 	bool	result;
 	bool	retryPosix = False;
 
@@ -345,9 +345,11 @@ static int aixjfs2_query_acl_support(
 	return 1; /* haven't found that ACL type. */
 }
 
-static bool aixjfs2_process_smbacl(vfs_handle_struct *handle, files_struct *fsp, SMB4ACL_T *smbacl)
+static bool aixjfs2_process_smbacl(vfs_handle_struct *handle,
+				   files_struct *fsp,
+				   struct SMB4ACL_T *smbacl)
 {
-	SMB4ACE_T	*smbace;
+	struct SMB4ACE_T *smbace;
 	TALLOC_CTX	*mem_ctx;
 	nfs4_acl_int_t	*jfs2acl;
 	int32_t		entryLen;
diff --git a/source3/modules/vfs_audit.c b/source3/modules/vfs_audit.c
index 6963c37..02e8f35 100644
--- a/source3/modules/vfs_audit.c
+++ b/source3/modules/vfs_audit.c
@@ -283,6 +283,7 @@ static struct vfs_fn_pointers vfs_audit_fns = {
 	.fchmod_acl_fn = audit_fchmod_acl
 };
 
+static_decl_vfs;
 NTSTATUS vfs_audit_init(void)
 {
 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "audit",
diff --git a/source3/modules/vfs_cacheprime.c b/source3/modules/vfs_cacheprime.c
index e90e09a..cb8b328 100644
--- a/source3/modules/vfs_cacheprime.c
+++ b/source3/modules/vfs_cacheprime.c
@@ -17,7 +17,7 @@
 
 #include "includes.h"
 #include "smbd/smbd.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 
 /* Cache priming module.
  *
diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c
index b5a1906..65b0b25 100644
--- a/source3/modules/vfs_cap.c
+++ b/source3/modules/vfs_cap.c
@@ -41,6 +41,19 @@ static uint64_t cap_disk_free(vfs_handle_struct *handle, const char *path,
 	return SMB_VFS_NEXT_DISK_FREE(handle, cappath, bsize, dfree, dsize);
 }
 
+static int cap_get_quota(vfs_handle_struct *handle, const char *path,
+			 enum SMB_QUOTA_TYPE qtype, unid_t id,
+			 SMB_DISK_QUOTA *dq)
+{
+	char *cappath = capencode(talloc_tos(), path);
+
+	if (!cappath) {
+		errno = ENOMEM;
+		return -1;
+	}
+	return SMB_VFS_NEXT_GET_QUOTA(handle, cappath, qtype, id, dq);
+}
+
 static DIR *cap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32_t attr)
 {
 	char *capname = capencode(talloc_tos(), fname);
@@ -73,13 +86,12 @@ static struct dirent *cap_readdir(vfs_handle_struct *handle,
 	}
 	DEBUG(3,("cap: cap_readdir: %s\n", newname));
 	newnamelen = strlen(newname)+1;
-	newdirent = (struct dirent *)talloc_array(talloc_tos(),
-			char,
-			sizeof(struct dirent)+
-				newnamelen);
+	newdirent = talloc_size(
+		talloc_tos(), sizeof(struct dirent) + newnamelen);
 	if (!newdirent) {
 		return NULL;
 	}
+	talloc_set_name_const(newdirent, "struct dirent");
 	memcpy(newdirent, result, sizeof(struct dirent));
 	memcpy(&newdirent->d_name, newname, newnamelen);
 	return newdirent;
@@ -517,6 +529,7 @@ static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, co
 
 static struct vfs_fn_pointers vfs_cap_fns = {
 	.disk_free_fn = cap_disk_free,
+	.get_quota_fn = cap_get_quota,
 	.opendir_fn = cap_opendir,
 	.readdir_fn = cap_readdir,
 	.mkdir_fn = cap_mkdir,
diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c
index f455afd..c17ffa8 100644
--- a/source3/modules/vfs_catia.c
+++ b/source3/modules/vfs_catia.c
@@ -1005,6 +1005,7 @@ static struct vfs_fn_pointers vfs_catia_fns = {
 	.setxattr_fn = catia_setxattr,
 };
 
+static_decl_vfs;
 NTSTATUS vfs_catia_init(void)
 {
 	NTSTATUS ret;
diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c
index 0113faa..d51499d 100644
--- a/source3/modules/vfs_ceph.c
+++ b/source3/modules/vfs_ceph.c
@@ -175,7 +175,6 @@ static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,
 		*bsize = statvfs_buf.f_bsize;
 		*dfree = statvfs_buf.f_bavail;
 		*dsize = statvfs_buf.f_blocks;
-		disk_norm(bsize, dfree, dsize);
 		DEBUG(10, ("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
 			llu(*bsize), llu(*dfree), llu(*dsize)));
 		return *dfree;
@@ -185,7 +184,9 @@ static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,
 	}
 }
 
-static int cephwrap_get_quota(struct vfs_handle_struct *handle,  enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
+static int cephwrap_get_quota(struct vfs_handle_struct *handle,
+			      const char *path, enum SMB_QUOTA_TYPE qtype,
+			      unid_t id, SMB_DISK_QUOTA *qt)
 {
 	/* libceph: Ceph does not implement this */
 #if 0
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 490c4ab..6a0872c 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -32,7 +32,7 @@
 #include "lib/util/tevent_unix.h"
 #include "lib/asys/asys.h"
 #include "lib/util/tevent_ntstatus.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -58,19 +58,23 @@ static uint64_t vfswrap_disk_free(vfs_handle_struct *handle, const char *path,
 				  uint64_t *bsize, uint64_t *dfree,
 				  uint64_t *dsize)
 {
-	uint64_t result;
+	if (sys_fsusage(path, dfree, dsize) != 0) {
+		return (uint64_t)-1;
+	}
 
-	result = sys_disk_free(handle->conn, path, bsize, dfree, dsize);
-	return result;
+	*bsize = 512;
+	return *dfree / 2;
 }
 
-static int vfswrap_get_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
+static int vfswrap_get_quota(struct vfs_handle_struct *handle, const char *path,
+			     enum SMB_QUOTA_TYPE qtype, unid_t id,
+			     SMB_DISK_QUOTA *qt)
 {
 #ifdef HAVE_SYS_QUOTAS
 	int result;
 
 	START_PROFILE(syscall_get_quota);
-	result = sys_get_quota(handle->conn->connectpath, qtype, id, qt);
+	result = sys_get_quota(path, qtype, id, qt);
 	END_PROFILE(syscall_get_quota);
 	return result;
 #else
@@ -471,8 +475,9 @@ static int vfswrap_mkdir(vfs_handle_struct *handle, const char *path, mode_t mod
 
 	if (lp_inherit_acls(SNUM(handle->conn))
 	    && parent_dirname(talloc_tos(), path, &parent, NULL)
-	    && (has_dacl = directory_has_default_acl(handle->conn, parent)))
+	    && (has_dacl = directory_has_default_acl(handle->conn, parent))) {
 		mode = (0777 & lp_directory_mask(SNUM(handle->conn)));
+	}
 
 	TALLOC_FREE(parent);
 
@@ -690,39 +695,42 @@ static void vfswrap_asys_finished(struct tevent_context *ev,
 
 static bool vfswrap_init_asys_ctx(struct smbd_server_connection *conn)
 {
+	struct asys_context *ctx;
+	struct tevent_fd *fde;
 	int ret;
 	int fd;
 
 	if (conn->asys_ctx != NULL) {
 		return true;
 	}
-	ret = asys_context_init(&conn->asys_ctx, aio_pending_size);
+
+	ret = asys_context_init(&ctx, lp_aio_max_threads());
 	if (ret != 0) {
 		DEBUG(1, ("asys_context_init failed: %s\n", strerror(ret)));
 		return false;
 	}
 
-	fd = asys_signalfd(conn->asys_ctx);
+	fd = asys_signalfd(ctx);
 
 	ret = set_blocking(fd, false);
 	if (ret != 0) {
-		DBG_WARNING("set_blocking failed: %s\n", strerror(ret));
+		DBG_WARNING("set_blocking failed: %s\n", strerror(errno));
 		goto fail;
 	}
 
-	conn->asys_fde = tevent_add_fd(conn->ev_ctx, conn, fd,
-				       TEVENT_FD_READ,
-				       vfswrap_asys_finished,
-				       conn->asys_ctx);
-	if (conn->asys_fde == NULL) {
+	fde = tevent_add_fd(conn->ev_ctx, conn, fd, TEVENT_FD_READ,
+			    vfswrap_asys_finished, ctx);
+	if (fde == NULL) {
 		DEBUG(1, ("tevent_add_fd failed\n"));
 		goto fail;
 	}
+
+	conn->asys_ctx = ctx;
+	conn->asys_fde = fde;
 	return true;
 
 fail:
-	asys_context_destroy(conn->asys_ctx);
-	conn->asys_ctx = NULL;
+	asys_context_destroy(ctx);
 	return false;
 }
 
@@ -846,14 +854,14 @@ static void vfswrap_asys_finished(struct tevent_context *ev,
 					uint16_t flags, void *p)
 {
 	struct asys_context *asys_ctx = (struct asys_context *)p;
-	struct asys_result results[outstanding_aio_calls];
+	struct asys_result results[get_outstanding_aio_calls()];
 	int i, ret;
 
 	if ((flags & TEVENT_FD_READ) == 0) {
 		return;
 	}
 
-	ret = asys_results(asys_ctx, results, outstanding_aio_calls);
+	ret = asys_results(asys_ctx, results, get_outstanding_aio_calls());
 	if (ret < 0) {
 		DEBUG(1, ("asys_results returned %s\n", strerror(-ret)));
 		return;
@@ -1277,7 +1285,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
 		/* unknown 4 bytes: this is not the length of the sid :-(  */
 		/*unknown = IVAL(pdata,0);*/
 
-		if (!sid_parse(in_data + 4, sid_len, &sid)) {
+		if (!sid_parse(_in_data + 4, sid_len, &sid)) {
 			return NT_STATUS_INVALID_PARAMETER;
 		}
 		DEBUGADD(10, ("for SID: %s\n", sid_string_dbg(&sid)));
diff --git a/source3/modules/vfs_default_quota.c b/source3/modules/vfs_default_quota.c
index a71d3c2..c8d718c 100644
--- a/source3/modules/vfs_default_quota.c
+++ b/source3/modules/vfs_default_quota.c
@@ -92,11 +92,13 @@
 #define DEFAULT_QUOTA_GID_NOLIMIT(handle) \
 	lp_parm_bool(SNUM((handle)->conn),DEFAULT_QUOTA_NAME,"gid nolimit",DEFAULT_QUOTA_GID_NOLIMIT_DEFAULT)
 
-static int default_quota_get_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dq)
+static int default_quota_get_quota(vfs_handle_struct *handle, const char *path,
+				   enum SMB_QUOTA_TYPE qtype, unid_t id,
+				   SMB_DISK_QUOTA *dq)
 {
 	int ret = -1;
 
-	if ((ret=SMB_VFS_NEXT_GET_QUOTA(handle, qtype, id, dq))!=0) {
+	if ((ret = SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, dq)) != 0) {
 		return ret;
 	}
 
@@ -122,7 +124,8 @@ static int default_quota_get_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYP
 				unid_t qid;
 				uint32_t qflags = dq->qflags;
 				qid.uid = DEFAULT_QUOTA_UID(handle);
-				SMB_VFS_NEXT_GET_QUOTA(handle, SMB_USER_QUOTA_TYPE, qid, dq);
+				SMB_VFS_NEXT_GET_QUOTA(
+				    handle, path, SMB_USER_QUOTA_TYPE, qid, dq);
 				dq->qflags = qflags;
 			}
 			break;
@@ -132,7 +135,9 @@ static int default_quota_get_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYP
 				unid_t qid;
 				uint32_t qflags = dq->qflags;
 				qid.gid = DEFAULT_QUOTA_GID(handle);
-				SMB_VFS_NEXT_GET_QUOTA(handle, SMB_GROUP_QUOTA_TYPE, qid, dq);
+				SMB_VFS_NEXT_GET_QUOTA(handle, path,
+						       SMB_GROUP_QUOTA_TYPE,
+						       qid, dq);
 				dq->qflags = qflags;
 			}
 			break;
diff --git a/source3/modules/vfs_dirsort.c b/source3/modules/vfs_dirsort.c
index 224229f..d164088 100644
--- a/source3/modules/vfs_dirsort.c
+++ b/source3/modules/vfs_dirsort.c
@@ -358,6 +358,7 @@ static struct vfs_fn_pointers vfs_dirsort_fns = {
 	.closedir_fn = dirsort_closedir,
 };
 
+static_decl_vfs;
 NTSTATUS vfs_dirsort_init(void)
 {
 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "dirsort",
diff --git a/source3/modules/vfs_extd_audit.c b/source3/modules/vfs_extd_audit.c
index 93ae7e6..7d6b4d3 100644
--- a/source3/modules/vfs_extd_audit.c
+++ b/source3/modules/vfs_extd_audit.c
@@ -360,6 +360,7 @@ static struct vfs_fn_pointers vfs_extd_audit_fns = {
 	.fchmod_acl_fn = audit_fchmod_acl,
 };
 
+static_decl_vfs;
 NTSTATUS vfs_extd_audit_init(void)
 {
 	NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
diff --git a/source3/modules/vfs_fake_dfq.c b/source3/modules/vfs_fake_dfq.c
new file mode 100644
index 0000000..e476e16
--- /dev/null
+++ b/source3/modules/vfs_fake_dfq.c
@@ -0,0 +1,174 @@
+/*
+ * Fake Disk-Free and Quota VFS module.  Implements passthrough operation
+ * of all VFS calls, except for "disk free" and "get quota" which
+ * are handled by reading a text file named ".dfq" in the current directory.
+ *
+ * This module is intended for testing purposes.
+ *
+ * Copyright (C) Uri Simchoni, 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smbd/smbd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+static int dfq_get_quota(struct vfs_handle_struct *handle, const char *path,
+			 enum SMB_QUOTA_TYPE qtype, unid_t id,
+			 SMB_DISK_QUOTA *qt);
+
+static uint64_t dfq_load_param(int snum, const char *path, const char *section,
+			       const char *param, uint64_t def_val)
+{
+	uint64_t ret;
+
+	char *option =
+	    talloc_asprintf(talloc_tos(), "%s/%s/%s", section, param, path);
+	if (option == NULL) {
+		return def_val;
+	}
+
+	ret = (uint64_t)lp_parm_ulonglong(snum, "fake_dfq", option,
+					  (unsigned long long)def_val);
+
+	TALLOC_FREE(option);
+
+	return ret;
+}
+
+static uint64_t dfq_disk_free(vfs_handle_struct *handle, const char *path,
+			      uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
+{
+	uint64_t free_1k;
+	int snum = SNUM(handle->conn);
+	uint64_t dfq_bsize = 0;
+	char *rpath = NULL;
+
+	/* look up the params based on real path to be resilient
+	 * to refactoring of path<->realpath
+	 */
+	rpath = SMB_VFS_NEXT_REALPATH(handle, path);
+	if (rpath != NULL) {
+		dfq_bsize = dfq_load_param(snum, rpath, "df", "block size", 0);
+	}
+	if (dfq_bsize == 0) {
+		SAFE_FREE(rpath);
+		return SMB_VFS_NEXT_DISK_FREE(handle, path, bsize, dfree,
+					      dsize);
+	}
+
+	*bsize = dfq_bsize;
+	*dfree = dfq_load_param(snum, rpath, "df", "disk free", 0);
+	*dsize = dfq_load_param(snum, rpath, "df", "disk size", 0);
+
+	if ((*bsize) < 1024) {
+		free_1k = (*dfree) / (1024 / (*bsize));
+	} else {
+		free_1k = ((*bsize) / 1024) * (*dfree);
+	}
+
+	SAFE_FREE(rpath);
+	return free_1k;
+}
+
+static int dfq_get_quota(struct vfs_handle_struct *handle, const char *path,
+			 enum SMB_QUOTA_TYPE qtype, unid_t id,
+			 SMB_DISK_QUOTA *qt)
+{
+	int rc = 0;
+	int save_errno;
+	char *section = NULL;
+	int snum = SNUM(handle->conn);
+	uint64_t bsize = 0;
+	char *rpath = NULL;
+
+	rpath = SMB_VFS_NEXT_REALPATH(handle, path);
+	if (rpath == NULL) {
+		goto dflt;
+	}
+
+	switch (qtype) {
+	case SMB_USER_QUOTA_TYPE:
+		section = talloc_asprintf(talloc_tos(), "u%llu",
+					  (unsigned long long)id.uid);
+		break;
+	case SMB_GROUP_QUOTA_TYPE:
+		section = talloc_asprintf(talloc_tos(), "g%llu",
+					  (unsigned long long)id.gid);
+		break;
+	default:
+		break;
+	}
+
+	if (section == NULL) {
+		goto dflt;
+	}
+
+	bsize = dfq_load_param(snum, rpath, section, "block size", 0);
+	if (bsize == 0) {
+		goto dflt;
+	}
+
+	if (dfq_load_param(snum, rpath, section, "err", 0) != 0) {
+		errno = ENOTSUP;
+		rc = -1;
+		goto out;
+	}
+
+	ZERO_STRUCTP(qt);
+
+	qt->bsize = bsize;
+	qt->hardlimit = dfq_load_param(snum, rpath, section, "hard limit", 0);
+	qt->softlimit = dfq_load_param(snum, rpath, section, "soft limit", 0);
+	qt->curblocks = dfq_load_param(snum, rpath, section, "cur blocks", 0);
+	qt->ihardlimit =
+	    dfq_load_param(snum, rpath, section, "inode hard limit", 0);
+	qt->isoftlimit =
+	    dfq_load_param(snum, rpath, section, "inode soft limit", 0);
+	qt->curinodes = dfq_load_param(snum, rpath, section, "cur inodes", 0);
+
+	if (dfq_load_param(snum, rpath, section, "edquot", 0) != 0) {
+		errno = EDQUOT;
+		rc = -1;
+	}
+
+	goto out;
+
+dflt:
+	rc = SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, qt);
+
+out:
+	save_errno = errno;
+	TALLOC_FREE(section);
+	SAFE_FREE(rpath);
+	errno = save_errno;
+	return rc;
+}
+
+struct vfs_fn_pointers vfs_fake_dfq_fns = {
+    /* Disk operations */
+
+    .disk_free_fn = dfq_disk_free,
+    .get_quota_fn = dfq_get_quota,
+};
+
+static_decl_vfs;
+NTSTATUS vfs_fake_dfq_init(void)
+{
+	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_dfq",
+				&vfs_fake_dfq_fns);
+}
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index d87afa6..cb0d284 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -29,7 +29,7 @@
 #include "messages.h"
 #include "libcli/security/security.h"
 #include "../libcli/smb/smb2_create_ctx.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 #include "lib/util/tevent_ntstatus.h"
 
 /*
@@ -1840,7 +1840,7 @@ static NTSTATUS check_aapl(vfs_handle_struct *handle,
 	}
 
 	if (aapl->data.length != 24) {
-		DEBUG(1, ("unexpected AAPL ctxt legnth: %ju\n",
+		DEBUG(1, ("unexpected AAPL ctxt length: %ju\n",
 			  (uintmax_t)aapl->data.length));
 		return NT_STATUS_INVALID_PARAMETER;
 	}
@@ -3394,7 +3394,7 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
 
 	status = check_aapl(handle, req, in_context_blobs, out_context_blobs);
 	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+		goto fail;
 	}
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c
index 6de22b1..904b569 100644
--- a/source3/modules/vfs_full_audit.c
+++ b/source3/modules/vfs_full_audit.c
@@ -666,14 +666,14 @@ static uint64_t smb_full_audit_disk_free(vfs_handle_struct *handle,
 }
 
 static int smb_full_audit_get_quota(struct vfs_handle_struct *handle,
-			   enum SMB_QUOTA_TYPE qtype, unid_t id,
-			   SMB_DISK_QUOTA *qt)
+				    const char *path, enum SMB_QUOTA_TYPE qtype,
+				    unid_t id, SMB_DISK_QUOTA *qt)
 {
 	int result;
 
-	result = SMB_VFS_NEXT_GET_QUOTA(handle, qtype, id, qt);
+	result = SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, qt);
 
-	do_log(SMB_VFS_OP_GET_QUOTA, (result >= 0), handle, "");
+	do_log(SMB_VFS_OP_GET_QUOTA, (result >= 0), handle, "%s", path);
 
 	return result;
 }
@@ -2323,6 +2323,7 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
 	.set_offline_fn = smb_full_audit_set_offline,
 };
 
+static_decl_vfs;
 NTSTATUS vfs_full_audit_init(void)
 {
 	NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
index a66887d..84530a8 100644
--- a/source3/modules/vfs_glusterfs.c
+++ b/source3/modules/vfs_glusterfs.c
@@ -43,7 +43,7 @@
 #include "lib/util/tevent_unix.h"
 #include "lib/tevent/tevent_internal.h"
 #include "smbd/globals.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 
 #define DEFAULT_VOLFILE_SERVER "localhost"
 
@@ -296,6 +296,7 @@ static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
 }
 
 static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
+				 const char *path,
 				 enum SMB_QUOTA_TYPE qtype, unid_t id,
 				 SMB_DISK_QUOTA *qt)
 {
@@ -487,11 +488,28 @@ static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
 	return glfs_pread(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, offset, 0);
 }
 
+struct glusterfs_aio_state;
+
+struct glusterfs_aio_wrapper {
+	struct glusterfs_aio_state *state;
+};
+
 struct glusterfs_aio_state {
 	ssize_t ret;
 	int err;
+	struct tevent_req *req;
+	bool cancelled;
 };
 
+static int aio_wrapper_destructor(struct glusterfs_aio_wrapper *wrap)
+{
+	if (wrap->state != NULL) {
+		wrap->state->cancelled = true;
+	}
+
+	return 0;
+}
+
 /*
  * This function is the callback that will be called on glusterfs
  * threads once the async IO submitted is complete. To notify
@@ -499,12 +517,10 @@ struct glusterfs_aio_state {
  */
 static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data)
 {
-	struct tevent_req *req = NULL;
 	struct glusterfs_aio_state *state = NULL;
 	int sts = 0;
 
-	req = talloc_get_type_abort(data, struct tevent_req);
-	state = tevent_req_data(req, struct glusterfs_aio_state);
+	state = (struct glusterfs_aio_state *)data;
 
 	if (ret < 0) {
 		state->ret = -1;
@@ -515,10 +531,10 @@ static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data)
 	}
 
 	/*
-	 * Write the pointer to each req that needs to be completed
-	 * by calling tevent_req_done(). tevent_req_done() cannot
-	 * be called here, as it is not designed to be executed
-	 * in the multithread environment, tevent_req_done() must be
+	 * Write the state pointer to glusterfs_aio_state to the
+	 * pipe, so we can call tevent_req_done() from the main thread,
+	 * because tevent_req_done() is not designed to be executed in
+	 * the multithread environment, so tevent_req_done() must be
 	 * executed from the smbd main thread.
 	 *
 	 * write(2) on pipes with sizes under _POSIX_PIPE_BUF
@@ -529,7 +545,7 @@ static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data)
 	 * that we can trust it here.
 	 */
 
-	sts = sys_write(write_fd, &req, sizeof(struct tevent_req *));
+	sts = sys_write(write_fd, &state, sizeof(struct glusterfs_aio_state *));
 	if (sts < 0) {
 		DEBUG(0,("\nWrite to pipe failed (%s)", strerror(errno)));
 	}
@@ -545,6 +561,7 @@ static void aio_tevent_fd_done(struct tevent_context *event_ctx,
 				uint16_t flags, void *data)
 {
 	struct tevent_req *req = NULL;
+	struct glusterfs_aio_state *state = NULL;
 	int sts = 0;
 
 	/*
@@ -557,11 +574,20 @@ static void aio_tevent_fd_done(struct tevent_context *event_ctx,
 	 * can trust it here.
 	 */
 
-	sts = sys_read(read_fd, &req, sizeof(struct tevent_req *));
+	sts = sys_read(read_fd, &state, sizeof(struct glusterfs_aio_state *));
+
 	if (sts < 0) {
 		DEBUG(0,("\nRead from pipe failed (%s)", strerror(errno)));
 	}
 
+	/* if we've cancelled the op, there is no req, so just clean up. */
+	if (state->cancelled == true) {
+		TALLOC_FREE(state);
+		return;
+	}
+
+	req = state->req;
+
 	if (req) {
 		tevent_req_done(req);
 	}
@@ -610,28 +636,63 @@ fail:
 	return false;
 }
 
-static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
-						 *handle, TALLOC_CTX *mem_ctx,
-						 struct tevent_context *ev,
-						 files_struct *fsp, void *data,
-						 size_t n, off_t offset)
+static struct glusterfs_aio_state *aio_state_create(TALLOC_CTX *mem_ctx)
 {
 	struct tevent_req *req = NULL;
 	struct glusterfs_aio_state *state = NULL;
-	int ret = 0;
+	struct glusterfs_aio_wrapper *wrapper = NULL;
+
+	req = tevent_req_create(mem_ctx, &wrapper, struct glusterfs_aio_wrapper);
 
-	req = tevent_req_create(mem_ctx, &state, struct glusterfs_aio_state);
 	if (req == NULL) {
 		return NULL;
 	}
 
+	state = talloc(NULL, struct glusterfs_aio_state);
+
+	if (state == NULL) {
+		TALLOC_FREE(req);
+		return NULL;
+	}
+
+	talloc_set_destructor(wrapper, aio_wrapper_destructor);
+	state->cancelled = false;
+	state->ret = 0;
+	state->err = 0;
+	state->req = req;
+
+	wrapper->state = state;
+
+	return state;
+}
+
+static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
+						  *handle, TALLOC_CTX *mem_ctx,
+						  struct tevent_context *ev,
+						  files_struct *fsp,
+						  void *data, size_t n,
+						  off_t offset)
+{
+	struct glusterfs_aio_state *state = NULL;
+	struct tevent_req *req = NULL;
+	int ret = 0;
+
+	state = aio_state_create(mem_ctx);
+
+	if (state == NULL) {
+		return NULL;
+	}
+
+	req = state->req;
+
 	if (!init_gluster_aio(handle)) {
 		tevent_req_error(req, EIO);
 		return tevent_req_post(req, ev);
 	}
+
 	ret = glfs_pread_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
 				fsp), data, n, offset, 0, aio_glusterfs_done,
-				req);
+				state);
 	if (ret < 0) {
 		tevent_req_error(req, -ret);
 		return tevent_req_post(req, ev);
@@ -640,19 +701,6 @@ static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
 	return req;
 }
 
-static ssize_t vfs_gluster_write(struct vfs_handle_struct *handle,
-				 files_struct *fsp, const void *data, size_t n)
-{
-	return glfs_write(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, 0);
-}
-
-static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
-				  files_struct *fsp, const void *data,
-				  size_t n, off_t offset)
-{
-	return glfs_pwrite(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, offset, 0);
-}
-
 static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
 						  *handle, TALLOC_CTX *mem_ctx,
 						  struct tevent_context *ev,
@@ -660,44 +708,76 @@ static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
 						  const void *data, size_t n,
 						  off_t offset)
 {
-	struct tevent_req *req = NULL;
 	struct glusterfs_aio_state *state = NULL;
+	struct tevent_req *req = NULL;
 	int ret = 0;
 
-	req = tevent_req_create(mem_ctx, &state, struct glusterfs_aio_state);
-	if (req == NULL) {
+	state = aio_state_create(mem_ctx);
+
+	if (state == NULL) {
 		return NULL;
 	}
+
+	req = state->req;
+
 	if (!init_gluster_aio(handle)) {
 		tevent_req_error(req, EIO);
 		return tevent_req_post(req, ev);
 	}
+
 	ret = glfs_pwrite_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
 				fsp), data, n, offset, 0, aio_glusterfs_done,
-				req);
+				state);
 	if (ret < 0) {
 		tevent_req_error(req, -ret);
 		return tevent_req_post(req, ev);
 	}
+
 	return req;
 }
 
 static ssize_t vfs_gluster_recv(struct tevent_req *req, int *err)
 {
-	struct glusterfs_aio_state *state = NULL;
+	struct glusterfs_aio_wrapper *wrapper = NULL;
+	int ret = 0;
 
-	state = tevent_req_data(req, struct glusterfs_aio_state);
-	if (state == NULL) {
+	wrapper = tevent_req_data(req, struct glusterfs_aio_wrapper);
+
+	if (wrapper == NULL) {
+		return -1;
+	}
+
+	if (wrapper->state == NULL) {
 		return -1;
 	}
 
 	if (tevent_req_is_unix_error(req, err)) {
 		return -1;
 	}
-	if (state->ret == -1) {
-		*err = state->err;
+	if (wrapper->state->ret == -1) {
+		*err = wrapper->state->err;
 	}
-	return state->ret;
+
+	ret = wrapper->state->ret;
+
+	/* Clean up the state, it is in a NULL context. */
+
+	TALLOC_FREE(wrapper->state);
+
+	return ret;
+}
+
+static ssize_t vfs_gluster_write(struct vfs_handle_struct *handle,
+				 files_struct *fsp, const void *data, size_t n)
+{
+	return glfs_write(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, 0);
+}
+
+static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
+				  files_struct *fsp, const void *data,
+				  size_t n, off_t offset)
+{
+	return glfs_pwrite(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, offset, 0);
 }
 
 static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
@@ -746,10 +826,14 @@ static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
 	struct glusterfs_aio_state *state = NULL;
 	int ret = 0;
 
-	req = tevent_req_create(mem_ctx, &state, struct glusterfs_aio_state);
-	if (req == NULL) {
+	state = aio_state_create(mem_ctx);
+
+	if (state == NULL) {
 		return NULL;
 	}
+
+	req = state->req;
+
 	if (!init_gluster_aio(handle)) {
 		tevent_req_error(req, EIO);
 		return tevent_req_post(req, ev);
diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c
index 62cc801..2216d1d 100644
--- a/source3/modules/vfs_gpfs.c
+++ b/source3/modules/vfs_gpfs.c
@@ -54,6 +54,10 @@ struct gpfs_config_data {
 	bool recalls;
 };
 
+struct gpfs_fsp_extension {
+	bool offline;
+};
+
 static inline unsigned int gpfs_acl_flags(gpfs_acl_t *gacl)
 {
 	if (gacl->acl_level == GPFS_ACL_LEVEL_V4FLAGS) {
@@ -122,6 +126,8 @@ static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
 	struct gpfs_config_data *config;
 	int ret = 0;
 
+	START_PROFILE(syscall_kernel_flock);
+
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct gpfs_config_data,
 				return -1);
@@ -141,8 +147,6 @@ static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
 		return 0;
 	}
 
-	START_PROFILE(syscall_kernel_flock);
-
 	kernel_flock(fsp->fh->fd, share_mode, access_mask);
 
 	if (!set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
@@ -196,12 +200,12 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp,
 	struct gpfs_config_data *config;
 	int ret=0;
 
+	START_PROFILE(syscall_linux_setlease);
+
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct gpfs_config_data,
 				return -1);
 
-	START_PROFILE(syscall_linux_setlease);
-
 	if (linux_set_lease_sighandler(fsp->fh->fd) == -1) {
 		ret = -1;
 		goto failure;
@@ -436,7 +440,8 @@ again:
  * On failure returns -1 if there is system (GPFS) error, check errno.
  * Returns 0 on success
  */
-static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *fname, SMB4ACL_T **ppacl)
+static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *fname,
+			     struct SMB4ACL_T **ppacl)
 {
 	gpfs_aclCount_t i;
 	struct gpfs_acl *gacl = NULL;
@@ -537,7 +542,7 @@ static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
 	TALLOC_CTX *mem_ctx,
 	struct security_descriptor **ppdesc)
 {
-	SMB4ACL_T *pacl = NULL;
+	struct SMB4ACL_T *pacl = NULL;
 	int	result;
 	struct gpfs_config_data *config;
 	TALLOC_CTX *frame = talloc_stackframe();
@@ -584,7 +589,7 @@ static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
 	uint32_t security_info,
 	TALLOC_CTX *mem_ctx, struct security_descriptor **ppdesc)
 {
-	SMB4ACL_T *pacl = NULL;
+	struct SMB4ACL_T *pacl = NULL;
 	int	result;
 	struct gpfs_config_data *config;
 	TALLOC_CTX *frame = talloc_stackframe();
@@ -627,12 +632,12 @@ static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
 
 static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx,
 						files_struct *fsp,
-						SMB4ACL_T *smbacl,
+						struct SMB4ACL_T *smbacl,
 						bool controlflags)
 {
 	struct gpfs_acl *gacl;
 	gpfs_aclLen_t gacl_len;
-	SMB4ACE_T *smbace;
+	struct SMB4ACE_T *smbace;
 
 	gacl_len = offsetof(gpfs_acl_t, ace_v4) + sizeof(unsigned int)
 		+ smb_get_naces(smbacl) * sizeof(gpfs_ace_v4_t);
@@ -720,7 +725,7 @@ static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx,
 
 static bool gpfsacl_process_smbacl(vfs_handle_struct *handle,
 				   files_struct *fsp,
-				   SMB4ACL_T *smbacl)
+				   struct SMB4ACL_T *smbacl)
 {
 	int ret;
 	struct gpfs_acl *gacl;
@@ -1295,12 +1300,12 @@ static uint32_t gpfsacl_mask_filter(uint32_t aceType, uint32_t aceMask, uint32_t
 static int gpfsacl_emu_chmod(vfs_handle_struct *handle,
 			     const char *path, mode_t mode)
 {
-	SMB4ACL_T *pacl = NULL;
+	struct SMB4ACL_T *pacl = NULL;
 	int     result;
 	bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
 	int     i;
 	files_struct fake_fsp = { 0 }; /* TODO: rationalize parametrization */
-	SMB4ACE_T       *smbace;
+	struct SMB4ACE_T *smbace;
 	TALLOC_CTX *frame = talloc_stackframe();
 
 	DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
@@ -1955,18 +1960,42 @@ static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
 	return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
 }
 
+static bool vfs_gpfs_fsp_is_offline(struct vfs_handle_struct *handle,
+				    struct files_struct *fsp)
+{
+	struct gpfs_fsp_extension *ext;
+
+	ext = VFS_FETCH_FSP_EXTENSION(handle, fsp);
+	if (ext == NULL) {
+		/*
+		 * Something bad happened, always ask.
+		 */
+		return vfs_gpfs_is_offline(handle, fsp->fsp_name,
+					   &fsp->fsp_name->st);
+	}
+
+	if (ext->offline) {
+		/*
+		 * As long as it's offline, ask.
+		 */
+		ext->offline = vfs_gpfs_is_offline(handle, fsp->fsp_name,
+						   &fsp->fsp_name->st);
+	}
+
+	return ext->offline;
+}
+
 static bool vfs_gpfs_aio_force(struct vfs_handle_struct *handle,
 			       struct files_struct *fsp)
 {
-	return vfs_gpfs_is_offline(handle, fsp->fsp_name, &fsp->fsp_name->st);
+	return vfs_gpfs_fsp_is_offline(handle, fsp);
 }
 
 static ssize_t vfs_gpfs_sendfile(vfs_handle_struct *handle, int tofd,
 				 files_struct *fsp, const DATA_BLOB *hdr,
 				 off_t offset, size_t n)
 {
-	if (SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name, &fsp->fsp_name->st))
-	{
+	if (vfs_gpfs_fsp_is_offline(handle, fsp)) {
 		errno = ENOSYS;
 		return -1;
 	}
@@ -2175,8 +2204,31 @@ static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle, const char *path,
 	vfs_gpfs_disk_free_quota(qi_user, cur_time, dfree, dsize);
 	vfs_gpfs_disk_free_quota(qi_group, cur_time, dfree, dsize);
 
-	disk_norm(bsize, dfree, dsize);
-	return *dfree;
+	return *dfree / 2;
+}
+
+static int vfs_gpfs_get_quota(vfs_handle_struct *handle, const char *path,
+			  enum SMB_QUOTA_TYPE qtype, unid_t id,
+			  SMB_DISK_QUOTA *dq)
+{
+	switch(qtype) {
+		/*
+		 * User/group quota are being used for disk-free
+		 * determination, which in this module is done directly
+		 * by the disk-free function. It's important that this
+		 * module does not return wrong quota values by mistake,
+		 * which would modify the correct values set by disk-free.
+		 * User/group quota are also being used for processing
+		 * NT_TRANSACT_GET_USER_QUOTA in smb1 protocol, which is
+		 * currently not supported by this module.
+		 */
+		case SMB_USER_QUOTA_TYPE:
+		case SMB_GROUP_QUOTA_TYPE:
+			errno = ENOSYS;
+			return -1;
+		default:
+			return SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, dq);
+	}
 }
 
 static uint32_t vfs_gpfs_capabilities(struct vfs_handle_struct *handle,
@@ -2202,25 +2254,42 @@ static int vfs_gpfs_open(struct vfs_handle_struct *handle,
 			 int flags, mode_t mode)
 {
 	struct gpfs_config_data *config;
+	int ret;
+	struct gpfs_fsp_extension *ext;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct gpfs_config_data,
 				return -1);
 
-	if (config->hsm && !config->recalls) {
-		if (SMB_VFS_IS_OFFLINE(handle->conn, smb_fname, &smb_fname->st))
-		{
-			DEBUG(10, ("Refusing access to offline file %s\n",
-				  fsp_str_dbg(fsp)));
-			errno = EACCES;
-			return -1;
-		}
+	if (config->hsm && !config->recalls &&
+	    vfs_gpfs_fsp_is_offline(handle, fsp)) {
+		DEBUG(10, ("Refusing access to offline file %s\n",
+			   fsp_str_dbg(fsp)));
+		errno = EACCES;
+		return -1;
 	}
 
 	if (config->syncio) {
 		flags |= O_SYNC;
 	}
-	return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+
+	ext = VFS_ADD_FSP_EXTENSION(handle, fsp, struct gpfs_fsp_extension,
+				    NULL);
+	if (ext == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	/*
+	 * Assume the file is offline until gpfs tells us it's online.
+	 */
+	*ext = (struct gpfs_fsp_extension) { .offline = true };
+
+	ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+	if (ret == -1) {
+		VFS_REMOVE_FSP_EXTENSION(handle, fsp);
+	}
+	return ret;
 }
 
 static ssize_t vfs_gpfs_pread(vfs_handle_struct *handle, files_struct *fsp,
@@ -2229,8 +2298,7 @@ static ssize_t vfs_gpfs_pread(vfs_handle_struct *handle, files_struct *fsp,
 	ssize_t ret;
 	bool was_offline;
 
-	was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
-					 &fsp->fsp_name->st);
+	was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
 
 	ret = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
 
@@ -2266,8 +2334,7 @@ static struct tevent_req *vfs_gpfs_pread_send(struct vfs_handle_struct *handle,
 	if (req == NULL) {
 		return NULL;
 	}
-	state->was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
-						&fsp->fsp_name->st);
+	state->was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
 	state->fsp = fsp;
 	subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
 					 n, offset);
@@ -2317,8 +2384,7 @@ static ssize_t vfs_gpfs_pwrite(vfs_handle_struct *handle, files_struct *fsp,
 	ssize_t ret;
 	bool was_offline;
 
-	was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
-					 &fsp->fsp_name->st);
+	was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
 
 	ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
 
@@ -2355,8 +2421,7 @@ static struct tevent_req *vfs_gpfs_pwrite_send(
 	if (req == NULL) {
 		return NULL;
 	}
-	state->was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
-						&fsp->fsp_name->st);
+	state->was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
 	state->fsp = fsp;
 	subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
 					 n, offset);
@@ -2404,6 +2469,7 @@ static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req, int *err)
 static struct vfs_fn_pointers vfs_gpfs_fns = {
 	.connect_fn = vfs_gpfs_connect,
 	.disk_free_fn = vfs_gpfs_disk_free,
+	.get_quota_fn = vfs_gpfs_get_quota,
 	.fs_capabilities_fn = vfs_gpfs_capabilities,
 	.kernel_flock_fn = vfs_gpfs_kernel_flock,
 	.linux_setlease_fn = vfs_gpfs_setlease,
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index d5d3e2b..b041699 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -72,11 +72,11 @@ static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
 
 static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
 					 DATA_BLOB *blob,
-					 SMB4ACL_T **ppacl)
+					 struct SMB4ACL_T **ppacl)
 {
 	int i;
 	struct nfs4acl *nfs4acl = NULL;
-	SMB4ACL_T *pacl = NULL;
+	struct SMB4ACL_T *pacl = NULL;
 	TALLOC_CTX *frame = talloc_stackframe();
 	nfs4acl = nfs4acl_blob2acl(blob, frame);
 
@@ -120,7 +120,7 @@ static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
 
 /* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
 static NTSTATUS nfs4_fget_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
-				   files_struct *fsp, SMB4ACL_T **ppacl)
+				   files_struct *fsp, struct SMB4ACL_T **ppacl)
 {
 	NTSTATUS status;
 	DATA_BLOB blob = data_blob_null;
@@ -149,7 +149,7 @@ static NTSTATUS nfs4_fget_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ct
 
 /* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
 static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
-				  const char *path, SMB4ACL_T **ppacl)
+				  const char *path, struct SMB4ACL_T **ppacl)
 {
 	NTSTATUS status;
 	DATA_BLOB blob = data_blob_null;
@@ -177,12 +177,12 @@ static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx
 }
 
 static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
-				    SMB4ACL_T *smbacl,
+				    struct SMB4ACL_T *smbacl,
 				    struct nfs4acl **pnfs4acl,
 				    bool denymissingspecial)
 {
 	struct nfs4acl *nfs4acl;
-	SMB4ACE_T *smbace;
+	struct SMB4ACE_T *smbace;
 	bool have_special_id = false;
 	int i;
 
@@ -252,7 +252,7 @@ static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
 
 static bool nfs4acl_xattr_set_smb4acl(vfs_handle_struct *handle,
 				      const char *path,
-				      SMB4ACL_T *smbacl)
+				      struct SMB4ACL_T *smbacl)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct nfs4acl *nfs4acl;
@@ -290,7 +290,7 @@ static bool nfs4acl_xattr_set_smb4acl(vfs_handle_struct *handle,
 /* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */
 static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
 				       files_struct *fsp,
-				       SMB4ACL_T *smbacl)
+				       struct SMB4ACL_T *smbacl)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct nfs4acl *nfs4acl;
@@ -340,10 +340,10 @@ static NTSTATUS nfs4_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
 			nfs4acl_xattr_fset_smb4acl);
 }
 
-static SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx)
+static struct SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx)
 {
-	SMB4ACL_T *pacl = NULL;
-	SMB4ACE_T *pace;
+	struct SMB4ACL_T *pacl = NULL;
+	struct SMB4ACE_T *pace;
 	SMB_ACE4PROP_T ace = {
 		.flags = SMB_ACE4_ID_SPECIAL,
 		.who = {
@@ -401,14 +401,14 @@ static SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx)
  *
  * Todo: Really use mem_ctx after fixing interface of nfs4_acls
  */
-static SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle,
+static struct SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle,
 	const char *path,
 	TALLOC_CTX *mem_ctx)
 {
 	char *parent_dir = NULL;
-	SMB4ACL_T *pparentacl = NULL;
-	SMB4ACL_T *pchildacl = NULL;
-	SMB4ACE_T *pace;
+	struct SMB4ACL_T *pparentacl = NULL;
+	struct SMB4ACL_T *pchildacl = NULL;
+	struct SMB4ACE_T *pace;
 	SMB_ACE4PROP_T ace;
 	bool isdir;
 	struct smb_filename *smb_fname = NULL;
@@ -469,7 +469,7 @@ static SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle,
 
 	for (pace = smb_first_ace4(pparentacl); pace != NULL;
 	     pace = smb_next_ace4(pace)) {
-		SMB4ACE_T *pchildace;
+		struct SMB4ACE_T *pchildace;
 		ace = *smb_get_ace4(pace);
 		if ((isdir && !(ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) ||
 		    (!isdir && !(ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE))) {
@@ -521,7 +521,7 @@ static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
 				   TALLOC_CTX *mem_ctx,
 				   struct security_descriptor **ppdesc)
 {
-	SMB4ACL_T *pacl;
+	struct SMB4ACL_T *pacl;
 	NTSTATUS status;
 	TALLOC_CTX *frame = talloc_stackframe();
 
@@ -545,7 +545,7 @@ static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
 				  TALLOC_CTX *mem_ctx,
 				  struct security_descriptor **ppdesc)
 {
-	SMB4ACL_T *pacl;
+	struct SMB4ACL_T *pacl;
 	NTSTATUS status;
 	TALLOC_CTX *frame = talloc_stackframe();
 
diff --git a/source3/modules/vfs_offline.c b/source3/modules/vfs_offline.c
new file mode 100644
index 0000000..5921f43
--- /dev/null
+++ b/source3/modules/vfs_offline.c
@@ -0,0 +1,47 @@
+/*
+  Unix SMB/CIFS implementation.
+  Samba VFS module for marking all files as offline.
+
+  (c) Uri Simchoni, 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+static uint32_t offline_fs_capabilities(struct vfs_handle_struct *handle,
+					enum timestamp_set_resolution *p_ts_res)
+{
+	return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) |
+	       FILE_SUPPORTS_REMOTE_STORAGE;
+}
+
+static bool offline_is_offline(struct vfs_handle_struct *handle,
+			       const struct smb_filename *fname,
+			       SMB_STRUCT_STAT *stbuf)
+{
+	return true;
+}
+
+static struct vfs_fn_pointers offline_fns = {
+    .fs_capabilities_fn = offline_fs_capabilities,
+    .is_offline_fn = offline_is_offline,
+};
+
+NTSTATUS vfs_offline_init(void);
+NTSTATUS vfs_offline_init(void)
+{
+	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "offline",
+				&offline_fns);
+}
diff --git a/source3/modules/vfs_posix_eadb.c b/source3/modules/vfs_posix_eadb.c
index 993c919..20679e1 100644
--- a/source3/modules/vfs_posix_eadb.c
+++ b/source3/modules/vfs_posix_eadb.c
@@ -431,7 +431,7 @@ static struct vfs_fn_pointers vfs_posix_eadb_fns = {
 	.connect_fn = posix_eadb_connect,
 };
 
-NTSTATUS vfs_posix_eadb_init(void);
+static_decl_vfs;
 NTSTATUS vfs_posix_eadb_init(void)
 {
 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posix_eadb",
diff --git a/source3/modules/vfs_preopen.c b/source3/modules/vfs_preopen.c
index c83d312..b67aad8 100644
--- a/source3/modules/vfs_preopen.c
+++ b/source3/modules/vfs_preopen.c
@@ -21,7 +21,7 @@
 #include "includes.h"
 #include "system/filesys.h"
 #include "smbd/smbd.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 
 struct preopen_state;
 
diff --git a/source3/modules/vfs_scannedonly.c b/source3/modules/vfs_scannedonly.c
deleted file mode 100644
index 0232a15..0000000
--- a/source3/modules/vfs_scannedonly.c
+++ /dev/null
@@ -1,1043 +0,0 @@
-/*
- * scannedonly VFS module for Samba 3.5 and beyond
- *
- * Copyright 2007,2008,2009,2010,2011 (C) Olivier Sessink
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * ABOUT SCANNEDONLY
- *
- * scannedonly implements a 'filter' like vfs module that talks over a
- * unix domain socket or over UDP to a anti-virus engine.
- *
- * files that are clean have a corresponding .scanned:{filename} file
- * in the same directory. So why the .scanned: files? They take up
- * only an inode, because they are 0 bytes. To test if the file is
- * scanned only a stat() call on the filesystem is needed which is
- * very quick compared to a database lookup. All modern filesystems
- * use database technology such as balanced trees for lookups anyway.
- * The number of inodes in modern filesystems is also not limiting
- * anymore. The .scanned: files are also easy scriptable. You can
- * remove them with a simple find command or create them with a
- * simple touch command. Extended filesystem attributes have similar
- * properties, but are not supported on all filesystems, so that
- * would limit the usage of the module (and attributes are not as
- * easily scriptable)
- *
- * files that are not clean are sent to the AV-engine. Only the
- * filename is sent over the socket. The protocol is very simple:
- * a newline separated list of filenames inside each datagram.
- *
- * a file AV-scan may be requested multiple times, the AV-engine
- * should also check if the file has been scanned already. Requests
- * can also be dropped by the AV-engine (and we thus don't need the
- * reliability of TCP).
- *
- */
-
-#include "includes.h"
-#include "smbd/smbd.h"
-#include "system/filesys.h"
-
-#include "config.h"
-
-#define SENDBUFFERSIZE 1450
-
-#ifndef       SUN_LEN
-#define       SUN_LEN(sunp)   ((size_t)((struct sockaddr_un *)0)->sun_path \
-				+ strlen((sunp)->sun_path))
-#endif
-
-
-struct Tscannedonly {
-	int socket;
-	int domain_socket;
-	int portnum;
-	int scanning_message_len;
-	int recheck_time_open;
-	int recheck_tries_open;
-	int recheck_size_open;
-	int recheck_time_readdir;
-	int recheck_tries_readdir;
-	bool show_special_files;
-	bool rm_hidden_files_on_rmdir;
-	bool hide_nonscanned_files;
-	bool allow_nonscanned_files;
-	const char *socketname;
-	const char *scanhost;
-	const char *scanning_message;
-	const char *p_scanned; /* prefix for scanned files */
-	const char *p_virus; /* prefix for virus containing files */
-	const char *p_failed; /* prefix for failed to scan files */
-	char gsendbuffer[SENDBUFFERSIZE + 1];
-};
-
-#define STRUCTSCANO(var) ((struct Tscannedonly *)var)
-
-struct scannedonly_DIR {
-	char *base;
-	int recheck_tries_done; /* if 0 the directory listing has not yet
-	been checked for files that need to be scanned. */
-	DIR *DIR;
-};
-#define SCANNEDONLY_DEBUG 9
-/*********************/
-/* utility functions */
-/*********************/
-
-static char *real_path_from_notify_path(TALLOC_CTX *ctx,
-					struct Tscannedonly *so,
-					const char *path)
-{
-	char *name;
-	int len, pathlen;
-
-	name = strrchr(path, '/');
-	if (!name) {
-		return NULL;
-	}
-	pathlen = name - path;
-	name++;
-	len = strlen(name);
-	if (len <= so->scanning_message_len) {
-		return NULL;
-	}
-
-	if (strcmp(name + (len - so->scanning_message_len),
-		   so->scanning_message) != 0) {
-		return NULL;
-	}
-
-	return talloc_strndup(ctx,path,
-			      pathlen + len - so->scanning_message_len);
-}
-
-static char *cachefile_name(TALLOC_CTX *ctx,
-			    const char *shortname,
-			    const char *base,
-			    const char *p_scanned)
-{
-	return talloc_asprintf(ctx, "%s%s%s", base, p_scanned, shortname);
-}
-
-static char *name_w_ending_slash(TALLOC_CTX *ctx, const char *name)
-{
-	int len = strlen(name);
-	if (name[len - 1] == '/') {
-		return talloc_strdup(ctx,name);
-	} else {
-		return talloc_asprintf(ctx, "%s/", name);
-	}
-}
-
-static char *cachefile_name_f_fullpath(TALLOC_CTX *ctx,
-				       const char *fullpath,
-				       const char *p_scanned)
-{
-	const char *base;
-	char *tmp, *cachefile;
-	const char *shortname;
-	tmp = strrchr(fullpath, '/');
-	if (tmp) {
-		base = talloc_strndup(ctx, fullpath, (tmp - fullpath) + 1);
-		shortname = tmp + 1;
-	} else {
-		base = "";
-		shortname = (const char *)fullpath;
-	}
-	cachefile = cachefile_name(ctx, shortname, base, p_scanned);
-	DEBUG(SCANNEDONLY_DEBUG,
-	      ("cachefile_name_f_fullpath cachefile=%s\n", cachefile));
-	return cachefile;
-}
-
-static char *construct_full_path(TALLOC_CTX *ctx, vfs_handle_struct * handle,
-				 const char *somepath, bool ending_slash)
-{
-	const char *tmp;
-
-	if (!somepath) {
-		return NULL;
-	}
-	if (somepath[0] == '/') {
-		if (ending_slash) {
-			return name_w_ending_slash(ctx,somepath);
-		}
-		return talloc_strdup(ctx,somepath);
-	}
-	tmp = somepath;
-	if (tmp[0]=='.'&&tmp[1]=='/') {
-		tmp+=2;
-	}
-	/* vfs_GetWd() seems to return a path with a slash */
-	if (ending_slash) {
-		return talloc_asprintf(ctx, "%s/%s/",
-				       vfs_GetWd(ctx, handle->conn),tmp);
-	}
-	return talloc_asprintf(ctx, "%s/%s",
-			       vfs_GetWd(ctx, handle->conn),tmp);
-}
-
-static int connect_to_scanner(vfs_handle_struct * handle)
-{
-	struct Tscannedonly *so = (struct Tscannedonly *)handle->data;
-
-	if (so->domain_socket) {
-		struct sockaddr_un saun;
-		DEBUG(SCANNEDONLY_DEBUG, ("socket=%s\n", so->socketname));
-		if ((so->socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
-			DEBUG(2, ("failed to create socket %s\n",
-				  so->socketname));
-			return -1;
-		}
-		saun.sun_family = AF_UNIX;
-		strncpy(saun.sun_path, so->socketname,
-			sizeof(saun.sun_path) - 1);
-		if (connect(so->socket, (struct sockaddr *)(void *)&saun,
-			    SUN_LEN(&saun)) < 0) {
-			DEBUG(2, ("failed to connect to socket %s\n",
-				  so->socketname));
-			return -1;
-		}
-		DEBUG(SCANNEDONLY_DEBUG,("bound %s to socket %d\n",
-					 saun.sun_path, so->socket));
-
-	} else {
-		so->socket = open_udp_socket(so->scanhost, so->portnum);
-		if (so->socket < 0) {
-			DEBUG(2,("failed to open UDP socket to %s:%d\n",
-				 so->scanhost,so->portnum));
-			return -1;
-		}
-	}
-
-	{/* increasing the socket buffer is done because we have large bursts
-	    of UDP packets or DGRAM's on a domain socket whenever we hit a
-	    large directory with lots of unscanned files. */
-		int sndsize;
-		socklen_t size = sizeof(int);
-		if (getsockopt(so->socket, SOL_SOCKET, SO_RCVBUF,
-			       (char *)&sndsize, &size) == 0) {
-			DEBUG(SCANNEDONLY_DEBUG,
-			      ("current socket buffer size=%d\n",
-			       sndsize));
-		}
-		sndsize = 262144;
-		if (setsockopt(so->socket, SOL_SOCKET, SO_RCVBUF,
-			       (char *)&sndsize,
-			       (int)sizeof(sndsize)) != 0) {
-			DEBUG(SCANNEDONLY_DEBUG,
-			      ("error setting socket buffer %s (%d)\n",
-			       strerror(errno), errno));
-		}
-	}
-	set_blocking(so->socket, false);
-	return 0;
-}
-
-static void flush_sendbuffer(vfs_handle_struct * handle)
-{
-	struct Tscannedonly *so = (struct Tscannedonly *)handle->data;
-	int ret, len, loop = 10;
-	if (so->gsendbuffer[0] == '\0') {
-		return;
-	}
-
-	do {
-		loop--;
-		len = strlen(so->gsendbuffer);
-		ret = send(so->socket, so->gsendbuffer, len, 0);
-		if (ret == len) {
-			so->gsendbuffer[0] = '\0';
-			break;
-		}
-		if (ret == -1) {
-			DEBUG(3,("scannedonly flush_sendbuffer: "
-				 "error sending on socket %d to scanner:"
-				 " %s (%d)\n",
-				 so->socket, strerror(errno), errno));
-			if (errno == ECONNREFUSED || errno == ENOTCONN
-			    || errno == ECONNRESET) {
-				if (connect_to_scanner(handle) == -1)
-					break;	/* connecting fails, abort */
-				/* try again */
-			} else if (errno != EINTR) {
-				/* on EINTR we just try again, all remaining
-				   other errors we log the error
-				   and try again ONCE */
-				loop = 1;
-				DEBUG(3,("scannedonly flush_sendbuffer: "
-					 "error sending data to scanner: %s "
-					 "(%d)\n", strerror(errno), errno));
-			}
-		} else {
-			/* --> partial write: Resend all filenames that were
-			   not or not completely written. a partial filename
-			   written means the filename will not arrive correctly,
-			   so resend it completely */
-			int pos = 0;
-			while (pos < len) {
-				char *tmp = strchr(so->gsendbuffer+pos, '\n');
-				if (tmp && tmp - so->gsendbuffer < ret)
-					pos = tmp - so->gsendbuffer + 1;
-				else
-					break;
-			}
-			memmove(so->gsendbuffer, so->gsendbuffer + pos,
-				SENDBUFFERSIZE - ret);
-			/* now try again */
-		}
-	} while (loop > 0);
-
-	if (so->gsendbuffer[0] != '\0') {
-		DEBUG(2,
-		      ("scannedonly flush_sendbuffer: "
-		       "failed to send files to AV scanner, "
-		       "discarding files."));
-		so->gsendbuffer[0] = '\0';
-	}
-}
-
-static void notify_scanner(vfs_handle_struct * handle, const char *scanfile)
-{
-	const char *tmp;
-	int tmplen, gsendlen;
-	struct Tscannedonly *so = (struct Tscannedonly *)handle->data;
-	TALLOC_CTX *ctx=talloc_tos();
-	if (scanfile[0] != '/') {
-		tmp = construct_full_path(ctx,handle, scanfile, false);
-	} else {
-		tmp = (const char *)scanfile;
-	}
-	tmplen = strlen(tmp);
-	gsendlen = strlen(so->gsendbuffer);
-	DEBUG(SCANNEDONLY_DEBUG,
-	      ("scannedonly notify_scanner: tmp=%s, tmplen=%d, gsendlen=%d\n",
-	       tmp, tmplen, gsendlen));
-	if (gsendlen + tmplen >= SENDBUFFERSIZE) {
-		flush_sendbuffer(handle);
-	}
-	/* FIXME ! Truncate checks... JRA. */
-	(void)strlcat(so->gsendbuffer, tmp, SENDBUFFERSIZE + 1);
-	(void)strlcat(so->gsendbuffer, "\n", SENDBUFFERSIZE + 1);
-}
-
-static bool is_scannedonly_file(struct Tscannedonly *so, const char *shortname)
-{
-	if (shortname[0]!='.') {
-		return false;
-	}
-	if (strncmp(shortname, so->p_scanned, strlen(so->p_scanned)) == 0) {
-		return true;
-	}
-	if (strncmp(shortname, so->p_virus, strlen(so->p_virus)) == 0) {
-		return true;
-	}
-	if (strncmp(shortname, so->p_failed, strlen(so->p_failed)) == 0) {
-		return true;
-	}
-	return false;
-}
-
-static bool timespec_is_newer(struct timespec *base, struct timespec *test)
-{
-	return timespec_compare(base,test) < 0;
-}
-
-/*
-vfs_handle_struct *handle the scannedonly handle
-scannedonly_DIR * sDIR the scannedonly struct if called from _readdir()
-or NULL
-fullpath is a full path starting from / or a relative path to the
-current working directory
-shortname is the filename without directory components
-basename, is the directory without file name component
-allow_nonexistent return TRUE if stat() on the requested file fails
-recheck_time, the time in milliseconds to wait for the daemon to
-create a .scanned file
-recheck_tries, the number of tries to wait
-recheck_size, size in Kb of files that should not be waited for
-loop : boolean if we should try to loop over all files in the directory
-and send a notify to the scanner for all files that need scanning
-*/
-static bool scannedonly_allow_access(vfs_handle_struct * handle,
-				     struct scannedonly_DIR *sDIR,
-				     struct smb_filename *smb_fname,
-				     const char *shortname,
-				     const char *base_name,
-				     int allow_nonexistent,
-				     int recheck_time, int recheck_tries,
-				     int recheck_size, int loop)
-{
-	struct smb_filename *cache_smb_fname;
-	TALLOC_CTX *ctx=talloc_tos();
-	char *cachefile;
-	int retval = -1;
-	DEBUG(SCANNEDONLY_DEBUG,
-	      ("smb_fname->base_name=%s, shortname=%s, base_name=%s\n"
-	       ,smb_fname->base_name,shortname,base_name));
-
-	if (ISDOT(shortname) || ISDOTDOT(shortname)) {
-		return true;
-	}
-	if (is_scannedonly_file(STRUCTSCANO(handle->data), shortname)) {
-		DEBUG(SCANNEDONLY_DEBUG,
-		      ("scannedonly_allow_access, %s is a scannedonly file, "
-		       "return 0\n", shortname));
-		return false;
-	}
-
-	if (!VALID_STAT(smb_fname->st)) {
-		DEBUG(SCANNEDONLY_DEBUG,("stat %s\n",smb_fname->base_name));
-		retval = SMB_VFS_NEXT_STAT(handle, smb_fname);
-		if (retval != 0) {
-			/* failed to stat this file?!? --> hide it */
-			DEBUG(SCANNEDONLY_DEBUG,("no valid stat, return"
-						 " allow_nonexistent=%d\n",
-						 allow_nonexistent));
-			return allow_nonexistent;
-		}
-	}
-	if (!S_ISREG(smb_fname->st.st_ex_mode)) {
-		DEBUG(SCANNEDONLY_DEBUG,
-		      ("%s is not a regular file, ISDIR=%d\n",
-		       smb_fname->base_name,
-		       S_ISDIR(smb_fname->st.st_ex_mode)));
-		return (STRUCTSCANO(handle->data)->
-			show_special_files ||
-			S_ISDIR(smb_fname->st.st_ex_mode));
-	}
-	if (smb_fname->st.st_ex_size == 0) {
-		DEBUG(SCANNEDONLY_DEBUG,("empty file, return 1\n"));
-		return true;	/* empty files cannot contain viruses ! */
-	}
-	cachefile = cachefile_name(ctx,
-				   shortname,
-				   base_name,
-				   STRUCTSCANO(handle->data)->p_scanned);
-	cache_smb_fname = synthetic_smb_fname(ctx, cachefile,NULL,NULL);
-	if (!VALID_STAT(cache_smb_fname->st)) {
-		retval = SMB_VFS_NEXT_STAT(handle, cache_smb_fname);
-	}
-	if (retval == 0 && VALID_STAT(cache_smb_fname->st)) {
-		if (timespec_is_newer(&smb_fname->st.st_ex_ctime,
-				      &cache_smb_fname->st.st_ex_ctime)) {
-			talloc_free(cache_smb_fname);
-			return true;
-		}
-		/* no cachefile or too old */
-		SMB_VFS_NEXT_UNLINK(handle, cache_smb_fname);
-		retval = -1;
-	}
-
-	notify_scanner(handle, smb_fname->base_name);
-
-	if (loop && sDIR && sDIR->recheck_tries_done == 0) {
-		/* check the rest of the directory and notify the
-		   scanner if some file needs scanning */
-		long offset;
-		struct dirent *dire;
-
-		offset = SMB_VFS_NEXT_TELLDIR(handle, sDIR->DIR);
-		dire = SMB_VFS_NEXT_READDIR(handle, sDIR->DIR, NULL);
-		while (dire) {
-			char *fpath2;
-			struct smb_filename *smb_fname2;
-			fpath2 = talloc_asprintf(ctx, "%s%s", base_name,dire->d_name);
-			DEBUG(SCANNEDONLY_DEBUG,
-			      ("scannedonly_allow_access in loop, "
-			       "found %s\n", fpath2));
-			smb_fname2 = synthetic_smb_fname(
-				ctx, fpath2,NULL,NULL);
-			scannedonly_allow_access(handle, NULL,
-						 smb_fname2,
-						 dire->d_name,
-						 base_name, 0, 0, 0, 0, 0);
-			talloc_free(fpath2);
-			talloc_free(smb_fname2);
-			dire = SMB_VFS_NEXT_READDIR(handle, sDIR->DIR,NULL);
-		}
-		sDIR->recheck_tries_done = 1;
-		SMB_VFS_NEXT_SEEKDIR(handle, sDIR->DIR, offset);
-	}
-	if (recheck_time > 0
-	    && ((recheck_size > 0
-		 && smb_fname->st.st_ex_size < (1024 * recheck_size))
-		 || (sDIR && sDIR->recheck_tries_done < recheck_tries)
-		)) {
-		int numloops = sDIR ? sDIR->recheck_tries_done : 0;
-		flush_sendbuffer(handle);
-		while (retval != 0	/*&& errno == ENOENT */
-		       && numloops < recheck_tries) {
-			DEBUG(SCANNEDONLY_DEBUG,
-			      ("scannedonly_allow_access, wait (try=%d "
-			       "(max %d), %d ms) for %s\n",
-			       numloops, recheck_tries,
-			       recheck_time, cache_smb_fname->base_name));
-			smb_msleep(recheck_time);
-			retval = SMB_VFS_NEXT_STAT(handle, cache_smb_fname);
-			numloops++;
-		}
-		if (sDIR)
-			sDIR->recheck_tries_done = numloops;
-	}
-	/* still no cachefile, or still too old, return 0 */
-	if (retval != 0
-	    || !timespec_is_newer(&smb_fname->st.st_ex_ctime,
-				  &cache_smb_fname->st.st_ex_ctime)) {
-		DEBUG(SCANNEDONLY_DEBUG,
-		      ("retval=%d, return 0\n",retval));
-		return false;
-	}
-	return true;
-}
-
-/*********************/
-/* VFS functions     */
-/*********************/
-
-static DIR *scannedonly_opendir(vfs_handle_struct * handle,
-					   const char *fname,
-					   const char *mask, uint32_t attr)
-{
-	DIR *DIRp;
-	struct scannedonly_DIR *sDIR;
-
-	DIRp = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
-	if (!DIRp) {
-		return NULL;
-	}
-
-	sDIR = talloc(NULL, struct scannedonly_DIR);
-	if (fname[0] != '/') {
-		sDIR->base = construct_full_path(sDIR,handle, fname, true);
-	} else {
-		sDIR->base = name_w_ending_slash(sDIR, fname);
-	}
-	DEBUG(SCANNEDONLY_DEBUG,
-			("scannedonly_opendir, fname=%s, base=%s\n",fname,sDIR->base));
-	sDIR->DIR = DIRp;
-	sDIR->recheck_tries_done = 0;
-	return (DIR *) sDIR;
-}
-
-static DIR *scannedonly_fdopendir(vfs_handle_struct * handle,
-					   files_struct *fsp,
-					   const char *mask, uint32_t attr)
-{
-	DIR *DIRp;
-	struct scannedonly_DIR *sDIR;
-	const char *fname;
-
-	DIRp = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
-	if (!DIRp) {
-		return NULL;
-	}
-
-	fname = (const char *)fsp->fsp_name->base_name;
-
-	sDIR = talloc(NULL, struct scannedonly_DIR);
-	if (fname[0] != '/') {
-		sDIR->base = construct_full_path(sDIR,handle, fname, true);
-	} else {
-		sDIR->base = name_w_ending_slash(sDIR, fname);
-	}
-	DEBUG(SCANNEDONLY_DEBUG,
-			("scannedonly_fdopendir, fname=%s, base=%s\n",fname,sDIR->base));
-	sDIR->DIR = DIRp;
-	sDIR->recheck_tries_done = 0;
-	return (DIR *) sDIR;
-}
-
-
-static struct dirent *scannedonly_readdir(vfs_handle_struct *handle,
-					      DIR * dirp,
-					      SMB_STRUCT_STAT *sbuf)
-{
-	struct dirent *result;
-	int allowed = 0;
-	char *tmp;
-	struct smb_filename *smb_fname;
-	char *notify_name;
-	int namelen;
-	struct dirent *newdirent;
-	TALLOC_CTX *ctx=talloc_tos();
-
-	struct scannedonly_DIR *sDIR = (struct scannedonly_DIR *)dirp;
-	if (!dirp) {
-		return NULL;
-	}
-
-	result = SMB_VFS_NEXT_READDIR(handle, sDIR->DIR, sbuf);
-
-	if (!result)
-		return NULL;
-
-	if (is_scannedonly_file(STRUCTSCANO(handle->data), result->d_name)) {
-		DEBUG(SCANNEDONLY_DEBUG,
-		      ("scannedonly_readdir, %s is a scannedonly file, "
-		       "skip to next entry\n", result->d_name));
-		return scannedonly_readdir(handle, dirp, NULL);
-	}
-	tmp = talloc_asprintf(ctx, "%s%s", sDIR->base, result->d_name);
-	DEBUG(SCANNEDONLY_DEBUG,
-	      ("scannedonly_readdir, check access to %s (sbuf=%p)\n",
-	       tmp,sbuf));
-
-	/* even if we don't hide nonscanned files or we allow non scanned
-	   files we call allow_access because it will notify the daemon to
-	   scan these files */
-	smb_fname = synthetic_smb_fname(ctx, tmp,NULL,
-					sbuf?VALID_STAT(*sbuf)?sbuf:NULL:NULL);
-	allowed = scannedonly_allow_access(
-		handle, sDIR, smb_fname,
-		result->d_name,
-		sDIR->base, 0,
-		STRUCTSCANO(handle->data)->hide_nonscanned_files
-		? STRUCTSCANO(handle->data)->recheck_time_readdir
-		: 0,
-		STRUCTSCANO(handle->data)->recheck_tries_readdir,
-		-1,
-		1);
-	DEBUG(SCANNEDONLY_DEBUG,
-	      ("scannedonly_readdir access to %s (%s) = %d\n", tmp,
-	       result->d_name, allowed));
-	if (allowed) {
-		return result;
-	}
-	DEBUG(SCANNEDONLY_DEBUG,
-	      ("hide_nonscanned_files=%d, allow_nonscanned_files=%d\n",
-	       STRUCTSCANO(handle->data)->hide_nonscanned_files,
-	       STRUCTSCANO(handle->data)->allow_nonscanned_files
-		      ));
-
-	if (!STRUCTSCANO(handle->data)->hide_nonscanned_files
-	    || STRUCTSCANO(handle->data)->allow_nonscanned_files) {
-		return result;
-	}
-
-	DEBUG(SCANNEDONLY_DEBUG,
-	      ("scannedonly_readdir, readdir listing for %s not "
-	       "allowed, notify user\n", result->d_name));
-	notify_name = talloc_asprintf(
-		ctx,"%s %s",result->d_name,
-		STRUCTSCANO(handle->data)->scanning_message);
-	namelen = strlen(notify_name);
-	newdirent = (struct dirent *)talloc_array(
-		ctx, char, sizeof(struct dirent) + namelen + 1);
-	if (!newdirent) {
-		return NULL;
-	}
-	memcpy(newdirent, result, sizeof(struct dirent));
-	memcpy(&newdirent->d_name, notify_name, namelen + 1);
-	DEBUG(SCANNEDONLY_DEBUG,
-	      ("scannedonly_readdir, return newdirent at %p with "
-	       "notification %s\n", newdirent, newdirent->d_name));
-	return newdirent;
-}
-
-static void scannedonly_seekdir(struct vfs_handle_struct *handle,
-				DIR * dirp, long offset)
-{
-	struct scannedonly_DIR *sDIR = (struct scannedonly_DIR *)dirp;
-	SMB_VFS_NEXT_SEEKDIR(handle, sDIR->DIR, offset);
-}
-
-static long scannedonly_telldir(struct vfs_handle_struct *handle,
-				DIR * dirp)
-{
-	struct scannedonly_DIR *sDIR = (struct scannedonly_DIR *)dirp;
-	return SMB_VFS_NEXT_TELLDIR(handle, sDIR->DIR);
-}
-
-static void scannedonly_rewinddir(struct vfs_handle_struct *handle,
-				  DIR * dirp)
-{
-	struct scannedonly_DIR *sDIR = (struct scannedonly_DIR *)dirp;
-	SMB_VFS_NEXT_REWINDDIR(handle, sDIR->DIR);
-}
-
-static int scannedonly_closedir(vfs_handle_struct * handle,
-				DIR * dirp)
-{
-	int retval;
-	struct scannedonly_DIR *sDIR = (struct scannedonly_DIR *)dirp;
-	flush_sendbuffer(handle);
-	retval = SMB_VFS_NEXT_CLOSEDIR(handle, sDIR->DIR);
-	TALLOC_FREE(sDIR);
-	return retval;
-}
-
-static int scannedonly_stat(vfs_handle_struct * handle,
-			    struct smb_filename *smb_fname)
-{
-	int ret;
-	ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
-	DEBUG(SCANNEDONLY_DEBUG, ("scannedonly_stat: %s returned %d\n",
-				  smb_fname->base_name, ret));
-	if (ret != 0 && errno == ENOENT) {
-		TALLOC_CTX *ctx=talloc_tos();
-		char *test_base_name, *tmp_base_name = smb_fname->base_name;
-		/* possibly this was a fake name (file is being scanned for
-		   viruses.txt): check for that and create the real name and
-		   stat the real name */
-		test_base_name = real_path_from_notify_path(
-			ctx,
-			STRUCTSCANO(handle->data),
-			smb_fname->base_name);
-		if (test_base_name) {
-			smb_fname->base_name = test_base_name;
-			ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
-			DEBUG(5, ("_stat: %s returned %d\n",
-				  test_base_name, ret));
-			smb_fname->base_name = tmp_base_name;
-		}
-	}
-	return ret;
-}
-
-static int scannedonly_lstat(vfs_handle_struct * handle,
-			     struct smb_filename *smb_fname)
-{
-	int ret;
-	ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-	DEBUG(SCANNEDONLY_DEBUG, ("scannedonly_lstat: %s returned %d\n",
-				  smb_fname->base_name, ret));
-	if (ret != 0 && errno == ENOENT) {
-		TALLOC_CTX *ctx=talloc_tos();
-		char *test_base_name, *tmp_base_name = smb_fname->base_name;
-		/* possibly this was a fake name (file is being scanned for
-		   viruses.txt): check for that and create the real name and
-		   stat the real name */
-		test_base_name = real_path_from_notify_path(
-			ctx, STRUCTSCANO(handle->data), smb_fname->base_name);
-		if (test_base_name) {
-			smb_fname->base_name = test_base_name;
-			ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-			DEBUG(5, ("_lstat: %s returned %d\n",
-				  test_base_name, ret));
-			smb_fname->base_name = tmp_base_name;
-		}
-	}
-	return ret;
-}
-
-static int scannedonly_open(vfs_handle_struct * handle,
-			    struct smb_filename *smb_fname,
-			    files_struct * fsp, int flags, mode_t mode)
-{
-	const char *base;
-	char *tmp, *shortname;
-	int allowed, write_access = 0;
-	TALLOC_CTX *ctx=talloc_tos();
-	/* if open for writing ignore it */
-	if ((flags & O_ACCMODE) == O_WRONLY) {
-		return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
-	}
-	if ((flags & O_ACCMODE) == O_RDWR) {
-		write_access = 1;
-	}
-	/* check if this file is scanned already */
-	tmp = strrchr(smb_fname->base_name, '/');
-	if (tmp) {
-		base = talloc_strndup(ctx,smb_fname->base_name,
-				      (tmp - smb_fname->base_name) + 1);
-		shortname = tmp + 1;
-	} else {
-		base = "";
-		shortname = (char *)smb_fname->base_name;
-	}
-	allowed = scannedonly_allow_access(
-		handle, NULL, smb_fname, shortname,
-		base,
-		write_access,
-		STRUCTSCANO(handle->data)->recheck_time_open,
-		STRUCTSCANO(handle->data)->recheck_tries_open,
-		STRUCTSCANO(handle->data)->recheck_size_open,
-		0);
-	flush_sendbuffer(handle);
-	DEBUG(SCANNEDONLY_DEBUG, ("scannedonly_open: allow=%d for %s\n",
-				  allowed, smb_fname->base_name));
-	if (allowed
-	    || STRUCTSCANO(handle->data)->allow_nonscanned_files) {
-		return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
-	}
-	errno = EACCES;
-	return -1;
-}
-
-static int scannedonly_close(vfs_handle_struct * handle, files_struct * fsp)
-{
-	/* we only have to notify the scanner
-	   for files that were open readwrite or writable. */
-	if (fsp->can_write) {
-		TALLOC_CTX *ctx = talloc_tos();
-		notify_scanner(handle, construct_full_path(
-				       ctx,handle,
-				       fsp->fsp_name->base_name,false));
-		flush_sendbuffer(handle);
-	}
-	return SMB_VFS_NEXT_CLOSE(handle, fsp);
-}
-
-static int scannedonly_rename(vfs_handle_struct * handle,
-			      const struct smb_filename *smb_fname_src,
-			      const struct smb_filename *smb_fname_dst)
-{
-	/* rename the cache file before we pass the actual rename on */
-	struct smb_filename *smb_fname_src_tmp = NULL;
-	struct smb_filename *smb_fname_dst_tmp = NULL;
-	char *cachefile_src, *cachefile_dst;
-	bool needscandst=false;
-	int ret;
-	TALLOC_CTX *ctx = talloc_tos();
-
-	/* Setup temporary smb_filename structs. */
-	cachefile_src = cachefile_name_f_fullpath(
-		ctx,
-		smb_fname_src->base_name,
-		STRUCTSCANO(handle->data)->p_scanned);
-	cachefile_dst =	cachefile_name_f_fullpath(
-		ctx,
-		smb_fname_dst->base_name,
-		STRUCTSCANO(handle->data)->p_scanned);
-	smb_fname_src_tmp = synthetic_smb_fname(ctx, cachefile_src,NULL,NULL);
-	smb_fname_dst_tmp = synthetic_smb_fname(ctx, cachefile_dst,NULL,NULL);
-
-	ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_tmp, smb_fname_dst_tmp);
-	if (ret == ENOENT) {
-		needscandst=true;
-	} else if (ret != 0) {
-		DEBUG(SCANNEDONLY_DEBUG,
-		      ("failed to rename %s into %s error %d: %s\n", cachefile_src,
-		       cachefile_dst, ret, strerror(ret)));
-		needscandst=true;
-	}
-	ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
-	if (ret == 0 && needscandst) {
-		notify_scanner(handle, smb_fname_dst->base_name);
-		flush_sendbuffer(handle);
-	}
-	return ret;
-}
-
-static int scannedonly_unlink(vfs_handle_struct * handle,
-			      const struct smb_filename *smb_fname)
-{
-	/* unlink the 'scanned' file too */
-	struct smb_filename *smb_fname_cache = NULL;
-	char * cachefile;
-	TALLOC_CTX *ctx = talloc_tos();
-
-	cachefile = cachefile_name_f_fullpath(
-		ctx,
-		smb_fname->base_name,
-		STRUCTSCANO(handle->data)->p_scanned);
-	smb_fname_cache = synthetic_smb_fname(ctx, cachefile,NULL,NULL);
-	if (SMB_VFS_NEXT_UNLINK(handle, smb_fname_cache) != 0) {
-		DEBUG(SCANNEDONLY_DEBUG, ("_unlink: failed to unlink %s\n",
-					  smb_fname_cache->base_name));
-	}
-	return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
-}
-
-static int scannedonly_rmdir(vfs_handle_struct * handle, const char *path)
-{
-	/* if there are only .scanned: .virus: or .failed: files, we delete
-	   those, because the client cannot see them */
-	DIR *dirp;
-	struct dirent *dire;
-	TALLOC_CTX *ctx = talloc_tos();
-	bool only_deletable_files = true, have_files = false;
-	char *path_w_slash;
-
-	if (!STRUCTSCANO(handle->data)->rm_hidden_files_on_rmdir)
-		return SMB_VFS_NEXT_RMDIR(handle, path);
-
-	path_w_slash = name_w_ending_slash(ctx,path);
-	dirp = SMB_VFS_NEXT_OPENDIR(handle, path, NULL, 0);
-	if (!dirp) {
-		return -1;
-	}
-	while ((dire = SMB_VFS_NEXT_READDIR(handle, dirp, NULL)) != NULL) {
-		if (ISDOT(dire->d_name) || ISDOTDOT(dire->d_name)) {
-			continue;
-		}
-		have_files = true;
-		if (!is_scannedonly_file(STRUCTSCANO(handle->data),
-					 dire->d_name)) {
-			struct smb_filename *smb_fname = NULL;
-			char *fullpath;
-			int retval;
-
-			if (STRUCTSCANO(handle->data)->show_special_files) {
-				only_deletable_files = false;
-				break;
-			}
-			/* stat the file and see if it is a
-			   special file */
-			fullpath = talloc_asprintf(ctx, "%s%s", path_w_slash,
-						  dire->d_name);
-			smb_fname = synthetic_smb_fname(ctx, fullpath,
-							NULL,NULL);
-			retval = SMB_VFS_NEXT_STAT(handle, smb_fname);
-			if (retval == 0
-			    && S_ISREG(smb_fname->st.st_ex_mode)) {
-				only_deletable_files = false;
-			}
-			TALLOC_FREE(fullpath);
-			TALLOC_FREE(smb_fname);
-			break;
-		}
-	}
-	DEBUG(SCANNEDONLY_DEBUG,
-	      ("path=%s, have_files=%d, only_deletable_files=%d\n",
-	       path, have_files, only_deletable_files));
-	if (have_files && only_deletable_files) {
-		DEBUG(SCANNEDONLY_DEBUG,
-		      ("scannedonly_rmdir, remove leftover scannedonly "
-		       "files from %s\n", path_w_slash));
-		SMB_VFS_NEXT_REWINDDIR(handle, dirp);
-		while ((dire = SMB_VFS_NEXT_READDIR(handle, dirp, NULL))
-		       != NULL) {
-			char *fullpath;
-			struct smb_filename *smb_fname = NULL;
-			if (ISDOT(dire->d_name) || ISDOTDOT(dire->d_name)) {
-				continue;
-			}
-			fullpath = talloc_asprintf(ctx, "%s%s", path_w_slash,
-						  dire->d_name);
-			smb_fname = synthetic_smb_fname(ctx, fullpath,
-							NULL,NULL);
-			DEBUG(SCANNEDONLY_DEBUG, ("unlink %s\n", fullpath));
-			SMB_VFS_NEXT_UNLINK(handle, smb_fname);
-			TALLOC_FREE(fullpath);
-			TALLOC_FREE(smb_fname);
-		}
-	}
-	SMB_VFS_NEXT_CLOSEDIR(handle, dirp);
-	return SMB_VFS_NEXT_RMDIR(handle, path);
-}
-
-static void free_scannedonly_data(void **data)
-{
-	SAFE_FREE(*data);
-}
-
-static int scannedonly_connect(struct vfs_handle_struct *handle,
-			       const char *service, const char *user)
-{
-
-	struct Tscannedonly *so;
-
-	so = SMB_MALLOC_P(struct Tscannedonly);
-	if (so == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-	handle->data = (void *)so;
-	handle->free_data = free_scannedonly_data;
-	so->gsendbuffer[0]='\0';
-	so->domain_socket =
-		lp_parm_bool(SNUM(handle->conn), "scannedonly",
-			     "domain_socket", True);
-	so->socketname = lp_parm_const_string(SNUM(handle->conn),
-					     "scannedonly", "socketname",
-					     "/var/lib/scannedonly/scan");
-
-	so->portnum =
-		lp_parm_int(SNUM(handle->conn), "scannedonly", "portnum",
-			    2020);
-	so->scanhost = lp_parm_const_string(SNUM(handle->conn),
-					     "scannedonly", "scanhost",
-					     "localhost");
-
-	so->show_special_files =
-		lp_parm_bool(SNUM(handle->conn), "scannedonly",
-			     "show_special_files", True);
-	so->rm_hidden_files_on_rmdir =
-		lp_parm_bool(SNUM(handle->conn), "scannedonly",
-			     "rm_hidden_files_on_rmdir", True);
-	so->hide_nonscanned_files =
-		lp_parm_bool(SNUM(handle->conn), "scannedonly",
-			     "hide_nonscanned_files", False);
-	so->allow_nonscanned_files =
-		lp_parm_bool(SNUM(handle->conn), "scannedonly",
-			     "allow_nonscanned_files", False);
-	so->scanning_message = lp_parm_const_string(SNUM(handle->conn),
-					     "scannedonly",
-					     "scanning_message",
-					     "is being scanned for viruses");
-	so->scanning_message_len = strlen(so->scanning_message);
-	so->recheck_time_open =
-		lp_parm_int(SNUM(handle->conn), "scannedonly",
-			    "recheck_time_open", 50);
-	so->recheck_tries_open =
-		lp_parm_int(SNUM(handle->conn), "scannedonly",
-			    "recheck_tries_open", 100);
-	so->recheck_size_open =
-		lp_parm_int(SNUM(handle->conn), "scannedonly",
-			    "recheck_size_open", 100);
-	so->recheck_time_readdir =
-		lp_parm_int(SNUM(handle->conn), "scannedonly",
-			    "recheck_time_readdir", 50);
-	so->recheck_tries_readdir =
-		lp_parm_int(SNUM(handle->conn), "scannedonly",
-			    "recheck_tries_readdir", 20);
-
-	so->p_scanned =
-		lp_parm_const_string(SNUM(handle->conn),
-					     "scannedonly",
-					     "pref_scanned",
-					     ".scanned:");
-	so->p_virus =
-		lp_parm_const_string(SNUM(handle->conn),
-					     "scannedonly",
-					     "pref_virus",
-					     ".virus:");
-	so->p_failed =
-		lp_parm_const_string(SNUM(handle->conn),
-					     "scannedonly",
-					     "pref_failed",
-					     ".failed:");
-	connect_to_scanner(handle);
-
-	return SMB_VFS_NEXT_CONNECT(handle, service, user);
-}
-
-/* VFS operations structure */
-static struct vfs_fn_pointers vfs_scannedonly_fns = {
-	.opendir_fn = scannedonly_opendir,
-	.fdopendir_fn = scannedonly_fdopendir,
-	.readdir_fn = scannedonly_readdir,
-	.seekdir_fn = scannedonly_seekdir,
-	.telldir_fn = scannedonly_telldir,
-	.rewind_dir_fn = scannedonly_rewinddir,
-	.closedir_fn = scannedonly_closedir,
-	.rmdir_fn = scannedonly_rmdir,
-	.stat_fn = scannedonly_stat,
-	.lstat_fn = scannedonly_lstat,
-	.open_fn = scannedonly_open,
-	.close_fn = scannedonly_close,
-	.rename_fn = scannedonly_rename,
-	.unlink_fn = scannedonly_unlink,
-	.connect_fn = scannedonly_connect
-};
-
-NTSTATUS vfs_scannedonly_init(void)
-{
-	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "scannedonly",
-				&vfs_scannedonly_fns);
-}
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 7ecdda5..61ef5d4 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -45,9 +45,8 @@ struct shadow_copy2_config {
 	bool fixinodes;
 	char *sort_order;
 	bool snapdir_absolute;
-	char *basedir;
 	char *mount_point;
-	char *rel_connectpath; /* share root, relative to the basedir */
+	char *rel_connectpath; /* share root, relative to a snapshot root */
 	char *snapshot_basepath; /* the absolute version of snapdir */
 };
 
@@ -1865,6 +1864,39 @@ static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
 	return ret;
 }
 
+static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path,
+				  enum SMB_QUOTA_TYPE qtype, unid_t id,
+				  SMB_DISK_QUOTA *dq)
+{
+	time_t timestamp;
+	char *stripped;
+	int ret;
+	int saved_errno;
+	char *conv;
+
+	if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, &timestamp,
+					 &stripped)) {
+		return -1;
+	}
+	if (timestamp == 0) {
+		return SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, dq);
+	}
+
+	conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
+	TALLOC_FREE(stripped);
+	if (conv == NULL) {
+		return -1;
+	}
+
+	ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv, qtype, id, dq);
+
+	saved_errno = errno;
+	TALLOC_FREE(conv);
+	errno = saved_errno;
+
+	return ret;
+}
+
 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 				const char *service, const char *user)
 {
@@ -1873,7 +1905,8 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 	const char *snapdir;
 	const char *gmt_format;
 	const char *sort_order;
-	const char *basedir;
+	const char *basedir = NULL;
+	const char *snapsharepath = NULL;
 	const char *mount_point;
 
 	DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
@@ -1928,6 +1961,11 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 						"shadow", "crossmountpoints",
 						false);
 
+	if (config->crossmountpoints && !config->snapdirseverywhere) {
+		DBG_WARNING("Warning: 'crossmountpoints' depends on "
+			    "'snapdirseverywhere'. Disabling crossmountpoints.\n");
+	}
+
 	config->fixinodes = lp_parm_bool(SNUM(handle->conn),
 					 "shadow", "fixinodes",
 					 false);
@@ -1954,11 +1992,12 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 			char *p;
 			p = strstr(handle->conn->connectpath, mount_point);
 			if (p != handle->conn->connectpath) {
-				DEBUG(1, ("Warning: mount_point (%s) is not a "
-					  "subdirectory of the share root "
-					  "(%s). Ignoring provided value.\n",
-					  mount_point,
-					  handle->conn->connectpath));
+				DBG_WARNING("Warning: the share root (%s) is "
+					    "not a subdirectory of the "
+					    "specified mountpoint (%s). "
+					    "Ignoring provided value.\n",
+					    handle->conn->connectpath,
+					    mount_point);
 				mount_point = NULL;
 			}
 		}
@@ -1990,6 +2029,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 				  "relative ('%s'), but it has to be an "
 				  "absolute path. Disabling basedir.\n",
 				  basedir));
+			basedir = NULL;
 		} else {
 			char *p;
 			p = strstr(basedir, config->mount_point);
@@ -1999,37 +2039,58 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 					  "mount point (%s). "
 					  "Disabling basedir\n",
 					  basedir, config->mount_point));
-			} else {
-				config->basedir = talloc_strdup(config,
-								basedir);
-				if (config->basedir == NULL) {
-					DEBUG(0, ("talloc_strdup() failed\n"));
-					errno = ENOMEM;
-					return -1;
-				}
+				basedir = NULL;
 			}
 		}
 	}
 
-	if (config->snapdirseverywhere && config->basedir != NULL) {
+	if (config->snapdirseverywhere && basedir != NULL) {
 		DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
 			  "with 'snapdirseverywhere'. Disabling basedir.\n"));
-		TALLOC_FREE(config->basedir);
+		basedir = NULL;
+	}
+
+	snapsharepath = lp_parm_const_string(SNUM(handle->conn), "shadow",
+					     "snapsharepath", NULL);
+	if (snapsharepath != NULL) {
+		if (snapsharepath[0] == '/') {
+			DBG_WARNING("Warning: 'snapsharepath' is "
+				    "absolute ('%s'), but it has to be a "
+				    "relative path. Disabling snapsharepath.\n",
+				    snapsharepath);
+			snapsharepath = NULL;
+		}
+		if (config->snapdirseverywhere && snapsharepath != NULL) {
+			DBG_WARNING("Warning: 'snapsharepath' is incompatible "
+				    "with 'snapdirseverywhere'. Disabling "
+				    "snapsharepath.\n");
+			snapsharepath = NULL;
+		}
 	}
 
-	if (config->crossmountpoints && config->basedir != NULL) {
-		DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
-			  "with 'crossmountpoints'. Disabling basedir.\n"));
-		TALLOC_FREE(config->basedir);
+	if (basedir != NULL && snapsharepath != NULL) {
+		DBG_WARNING("Warning: 'snapsharepath' is incompatible with "
+			    "'basedir'. Disabling snapsharepath\n");
+		snapsharepath = NULL;
+	}
+
+	if (snapsharepath != NULL) {
+		config->rel_connectpath = talloc_strdup(config, snapsharepath);
+		if (config->rel_connectpath == NULL) {
+			DBG_ERR("talloc_strdup() failed\n");
+			errno = ENOMEM;
+			return -1;
+		}
 	}
 
-	if (config->basedir == NULL) {
-		config->basedir = config->mount_point;
+	if (basedir == NULL) {
+		basedir = config->mount_point;
 	}
 
-	if (strlen(config->basedir) != strlen(handle->conn->connectpath)) {
+	if (config->rel_connectpath == NULL &&
+	    strlen(basedir) != strlen(handle->conn->connectpath)) {
 		config->rel_connectpath = talloc_strdup(config,
-			handle->conn->connectpath + strlen(config->basedir));
+			handle->conn->connectpath + strlen(basedir));
 		if (config->rel_connectpath == NULL) {
 			DEBUG(0, ("talloc_strdup() failed\n"));
 			errno = ENOMEM;
@@ -2067,7 +2128,6 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 
 	DEBUG(10, ("shadow_copy2_connect: configuration:\n"
 		   "  share root: '%s'\n"
-		   "  basedir: '%s'\n"
 		   "  mountpoint: '%s'\n"
 		   "  rel share root: '%s'\n"
 		   "  snapdir: '%s'\n"
@@ -2080,7 +2140,6 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 		   "  sort order: %s\n"
 		   "",
 		   handle->conn->connectpath,
-		   config->basedir,
 		   config->mount_point,
 		   config->rel_connectpath,
 		   config->snapdir,
@@ -2105,6 +2164,7 @@ static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
 	.connect_fn = shadow_copy2_connect,
 	.opendir_fn = shadow_copy2_opendir,
 	.disk_free_fn = shadow_copy2_disk_free,
+	.get_quota_fn = shadow_copy2_get_quota,
 	.rename_fn = shadow_copy2_rename,
 	.link_fn = shadow_copy2_link,
 	.symlink_fn = shadow_copy2_symlink,
diff --git a/source3/modules/vfs_smb_traffic_analyzer.c b/source3/modules/vfs_smb_traffic_analyzer.c
deleted file mode 100644
index f32d064..0000000
--- a/source3/modules/vfs_smb_traffic_analyzer.c
+++ /dev/null
@@ -1,946 +0,0 @@
-/*
- * traffic-analyzer VFS module. Measure the smb traffic users create
- * on the net.
- *
- * Copyright (C) Holger Hetterich, 2008-2010
- * Copyright (C) Jeremy Allison, 2008
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-#include "smbd/smbd.h"
-#include "../smbd/globals.h"
-#include "../lib/crypto/crypto.h"
-#include "vfs_smb_traffic_analyzer.h"
-#include "../libcli/security/security.h"
-#include "secrets.h"
-#include "../librpc/gen_ndr/ndr_netlogon.h"
-#include "auth.h"
-#include "../lib/tsocket/tsocket.h"
-#include "lib/sys_rw_data.h"
-
-/* abstraction for the send_over_network function */
-enum sock_type {INTERNET_SOCKET = 0, UNIX_DOMAIN_SOCKET};
-
-#define LOCAL_PATHNAME "/var/tmp/stadsocket"
-
-static int vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
-
-static enum sock_type smb_traffic_analyzer_connMode(vfs_handle_struct *handle)
-{
-	connection_struct *conn = handle->conn;
-        const char *Mode;
-        Mode=lp_parm_const_string(SNUM(conn), "smb_traffic_analyzer","mode", \
-			"internet_socket");
-	if (strstr(Mode,"unix_domain_socket")) {
-		return UNIX_DOMAIN_SOCKET;
-	} else {
-		return INTERNET_SOCKET;
-	}
-}
-
-
-/* Connect to an internet socket */
-static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle,
-					const char *name, uint16_t port)
-{
-	/* Create a streaming Socket */
-	int sockfd = -1;
-	struct addrinfo hints;
-	struct addrinfo *ailist = NULL;
-	struct addrinfo *res = NULL;
-	int ret;
-
-	ZERO_STRUCT(hints);
-	/* By default make sure it supports TCP. */
-	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_flags = AI_ADDRCONFIG;
-
-	ret = getaddrinfo(name,
-			NULL,
-			&hints,
-			&ailist);
-
-        if (ret) {
-		DEBUG(3,("smb_traffic_analyzer_connect_inet_socket: "
-			"getaddrinfo failed for name %s [%s]\n",
-                        name,
-                        gai_strerror(ret) ));
-		return -1;
-        }
-
-	DEBUG(3,("smb_traffic_analyzer: Internet socket mode. Hostname: %s,"
-		"Port: %i\n", name, port));
-
-	for (res = ailist; res; res = res->ai_next) {
-		struct sockaddr_storage ss;
-		NTSTATUS status;
-
-		if (!res->ai_addr || res->ai_addrlen == 0) {
-			continue;
-		}
-
-		ZERO_STRUCT(ss);
-		memcpy(&ss, res->ai_addr, res->ai_addrlen);
-
-		status = open_socket_out(&ss, port, 10000, &sockfd);
-		if (NT_STATUS_IS_OK(status)) {
-			break;
-		}
-	}
-
-	if (ailist) {
-		freeaddrinfo(ailist);
-	}
-
-        if (sockfd == -1) {
-		DEBUG(1, ("smb_traffic_analyzer: unable to create "
-			"socket, error is %s",
-			strerror(errno)));
-		return -1;
-	}
-
-	return sockfd;
-}
-
-/* Connect to a unix domain socket */
-static int smb_traffic_analyzer_connect_unix_socket(vfs_handle_struct *handle,
-						const char *name)
-{
-	/* Create the socket to stad */
-	int len, sock;
-	struct sockaddr_un remote;
-
-	DEBUG(7, ("smb_traffic_analyzer_connect_unix_socket: "
-			"Unix domain socket mode. Using %s\n",
-			name ));
-
-	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
-		DEBUG(1, ("smb_traffic_analyzer_connect_unix_socket: "
-			"Couldn't create socket, "
-			"make sure stad is running!\n"));
-		return -1;
-	}
-	remote.sun_family = AF_UNIX;
-	strlcpy(remote.sun_path, name,
-		    sizeof(remote.sun_path));
-	len=strlen(remote.sun_path) + sizeof(remote.sun_family);
-	if (connect(sock, (struct sockaddr *)&remote, len) == -1 ) {
-		DEBUG(1, ("smb_traffic_analyzer_connect_unix_socket: "
-			"Could not connect to "
-			"socket, make sure\nstad is running!\n"));
-		close(sock);
-		return -1;
-	}
-	return sock;
-}
-
-/* Private data allowing shared connection sockets. */
-struct refcounted_sock {
-	struct refcounted_sock *next, *prev;
-	char *name;
-	uint16_t port;
-	int sock;
-	unsigned int ref_count;
-};
-
-
-/**
- * Encryption of a data block with AES
- * TALLOC_CTX *ctx	Talloc context to work on
- * const char *akey	128bit key for the encryption
- * const char *str	Data buffer to encrypt, \0 terminated
- * int *len		Will be set to the length of the
- *			resulting data block
- * The caller has to take care for the memory
- * allocated on the context.
- */
-static char *smb_traffic_analyzer_encrypt( TALLOC_CTX *ctx,
-	const char *akey, const char *str, size_t *len)
-{
-	int s1,s2,h;
-	AES_KEY key;
-	unsigned char filler[17]= "................";
-	char *output;
-	if (akey == NULL) return NULL;
-	AES_set_encrypt_key((const unsigned char *) akey, 128, &key);
-	s1 = strlen(str) / 16;
-	s2 = strlen(str) % 16;
-	memcpy(filler, str + (s1*16), s2);
-	DEBUG(10, ("smb_traffic_analyzer_send_data_socket: created %s"
-		" as filling block.\n", filler));
-
-	*len = ((s1 + 1)*16);
-	output = talloc_array(ctx, char, *len);
-	for (h = 0; h < s1; h++) {
-		AES_encrypt((const unsigned char *) str+(16*h), (unsigned char *)output+16*h,
-			&key);
-	}
-	AES_encrypt(filler, (unsigned char *)(output+(16*h)), &key);
-	*len = (s1*16)+16;
-	return output;
-}
-
-/**
- * Create a v2 header.
- * TALLLOC_CTX *ctx		Talloc context to work on
- * const char *state_flags 	State flag string
- * int len			length of the data block
- */
-static char *smb_traffic_analyzer_create_header( TALLOC_CTX *ctx,
-	const char *state_flags, size_t data_len)
-{
-	char *header = talloc_asprintf( ctx, "V2.%s%017u",
-					state_flags, (unsigned int) data_len);
-	DEBUG(10, ("smb_traffic_analyzer_send_data_socket: created Header:\n"));
-	dump_data(10, (uint8_t *)header, strlen(header));
-	return header;
-}
-
-
-/**
- * Actually send header and data over the network
- * char *header 	Header data
- * char *data		Data Block
- * int dlength		Length of data block
- * int socket
- */
-static void smb_traffic_analyzer_write_data( char *header, char *data,
-			int dlength, int _socket)
-{
-		int len = strlen(header);
-		if (write_data( _socket, header, len) != len) {
-			DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
-						"error sending the header"
-						" over the socket!\n"));
-                }
-		DEBUG(10,("smb_traffic_analyzer_write_data: sending data:\n"));
-		dump_data( 10, (uint8_t *)data, dlength);
-
-                if (write_data( _socket, data, dlength) != dlength) {
-                        DEBUG(1, ("smb_traffic_analyzer_write_data: "
-                                "error sending crypted data to socket!\n"));
-                }
-}
-
-
-/*
- * Anonymize a string if required.
- * TALLOC_CTX *ctx			The talloc context to work on
- * const char *str			The string to anonymize
- * vfs_handle_struct *handle		The handle struct to work on
- *
- * Returns a newly allocated string, either the anonymized one,
- * or a copy of const char *str. The caller has to take care for
- * freeing the allocated memory.
- */
-static char *smb_traffic_analyzer_anonymize( TALLOC_CTX *ctx,
-					const char *str,
-					vfs_handle_struct *handle )
-{
-	const char *total_anonymization;
-	const char *anon_prefix;
-	char *output;
-	total_anonymization=lp_parm_const_string(SNUM(handle->conn),
-					"smb_traffic_analyzer",
-					"total_anonymization", NULL);
-
-	anon_prefix=lp_parm_const_string(SNUM(handle->conn),
-					"smb_traffic_analyzer",
-					"anonymize_prefix", NULL );
-	if (anon_prefix != NULL) {
-		if (total_anonymization != NULL) {
-			output = talloc_asprintf(ctx, "%s",
-					anon_prefix);
-		} else {
-		output = talloc_asprintf(ctx, "%s%i", anon_prefix,
-						str_checksum(str));
-		}
-	} else {
-		output = talloc_asprintf(ctx, "%s", str);
-	}
-
-	return output;
-}
-
-
-/**
- * The marshalling function for protocol v2.
- * TALLOC_CTX *ctx		Talloc context to work on
- * struct tm *tm		tm struct for the timestamp
- * int seconds			milliseconds of the timestamp
- * vfs_handle_struct *handle	vfs_handle_struct
- * char *username		Name of the user
- * int vfs_operation		VFS operation identifier
- * int count			Number of the common data blocks
- * [...] variable args		data blocks taken from the individual
- *				VFS data structures
- *
- * Returns the complete data block to send. The caller has to
- * take care for freeing the allocated buffer.
- */
-static char *smb_traffic_analyzer_create_string( TALLOC_CTX *ctx,
-	struct tm *tm, int seconds, vfs_handle_struct *handle, \
-	char *username, int vfs_operation, int count, ... )
-{
-	
-	va_list ap;
-	char *arg = NULL;
-	int len;
-	char *common_data_count_str = NULL;
-	char *timestr = NULL;
-	char *sidstr = NULL;
-	char *usersid = NULL;
-	char *raddr = NULL;
-	char *buf = NULL;
-	char *vfs_operation_str = NULL;
-	const char *service_name = lp_const_servicename(handle->conn->params->service);
-
-	/*
-	 * first create the data that is transfered with any VFS op
-	 * These are, in the following order:
-	 *(0) number of data to come [6 in v2.0]
-	 * 1.vfs_operation identifier
-	 * 2.username
-	 * 3.user-SID
-	 * 4.affected share
-	 * 5.domain
-	 * 6.timestamp
-	 * 7.IP Addresss of client
-	 */
-
-	/*
-	 * number of common data blocks to come,
-	 * this is a #define in vfs_smb_traffic_anaylzer.h,
-	 * it's length is known at compile time
-	 */
-	common_data_count_str = talloc_strdup( ctx, SMBTA_COMMON_DATA_COUNT);
-	/* vfs operation identifier */
-	vfs_operation_str = talloc_asprintf( common_data_count_str, "%i",
-							vfs_operation);
-	/*
-	 * Handle anonymization. In protocol v2, we have to anonymize
-	 * both the SID and the username. The name is already
-	 * anonymized if needed, by the calling function.
-	 */
-	usersid = dom_sid_string( common_data_count_str,
-		&handle->conn->session_info->security_token->sids[0]);
-
-	sidstr = smb_traffic_analyzer_anonymize(
-		common_data_count_str,
-		usersid,
-		handle);
-
-	raddr = tsocket_address_inet_addr_string(handle->conn->sconn->remote_address,
-						 ctx);
-	if (raddr == NULL) {
-		return NULL;
-	}
-
-	/* time stamp */
-	timestr = talloc_asprintf( common_data_count_str, \
-		"%04d-%02d-%02d %02d:%02d:%02d.%03d", \
-		tm->tm_year+1900, \
-		tm->tm_mon+1, \
-		tm->tm_mday, \
-		tm->tm_hour, \
-		tm->tm_min, \
-		tm->tm_sec, \
-		(int)seconds);
-	len = strlen( timestr );
-	/* create the string of common data */
-	buf = talloc_asprintf(ctx,
-		"%s%04u%s%04u%s%04u%s%04u%s%04u%s%04u%s%04u%s",
-		common_data_count_str,
-		(unsigned int) strlen(vfs_operation_str),
-		vfs_operation_str,
-		(unsigned int) strlen(username),
-		username,
-		(unsigned int) strlen(sidstr),
-		sidstr,
-		(unsigned int) strlen(service_name),
-		service_name,
-		(unsigned int)
-		strlen(handle->conn->session_info->info->domain_name),
-		handle->conn->session_info->info->domain_name,
-		(unsigned int) strlen(timestr),
-		timestr,
-		(unsigned int) strlen(raddr),
-		raddr);
-
-	talloc_free(common_data_count_str);
-
-	/* data blocks depending on the VFS function */	
-	va_start( ap, count );
-	while ( count-- ) {
-		arg = va_arg( ap, char * );
-		/*
-		 *  protocol v2 sends a four byte string
-		 * as a header to each block, including
-		 * the numbers of bytes to come in the
-		 * next string.
-		 */
-		len = strlen( arg );
-		buf = talloc_asprintf_append( buf, "%04u%s", len, arg);
-	}
-	va_end( ap );
-	return buf;
-}
-
-static void smb_traffic_analyzer_send_data(vfs_handle_struct *handle,
-					void *data,
-					enum vfs_id vfs_operation )
-{
-	struct refcounted_sock *rf_sock = NULL;
-	struct timeval tv;
-	time_t tv_sec;
-	struct tm *tm = NULL;
-	int seconds;
-	char *str = NULL;
-	char *username = NULL;
-	char *header = NULL;
-	const char *protocol_version = NULL;
-	bool Write = false;
-	size_t len;
-	size_t size;
-	char *akey, *output;
-
-	/*
-	 * The state flags are part of the header
-	 * and are descripted in the protocol description
-	 * in vfs_smb_traffic_analyzer.h. They begin at byte
-	 * 03 of the header.
-	 */
-	char state_flags[9] = "000000\0";
-
-	/**
-	 * The first byte of the state flag string represents
-	 * the modules protocol subversion number, defined
-	 * in smb_traffic_analyzer.h. smbtatools/smbtad are designed
-	 * to handle not yet implemented protocol enhancements
-	 * by ignoring them. By recognizing the SMBTA_SUBRELEASE
-	 * smbtatools can tell the user to update the client
-	 * software.
-	 */
-	state_flags[0] = SMBTA_SUBRELEASE;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, rf_sock, struct refcounted_sock, return);
-
-	if (rf_sock == NULL || rf_sock->sock == -1) {
-		DEBUG(1, ("smb_traffic_analyzer_send_data: socket is "
-			"closed\n"));
-		return;
-	}
-
-	GetTimeOfDay(&tv);
-	tv_sec = tv.tv_sec;
-	tm = localtime(&tv_sec);
-	if (!tm) {
-		return;
-	}
-	seconds=(float) (tv.tv_usec / 1000);
-
-	/*
-	 * Check if anonymization is required, and if yes do this only for
-	 * the username here, needed vor protocol version 1. In v2 we
-	 * additionally anonymize the SID, which is done in it's marshalling
-	 * function.
-	 */
-	username = smb_traffic_analyzer_anonymize( talloc_tos(),
-			handle->conn->session_info->unix_info->sanitized_username,
-			handle);
-
-	if (!username) {
-		return;
-	}
-
-	protocol_version = lp_parm_const_string(SNUM(handle->conn),
-					"smb_traffic_analyzer",
-					"protocol_version", NULL );
-
-
-	if (protocol_version != NULL && strcmp(protocol_version,"V1") == 0) {
-
-		struct rw_data *s_data = (struct rw_data *) data;
-
-		/*
-		 * in case of protocol v1, ignore any vfs operations
-		 * except read,pread,write,pwrite, and set the "Write"
-		 * bool accordingly, send data and return.
-		 */
-		if ( vfs_operation > vfs_id_pwrite ) return;
-
-		if ( vfs_operation <= vfs_id_pread ) Write=false;
-			else Write=true;
-
-		str = talloc_asprintf(talloc_tos(),
-			"V1,%u,\"%s\",\"%s\",\"%c\",\"%s\",\"%s\","
-			"\"%04d-%02d-%02d %02d:%02d:%02d.%03d\"\n",
-			(unsigned int) s_data->len,
-			username,
-			handle->conn->session_info->info->domain_name,
-			Write ? 'W' : 'R',
-			handle->conn->cwd,
-			s_data->filename,
-			tm->tm_year+1900,
-			tm->tm_mon+1,
-			tm->tm_mday,
-			tm->tm_hour,
-			tm->tm_min,
-			tm->tm_sec,
-			(int)seconds);
-		len = strlen(str);
-		if (write_data(rf_sock->sock, str, len) != len) {
-                	DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
-			"error sending V1 protocol data to socket!\n"));
-		return;
-		}
-
-	} else {
-		/**
-		 * Protocol 2 is used by default.
-		 */
-
-		switch( vfs_operation ) {
-		case vfs_id_open: ;
-			str = smb_traffic_analyzer_create_string( talloc_tos(),
-				tm, seconds, handle, username, vfs_id_open,
-				3, ((struct open_data *) data)->filename,
-				talloc_asprintf( talloc_tos(), "%u",
-				(unsigned int)((struct open_data *) data)->mode),
-				talloc_asprintf( talloc_tos(), "%u",
-				((struct open_data *) data)->result));
-			break;
-		case vfs_id_close: ;
-			str = smb_traffic_analyzer_create_string( talloc_tos(),
-				tm, seconds, handle, username, vfs_id_close,
-				2, ((struct close_data *) data)->filename,
-				talloc_asprintf( talloc_tos(), "%u",
-				((struct close_data *) data)->result));
-			break;
-		case vfs_id_mkdir: ;
-			str = smb_traffic_analyzer_create_string( talloc_tos(),
-				tm, seconds, handle, username, vfs_id_mkdir, \
-				3, ((struct mkdir_data *) data)->path, \
-				talloc_asprintf( talloc_tos(), "%u", \
-				(unsigned int)((struct mkdir_data *) data)->mode), \
-				talloc_asprintf( talloc_tos(), "%u", \
-				((struct mkdir_data *) data)->result ));
-			break;
-		case vfs_id_rmdir: ;
-			str = smb_traffic_analyzer_create_string( talloc_tos(),
-				tm, seconds, handle, username, vfs_id_rmdir,
-				2, ((struct rmdir_data *) data)->path, \
-				talloc_asprintf( talloc_tos(), "%u", \
-				((struct rmdir_data *) data)->result ));
-			break;
-		case vfs_id_rename: ;
-			str = smb_traffic_analyzer_create_string( talloc_tos(),
-				tm, seconds, handle, username, vfs_id_rename,
-				3, ((struct rename_data *) data)->src, \
-				((struct rename_data *) data)->dst,
-				talloc_asprintf(talloc_tos(), "%u", \
-				((struct rename_data *) data)->result));
-			break;
-		case vfs_id_chdir: ;
-			str = smb_traffic_analyzer_create_string( talloc_tos(),
-				tm, seconds, handle, username, vfs_id_chdir,
-				2, ((struct chdir_data *) data)->path, \
-				talloc_asprintf(talloc_tos(), "%u", \
-				((struct chdir_data *) data)->result));
-			break;
-
-		case vfs_id_write:
-		case vfs_id_pwrite:
-		case vfs_id_read:
-		case vfs_id_pread: ;
-			str = smb_traffic_analyzer_create_string( talloc_tos(),
-				tm, seconds, handle, username, vfs_operation,
-				2, ((struct rw_data *) data)->filename, \
-				talloc_asprintf(talloc_tos(), "%u", \
-				(unsigned int)
-					((struct rw_data *) data)->len));
-			break;
-		default:
-			DEBUG(1, ("smb_traffic_analyzer: error! "
-				"wrong VFS operation id detected!\n"));
-			return;
-		}
-
-	}
-
-	if (!str) {
-		DEBUG(1, ("smb_traffic_analyzer_send_data: "
-			"unable to create string to send!\n"));
-		return;
-	}
-
-
-	/*
-	 * If configured, optain the key and run AES encryption
-	 * over the data.
-	 */
-	become_root();
-	akey = (char *) secrets_fetch("smb_traffic_analyzer_key", &size);
-	unbecome_root();
-	if ( akey != NULL ) {
-		state_flags[2] = 'E';
-		DEBUG(10, ("smb_traffic_analyzer_send_data_socket: a key was"
-			" found, encrypting data!\n"));
-		output = smb_traffic_analyzer_encrypt( talloc_tos(),
-						akey, str, &len);
-		SAFE_FREE(akey);
-		header = smb_traffic_analyzer_create_header( talloc_tos(),
-						state_flags, len);
-
-		DEBUG(10, ("smb_traffic_analyzer_send_data_socket:"
-			" header created for crypted data: %s\n", header));
-		smb_traffic_analyzer_write_data(header, output, len,
-							rf_sock->sock);
-		return;
-
-	}
-
-        len = strlen(str);
-	header = smb_traffic_analyzer_create_header( talloc_tos(),
-				state_flags, len);
-	smb_traffic_analyzer_write_data(header, str, strlen(str),
-				rf_sock->sock);
-
-}
-
-static struct refcounted_sock *sock_list;
-
-static void smb_traffic_analyzer_free_data(void **pptr)
-{
-	struct refcounted_sock *rf_sock = *(struct refcounted_sock **)pptr;
-	if (rf_sock == NULL) {
-		return;
-	}
-	rf_sock->ref_count--;
-	if (rf_sock->ref_count != 0) {
-		return;
-	}
-	if (rf_sock->sock != -1) {
-		close(rf_sock->sock);
-	}
-	DLIST_REMOVE(sock_list, rf_sock);
-	TALLOC_FREE(rf_sock);
-}
-
-static int smb_traffic_analyzer_connect(struct vfs_handle_struct *handle,
-                         const char *service,
-                         const char *user)
-{
-	connection_struct *conn = handle->conn;
-	enum sock_type st = smb_traffic_analyzer_connMode(handle);
-	struct refcounted_sock *rf_sock = NULL;
-	const char *name = (st == UNIX_DOMAIN_SOCKET) ? LOCAL_PATHNAME :
-				lp_parm_const_string(SNUM(conn),
-					"smb_traffic_analyzer",
-				"host", "localhost");
-	uint16_t port = (st == UNIX_DOMAIN_SOCKET) ? 0 :
-				atoi( lp_parm_const_string(SNUM(conn),
-				"smb_traffic_analyzer", "port", "9430"));
-	int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
-
-	if (ret < 0) {
-		return ret;
-	}
-
-	/* Are we already connected ? */
-	for (rf_sock = sock_list; rf_sock; rf_sock = rf_sock->next) {
-		if (port == rf_sock->port &&
-				(strcmp(name, rf_sock->name) == 0)) {
-			break;
-		}
-	}
-
-	/* If we're connected already, just increase the
- 	 * reference count. */
-	if (rf_sock) {
-		rf_sock->ref_count++;
-	} else {
-		/* New connection. */
-		rf_sock = talloc_zero(NULL, struct refcounted_sock);
-		if (rf_sock == NULL) {
-			SMB_VFS_NEXT_DISCONNECT(handle);
-			errno = ENOMEM;
-			return -1;
-		}
-		rf_sock->name = talloc_strdup(rf_sock, name);
-		if (rf_sock->name == NULL) {
-			SMB_VFS_NEXT_DISCONNECT(handle);
-			TALLOC_FREE(rf_sock);
-			errno = ENOMEM;
-			return -1;
-		}
-		rf_sock->port = port;
-		rf_sock->ref_count = 1;
-
-		if (st == UNIX_DOMAIN_SOCKET) {
-			rf_sock->sock = smb_traffic_analyzer_connect_unix_socket(handle,
-							name);
-		} else {
-
-			rf_sock->sock = smb_traffic_analyzer_connect_inet_socket(handle,
-							name,
-							port);
-		}
-		if (rf_sock->sock == -1) {
-			SMB_VFS_NEXT_DISCONNECT(handle);
-			TALLOC_FREE(rf_sock);
-			return -1;
-		}
-		DLIST_ADD(sock_list, rf_sock);
-	}
-
-	/* Store the private data. */
-	SMB_VFS_HANDLE_SET_DATA(handle, rf_sock, smb_traffic_analyzer_free_data,
-				struct refcounted_sock, return -1);
-	return 0;
-}
-
-/* VFS Functions */
-static int smb_traffic_analyzer_chdir(vfs_handle_struct *handle, \
-			const char *path)
-{
-	struct chdir_data s_data;
-	s_data.result = SMB_VFS_NEXT_CHDIR(handle, path);
-	s_data.path = path;
-	DEBUG(10, ("smb_traffic_analyzer_chdir: CHDIR: %s\n", path));
-	smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_chdir);
-	return s_data.result;
-}
-
-static int smb_traffic_analyzer_rename(vfs_handle_struct *handle, \
-		const struct smb_filename *smb_fname_src,
-		const struct smb_filename *smb_fname_dst)
-{
-	struct rename_data s_data;
-	s_data.result = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, \
-		smb_fname_dst);
-	s_data.src = smb_fname_src->base_name;
-	s_data.dst = smb_fname_dst->base_name;
-	DEBUG(10, ("smb_traffic_analyzer_rename: RENAME: %s / %s\n",
-		smb_fname_src->base_name,
-		smb_fname_dst->base_name));
-	smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_rename);
-	return s_data.result;
-}
-
-static int smb_traffic_analyzer_rmdir(vfs_handle_struct *handle, \
-			const char *path)
-{
-	struct rmdir_data s_data;
-	s_data.result = SMB_VFS_NEXT_RMDIR(handle, path);
-	s_data.path = path;
-	DEBUG(10, ("smb_traffic_analyzer_rmdir: RMDIR: %s\n", path));
-	smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_rmdir);
-	return s_data.result;
-}
-
-static int smb_traffic_analyzer_mkdir(vfs_handle_struct *handle, \
-			const char *path, mode_t mode)
-{
-	struct mkdir_data s_data;
-	s_data.result = SMB_VFS_NEXT_MKDIR(handle, path, mode);
-	s_data.path = path;
-	s_data.mode = mode;
-	DEBUG(10, ("smb_traffic_analyzer_mkdir: MKDIR: %s\n", path));
-	smb_traffic_analyzer_send_data(handle,
-			&s_data,
-			vfs_id_mkdir);
-	return s_data.result;
-}
-
-static ssize_t smb_traffic_analyzer_sendfile(vfs_handle_struct *handle,
-				int tofd,
-				files_struct *fromfsp,
-				const DATA_BLOB *hdr,
-				off_t offset,
-				size_t n)
-{
-	struct rw_data s_data;
-	s_data.len = SMB_VFS_NEXT_SENDFILE(handle,
-			tofd, fromfsp, hdr, offset, n);
-	s_data.filename = fromfsp->fsp_name->base_name;
-	DEBUG(10, ("smb_traffic_analyzer_sendfile: sendfile(r): %s\n",
-		fsp_str_dbg(fromfsp)));
-	smb_traffic_analyzer_send_data(handle,
-		&s_data,
-		vfs_id_read);
-	return s_data.len;
-}
-
-static ssize_t smb_traffic_analyzer_recvfile(vfs_handle_struct *handle,
-				int fromfd,
-				files_struct *tofsp,
-				off_t offset,
-				size_t n)
-{
-	struct rw_data s_data;
-	s_data.len = SMB_VFS_NEXT_RECVFILE(handle,
-			fromfd, tofsp, offset, n);
-	s_data.filename = tofsp->fsp_name->base_name;
-	DEBUG(10, ("smb_traffic_analyzer_recvfile: recvfile(w): %s\n",
-		fsp_str_dbg(tofsp)));
-	smb_traffic_analyzer_send_data(handle,
-		&s_data,
-		vfs_id_write);
-	return s_data.len;
-}
-
-
-static ssize_t smb_traffic_analyzer_read(vfs_handle_struct *handle, \
-				files_struct *fsp, void *data, size_t n)
-{
-	struct rw_data s_data;
-
-	s_data.len = SMB_VFS_NEXT_READ(handle, fsp, data, n);
-	s_data.filename = fsp->fsp_name->base_name;
-	DEBUG(10, ("smb_traffic_analyzer_read: READ: %s\n", fsp_str_dbg(fsp)));
-
-	smb_traffic_analyzer_send_data(handle,
-			&s_data,
-			vfs_id_read);
-	return s_data.len;
-}
-
-
-static ssize_t smb_traffic_analyzer_pread(vfs_handle_struct *handle, \
-		files_struct *fsp, void *data, size_t n, off_t offset)
-{
-	struct rw_data s_data;
-
-	s_data.len = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
-	s_data.filename = fsp->fsp_name->base_name;
-	DEBUG(10, ("smb_traffic_analyzer_pread: PREAD: %s\n",
-		   fsp_str_dbg(fsp)));
-
-	smb_traffic_analyzer_send_data(handle,
-			&s_data,
-			vfs_id_pread);
-
-	return s_data.len;
-}
-
-static ssize_t smb_traffic_analyzer_write(vfs_handle_struct *handle, \
-			files_struct *fsp, const void *data, size_t n)
-{
-	struct rw_data s_data;
-
-	s_data.len = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
-	s_data.filename = fsp->fsp_name->base_name;
-	DEBUG(10, ("smb_traffic_analyzer_write: WRITE: %s\n",
-		   fsp_str_dbg(fsp)));
-
-	smb_traffic_analyzer_send_data(handle,
-			&s_data,
-			vfs_id_write);
-	return s_data.len;
-}
-
-static ssize_t smb_traffic_analyzer_pwrite(vfs_handle_struct *handle, \
-	     files_struct *fsp, const void *data, size_t n, off_t offset)
-{
-	struct rw_data s_data;
-
-	s_data.len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
-	s_data.filename = fsp->fsp_name->base_name;
-	DEBUG(10, ("smb_traffic_analyzer_pwrite: PWRITE: %s\n", \
-		fsp_str_dbg(fsp)));
-
-	smb_traffic_analyzer_send_data(handle,
-			&s_data,
-			vfs_id_pwrite);
-	return s_data.len;
-}
-
-static int smb_traffic_analyzer_open(vfs_handle_struct *handle, \
-	struct smb_filename *smb_fname, files_struct *fsp,\
-	int flags, mode_t mode)
-{
-	struct open_data s_data;
-
-	s_data.result = SMB_VFS_NEXT_OPEN( handle, smb_fname, fsp,
-			flags, mode);
-	DEBUG(10,("smb_traffic_analyzer_open: OPEN: %s\n",
-		fsp_str_dbg(fsp)));
-	s_data.filename = fsp->fsp_name->base_name;
-	s_data.mode = mode;
-	smb_traffic_analyzer_send_data(handle,
-			&s_data,
-			vfs_id_open);
-	return s_data.result;
-}
-
-static int smb_traffic_analyzer_close(vfs_handle_struct *handle, \
-	files_struct *fsp)
-{
-	struct close_data s_data;
-	s_data.result = SMB_VFS_NEXT_CLOSE(handle, fsp);
-	DEBUG(10,("smb_traffic_analyzer_close: CLOSE: %s\n",
-		fsp_str_dbg(fsp)));
-	s_data.filename = fsp->fsp_name->base_name;
-	smb_traffic_analyzer_send_data(handle,
-			&s_data,
-			vfs_id_close);
-	return s_data.result;
-}
-
-	
-static struct vfs_fn_pointers vfs_smb_traffic_analyzer_fns = {
-	.connect_fn = smb_traffic_analyzer_connect,
-	.read_fn = smb_traffic_analyzer_read,
-	.pread_fn = smb_traffic_analyzer_pread,
-	.write_fn = smb_traffic_analyzer_write,
-	.pwrite_fn = smb_traffic_analyzer_pwrite,
-	.mkdir_fn = smb_traffic_analyzer_mkdir,
-	.rename_fn = smb_traffic_analyzer_rename,
-	.chdir_fn = smb_traffic_analyzer_chdir,
-	.open_fn = smb_traffic_analyzer_open,
-	.rmdir_fn = smb_traffic_analyzer_rmdir,
-	.close_fn = smb_traffic_analyzer_close,
-	.sendfile_fn = smb_traffic_analyzer_sendfile,
-	.recvfile_fn = smb_traffic_analyzer_recvfile
-};
-
-/* Module initialization */
-NTSTATUS vfs_smb_traffic_analyzer_init(void)
-{
-	NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
-					"smb_traffic_analyzer",
-					&vfs_smb_traffic_analyzer_fns);
-
-	if (!NT_STATUS_IS_OK(ret)) {
-		return ret;
-	}
-
-	vfs_smb_traffic_analyzer_debug_level =
-		debug_add_class("smb_traffic_analyzer");
-
-	if (vfs_smb_traffic_analyzer_debug_level == -1) {
-		vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
-		DEBUG(1, ("smb_traffic_analyzer_init: Couldn't register custom"
-			 "debugging class!\n"));
-	} else {
-		DEBUG(3, ("smb_traffic_analyzer_init: Debug class number of"
-			"'smb_traffic_analyzer': %d\n", \
-			vfs_smb_traffic_analyzer_debug_level));
-	}
-
-	return ret;
-}
diff --git a/source3/modules/vfs_smb_traffic_analyzer.h b/source3/modules/vfs_smb_traffic_analyzer.h
deleted file mode 100644
index 817ffd8..0000000
--- a/source3/modules/vfs_smb_traffic_analyzer.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * traffic-analyzer VFS module. Measure the smb traffic users create
- * on the net.
- *
- * Copyright (C) Holger Hetterich, 2008
- * Copyright (C) Jeremy Allison, 2008
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * Protocol version 2.0 description
- *
- * The following table shows the exact assembly of the 2.0 protocol.
- *
- * -->Header<--
- * The protocol header is always send first, and contains various
- * information about the data block to come.
- * The header is always of fixed length, and will be send unencrypted.
- *
- * Byte Number/Bytes    Description
- * 00-02                Contains always the string "V2."
- * 03                   This byte contains a possible subrelease number of the
- *                      protocol. This enables the receiver to make a version
- *                      check to ensure the compatibility and allows us to
- *                      release 2.x versions of the protocol with bugfixes or
- *                      enhancements.
- * 04                   This byte is reserved for possible future extensions.
- * 05                   Usually, this byte contains the character '0'. If the
- *                      VFS module is configured for encryption of the data,
- *                      this byte is set to 'E'.
- * 06-09                These bytes contain the character '0' by default, and
- *                      are reserved for possible future extensions. They have
- *                      no function in 2.0.
- * 10-27                17 bytes containing a string representation of the
- *                      number of bytes to come in the following data block.
- *                      It is right aligned and filled from the left with '0'.
- *
- * -->Data Block<--
- * The data block is send immediately after the header was send. It's length
- * is exactly what was given in bytes 11-28 from in the header.
- *
- * The data block may be send encrypted.
- *
- * To make the data block easy for the receiver to read, it is divided into
- * several sub-blocks, each with it's own header of four byte length. In each
- * of the sub-headers, a string representation of the length of this block is
- * to be found.
- *
- * Thus the formal structure is very simple:
- *
- * [HEADER]data[HEADER]data[HEADER]data[END]
- *
- * whereas [END] is exactly at the position given in bytes 11-28 of the
- * header.
- *
- * Some data the VFS module is capturing is of use for any VFS operation.
- * Therefore, there is a "common set" of data, that will be send with any
- * data block. The following provides a list of this data.
- * - the VFS function identifier (see VFS function ifentifier table below).
- * - a timestamp to the millisecond.
- * - the username (as text) who runs the VFS operation.
- * - the SID of the user who run the VFS operation.
- * - the domain under which the VFS operation has happened.
- *
- */
-
-/* Protocol subrelease number */
-#define SMBTA_SUBRELEASE '0'
-
-/*
- * Every data block sends a number of blocks sending common data
- * we send the number of "common data blocks" to come very first
- * so that if the receiver is using an older version of the protocol
- * it knows which blocks it can ignore.
- */
-#define SMBTA_COMMON_DATA_COUNT "00017"
-
-/*
- * VFS Functions identifier table. In protocol version 2, every vfs
- * function is given a unique id.
- */
-enum vfs_id {
-        /*
-         * care for the order here, required for compatibility
-         * with protocol version 1.
-         */
-        vfs_id_read,
-        vfs_id_pread,
-        vfs_id_write,
-        vfs_id_pwrite,
-        /* end of protocol version 1 identifiers. */
-        vfs_id_mkdir,
-        vfs_id_rmdir,
-        vfs_id_rename,
-        vfs_id_chdir,
-	vfs_id_open,
-	vfs_id_close
-};
-
-
-
-/*
- * Specific data sets for the VFS functions.
- * A compatible receiver has to have the exact same dataset.
- */
-struct open_data {
-	const char *filename;
-	mode_t mode;
-	int result;
-};
-
-struct close_data {
-	const char *filename;
-	int result;
-};
-
-struct mkdir_data {
-        const char *path;
-        mode_t mode;
-        int result;
-};
-
-struct rmdir_data {
-        const char *path;
-        int result;
-};
-
-struct rename_data {
-        const char *src;
-        const char *dst;
-        int result;
-};
-
-struct chdir_data {
-        const char *path;
-        int result;
-};
-
-/* rw_data used for read/write/pread/pwrite */
-struct rw_data {
-        char *filename;
-        size_t len;
-};
-
-
diff --git a/source3/modules/vfs_snapper.c b/source3/modules/vfs_snapper.c
index a25ae95..cd7904c 100644
--- a/source3/modules/vfs_snapper.c
+++ b/source3/modules/vfs_snapper.c
@@ -1404,7 +1404,7 @@ static NTSTATUS snapper_create_snap_call(TALLOC_CTX *mem_ctx,
 	NTSTATUS status;
 	DBusMessage *req_msg;
 	DBusMessage *rsp_msg;
-	uint32_t snap_id;
+	uint32_t snap_id = 0;
 	char *snap_path;
 
 	status = snapper_create_snap_pack(mem_ctx,
@@ -2767,6 +2767,39 @@ static uint64_t snapper_gmt_disk_free(vfs_handle_struct *handle,
 	return ret;
 }
 
+static int snapper_gmt_get_quota(vfs_handle_struct *handle, const char *path,
+				 enum SMB_QUOTA_TYPE qtype, unid_t id,
+				 SMB_DISK_QUOTA *dq)
+{
+	time_t timestamp;
+	char *stripped;
+	int ret;
+	int saved_errno;
+	char *conv;
+
+	if (!snapper_gmt_strip_snapshot(talloc_tos(), handle, path, &timestamp,
+					&stripped)) {
+		return -1;
+	}
+	if (timestamp == 0) {
+		return SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, dq);
+	}
+
+	conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp);
+	TALLOC_FREE(stripped);
+	if (conv == NULL) {
+		return -1;
+	}
+
+	ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv, qtype, id, dq);
+
+	saved_errno = errno;
+	TALLOC_FREE(conv);
+	errno = saved_errno;
+
+	return ret;
+}
+
 
 static struct vfs_fn_pointers snapper_fns = {
 	.snap_check_path_fn = snapper_snap_check_path,
@@ -2775,6 +2808,7 @@ static struct vfs_fn_pointers snapper_fns = {
 	.get_shadow_copy_data_fn = snapper_get_shadow_copy_data,
 	.opendir_fn = snapper_gmt_opendir,
 	.disk_free_fn = snapper_gmt_disk_free,
+	.get_quota_fn = snapper_gmt_get_quota,
 	.rename_fn = snapper_gmt_rename,
 	.link_fn = snapper_gmt_link,
 	.symlink_fn = snapper_gmt_symlink,
diff --git a/source3/modules/vfs_syncops.c b/source3/modules/vfs_syncops.c
index 8ff283d..99f6178 100644
--- a/source3/modules/vfs_syncops.c
+++ b/source3/modules/vfs_syncops.c
@@ -291,6 +291,7 @@ static struct vfs_fn_pointers vfs_syncops_fns = {
 	.close_fn = syncops_close,
 };
 
+static_decl_vfs;
 NTSTATUS vfs_syncops_init(void)
 {
 	NTSTATUS ret;
diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c
index 7efad1e..2fc6afd 100644
--- a/source3/modules/vfs_time_audit.c
+++ b/source3/modules/vfs_time_audit.c
@@ -178,15 +178,15 @@ static uint64_t smb_time_audit_disk_free(vfs_handle_struct *handle,
 }
 
 static int smb_time_audit_get_quota(struct vfs_handle_struct *handle,
-				    enum SMB_QUOTA_TYPE qtype, unid_t id,
-				    SMB_DISK_QUOTA *qt)
+				    const char *path, enum SMB_QUOTA_TYPE qtype,
+				    unid_t id, SMB_DISK_QUOTA *qt)
 {
 	int result;
 	struct timespec ts1,ts2;
 	double timediff;
 
 	clock_gettime_mono(&ts1);
-	result = SMB_VFS_NEXT_GET_QUOTA(handle, qtype, id, qt);
+	result = SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, qt);
 	clock_gettime_mono(&ts2);
 	timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9;
 
diff --git a/source3/modules/vfs_zfsacl.c b/source3/modules/vfs_zfsacl.c
index 82a48ae..02cbcdf 100644
--- a/source3/modules/vfs_zfsacl.c
+++ b/source3/modules/vfs_zfsacl.c
@@ -42,11 +42,11 @@
  */
 static NTSTATUS zfs_get_nt_acl_common(TALLOC_CTX *mem_ctx,
 				      const char *name,
-				      SMB4ACL_T **ppacl)
+				      struct SMB4ACL_T **ppacl)
 {
 	int naces, i;
 	ace_t *acebuf;
-	SMB4ACL_T *pacl;
+	struct SMB4ACL_T *pacl;
 
 	/* read the number of file aces */
 	if((naces = acl(name, ACE_GETACLCNT, 0, NULL)) == -1) {
@@ -105,11 +105,12 @@ static NTSTATUS zfs_get_nt_acl_common(TALLOC_CTX *mem_ctx,
 }
 
 /* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
-static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp, SMB4ACL_T *smbacl)
+static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp,
+			       struct SMB4ACL_T *smbacl)
 {
 	int naces = smb_get_naces(smbacl), i;
 	ace_t *acebuf;
-	SMB4ACE_T *smbace;
+	struct SMB4ACE_T *smbace;
 	TALLOC_CTX	*mem_ctx;
 	bool have_special_id = false;
 
@@ -196,7 +197,7 @@ static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
 				   TALLOC_CTX *mem_ctx,
 				   struct security_descriptor **ppdesc)
 {
-	SMB4ACL_T *pacl;
+	struct SMB4ACL_T *pacl;
 	NTSTATUS status;
 	TALLOC_CTX *frame = talloc_stackframe();
 
@@ -218,7 +219,7 @@ static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle,
 				  TALLOC_CTX *mem_ctx,
 				  struct security_descriptor **ppdesc)
 {
-	SMB4ACL_T *pacl;
+	struct SMB4ACL_T *pacl;
 	NTSTATUS status;
 	TALLOC_CTX *frame = talloc_stackframe();
 
diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
index e618b08..77b28f6 100644
--- a/source3/modules/wscript_build
+++ b/source3/modules/wscript_build
@@ -281,10 +281,6 @@ bld.SAMBA3_MODULE('vfs_gpfs',
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_gpfs'),
                  includes=bld.CONFIG_GET('CPPPATH_GPFS'))
 
-vfs_notify_fam_deps='samba-util '
-if bld.CONFIG_SET('SAMBA_FAM_LIBS'):
-   vfs_notify_fam_deps += bld.CONFIG_GET('SAMBA_FAM_LIBS')
-
 bld.SAMBA3_MODULE('vfs_readahead',
                  subsystem='vfs',
                  source='vfs_readahead.c',
@@ -325,14 +321,6 @@ bld.SAMBA3_MODULE('vfs_aio_pthread',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_aio_pthread'),
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_aio_pthread'))
 
-bld.SAMBA3_MODULE('vfs_aio_posix',
-                 subsystem='vfs',
-                 source='vfs_aio_posix.c',
-                 deps='samba-util tevent',
-                 init_function='',
-                 internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_aio_posix'),
-                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_aio_posix'))
-
 bld.SAMBA3_MODULE('vfs_aio_linux',
                  subsystem='vfs',
                  source='vfs_aio_linux.c',
@@ -373,14 +361,6 @@ bld.SAMBA3_MODULE('vfs_acl_tdb',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_acl_tdb'),
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_acl_tdb'))
 
-bld.SAMBA3_MODULE('vfs_smb_traffic_analyzer',
-                 subsystem='vfs',
-                 source='vfs_smb_traffic_analyzer.c',
-                 deps='samba-util',
-                 init_function='',
-                 internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_smb_traffic_analyzer'),
-                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_smb_traffic_analyzer'))
-
 bld.SAMBA3_MODULE('vfs_dirsort',
                  subsystem='vfs',
                  source='vfs_dirsort.c',
@@ -389,14 +369,6 @@ bld.SAMBA3_MODULE('vfs_dirsort',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_dirsort'),
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_dirsort'))
 
-bld.SAMBA3_MODULE('vfs_scannedonly',
-                 subsystem='vfs',
-                 source='vfs_scannedonly.c',
-                 deps='samba-util',
-                 init_function='',
-                 internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_scannedonly'),
-                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_scannedonly'))
-
 bld.SAMBA3_MODULE('vfs_crossrename',
                  subsystem='vfs',
                  source='vfs_crossrename.c',
@@ -511,3 +483,17 @@ bld.SAMBA3_MODULE('vfs_vxfs',
                  init_function='',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_vxfs'),
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_vxfs'))
+
+bld.SAMBA3_MODULE('vfs_offline',
+                 subsystem='vfs',
+                 source='vfs_offline.c',
+                 init_function='',
+                 internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_offline'),
+                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_offline'))
+
+bld.SAMBA3_MODULE('vfs_fake_dfq',
+                 subsystem='vfs',
+                 source='vfs_fake_dfq.c',
+                 init_function='',
+                 internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_fake_dfq'),
+                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_fake_dfq'))
diff --git a/source3/nmbd/asyncdns.c b/source3/nmbd/asyncdns.c
index 5973c8e..b4532fa 100644
--- a/source3/nmbd/asyncdns.c
+++ b/source3/nmbd/asyncdns.c
@@ -19,7 +19,7 @@
 
 #include "includes.h"
 #include "nmbd/nmbd.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 
 /***************************************************************************
   Add a DNS result to the name cache.
@@ -167,7 +167,7 @@ void start_async_dns(struct messaging_context *msg)
 	CatchSignal(SIGHUP, SIG_IGN);
         CatchSignal(SIGTERM, sig_term);
 
-	status = reinit_after_fork(msg, nmbd_event_context(), true);
+	status = reinit_after_fork(msg, nmbd_event_context(), true, NULL);
 
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c
index c7e72de..14eaef6 100644
--- a/source3/nmbd/nmbd.c
+++ b/source3/nmbd/nmbd.c
@@ -988,8 +988,7 @@ static bool open_sockets(bool isdaemon, int port)
 
 	pidfile_create(lp_pid_directory(), "nmbd");
 
-	status = reinit_after_fork(msg, nmbd_event_context(),
-				   false);
+	status = reinit_after_fork(msg, nmbd_event_context(), false, NULL);
 
 	if (!NT_STATUS_IS_OK(status)) {
 		exit_daemon("reinit_after_fork() failed", map_errno_from_nt_status(status));
diff --git a/source3/nmbd/nmbd_browserdb.c b/source3/nmbd/nmbd_browserdb.c
index b36f5c7..b883f56 100644
--- a/source3/nmbd/nmbd_browserdb.c
+++ b/source3/nmbd/nmbd_browserdb.c
@@ -120,7 +120,7 @@ struct browse_cache_record *create_browser_in_lmb_cache( const char *work_name,
   
 	browc->ip = ip;
  
-	DLIST_ADD_END(lmb_browserlist, browc, struct browse_cache_record *);
+	DLIST_ADD_END(lmb_browserlist, browc);
 
 	DEBUG(3, ("nmbd_browserdb:create_browser_in_lmb_cache()\n"));
 	DEBUGADD(3, ("  Added lmb cache entry for workgroup %s name %s IP %s "
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index 9f5cc18..b608354 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -1033,7 +1033,7 @@ void reply_netbios_packet(struct packet_struct *orig_packet,
 
 void queue_packet(struct packet_struct *packet)
 {
-	DLIST_ADD_END(packet_queue, packet, struct packet_struct *);
+	DLIST_ADD_END(packet_queue, packet);
 }
 
 /****************************************************************************
diff --git a/source3/nmbd/nmbd_responserecordsdb.c b/source3/nmbd/nmbd_responserecordsdb.c
index bd18850..4753bbf 100644
--- a/source3/nmbd/nmbd_responserecordsdb.c
+++ b/source3/nmbd/nmbd_responserecordsdb.c
@@ -37,7 +37,7 @@ static void add_response_record(struct subnet_record *subrec,
 	DEBUG(4,("add_response_record: adding response record id:%hu to subnet %s. num_records:%d\n",
 		rrec->response_id, subrec->subnet_name, num_response_packets));
 
-	DLIST_ADD_END(subrec->responselist, rrec, struct response_record *);
+	DLIST_ADD_END(subrec->responselist, rrec);
 }
 
 /***************************************************************************
diff --git a/source3/nmbd/nmbd_serverlistdb.c b/source3/nmbd/nmbd_serverlistdb.c
index cd84bdf..43471d6 100644
--- a/source3/nmbd/nmbd_serverlistdb.c
+++ b/source3/nmbd/nmbd_serverlistdb.c
@@ -54,7 +54,7 @@ void remove_all_servers(struct work_record *work)
 static void add_server_to_workgroup(struct work_record *work,
                              struct server_record *servrec)
 {
-	DLIST_ADD_END(work->serverlist, servrec, struct server_record *);
+	DLIST_ADD_END(work->serverlist, servrec);
 	work->subnet->work_changed = True;
 }
 
diff --git a/source3/pam_smbpass/CHANGELOG b/source3/pam_smbpass/CHANGELOG
deleted file mode 100644
index 96ef784..0000000
--- a/source3/pam_smbpass/CHANGELOG
+++ /dev/null
@@ -1,31 +0,0 @@
-version 0.7.5  25 Mar 2001
-   - Use Samba 2.2.0 (alpha) as the target codebase, since it doesn't look
-     like Samba will be offering shared libraries in the near future.
-   - added a Makefile and support scripts to make the build process easier.
-   - imported some Solaris fixes that I've been sitting on.
-
-version 0.7.4  20 Jan 2000
-   - added a 'migrate' option to the authentication code which makes no
-     effort to authenticate the user, or even to ask for a password, but
-     it can be useful for filling in an SMB password db.
-
-version 0.7.3  19 Jan 2000
-   - updated to use the SAMBA_TNG Samba branch, allowing us to dynamically
-     link against Luke's new shared libs (libsamba, libsmb).
-
-version 0.7.2  20 Jul 1999
-   - miscellaneous bugfixes.  Cleanup of legacy pam_pwdb code.
-   - fixed return value of pam_sm_setcred function.
-   - fix to autoconf support
-   - clarified some of the messages being logged
-
-version 0.6,  15 Jul 1999
-   - updated to use the new Samba (2.0) password database API.
-   - added autoconf support. May now theoretically compile on more
-     platforms than PAM itself does.
-   - added support for account management functions (i.e., disabled
-     accounts)
-
-version 0.5,  4 Apr 1998
-   - added support for hashed passwords as input.  Now capable of serving
-     as an authentication agent for encrypted network transactions.
diff --git a/source3/pam_smbpass/INSTALL b/source3/pam_smbpass/INSTALL
deleted file mode 100644
index ae2ba02..0000000
--- a/source3/pam_smbpass/INSTALL
+++ /dev/null
@@ -1,64 +0,0 @@
-
-Because pam_smbpass is derived from the Samba smbpasswd utility, recent
-versions of pam_smbpass require a copy of the Samba source code to be
-available on the build system.  Version 0.7.5 has been tested against
-Samba 2.2.0-alpha3, and this is the recommended version of Samba to use
-for building pam_smbpass.  This only affects /building/ pam_smbpass; you
-can still run any version of the Samba server that you want, although
-clearly it saves some disk space to have only one copy of the source
-code on your system (Samba 2.2.0-alpha3 takes roughly 32MB of disk space
-to build pam_smbpass).
-
-Version 0.7.5 features a new build system to make it easier to build
-pam_smbpass.
-
-
-Using the new build system
-==========================
-
-If you don't have a copy of the Samba source code on your machine, and you
-don't have a preferred Samba version (or mirror site), you can build
-pam_smbpass by just typing 'make'.
-
-If you want to use a version other than 2.2.0-alpha3, or you want to
-download the source code from a faster Samba mirror (see
-<http://us1.samba.org/samba/> for a list of mirror sites), please download
-the source code and unpack it before running make.  The build scripts will
-attempt to autodetect your Samba source directory, and if it can't be
-found automatically, you will be given the opportunity to specify an
-alternate directory for the Samba sources.
-
-Feedback is welcome if you try (or succeed!) to build pam_smbpass with
-other versions of Samba.
-
-
-Options to 'make'
-=================
-
-By default, pam_smbpass will configure the Samba build tree with the
-options
-
-    --with-fhs --with-privatedir=/etc --with-configdir=/etc
-
-This will configure pam_smbpass to look for the smbpasswd file as
-/etc/smbpasswd (or /etc/smbpasswd.tdb), and the smb.conf file as
-/etc/smb.conf.  You can override these options by setting CONFIGOPTS when
-calling make.  E.g., if you have your smb.conf file in /usr/etc and your
-smbpasswd file in /usr/etc/private, you might run
-
-    make CONFIGOPTS="--with-privatedir=/usr/etc/private --with-configdir=/usr/etc"
-
-For a complete list of available configuration options, see
-'./samba/configure --help'
-
-
-Installing the module
-=====================
-
-If all goes well in the build process, the file pam_smbpass.so will be
-created in the current directory.  Simply install the module into your
-system's PAM module directory:
-
-	install -m 755 -s bin/pam_smbpass.so /lib/security
-
-and you're all set.
diff --git a/source3/pam_smbpass/README b/source3/pam_smbpass/README
deleted file mode 100644
index a5bde25..0000000
--- a/source3/pam_smbpass/README
+++ /dev/null
@@ -1,68 +0,0 @@
-23 Jan 2015
-
-=== WARNING ===
-
-This PAM module is deprecated and will be removed from the Samba source code
-with the release of Samba 4.3. If you are still using this module please
-migrate to pam_winbind or another suiteable solution.
-
-25 Mar 2001
-
-pam_smbpass is a PAM module which can be used on conforming systems to
-keep the smbpasswd (Samba password) database in sync with the unix
-password file. PAM (Pluggable Authentication Modules) is an API supported
-under some Unices, such as Solaris, HPUX and Linux, that provides a
-generic interface to authentication mechanisms.
-
-For more information on PAM, see http://ftp.kernel.org/pub/linux/libs/pam/
-
-This module authenticates a local smbpasswd user database.  If you require
-support for authenticating against a remote SMB server, or if you're
-concerned about the presence of suid root binaries on your system, it is
-recommended that you use pam_winbind instead.
-
-Options recognized by this module are as follows:
-
-	debug		-	log more debugging info
-	audit		-	like debug, but also logs unknown usernames
-	use_first_pass	-	don't prompt the user for passwords;
-				take them from PAM_ items instead
-	try_first_pass  -	try to get the password from a previous
-				PAM module, fall back to prompting the user
-	use_authtok	-	like try_first_pass, but *fail* if the new
-				PAM_AUTHTOK has not been previously set.
-				(intended for stacking password modules only)
-	not_set_pass    -	don't make passwords used by this module
-				available to other modules.
-	nodelay		-	don't insert ~1 second delays on authentication
-				failure.
-	nullok		-	null passwords are allowed.
-	nonull		-	null passwords are not allowed. Used to
-				override the Samba configuration.
-	migrate		-	only meaningful in an "auth" context;
-				used to update smbpasswd file with a
-				password used for successful authentication.
-	smbconf=<file>	-	specify an alternate path to the smb.conf
-				file.
-
-See the samples/ directory for example PAM configurations using this
-module.
-
-Thanks go to the following people:
-
-* Andrew Morgan <morgan at transmeta.com>, for providing the Linux-PAM
-framework, without which none of this would have happened
-
-* Christian Gafton <gafton at redhat.com> and Andrew Morgan again, for the
-pam_pwdb module upon which pam_smbpass was originally based
-
-* Luke Leighton <lkcl at switchboard.net> for being receptive to the idea,
-and for the occasional good-natured complaint about the project's status
-that keep me working on it :)
-
-* and of course, all the other members of the Samba team 
-<http://www.samba.org/samba/team.html>, for creating a great product 
-and for giving this project a purpose
-
----------------------
-Stephen Langasek <vorlon at netexpress.net>
diff --git a/source3/pam_smbpass/TODO b/source3/pam_smbpass/TODO
deleted file mode 100644
index 20cf4fb..0000000
--- a/source3/pam_smbpass/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a tentative TODO file which will probably get much longer before
-it gets much shorter.
-
-- Recognizing (and overriding) debug options in the smb.conf file
-- Support for 'name=value' parameters in the PAM config
-- Compliant handling of unrecognized PAM parameters (i.e., fail on error)
-- 
diff --git a/source3/pam_smbpass/general.h b/source3/pam_smbpass/general.h
deleted file mode 100644
index c3e4b8b..0000000
--- a/source3/pam_smbpass/general.h
+++ /dev/null
@@ -1,134 +0,0 @@
-#include "../librpc/gen_ndr/samr.h"
-#include "../libcli/auth/pam_errors.h"
-#include "passdb.h"
-
-#ifndef LINUX
-/* This is only needed by modules in the Sun implementation. */
-#if defined(HAVE_SECURITY_PAM_APPL_H)
-#include <security/pam_appl.h>
-#elif defined(HAVE_PAM_PAM_APPL_H)
-#include <pam/pam_appl.h>
-#endif
-#endif  /* LINUX */
-
-#if defined(HAVE_SECURITY_PAM_MODULES_H)
-#include <security/pam_modules.h>
-#elif defined(HAVE_PAM_PAM_MODULES_H)
-#include <pam/pam_modules.h>
-#endif
-
-#ifndef PAM_AUTHTOK_RECOVER_ERR  
-#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
-#endif
-
-#include "replace.h"
-#include "system/filesys.h"
-#include "system/wait.h"
-#include "system/syslog.h"
-
-/*
- * here is the string to inform the user that the new passwords they
- * typed were not the same.
- */
-
-#define MISTYPED_PASS "Sorry, passwords do not match"
-
-/* type definition for the control options */
-
-typedef struct {
-     const char *token;
-     unsigned int mask;            /* shall assume 32 bits of flags */
-     unsigned int flag;
-} SMB_Ctrls;
-
-#ifndef False
-#define False (0)
-#endif
-
-#ifndef True
-#define True (1)
-#endif
-
-/* macro to determine if a given flag is on */
-#define on(x,ctrl)  (smb_args[x].flag & ctrl)
-
-/* macro to determine that a given flag is NOT on */
-#define off(x,ctrl) (!on(x,ctrl))
-
-/* macro to turn on/off a ctrl flag manually */
-#define set(x,ctrl)   (ctrl = ((ctrl)&smb_args[x].mask)|smb_args[x].flag)
-#define unset(x,ctrl) (ctrl &= ~(smb_args[x].flag))
-
-/* the generic mask */
-#define _ALL_ON_  (~0U)
-
-/* end of macro definitions definitions for the control flags */
-
-/*
- * These are the options supported by the smb password module, very
- * similar to the pwdb options
- */
-
-#define SMB__OLD_PASSWD		 0	/* internal */
-#define SMB__VERIFY_PASSWD	 1	/* internal */
-
-#define SMB_AUDIT		 2	/* print more things than debug..
-					   some information may be sensitive */
-#define SMB_USE_FIRST_PASS	 3
-#define SMB_TRY_FIRST_PASS	 4
-#define SMB_NOT_SET_PASS	 5	/* don't set the AUTHTOK items */
-
-#define SMB__NONULL		 6	/* internal */
-#define SMB__QUIET		 7	/* internal */
-#define SMB_USE_AUTHTOK		 8	/* insist on reading PAM_AUTHTOK */
-#define SMB__NULLOK		 9	/* Null token ok */
-#define SMB_DEBUG		10	/* send more info to syslog(3) */
-#define SMB_NODELAY		11	/* admin does not want a fail-delay */
-#define SMB_MIGRATE		12	/* Does no authentication, just
-					   updates the smb database. */
-#define SMB_CONF_FILE		13	/* Alternate location of smb.conf */
-
-#define SMB_CTRLS_		14	/* number of ctrl arguments defined */
-
-static const SMB_Ctrls smb_args[SMB_CTRLS_] = {
-/* symbol                 token name          ctrl mask      ctrl       *
- * ------------------     ------------------  -------------- ---------- */
-
-/* SMB__OLD_PASSWD */	 {  NULL,            _ALL_ON_,              01 },
-/* SMB__VERIFY_PASSWD */ {  NULL,            _ALL_ON_,              02 },
-/* SMB_AUDIT */		 { "audit",          _ALL_ON_,              04 },
-/* SMB_USE_FIRST_PASS */ { "use_first_pass", _ALL_ON_^(030),       010 },
-/* SMB_TRY_FIRST_PASS */ { "try_first_pass", _ALL_ON_^(030),       020 },
-/* SMB_NOT_SET_PASS */	 { "not_set_pass",   _ALL_ON_,             040 },
-/* SMB__NONULL */	 {  "nonull",        _ALL_ON_,            0100 },
-/* SMB__QUIET */	 {  NULL,            _ALL_ON_,            0200 },
-/* SMB_USE_AUTHTOK */	 { "use_authtok",    _ALL_ON_,            0400 },
-/* SMB__NULLOK */	 { "nullok",         _ALL_ON_^(0100),        0 },
-/* SMB_DEBUG */		 { "debug",          _ALL_ON_,           01000 },
-/* SMB_NODELAY */	 { "nodelay",        _ALL_ON_,           02000 },
-/* SMB_MIGRATE */	 { "migrate",        _ALL_ON_^(0100),	 04000 },
-/* SMB_CONF_FILE */	 { "smbconf=",       _ALL_ON_,		     0 },
-};
-
-#define SMB_DEFAULTS  (smb_args[SMB__NONULL].flag)
-
-/*
- * the following is used to keep track of the number of times a user fails
- * to authenticate themself.
- */
-
-#define SMB_MAX_RETRIES			3
-
-struct _pam_failed_auth {
-    char *user;                 /* user that's failed to be authenticated */
-    uid_t id;                   /* uid of requested user */
-    char *agent;                /* attempt from user with name */
-    int count;                  /* number of failures so far */
-};
-
-/*
- * General use functions go here 
- */
-
-/* from support.c */
-int make_remark(pam_handle_t *, unsigned int, int, const char *);
diff --git a/source3/pam_smbpass/pam_smb_acct.c b/source3/pam_smbpass/pam_smb_acct.c
deleted file mode 100644
index 8dbbf3a..0000000
--- a/source3/pam_smbpass/pam_smb_acct.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* Unix NT password database implementation, version 0.7.5.
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-/* indicate the following groups are defined */
-#define PAM_SM_ACCT
-
-#include "includes.h"
-
-#ifndef LINUX
-
-/* This is only used in the Sun implementation. */
-#if defined(HAVE_SECURITY_PAM_APPL_H)
-#include <security/pam_appl.h>
-#elif defined(HAVE_PAM_PAM_APPL_H)
-#include <pam/pam_appl.h>
-#endif
-
-#endif  /* LINUX */
-
-#if defined(HAVE_SECURITY_PAM_MODULES_H)
-#include <security/pam_modules.h>
-#elif defined(HAVE_PAM_PAM_MODULES_H)
-#include <pam/pam_modules.h>
-#endif
-
-#include "general.h"
-
-#include "support.h"
-
-
-/*
- * pam_sm_acct_mgmt() verifies whether or not the account is disabled.
- *
- */
-
-int pam_sm_acct_mgmt( pam_handle_t *pamh, int flags,
-                      int argc, const char **argv )
-{
-	unsigned int ctrl;
-	int retval;
-
-	const char *name;
-	struct samu *sampass = NULL;
-	void (*oldsig_handler)(int);
-	TALLOC_CTX *frame = talloc_stackframe();
-
-	/* Samba initialization. */
-
-	ctrl = set_ctrl(pamh, flags, argc, argv );
-
-	/* get the username */
-
-	retval = pam_get_user( pamh, &name, "Username: " );
-	if (retval != PAM_SUCCESS) {
-		if (on( SMB_DEBUG, ctrl )) {
-			_log_err(pamh, LOG_DEBUG, "acct: could not identify user" );
-		}
-		TALLOC_FREE(frame);
-		return retval;
-	}
-	if (on( SMB_DEBUG, ctrl )) {
-		_log_err(pamh, LOG_DEBUG, "acct: username [%s] obtained", name );
-	}
-
-	if (geteuid() != 0) {
-		_log_err(pamh, LOG_DEBUG, "Cannot access samba password database, not running as root.");
-		TALLOC_FREE(frame);
-		return PAM_AUTHINFO_UNAVAIL;
-	}
-
-	/* Getting into places that might use LDAP -- protect the app
-		from a SIGPIPE it's not expecting */
-	oldsig_handler = CatchSignal(SIGPIPE, SIG_IGN);
-	if (!initialize_password_db(True, NULL)) {
-	  _log_err(pamh, LOG_ALERT, "Cannot access samba password database" );
-		CatchSignal(SIGPIPE, oldsig_handler);
-		TALLOC_FREE(frame);
-		return PAM_AUTHINFO_UNAVAIL;
-	}
-
-	/* Get the user's record. */
-
-	if (!(sampass = samu_new( NULL ))) {
-		CatchSignal(SIGPIPE, oldsig_handler);
-		/* malloc fail. */
-		TALLOC_FREE(frame);
-		return nt_status_to_pam(NT_STATUS_NO_MEMORY);
-	}
-
-	if (!pdb_getsampwnam(sampass, name )) {
-		_log_err(pamh, LOG_DEBUG, "acct: could not identify user");
-		CatchSignal(SIGPIPE, oldsig_handler);
-		TALLOC_FREE(frame);
-        	return PAM_USER_UNKNOWN;
-	}
-
-	/* check for lookup failure */
-	if (!strlen(pdb_get_username(sampass)) ) {
-		CatchSignal(SIGPIPE, oldsig_handler);
-		TALLOC_FREE(frame);
-		return PAM_USER_UNKNOWN;
-	}
-
-	if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
-		if (on( SMB_DEBUG, ctrl )) {
-			_log_err(pamh, LOG_DEBUG,
-				 "acct: account %s is administratively disabled", name);
-		}
-		make_remark( pamh, ctrl, PAM_ERROR_MSG
-			, "Your account has been disabled; "
-			"please see your system administrator." );
-
-		CatchSignal(SIGPIPE, oldsig_handler);
-		TALLOC_FREE(frame);
-		return PAM_ACCT_EXPIRED;
-	}
-
-	/* TODO: support for expired passwords. */
-
-	CatchSignal(SIGPIPE, oldsig_handler);
-	TALLOC_FREE(frame);
-	return PAM_SUCCESS;
-}
-
-/* static module data */
-#ifdef PAM_STATIC
-struct pam_module _pam_smbpass_acct_modstruct = {
-     "pam_smbpass",
-     NULL,
-     NULL,
-     pam_sm_acct_mgmt,
-     NULL,
-     NULL,
-     NULL
-};
-#endif
-
diff --git a/source3/pam_smbpass/pam_smb_auth.c b/source3/pam_smbpass/pam_smb_auth.c
deleted file mode 100644
index 06ab845..0000000
--- a/source3/pam_smbpass/pam_smb_auth.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/* Unix NT password database implementation, version 0.7.5.
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-/* indicate the following groups are defined */
-#define PAM_SM_AUTH
-
-#include "includes.h"
-#include "lib/util/debug.h"
-
-#ifndef LINUX
-
-/* This is only used in the Sun implementation. */
-#if defined(HAVE_SECURITY_PAM_APPL_H)
-#include <security/pam_appl.h>
-#elif defined(HAVE_PAM_PAM_APPL_H)
-#include <pam/pam_appl.h>
-#endif
-
-#endif  /* LINUX */
-
-#if defined(HAVE_SECURITY_PAM_MODULES_H)
-#include <security/pam_modules.h>
-#elif defined(HAVE_PAM_PAM_MODULES_H)
-#include <pam/pam_modules.h>
-#endif
-
-#include "general.h"
-
-#include "support.h"
-
-static void ret_data_cleanup(pam_handle_t *pamh, void *data, int error_status)
-{
-	free(data);
-}
-
-#define AUTH_RETURN						\
-do {								\
-	/* Restore application signal handler */		\
-	CatchSignal(SIGPIPE, oldsig_handler);			\
-	if(ret_data) {						\
-		*ret_data = retval;				\
-		pam_set_data(pamh,				\
-			"smb_setcred_return",			\
-			(void *)ret_data,			\
-			ret_data_cleanup);			\
-	}							\
-	TALLOC_FREE(frame);					\
-	return retval;						\
-} while (0)
-
-static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
-                         const char *name, struct samu *sampass, bool exist);
-
-
-/*
- * pam_sm_authenticate() authenticates users against the samba password file.
- *
- *	First, obtain the password from the user. Then use a
- *      routine in 'support.c' to authenticate the user.
- */
-
-#define _SMB_AUTHTOK  "-SMB-PASS"
-
-int pam_sm_authenticate(pam_handle_t *pamh, int flags,
-                        int argc, const char **argv)
-{
-	unsigned int ctrl;
-	int retval, *ret_data = NULL;
-	struct samu *sampass = NULL;
-	const char *name;
-	void (*oldsig_handler)(int) = NULL;
-	bool found;
-	TALLOC_CTX *frame = talloc_stackframe();
-
-	/* Points to memory managed by the PAM library. Do not free. */
-	char *p = NULL;
-
-	/* Samba initialization. */
-
-	ctrl = set_ctrl(pamh, flags, argc, argv);
-
-	/* Get a few bytes so we can pass our return value to
-		pam_sm_setcred(). */
-	ret_data = SMB_MALLOC_P(int);
-
-	/* we need to do this before we call AUTH_RETURN */
-	/* Getting into places that might use LDAP -- protect the app
-	from a SIGPIPE it's not expecting */
-	oldsig_handler = CatchSignal(SIGPIPE, SIG_IGN);
-
-	/* get the username */
-	retval = pam_get_user( pamh, &name, "Username: " );
-	if ( retval != PAM_SUCCESS ) {
-		if (on( SMB_DEBUG, ctrl )) {
-			_log_err(pamh, LOG_DEBUG, "auth: could not identify user");
-		}
-		AUTH_RETURN;
-	}
-	if (on( SMB_DEBUG, ctrl )) {
-		_log_err(pamh, LOG_DEBUG, "username [%s] obtained", name );
-	}
-
-	if (geteuid() != 0) {
-		_log_err(pamh, LOG_DEBUG, "Cannot access samba password database, not running as root.");
-		retval = PAM_AUTHINFO_UNAVAIL;
-		AUTH_RETURN;
-	}
-
-	if (!initialize_password_db(True, NULL)) {
-		_log_err(pamh, LOG_ALERT, "Cannot access samba password database" );
-		retval = PAM_AUTHINFO_UNAVAIL;
-		AUTH_RETURN;
-	}
-
-	sampass = samu_new( NULL );
-    	if (!sampass) {
-		_log_err(pamh, LOG_ALERT, "Cannot talloc a samu struct" );
-		retval = nt_status_to_pam(NT_STATUS_NO_MEMORY);
-		AUTH_RETURN;
-	}
-
-	found = pdb_getsampwnam( sampass, name );
-
-	if (on( SMB_MIGRATE, ctrl )) {
-		retval = _smb_add_user(pamh, ctrl, name, sampass, found);
-		TALLOC_FREE(sampass);
-		AUTH_RETURN;
-	}
-
-	if (!found) {
-		_log_err(pamh, LOG_ALERT, "Failed to find entry for user %s.", name);
-		retval = PAM_USER_UNKNOWN;
-		TALLOC_FREE(sampass);
-		sampass = NULL;
-		AUTH_RETURN;
-	}
-
-	/* if this user does not have a password... */
-
-	if (_smb_blankpasswd( ctrl, sampass )) {
-		TALLOC_FREE(sampass);
-		retval = PAM_SUCCESS;
-		AUTH_RETURN;
-	}
-
-	/* get this user's authentication token */
-
-	retval = _smb_read_password(pamh, ctrl, NULL, "Password: ", NULL, _SMB_AUTHTOK, &p);
-	if (retval != PAM_SUCCESS ) {
-		_log_err(pamh,LOG_CRIT, "auth: no password provided for [%s]", name);
-		TALLOC_FREE(sampass);
-		AUTH_RETURN;
-	}
-
-	/* verify the password of this user */
-
-	retval = _smb_verify_password( pamh, sampass, p, ctrl );
-	TALLOC_FREE(sampass);
-	p = NULL;
-	AUTH_RETURN;
-}
-
-/*
- * This function is for setting samba credentials.  If anyone comes up
- * with any credentials they think should be set, let me know.
- */
-
-int pam_sm_setcred(pam_handle_t *pamh, int flags,
-                   int argc, const char **argv)
-{
-	int retval, *pretval = NULL;
-
-	retval = PAM_SUCCESS;
-
-	_pam_get_data(pamh, "smb_setcred_return", &pretval);
-	if(pretval) {
-		retval = *pretval;
-		SAFE_FREE(pretval);
-	}
-	pam_set_data(pamh, "smb_setcred_return", NULL, NULL);
-
-	return retval;
-}
-
-/* Helper function for adding a user to the db. */
-static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
-                         const char *name, struct samu *sampass, bool exist)
-{
-	char *err_str = NULL;
-	char *msg_str = NULL;
-	const char *pass = NULL;
-	int retval;
-	TALLOC_CTX *frame = talloc_stackframe();
-
-	/* Get the authtok; if we don't have one, silently fail. */
-	retval = _pam_get_item( pamh, PAM_AUTHTOK, &pass );
-
-	if (retval != PAM_SUCCESS) {
-		_log_err(pamh, LOG_ALERT
-			, "pam_get_item returned error to pam_sm_authenticate" );
-		TALLOC_FREE(frame);
-		return PAM_AUTHTOK_RECOVER_ERR;
-	}
-
-	/* Add the user to the db if they aren't already there. */
-	if (!exist) {
-		retval = NT_STATUS_IS_OK(local_password_change(name, LOCAL_ADD_USER|LOCAL_SET_PASSWORD,
-					pass, &err_str, &msg_str));
-		if (!retval && err_str) {
-			make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str );
-		} else if (msg_str) {
-			make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str );
-		}
-		pass = NULL;
-
-		SAFE_FREE(err_str);
-		SAFE_FREE(msg_str);
-		TALLOC_FREE(frame);
-		return PAM_IGNORE;
-	} else {
-		/* mimick 'update encrypted' as long as the 'no pw req' flag is not set */
-		if ( pdb_get_acct_ctrl(sampass) & ~ACB_PWNOTREQ ) {
-			retval = NT_STATUS_IS_OK(local_password_change(name, LOCAL_SET_PASSWORD,
-					pass, &err_str, &msg_str));
-			if (!retval && err_str) {
-				make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str );
-			} else if (msg_str) {
-				make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str );
-			}
-		}
-	}
-    
-	SAFE_FREE(err_str);
-	SAFE_FREE(msg_str);
-	pass = NULL;
-	TALLOC_FREE(frame);
-	return PAM_IGNORE;
-}
-
-/* static module data */
-#ifdef PAM_STATIC
-struct pam_module _pam_smbpass_auth_modstruct = {
-	"pam_smbpass",
-	pam_sm_authenticate,
-	pam_sm_setcred,
-	NULL,
-	NULL,
-	NULL,
-	NULL
-};
-#endif
diff --git a/source3/pam_smbpass/pam_smb_passwd.c b/source3/pam_smbpass/pam_smb_passwd.c
deleted file mode 100644
index 1adebe2..0000000
--- a/source3/pam_smbpass/pam_smb_passwd.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-   Use PAM to update user passwords in the local SAM
-   Copyright (C) Steve Langasek		1998-2003
-   
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-/* indicate the following groups are defined */
-#define PAM_SM_PASSWORD
-
-#include "includes.h"
-
-/* This is only used in the Sun implementation.  FIXME: we really
-   want a define here that distinguishes between the Solaris PAM
-   and others (including FreeBSD). */
-
-#ifndef LINUX
-#if defined(HAVE_SECURITY_PAM_APPL_H)
-#include <security/pam_appl.h>
-#elif defined(HAVE_PAM_PAM_APPL_H)
-#include <pam/pam_appl.h>
-#endif
-#endif
-
-#if defined(HAVE_SECURITY_PAM_MODULES_H)
-#include <security/pam_modules.h>
-#elif defined(HAVE_PAM_PAM_MODULES_H)
-#include <pam/pam_modules.h>
-#endif
-
-#include "general.h" 
-
-#include "support.h"
-
-static int smb_update_db( pam_handle_t *pamh, int ctrl, const char *user,  const char *pass_new )
-{
-	int retval;
-	char *err_str = NULL;
-	char *msg_str = NULL;
-
-	retval = NT_STATUS_IS_OK(local_password_change(user, LOCAL_SET_PASSWORD, pass_new,
-	                                &err_str,
-	                                &msg_str));
-
-	if (!retval) {
-		if (err_str) {
-			make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str );
-		}
-
-		/* FIXME: what value is appropriate here? */
-		retval = PAM_AUTHTOK_ERR;
-	} else {
-		if (msg_str) {
-			make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str );
-		}
-		retval = PAM_SUCCESS;
-	}
-
-	SAFE_FREE(err_str);
-	SAFE_FREE(msg_str);
-	return retval;      
-}
-
-
-/* data tokens */
-
-#define _SMB_OLD_AUTHTOK  "-SMB-OLD-PASS"
-#define _SMB_NEW_AUTHTOK  "-SMB-NEW-PASS"
-
-/*
- * FUNCTION: pam_sm_chauthtok()
- *
- * This function is called twice by the PAM library, once with
- * PAM_PRELIM_CHECK set, and then again with PAM_UPDATE_AUTHTOK set.  With
- * Linux-PAM, these two passes generally involve first checking the old
- * token and then changing the token.  This is what we do here.
- *
- * Having obtained a new password. The function updates the
- * SMB_PASSWD_FILE file (normally, $(LIBDIR)/smbpasswd).
- */
-
-int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
-                     int argc, const char **argv)
-{
-    unsigned int ctrl;
-    int retval;
-
-    struct samu *sampass = NULL;
-    void (*oldsig_handler)(int);
-    const char *user;
-    char *pass_old = NULL;
-    char *pass_new = NULL;
-    TALLOC_CTX *frame = talloc_stackframe();
-
-    /* Samba initialization. */
-
-    ctrl = set_ctrl(pamh, flags, argc, argv);
-
-    /*
-     * First get the name of a user.  No need to do anything if we can't
-     * determine this.
-     */
-
-    retval = pam_get_user( pamh, &user, "Username: " );
-    if (retval != PAM_SUCCESS) {
-        if (on( SMB_DEBUG, ctrl )) {
-            _log_err(pamh, LOG_DEBUG, "password: could not identify user");
-        }
-	TALLOC_FREE(frame);
-        return retval;
-    }
-    if (on( SMB_DEBUG, ctrl )) {
-        _log_err(pamh, LOG_DEBUG, "username [%s] obtained", user);
-    }
-
-    if (geteuid() != 0) {
-	_log_err(pamh, LOG_DEBUG, "Cannot access samba password database, not running as root.");
-	TALLOC_FREE(frame);
-	return PAM_AUTHINFO_UNAVAIL;
-    }
-
-    /* Getting into places that might use LDAP -- protect the app
-       from a SIGPIPE it's not expecting */
-    oldsig_handler = CatchSignal(SIGPIPE, SIG_IGN);
-
-    if (!initialize_password_db(False, NULL)) {
-      _log_err(pamh, LOG_ALERT, "Cannot access samba password database" );
-        CatchSignal(SIGPIPE, oldsig_handler);
-	TALLOC_FREE(frame);
-        return PAM_AUTHINFO_UNAVAIL;
-    }
-
-    /* obtain user record */
-    if ( !(sampass = samu_new( NULL )) ) {
-        CatchSignal(SIGPIPE, oldsig_handler);
-	TALLOC_FREE(frame);
-        return nt_status_to_pam(NT_STATUS_NO_MEMORY);
-    }
-
-    if (!pdb_getsampwnam(sampass,user)) {
-        _log_err(pamh, LOG_ALERT, "Failed to find entry for user %s.", user);
-        CatchSignal(SIGPIPE, oldsig_handler);
-	TALLOC_FREE(frame);
-	return PAM_USER_UNKNOWN;
-    }
-    if (on( SMB_DEBUG, ctrl )) {
-        _log_err(pamh, LOG_DEBUG, "Located account for %s", user);
-    }
-
-    if (flags & PAM_PRELIM_CHECK) {
-        /*
-         * obtain and verify the current password (OLDAUTHTOK) for
-         * the user.
-         */
-
-        char *Announce;
-
-        if (_smb_blankpasswd( ctrl, sampass )) {
-
-            TALLOC_FREE(sampass);
-            CatchSignal(SIGPIPE, oldsig_handler);
-	    TALLOC_FREE(frame);
-            return PAM_SUCCESS;
-        }
-
-	/* Password change by root, or for an expired token, doesn't
-           require authentication.  Is this a good choice? */
-        if (getuid() != 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
-
-            /* tell user what is happening */
-		if (asprintf(&Announce, "Changing password for %s", user) == -1) {
-			_log_err(pamh, LOG_CRIT, "password: out of memory");
-			TALLOC_FREE(sampass);
-			CatchSignal(SIGPIPE, oldsig_handler);
-			TALLOC_FREE(frame);
-			return PAM_BUF_ERR;
-		}
-
-            set( SMB__OLD_PASSWD, ctrl );
-            retval = _smb_read_password( pamh, ctrl, Announce, "Current SMB password: ",
-                                         NULL, _SMB_OLD_AUTHTOK, &pass_old );
-            SAFE_FREE( Announce );
-
-            if (retval != PAM_SUCCESS) {
-                _log_err(pamh, LOG_NOTICE,
-                         "password - (old) token not obtained");
-                TALLOC_FREE(sampass);
-                CatchSignal(SIGPIPE, oldsig_handler);
-		TALLOC_FREE(frame);
-                return retval;
-            }
-
-            /* verify that this is the password for this user */
-
-            retval = _smb_verify_password( pamh, sampass, pass_old, ctrl );
-
-        } else {
-	    pass_old = NULL;
-            retval = PAM_SUCCESS;           /* root doesn't have to */
-        }
-
-        pass_old = NULL;
-        TALLOC_FREE(sampass);
-        CatchSignal(SIGPIPE, oldsig_handler);
-	TALLOC_FREE(frame);
-        return retval;
-
-    } else if (flags & PAM_UPDATE_AUTHTOK) {
-
-        /*
-         * obtain the proposed password
-         */
-
-        /*
-         * get the old token back. NULL was ok only if root [at this
-         * point we assume that this has already been enforced on a
-         * previous call to this function].
-         */
-
-        if (off( SMB_NOT_SET_PASS, ctrl )) {
-            retval = _pam_get_item( pamh, PAM_OLDAUTHTOK,
-                                   &pass_old );
-        } else {
-            retval = _pam_get_data( pamh, _SMB_OLD_AUTHTOK,
-                                   &pass_old );
-            if (retval == PAM_NO_MODULE_DATA) {
-		pass_old = NULL;
-                retval = PAM_SUCCESS;
-            }
-        }
-
-        if (retval != PAM_SUCCESS) {
-            _log_err(pamh, LOG_NOTICE, "password: user not authenticated");
-            TALLOC_FREE(sampass);
-            CatchSignal(SIGPIPE, oldsig_handler);
-	    TALLOC_FREE(frame);
-            return retval;
-        }
-
-        /*
-         * use_authtok is to force the use of a previously entered
-         * password -- needed for pluggable password strength checking
-	 * or other module stacking
-         */
-
-        if (on( SMB_USE_AUTHTOK, ctrl )) {
-            set( SMB_USE_FIRST_PASS, ctrl );
-        }
-
-        retval = _smb_read_password( pamh, ctrl
-                                      , NULL
-                                      , "Enter new SMB password: "
-                                      , "Retype new SMB password: "
-                                      , _SMB_NEW_AUTHTOK
-                                      , &pass_new );
-
-        if (retval != PAM_SUCCESS) {
-            if (on( SMB_DEBUG, ctrl )) {
-                _log_err(pamh, LOG_ALERT,
-                         "password: new password not obtained");
-            }
-            pass_old = NULL;                               /* tidy up */
-            TALLOC_FREE(sampass);
-            CatchSignal(SIGPIPE, oldsig_handler);
-	    TALLOC_FREE(frame);
-            return retval;
-        }
-
-        /*
-         * At this point we know who the user is and what they
-         * propose as their new password. Verify that the new
-         * password is acceptable.
-         */ 
-
-        if (pass_new[0] == '\0') {     /* "\0" password = NULL */
-            pass_new = NULL;
-        }
-
-        retval = _pam_smb_approve_pass(pamh, ctrl, pass_old, pass_new);
-
-        if (retval != PAM_SUCCESS) {
-            _log_err(pamh, LOG_NOTICE, "new password not acceptable");
-            pass_new = pass_old = NULL;               /* tidy up */
-            TALLOC_FREE(sampass);
-            CatchSignal(SIGPIPE, oldsig_handler);
-	    TALLOC_FREE(frame);
-            return retval;
-        }
-
-        /*
-         * By reaching here we have approved the passwords and must now
-         * rebuild the smb password file.
-         */
-
-        /* update the password database */
-
-        retval = smb_update_db(pamh, ctrl, user, pass_new);
-        if (retval == PAM_SUCCESS) {
-	    uid_t uid;
-	    
-            /* password updated */
-		if (!sid_to_uid(pdb_get_user_sid(sampass), &uid)) {
-			_log_err(pamh, LOG_NOTICE,
-			         "Unable to get uid for user %s",
-				pdb_get_username(sampass));
-			_log_err(pamh, LOG_NOTICE, "password for (%s) changed by (%s/%d)",
-				user, uidtoname(getuid()), getuid());
-		} else {
-			_log_err(pamh, LOG_NOTICE, "password for (%s/%d) changed by (%s/%d)",
-				user, uid, uidtoname(getuid()), getuid());
-		}
-	} else {
-		_log_err(pamh, LOG_ERR, "password change failed for user %s", user);
-	}
-
-        pass_old = pass_new = NULL;
-	if (sampass) {
-		TALLOC_FREE(sampass);
-		sampass = NULL;
-	}
-
-    } else {            /* something has broken with the library */
-
-        _log_err(pamh, LOG_ALERT, "password received unknown request");
-        retval = PAM_ABORT;
-
-    }
-    
-    if (sampass) {
-    	TALLOC_FREE(sampass);
-	sampass = NULL;
-    }
-
-    TALLOC_FREE(sampass);
-    CatchSignal(SIGPIPE, oldsig_handler);
-    TALLOC_FREE(frame);
-    return retval;
-}
-
-/* static module data */
-#ifdef PAM_STATIC
-struct pam_module _pam_smbpass_passwd_modstruct = {
-     "pam_smbpass",
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     pam_sm_chauthtok
-};
-#endif
-
diff --git a/source3/pam_smbpass/samples/README b/source3/pam_smbpass/samples/README
deleted file mode 100644
index d776033..0000000
--- a/source3/pam_smbpass/samples/README
+++ /dev/null
@@ -1,3 +0,0 @@
-This directory contains example configurations demonstrating various uses
-of pam_smbpass.  These examples use Linux-style /etc/pam.d syntax, and
-must be modified for use on Solaris systems.
diff --git a/source3/pam_smbpass/samples/kdc-pdc b/source3/pam_smbpass/samples/kdc-pdc
deleted file mode 100644
index 70f1998..0000000
--- a/source3/pam_smbpass/samples/kdc-pdc
+++ /dev/null
@@ -1,15 +0,0 @@
-#%PAM-1.0
-# kdc-pdc
-# 
-# A sample PAM configuration that shows pam_smbpass used together with
-# pam_krb5.  This could be useful on a Samba PDC that is also a member of
-# a Kerberos realm.
-
-auth       requisite        pam_nologin.so
-auth       requisite        pam_krb5.so
-auth       optional         pam_smbpass.so migrate
-account    required         pam_krb5.so
-password   requisite        pam_cracklib.so retry=3
-password   optional         pam_smbpass.so nullok use_authtok try_first_pass
-password   required         pam_krb5.so use_authtok try_first_pass
-session    required         pam_krb5.so
diff --git a/source3/pam_smbpass/samples/password-mature b/source3/pam_smbpass/samples/password-mature
deleted file mode 100644
index 6d73e09..0000000
--- a/source3/pam_smbpass/samples/password-mature
+++ /dev/null
@@ -1,14 +0,0 @@
-#%PAM-1.0
-# password-mature
-#
-# A sample PAM configuration for a 'mature' smbpasswd installation.
-# private/smbpasswd is fully populated, and we consider it an error if
-# the smbpasswd doesn't exist or doesn't match the Unix password.
-
-auth       requisite        pam_nologin.so
-auth       required         pam_unix.so
-account    required         pam_unix.so
-password   requisite        pam_cracklib.so retry=3
-password   requisite        pam_unix.so shadow md5 use_authtok try_first_pass
-password   required         pam_smbpass.so use_authtok use_first_pass
-session    required         pam_unix.so
diff --git a/source3/pam_smbpass/samples/password-migration b/source3/pam_smbpass/samples/password-migration
deleted file mode 100644
index 305cb53..0000000
--- a/source3/pam_smbpass/samples/password-migration
+++ /dev/null
@@ -1,18 +0,0 @@
-#%PAM-1.0
-# password-migration
-#
-# A sample PAM configuration that shows the use of pam_smbpass to migrate
-# from plaintext to encrypted passwords for Samba.  Unlike other methods,
-# this can be used for users who have never connected to Samba shares:
-# password migration takes place when users ftp in, login using ssh, pop
-# their mail, etc.
-
-auth       requisite        pam_nologin.so
-# pam_smbpass is called IFF pam_unix succeeds.
-auth       requisite        pam_unix.so
-auth       optional         pam_smbpass.so migrate
-account    required         pam_unix.so
-password   requisite        pam_cracklib.so retry=3
-password   requisite        pam_unix.so shadow md5 use_authtok try_first_pass
-password   optional         pam_smbpass.so nullok use_authtok try_first_pass
-session    required         pam_unix.so
diff --git a/source3/pam_smbpass/samples/password-sync b/source3/pam_smbpass/samples/password-sync
deleted file mode 100644
index 0a950dd..0000000
--- a/source3/pam_smbpass/samples/password-sync
+++ /dev/null
@@ -1,15 +0,0 @@
-#%PAM-1.0
-# password-sync
-#
-# A sample PAM configuration that shows the use of pam_smbpass to make
-# sure private/smbpasswd is kept in sync when /etc/passwd (/etc/shadow)
-# is changed.  Useful when an expired password might be changed by an
-# application (such as ssh).
-
-auth       requisite        pam_nologin.so
-auth       required         pam_unix.so
-account    required         pam_unix.so
-password   requisite        pam_cracklib.so retry=3
-password   requisite        pam_unix.so shadow md5 use_authtok try_first_pass
-password   required         pam_smbpass.so nullok use_authtok try_first_pass
-session    required         pam_unix.so
diff --git a/source3/pam_smbpass/support.c b/source3/pam_smbpass/support.c
deleted file mode 100644
index c49c2c5..0000000
--- a/source3/pam_smbpass/support.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/* Unix NT password database implementation, version 0.6.
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#include "includes.h"
-#include "general.h"
-
-#include "support.h"
-#include "secrets.h"
-
-#include "../libcli/auth/libcli_auth.h"
-#if defined(HAVE_SECURITY_PAM_EXT_H)
-#include <security/pam_ext.h>
-#elif defined(HAVE_PAM_PAM_EXT_H)
-#include <pam/pam_ext.h>
-#endif
-
-#if defined(HAVE_SECURITY__PAM_MACROS_H)
-#include <security/_pam_macros.h>
-#elif defined(HAVE_PAM__PAM_MACROS_H)
-#include <pam/_pam_macros.h>
-#endif
-
-#ifdef HAVE_SYSLOG_H
-#include <syslog.h>
-#endif
-
-#define _pam_overwrite(x)        \
-do {                             \
-     register char *__xx__;      \
-     if ((__xx__=(x)))           \
-	  while (*__xx__)        \
-	       *__xx__++ = '\0'; \
-} while (0)
-
-/*
- * Don't just free it, forget it too.
- */
-
-#define _pam_drop(X) \
-do {                 \
-    if (X) {         \
-	free(X);     \
-	X=NULL;      \
-    }                \
-} while (0)
-
-#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
-do {                                              \
-    int reply_i;                                  \
-						  \
-    for (reply_i=0; reply_i<replies; ++reply_i) { \
-	if (reply[reply_i].resp) {                \
-	    _pam_overwrite(reply[reply_i].resp);  \
-	    free(reply[reply_i].resp);            \
-	}                                         \
-    }                                             \
-    if (reply)                                    \
-	free(reply);                              \
-} while (0)
-
-
-int converse(pam_handle_t *, int, int, struct pam_message **,
-			 struct pam_response **);
-int make_remark(pam_handle_t *, unsigned int, int, const char *);
-void _cleanup(pam_handle_t *, void *, int);
-char *_pam_delete(register char *);
-
-/* syslogging function for errors and other information */
-#ifdef HAVE_PAM_VSYSLOG
-void _log_err( pam_handle_t *pamh, int err, const char *format, ... )
-{
-	va_list args;
-
-	va_start(args, format);
-	pam_vsyslog(pamh, err, format, args);
-	va_end(args);
-}
-#else
-void _log_err( pam_handle_t *pamh, int err, const char *format, ... )
-{
-	va_list args;
-	char *mod_format;
-
-	if (asprintf(&mod_format, "(pam_smbpass) %s", format) == -1) {
-		/*
-		 * try really, really hard to log something, since
-		 * this may have been a message about a malloc()
-		 * failure...
-		 */
-		va_start(args, format);
-		vsyslog(err | LOG_AUTH, format, args);
-		va_end(args);
-		return;
-	}
-
-	va_start(args, format);
-	vsyslog(err | LOG_AUTH, mod_format, args);
-	va_end(args);
-
-	free(mod_format);
-}
-#endif
-
-/* this is a front-end for module-application conversations */
-
-int converse( pam_handle_t * pamh, int ctrl, int nargs
-	      , struct pam_message **message
-	      , struct pam_response **response )
-{
-	int retval;
-	struct pam_conv *conv = NULL;
-
-	retval = _pam_get_item(pamh, PAM_CONV, &conv);
-	if (retval == PAM_SUCCESS) {
-
-		retval = conv->conv(nargs, (const struct pam_message **) message
-							,response, conv->appdata_ptr);
-
-		if (retval != PAM_SUCCESS && on(SMB_DEBUG, ctrl)) {
-			_log_err(pamh, LOG_DEBUG, "conversation failure [%s]"
-					 ,pam_strerror(pamh, retval));
-		}
-	} else {
-		_log_err(pamh, LOG_ERR, "couldn't obtain coversation function [%s]"
-				 ,pam_strerror(pamh, retval));
-	}
-
-	return retval;				/* propagate error status */
-}
-
-int make_remark( pam_handle_t * pamh, unsigned int ctrl
-		 , int type, const char *text )
-{
-	if (off(SMB__QUIET, ctrl)) {
-		struct pam_message *pmsg[1], msg[1];
-		struct pam_response *resp;
-
-		pmsg[0] = &msg[0];
-		msg[0].msg = discard_const_p(char, text);
-		msg[0].msg_style = type;
-		resp = NULL;
-
-		return converse(pamh, ctrl, 1, pmsg, &resp);
-	}
-	return PAM_SUCCESS;
-}
-
-
-/* set the control flags for the SMB module. */
-
-unsigned int set_ctrl(pam_handle_t *pamh,
-		      int flags,
-		      int argc,
-		      const char **argv)
-{
-    int i = 0;
-    const char *service_file = NULL;
-    unsigned int ctrl;
-    bool ok;
-
-    ctrl = SMB_DEFAULTS;	/* the default selection of options */
-
-    /* set some flags manually */
-
-    /* A good, sane default (matches Samba's behavior). */
-    set( SMB__NONULL, ctrl );
-
-    /* initialize service file location */
-    service_file=get_dyn_CONFIGFILE();
-
-    if (flags & PAM_SILENT) {
-        set( SMB__QUIET, ctrl );
-    }
-
-    /* Run through the arguments once, looking for an alternate smb config
-       file location */
-    while (i < argc) {
-	int j;
-
-	for (j = 0; j < SMB_CTRLS_; ++j) {
-	    if (smb_args[j].token
-	        && !strncmp(argv[i], smb_args[j].token, strlen(smb_args[j].token)))
-	    {
-		break;
-	    }
-	}
-
-	if (j == SMB_CONF_FILE) {
-	    service_file = argv[i] + 8;
-	}
-	i++;
-    }
-
-    /* Read some options from the Samba config. Can be overridden by
-       the PAM config. */
-    if(lp_load_client(service_file) == false) {
-	_log_err(pamh, LOG_ERR, "Error loading service file %s", service_file);
-    }
-
-	ok = secrets_init();
-	if (!ok) {
-		_log_err(pamh, LOG_ERR, "Error loading secrets database");
-	}
-
-    if (lp_null_passwords()) {
-        set( SMB__NULLOK, ctrl );
-    }
-
-    /* now parse the rest of the arguments to this module */
-
-    while (argc-- > 0) {
-        int j;
-
-        for (j = 0; j < SMB_CTRLS_; ++j) {
-            if (smb_args[j].token
-	        && !strncmp(*argv, smb_args[j].token, strlen(smb_args[j].token)))
-            {
-                break;
-            }
-        }
-
-        if (j >= SMB_CTRLS_) {
-            _log_err(pamh, LOG_ERR, "unrecognized option [%s]", *argv);
-        } else {
-            ctrl &= smb_args[j].mask;	/* for turning things off */
-            ctrl |= smb_args[j].flag;	/* for turning things on  */
-        }
-
-        ++argv;				/* step to next argument */
-    }
-
-    /* auditing is a more sensitive version of debug */
-
-    if (on( SMB_AUDIT, ctrl )) {
-        set( SMB_DEBUG, ctrl );
-    }
-    /* return the set of flags */
-
-    return ctrl;
-}
-
-/* use this to free strings. ESPECIALLY password strings */
-
-char * _pam_delete( register char *xx )
-{
-    _pam_overwrite( xx );
-    _pam_drop( xx );
-    return NULL;
-}
-
-void _cleanup( pam_handle_t * pamh, void *x, int error_status )
-{
-    x = _pam_delete( (char *) x );
-}
-
-/* JHT
- *
- * Safe duplication of character strings. "Paranoid"; don't leave
- * evidence of old token around for later stack analysis.
- *
- */
-char * smbpXstrDup( pam_handle_t *pamh, const char *x )
-{
-    register char *newstr = NULL;
-
-    if (x != NULL) {
-        register int i;
-
-        for (i = 0; x[i]; ++i); /* length of string */
-        if ((newstr = SMB_MALLOC_ARRAY(char, ++i)) == NULL) {
-            i = 0;
-            _log_err(pamh, LOG_CRIT, "out of memory in smbpXstrDup");
-        } else {
-            while (i-- > 0) {
-                newstr[i] = x[i];
-            }
-        }
-        x = NULL;
-    }
-    return newstr;			/* return the duplicate or NULL on error */
-}
-
-/* ************************************************************** *
- * Useful non-trivial functions                                   *
- * ************************************************************** */
-
-void _cleanup_failures( pam_handle_t * pamh, void *fl, int err )
-{
-    int quiet;
-    const char *service = NULL;
-    struct _pam_failed_auth *failure;
-
-#ifdef PAM_DATA_SILENT
-    quiet = err & PAM_DATA_SILENT;	/* should we log something? */
-#else
-    quiet = 0;
-#endif
-#ifdef PAM_DATA_REPLACE
-    err &= PAM_DATA_REPLACE;	/* are we just replacing data? */
-#endif
-    failure = (struct _pam_failed_auth *) fl;
-
-    if (failure != NULL) {
-
-#ifdef PAM_DATA_SILENT
-        if (!quiet && !err) {	/* under advisement from Sun,may go away */
-#else
-        if (!quiet) {	/* under advisement from Sun,may go away */
-#endif
-
-            /* log the number of authentication failures */
-            if (failure->count != 0) {
-                _pam_get_item( pamh, PAM_SERVICE, &service );
-                _log_err(pamh, LOG_NOTICE
-                          , "%d authentication %s "
-                            "from %s for service %s as %s(%d)"
-                          , failure->count
-                          , failure->count == 1 ? "failure" : "failures"
-                          , failure->agent
-                          , service == NULL ? "**unknown**" : service 
-                          , failure->user, failure->id );
-                if (failure->count > SMB_MAX_RETRIES) {
-                    _log_err(pamh, LOG_ALERT
-                              , "service(%s) ignoring max retries; %d > %d"
-                              , service == NULL ? "**unknown**" : service
-                              , failure->count
-                              , SMB_MAX_RETRIES );
-                }
-            }
-        }
-        _pam_delete( failure->agent );	/* tidy up */
-        _pam_delete( failure->user );	/* tidy up */
-	SAFE_FREE( failure );
-    }
-}
-
-int _smb_verify_password( pam_handle_t * pamh, struct samu *sampass,
-			  const char *p, unsigned int ctrl )
-{
-    uchar lm_pw[16];
-    uchar nt_pw[16];
-    int retval = PAM_AUTH_ERR;
-    char *data_name;
-    const char *name;
-
-    if (!sampass)
-        return PAM_ABORT;
-
-    name = pdb_get_username(sampass);
-
-#ifdef HAVE_PAM_FAIL_DELAY
-    if (off( SMB_NODELAY, ctrl )) {
-        (void) pam_fail_delay( pamh, 1000000 );	/* 1 sec delay for on failure */
-    }
-#endif
-
-    if (!pdb_get_nt_passwd(sampass))
-    {
-        _log_err(pamh, LOG_DEBUG, "user %s has null SMB password", name);
-
-        if (off( SMB__NONULL, ctrl )
-            && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ))
-        { /* this means we've succeeded */
-            return PAM_SUCCESS;
-        } else {
-            const char *service = NULL;
-
-            _pam_get_item( pamh, PAM_SERVICE, &service );
-            _log_err(pamh, LOG_NOTICE, "failed auth request by %s for service %s as %s",
-                      uidtoname(getuid()), service ? service : "**unknown**", name);
-            return PAM_AUTH_ERR;
-        }
-    }
-
-    if (asprintf(&data_name, "-SMB-FAIL- %s", name) == -1) {
-        _log_err(pamh, LOG_CRIT, "no memory for data-name" );
-        return PAM_AUTH_ERR;
-    }
-
-    /*
-     * The password we were given wasn't an encrypted password, or it
-     * didn't match the one we have.  We encrypt the password now and try
-     * again.
-     */
-
-    nt_lm_owf_gen(p, nt_pw, lm_pw);
-
-    /* the moment of truth -- do we agree with the password? */
-
-    if (!memcmp( nt_pw, pdb_get_nt_passwd(sampass), 16 )) {
-
-        retval = PAM_SUCCESS;
-        if (data_name) {		/* reset failures */
-            pam_set_data(pamh, data_name, NULL, _cleanup_failures);
-        }
-    } else {
-
-        const char *service = NULL;
-
-        retval = PAM_AUTH_ERR;
-
-        _pam_get_item( pamh, PAM_SERVICE, &service );
-
-        if (data_name != NULL) {
-            struct _pam_failed_auth *newauth = NULL;
-            const struct _pam_failed_auth *old = NULL;
-
-            /* get a failure recorder */
-
-            newauth = SMB_MALLOC_P( struct _pam_failed_auth );
-
-            if (newauth != NULL) {
-
-                /* any previous failures for this user ? */
-                _pam_get_data(pamh, data_name, &old);
-
-                if (old != NULL) {
-                    newauth->count = old->count + 1;
-                    if (newauth->count >= SMB_MAX_RETRIES) {
-                        retval = PAM_MAXTRIES;
-                    }
-                } else {
-                    _log_err(pamh, LOG_NOTICE,
-                      "failed auth request by %s for service %s as %s",
-                      uidtoname(getuid()),
-                      service ? service : "**unknown**", name);
-                    newauth->count = 1;
-                }
-		if (!sid_to_uid(pdb_get_user_sid(sampass), &(newauth->id))) {
-                    _log_err(pamh, LOG_NOTICE,
-                      "failed auth request by %s for service %s as %s",
-                      uidtoname(getuid()),
-                      service ? service : "**unknown**", name);
-		}		
-                newauth->user = smbpXstrDup( pamh, name );
-                newauth->agent = smbpXstrDup( pamh, uidtoname( getuid() ) );
-                pam_set_data( pamh, data_name, newauth, _cleanup_failures );
-
-            } else {
-                _log_err(pamh, LOG_CRIT, "no memory for failure recorder" );
-                _log_err(pamh, LOG_NOTICE,
-                      "failed auth request by %s for service %s as %s(%d)",
-                      uidtoname(getuid()),
-                      service ? service : "**unknown**", name);
-            }
-        }
-        _log_err(pamh, LOG_NOTICE,
-                  "failed auth request by %s for service %s as %s(%d)",
-                  uidtoname(getuid()),
-                  service ? service : "**unknown**", name);
-    }
-
-    _pam_delete( data_name );
-
-    return retval;
-}
-
-
-/*
- * _smb_blankpasswd() is a quick check for a blank password
- *
- * returns TRUE if user does not have a password
- * - to avoid prompting for one in such cases (CG)
- */
-
-int _smb_blankpasswd( unsigned int ctrl, struct samu *sampass )
-{
-	int retval;
-
-	/*
-	 * This function does not have to be too smart if something goes
-	 * wrong, return FALSE and let this case to be treated somewhere
-	 * else (CG)
-	 */
-
-	if (on( SMB__NONULL, ctrl ))
-		return 0;		/* will fail but don't let on yet */
-
-	if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ))
-		return 0;
-
-	if (pdb_get_nt_passwd(sampass) == NULL)
-		retval = 1;
-	else
-		retval = 0;
-
-	return retval;
-}
-
-/*
- * obtain a password from the user
- */
-
-int _smb_read_password( pam_handle_t * pamh, unsigned int ctrl,
-                        const char *comment, const char *prompt1,
-                        const char *prompt2, const char *data_name, char **pass )
-{
-    int authtok_flag;
-    int retval;
-    char *item = NULL;
-    char *token;
-
-    struct pam_message msg[3], *pmsg[3];
-    struct pam_response *resp;
-    int i, expect;
-
-
-    /* make sure nothing inappropriate gets returned */
-
-    *pass = token = NULL;
-
-    /* which authentication token are we getting? */
-
-    authtok_flag = on(SMB__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;
-
-    /* should we obtain the password from a PAM item ? */
-
-    if (on(SMB_TRY_FIRST_PASS, ctrl) || on(SMB_USE_FIRST_PASS, ctrl)) {
-        retval = _pam_get_item( pamh, authtok_flag, &item );
-        if (retval != PAM_SUCCESS) {
-            /* very strange. */
-            _log_err(pamh, LOG_ALERT,
-                     "pam_get_item returned error to smb_read_password");
-            return retval;
-        } else if (item != NULL) {	/* we have a password! */
-            *pass = item;
-            item = NULL;
-            return PAM_SUCCESS;
-        } else if (on( SMB_USE_FIRST_PASS, ctrl )) {
-            return PAM_AUTHTOK_RECOVER_ERR;		/* didn't work */
-        } else if (on( SMB_USE_AUTHTOK, ctrl )
-                   && off( SMB__OLD_PASSWD, ctrl ))
-        {
-            return PAM_AUTHTOK_RECOVER_ERR;
-        }
-    }
-
-    /*
-     * getting here implies we will have to get the password from the
-     * user directly.
-     */
-
-    /* prepare to converse */
-    if (comment != NULL && off(SMB__QUIET, ctrl)) {
-        pmsg[0] = &msg[0];
-        msg[0].msg_style = PAM_TEXT_INFO;
-        msg[0].msg = discard_const_p(char, comment);
-        i = 1;
-    } else {
-        i = 0;
-    }
-
-    pmsg[i] = &msg[i];
-    msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
-    msg[i++].msg = discard_const_p(char, prompt1);
-
-    if (prompt2 != NULL) {
-        pmsg[i] = &msg[i];
-        msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
-        msg[i++].msg = discard_const_p(char, prompt2);
-        expect = 2;
-    } else
-        expect = 1;
-
-    resp = NULL;
-
-    retval = converse( pamh, ctrl, i, pmsg, &resp );
-
-    if (resp != NULL) {
-        int j = comment ? 1 : 0;
-        /* interpret the response */
-
-        if (retval == PAM_SUCCESS) {	/* a good conversation */
-
-            token = smbpXstrDup(pamh, resp[j++].resp);
-            if (token != NULL) {
-                if (expect == 2) {
-                    /* verify that password entered correctly */
-                    if (!resp[j].resp || strcmp( token, resp[j].resp )) {
-                        _pam_delete( token );
-                        retval = PAM_AUTHTOK_RECOVER_ERR;
-                        make_remark( pamh, ctrl, PAM_ERROR_MSG
-                                     , MISTYPED_PASS );
-                    }
-                }
-            } else {
-                _log_err(pamh, LOG_NOTICE,
-		         "could not recover authentication token");
-            }
-        }
-
-        /* tidy up */
-        _pam_drop_reply( resp, expect );
-
-    } else {
-        retval = (retval == PAM_SUCCESS) ? PAM_AUTHTOK_RECOVER_ERR : retval;
-    }
-
-    if (retval != PAM_SUCCESS) {
-        if (on( SMB_DEBUG, ctrl ))
-            _log_err(pamh, LOG_DEBUG, "unable to obtain a password");
-        return retval;
-    }
-    /* 'token' is the entered password */
-
-    if (off( SMB_NOT_SET_PASS, ctrl )) {
-
-        /* we store this password as an item */
-
-        retval = pam_set_item( pamh, authtok_flag, (const void *)token );
-        _pam_delete( token );		/* clean it up */
-        if (retval != PAM_SUCCESS
-            || (retval = _pam_get_item( pamh, authtok_flag
-                            ,&item )) != PAM_SUCCESS)
-        {
-            _log_err(pamh, LOG_CRIT, "error manipulating password");
-            return retval;
-        }
-    } else {
-        /*
-         * then store it as data specific to this module. pam_end()
-         * will arrange to clean it up.
-         */
-
-        retval = pam_set_data( pamh, data_name, (void *) token, _cleanup );
-        if (retval != PAM_SUCCESS
-            || (retval = _pam_get_data( pamh, data_name, &item ))
-                             != PAM_SUCCESS)
-        {
-            _log_err(pamh, LOG_CRIT, "error manipulating password data [%s]",
-                     pam_strerror( pamh, retval ));
-            _pam_delete( token );
-            item = NULL;
-            return retval;
-        }
-        token = NULL;			/* break link to password */
-    }
-
-    *pass = item;
-    item = NULL;			/* break link to password */
-
-    return PAM_SUCCESS;
-}
-
-int _pam_smb_approve_pass(pam_handle_t * pamh,
-		unsigned int ctrl,
-		const char *pass_old,
-		const char *pass_new )
-{
-
-    /* Further checks should be handled through module stacking. -SRL */
-    if (pass_new == NULL || (pass_old && !strcmp( pass_old, pass_new )))
-    {
-	if (on(SMB_DEBUG, ctrl)) {
-	    _log_err(pamh, LOG_DEBUG,
-	             "passwd: bad authentication token (null or unchanged)");
-	}
-	make_remark( pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
-				"No password supplied" : "Password unchanged" );
-	return PAM_AUTHTOK_ERR;
-    }
-
-    return PAM_SUCCESS;
-}
-
-/*
- * Work around the pam API that has functions with void ** as parameters
- * These lead to strict aliasing warnings with gcc.
- */
-int _pam_get_item(const pam_handle_t *pamh,
-		  int item_type,
-		  const void *_item)
-{
-	const void **item = (const void **)_item;
-	return pam_get_item(pamh, item_type, item);
-}
-
-int _pam_get_data(const pam_handle_t *pamh,
-		  const char *module_data_name,
-		  const void *_data)
-{
-	const void **data = (const void **)_data;
-	return pam_get_data(pamh, module_data_name, data);
-}
diff --git a/source3/pam_smbpass/support.h b/source3/pam_smbpass/support.h
deleted file mode 100644
index 832247d..0000000
--- a/source3/pam_smbpass/support.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* syslogging function for errors and other information */
-extern void _log_err(pam_handle_t *, int, const char *, ...);
-
-/* set the control flags for the UNIX module. */
-extern unsigned int set_ctrl(pam_handle_t *, int, int, const char **);
-
-/* generic function for freeing pam data segments */
-extern void _cleanup(pam_handle_t *, void *, int);
-
-/*
- * Safe duplication of character strings. "Paranoid"; don't leave
- * evidence of old token around for later stack analysis.
- */
-
-extern char *smbpXstrDup(pam_handle_t *,const char *);
-
-/* ************************************************************** *
- * Useful non-trivial functions                                   *
- * ************************************************************** */
-
-extern void _cleanup_failures(pam_handle_t *, void *, int);
-
-/* compare 2 strings */
-extern bool strequal(const char *, const char *);
-
-extern struct smb_passwd *
-_my_get_smbpwnam(FILE *, const char *, bool *, bool *, long *);
-
-extern int _smb_verify_password( pam_handle_t *pamh , struct samu *sampass, 
-	const char *p, unsigned int ctrl );
-
-/*
- * this function obtains the name of the current user and ensures
- * that the PAM_USER item is set to this value
- */
-
-extern int _smb_get_user(pam_handle_t *, unsigned int,
-			 const char *, const char **);
-
-/* _smb_blankpasswd() is a quick check for a blank password */
-
-extern int _smb_blankpasswd(unsigned int, struct samu *);
-
-
-/* obtain a password from the user */
-extern int _smb_read_password( pam_handle_t *, unsigned int, const char*,
-				const char *, const char *, const char *, char **);
-
-extern int _pam_smb_approve_pass(pam_handle_t *, unsigned int, const char *,
-				 const char *);
-
-int _pam_get_item(const pam_handle_t *pamh,
-		  int item_type,
-		  const void *_item);
-int _pam_get_data(const pam_handle_t *pamh,
-		  const char *module_data_name,
-		  const void *_data);
diff --git a/source3/pam_smbpass/wscript_build b/source3/pam_smbpass/wscript_build
deleted file mode 100644
index a4eaa6c..0000000
--- a/source3/pam_smbpass/wscript_build
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-
-if bld.CONFIG_SET('WITH_PAM_MODULES'):
-    bld.SAMBA3_LIBRARY('pamsmbpass',
-        source='''pam_smb_auth.c
-                  pam_smb_passwd.c
-                  pam_smb_acct.c
-                  support.c''',
-        allow_warnings=True,
-        deps='''tdb talloc pam PAM_ERRORS wbclient cap asn1util param pdb
-                LIBNTLMSSP LIBTSOCKET''',
-        cflags='-DLOCALEDIR=\"%s/locale\"' % bld.env.DATADIR,
-        realname='pam_smbpass.so',
-        install_path='${PAMMODULESDIR}',
-        enabled=bld.env.with_pam_smbpass
-        )
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index c576b22..50b29e3 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -75,10 +75,6 @@
 #include <sys/sysctl.h>
 #endif
 
-#ifdef HAVE_HTTPCONNECTENCRYPT
-#include <cups/http.h>
-#endif
-
 bool bLoaded = false;
 
 extern userdom_struct current_user_info;
@@ -97,8 +93,11 @@ static struct smbconf_csn conf_last_csn;
 static int config_backend = CONFIG_BACKEND_FILE;
 
 /* some helpful bits */
-#define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && (ServicePtrs != NULL) && ServicePtrs[(i)]->valid)
-#define VALID(i) (ServicePtrs != NULL && ServicePtrs[i]->valid)
+#define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && \
+                       (ServicePtrs != NULL) && \
+		       (ServicePtrs[(i)] != NULL) && ServicePtrs[(i)]->valid)
+#define VALID(i) ((ServicePtrs != NULL) && (ServicePtrs[i]!= NULL) && \
+                  ServicePtrs[i]->valid)
 
 #define USERSHARE_VALID 1
 #define USERSHARE_PENDING_DELETE 2
@@ -122,8 +121,8 @@ static struct loadparm_service sDefault =
 	.invalid_users = NULL,
 	.valid_users = NULL,
 	.admin_users = NULL,
-	.szCopy = NULL,
-	.szInclude = NULL,
+	.copy = NULL,
+	.include = NULL,
 	.preexec = NULL,
 	.postexec = NULL,
 	.root_preexec = NULL,
@@ -158,7 +157,7 @@ static struct loadparm_service sDefault =
 	.aio_write_behind = NULL,
 	.dfree_command = NULL,
 	.min_print_space = 0,
-	.iMaxPrintJobs = 1000,
+	.max_print_jobs = 1000,
 	.max_reported_print_jobs = 0,
 	.write_cache_size = 0,
 	.create_mask = 0744,
@@ -183,7 +182,7 @@ static struct loadparm_service sDefault =
 	.hide_unwriteable_files = false,
 	.browseable = true,
 	.access_based_share_enum = false,
-	.bAvailable = true,
+	.available = true,
 	.read_only = true,
 	.spotlight = false,
 	.guest_only = false,
@@ -204,7 +203,7 @@ static struct loadparm_service sDefault =
 	.level2_oplocks = true,
 	.only_user = false,
 	.mangled_names = true,
-	.bWidelinks = false,
+	.wide_links = false,
 	.follow_symlinks = true,
 	.sync_always = false,
 	.strict_allocate = false,
@@ -467,7 +466,7 @@ bool store_lp_set_cmdline(const char *pszParmName, const char *pszParmValue)
 		return false;
 	}
 
-	DLIST_ADD_END(stored_options, entry, struct lp_stored_option);
+	DLIST_ADD_END(stored_options, entry);
 
 	return true;
 }
@@ -588,7 +587,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 	/*
 	 * By default support explicit binding to broadcast
  	 * addresses.
-         */
+ 	 */
 	Globals.nmbd_bind_explicit_broadcast = true;
 
 	s = talloc_asprintf(talloc_tos(), "Samba %s", samba_version_string());
@@ -708,7 +707,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 	Globals.reset_on_zero_vc = false;
 	Globals.log_writeable_files_on_exit = false;
 	Globals.create_krb5_conf = true;
-	Globals.winbindMaxDomainConnections = 1;
+	Globals._winbind_max_domain_connections = 1;
 
 	/* hostname lookups can be very expensive and are broken on
 	   a large number of sites (tridge) */
@@ -719,10 +718,10 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 
 	lpcfg_string_set(Globals.ctx, &Globals.passdb_backend, "tdbsam");
 	lpcfg_string_set(Globals.ctx, &Globals.ldap_suffix, "");
-	lpcfg_string_set(Globals.ctx, &Globals.szLdapMachineSuffix, "");
-	lpcfg_string_set(Globals.ctx, &Globals.szLdapUserSuffix, "");
-	lpcfg_string_set(Globals.ctx, &Globals.szLdapGroupSuffix, "");
-	lpcfg_string_set(Globals.ctx, &Globals.szLdapIdmapSuffix, "");
+	lpcfg_string_set(Globals.ctx, &Globals._ldap_machine_suffix, "");
+	lpcfg_string_set(Globals.ctx, &Globals._ldap_user_suffix, "");
+	lpcfg_string_set(Globals.ctx, &Globals._ldap_group_suffix, "");
+	lpcfg_string_set(Globals.ctx, &Globals._ldap_idmap_suffix, "");
 
 	lpcfg_string_set(Globals.ctx, &Globals.ldap_admin_dn, "");
 	Globals.ldap_ssl = LDAP_SSL_START_TLS;
@@ -774,12 +773,14 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 	Globals.wins_dns_proxy = true;
 
 	Globals.allow_trusted_domains = true;
-	lpcfg_string_set(Globals.ctx, &Globals.szIdmapBackend, "tdb");
+	lpcfg_string_set(Globals.ctx, &Globals.idmap_backend, "tdb");
 
 	lpcfg_string_set(Globals.ctx, &Globals.template_shell, "/bin/false");
-	lpcfg_string_set(Globals.ctx, &Globals.template_homedir, "/home/%D/%U");
+	lpcfg_string_set(Globals.ctx, &Globals.template_homedir,
+			 "/home/%D/%U");
 	lpcfg_string_set(Globals.ctx, &Globals.winbind_separator, "\\");
-	lpcfg_string_set(Globals.ctx, &Globals.winbindd_socket_directory, dyn_WINBINDD_SOCKET_DIR);
+	lpcfg_string_set(Globals.ctx, &Globals.winbindd_socket_directory,
+			 dyn_WINBINDD_SOCKET_DIR);
 
 	lpcfg_string_set(Globals.ctx, &Globals.cups_server, "");
 	lpcfg_string_set(Globals.ctx, &Globals.iprint_server, "");
@@ -844,7 +845,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 	/* By default no shares out of the registry */
 	Globals.registry_shares = false;
 
-	Globals.iminreceivefile = 0;
+	Globals.min_receivefile_size = 0;
 
 	Globals.map_untrusted_to_domain = false;
 	Globals.multicast_dns_register = true;
@@ -852,7 +853,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 	Globals.smb2_max_read = DEFAULT_SMB2_MAX_READ;
 	Globals.smb2_max_write = DEFAULT_SMB2_MAX_WRITE;
 	Globals.smb2_max_trans = DEFAULT_SMB2_MAX_TRANSACT;
-	Globals.ismb2_max_credits = DEFAULT_SMB2_MAX_CREDITS;
+	Globals.smb2_max_credits = DEFAULT_SMB2_MAX_CREDITS;
 	Globals.smb2_leases = false;
 
 	lpcfg_string_set(Globals.ctx, &Globals.ncalrpc_dir,
@@ -867,20 +868,21 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 	lpcfg_string_set(Globals.ctx, &Globals._tls_keyfile, "tls/key.pem");
 	lpcfg_string_set(Globals.ctx, &Globals._tls_certfile, "tls/cert.pem");
 	lpcfg_string_set(Globals.ctx, &Globals._tls_cafile, "tls/ca.pem");
-	lpcfg_string_set(Globals.ctx, &Globals.tls_priority, "NORMAL:-VERS-SSL3.0");
+	lpcfg_string_set(Globals.ctx, &Globals.tls_priority,
+			 "NORMAL:-VERS-SSL3.0");
 
 	lpcfg_string_set(Globals.ctx, &Globals.share_backend, "classic");
 
-	Globals.iPreferredMaster = Auto;
+	Globals._preferred_master = Auto;
 
 	Globals.allow_dns_updates = DNS_UPDATE_SIGNED;
 
 	lpcfg_string_set(Globals.ctx, &Globals.ntp_signd_socket_directory,
-		get_dyn_NTP_SIGND_SOCKET_DIR());
+			 get_dyn_NTP_SIGND_SOCKET_DIR());
 
 	lpcfg_string_set(Globals.ctx,
-		&Globals.winbindd_privileged_socket_directory,
-		get_dyn_WINBINDD_PRIVILEGED_SOCKET_DIR());
+			 &Globals.winbindd_privileged_socket_directory,
+			 get_dyn_WINBINDD_PRIVILEGED_SOCKET_DIR());
 
 	s = talloc_asprintf(talloc_tos(), "%s/samba_kcc", get_dyn_SCRIPTSBINDIR());
 	if (s == NULL) {
@@ -919,6 +921,8 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 
 	Globals.web_port = 901;
 
+	Globals.aio_max_threads = 100;
+
 	/* Now put back the settings that were set with lp_set_cmdline() */
 	apply_lp_set_cmdline();
 }
@@ -1017,44 +1021,15 @@ char *lp_ ## fn_name(TALLOC_CTX *ctx,int i) {return(lp_string((ctx), (LP_SNUM_OK
 #define FN_LOCAL_PARM_CHAR(fn_name,val) \
  char lp_ ## fn_name(const struct share_params *p) {return(LP_SNUM_OK(p->service)? ServicePtrs[(p->service)]->val : sDefault.val);}
 
-static FN_GLOBAL_INTEGER(winbind_max_domain_connections_int,
-		  winbindMaxDomainConnections)
-
 int lp_winbind_max_domain_connections(void)
 {
 	if (lp_winbind_offline_logon() &&
-	    lp_winbind_max_domain_connections_int() > 1) {
+	    lp__winbind_max_domain_connections() > 1) {
 		DEBUG(1, ("offline logons active, restricting max domain "
 			  "connections to 1\n"));
 		return 1;
 	}
-	return MAX(1, lp_winbind_max_domain_connections_int());
-}
-
-int lp_smb2_max_credits(void)
-{
-	if (Globals.ismb2_max_credits == 0) {
-		Globals.ismb2_max_credits = DEFAULT_SMB2_MAX_CREDITS;
-	}
-	return Globals.ismb2_max_credits;
-}
-int lp_cups_encrypt(void)
-{
-	int result = 0;
-#ifdef HAVE_HTTPCONNECTENCRYPT
-	switch (Globals.CupsEncrypt) {
-		case Auto:
-			result = HTTP_ENCRYPT_REQUIRED;
-			break;
-		case true:
-			result = HTTP_ENCRYPT_ALWAYS;
-			break;
-		case false:
-			result = HTTP_ENCRYPT_NEVER;
-			break;
-	}
-#endif
-	return result;
+	return MAX(1, lp__winbind_max_domain_connections());
 }
 
 /* These functions remain in source3/param for now */
@@ -1273,6 +1248,22 @@ unsigned long lp_parm_ulong(int snum, const char *type, const char *option, unsi
 /* Return parametric option from a given service. Type is a part of option before ':' */
 /* Parametric option has following syntax: 'Type: option = value' */
 
+unsigned long long lp_parm_ulonglong(int snum, const char *type,
+				     const char *option, unsigned long long def)
+{
+	struct parmlist_entry *data = get_parametrics(snum, type, option);
+
+	if (data && data->value && *data->value) {
+		return lp_ulonglong(data->value);
+	}
+
+	return def;
+}
+
+/* Return parametric option from a given service. Type is a part of option
+ * before ':' */
+/* Parametric option has following syntax: 'Type: option = value' */
+
 bool lp_parm_bool(int snum, const char *type, const char *option, bool def)
 {
 	struct parmlist_entry *data = get_parametrics(snum, type, option);
@@ -1370,7 +1361,7 @@ static void free_service_byindex(int idx)
 	}
 
 	free_service(ServicePtrs[idx]);
-	talloc_free_children(ServicePtrs[idx]);
+	TALLOC_FREE(ServicePtrs[idx]);
 }
 
 /***************************************************************************
@@ -1392,20 +1383,30 @@ static int add_a_service(const struct loadparm_service *pservice, const char *na
 		}
 	}
 
-	/* if not, then create one */
-	i = iNumServices;
-	tsp = talloc_realloc(NULL, ServicePtrs, struct loadparm_service *, num_to_alloc);
-	if (tsp == NULL) {
-		DEBUG(0,("add_a_service: failed to enlarge ServicePtrs!\n"));
-		return (-1);
+	/* Re use empty slots if any before allocating new one.*/
+	for (i=0; i < iNumServices; i++) {
+		if (ServicePtrs[i] == NULL) {
+			break;
+		}
 	}
-	ServicePtrs = tsp;
-	ServicePtrs[iNumServices] = talloc_zero(ServicePtrs, struct loadparm_service);
-	if (!ServicePtrs[iNumServices]) {
+	if (i == iNumServices) {
+		/* if not, then create one */
+		tsp = talloc_realloc(NULL, ServicePtrs,
+				     struct loadparm_service *,
+				     num_to_alloc);
+		if (tsp == NULL) {
+			DEBUG(0, ("add_a_service: failed to enlarge "
+				  "ServicePtrs!\n"));
+			return (-1);
+		}
+		ServicePtrs = tsp;
+		iNumServices++;
+	}
+	ServicePtrs[i] = talloc_zero(ServicePtrs, struct loadparm_service);
+	if (!ServicePtrs[i]) {
 		DEBUG(0,("add_a_service: out of memory!\n"));
 		return (-1);
 	}
-	iNumServices++;
 
 	ServicePtrs[i]->valid = true;
 
@@ -1564,13 +1565,14 @@ static bool lp_add_ipc(const char *ipc_name, bool guest_ok)
 	lpcfg_string_set(ServicePtrs[i], &ServicePtrs[i]->comment, comment);
 	lpcfg_string_set(ServicePtrs[i], &ServicePtrs[i]->fstype, "IPC");
 	ServicePtrs[i]->max_connections = 0;
-	ServicePtrs[i]->bAvailable = true;
+	ServicePtrs[i]->available = true;
 	ServicePtrs[i]->read_only = true;
 	ServicePtrs[i]->guest_only = false;
 	ServicePtrs[i]->administrative_share = true;
 	ServicePtrs[i]->guest_ok = guest_ok;
 	ServicePtrs[i]->printable = false;
 	ServicePtrs[i]->browseable = sDefault.browseable;
+	ServicePtrs[i]->autoloaded = true;
 
 	DEBUG(3, ("adding IPC service\n"));
 
@@ -2436,32 +2438,32 @@ static const char *append_ldap_suffix(TALLOC_CTX *ctx, const char *str )
 
 const char *lp_ldap_machine_suffix(TALLOC_CTX *ctx)
 {
-	if (Globals.szLdapMachineSuffix[0])
-		return append_ldap_suffix(ctx, Globals.szLdapMachineSuffix);
+	if (Globals._ldap_machine_suffix[0])
+		return append_ldap_suffix(ctx, Globals._ldap_machine_suffix);
 
 	return lp_string(ctx, Globals.ldap_suffix);
 }
 
 const char *lp_ldap_user_suffix(TALLOC_CTX *ctx)
 {
-	if (Globals.szLdapUserSuffix[0])
-		return append_ldap_suffix(ctx, Globals.szLdapUserSuffix);
+	if (Globals._ldap_user_suffix[0])
+		return append_ldap_suffix(ctx, Globals._ldap_user_suffix);
 
 	return lp_string(ctx, Globals.ldap_suffix);
 }
 
 const char *lp_ldap_group_suffix(TALLOC_CTX *ctx)
 {
-	if (Globals.szLdapGroupSuffix[0])
-		return append_ldap_suffix(ctx, Globals.szLdapGroupSuffix);
+	if (Globals._ldap_group_suffix[0])
+		return append_ldap_suffix(ctx, Globals._ldap_group_suffix);
 
 	return lp_string(ctx, Globals.ldap_suffix);
 }
 
 const char *lp_ldap_idmap_suffix(TALLOC_CTX *ctx)
 {
-	if (Globals.szLdapIdmapSuffix[0])
-		return append_ldap_suffix(ctx, Globals.szLdapIdmapSuffix);
+	if (Globals._ldap_idmap_suffix[0])
+		return append_ldap_suffix(ctx, Globals._ldap_idmap_suffix);
 
 	return lp_string(ctx, Globals.ldap_suffix);
 }
@@ -2738,7 +2740,7 @@ static void dump_copy_map(bool *pcopymap)
 
 bool lp_snum_ok(int iService)
 {
-	return (LP_SNUM_OK(iService) && ServicePtrs[iService]->bAvailable);
+	return (LP_SNUM_OK(iService) && ServicePtrs[iService]->available);
 }
 
 /***************************************************************************
@@ -3748,7 +3750,7 @@ static bool lp_load_ex(const char *pszFname,
 		apply_lp_set_cmdline();
 	}
 
-	lp_do_parameter(-1, "idmap config * : backend", Globals.szIdmapBackend);
+	lp_do_parameter(-1, "idmap config * : backend", Globals.idmap_backend);
 
 	/* We get sections first, so have to start 'behind' to make up */
 	iServiceIndex = -1;
@@ -4183,10 +4185,12 @@ static bool lp_domain_master_true_or_auto(void)
 
 bool lp_preferred_master(void)
 {
-	if (Globals.iPreferredMaster == Auto)
+	int preferred_master = lp__preferred_master();
+
+	if (preferred_master == Auto)
 		return (lp_local_master() && lp_domain_master());
 
-	return (bool)Globals.iPreferredMaster;
+	return (bool)preferred_master;
 }
 
 /*******************************************************************
@@ -4225,7 +4229,8 @@ void lp_set_logfile(const char *name)
 
 int lp_maxprintjobs(int snum)
 {
-	int maxjobs = LP_SNUM_OK(snum) ? ServicePtrs[snum]->iMaxPrintJobs : sDefault.iMaxPrintJobs;
+	int maxjobs = lp_max_print_jobs(snum);
+
 	if (maxjobs <= 0 || maxjobs >= PRINT_MAX_JOBID)
 		maxjobs = PRINT_MAX_JOBID - 1;
 
@@ -4234,9 +4239,11 @@ int lp_maxprintjobs(int snum)
 
 const char *lp_printcapname(void)
 {
-	if ((Globals.szPrintcapname != NULL) &&
-	    (Globals.szPrintcapname[0] != '\0'))
-		return Globals.szPrintcapname;
+	const char *printcap_name = lp_printcap_name();
+
+	if ((printcap_name != NULL) &&
+	    (printcap_name[0] != '\0'))
+		return printcap_name;
 
 	if (sDefault.printing == PRINT_CUPS) {
 		return "cups";
@@ -4356,10 +4363,12 @@ void lp_set_posix_default_cifsx_readwrite_locktype(enum brl_flavour val)
 
 int lp_min_receive_file_size(void)
 {
-	if (Globals.iminreceivefile < 0) {
+	int min_receivefile_size = lp_min_receivefile_size();
+
+	if (min_receivefile_size < 0) {
 		return 0;
 	}
-	return Globals.iminreceivefile;
+	return min_receivefile_size;
 }
 
 /*******************************************************************
@@ -4368,19 +4377,13 @@ int lp_min_receive_file_size(void)
  even after a configuration file reload.
 ********************************************************************/
 
-static bool lp_widelinks_internal(int snum)
-{
-	return (bool)(LP_SNUM_OK(snum)? ServicePtrs[(snum)]->bWidelinks :
-			sDefault.bWidelinks);
-}
-
 void widelinks_warning(int snum)
 {
 	if (lp_allow_insecure_wide_links()) {
 		return;
 	}
 
-	if (lp_unix_extensions() && lp_widelinks_internal(snum)) {
+	if (lp_unix_extensions() && lp_wide_links(snum)) {
 		DEBUG(0,("Share '%s' has wide links and unix extensions enabled. "
 			"These parameters are incompatible. "
 			"Wide links will be disabled for this share.\n",
@@ -4401,7 +4404,7 @@ bool lp_widelinks(int snum)
 		}
 	}
 
-	return lp_widelinks_internal(snum);
+	return lp_wide_links(snum);
 }
 
 int lp_server_role(void)
diff --git a/source3/passdb/ABI/samba-passdb-0.24.2.sigs b/source3/passdb/ABI/samba-passdb-0.24.2.sigs
new file mode 100644
index 0000000..6ab600e
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.24.2.sigs
@@ -0,0 +1,313 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+my_sam_name: const char *(void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/samba-passdb-0.25.0.sigs b/source3/passdb/ABI/samba-passdb-0.25.0.sigs
new file mode 100644
index 0000000..546374c
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.25.0.sigs
@@ -0,0 +1,312 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 717eaa1..3f097ab 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -565,6 +565,28 @@ char *secrets_fetch_prev_machine_password(const char *domain)
 }
 
 /************************************************************************
+ Routine to fetch the last change time of the machine account password
+  for a realm
+************************************************************************/
+
+time_t secrets_fetch_pass_last_set_time(const char *domain)
+{
+	uint32_t *last_set_time;
+	time_t pass_last_set_time;
+
+	last_set_time = secrets_fetch(machine_last_change_time_keystr(domain),
+				      NULL);
+	if (last_set_time) {
+		pass_last_set_time = IVAL(last_set_time,0);
+		SAFE_FREE(last_set_time);
+	} else {
+		pass_last_set_time = 0;
+	}
+
+	return pass_last_set_time;
+}
+
+/************************************************************************
  Routine to fetch the plaintext machine account password for a realm
  the password is assumed to be a null terminated ascii string.
 ************************************************************************/
@@ -577,15 +599,7 @@ char *secrets_fetch_machine_password(const char *domain,
 	ret = (char *)secrets_fetch(machine_password_keystr(domain), NULL);
 
 	if (pass_last_set_time) {
-		size_t size;
-		uint32_t *last_set_time;
-		last_set_time = (unsigned int *)secrets_fetch(machine_last_change_time_keystr(domain), &size);
-		if (last_set_time) {
-			*pass_last_set_time = IVAL(last_set_time,0);
-			SAFE_FREE(last_set_time);
-		} else {
-			*pass_last_set_time = 0;
-		}
+		*pass_last_set_time = secrets_fetch_pass_last_set_time(domain);
 	}
 
 	if (channel) {
diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c
index f071027..f48c317 100644
--- a/source3/passdb/passdb.c
+++ b/source3/passdb/passdb.c
@@ -36,24 +36,6 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_PASSDB
 
-/******************************************************************
- Get the default domain/netbios name to be used when
- testing authentication.
-
- LEGACY: this function provides the legacy domain mapping used with
-	 the lp_map_untrusted_to_domain() parameter
-******************************************************************/
-
-const char *my_sam_name(void)
-{
-       /* Standalone servers can only use the local netbios name */
-       if ( lp_server_role() == ROLE_STANDALONE )
-               return lp_netbios_name();
-
-       /* Default to the DOMAIN name when not specified */
-       return lp_workgroup();
-}
-
 /**********************************************************************
 ***********************************************************************/
 
@@ -658,7 +640,8 @@ bool lookup_global_sam_name(const char *name, int flags, uint32_t *rid,
 	/* BUILTIN groups are looked up elsewhere */
 	if (!sid_check_is_in_our_sam(&map->sid)) {
 		DEBUG(10, ("Found group %s (%s) not in our domain -- "
-			   "ignoring.", name, sid_string_dbg(&map->sid)));
+			   "ignoring.\n",
+			   name, sid_string_dbg(&map->sid)));
 		TALLOC_FREE(map);
 		return False;
 	}
diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c
index 9f27459..74a71cb 100644
--- a/source3/passdb/pdb_get_set.c
+++ b/source3/passdb/pdb_get_set.c
@@ -999,10 +999,6 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
 {
 	uchar new_lanman_p16[LM_HASH_LEN];
 	uchar new_nt_p16[NT_HASH_LEN];
-	uchar *pwhistory;
-	uint32_t pwHistLen;
-	uint32_t current_history_len;
-	const uint8_t *current_history;
 
 	if (!plaintext)
 		return False;
@@ -1032,6 +1028,21 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
 	if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED))
 		return False;
 
+	
+	return pdb_update_history(sampass, new_nt_p16);
+}
+
+/*********************************************************************
+ Update password history after change 
+ ********************************************************************/
+
+bool pdb_update_history(struct samu *sampass, const uint8_t new_nt[NT_HASH_LEN])
+{
+	uchar *pwhistory;
+	uint32_t pwHistLen;
+	uint32_t current_history_len;
+	const uint8_t *current_history;
+
 	if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) == 0) {
 		/*
 		 * No password history for non-user accounts
@@ -1055,7 +1066,7 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
 	 */
 	current_history = pdb_get_pw_history(sampass, &current_history_len);
 	if ((current_history_len != 0) && (current_history == NULL)) {
-		DEBUG(1, ("pdb_set_plaintext_passwd: pwhistory == NULL!\n"));
+		DEBUG(1, ("pdb_update_history: pwhistory == NULL!\n"));
 		return false;
 	}
 
@@ -1096,11 +1107,12 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
 	 * The old format was to store the md5 hash of
 	 * the salt+newpw.
 	 */
-	memcpy(&pwhistory[PW_HISTORY_SALT_LEN], new_nt_p16, SALTED_MD5_HASH_LEN);
+	memcpy(&pwhistory[PW_HISTORY_SALT_LEN], new_nt, SALTED_MD5_HASH_LEN);
 
 	pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED);
 
 	return True;
+
 }
 
 /* check for any PDB_SET/CHANGED field and fill the appropriate mask bit */
diff --git a/source3/passdb/pdb_ipa.c b/source3/passdb/pdb_ipa.c
index e1e5527..4d9d09c 100644
--- a/source3/passdb/pdb_ipa.c
+++ b/source3/passdb/pdb_ipa.c
@@ -768,7 +768,7 @@ static struct pdb_domain_info *pdb_ipasam_get_domain_info(struct pdb_methods *pd
 	struct pdb_domain_info *info;
 	struct ldapsam_privates *ldap_state =
 			(struct ldapsam_privates *)pdb_methods->private_data;
-	char sid_buf[24];
+	uint8_t sid_buf[24];
 	DATA_BLOB sid_blob;
 	NTSTATUS status;
 
diff --git a/source3/passdb/py_passdb.c b/source3/passdb/py_passdb.c
index ca43f70..c49354c 100644
--- a/source3/passdb/py_passdb.c
+++ b/source3/passdb/py_passdb.c
@@ -27,13 +27,6 @@
 #include "secrets.h"
 #include "idmap.h"
 
-/* There's no Py_ssize_t in 2.4, apparently */
-#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
-typedef int Py_ssize_t;
-typedef inquiry lenfunc;
-typedef intargfunc ssizeargfunc;
-#endif
-
 #ifndef Py_TYPE /* Py_TYPE is only available on Python > 2.6 */
 #define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)
 #endif
@@ -1115,7 +1108,6 @@ static PyObject *py_samu_new(PyTypeObject *type, PyObject *args, PyObject *kwarg
 
 static PyTypeObject PySamu = {
 	.tp_name = "passdb.Samu",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_getset = py_samu_getsetters,
 	.tp_methods = NULL,
 	.tp_new = py_samu_new,
@@ -1318,7 +1310,6 @@ static PyObject *py_groupmap_new(PyTypeObject *type, PyObject *args, PyObject *k
 
 static PyTypeObject PyGroupmap = {
 	.tp_name = "passdb.Groupmap",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_getset = py_groupmap_getsetters,
 	.tp_methods = NULL,
 	.tp_new = py_groupmap_new,
@@ -1327,7 +1318,7 @@ static PyTypeObject PyGroupmap = {
 };
 
 
-static PyObject *py_pdb_domain_info(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_domain_info(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -1375,7 +1366,7 @@ static PyObject *py_pdb_domain_info(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_getsampwnam(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_getsampwnam(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1414,7 +1405,7 @@ static PyObject *py_pdb_getsampwnam(pytalloc_Object *self, PyObject *args)
 	return py_sam_acct;
 }
 
-static PyObject *py_pdb_getsampwsid(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_getsampwsid(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1452,7 +1443,7 @@ static PyObject *py_pdb_getsampwsid(pytalloc_Object *self, PyObject *args)
 	return py_sam_acct;
 }
 
-static PyObject *py_pdb_create_user(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_create_user(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1482,7 +1473,7 @@ static PyObject *py_pdb_create_user(pytalloc_Object *self, PyObject *args)
 	return PyInt_FromLong(rid);
 }
 
-static PyObject *py_pdb_delete_user(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_delete_user(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1508,11 +1499,11 @@ static PyObject *py_pdb_delete_user(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
-static PyObject *py_pdb_add_sam_account(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_add_sam_account(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1539,11 +1530,11 @@ static PyObject *py_pdb_add_sam_account(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
-static PyObject *py_pdb_update_sam_account(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_update_sam_account(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1569,11 +1560,11 @@ static PyObject *py_pdb_update_sam_account(pytalloc_Object *self, PyObject *args
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
-static PyObject *py_pdb_delete_sam_account(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_delete_sam_account(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1599,11 +1590,11 @@ static PyObject *py_pdb_delete_sam_account(pytalloc_Object *self, PyObject *args
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
-static PyObject *py_pdb_rename_sam_account(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_rename_sam_account(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1631,12 +1622,12 @@ static PyObject *py_pdb_rename_sam_account(pytalloc_Object *self, PyObject *args
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_getgrsid(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_getgrsid(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1677,7 +1668,7 @@ static PyObject *py_pdb_getgrsid(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_getgrgid(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_getgrgid(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1716,7 +1707,7 @@ static PyObject *py_pdb_getgrgid(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_getgrnam(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_getgrnam(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1755,7 +1746,7 @@ static PyObject *py_pdb_getgrnam(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_create_dom_group(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_create_dom_group(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1785,7 +1776,7 @@ static PyObject *py_pdb_create_dom_group(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_delete_dom_group(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_delete_dom_group(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1809,12 +1800,12 @@ static PyObject *py_pdb_delete_dom_group(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_add_group_mapping_entry(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_add_group_mapping_entry(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1840,12 +1831,12 @@ static PyObject *py_pdb_add_group_mapping_entry(pytalloc_Object *self, PyObject
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_update_group_mapping_entry(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_update_group_mapping_entry(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1871,12 +1862,12 @@ static PyObject *py_pdb_update_group_mapping_entry(pytalloc_Object *self, PyObje
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_delete_group_mapping_entry(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_delete_group_mapping_entry(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1902,12 +1893,12 @@ static PyObject *py_pdb_delete_group_mapping_entry(pytalloc_Object *self, PyObje
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_enum_group_mapping(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_enum_group_mapping(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1976,7 +1967,7 @@ static PyObject *py_pdb_enum_group_mapping(pytalloc_Object *self, PyObject *args
 }
 
 
-static PyObject *py_pdb_enum_group_members(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_enum_group_members(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2027,7 +2018,7 @@ static PyObject *py_pdb_enum_group_members(pytalloc_Object *self, PyObject *args
 }
 
 
-static PyObject *py_pdb_enum_group_memberships(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_enum_group_memberships(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2076,7 +2067,7 @@ static PyObject *py_pdb_enum_group_memberships(pytalloc_Object *self, PyObject *
 }
 
 
-static PyObject *py_pdb_add_groupmem(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_add_groupmem(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2099,12 +2090,12 @@ static PyObject *py_pdb_add_groupmem(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_del_groupmem(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_del_groupmem(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2127,12 +2118,12 @@ static PyObject *py_pdb_del_groupmem(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_create_alias(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_create_alias(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2162,7 +2153,7 @@ static PyObject *py_pdb_create_alias(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_delete_alias(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_delete_alias(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2188,12 +2179,12 @@ static PyObject *py_pdb_delete_alias(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_get_aliasinfo(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_get_aliasinfo(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2247,7 +2238,7 @@ static PyObject *py_pdb_get_aliasinfo(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_set_aliasinfo(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_set_aliasinfo(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2288,12 +2279,12 @@ static PyObject *py_pdb_set_aliasinfo(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_add_aliasmem(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_add_aliasmem(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2321,12 +2312,12 @@ static PyObject *py_pdb_add_aliasmem(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_del_aliasmem(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_del_aliasmem(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2354,12 +2345,12 @@ static PyObject *py_pdb_del_aliasmem(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_enum_aliasmem(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_enum_aliasmem(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2412,7 +2403,7 @@ static PyObject *py_pdb_enum_aliasmem(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_get_account_policy(pytalloc_Object *self)
+static PyObject *py_pdb_get_account_policy(PyObject *self, PyObject *unused)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2446,7 +2437,7 @@ static PyObject *py_pdb_get_account_policy(pytalloc_Object *self)
 }
 
 
-static PyObject *py_pdb_set_account_policy(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_set_account_policy(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2477,11 +2468,11 @@ static PyObject *py_pdb_set_account_policy(pytalloc_Object *self, PyObject *args
 		}
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
-static PyObject *py_pdb_search_users(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_search_users(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2545,7 +2536,7 @@ static PyObject *py_pdb_search_users(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_search_groups(pytalloc_Object *self)
+static PyObject *py_pdb_search_groups(PyObject *self, PyObject *unused)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2603,7 +2594,7 @@ static PyObject *py_pdb_search_groups(pytalloc_Object *self)
 }
 
 
-static PyObject *py_pdb_search_aliases(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_search_aliases(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2675,7 +2666,7 @@ static PyObject *py_pdb_search_aliases(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_uid_to_sid(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_uid_to_sid(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2714,7 +2705,7 @@ static PyObject *py_pdb_uid_to_sid(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_gid_to_sid(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_gid_to_sid(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2753,7 +2744,7 @@ static PyObject *py_pdb_gid_to_sid(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_sid_to_id(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_sid_to_id(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2781,7 +2772,7 @@ static PyObject *py_pdb_sid_to_id(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_new_rid(pytalloc_Object *self)
+static PyObject *py_pdb_new_rid(PyObject *self, PyObject *unused)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2800,7 +2791,7 @@ static PyObject *py_pdb_new_rid(pytalloc_Object *self)
 }
 
 
-static PyObject *py_pdb_get_trusteddom_pw(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_get_trusteddom_pw(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2854,7 +2845,7 @@ static PyObject *py_pdb_get_trusteddom_pw(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_set_trusteddom_pw(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_set_trusteddom_pw(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2879,12 +2870,12 @@ static PyObject *py_pdb_set_trusteddom_pw(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_del_trusteddom_pw(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_del_trusteddom_pw(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct pdb_methods *methods;
@@ -2903,12 +2894,12 @@ static PyObject *py_pdb_del_trusteddom_pw(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_enum_trusteddoms(pytalloc_Object *self)
+static PyObject *py_pdb_enum_trusteddoms(PyObject *self, PyObject *unused)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -2953,7 +2944,7 @@ static PyObject *py_pdb_enum_trusteddoms(pytalloc_Object *self)
 }
 
 
-static PyObject *py_pdb_get_trusted_domain(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_get_trusted_domain(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -3012,7 +3003,7 @@ static PyObject *py_pdb_get_trusted_domain(pytalloc_Object *self, PyObject *args
 }
 
 
-static PyObject *py_pdb_get_trusted_domain_by_sid(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_get_trusted_domain_by_sid(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -3074,7 +3065,7 @@ static PyObject *py_pdb_get_trusted_domain_by_sid(pytalloc_Object *self, PyObjec
 }
 
 
-static PyObject *py_pdb_set_trusted_domain(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_set_trusted_domain(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -3131,12 +3122,12 @@ static PyObject *py_pdb_set_trusted_domain(pytalloc_Object *self, PyObject *args
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_del_trusted_domain(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_del_trusted_domain(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -3159,12 +3150,12 @@ static PyObject *py_pdb_del_trusted_domain(pytalloc_Object *self, PyObject *args
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_enum_trusted_domains(pytalloc_Object *self)
+static PyObject *py_pdb_enum_trusted_domains(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -3233,7 +3224,7 @@ static PyObject *py_pdb_enum_trusted_domains(pytalloc_Object *self)
 }
 
 
-static PyObject *py_pdb_get_secret(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_get_secret(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -3298,7 +3289,7 @@ static PyObject *py_pdb_get_secret(pytalloc_Object *self, PyObject *args)
 }
 
 
-static PyObject *py_pdb_set_secret(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_set_secret(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -3341,12 +3332,12 @@ static PyObject *py_pdb_set_secret(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
-static PyObject *py_pdb_delete_secret(pytalloc_Object *self, PyObject *args)
+static PyObject *py_pdb_delete_secret(PyObject *self, PyObject *args)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -3370,169 +3361,169 @@ static PyObject *py_pdb_delete_secret(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 static PyMethodDef py_pdb_methods[] = {
-	{ "domain_info", (PyCFunction)py_pdb_domain_info, METH_NOARGS,
+	{ "domain_info", py_pdb_domain_info, METH_NOARGS,
 		"domain_info() -> str\n\n \
 		Get domain information for the database." },
-	{ "getsampwnam", (PyCFunction)py_pdb_getsampwnam, METH_VARARGS,
+	{ "getsampwnam", py_pdb_getsampwnam, METH_VARARGS,
 		"getsampwnam(username) -> samu object\n\n \
 		Get user information by name." },
-	{ "getsampwsid", (PyCFunction)py_pdb_getsampwsid, METH_VARARGS,
+	{ "getsampwsid", py_pdb_getsampwsid, METH_VARARGS,
 		"getsampwsid(user_sid) -> samu object\n\n \
 		Get user information by sid (dcerpc.security.dom_sid object)." },
-	{ "create_user", (PyCFunction)py_pdb_create_user, METH_VARARGS,
+	{ "create_user", py_pdb_create_user, METH_VARARGS,
 		"create_user(username, acct_flags) -> rid\n\n \
 		Create user. acct_flags are samr account control flags." },
-	{ "delete_user", (PyCFunction)py_pdb_delete_user, METH_VARARGS,
+	{ "delete_user", py_pdb_delete_user, METH_VARARGS,
 		"delete_user(samu object) -> None\n\n \
 		Delete user." },
-	{ "add_sam_account", (PyCFunction)py_pdb_add_sam_account, METH_VARARGS,
+	{ "add_sam_account", py_pdb_add_sam_account, METH_VARARGS,
 		"add_sam_account(samu object) -> None\n\n \
 		Add SAM account." },
-	{ "update_sam_account", (PyCFunction)py_pdb_update_sam_account, METH_VARARGS,
+	{ "update_sam_account", py_pdb_update_sam_account, METH_VARARGS,
 		"update_sam_account(samu object) -> None\n\n \
 		Update SAM account." },
-	{ "delete_sam_account", (PyCFunction)py_pdb_delete_sam_account, METH_VARARGS,
+	{ "delete_sam_account", py_pdb_delete_sam_account, METH_VARARGS,
 		"delete_sam_account(samu object) -> None\n\n \
 		Delete SAM account." },
-	{ "rename_sam_account", (PyCFunction)py_pdb_rename_sam_account, METH_VARARGS,
+	{ "rename_sam_account", py_pdb_rename_sam_account, METH_VARARGS,
 		"rename_sam_account(samu object1, new_username) -> None\n\n \
 		Rename SAM account." },
 	/* update_login_attempts */
-	{ "getgrsid", (PyCFunction)py_pdb_getgrsid, METH_VARARGS,
+	{ "getgrsid", py_pdb_getgrsid, METH_VARARGS,
 		"getgrsid(group_sid) -> groupmap object\n\n \
 		Get group information by sid (dcerpc.security.dom_sid object)." },
-	{ "getgrgid", (PyCFunction)py_pdb_getgrgid, METH_VARARGS,
+	{ "getgrgid", py_pdb_getgrgid, METH_VARARGS,
 		"getgrsid(gid) -> groupmap object\n\n \
 		Get group information by gid." },
-	{ "getgrnam", (PyCFunction)py_pdb_getgrnam, METH_VARARGS,
+	{ "getgrnam", py_pdb_getgrnam, METH_VARARGS,
 		"getgrsid(groupname) -> groupmap object\n\n \
 		Get group information by name." },
-	{ "create_dom_group", (PyCFunction)py_pdb_create_dom_group, METH_VARARGS,
+	{ "create_dom_group", py_pdb_create_dom_group, METH_VARARGS,
 		"create_dom_group(groupname) -> group_rid\n\n \
 		Create new domain group by name." },
-	{ "delete_dom_group", (PyCFunction)py_pdb_delete_dom_group, METH_VARARGS,
+	{ "delete_dom_group", py_pdb_delete_dom_group, METH_VARARGS,
 		"delete_dom_group(group_rid) -> None\n\n \
 		Delete domain group identified by rid" },
-	{ "add_group_mapping_entry", (PyCFunction)py_pdb_add_group_mapping_entry, METH_VARARGS,
+	{ "add_group_mapping_entry", py_pdb_add_group_mapping_entry, METH_VARARGS,
 		"add_group_mapping_entry(groupmap) -> None\n \
 		Add group mapping entry for groupmap object." },
-	{ "update_group_mapping_entry", (PyCFunction)py_pdb_update_group_mapping_entry, METH_VARARGS,
+	{ "update_group_mapping_entry", py_pdb_update_group_mapping_entry, METH_VARARGS,
 		"update_group_mapping_entry(groupmap) -> None\n\n \
 		Update group mapping entry for groupmap object." },
-	{ "delete_group_mapping_entry", (PyCFunction)py_pdb_delete_group_mapping_entry, METH_VARARGS,
+	{ "delete_group_mapping_entry", py_pdb_delete_group_mapping_entry, METH_VARARGS,
 		"delete_group_mapping_entry(groupmap) -> None\n\n \
 		Delete group mapping entry for groupmap object." },
-	{ "enum_group_mapping", (PyCFunction)py_pdb_enum_group_mapping, METH_VARARGS,
+	{ "enum_group_mapping", py_pdb_enum_group_mapping, METH_VARARGS,
 		"enum_group_mapping([domain_sid, [type, [unix_only]]]) -> List\n\n \
 		Return list of group mappings as groupmap objects. Optional arguments are domain_sid object, type of group, unix only flag." },
-	{ "enum_group_members", (PyCFunction)py_pdb_enum_group_members, METH_VARARGS,
+	{ "enum_group_members", py_pdb_enum_group_members, METH_VARARGS,
 		"enum_group_members(group_sid) -> List\n\n \
 		Return list of users (dom_sid object) in group." },
-	{ "enum_group_memberships", (PyCFunction)py_pdb_enum_group_memberships, METH_VARARGS,
+	{ "enum_group_memberships", py_pdb_enum_group_memberships, METH_VARARGS,
 		"enum_group_memberships(samu object) -> List\n\n \
 		Return list of groups (dom_sid object) this user is part of." },
 	/* set_unix_primary_group */
-	{ "add_groupmem", (PyCFunction)py_pdb_add_groupmem, METH_VARARGS,
+	{ "add_groupmem", py_pdb_add_groupmem, METH_VARARGS,
 		"add_groupmem(group_rid, member_rid) -> None\n\n \
 		Add user to group." },
-	{ "del_groupmem", (PyCFunction)py_pdb_del_groupmem, METH_VARARGS,
+	{ "del_groupmem", py_pdb_del_groupmem, METH_VARARGS,
 		"del_groupmem(group_rid, member_rid) -> None\n\n \
 		Remove user from from group." },
-	{ "create_alias", (PyCFunction)py_pdb_create_alias, METH_VARARGS,
+	{ "create_alias", py_pdb_create_alias, METH_VARARGS,
 		"create_alias(alias_name) -> alias_rid\n\n \
 		Create alias entry." },
-	{ "delete_alias", (PyCFunction)py_pdb_delete_alias, METH_VARARGS,
+	{ "delete_alias", py_pdb_delete_alias, METH_VARARGS,
 		"delete_alias(alias_sid) -> None\n\n \
 		Delete alias entry." },
-	{ "get_aliasinfo", (PyCFunction)py_pdb_get_aliasinfo, METH_VARARGS,
+	{ "get_aliasinfo", py_pdb_get_aliasinfo, METH_VARARGS,
 		"get_aliasinfo(alias_sid) -> Mapping\n\n \
 		Get alias information as a dictionary with keys - acct_name, acct_desc, rid." },
-	{ "set_aliasinfo", (PyCFunction)py_pdb_set_aliasinfo, METH_VARARGS,
+	{ "set_aliasinfo", py_pdb_set_aliasinfo, METH_VARARGS,
 		"set_alias_info(alias_sid, Mapping) -> None\n\n \
 		Set alias information from a dictionary with keys - acct_name, acct_desc." },
-	{ "add_aliasmem", (PyCFunction)py_pdb_add_aliasmem, METH_VARARGS,
+	{ "add_aliasmem", py_pdb_add_aliasmem, METH_VARARGS,
 		"add_aliasmem(alias_sid, member_sid) -> None\n\n \
 		Add user to alias entry." },
-	{ "del_aliasmem", (PyCFunction)py_pdb_del_aliasmem, METH_VARARGS,
+	{ "del_aliasmem", py_pdb_del_aliasmem, METH_VARARGS,
 		"del_aliasmem(alias_sid, member_sid) -> None\n\n \
 		Remove a user from alias entry." },
-	{ "enum_aliasmem", (PyCFunction)py_pdb_enum_aliasmem, METH_VARARGS,
+	{ "enum_aliasmem", py_pdb_enum_aliasmem, METH_VARARGS,
 		"enum_aliasmem(alias_sid) -> List\n\n \
 		Return a list of members (dom_sid object) for alias entry." },
 	/* enum_alias_memberships */
 	/* lookup_rids */
 	/* lookup_names */
-	{ "get_account_policy", (PyCFunction)py_pdb_get_account_policy, METH_NOARGS,
+	{ "get_account_policy", py_pdb_get_account_policy, METH_NOARGS,
 		"get_account_policy() -> Mapping\n\n \
 		Get account policy information as a dictionary." },
-	{ "set_account_policy", (PyCFunction)py_pdb_set_account_policy, METH_VARARGS,
+	{ "set_account_policy", py_pdb_set_account_policy, METH_VARARGS,
 		"get_account_policy(Mapping) -> None\n\n \
 		Set account policy settings from a dicionary." },
 	/* get_seq_num */
-	{ "search_users", (PyCFunction)py_pdb_search_users, METH_VARARGS,
+	{ "search_users", py_pdb_search_users, METH_VARARGS,
 		"search_users(acct_flags) -> List\n\n \
 		Search users. acct_flags are samr account control flags.\n \
 		Each list entry is dictionary with keys - idx, rid, acct_flags, account_name, fullname, description." },
-	{ "search_groups", (PyCFunction)py_pdb_search_groups, METH_NOARGS,
+	{ "search_groups", py_pdb_search_groups, METH_NOARGS,
 		"search_groups() -> List\n\n \
 		Search unix only groups. \n \
 		Each list entry is dictionary with keys - idx, rid, acct_flags, account_name, fullname, description." },
-	{ "search_aliases", (PyCFunction)py_pdb_search_aliases, METH_VARARGS,
+	{ "search_aliases", py_pdb_search_aliases, METH_VARARGS,
 		"search_aliases([domain_sid]) -> List\n\n \
 		Search aliases. domain_sid is dcerpc.security.dom_sid object.\n \
 		Each list entry is dictionary with keys - idx, rid, acct_flags, account_name, fullname, description." },
-	{ "uid_to_sid", (PyCFunction)py_pdb_uid_to_sid, METH_VARARGS,
+	{ "uid_to_sid", py_pdb_uid_to_sid, METH_VARARGS,
 		"uid_to_sid(uid) -> sid\n\n \
 		Return sid for given user id." },
-	{ "gid_to_sid", (PyCFunction)py_pdb_gid_to_sid, METH_VARARGS,
+	{ "gid_to_sid", py_pdb_gid_to_sid, METH_VARARGS,
 		"gid_to_sid(gid) -> sid\n\n \
 		Return sid for given group id." },
-	{ "sid_to_id", (PyCFunction)py_pdb_sid_to_id, METH_VARARGS,
+	{ "sid_to_id", py_pdb_sid_to_id, METH_VARARGS,
 		"sid_to_id(sid) -> Tuple\n\n \
 		Return id and type for given sid." },
 	/* capabilities */
-	{ "new_rid", (PyCFunction)py_pdb_new_rid, METH_NOARGS,
+	{ "new_rid", py_pdb_new_rid, METH_NOARGS,
 		"new_rid() -> rid\n\n \
 		Get a new rid." },
-	{ "get_trusteddom_pw", (PyCFunction)py_pdb_get_trusteddom_pw, METH_VARARGS,
+	{ "get_trusteddom_pw", py_pdb_get_trusteddom_pw, METH_VARARGS,
 		"get_trusteddom_pw(domain) -> Mapping\n\n \
 		Get trusted domain password, sid and last set time in a dictionary." },
-	{ "set_trusteddom_pw", (PyCFunction)py_pdb_set_trusteddom_pw, METH_VARARGS,
+	{ "set_trusteddom_pw", py_pdb_set_trusteddom_pw, METH_VARARGS,
 		"set_trusteddom_pw(domain, pwd, sid) -> None\n\n \
 		Set trusted domain password." },
-	{ "del_trusteddom_pw", (PyCFunction)py_pdb_del_trusteddom_pw, METH_VARARGS,
+	{ "del_trusteddom_pw", py_pdb_del_trusteddom_pw, METH_VARARGS,
 		"del_trusteddom_pw(domain) -> None\n\n \
 		Delete trusted domain password." },
-	{ "enum_trusteddoms", (PyCFunction)py_pdb_enum_trusteddoms, METH_NOARGS,
+	{ "enum_trusteddoms", py_pdb_enum_trusteddoms, METH_NOARGS,
 		"enum_trusteddoms() -> List\n\n \
 		Get list of trusted domains. Each item is a dictionary with name and sid keys" },
-	{ "get_trusted_domain", (PyCFunction)py_pdb_get_trusted_domain, METH_VARARGS,
+	{ "get_trusted_domain", py_pdb_get_trusted_domain, METH_VARARGS,
 		"get_trusted_domain(domain) -> Mapping\n\n \
 		Get trusted domain information by name. Information is a dictionary with keys - domain_name, netbios_name, security_identifier, trust_auth_incoming, trust_auth_outgoing, trust_direction, trust_type, trust_attributes, trust_forest_trust_info." },
-	{ "get_trusted_domain_by_sid", (PyCFunction)py_pdb_get_trusted_domain_by_sid, METH_VARARGS,
+	{ "get_trusted_domain_by_sid", py_pdb_get_trusted_domain_by_sid, METH_VARARGS,
 		"get_trusted_domain_by_sid(domain_sid) -> Mapping\n\n \
 		Get trusted domain information by sid. Information is a dictionary with keys - domain_name, netbios_name, security_identifier, trust_auth_incoming, trust_auth_outgoing, trust_direction, trust_type, trust_attributes, trust_forest_trust_info" },
-	{ "set_trusted_domain", (PyCFunction)py_pdb_set_trusted_domain, METH_VARARGS,
+	{ "set_trusted_domain", py_pdb_set_trusted_domain, METH_VARARGS,
 		"set_trusted_domain(domain, Mapping) -> None\n\n \
 		Set trusted domain information for domain. Mapping is a dictionary with keys - domain_name, netbios_name, security_identifier, trust_auth_incoming, trust_auth_outgoing, trust_direction, trust_type, trust_attributes, trust_forest_trust_info." },
-	{ "del_trusted_domain", (PyCFunction)py_pdb_del_trusted_domain, METH_VARARGS,
+	{ "del_trusted_domain", py_pdb_del_trusted_domain, METH_VARARGS,
 		"del_trusted_domain(domain) -> None\n\n \
 		Delete trusted domain." },
-	{ "enum_trusted_domains", (PyCFunction)py_pdb_enum_trusted_domains, METH_VARARGS,
+	{ "enum_trusted_domains", py_pdb_enum_trusted_domains, METH_VARARGS,
 		"enum_trusted_domains() -> List\n\n \
 		Get list of trusted domains. Each entry is a dictionary with keys - domain_name, netbios_name, security_identifier, trust_auth_incoming, trust_auth_outgoing, trust_direction, trust_type, trust_attributes, trust_forest_trust_info." },
-	{ "get_secret", (PyCFunction)py_pdb_get_secret, METH_VARARGS,
+	{ "get_secret", py_pdb_get_secret, METH_VARARGS,
 		"get_secret(secret_name) -> Mapping\n\n \
 		Get secret information for secret_name. Information is a dictionary with keys - secret_current, secret_current_lastchange, secret_old, secret_old_lastchange, sd." },
-	{ "set_secret", (PyCFunction)py_pdb_set_secret, METH_VARARGS,
+	{ "set_secret", py_pdb_set_secret, METH_VARARGS,
 		"set_secret(secret_name, Mapping) -> None\n\n \
 		Set secret information for secret_name using dictionary with keys - secret_current, sd." },
-	{ "delete_secret", (PyCFunction)py_pdb_delete_secret, METH_VARARGS,
+	{ "delete_secret", py_pdb_delete_secret, METH_VARARGS,
 		"delete_secret(secret_name) -> None\n\n \
 		Delete secret information for secret_name." },
 	{ NULL },
@@ -3576,7 +3567,6 @@ static PyObject *py_pdb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs
 
 static PyTypeObject PyPDB = {
 	.tp_name = "passdb.PDB",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_new = py_pdb_new,
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 	.tp_methods = py_pdb_methods,
@@ -3587,7 +3577,7 @@ static PyTypeObject PyPDB = {
 /*
  * Return a list of passdb backends
  */
-static PyObject *py_passdb_backends(PyObject *self)
+static PyObject *py_passdb_backends(PyObject *self, PyObject *unused)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	PyObject *py_blist;
@@ -3631,8 +3621,8 @@ static PyObject *py_set_smb_config(PyObject *self, PyObject *args)
 		return NULL;
 	}
 
-	Py_RETURN_NONE;
 	talloc_free(frame);
+	Py_RETURN_NONE;
 }
 
 
@@ -3673,7 +3663,7 @@ static PyObject *py_reload_static_pdb(PyObject *self, PyObject *args)
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_get_global_sam_sid(PyObject *self)
+static PyObject *py_get_global_sam_sid(PyObject *self, PyObject *unused)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct dom_sid *domain_sid, *domain_sid_copy;
@@ -3696,19 +3686,19 @@ static PyObject *py_get_global_sam_sid(PyObject *self)
 
 
 static PyMethodDef py_passdb_methods[] = {
-	{ "get_backends", (PyCFunction)py_passdb_backends, METH_NOARGS,
+	{ "get_backends", py_passdb_backends, METH_NOARGS,
 		"get_backends() -> list\n\n \
 		Get a list of password database backends supported." },
-	{ "set_smb_config", (PyCFunction)py_set_smb_config, METH_VARARGS,
+	{ "set_smb_config", py_set_smb_config, METH_VARARGS,
 		"set_smb_config(path) -> None\n\n \
 		Set path to smb.conf file to load configuration parameters." },
-	{ "set_secrets_dir", (PyCFunction)py_set_secrets_dir, METH_VARARGS,
+	{ "set_secrets_dir", py_set_secrets_dir, METH_VARARGS,
 		"set_secrets_dir(private_dir) -> None\n\n \
 		Set path to private directory to load secrets database from non-default location." },
-	{ "get_global_sam_sid", (PyCFunction)py_get_global_sam_sid, METH_NOARGS,
+	{ "get_global_sam_sid", py_get_global_sam_sid, METH_NOARGS,
 		"get_global_sam_sid() -> dom_sid\n\n \
 		Return domain SID." },
-	{ "reload_static_pdb", (PyCFunction)py_reload_static_pdb, METH_NOARGS,
+	{ "reload_static_pdb", py_reload_static_pdb, METH_NOARGS,
 		"reload_static_pdb() -> None\n\n \
 		Re-initalise the static pdb used internally.  Needed if 'passdb backend' is changed." },
 	{ NULL },
@@ -3720,26 +3710,17 @@ void initpassdb(void)
 	PyObject *m, *mod;
 	char exception_name[] = "passdb.error";
 
-	PyTypeObject *talloc_type = pytalloc_GetObjectType();
-	if (talloc_type == NULL) {
-		talloc_free(frame);
-		return;
-	}
-
-	PyPDB.tp_base = talloc_type;
-	if (PyType_Ready(&PyPDB) < 0) {
+	if (pytalloc_BaseObject_PyType_Ready(&PyPDB) < 0) {
 		talloc_free(frame);
 		return;
 	}
 
-	PySamu.tp_base = talloc_type;
-	if (PyType_Ready(&PySamu) < 0) {
+	if (pytalloc_BaseObject_PyType_Ready(&PySamu) < 0) {
 		talloc_free(frame);
 		return;
 	}
 
-	PyGroupmap.tp_base = talloc_type;
-	if (PyType_Ready(&PyGroupmap) < 0) {
+	if (pytalloc_BaseObject_PyType_Ready(&PyGroupmap) < 0) {
 		talloc_free(frame);
 		return;
 	}
diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c
index 7071fd9..4372c63 100644
--- a/source3/passdb/secrets.c
+++ b/source3/passdb/secrets.c
@@ -37,28 +37,10 @@
 
 static struct db_context *db_ctx;
 
-/**
- * Use a TDB to store an incrementing random seed.
- *
- * Initialised to the current pid, the very first time Samba starts,
- * and incremented by one each time it is needed.
- *
- * @note Not called by systems with a working /dev/urandom.
- */
-static void get_rand_seed(void *userdata, int *new_seed)
-{
-	*new_seed = getpid();
-	if (db_ctx) {
-		dbwrap_trans_change_int32_atomic_bystring(
-			db_ctx, "INFO/random_seed", new_seed, 1);
-	}
-}
-
 /* open up the secrets database with specified private_dir path */
 bool secrets_init_path(const char *private_dir)
 {
 	char *fname = NULL;
-	unsigned char dummy;
 	TALLOC_CTX *frame;
 
 	if (db_ctx != NULL) {
@@ -86,17 +68,6 @@ bool secrets_init_path(const char *private_dir)
 		return False;
 	}
 
-	/**
-	 * Set a reseed function for the crypto random generator
-	 *
-	 * This avoids a problem where systems without /dev/urandom
-	 * could send the same challenge to multiple clients
-	 */
-	set_rand_reseed_callback(get_rand_seed, NULL);
-
-	/* Ensure that the reseed is done now, while we are root, etc */
-	generate_random_buffer(&dummy, sizeof(dummy));
-
 	TALLOC_FREE(frame);
 	return True;
 }
diff --git a/source3/passdb/wscript_build b/source3/passdb/wscript_build
index 9bbd5ca..105777a 100644
--- a/source3/passdb/wscript_build
+++ b/source3/passdb/wscript_build
@@ -43,6 +43,6 @@ bld.SAMBA3_MODULE('pdb_samba_dsdb',
 bld.SAMBA3_PYTHON('pypassdb',
                   source='py_passdb.c',
                   deps='pdb',
-                  public_deps='samba-util tdb talloc pyrpc_util',
+                  public_deps='samba-util tdb talloc pyrpc_util pytalloc-util',
                   realname='samba/samba3/passdb.so'
                   )
diff --git a/source3/printing/notify.c b/source3/printing/notify.c
index 930e72b..d2c5f72 100644
--- a/source3/printing/notify.c
+++ b/source3/printing/notify.c
@@ -331,7 +331,7 @@ to notify_queue_head\n", msg->type, msg->field, msg->printer));
 	 * the messages are sent in the order they were received. JRA.
 	 */
 
-	DLIST_ADD_END(notify_queue_head, pnqueue, struct notify_queue *);
+	DLIST_ADD_END(notify_queue_head, pnqueue);
 	num_messages++;
 
 	if ((notify_event == NULL) && (ev != NULL)) {
diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c
index 3ebb2e6..756d67a 100644
--- a/source3/printing/print_cups.c
+++ b/source3/printing/print_cups.c
@@ -26,7 +26,7 @@
 #include "printing.h"
 #include "printing/pcap.h"
 #include "librpc/gen_ndr/ndr_printcap.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 
 #ifdef HAVE_CUPS
 #include <cups/cups.h>
@@ -475,7 +475,7 @@ static bool cups_pcap_load_async(struct tevent_context *ev,
 
 	close_all_print_db();
 
-	status = reinit_after_fork(msg_ctx, ev, true);
+	status = reinit_after_fork(msg_ctx, ev, true, NULL);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n"));
 		smb_panic("cups_pcap_load_async: reinit_after_fork() failed");
diff --git a/source3/printing/printing.c b/source3/printing/printing.c
index 4a2ffd1..e7e6c6d 100644
--- a/source3/printing/printing.c
+++ b/source3/printing/printing.c
@@ -36,7 +36,7 @@
 #include "messages.h"
 #include "util_tdb.h"
 #include "lib/param/loadparm.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 
 extern struct current_user current_user;
 extern userdom_struct current_user_info;
diff --git a/source3/printing/queue_process.c b/source3/printing/queue_process.c
index 50622dc..6e31ee4 100644
--- a/source3/printing/queue_process.c
+++ b/source3/printing/queue_process.c
@@ -373,15 +373,13 @@ pid_t start_background_queue(struct tevent_context *ev,
 		close(pause_pipe[0]);
 		pause_pipe[0] = -1;
 
-		status = smbd_reinit_after_fork(msg_ctx, ev, true);
+		status = smbd_reinit_after_fork(msg_ctx, ev, true, "lpqd");
 
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(0,("reinit_after_fork() failed\n"));
 			smb_panic("reinit_after_fork() failed");
 		}
 
-		prctl_set_comment("lpqd");
-
 		bq_reopen_logs(logfile);
 		bq_setup_sig_term_handler();
 		bq_setup_sig_hup_handler(ev, msg_ctx);
diff --git a/source3/printing/spoolssd.c b/source3/printing/spoolssd.c
index 9f533b3..51d10b6 100644
--- a/source3/printing/spoolssd.c
+++ b/source3/printing/spoolssd.c
@@ -20,8 +20,6 @@
 #include "serverid.h"
 #include "smbd/smbd.h"
 
-#include "lib/util/util_process.h"
-
 #include "messages.h"
 #include "include/printing.h"
 #include "printing/nt_printing_migrate_internal.h"
@@ -268,15 +266,12 @@ static bool spoolss_child_init(struct tevent_context *ev_ctx,
 	struct messaging_context *msg_ctx = server_messaging_context();
 	bool ok;
 
-	status = reinit_after_fork(msg_ctx, ev_ctx,
-				   true);
+	status = reinit_after_fork(msg_ctx, ev_ctx, true, "spoolssd-child");
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
 		smb_panic("reinit_after_fork() failed");
 	}
 
-	prctl_set_comment("spoolssd-child");
-
 	spoolss_child_id = child_id;
 	spoolss_reopen_logs(child_id);
 
@@ -645,14 +640,13 @@ pid_t start_spoolssd(struct tevent_context *ev_ctx,
 		return pid;
 	}
 
-	status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true);
+	status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true,
+					"spoolssd-master");
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
 		smb_panic("reinit_after_fork() failed");
 	}
 
-	prctl_set_comment("spoolssd-master");
-
 	/* save the parent process id so the children can use it later */
 	parent_id = messaging_server_id(msg_ctx);
 
diff --git a/source3/profile/profile.c b/source3/profile/profile.c
index 00cb3e5..1464a42 100644
--- a/source3/profile/profile.c
+++ b/source3/profile/profile.c
@@ -312,7 +312,7 @@ void smbprofile_dump(void)
 	return;
 }
 
-void smbprofile_cleanup(pid_t pid)
+void smbprofile_cleanup(pid_t pid, pid_t dst)
 {
 	TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
 	struct profile_stats s = {};
@@ -336,7 +336,7 @@ void smbprofile_cleanup(pid_t pid)
 	tdb_delete(smbprofile_state.internal.db->tdb, key);
 	tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
 
-	pid = getpid();
+	pid = dst;
 	ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
 	if (ret != 0) {
 		return;
diff --git a/source3/registry/reg_backend_db.c b/source3/registry/reg_backend_db.c
index 7b3391d..bdfe7d2 100644
--- a/source3/registry/reg_backend_db.c
+++ b/source3/registry/reg_backend_db.c
@@ -966,12 +966,7 @@ static WERROR regdb_delete_key_with_prefix(struct db_context *db,
 		goto done;
 	}
 
-	werr = ntstatus_to_werror(dbwrap_delete_bystring(db, path));
-
-	/* treat "not found" as ok */
-	if (W_ERROR_EQUAL(werr, WERR_NOT_FOUND)) {
-		werr = WERR_OK;
-	}
+	werr = ntstatus_to_werror(dbwrap_purge_bystring(db, path));
 
 done:
 	talloc_free(mem_ctx);
diff --git a/source3/registry/reg_objects.c b/source3/registry/reg_objects.c
index 2d48b26..ded69e8 100644
--- a/source3/registry/reg_objects.c
+++ b/source3/registry/reg_objects.c
@@ -304,7 +304,7 @@ int regsubkey_ctr_numkeys( struct regsubkey_ctr *ctr )
 }
 
 /***********************************************************************
- Retreive a specific key string
+ Retrieve a specific key string
  **********************************************************************/
 
 char* regsubkey_ctr_specific_key( struct regsubkey_ctr *ctr, uint32_t key_index )
@@ -378,7 +378,7 @@ uint32_t regval_type(struct regval_blob *val)
 }
 
 /***********************************************************************
- Retreive a pointer to a specific value.  Caller shoud dup the structure
+ Retrieve a pointer to a specific value.  Caller shoud dup the structure
  since this memory will go away when the ctr is free()'d
  **********************************************************************/
 
diff --git a/source3/registry/regfio.c b/source3/registry/regfio.c
index c895bc4..9bb89ff 100644
--- a/source3/registry/regfio.c
+++ b/source3/registry/regfio.c
@@ -1852,7 +1852,7 @@ static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
 			nk->sec_desc->size      = ndr_size_security_descriptor(sec_desc, 0)
 				+ sizeof(uint32_t);
 
-			DLIST_ADD_END( file->sec_desc_list, nk->sec_desc, REGF_SK_REC *);
+			DLIST_ADD_END( file->sec_desc_list, nk->sec_desc);
 
 			/* update the offsets for us and the previous sd in the list.
 			   if this is the first record, then just set the next and prev
diff --git a/source3/rpc_client/rpc_transport_np.c b/source3/rpc_client/rpc_transport_np.c
index b928b7c..9dc5c56 100644
--- a/source3/rpc_client/rpc_transport_np.c
+++ b/source3/rpc_client/rpc_transport_np.c
@@ -141,7 +141,8 @@ static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq)
 				 timeval_current_ofs_msec(100 * state->retries),
 				 rpc_transport_np_init_pipe_open_retry, req);
 		if (tevent_req_nomem(te, req)) {
-			return;
+			DEBUG(2, ("Failed to create asynchronous "
+					"tevent_timer"));
 		}
 		return;
 	} else if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/rpc_server/epmd.c b/source3/rpc_server/epmd.c
index f87edd8..faf60f5 100644
--- a/source3/rpc_server/epmd.c
+++ b/source3/rpc_server/epmd.c
@@ -25,8 +25,6 @@
 #include "ntdomain.h"
 #include "messages.h"
 
-#include "lib/util/util_process.h"
-
 #include "librpc/rpc/dcerpc_ep.h"
 #include "../librpc/gen_ndr/srv_epmapper.h"
 #include "rpc_server/rpc_server.h"
@@ -162,14 +160,12 @@ void start_epmd(struct tevent_context *ev_ctx,
 		return;
 	}
 
-	status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true);
+	status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, "epmd");
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
 		smb_panic("reinit_after_fork() failed");
 	}
 
-	prctl_set_comment("epmd");
-
 	epmd_reopen_logs();
 
 	epmd_setup_sig_term_handler(ev_ctx);
diff --git a/source3/rpc_server/fss/srv_fss_agent.c b/source3/rpc_server/fss/srv_fss_agent.c
index 19578cc..68a5143 100644
--- a/source3/rpc_server/fss/srv_fss_agent.c
+++ b/source3/rpc_server/fss/srv_fss_agent.c
@@ -247,8 +247,7 @@ static NTSTATUS fss_prune_stale(struct messaging_context *msg_ctx,
 			while (sc_smap != NULL) {
 				struct fss_sc_smap *smap_next = sc_smap->next;
 				DLIST_REMOVE(sc->smaps, sc_smap);
-				DLIST_ADD_END(prunable_sc_smaps, sc_smap,
-					      struct fss_sc_smap *);
+				DLIST_ADD_END(prunable_sc_smaps, sc_smap);
 				sc->smaps_count--;
 				sc_smap = smap_next;
 			}
@@ -668,7 +667,7 @@ uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
 	}
 	sc_set->state = FSS_SC_STARTED;
 	sc_set->context = fss_global.cur_ctx;
-	DLIST_ADD_END(fss_global.sc_sets, sc_set, struct fss_sc_set *);
+	DLIST_ADD_END(fss_global.sc_sets, sc_set);
 	fss_global.sc_sets_count++;
 	DEBUG(6, ("%s: shadow-copy set %u added\n",
 		  sc_set->id_str, fss_global.sc_sets_count));
@@ -864,10 +863,10 @@ uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
 	}
 
 	/* add share map to shadow-copy */
-	DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *);
+	DLIST_ADD_END(sc->smaps, sc_smap);
 	sc->smaps_count++;
 	/* add shadow-copy to shadow-copy set */
-	DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
+	DLIST_ADD_END(sc_set->scs, sc);
 	sc_set->scs_count++;
 	DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
 		  sc->volume_name, sc_set->id_str));
diff --git a/source3/rpc_server/fss/srv_fss_state.c b/source3/rpc_server/fss/srv_fss_state.c
index 97604f3..0f2ef0e 100644
--- a/source3/rpc_server/fss/srv_fss_state.c
+++ b/source3/rpc_server/fss/srv_fss_state.c
@@ -437,7 +437,7 @@ static int fss_state_retrieve_traverse(struct db_record *rec,
 		if (!NT_STATUS_IS_OK(status)) {
 			return -1;
 		}
-		DLIST_ADD_END(trv_state->smaps, smap, struct fss_sc_smap *);
+		DLIST_ADD_END(trv_state->smaps, smap);
 		trv_state->smaps_count++;
 	} else if (strstr((char *)key.dptr, FSS_DB_KEY_PFX_SC) != NULL) {
 		struct fss_sc *sc;
@@ -446,7 +446,7 @@ static int fss_state_retrieve_traverse(struct db_record *rec,
 		if (!NT_STATUS_IS_OK(status)) {
 			return -1;
 		}
-		DLIST_ADD_END(trv_state->scs, sc, struct fss_sc *);
+		DLIST_ADD_END(trv_state->scs, sc);
 		trv_state->scs_count++;
 	} else if (strstr((char *)key.dptr, FSS_DB_KEY_PFX_SC_SET) != NULL) {
 		struct fss_sc_set *sc_set;
@@ -455,7 +455,7 @@ static int fss_state_retrieve_traverse(struct db_record *rec,
 		if (!NT_STATUS_IS_OK(status)) {
 			return -1;
 		}
-		DLIST_ADD_END(trv_state->sc_sets, sc_set, struct fss_sc_set *);
+		DLIST_ADD_END(trv_state->sc_sets, sc_set);
 		trv_state->sc_sets_count++;
 	} else {
 		/* global context and db vers */
@@ -487,7 +487,7 @@ static NTSTATUS fss_state_hierarchize_smaps(struct fss_traverse_state *trv_state
 		talloc_steal(sc, smap);
 		DLIST_REMOVE(trv_state->smaps, smap);
 		trv_state->smaps_count--;
-		DLIST_ADD_END(sc->smaps, smap, struct fss_sc_smap *);
+		DLIST_ADD_END(sc->smaps, smap);
 		smaps_moved++;
 
 		/* last component of the tdb key path is the sc share name */
@@ -527,7 +527,7 @@ static NTSTATUS fss_state_hierarchize_scs(struct fss_traverse_state *trv_state,
 		talloc_steal(sc_set, sc);
 		DLIST_REMOVE(trv_state->scs, sc);
 		trv_state->scs_count--;
-		DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
+		DLIST_ADD_END(sc_set->scs, sc);
 		scs_moved++;
 
 		sc->sc_set = sc_set;
@@ -575,7 +575,7 @@ static NTSTATUS fss_state_hierarchize(struct fss_traverse_state *trv_state,
 		/* sc_set mem already owned by trv_state->mem_ctx */
 		DLIST_REMOVE(trv_state->sc_sets, sc_set);
 		trv_state->sc_sets_count--;
-		DLIST_ADD_END(*sc_sets, sc_set, struct fss_sc_set *);
+		DLIST_ADD_END(*sc_sets, sc_set);
 		i++;
 
 		/* last component of the tdb key path is the sc_set GUID str */
diff --git a/source3/rpc_server/fssd.c b/source3/rpc_server/fssd.c
index 81c65a6..8f55aff 100644
--- a/source3/rpc_server/fssd.c
+++ b/source3/rpc_server/fssd.c
@@ -171,7 +171,7 @@ void start_fssd(struct tevent_context *ev_ctx,
 	}
 
 	/* child */
-	status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true);
+	status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, NULL);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
 		smb_panic("reinit_after_fork() failed");
@@ -182,7 +182,7 @@ void start_fssd(struct tevent_context *ev_ctx,
 	fssd_setup_sig_term_handler(ev_ctx);
 	fssd_setup_sig_hup_handler(ev_ctx, msg_ctx);
 
-	ok = serverid_register(procid_self(),
+	ok = serverid_register(messaging_server_id(msg_ctx),
 			       FLAG_MSG_GENERAL |
 			       FLAG_MSG_PRINT_GENERAL);
 	if (!ok) {
diff --git a/source3/rpc_server/lsa/srv_lsa_nt.c b/source3/rpc_server/lsa/srv_lsa_nt.c
index 1e3f9f9..2d0d29e 100644
--- a/source3/rpc_server/lsa/srv_lsa_nt.c
+++ b/source3/rpc_server/lsa/srv_lsa_nt.c
@@ -3905,7 +3905,7 @@ NTSTATUS _lsa_EnumTrustedDomainsEx(struct pipes_struct *p,
 	NTSTATUS nt_status;
 
 	/* bail out early if pdb backend is not capable of ex trusted domains,
-	 * if we dont do that, the client might not call
+	 * if we don't do that, the client might not call
 	 * _lsa_EnumTrustedDomains() afterwards - gd */
 
 	if (!(pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
diff --git a/source3/rpc_server/lsasd.c b/source3/rpc_server/lsasd.c
index 6fd0817..8cd89a9 100644
--- a/source3/rpc_server/lsasd.c
+++ b/source3/rpc_server/lsasd.c
@@ -24,8 +24,6 @@
 #include "messages.h"
 #include "ntdomain.h"
 
-#include "lib/util/util_process.h"
-
 #include "lib/id_cache.h"
 
 #include "../lib/tsocket/tsocket.h"
@@ -249,14 +247,12 @@ static bool lsasd_child_init(struct tevent_context *ev_ctx,
 	bool ok;
 
 	status = reinit_after_fork(msg_ctx, ev_ctx,
-				   true);
+				   true, "lsasd-child");
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
 		smb_panic("reinit_after_fork() failed");
 	}
 
-	prctl_set_comment("lsasd-child");
-
 	lsasd_child_id = child_id;
 	lsasd_reopen_logs(child_id);
 
@@ -861,14 +857,12 @@ void start_lsasd(struct tevent_context *ev_ctx,
 		return;
 	}
 
-	status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true);
+	status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, "lsasd-master");
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
 		smb_panic("reinit_after_fork() failed");
 	}
 
-	prctl_set_comment("lsasd-master");
-
 	/* save the parent process id so the children can use it later */
 	parent_id = messaging_server_id(msg_ctx);
 
diff --git a/source3/rpc_server/mdssd.c b/source3/rpc_server/mdssd.c
index fac386b..f76d13e 100644
--- a/source3/rpc_server/mdssd.c
+++ b/source3/rpc_server/mdssd.c
@@ -24,8 +24,6 @@
 #include "messages.h"
 #include "ntdomain.h"
 
-#include "lib/util/util_process.h"
-
 #include "lib/id_cache.h"
 
 #include "../lib/tsocket/tsocket.h"
@@ -206,14 +204,12 @@ static bool mdssd_child_init(struct tevent_context *ev_ctx,
 	bool ok;
 
 	status = reinit_after_fork(msg_ctx, ev_ctx,
-				   true);
+				   true, "mdssd-child");
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
 		smb_panic("reinit_after_fork() failed");
 	}
 
-	prctl_set_comment("mdssd-child");
-
 	mdssd_child_id = child_id;
 	reopen_logs();
 
@@ -671,15 +667,12 @@ void start_mdssd(struct tevent_context *ev_ctx,
 		return;
 	}
 
-	status = reinit_after_fork(msg_ctx,
-				   ev_ctx,
-				   true);
+	status = reinit_after_fork(msg_ctx, ev_ctx, true, "mdssd-master");
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
 		smb_panic("reinit_after_fork() failed");
 	}
 
-	prctl_set_comment("mdssd-master");
 	reopen_logs();
 
 	/* save the parent process id so the children can use it later */
diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c
index ad710bb..bfb7af6 100644
--- a/source3/rpc_server/samr/srv_samr_chgpasswd.c
+++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c
@@ -54,7 +54,7 @@
 #include "rpc_server/samr/srv_samr_util.h"
 #include "passdb.h"
 #include "auth.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw.h"
 
 #ifndef ALLOW_CHANGE_PASSWORD
 #if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID))
diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c
index 0639b87..2778ba8 100644
--- a/source3/rpc_server/spoolss/srv_spoolss_nt.c
+++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c
@@ -7015,6 +7015,89 @@ WERROR _spoolss_SetPrinter(struct pipes_struct *p,
 		case 3:
 			return update_printer_sec(r->in.handle, p,
 						  r->in.secdesc_ctr);
+		case 4: {
+			struct spoolss_PrinterInfo2 *old_printer;
+			struct spoolss_SetPrinterInfo2 *set_old_printer;
+			struct spoolss_SetPrinterInfoCtr *info_ctr;
+			struct dcerpc_binding_handle *b;
+			int snum;
+			TALLOC_CTX *tmp_ctx;
+
+			tmp_ctx = talloc_new(p->mem_ctx);
+			if (tmp_ctx == NULL) {
+				return WERR_NOMEM;
+			}
+
+			if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
+				TALLOC_FREE(tmp_ctx);
+				return WERR_BADFID;
+			}
+
+			result = winreg_printer_binding_handle(tmp_ctx,
+							       get_session_info_system(),
+							       p->msg_ctx,
+							       &b);
+			if (!W_ERROR_IS_OK(result)) {
+				TALLOC_FREE(tmp_ctx);
+				return result;
+			}
+
+			result = winreg_get_printer(tmp_ctx, b,
+						    lp_const_servicename(snum),
+						    &old_printer);
+			if (!W_ERROR_IS_OK(result)) {
+				TALLOC_FREE(tmp_ctx);
+				return WERR_BADFID;
+			}
+
+			old_printer->servername = talloc_strdup(tmp_ctx, r->in.info_ctr->info.info4->servername);
+			if (old_printer->servername == NULL) {
+				TALLOC_FREE(tmp_ctx);
+				return WERR_NOMEM;
+			}
+
+			old_printer->printername = talloc_strdup(tmp_ctx, r->in.info_ctr->info.info4->printername);
+			if (old_printer->printername == NULL) {
+				TALLOC_FREE(tmp_ctx);
+				return WERR_NOMEM;
+			}
+
+			old_printer->attributes = r->in.info_ctr->info.info4->attributes;
+
+			set_old_printer = talloc_zero(tmp_ctx, struct spoolss_SetPrinterInfo2);
+			if (set_old_printer == NULL) {
+				TALLOC_FREE(tmp_ctx);
+				return WERR_NOMEM;
+			}
+
+			spoolss_printerinfo2_to_setprinterinfo2(old_printer, set_old_printer);
+
+			info_ctr = talloc_zero(tmp_ctx, struct spoolss_SetPrinterInfoCtr);
+			if (info_ctr == NULL) {
+				TALLOC_FREE(tmp_ctx);
+				return WERR_NOMEM;
+			}
+
+			info_ctr->level = 2;
+			info_ctr->info.info2 = set_old_printer;
+
+			result = update_printer(p, r->in.handle,
+						info_ctr,
+						r->in.devmode_ctr->devmode);
+
+			if (!W_ERROR_IS_OK(result)) {
+				TALLOC_FREE(tmp_ctx);
+				return result;
+			}
+
+			if (r->in.secdesc_ctr->sd) {
+				result = update_printer_sec(r->in.handle, p,
+							    r->in.secdesc_ctr);
+			}
+
+			TALLOC_FREE(tmp_ctx);
+			return result;
+		}
 		case 7:
 			return publish_or_unpublish_printer(p, r->in.handle,
 							    r->in.info_ctr->info.info7);
diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
index 96c022b..279cd9e 100644
--- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
@@ -477,12 +477,19 @@ static bool is_hidden_share(int snum)
 static bool is_enumeration_allowed(struct pipes_struct *p,
                                    int snum)
 {
-    if (!lp_access_based_share_enum(snum))
-        return true;
+	if (!lp_access_based_share_enum(snum)) {
+		return true;
+	}
+
+	if (!user_ok_token(p->session_info->unix_info->unix_name,
+			   p->session_info->info->domain_name,
+			   p->session_info->security_token, snum)) {
+		return false;
+	}
 
-    return share_access_check(p->session_info->security_token,
-			      lp_servicename(talloc_tos(), snum),
-			      FILE_READ_DATA, NULL);
+	return share_access_check(p->session_info->security_token,
+				  lp_servicename(talloc_tos(), snum),
+				  FILE_READ_DATA, NULL);
 }
 
 /****************************************************************************
@@ -2311,6 +2318,7 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p,
 	files_struct *fsp = NULL;
 	int snum;
 	char *oldcwd = NULL;
+	uint32_t ucf_flags = 0;
 
 	ZERO_STRUCT(st);
 
@@ -2346,7 +2354,7 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p,
 					conn,
 					false,
 					r->in.file,
-					0,
+					ucf_flags,
 					NULL,
 					&smb_fname);
 	if (!NT_STATUS_IS_OK(nt_status)) {
@@ -2458,6 +2466,7 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p,
 	char *oldcwd = NULL;
 	struct security_descriptor *psd = NULL;
 	uint32_t security_info_sent = 0;
+	uint32_t ucf_flags = 0;
 
 	ZERO_STRUCT(st);
 
@@ -2495,7 +2504,7 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p,
 					conn,
 					false,
 					r->in.file,
-					0,
+					ucf_flags,
 					NULL,
 					&smb_fname);
 	if (!NT_STATUS_IS_OK(nt_status)) {
diff --git a/source3/rpcclient/cmd_clusapi.c b/source3/rpcclient/cmd_clusapi.c
index b7451dc..ab1b1f4 100644
--- a/source3/rpcclient/cmd_clusapi.c
+++ b/source3/rpcclient/cmd_clusapi.c
@@ -203,6 +203,63 @@ static WERROR cmd_clusapi_create_enum(struct rpc_pipe_client *cli,
 	return WERR_OK;
 }
 
+static WERROR cmd_clusapi_create_enumex(struct rpc_pipe_client *cli,
+					TALLOC_CTX *mem_ctx,
+					int argc,
+					const char **argv)
+{
+	struct dcerpc_binding_handle *b = cli->binding_handle;
+	NTSTATUS status;
+	WERROR error;
+	uint32_t dwType = 1;
+	struct ENUM_LIST *ReturnIdEnum;
+	struct ENUM_LIST *ReturnNameEnum;
+	WERROR rpc_status, ignore;
+	struct policy_handle Cluster;
+
+	status = dcerpc_clusapi_OpenCluster(b, mem_ctx,
+					    &error,
+					    &Cluster);
+	if (!NT_STATUS_IS_OK(status)) {
+		return ntstatus_to_werror(status);
+	}
+
+	if (!W_ERROR_IS_OK(error)) {
+		printf("error: %s\n", win_errstr(error));
+		return error;
+	}
+
+	if (argc >= 2) {
+		sscanf(argv[1],"%x",&dwType);
+	}
+
+	status = dcerpc_clusapi_CreateEnumEx(b, mem_ctx,
+					     Cluster,
+					     dwType,
+					     0,
+					     &ReturnIdEnum,
+					     &ReturnNameEnum,
+					     &rpc_status,
+					     &error);
+	dcerpc_clusapi_CloseCluster(b, mem_ctx,
+				    &Cluster,
+				    &ignore);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		return ntstatus_to_werror(status);
+	}
+
+	if (!W_ERROR_IS_OK(error)) {
+		printf("error: %s\n", win_errstr(error));
+		return error;
+	}
+
+	printf("rpc_status: %s\n", win_errstr(rpc_status));
+
+	return WERR_OK;
+}
+
+
 static WERROR cmd_clusapi_open_resource(struct rpc_pipe_client *cli,
 					TALLOC_CTX *mem_ctx,
 					int argc,
@@ -453,6 +510,7 @@ struct cmd_set clusapi_commands[] = {
 	{ "clusapi_get_cluster_version", RPC_RTYPE_WERROR, NULL, cmd_clusapi_get_cluster_version, &ndr_table_clusapi, NULL, "bla", "" },
 	{ "clusapi_get_quorum_resource", RPC_RTYPE_WERROR, NULL, cmd_clusapi_get_quorum_resource, &ndr_table_clusapi, NULL, "bla", "" },
 	{ "clusapi_create_enum", RPC_RTYPE_WERROR, NULL, cmd_clusapi_create_enum, &ndr_table_clusapi, NULL, "bla", "" },
+	{ "clusapi_create_enumex", RPC_RTYPE_WERROR, NULL, cmd_clusapi_create_enumex, &ndr_table_clusapi, NULL, "bla", "" },
 	{ "clusapi_open_resource", RPC_RTYPE_WERROR, NULL, cmd_clusapi_open_resource, &ndr_table_clusapi, NULL, "bla", "" },
 	{ "clusapi_online_resource", RPC_RTYPE_WERROR, NULL, cmd_clusapi_online_resource, &ndr_table_clusapi, NULL, "bla", "" },
 	{ "clusapi_offline_resource", RPC_RTYPE_WERROR, NULL, cmd_clusapi_offline_resource, &ndr_table_clusapi, NULL, "bla", "" },
diff --git a/source3/rpcclient/cmd_witness.c b/source3/rpcclient/cmd_witness.c
index bd0372f..5d07dde 100644
--- a/source3/rpcclient/cmd_witness.c
+++ b/source3/rpcclient/cmd_witness.c
@@ -406,6 +406,11 @@ static WERROR cmd_witness_AsyncNotify(struct rpc_pipe_client *cli,
 		goto done;
 	}
 
+	if (response == NULL) {
+		d_printf("Got an empty response\n");
+		goto done;
+	}
+
 	switch(response->type) {
 	case WITNESS_NOTIFY_RESOURCE_CHANGE:
 		d_printf("Resource change");
diff --git a/source3/script/tests/test_dfree_quota.sh b/source3/script/tests/test_dfree_quota.sh
new file mode 100755
index 0000000..5392d3d
--- /dev/null
+++ b/source3/script/tests/test_dfree_quota.sh
@@ -0,0 +1,174 @@
+#!/bin/sh
+#
+# Blackbox test for disk-free, quota, and their interaction
+#
+
+if [ $# -lt 6 ]; then
+cat <<EOF
+Usage: test_dfree_quota.sh SERVER DOMAIN USERNAME PASSWORD LOCAL_PATH SMBCLIENT SMBCQUOTAS
+EOF
+exit 1;
+fi
+
+SERVER=$1
+DOMAIN=$2
+USERNAME=$3
+PASSWORD=$4
+ENVDIR=`dirname $5`
+WORKDIR=$5/dfree
+smbclient=$6
+smbcquotas=$7
+shift 7
+failed=0
+
+CONFFILE=$ENVDIR/lib/dfq.conf
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+sighup_smbd() {
+    kill -HUP -`cat $ENVDIR/pid/smbd.pid`
+}
+
+conf_lines() {
+    local uid
+    local gid
+    uid=$(id -u $USERNAME)
+    gid=$(id -g $USERNAME)
+cat <<ABC
+conf1:df:block size = 512:disk free = 10:disk size = 20
+conf2:df:block size = 1024:disk free = 10:disk size = 20
+conf3:df:block size = 4096:disk free = 750:disk size = 281474976710656
+confq1:u$uid:block size = 4096:hard limit = 750:soft limit = 1000:cur blocks = 10
+confdfq1:df:block size = 4096:disk free = 10:disk size = 20
+confdfq1:u$uid:block size = 4096:hard limit = 750:soft limit = 1000:cur blocks = 10
+confdfq2:df:block size = 4096:disk free = 10:disk size = 20
+confdfq2:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 37
+confdfq3:df:block size = 4096:disk free = 10:disk size = 80
+confdfq3:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 0
+confdfq4:df:block size = 4096:disk free = 10:disk size = 80
+confdfq4:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 37
+edquot:df:block size = 4096:disk free = 10:disk size = 80
+edquot:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 41:edquot = 1
+slimit:df:block size = 4096:disk free = 10:disk size = 80
+slimit:u$uid:block size = 4096:hard limit = 44:soft limit = 40:cur blocks = 42
+hlimit:df:block size = 4096:disk free = 10:disk size = 80
+hlimit:u$uid:block size = 4096:hard limit = 44:soft limit = 0:cur blocks = 45
+islimit:df:block size = 4096:disk free = 10:disk size = 80
+islimit:u$uid:block size = 4096:hard limit = 44:soft limit = 40:cur blocks = 37:inode soft limit = 30:inode hard limit = 35:cur inodes = 32
+ihlimit:df:block size = 4096:disk free = 10:disk size = 80
+ihlimit:u$uid:block size = 4096:hard limit = 44:soft limit = 40:cur blocks = 37:inode soft limit = 0:inode hard limit = 35:cur inodes = 36
+trygrp1:df:block size = 4096:disk free = 10:disk size = 80
+trygrp1:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 41:err = 1
+trygrp1:g$gid:block size = 4096:hard limit = 60:soft limit = 60:cur blocks = 55
+trygrp2:df:block size = 4096:disk free = 10:disk size = 80
+trygrp2:u$uid:block size = 4096:hard limit = 0:soft limit = 0:cur blocks = 41
+trygrp2:g$gid:block size = 4096:hard limit = 60:soft limit = 60:cur blocks = 56
+ABC
+}
+
+setup_1_conf() {
+    conf_name="$1"
+    subdir="$2"
+    absdir=`realpath $WORKDIR/$subdir`
+    conf_lines | sed -rn "s/^$conf_name:(.*)/\1/p" | tr ":" "\n" | \
+    awk  -F '=' -v atdir=$absdir 'NF==1 {section=$1} NF==2 {sub(/\s*$/, "", $1); printf "\tfake_dfq:%s/%s/%s =%s\n", section, $1, atdir, $2}'
+}
+
+setup_conf() {
+    rm $CONFFILE
+    touch $CONFFILE
+
+    until [ -z "$1" ]
+    do
+        setup_1_conf $1 $2 >> $CONFFILE
+        shift
+        shift
+    done
+    sighup_smbd
+    #let it load...
+    sleep .5
+}
+
+
+test_smbclient_dfree() {
+	name="$1"
+	dir="$2"
+    confs="$3"
+    expected="$4"
+	shift
+    shift
+    shift
+    shift
+    subunit_start_test "$name"
+    setup_conf $confs
+	output=$($VALGRIND $smbclient //$SERVER/dfq -c "cd $dir; l" $@ 2>&1)
+    status=$?
+    if [ "$status" = "0" ]; then
+		received=$(echo "$output" | awk '/blocks of size/ {print $1, $5, $6}')
+		if [ "$expected" = "$received" ]; then
+			subunit_pass_test "$name"
+		else
+			echo "$output" | subunit_fail_test "$name"
+		fi
+	else
+		echo "$output" | subunit_fail_test "$name"
+	fi
+	return $status
+}
+
+test_smbcquotas() {
+	name="$1"
+    conf="$2"
+    user="$3"
+    expected="$4"
+	shift
+    shift
+    shift
+    shift
+	subunit_start_test "$name"
+    setup_conf "$conf" "."
+	output=$($VALGRIND $smbcquotas //$SERVER/dfq $@ 2>/dev/null | tr '\\' '/')
+	status=$?
+	if [ "$status" = "0" ]; then
+		received=$(echo "$output" | awk "/$SERVER\\/$user/ {printf \"%s%s%s\", \$3, \$4, \$5}")
+		if [ "$expected" = "$received" ]; then
+			subunit_pass_test "$name"
+		else
+			echo "$output" | subunit_fail_test "$name"
+		fi
+	else
+		echo "$output" | subunit_fail_test "$name"
+	fi
+	return $status
+}
+
+#basic disk-free tests
+test_smbclient_dfree "Test dfree share root SMB3 no quota" "." "conf1 ." "10 1024. 5" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree subdir SMB3 no quota" "subdir1" "conf1 . conf2 subdir1" "20 1024. 10" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree subdir NT1 no quota" "subdir1" "conf1 . conf2 subdir1" "10 1024. 5" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test large disk" "." "conf3 ." "1125899906842624 1024. 3000" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+#basic quota test (SMB1 only)
+test_smbcquotas "Test user quota" confq1 $USERNAME "40960/4096000/3072000" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=`expr $failed + 1`
+
+#quota limit > disk size, remaining quota > disk free
+test_smbclient_dfree "Test dfree share root df vs quota case 1" "." "confdfq1 ." "80 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+#quota limit > disk size, remaining quota < disk free
+test_smbclient_dfree "Test dfree share root df vs quota case 2" "." "confdfq2 ." "80 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+#quota limit < disk size, remaining quota > disk free
+test_smbclient_dfree "Test dfree share root df vs quota case 3" "." "confdfq3 ." "160 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+#quota limit < disk size, remaining quota < disk free
+test_smbclient_dfree "Test dfree share root df vs quota case 4" "." "confdfq4 ." "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree subdir df vs quota case 4" "subdir1" "confdfq4 subdir1" "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+
+#quota-->disk free special cases
+test_smbclient_dfree "Test quota->dfree edquot" "subdir1" "edquot subdir1" "164 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree soft limit" "subdir1" "slimit subdir1" "168 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree hard limit" "subdir1" "hlimit subdir1" "180 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree inode soft limit" "subdir1" "islimit subdir1" "148 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree inode hard limit" "subdir1" "ihlimit subdir1" "148 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree err try group" "subdir1" "trygrp1 subdir1" "240 1024. 20" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree no-quota try group" "subdir1" "trygrp2 subdir1" "240 1024. 16" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+
+setup_conf
+exit $failed
diff --git a/source3/script/tests/test_forceuser_validusers.sh b/source3/script/tests/test_forceuser_validusers.sh
new file mode 100755
index 0000000..07aa1a5
--- /dev/null
+++ b/source3/script/tests/test_forceuser_validusers.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# Blackbox test for share with force user settings
+#
+
+if [ $# -lt 6 ]; then
+cat <<EOF
+Usage: test_forceuser.sh SERVER DOMAIN USERNAME PASSWORD LOCAL_PATH SMBCLIENT <smbclient arguments>
+EOF
+exit 1;
+fi
+
+SERVER="$1"
+DOMAIN="$2"
+USERNAME="force_user"
+PASSWORD="$4"
+LOCAL_PATH="$5"
+SMBCLIENT="$6"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+ADDARGS="$*"
+failed=0
+
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+
+run_cmd_nooutput() {
+	CMD="$1"
+
+	out=`eval ${CMD} &> TESTOUT`
+	if [ $? != 0 ] ; then
+		cat TESTOUT
+		rm -f TESTOUT
+		echo "command failed"
+		false
+		return
+	fi
+
+	rm -f TESTOUT
+	true
+	return
+}
+
+test_force_user_valid_users()
+{
+	SMB_SHARE="force_user_valid_users"
+	run_cmd_nooutput "${SMBCLIENT} //${SERVER}/${SMB_SHARE} -U$USERNAME%$PASSWORD -c 'ls'"
+}
+
+# Test
+testit "force user not works when combined with valid users" \
+	test_force_user_valid_users || failed=`expr $failed + 1`
+
+# Cleanup
+
+# Results
+testok $0 $failed
diff --git a/source3/script/tests/test_ntlm_auth_s3.sh b/source3/script/tests/test_ntlm_auth_s3.sh
index 655556b..a6f20ed 100755
--- a/source3/script/tests/test_ntlm_auth_s3.sh
+++ b/source3/script/tests/test_ntlm_auth_s3.sh
@@ -24,7 +24,7 @@ BADSID=`eval $BINDIR/wbinfo -n $USERNAME | cut -d ' ' -f1 | sed 's/..$//'`
 
 failed=0
 
-test_interactive_prompt_stdout()
+test_plaintext_check_output_stdout()
 {
 	tmpfile=$PREFIX/ntlm_commands
 
@@ -55,7 +55,7 @@ EOF
 	fi
 }
 
-test_interactive_prompt_stdout_fail()
+test_plaintext_check_output_fail()
 {
 	tmpfile=$PREFIX/ntlm_commands
 
@@ -86,6 +86,188 @@ EOF
 	fi
 }
 
+test_ntlm_server_1_check_output()
+{
+	tmpfile=$PREFIX/ntlm_commands
+
+	cat > $tmpfile <<EOF
+LANMAN-Challenge: 0123456789abcdef
+NT-Response: 25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6
+NT-Domain: TEST
+Username: testuser
+Request-User-Session-Key: Yes
+.
+EOF
+	cmd='$NTLM_AUTH "$@" --helper-protocol=ntlm-server-1  --password=SecREt01< $tmpfile 2>&1'
+	eval echo "$cmd"
+	out=`eval $cmd`
+	ret=$?
+	rm -f $tmpfile
+
+	if [ $ret != 0 ] ; then
+		echo "$out"
+		echo "command failed"
+		false
+		return
+	fi
+
+	echo "$out" | grep "User-Session-Key: 3F373EA8E4AF954F14FAA506F8EEBDC4" >/dev/null 2>&1
+
+	if [ $? = 0 ] ; then
+		# authenticated .. succeed
+		true
+	else
+		echo failed to get successful authentication
+		false
+	fi
+}
+
+test_ntlm_server_1_check_output_fail()
+{
+	tmpfile=$PREFIX/ntlm_commands
+
+	# Break the password with a leading A on the challenge
+	cat > $tmpfile <<EOF
+LANMAN-Challenge: A123456789abcdef
+NT-Response: 25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6
+NT-Domain: TEST
+Username: testuser
+Request-User-Session-Key: Yes
+.
+EOF
+	cmd='$NTLM_AUTH "$@" --helper-protocol=ntlm-server-1 --password=SecREt01 < $tmpfile 2>&1'
+	eval echo "$cmd"
+	out=`eval $cmd`
+	ret=$?
+	rm -f $tmpfile
+
+	if [ $ret != 0 ] ; then
+		echo "$out"
+		echo "command failed"
+		false
+		return
+	fi
+
+	echo "$out" | grep "Authenticated: No" >/dev/null 2>&1
+
+	if [ $? = 0 ] ; then
+		# failed to authenticate .. success
+		true
+	else
+		echo "incorrectly gave a successful authentication"
+		false
+	fi
+}
+
+test_ntlm_server_1_check_winbind_output()
+{
+	tmpfile=$PREFIX/ntlm_commands
+
+	# This isn't the correct password
+	cat > $tmpfile <<EOF
+Password: $PASSWORD
+NT-Domain: $DOMAIN
+Username: $USERNAME
+Request-User-Session-Key: Yes
+.
+EOF
+	cmd='$NTLM_AUTH "$@" --helper-protocol=ntlm-server-1 --require-membership-of=$SID < $tmpfile 2>&1'
+	eval echo "$cmd"
+	out=`eval $cmd`
+	ret=$?
+	rm -f $tmpfile
+
+	if [ $ret != 0 ] ; then
+		echo "$out"
+		echo "command failed"
+		false
+		return
+	fi
+
+	echo "$out" | grep "Authenticated: Yes" >/dev/null 2>&1
+
+	if [ $? = 0 ] ; then
+		# authenticated .. success
+		true
+	else
+		echo "Failed to authenticate the user or match with SID $SID"
+		false
+	fi
+}
+
+test_ntlm_server_1_check_winbind_output_wrong_sid()
+{
+	tmpfile=$PREFIX/ntlm_commands
+
+	# This isn't the correct password
+	cat > $tmpfile <<EOF
+Password: $PASSWORD
+NT-Domain: $DOMAIN
+Username: $USERNAME
+Request-User-Session-Key: Yes
+.
+EOF
+	cmd='$NTLM_AUTH "$@" --helper-protocol=ntlm-server-1 --require-membership-of=$BADSID < $tmpfile 2>&1'
+	eval echo "$cmd"
+	out=`eval $cmd`
+	ret=$?
+	rm -f $tmpfile
+
+	if [ $ret != 0 ] ; then
+		echo "$out"
+		echo "command failed"
+		false
+		return
+	fi
+
+	echo "$out" | grep "Authenticated: No" >/dev/null 2>&1
+
+	if [ $? = 0 ] ; then
+		# failed to authenticate .. success
+		true
+	else
+		echo "incorrectly gave a successful authentication"
+		false
+	fi
+}
+
+test_ntlm_server_1_check_winbind_output_fail()
+{
+	tmpfile=$PREFIX/ntlm_commands
+
+	# This isn't the correct password
+	cat > $tmpfile <<EOF
+LANMAN-Challenge: 0123456789abcdef
+NT-Response: 25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6
+NT-Domain: $DOMAIN
+Username: $USERNAME
+Request-User-Session-Key: Yes
+.
+EOF
+	cmd='$NTLM_AUTH "$@" --helper-protocol=ntlm-server-1 < $tmpfile 2>&1'
+	eval echo "$cmd"
+	out=`eval $cmd`
+	ret=$?
+	rm -f $tmpfile
+
+	if [ $ret != 0 ] ; then
+		echo "$out"
+		echo "command failed"
+		false
+		return
+	fi
+
+	echo "$out" | grep "Authenticated: No" >/dev/null 2>&1
+
+	if [ $? = 0 ] ; then
+		# failed to authenticate .. success
+		true
+	else
+		echo "incorrectly gave a successful authentication"
+		false
+	fi
+}
+
 testit "ntlm_auth" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH $ADDARGS || failed=`expr $failed + 1`
 # This should work even with NTLMv2
 testit "ntlm_auth with specified domain" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH $ADDARGS --client-domain=fOo --server-domain=fOo || failed=`expr $failed + 1`
@@ -101,7 +283,13 @@ testit "ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server against w
 testit_expect_failure "ntlm_auth against winbindd with failed require-membership-of" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH --client-username=$USERNAME --client-domain=$DOMAIN --client-password=$PASSWORD --server-use-winbindd $ADDARGS --require-membership-of=$BADSID && failed=`expr $failed + 1`
 testit_expect_failure "ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server against winbind with failed require-membership-of" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH --client-username=$USERNAME --client-domain=$DOMAIN --client-password=$PASSWORD --server-use-winbindd --client-helper=gss-spnego-client --server-helper=gss-spnego $ADDARGS --require-membership-of=$BADSID && failed=`expr $failed + 1`
 
-testit "ntlm_auth plaintext authentication with require-membership-of" test_interactive_prompt_stdout || failed=`expr $failed + 1`
-testit "ntlm_auth plaintext authentication with failed require-membership-of" test_interactive_prompt_stdout_fail || failed=`expr $failed + 1`
+testit "ntlm_auth plaintext authentication with require-membership-of" test_plaintext_check_output_stdout || failed=`expr $failed + 1`
+testit "ntlm_auth plaintext authentication with failed require-membership-of" test_plaintext_check_output_fail || failed=`expr $failed + 1`
+
+testit "ntlm_auth ntlm-server-1 with fixed password" test_ntlm_server_1_check_output || failed=`expr $failed + 1`
+testit "ntlm_auth ntlm-server-1 with incorrect fixed password" test_ntlm_server_1_check_output_fail || failed=`expr $failed + 1`
+testit "ntlm_auth ntlm-server-1 with plaintext password against winbind" test_ntlm_server_1_check_winbind_output || failed=`expr $failed + 1`
+testit "ntlm_auth ntlm-server-1 with plaintext password against winbind but wrong sid" test_ntlm_server_1_check_winbind_output_wrong_sid || failed=`expr $failed + 1`
+testit "ntlm_auth ntlm-server-1 with incorrect fixed password against winbind" test_ntlm_server_1_check_winbind_output_fail || failed=`expr $failed + 1`
 
 testok $0 $failed
diff --git a/source3/script/tests/test_offline.sh b/source3/script/tests/test_offline.sh
new file mode 100755
index 0000000..fbc071a
--- /dev/null
+++ b/source3/script/tests/test_offline.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Blackbox test for shadow_copy2 VFS.
+#
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: test_offline SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+WORKDIR=${6}
+SMBCLIENT=${7}
+shift 7
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$*"
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+touch $WORKDIR/foo
+
+failed=0
+
+attribs=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/offline" -I $SERVER_IP -c "allinfo foo" | sed -n 's/^attributes:.*(\([^)]*\)).*/\1/p'`
+testit "file has offline attribute" test "x$attribs" = "x1000"  || failed=`expr $failed + 1`
+
+exit $failed
diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
index eecd5b8..171008d 100755
--- a/source3/script/tests/test_shadow_copy.sh
+++ b/source3/script/tests/test_shadow_copy.sh
@@ -278,6 +278,7 @@ test_shadow_copy_fixed shadow3 mount/base share "sub volume snapshots mounted un
 test_shadow_copy_fixed shadow4 . share "sub volume snapshots mounted outside"
 test_shadow_copy_fixed shadow5 mount/base/share "" "full volume snapshots and share mounted under volume"
 test_shadow_copy_fixed shadow6 . "" "full volume snapshots and share mounted outside"
+test_shadow_copy_fixed shadow8 . share "logical snapshot layout"
 
 # tests for snapshot everywhere - one snapshot location
 test_shadow_copy_fixed shadow7 mount base/share "'everywhere' full volume snapshots"
diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh
index c073b43..5e3db5d 100755
--- a/source3/script/tests/test_smbclient_s3.sh
+++ b/source3/script/tests/test_smbclient_s3.sh
@@ -1003,6 +1003,62 @@ EOF
     fi
 }
 
+# Test wide links are restricted.
+test_widelinks()
+{
+    tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+    cat > $tmpfile <<EOF
+cd dot
+ls
+quit
+EOF
+    cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/widelinks_share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+    eval echo "$cmd"
+    out=`eval $cmd`
+    ret=$?
+    rm -f $tmpfile
+
+    if [ $ret != 0 ] ; then
+	echo "$out"
+	echo "failed accessing widelinks_share with error $ret"
+	false
+	return
+    fi
+
+    echo "$out" | grep 'NT_STATUS'
+    ret=$?
+    if [ $ret == 0 ] ; then
+	echo "$out"
+	echo "failed - NT_STATUS_XXXX listing \\widelinks_share\\dot"
+	false
+    fi
+
+    cat > $tmpfile <<EOF
+allinfo source
+quit
+EOF
+    cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/widelinks_share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+    eval echo "$cmd"
+    out=`eval $cmd`
+    ret=$?
+    rm -f $tmpfile
+
+    if [ $ret != 0 ] ; then
+	echo "$out"
+	echo "failed accessing widelinks_share with error $ret"
+	false
+	return
+    fi
+
+# This should fail with NT_STATUS_ACCESS_DENIED
+    echo "$out" | grep 'NT_STATUS_ACCESS_DENIED'
+    ret=$?
+    if [ $ret != 0 ] ; then
+	echo "$out"
+	echo "failed - should get NT_STATUS_ACCESS_DENIED listing \\widelinks_share\\source"
+	false
+    fi
+}
 
 LOGDIR_PREFIX=test_smbclient_s3
 
@@ -1095,6 +1151,10 @@ testit "creating a :stream at root of share" \
     test_toplevel_stream || \
     failed=`expr $failed + 1`
 
+testit "Ensure widelinks are restricted" \
+    test_widelinks || \
+    failed=`expr $failed + 1`
+
 testit "rm -rf $LOGDIR" \
     rm -rf $LOGDIR || \
     failed=`expr $failed + 1`
diff --git a/source3/script/tests/test_smbclient_tarmode.pl b/source3/script/tests/test_smbclient_tarmode.pl
index 663f02f..29cea99 100755
--- a/source3/script/tests/test_smbclient_tarmode.pl
+++ b/source3/script/tests/test_smbclient_tarmode.pl
@@ -1063,8 +1063,12 @@ sub check_tar {
     my $i = Archive::Tar->iter($tar, 1, {md5 => 1});
     while (my $f = $i->()) {
         if ($f->has_content) {
-            $total++;
             my $p = $f->full_path;
+
+	    # we skip pseudo files of Pax format archives
+            next if ($p =~ m/\/PaxHeader/);
+
+            $total++;
             $p =~ s{^\./+}{};
 
             # file that shouldn't be there
diff --git a/source3/script/tests/test_smbget.sh b/source3/script/tests/test_smbget.sh
new file mode 100755
index 0000000..f21a131
--- /dev/null
+++ b/source3/script/tests/test_smbget.sh
@@ -0,0 +1,236 @@
+#!/bin/bash
+#
+# Blackbox test for smbget.
+#
+
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: test_smbget SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBGET
+EOF
+exit 1;
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+WORKDIR=${6}
+SMBGET="$VALGRIND ${7}"
+
+TMPDIR="$SRCDIR_ABS/st/tmp"
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+create_test_data()
+{
+	pushd $WORKDIR
+	dd if=/dev/urandom bs=1024 count=128 of=testfile
+	chmod 644 testfile
+	mkdir dir1
+	dd if=/dev/urandom bs=1024 count=128 of=dir1/testfile1
+	mkdir dir2
+	dd if=/dev/urandom bs=1024 count=128 of=dir2/testfile2
+	popd
+}
+
+remove_test_data()
+{
+	rm -rf dir1 dir2 testfile
+	pushd $WORKDIR
+	rm -rf dir1 dir2 testfile
+	popd
+}
+
+test_singlefile_guest()
+{
+	[ -e testfile ] && rm testfile
+	echo "$SMBGET -v -a smb://$SERVER_IP/smbget/testfile"
+	$SMBGET -v -a smb://$SERVER_IP/smbget/testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: RC does not match, expected: 0'
+		return 1
+	fi
+	cmp --silent $WORKDIR/testfile ./testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: file content does not match'
+		return 1
+	fi
+	return 0
+}
+
+test_singlefile_U()
+{
+	[ -e testfile ] && rm testfile
+	$SMBGET -v -U$USERNAME%$PASSWORD smb://$SERVER_IP/smbget/testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: RC does not match, expected: 0'
+		return 1
+	fi
+	cmp --silent $WORKDIR/testfile ./testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: file content does not match'
+		return 1
+	fi
+	return 0
+}
+
+test_singlefile_smburl()
+{
+	[ -e testfile ] && rm testfile
+	$SMBGET -w $DOMAIN smb://$USERNAME:$PASSWORD@$SERVER_IP/smbget/testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: RC does not match, expected: 0'
+		return 1
+	fi
+	cmp --silent $WORKDIR/testfile ./testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: file content does not match'
+		return 1
+	fi
+	return 0
+}
+
+test_singlefile_rcfile()
+{
+	[ -e testfile ] && rm testfile
+	echo "user $USERNAME%$PASSWORD" > $TMPDIR/rcfile
+	$SMBGET -vn -f $TMPDIR/rcfile smb://$SERVER_IP/smbget/testfile
+	rc=$?
+	rm -f $TMPDIR/rcfile
+	if [ $rc -ne 0 ]; then
+		echo 'ERROR: RC does not match, expected: 0'
+		return 1
+	fi
+	cmp --silent $WORKDIR/testfile ./testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: file content does not match'
+		return 1
+	fi
+	return 0
+}
+
+test_recursive_U()
+{
+	[ -e testfile ] && rm testfile
+	[ -d dir1 ] && rm -rf dir1
+	[ -d dir2 ] && rm -rf dir2
+	$SMBGET -v -R -U$USERNAME%$PASSWORD smb://$SERVER_IP/smbget/
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: RC does not match, expected: 0'
+		return 1
+	fi
+
+	cmp --silent $WORKDIR/testfile ./testfile && \
+	cmp --silent $WORKDIR/dir1/testfile1 ./dir1/testfile1 && \
+	cmp --silent $WORKDIR/dir2/testfile2 ./dir2/testfile2
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: file content does not match'
+		return 1
+	fi
+
+	return 0
+}
+
+test_resume()
+{
+	[ -e testfile ] && rm testfile
+	cp $WORKDIR/testfile .
+	truncate -s 1024 testfile
+	$SMBGET -v -r -U$USERNAME%$PASSWORD smb://$SERVER_IP/smbget/testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: RC does not match, expected: 0'
+		return 1
+	fi
+
+	cmp --silent $WORKDIR/testfile ./testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: file content does not match'
+		return 1
+	fi
+
+	return 0
+}
+
+test_resume_modified()
+{
+	dd if=/dev/urandom bs=1024 count=2 of=testfile
+	$SMBGET -v -r -U$USERNAME%$PASSWORD smb://$SERVER_IP/smbget/testfile
+	if [ $? -ne 1 ]; then
+		echo 'ERROR: RC does not match, expected: 1'
+		return 1
+	fi
+
+	return 0
+}
+
+test_update()
+{
+	[ -e testfile ] && rm testfile
+	$SMBGET -v -U$USERNAME%$PASSWORD smb://$SERVER_IP/smbget/testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: RC does not match, expected: 0'
+		return 1
+	fi
+
+	# secondary download should pass
+	$SMBGET -v -u -U$USERNAME%$PASSWORD smb://$SERVER_IP/smbget/testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: RC does not match, expected: 0'
+		return 1
+	fi
+
+	echo "modified" >> testfile
+	# touch source to trigger new download
+	sleep 2
+	touch -m $WORKDIR/testfile
+	$SMBGET -v -u -U$USERNAME%$PASSWORD smb://$SERVER_IP/smbget/testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: RC does not match, expected: 0'
+		return 1
+	fi
+
+	cmp --silent $WORKDIR/testfile ./testfile
+	if [ $? -ne 0 ]; then
+		echo 'ERROR: file content does not match'
+		return 1
+	fi
+
+	return 0
+}
+
+create_test_data
+
+pushd $TMPDIR
+
+failed=0
+testit "download single file as guest" test_singlefile_guest \
+	|| failed=`expr $failed + 1`
+
+testit "download single file with -U" test_singlefile_U \
+	|| failed=`expr $failed + 1`
+
+testit "download single file with smb URL" test_singlefile_smburl \
+	|| failed=`expr $failed + 1`
+
+testit "download single file with rcfile" test_singlefile_rcfile \
+	|| failed=`expr $failed + 1`
+
+testit "recursive download" test_recursive_U \
+	|| failed=`expr $failed + 1`
+
+testit "resume download" test_resume \
+	|| failed=`expr $failed + 1`
+
+testit "resume download (modified file)" test_resume_modified \
+	|| failed=`expr $failed + 1`
+
+testit "update" test_update \
+	|| failed=`expr $failed + 1`
+
+popd
+
+remove_test_data
+
+exit $failed
diff --git a/source3/script/tests/test_valid_users.sh b/source3/script/tests/test_valid_users.sh
new file mode 100755
index 0000000..a7f9333
--- /dev/null
+++ b/source3/script/tests/test_valid_users.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# Blackbox test for valid users.
+#
+
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: valid_users SERVER SERVER_IP DOMAIN USERNAME PASSWORD PREFIX SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+PREFIX=${6}
+SMBCLIENT=${7}
+shift 7
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$*"
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+# Test listing a share with valid users succeeds
+test_valid_users_access()
+{
+    tmpfile=$PREFIX/smbclient.in.$$
+    prompt="foo"
+    cat > $tmpfile <<EOF
+ls
+quit
+EOF
+
+    cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$1" -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+    eval echo "$cmd"
+    out=`eval $cmd`
+    ret=$?
+    rm -f $tmpfile
+
+    if [ $ret != 0 ] ; then
+        echo "$out"
+        echo "failed accessing share with valid users with error $ret"
+
+        false
+        return
+    fi
+
+    echo "$out" | grep "$prompt" >/dev/null 2>&1
+
+    ret=$?
+    if [ $ret = 0 ] ; then
+        # got the correct prompt .. succeed
+        true
+    else
+        echo "$out"
+        echo "failed listing share with valid users"
+        false
+    fi
+}
+
+testit "accessing a valid users share succeeds" \
+   test_valid_users_access valid-users-access || \
+   failed=`expr $failed + 1`
+
+exit $failed
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 79db4b5..71b4e21 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -177,7 +177,12 @@ for env in ["nt4_dc"]:
 for env in ["fileserver"]:
     plantestsuite("samba3.blackbox.preserve_case (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_preserve_case.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3])
     plantestsuite("samba3.blackbox.dfree_command (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_dfree_command.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3])
+    plantestsuite("samba3.blackbox.dfree_quota (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_dfree_quota.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', smbclient3, smbcquotas])
+    plantestsuite("samba3.blackbox.valid_users (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_valid_users.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3])
+    plantestsuite("samba3.blackbox.offline (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_offline.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/offline', smbclient3])
     plantestsuite("samba3.blackbox.shadow_copy2 (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3])
+    plantestsuite("samba3.blackbox.smbclient.forceuser_validusers (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_forceuser_validusers.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', smbclient3])
+    plantestsuite("samba3.blackbox.smbget (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbget.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', 'smbget_user', '$PASSWORD', '$LOCAL_PATH/smbget', smbget])
 
     #
     # tar command tests
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index 253782b..32a1ce0 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -26,6 +26,27 @@
 #include "lib/tevent_wait.h"
 
 /****************************************************************************
+ Statics plus accessor functions.
+*****************************************************************************/
+
+static int outstanding_aio_calls;
+
+int get_outstanding_aio_calls(void)
+{
+	return outstanding_aio_calls;
+}
+
+void increment_outstanding_aio_calls(void)
+{
+	outstanding_aio_calls++;
+}
+
+void decrement_outstanding_aio_calls(void)
+{
+	outstanding_aio_calls--;
+}
+
+/****************************************************************************
  The buffer we keep around whilst an aio request is in process.
 *****************************************************************************/
 
@@ -50,7 +71,7 @@ bool aio_write_through_requested(struct aio_extra *aio_ex)
 
 static int aio_extra_destructor(struct aio_extra *aio_ex)
 {
-	outstanding_aio_calls--;
+	decrement_outstanding_aio_calls();
 	return 0;
 }
 
@@ -82,7 +103,7 @@ static struct aio_extra *create_aio_extra(TALLOC_CTX *mem_ctx,
 	}
 	talloc_set_destructor(aio_ex, aio_extra_destructor);
 	aio_ex->fsp = fsp;
-	outstanding_aio_calls++;
+	increment_outstanding_aio_calls();
 	return aio_ex;
 }
 
@@ -186,13 +207,6 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
 		return NT_STATUS_RETRY;
 	}
 
-	if (outstanding_aio_calls >= aio_pending_size) {
-		DEBUG(10,("schedule_aio_read_and_X: Already have %d aio "
-			  "activities outstanding.\n",
-			  outstanding_aio_calls ));
-		return NT_STATUS_RETRY;
-	}
-
 	/* The following is safe from integer wrap as we've already checked
 	   smb_maxcnt is 128k or less. Wct is 12 for read replies */
 
@@ -452,19 +466,6 @@ NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
 		return NT_STATUS_RETRY;
 	}
 
-	if (outstanding_aio_calls >= aio_pending_size) {
-		DEBUG(3,("schedule_aio_write_and_X: Already have %d aio "
-			 "activities outstanding.\n",
-			  outstanding_aio_calls ));
-		DEBUG(10,("schedule_aio_write_and_X: failed to schedule "
-			  "aio_write for file %s, offset %.0f, len = %u "
-			  "(mid = %u)\n",
-			  fsp_str_dbg(fsp), (double)startpos,
-			  (unsigned int)numtowrite,
-			  (unsigned int)smbreq->mid ));
-		return NT_STATUS_RETRY;
-	}
-
 	bufsize = smb_size + 6*2;
 
 	if (!(aio_ex = create_aio_extra(NULL, fsp, bufsize))) {
@@ -538,7 +539,8 @@ NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
 		  "%s, offset %.0f, len = %u (mid = %u) "
 		  "outstanding_aio_calls = %d\n",
 		  fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite,
-		  (unsigned int)aio_ex->smbreq->mid, outstanding_aio_calls ));
+		  (unsigned int)aio_ex->smbreq->mid,
+		  get_outstanding_aio_calls() ));
 
 	return NT_STATUS_OK;
 }
@@ -711,13 +713,6 @@ NTSTATUS schedule_smb2_aio_read(connection_struct *conn,
 		return NT_STATUS_RETRY;
 	}
 
-	if (outstanding_aio_calls >= aio_pending_size) {
-		DEBUG(10,("smb2: Already have %d aio "
-			"activities outstanding.\n",
-			outstanding_aio_calls ));
-		return NT_STATUS_RETRY;
-	}
-
 	/* Create the out buffer. */
 	*preadbuf = data_blob_talloc(ctx, NULL, smb_maxcnt);
 	if (preadbuf->data == NULL) {
@@ -867,13 +862,6 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
 		return NT_STATUS_RETRY;
 	}
 
-	if (outstanding_aio_calls >= aio_pending_size) {
-		DEBUG(3,("smb2: Already have %d aio "
-			"activities outstanding.\n",
-			outstanding_aio_calls ));
-		return NT_STATUS_RETRY;
-	}
-
 	if (smbreq->unread_bytes) {
 		/* Can't do async with recvfile. */
 		return NT_STATUS_RETRY;
@@ -939,7 +927,7 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
 		(double)in_offset,
 		(unsigned int)in_data.length,
 		(unsigned int)aio_ex->smbreq->mid,
-		outstanding_aio_calls ));
+		get_outstanding_aio_calls() ));
 
 	return NT_STATUS_OK;
 }
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 4fd8e1d..1e3a596 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -238,7 +238,7 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
 	SMB_PERFCOUNT_DEFER_OP(&req->pcd, &req->pcd);
 	blr->req = talloc_move(blr, &req);
 
-	DLIST_ADD_END(sconn->smb1.locks.blocking_lock_queue, blr, struct blocking_lock_record *);
+	DLIST_ADD_END(sconn->smb1.locks.blocking_lock_queue, blr);
 	recalc_brl_timeout(sconn);
 
 	/* Ensure we'll receive messages when this is unlocked. */
diff --git a/source3/smbd/dfree.c b/source3/smbd/dfree.c
index 0c38837..765fbe6 100644
--- a/source3/smbd/dfree.c
+++ b/source3/smbd/dfree.c
@@ -25,7 +25,7 @@
  Normalise for DOS usage.
 ****************************************************************************/
 
-void disk_norm(uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
+static void disk_norm(uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
 	/* check if the disk is beyond the max disk size */
 	uint64_t maxdisksize = lp_max_disk_size();
@@ -116,13 +116,14 @@ uint64_t sys_disk_free(connection_struct *conn, const char *path,
 			   syscmd, strerror(errno) ));
 	}
 
-	if (sys_fsusage(path, dfree, dsize) != 0) {
-		DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n",
-			strerror(errno) ));
+	if (SMB_VFS_DISK_FREE(conn, path, bsize, dfree, dsize) ==
+	    (uint64_t)-1) {
+		DBG_ERR("VFS disk_free failed. Error was : %s\n",
+			strerror(errno));
 		return (uint64_t)-1;
 	}
 
-	if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
+	if (disk_quotas(conn, path, &bsize_q, &dfree_q, &dsize_q)) {
 		uint64_t min_bsize = MIN(*bsize, bsize_q);
 
 		(*dfree) = (*dfree) * (*bsize) / min_bsize;
@@ -177,7 +178,7 @@ uint64_t get_dfree_info(connection_struct *conn,
 	uint64_t dfree_ret;
 
 	if (!dfree_cache_time) {
-		return SMB_VFS_DISK_FREE(conn, path, bsize, dfree, dsize);
+		return sys_disk_free(conn, path, bsize, dfree, dsize);
 	}
 
 	if (dfc && (conn->lastused - dfc->last_dfree_time < dfree_cache_time)) {
@@ -188,7 +189,7 @@ uint64_t get_dfree_info(connection_struct *conn,
 		return dfc->dfree_ret;
 	}
 
-	dfree_ret = SMB_VFS_DISK_FREE(conn, path, bsize, dfree, dsize);
+	dfree_ret = sys_disk_free(conn, path, bsize, dfree, dsize);
 
 	if (dfree_ret == (uint64_t)-1) {
 		/* Don't cache bad data. */
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index 99bfed3..3805915 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -485,7 +485,7 @@ NTSTATUS dptr_create(connection_struct *conn,
 		if (smb_dname == NULL) {
 			return NT_STATUS_NO_MEMORY;
 		}
-		if (lp_posix_pathnames()) {
+		if (req != NULL && req->posix_pathnames) {
 			ret = SMB_VFS_LSTAT(conn, smb_dname);
 		} else {
 			ret = SMB_VFS_STAT(conn, smb_dname);
@@ -545,7 +545,8 @@ NTSTATUS dptr_create(connection_struct *conn,
 		TALLOC_FREE(dir_hnd);
 		return NT_STATUS_NO_MEMORY;
 	}
-	if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
+	if ((req != NULL && req->posix_pathnames) ||
+			(wcard[0] == '.' && wcard[1] == 0)) {
 		dptr->has_wild = True;
 	} else {
 		dptr->has_wild = wcard_has_wild;
@@ -1523,9 +1524,8 @@ bool is_visible_file(connection_struct *conn, const char *dir_path,
 			if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
 				ret = true;
 				goto out;
-			} else {
-				*pst = smb_fname_base->st;
 			}
+			*pst = smb_fname_base->st;
 		}
 
 		/* Honour _hide unreadable_ option */
@@ -1944,7 +1944,6 @@ static int files_below_forall(connection_struct *conn,
 					  &state.dirpath, &to_free);
 	if (state.dirpath_len == -1) {
 		return -1;
-
 	}
 
 	ret = share_mode_forall(files_below_forall_fn, &state);
@@ -1965,7 +1964,7 @@ static int have_file_open_below_fn(struct file_id fid,
 	return 1;
 }
 
-static bool have_file_open_below(connection_struct *conn,
+bool have_file_open_below(connection_struct *conn,
 				 const struct smb_filename *name)
 {
 	struct have_file_open_below_state state = {
@@ -2037,7 +2036,7 @@ NTSTATUS can_delete_directory_fsp(files_struct *fsp)
 		return status;
 	}
 
-	if (!lp_posix_pathnames() &&
+	if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
 	    lp_strict_rename(SNUM(conn)) &&
 	    have_file_open_below(fsp->conn, fsp->fsp_name))
 	{
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 907f3f9..ecc211c 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -31,36 +31,43 @@ static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
 				files_struct **ret_fsp,
 				bool *need_close);
 
-static void dos_mode_debug_print(uint32_t mode)
+static void dos_mode_debug_print(const char *func, uint32_t mode)
 {
-	DEBUG(8,("dos_mode returning "));
+	fstring modestr;
+
+	if (DEBUGLEVEL < DBGLVL_INFO) {
+		return;
+	}
+
+	modestr[0] = '\0';
 
 	if (mode & FILE_ATTRIBUTE_HIDDEN) {
-		DEBUG(8, ("h"));
+		fstrcat(modestr, "h");
 	}
 	if (mode & FILE_ATTRIBUTE_READONLY) {
-		DEBUG(8, ("r"));
+		fstrcat(modestr, "r");
 	}
 	if (mode & FILE_ATTRIBUTE_SYSTEM) {
-		DEBUG(8, ("s"));
+		fstrcat(modestr, "s");
 	}
 	if (mode & FILE_ATTRIBUTE_DIRECTORY) {
-		DEBUG(8, ("d"));
+		fstrcat(modestr, "d");
 	}
 	if (mode & FILE_ATTRIBUTE_ARCHIVE) {
-		DEBUG(8, ("a"));
+		fstrcat(modestr, "a");
 	}
 	if (mode & FILE_ATTRIBUTE_SPARSE) {
-		DEBUG(8, ("[sparse]"));
+		fstrcat(modestr, "[sparse]");
 	}
 	if (mode & FILE_ATTRIBUTE_OFFLINE) {
-		DEBUG(8, ("[offline]"));
+		fstrcat(modestr, "[offline]");
 	}
 	if (mode & FILE_ATTRIBUTE_COMPRESSED) {
-		DEBUG(8, ("[compressed]"));
+		fstrcat(modestr, "[compressed]");
 	}
 
-	DEBUG(8,("\n"));
+	DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
+		 modestr);
 }
 
 static uint32_t filter_mode_by_protocol(uint32_t mode)
@@ -240,15 +247,8 @@ static uint32_t dos_mode_from_sbuf(connection_struct *conn,
 
 	result |= set_link_read_only_flag(&smb_fname->st);
 
-	DEBUG(8,("dos_mode_from_sbuf returning "));
-
-	if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
-	if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
-	if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
-	if (result & FILE_ATTRIBUTE_DIRECTORY   ) DEBUG(8, ("d"));
-	if (result & FILE_ATTRIBUTE_ARCHIVE  ) DEBUG(8, ("a"));
+	dos_mode_debug_print(__func__, result);
 
-	DEBUG(8,("\n"));
 	return result;
 }
 
@@ -279,7 +279,7 @@ static bool get_ea_dos_attribute(connection_struct *conn,
 				   SAMBA_XATTR_DOS_ATTRIB, attrstr,
 				   sizeof(attrstr));
 	if (sizeret == -1) {
-		DBG_INFO("get_ea_dos_attribute: Cannot get attribute "
+		DBG_INFO("Cannot get attribute "
 			 "from EA on file %s: Error = %s\n",
 			 smb_fname_str_dbg(smb_fname), strerror(errno));
 		return False;
@@ -358,15 +358,7 @@ static bool get_ea_dos_attribute(connection_struct *conn,
 	/* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
 	*pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
 
-	DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
-
-	if (dosattr & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
-	if (dosattr & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
-	if (dosattr & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
-	if (dosattr & FILE_ATTRIBUTE_DIRECTORY   ) DEBUG(8, ("d"));
-	if (dosattr & FILE_ATTRIBUTE_ARCHIVE  ) DEBUG(8, ("a"));
-
-	DEBUG(8,("\n"));
+	dos_mode_debug_print(__func__, *pattr);
 
 	return True;
 }
@@ -421,7 +413,7 @@ static bool set_ea_dos_attribute(connection_struct *conn,
 		files_struct *fsp = NULL;
 
 		if((errno != EPERM) && (errno != EACCES)) {
-			DBG_INFO("set_ea_dos_attributes: Cannot set "
+			DBG_INFO("Cannot set "
 				 "attribute EA on file %s: Error = %s\n",
 				 smb_fname_str_dbg(smb_fname), strerror(errno));
 			return false;
@@ -521,16 +513,7 @@ uint32_t dos_mode_msdfs(connection_struct *conn,
 	 */
 	result |= FILE_ATTRIBUTE_REPARSE_POINT;
 
-	DEBUG(8,("dos_mode_msdfs returning "));
-
-	if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
-	if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
-	if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
-	if (result & FILE_ATTRIBUTE_DIRECTORY   ) DEBUG(8, ("d"));
-	if (result & FILE_ATTRIBUTE_ARCHIVE  ) DEBUG(8, ("a"));
-	if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
-
-	DEBUG(8,("\n"));
+	dos_mode_debug_print(__func__, result);
 
 	return(result);
 }
@@ -635,7 +618,7 @@ uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
 
 	result = filter_mode_by_protocol(result);
 
-	dos_mode_debug_print(result);
+	dos_mode_debug_print(__func__, result);
 
 	return result;
 }
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 555658d..f2c9184 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -55,9 +55,11 @@ static bool mangled_equal(const char *name1,
 ****************************************************************************/
 
 static NTSTATUS determine_path_error(const char *name,
-			bool allow_wcard_last_component)
+			bool allow_wcard_last_component,
+			bool posix_pathnames)
 {
 	const char *p;
+	bool name_has_wild = false;
 
 	if (!allow_wcard_last_component) {
 		/* Error code within a pathname. */
@@ -74,7 +76,11 @@ static NTSTATUS determine_path_error(const char *name,
 
 	p = strchr(name, '/');
 
-	if (!p && (ms_has_wild(name) || ISDOT(name))) {
+	if (!posix_pathnames) {
+		name_has_wild = ms_has_wild(name);
+	}
+
+	if (!p && (name_has_wild || ISDOT(name))) {
 		/* Error code at the end of a pathname. */
 		return NT_STATUS_OBJECT_NAME_INVALID;
 	} else {
@@ -122,6 +128,7 @@ static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
 	const char *last_component = NULL;
 	NTSTATUS status;
 	int ret;
+	bool parent_fname_has_wild = false;
 
 	ZERO_STRUCT(parent_fname);
 	if (!parent_dirname(ctx, smb_fname->base_name,
@@ -130,6 +137,10 @@ static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	if (!posix_pathnames) {
+		parent_fname_has_wild = ms_has_wild(parent_fname.base_name);
+	}
+
 	/*
 	 * If there was no parent component in
 	 * smb_fname->base_name of the parent name
@@ -137,7 +148,7 @@ static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
 	 * optimization.
 	 */
 	if ((smb_fname->base_name == last_component) ||
-			ms_has_wild(parent_fname.base_name)) {
+			parent_fname_has_wild) {
 		return NT_STATUS_OK;
 	}
 
@@ -224,12 +235,20 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 		      uint32_t ucf_flags)
 {
 	struct smb_filename *smb_fname = NULL;
-	char *start, *end;
+
+	/*
+	 * This looks strange. But we need "start" initialized to "" here but
+	 * it can't be a const char *, so 'char *start = "";' does not work.
+	 */
+	char cnull = '\0';
+	char *start = &cnull;
+
+	char *end;
 	char *dirpath = NULL;
 	char *stream = NULL;
 	bool component_was_mangled = False;
 	bool name_has_wildcard = False;
-	bool posix_pathnames = false;
+	bool posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES);
 	bool allow_wcard_last_component =
 	    (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
 	bool save_last_component = ucf_flags & UCF_SAVE_LCOMP;
@@ -299,7 +318,8 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 			status = NT_STATUS_OBJECT_NAME_INVALID;
 		} else {
 			status =determine_path_error(&orig_path[2],
-			    allow_wcard_last_component);
+			    allow_wcard_last_component,
+			    posix_pathnames);
 		}
 		goto err;
 	}
@@ -348,9 +368,6 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 		}
 	}
 
-	posix_pathnames = (lp_posix_pathnames() ||
-				(ucf_flags & UCF_POSIX_PATHNAMES));
-
 	/*
 	 * Strip off the stream, and add it back when we're done with the
 	 * base_name.
@@ -438,11 +455,14 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 	 * is true.
 	 */
 
-	name_has_wildcard = ms_has_wild(smb_fname->base_name);
-	if (name_has_wildcard && !allow_wcard_last_component) {
-		/* Wildcard not valid anywhere. */
-		status = NT_STATUS_OBJECT_NAME_INVALID;
-		goto fail;
+	if (!posix_pathnames) {
+		/* POSIX pathnames have no wildcards. */
+		name_has_wildcard = ms_has_wild(smb_fname->base_name);
+		if (name_has_wildcard && !allow_wcard_last_component) {
+			/* Wildcard not valid anywhere. */
+			status = NT_STATUS_OBJECT_NAME_INVALID;
+			goto fail;
+		}
 	}
 
 	DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
@@ -628,7 +648,8 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 				status = NT_STATUS_OBJECT_NAME_INVALID;
 			} else {
 				status = determine_path_error(end+1,
-						allow_wcard_last_component);
+						allow_wcard_last_component,
+						posix_pathnames);
 			}
 			goto fail;
 		}
@@ -636,7 +657,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 		/* The name cannot have a wildcard if it's not
 		   the last component. */
 
-		name_has_wildcard = ms_has_wild(start);
+		if (!posix_pathnames) {
+			name_has_wildcard = ms_has_wild(start);
+		}
 
 		/* Wildcards never valid within a pathname. */
 		if (name_has_wildcard && end) {
diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c
index a501234..70805a1 100644
--- a/source3/smbd/globals.c
+++ b/source3/smbd/globals.c
@@ -24,9 +24,6 @@
 #include "messages.h"
 #include <tdb.h>
 
-int aio_pending_size = 100;	/* tevent supports 100 signals SA_SIGINFO */
-int outstanding_aio_calls = 0;
-
 #ifdef USE_DMAPI
 struct smbd_dmapi_context *dmapi_ctx = NULL;
 #endif
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 35a3ee9..c843f5a 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -22,9 +22,6 @@
 #include "librpc/gen_ndr/smbXsrv.h"
 #include "smbprofile.h"
 
-extern int aio_pending_size;
-extern int outstanding_aio_calls;
-
 #ifdef USE_DMAPI
 struct smbd_dmapi_context;
 extern struct smbd_dmapi_context *dmapi_ctx;
@@ -226,8 +223,9 @@ NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
 
 void reply_smb2002(struct smb_request *req, uint16_t choice);
 void reply_smb20ff(struct smb_request *req, uint16_t choice);
-void smbd_smb2_first_negprot(struct smbXsrv_connection *xconn,
-			     const uint8_t *inpdu, size_t size);
+void smbd_smb2_process_negprot(struct smbXsrv_connection *xconn,
+			       uint64_t expected_seq_low,
+			       const uint8_t *inpdu, size_t size);
 
 DATA_BLOB smbd_smb2_generate_outbody(struct smbd_smb2_request *req, size_t size);
 
@@ -503,6 +501,7 @@ struct smbXsrv_connection {
 		struct {
 			uint32_t capabilities;
 			struct GUID guid;
+			bool guid_verified;
 			uint16_t security_mode;
 			uint16_t num_dialects;
 			uint16_t *dialects;
@@ -529,6 +528,22 @@ const char *smbXsrv_connection_dbg(const struct smbXsrv_connection *xconn);
 NTSTATUS smbXsrv_version_global_init(const struct server_id *server_id);
 uint32_t smbXsrv_version_global_current(void);
 
+struct smbXsrv_client_table;
+NTSTATUS smbXsrv_client_global_init(void);
+NTSTATUS smbXsrv_client_create(TALLOC_CTX *mem_ctx,
+			       struct tevent_context *ev_ctx,
+			       struct messaging_context *msg_ctx,
+			       NTTIME now,
+			       struct smbXsrv_client **_client);
+NTSTATUS smbXsrv_client_update(struct smbXsrv_client *client);
+NTSTATUS smbXsrv_client_remove(struct smbXsrv_client *client);
+NTSTATUS smb2srv_client_lookup_global(struct smbXsrv_client *client,
+				      struct GUID client_guid,
+				      TALLOC_CTX *mem_ctx,
+				      struct smbXsrv_client_global0 **_pass);
+NTSTATUS smb2srv_client_connection_pass(struct smbd_smb2_request *smb2req,
+					struct smbXsrv_client_global0 *global);
+
 NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn,
 					enum protocol_types protocol);
 
@@ -536,11 +551,24 @@ NTSTATUS smbXsrv_session_global_init(void);
 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
 				NTTIME now,
 				struct smbXsrv_session **_session);
+NTSTATUS smbXsrv_session_add_channel(struct smbXsrv_session *session,
+				     struct smbXsrv_connection *conn,
+				     struct smbXsrv_channel_global0 **_c);
 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session);
 struct smbXsrv_channel_global0;
 NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session,
 				      const struct smbXsrv_connection *conn,
 				      struct smbXsrv_channel_global0 **_c);
+NTSTATUS smbXsrv_session_find_auth(const struct smbXsrv_session *session,
+				   const struct smbXsrv_connection *conn,
+				   NTTIME now,
+				   struct smbXsrv_session_auth0 **_a);
+NTSTATUS smbXsrv_session_create_auth(struct smbXsrv_session *session,
+				     struct smbXsrv_connection *conn,
+				     NTTIME now,
+				     uint8_t in_flags,
+				     uint8_t in_security_mode,
+				     struct smbXsrv_session_auth0 **_a);
 struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct smbXsrv_session *session,
@@ -553,9 +581,12 @@ NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
 				uint16_t vuid, NTTIME now,
 				struct smbXsrv_session **session);
 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn);
-NTSTATUS smb2srv_session_lookup(struct smbXsrv_connection *conn,
-				uint64_t session_id, NTTIME now,
-				struct smbXsrv_session **session);
+NTSTATUS smb2srv_session_lookup_conn(struct smbXsrv_connection *conn,
+				     uint64_t session_id, NTTIME now,
+				     struct smbXsrv_session **session);
+NTSTATUS smb2srv_session_lookup_client(struct smbXsrv_client *client,
+				       uint64_t session_id, NTTIME now,
+				       struct smbXsrv_session **session);
 struct smbXsrv_session_global0;
 NTSTATUS smbXsrv_session_global_traverse(
 			int (*fn)(struct smbXsrv_session_global0 *, void *),
@@ -610,6 +641,10 @@ NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn,
 			     uint64_t volatile_id,
 			     NTTIME now,
 			     struct smbXsrv_open **_open);
+NTSTATUS smb2srv_open_lookup_replay_cache(struct smbXsrv_connection *conn,
+					  const struct GUID *create_guid,
+					  NTTIME now,
+					  struct smbXsrv_open **_open);
 NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
 			       struct auth_session_info *session_info,
 			       uint64_t persistent_id,
@@ -622,6 +657,11 @@ NTSTATUS smbXsrv_open_global_traverse(
 	void *private_data);
 
 NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id);
+bool smbXsrv_is_encrypted(uint8_t encryption_flags);
+bool smbXsrv_is_partially_encrypted(uint8_t encryption_flags);
+bool smbXsrv_set_crypto_flag(uint8_t *flags, uint8_t flag);
+bool smbXsrv_is_signed(uint8_t signing_flags);
+bool smbXsrv_is_partially_signed(uint8_t signing_flags);
 
 struct smbd_smb2_send_queue {
 	struct smbd_smb2_send_queue *prev, *next;
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index fe942c1..7590421 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -21,7 +21,6 @@
 #include "includes.h"
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
-#include "../libcli/auth/spnego.h"
 #include "serverid.h"
 #include "auth.h"
 #include "messages.h"
@@ -443,41 +442,67 @@ protocol [XENIX CORE]
 protocol [LANMAN1.0]
 protocol [LM1.2X002]
 protocol [LANMAN2.1]
+
+OSX:
+protocol [NT LM 0.12]
+protocol [SMB 2.002]
+protocol [SMB 2.???]
 */
 
 /*
   * Modified to recognize the architecture of the remote machine better.
   *
   * This appears to be the matrix of which protocol is used by which
-  * MS product.
-       Protocol                       WfWg    Win95   WinNT  Win2K  OS/2 Vista
-       PC NETWORK PROGRAM 1.0          1       1       1      1      1     1
-       XENIX CORE                                      2             2
-       MICROSOFT NETWORKS 3.0          2       2       
-       DOS LM1.2X002                   3       3       
-       MICROSOFT NETWORKS 1.03                         3
-       DOS LANMAN2.1                   4       4       
-       LANMAN1.0                                       4      2      3     2
-       Windows for Workgroups 3.1a     5       5       5      3            3
-       LM1.2X002                                       6      4      4     4
-       LANMAN2.1                                       7      5      5     5
-       NT LM 0.12                              6       8      6            6
-       SMB 2.001                                                           7
+  * product.
+       Protocol                       WfWg Win95 WinNT Win2K OS/2 Vista OSX
+       PC NETWORK PROGRAM 1.0          1     1     1     1     1    1
+       XENIX CORE                                  2           2
+       MICROSOFT NETWORKS 3.0          2     2
+       DOS LM1.2X002                   3     3
+       MICROSOFT NETWORKS 1.03                     3
+       DOS LANMAN2.1                   4     4
+       LANMAN1.0                                   4     2     3    2
+       Windows for Workgroups 3.1a     5     5     5     3          3
+       LM1.2X002                                   6     4     4    4
+       LANMAN2.1                                   7     5     5    5
+       NT LM 0.12                            6     8     6     6    6    1
+       SMB 2.001                                                    7
+       SMB 2.002                                                         2
+       SMB 2.???                                                         3
   *
   *  tim at fsg.com 09/29/95
   *  Win2K added by matty 17/7/99
   */
 
-#define ARCH_WFWG     0x3      /* This is a fudge because WfWg is like Win95 */
-#define ARCH_WIN95    0x2
-#define ARCH_WINNT    0x4
-#define ARCH_WIN2K    0xC      /* Win2K is like NT */
-#define ARCH_OS2      0x14     /* Again OS/2 is like NT */
-#define ARCH_SAMBA    0x20
-#define ARCH_CIFSFS   0x40
-#define ARCH_VISTA    0x8C     /* Vista is like XP/2K */
-
-#define ARCH_ALL      0x7F
+#define PROT_PC_NETWORK_PROGRAM_1_0		0x0001
+#define PROT_XENIX_CORE				0x0002
+#define PROT_MICROSOFT_NETWORKS_3_0		0x0004
+#define PROT_DOS_LM1_2X002			0x0008
+#define PROT_MICROSOFT_NETWORKS_1_03		0x0010
+#define PROT_DOS_LANMAN2_1			0x0020
+#define PROT_LANMAN1_0				0x0040
+#define PROT_WFWG				0x0080
+#define PROT_LM1_2X002				0x0100
+#define PROT_LANMAN2_1				0x0200
+#define PROT_NT_LM_0_12				0x0400
+#define PROT_SMB_2_001				0x0800
+#define PROT_SMB_2_002				0x1000
+#define PROT_SMB_2_FF				0x2000
+#define PROT_SAMBA				0x4000
+#define PROT_POSIX_2				0x8000
+
+#define ARCH_WFWG     ( PROT_PC_NETWORK_PROGRAM_1_0 | PROT_MICROSOFT_NETWORKS_3_0 | \
+			PROT_DOS_LM1_2X002 | PROT_DOS_LANMAN2_1 | PROT_WFWG )
+#define ARCH_WIN95    ( ARCH_WFWG | PROT_NT_LM_0_12 )
+#define ARCH_WINNT    ( PROT_PC_NETWORK_PROGRAM_1_0 | PROT_XENIX_CORE | \
+			PROT_MICROSOFT_NETWORKS_1_03 | PROT_LANMAN1_0 | PROT_WFWG | \
+			PROT_LM1_2X002 | PROT_LANMAN2_1 | PROT_NT_LM_0_12 )
+#define ARCH_WIN2K    ( ARCH_WINNT & ~(PROT_XENIX_CORE | PROT_MICROSOFT_NETWORKS_1_03) )
+#define ARCH_OS2      ( ARCH_WINNT & ~(PROT_MICROSOFT_NETWORKS_1_03 | PROT_WFWG) )
+#define ARCH_VISTA    ( ARCH_WIN2K | PROT_SMB_2_001 )
+#define ARCH_SAMBA    ( PROT_SAMBA )
+#define ARCH_CIFSFS   ( PROT_POSIX_2 )
+#define ARCH_OSX      ( PROT_NT_LM_0_12 | PROT_SMB_2_002 | PROT_SMB_2_FF )
 
 /* List of supported protocols, most desired first */
 static const struct {
@@ -511,7 +536,7 @@ void reply_negprot(struct smb_request *req)
 	int chosen_level = -1;
 	int protocol;
 	const char *p;
-	int arch = ARCH_ALL;
+	int protocols = 0;
 	int num_cliprotos;
 	char **cliprotos;
 	int i;
@@ -579,41 +604,46 @@ void reply_negprot(struct smb_request *req)
 	}
 
 	for (i=0; i<num_cliprotos; i++) {
-		if (strcsequal(cliprotos[i], "Windows for Workgroups 3.1a"))
-			arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT
-				  | ARCH_WIN2K );
-		else if (strcsequal(cliprotos[i], "DOS LM1.2X002"))
-			arch &= ( ARCH_WFWG | ARCH_WIN95 );
-		else if (strcsequal(cliprotos[i], "DOS LANMAN2.1"))
-			arch &= ( ARCH_WFWG | ARCH_WIN95 );
-		else if (strcsequal(cliprotos[i], "NT LM 0.12"))
-			arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K
-				  | ARCH_CIFSFS);
-		else if (strcsequal(cliprotos[i], "SMB 2.001"))
-			arch = ARCH_VISTA;		
-		else if (strcsequal(cliprotos[i], "LANMAN2.1"))
-			arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
-		else if (strcsequal(cliprotos[i], "LM1.2X002"))
-			arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
-		else if (strcsequal(cliprotos[i], "MICROSOFT NETWORKS 1.03"))
-			arch &= ARCH_WINNT;
-		else if (strcsequal(cliprotos[i], "XENIX CORE"))
-			arch &= ( ARCH_WINNT | ARCH_OS2 );
-		else if (strcsequal(cliprotos[i], "Samba")) {
-			arch = ARCH_SAMBA;
+		if (strcsequal(cliprotos[i], "Windows for Workgroups 3.1a")) {
+			protocols |= PROT_WFWG;
+		} else if (strcsequal(cliprotos[i], "DOS LM1.2X002")) {
+			protocols |= PROT_DOS_LM1_2X002;
+		} else if (strcsequal(cliprotos[i], "DOS LANMAN2.1")) {
+			protocols |= PROT_DOS_LANMAN2_1;
+		} else if (strcsequal(cliprotos[i], "LANMAN1.0")) {
+			protocols |= PROT_LANMAN1_0;
+		} else if (strcsequal(cliprotos[i], "NT LM 0.12")) {
+			protocols |= PROT_NT_LM_0_12;
+		} else if (strcsequal(cliprotos[i], "SMB 2.001")) {
+			protocols |= PROT_SMB_2_001;
+		} else if (strcsequal(cliprotos[i], "SMB 2.002")) {
+			protocols |= PROT_SMB_2_002;
+		} else if (strcsequal(cliprotos[i], "SMB 2.???")) {
+			protocols |= PROT_SMB_2_FF;
+		} else if (strcsequal(cliprotos[i], "LANMAN2.1")) {
+			protocols |= PROT_LANMAN2_1;
+		} else if (strcsequal(cliprotos[i], "LM1.2X002")) {
+			protocols |= PROT_LM1_2X002;
+		} else if (strcsequal(cliprotos[i], "MICROSOFT NETWORKS 1.03")) {
+			protocols |= PROT_MICROSOFT_NETWORKS_1_03;
+		} else if (strcsequal(cliprotos[i], "MICROSOFT NETWORKS 3.0")) {
+			protocols |= PROT_MICROSOFT_NETWORKS_3_0;
+		} else if (strcsequal(cliprotos[i], "PC NETWORK PROGRAM 1.0")) {
+			protocols |= PROT_PC_NETWORK_PROGRAM_1_0;
+		} else if (strcsequal(cliprotos[i], "XENIX CORE")) {
+			protocols |= PROT_XENIX_CORE;
+		} else if (strcsequal(cliprotos[i], "Samba")) {
+			protocols = PROT_SAMBA;
 			break;
 		} else if (strcsequal(cliprotos[i], "POSIX 2")) {
-			arch = ARCH_CIFSFS;
+			protocols = PROT_POSIX_2;
 			break;
 		}
 	}
 
-	/* CIFSFS can send one arch only, NT LM 0.12. */
-	if (i == 1 && (arch & ARCH_CIFSFS)) {
-		arch = ARCH_CIFSFS;
-	}
-
-	switch ( arch ) {
+	switch ( protocols ) {
+		/* Old CIFSFS can send one arch only, NT LM 0.12. */
+		case PROT_NT_LM_0_12:
 		case ARCH_CIFSFS:
 			set_remote_arch(RA_CIFSFS);
 			break;
@@ -627,16 +657,10 @@ void reply_negprot(struct smb_request *req)
 			set_remote_arch(RA_WIN95);
 			break;
 		case ARCH_WINNT:
-			if(req->flags2 == FLAGS2_WIN2K_SIGNATURE)
-				set_remote_arch(RA_WIN2K);
-			else
-				set_remote_arch(RA_WINNT);
+			set_remote_arch(RA_WINNT);
 			break;
 		case ARCH_WIN2K:
-			/* Vista may have been set in the negprot so don't 
-			   override it here */
-			if ( get_remote_arch() != RA_VISTA )
-				set_remote_arch(RA_WIN2K);
+			set_remote_arch(RA_WIN2K);
 			break;
 		case ARCH_VISTA:
 			set_remote_arch(RA_VISTA);
@@ -644,6 +668,9 @@ void reply_negprot(struct smb_request *req)
 		case ARCH_OS2:
 			set_remote_arch(RA_OS2);
 			break;
+		case ARCH_OSX:
+			set_remote_arch(RA_OSX);
+			break;
 		default:
 			set_remote_arch(RA_UNKNOWN);
 		break;
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 6257260..d7382db 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -327,8 +327,7 @@ NTSTATUS change_notify_add_request(struct smb_request *req,
 	request->reply_fn = reply_fn;
 	request->backend_data = NULL;
 
-	DLIST_ADD_END(fsp->notify->requests, request,
-		      struct notify_change_request *);
+	DLIST_ADD_END(fsp->notify->requests, request);
 
 	map->mid = request->req->mid;
 	DLIST_ADD(sconn->smb1.notify_mid_maps, map);
diff --git a/source3/smbd/notify_inotify.c b/source3/smbd/notify_inotify.c
index 8f47124..78fb654 100644
--- a/source3/smbd/notify_inotify.c
+++ b/source3/smbd/notify_inotify.c
@@ -24,7 +24,7 @@
 #include "includes.h"
 #include "../librpc/gen_ndr/notify.h"
 #include "smbd/smbd.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 
 #include <sys/inotify.h>
 
diff --git a/source3/smbd/notifyd/notifyd.c b/source3/smbd/notifyd/notifyd.c
index 3a9bc75..316cdea 100644
--- a/source3/smbd/notifyd/notifyd.c
+++ b/source3/smbd/notifyd/notifyd.c
@@ -33,11 +33,14 @@
 #include "ctdbd_conn.h"
 #include "ctdb_srvids.h"
 #include "source3/smbd/proto.h"
-#include "ctdb/include/ctdb_protocol.h"
 #include "server_id_db_util.h"
 #include "lib/util/iov_buf.h"
 #include "messages_util.h"
 
+#ifdef CLUSTER_SUPPORT
+#include "ctdb_protocol.h"
+#endif
+
 struct notifyd_peer;
 
 /*
@@ -130,12 +133,16 @@ static bool notifyd_get_db(struct messaging_context *msg_ctx,
 static bool notifyd_got_db(struct messaging_context *msg_ctx,
 			   struct messaging_rec **prec,
 			   void *private_data);
+
+#ifdef CLUSTER_SUPPORT
 static void notifyd_broadcast_reclog(struct ctdbd_connection *ctdbd_conn,
 				     struct server_id src,
 				     struct messaging_reclog *log);
+#endif
 static void notifyd_sys_callback(struct sys_notify_context *ctx,
 				 void *private_data, struct notify_event *ev);
 
+#ifdef CLUSTER_SUPPORT
 static struct tevent_req *notifyd_broadcast_reclog_send(
 	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 	struct ctdbd_connection *ctdbd_conn, struct server_id src,
@@ -146,6 +153,7 @@ static struct tevent_req *notifyd_clean_peers_send(
 	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 	struct notifyd_state *notifyd);
 static int notifyd_clean_peers_recv(struct tevent_req *req);
+#endif
 
 static int sys_notify_watch_dummy(
 	TALLOC_CTX *mem_ctx,
@@ -165,12 +173,15 @@ static int sys_notify_watch_dummy(
 }
 
 static void notifyd_handler_done(struct tevent_req *subreq);
+
+#ifdef CLUSTER_SUPPORT
 static void notifyd_broadcast_reclog_finished(struct tevent_req *subreq);
 static void notifyd_clean_peers_finished(struct tevent_req *subreq);
 static int notifyd_snoop_broadcast(uint32_t src_vnn, uint32_t dst_vnn,
 				   uint64_t dst_srvid,
 				   const uint8_t *msg, size_t msglen,
 				   void *private_data);
+#endif
 
 struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 				struct messaging_context *msg_ctx,
@@ -181,7 +192,6 @@ struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 	struct tevent_req *req, *subreq;
 	struct notifyd_state *state;
 	struct server_id_db *names_db;
-	NTSTATUS status;
 	int ret;
 
 	req = tevent_req_create(mem_ctx, &state, struct notifyd_state);
@@ -254,6 +264,7 @@ struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 		return req;
 	}
 
+#ifdef CLUSTER_SUPPORT
 	state->log = talloc_zero(state, struct messaging_reclog);
 	if (tevent_req_nomem(state->log, req)) {
 		return tevent_req_post(req, ev);
@@ -275,12 +286,13 @@ struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 	tevent_req_set_callback(subreq, notifyd_clean_peers_finished,
 				req);
 
-	status = register_with_ctdbd(ctdbd_conn, CTDB_SRVID_SAMBA_NOTIFY_PROXY,
-				     notifyd_snoop_broadcast, state);
-	if (!NT_STATUS_IS_OK(status)) {
-		tevent_req_error(req, map_errno_from_nt_status(status));
+	ret = register_with_ctdbd(ctdbd_conn, CTDB_SRVID_SAMBA_NOTIFY_PROXY,
+				  notifyd_snoop_broadcast, state);
+	if (ret != 0) {
+		tevent_req_error(req, ret);
 		return tevent_req_post(req, ev);
 	}
+#endif
 
 	return req;
 }
@@ -296,6 +308,8 @@ static void notifyd_handler_done(struct tevent_req *subreq)
 	tevent_req_error(req, ret);
 }
 
+#ifdef CLUSTER_SUPPORT
+
 static void notifyd_broadcast_reclog_finished(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
@@ -318,6 +332,8 @@ static void notifyd_clean_peers_finished(struct tevent_req *subreq)
 	tevent_req_error(req, ret);
 }
 
+#endif
+
 int notifyd_recv(struct tevent_req *req)
 {
 	return tevent_req_simple_recv_unix(req);
@@ -553,8 +569,6 @@ static bool notifyd_rec_change(struct messaging_context *msg_ctx,
 		private_data, struct notifyd_state);
 	struct server_id_buf idbuf;
 	struct messaging_rec *rec = *prec;
-	struct messaging_rec **tmp;
-	struct messaging_reclog *log;
 	struct notify_rec_change_msg *msg;
 	size_t pathlen;
 	bool ok;
@@ -582,6 +596,13 @@ static bool notifyd_rec_change(struct messaging_context *msg_ctx,
 	if ((state->log == NULL) || (state->ctdbd_conn == NULL)) {
 		return true;
 	}
+
+#ifdef CLUSTER_SUPPORT
+	{
+
+	struct messaging_rec **tmp;
+	struct messaging_reclog *log;
+
 	log = state->log;
 
 	tmp = talloc_realloc(log, log->recs, struct messaging_rec *,
@@ -603,6 +624,9 @@ static bool notifyd_rec_change(struct messaging_context *msg_ctx,
 					 messaging_server_id(msg_ctx), log);
 	}
 
+	}
+#endif
+
 	return true;
 }
 
@@ -792,7 +816,7 @@ static void notifyd_send_delete(struct messaging_context *msg_ctx,
 	};
 	uint8_t nul = 0;
 	struct iovec iov[3];
-	NTSTATUS status;
+	int ret;
 
 	/*
 	 * Send a rec_change to ourselves to delete a dead entry
@@ -804,13 +828,13 @@ static void notifyd_send_delete(struct messaging_context *msg_ctx,
 	iov[1] = (struct iovec) { .iov_base = key.dptr, .iov_len = key.dsize };
 	iov[2] = (struct iovec) { .iov_base = &nul, .iov_len = sizeof(nul) };
 
-	status = messaging_send_iov_from(
+	ret = messaging_send_iov_from(
 		msg_ctx, instance->client, messaging_server_id(msg_ctx),
 		MSG_SMB_NOTIFY_REC_CHANGE, iov, ARRAY_SIZE(iov), NULL, 0);
 
-	if (!NT_STATUS_IS_OK(status)) {
+	if (ret != 0) {
 		DEBUG(10, ("%s: messaging_send_iov_from returned %s\n",
-			   __func__, nt_errstr(status)));
+			   __func__, strerror(ret)));
 	}
 }
 
@@ -939,15 +963,17 @@ static bool notifyd_got_db(struct messaging_context *msg_ctx,
 	return true;
 }
 
+#ifdef CLUSTER_SUPPORT
+
 static void notifyd_broadcast_reclog(struct ctdbd_connection *ctdbd_conn,
 				     struct server_id src,
 				     struct messaging_reclog *log)
 {
-	NTSTATUS status;
 	enum ndr_err_code ndr_err;
 	uint8_t msghdr[MESSAGE_HDR_LENGTH];
 	DATA_BLOB blob;
 	struct iovec iov[2];
+	int ret;
 
 	if (log == NULL) {
 		return;
@@ -972,13 +998,13 @@ static void notifyd_broadcast_reclog(struct ctdbd_connection *ctdbd_conn,
 	iov[1] = (struct iovec) { .iov_base = blob.data,
 				  .iov_len = blob.length };
 
-	status = ctdbd_messaging_send_iov(
+	ret = ctdbd_messaging_send_iov(
 		ctdbd_conn, CTDB_BROADCAST_VNNMAP,
 		CTDB_SRVID_SAMBA_NOTIFY_PROXY, iov, ARRAY_SIZE(iov));
 	TALLOC_FREE(blob.data);
-	if (!NT_STATUS_IS_OK(status)) {
+	if (ret != 0) {
 		DEBUG(1, ("%s: ctdbd_messaging_send failed: %s\n",
-			  __func__, nt_errstr(status)));
+			  __func__, strerror(ret)));
 		goto done;
 	}
 
@@ -1140,6 +1166,8 @@ static int notifyd_clean_peers_recv(struct tevent_req *req)
 	return tevent_req_simple_recv_unix(req);
 }
 
+#endif
+
 static int notifyd_add_proxy_syswatches(struct db_record *rec,
 					void *private_data)
 {
@@ -1185,6 +1213,8 @@ static int notifyd_add_proxy_syswatches(struct db_record *rec,
 	return 0;
 }
 
+#ifdef CLUSTER_SUPPORT
+
 static int notifyd_db_del_syswatches(struct db_record *rec, void *private_data)
 {
 	TDB_DATA key = dbwrap_record_get_key(rec);
@@ -1419,6 +1449,7 @@ static int notifyd_snoop_broadcast(uint32_t src_vnn, uint32_t dst_vnn,
 
 	return 0;
 }
+#endif
 
 struct notifyd_parse_db_state {
 	bool (*fn)(const char *path,
diff --git a/source3/smbd/ntquotas.c b/source3/smbd/ntquotas.c
index 15fd35b..aa2ec3b 100644
--- a/source3/smbd/ntquotas.c
+++ b/source3/smbd/ntquotas.c
@@ -96,7 +96,7 @@ int vfs_get_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, struct dom_sid
 			 sid_string_dbg(psid)));
 	}
 
-	ret = SMB_VFS_GET_QUOTA(fsp->conn, qtype, id, &D);
+	ret = SMB_VFS_GET_QUOTA(fsp->conn, ".", qtype, id, &D);
 
 	if (psid)
 		qt->sid    = *psid;
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 9233738..32c54e7 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -461,6 +461,8 @@ void reply_ntcreate_and_X(struct smb_request *req)
 	int oplock_request;
 	uint8_t oplock_granted = NO_OPLOCK_RETURN;
 	struct case_semantics_state *case_state = NULL;
+	uint32_t ucf_flags = UCF_PREP_CREATEFILE |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBntcreateX);
@@ -538,7 +540,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				fname,
-				UCF_PREP_CREATEFILE,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 
@@ -760,9 +762,25 @@ static void do_nt_transact_create_pipe(connection_struct *conn,
 
 	flags = IVAL(params,0);
 
-	srvstr_get_path(ctx, params, req->flags2, &fname, params+53,
-			parameter_count-53, STR_TERMINATE,
+	if (req->posix_pathnames) {
+		srvstr_get_path_posix(ctx,
+			params,
+			req->flags2,
+			&fname,
+			params+53,
+			parameter_count-53,
+			STR_TERMINATE,
 			&status);
+	} else {
+		srvstr_get_path(ctx,
+			params,
+			req->flags2,
+			&fname,
+			params+53,
+			parameter_count-53,
+			STR_TERMINATE,
+			&status);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		reply_nterror(req, status);
 		return;
@@ -1006,6 +1024,8 @@ static void call_nt_transact_create(connection_struct *conn,
 	int oplock_request;
 	uint8_t oplock_granted;
 	struct case_semantics_state *case_state = NULL;
+	uint32_t ucf_flags = UCF_PREP_CREATEFILE |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	DEBUG(5,("call_nt_transact_create\n"));
@@ -1054,9 +1074,25 @@ static void call_nt_transact_create(connection_struct *conn,
 	 */
 	create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
 
-	srvstr_get_path(ctx, params, req->flags2, &fname,
-			params+53, parameter_count-53,
-			STR_TERMINATE, &status);
+	if (req->posix_pathnames) {
+		srvstr_get_path_posix(ctx,
+			params,
+			req->flags2,
+			&fname,
+			params+53,
+			parameter_count-53,
+			STR_TERMINATE,
+			&status);
+	} else {
+		srvstr_get_path(ctx,
+			params,
+			req->flags2,
+			&fname,
+			params+53,
+			parameter_count-53,
+			STR_TERMINATE,
+			&status);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		reply_nterror(req, status);
 		goto out;
@@ -1074,7 +1110,7 @@ static void call_nt_transact_create(connection_struct *conn,
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				fname,
-				UCF_PREP_CREATEFILE,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 
@@ -1530,8 +1566,8 @@ void reply_ntrename(struct smb_request *req)
 	bool src_has_wcard = False;
 	bool dest_has_wcard = False;
 	uint32_t attrs;
-	uint32_t ucf_flags_src = 0;
-	uint32_t ucf_flags_dst = 0;
+	uint32_t ucf_flags_src = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
+	uint32_t ucf_flags_dst = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	uint16_t rename_type;
 	TALLOC_CTX *ctx = talloc_tos();
 	bool stream_rename = false;
@@ -1554,7 +1590,7 @@ void reply_ntrename(struct smb_request *req)
 		goto out;
 	}
 
-	if (ms_has_wild(oldname)) {
+	if (!req->posix_pathnames && ms_has_wild(oldname)) {
 		reply_nterror(req, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
 		goto out;
 	}
@@ -1567,7 +1603,7 @@ void reply_ntrename(struct smb_request *req)
 		goto out;
 	}
 
-	if (!lp_posix_pathnames()) {
+	if (!req->posix_pathnames) {
 		/* The newname must begin with a ':' if the
 		   oldname contains a ':'. */
 		if (strchr_m(oldname, ':')) {
@@ -1837,9 +1873,28 @@ static void call_nt_transact_rename(connection_struct *conn,
 	if (!check_fsp(conn, req, fsp)) {
 		return;
 	}
-	srvstr_get_path_wcard(ctx, params, req->flags2, &new_name, params+4,
-			      parameter_count - 4,
-			      STR_TERMINATE, &status, &dest_has_wcard);
+	if (req->posix_pathnames) {
+		srvstr_get_path_wcard_posix(ctx,
+				params,
+				req->flags2,
+				&new_name,
+				params+4,
+				parameter_count - 4,
+				STR_TERMINATE,
+				&status,
+				&dest_has_wcard);
+	} else {
+		srvstr_get_path_wcard(ctx,
+				params,
+				req->flags2,
+				&new_name,
+				params+4,
+				parameter_count - 4,
+				STR_TERMINATE,
+				&status,
+				&dest_has_wcard);
+	}
+
 	if (!NT_STATUS_IS_OK(status)) {
 		reply_nterror(req, status);
 		return;
@@ -2268,7 +2323,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
 	ZERO_STRUCT(qt);
 
 	/* access check */
-	if (get_current_uid(conn) != 0) {
+	if (get_current_uid(conn) != sec_initial_uid()) {
 		DEBUG(1,("get_user_quota: access_denied service [%s] user "
 			 "[%s]\n", lp_servicename(talloc_tos(), SNUM(conn)),
 			 conn->session_info->unix_info->unix_name));
@@ -2397,7 +2452,8 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
 				SBIG_UINT(entry,32,tmp_list->quotas->hardlim);
 
 				/* and now the SID */
-				sid_linearize(entry+40, sid_len, &tmp_list->quotas->sid);
+				sid_linearize((uint8_t *)(entry+40), sid_len,
+					      &tmp_list->quotas->sid);
 			}
 
 			qt_handle->tmp_list = tmp_list;
@@ -2446,7 +2502,8 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
 				break;
 			}
 
-			if (!sid_parse(pdata+8,sid_len,&sid)) {
+			if (!sid_parse((const uint8_t *)(pdata+8), sid_len,
+				       &sid)) {
 				reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
 				return;
 			}
@@ -2498,7 +2555,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
 			SBIG_UINT(entry,32,qt.hardlim);
 
 			/* and now the SID */
-			sid_linearize(entry+40, sid_len, &sid);
+			sid_linearize((uint8_t *)(entry+40), sid_len, &sid);
 
 			break;
 
@@ -2599,7 +2656,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
 	/* the hard quotas 8 bytes (uint64_t)*/
 	qt.hardlim = BVAL(pdata,32);
 
-	if (!sid_parse(pdata+40,sid_len,&sid)) {
+	if (!sid_parse((const uint8_t *)(pdata+40), sid_len, &sid)) {
 		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
 		return;
 	}
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index eb6058f..0d90c99 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -153,7 +153,7 @@ NTSTATUS smbd_check_access_rights(struct connection_struct *conn,
 	 * Samba 3.6 and earlier granted execute access even
 	 * if the ACL did not contain execute rights.
 	 * Samba 4.0 is more correct and checks it.
-	 * The compatibilty mode allows to skip this check
+	 * The compatibilty mode allows one to skip this check
 	 * to smoothen upgrades.
 	 */
 	if (lp_acl_allow_execute_always(SNUM(conn))) {
@@ -809,6 +809,7 @@ static NTSTATUS open_file(files_struct *fsp,
 			wild = smb_fname->base_name;
 		}
 		if ((local_flags & O_CREAT) && !file_existed &&
+		    !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
 		    ms_has_wild(wild))  {
 			return NT_STATUS_OBJECT_NAME_INVALID;
 		}
@@ -2354,7 +2355,6 @@ static int disposition_to_open_flags(uint32_t create_disposition)
 }
 
 static int calculate_open_access_flags(uint32_t access_mask,
-				       int oplock_request,
 				       uint32_t private_flags)
 {
 	bool need_write, need_read;
@@ -2529,7 +2529,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 	}
 
 	/* this is for OS/2 long file names - say we don't support them */
-	if (!lp_posix_pathnames() && strstr(smb_fname->base_name,".+,;=[].")) {
+	if (req != NULL && !req->posix_pathnames &&
+			strstr(smb_fname->base_name,".+,;=[].")) {
 		/* OS/2 Workplace shell fix may be main code stream in a later
 		 * release. */
 		DEBUG(5,("open_file_ntcreate: OS/2 long filenames are not "
@@ -2641,8 +2642,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 	 * mean the same thing under DOS and Unix.
 	 */
 
-	flags = calculate_open_access_flags(access_mask, oplock_request,
-					    private_flags);
+	flags = calculate_open_access_flags(access_mask, private_flags);
 
 	/*
 	 * Currently we only look at FILE_WRITE_THROUGH for create options.
@@ -2705,7 +2705,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 	fsp->access_mask = open_access_mask; /* We change this to the
 					      * requested access_mask after
 					      * the open is done. */
-	fsp->posix_flags |= posix_open ? FSP_POSIX_FLAGS_OPEN : 0;
+	if (posix_open) {
+		fsp->posix_flags |= FSP_POSIX_FLAGS_ALL;
+	}
 
 	if (timeval_is_zero(&request_time)) {
 		request_time = fsp->open_time;
@@ -3622,8 +3624,18 @@ static NTSTATUS open_directory(connection_struct *conn,
 		return status;
 	}
 
-	/* Ensure there was no race condition. */
-	if (!check_same_stat(&smb_dname->st, &fsp->fsp_name->st)) {
+	if(!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
+		DEBUG(5,("open_directory: %s is not a directory !\n",
+			 smb_fname_str_dbg(smb_dname)));
+                fd_close(fsp);
+                file_free(req, fsp);
+		return NT_STATUS_NOT_A_DIRECTORY;
+	}
+
+	/* Ensure there was no race condition.  We need to check
+	 * dev/inode but not permissions, as these can change
+	 * legitimately */
+	if (!check_same_dev_ino(&smb_dname->st, &fsp->fsp_name->st)) {
 		DEBUG(5,("open_directory: stat struct differs for "
 			"directory %s.\n",
 			smb_fname_str_dbg(smb_dname)));
@@ -4823,6 +4835,8 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
 	files_struct *dir_fsp;
 	char *parent_fname = NULL;
 	char *new_base_name = NULL;
+	uint32_t ucf_flags = ((req != NULL && req->posix_pathnames) ?
+			UCF_POSIX_PATHNAMES : 0);
 	NTSTATUS status;
 
 	if (root_dir_fid == 0 || !smb_fname) {
@@ -4917,7 +4931,7 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				new_base_name,
-				0,
+				ucf_flags,
 				NULL,
 				smb_fname_out);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -5034,7 +5048,7 @@ NTSTATUS create_file_default(connection_struct *conn,
 			status = NT_STATUS_NOT_A_DIRECTORY;
 			goto fail;
 		}
-		if (lp_posix_pathnames()) {
+		if (req != NULL && req->posix_pathnames) {
 			ret = SMB_VFS_LSTAT(conn, smb_fname);
 		} else {
 			ret = SMB_VFS_STAT(conn, smb_fname);
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 80d4fea..0c9c749 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -1688,7 +1688,7 @@ static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
 		    (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
 
 			canon_ace *current_dir_ace = current_ace;
-			DLIST_ADD_END(*dir_ace, current_ace, canon_ace *);
+			DLIST_ADD_END(*dir_ace, current_ace);
 
 			/*
 			 * Note if this was an allow ace. We can't process
@@ -1790,7 +1790,7 @@ static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
 	 */
 
 	if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
-		DLIST_ADD_END(*file_ace, current_ace, canon_ace *);
+		DLIST_ADD_END(*file_ace, current_ace);
 
 		/*
 		 * Note if this was an allow ace. We can't process
@@ -2319,7 +2319,7 @@ static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
 
 			curr_ace->attr = ALLOW_ACE;
 			curr_ace->perms = (mode_t)0;
-			DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
+			DLIST_DEMOTE(ace_list, curr_ace);
 			continue;
 		}
 
@@ -2344,7 +2344,7 @@ static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
 
 		curr_ace->attr = ALLOW_ACE;
 		curr_ace->perms = (new_perms & ~curr_ace->perms);
-		DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
+		DLIST_DEMOTE(ace_list, curr_ace);
 	}
 
 	/* Pass 3 above - deal with deny group entries. */
@@ -2391,7 +2391,7 @@ static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
 			curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
 		else
 			curr_ace->perms = (mode_t)0;
-		DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
+		DLIST_DEMOTE(ace_list, curr_ace);
 	}
 
 	/* Doing this fourth pass allows Windows semantics to be layered
@@ -2589,7 +2589,7 @@ static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
 	}
 
 	if (other_ace) {
-		DLIST_DEMOTE(l_head, other_ace, canon_ace *);
+		DLIST_DEMOTE(l_head, other_ace);
 	}
 
 	/* We have probably changed the head of the list. */
@@ -2624,7 +2624,6 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
 
 		entry_id = SMB_ACL_NEXT_ENTRY;
 
-		/* Is this a MASK entry ? */
 		if (sys_acl_get_tag_type(entry, &tagtype) == -1)
 			continue;
 
@@ -2695,14 +2694,15 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
 		if ((ace = talloc(talloc_tos(), canon_ace)) == NULL)
 			goto fail;
 
-		ZERO_STRUCTP(ace);
-		ace->type = tagtype;
-		ace->perms = convert_permset_to_mode_t(permset);
-		ace->attr = ALLOW_ACE;
-		ace->trustee = sid;
-		ace->unix_ug = unix_ug;
-		ace->owner_type = owner_type;
-		ace->ace_flags = get_pai_flags(pal, ace, is_default_acl);
+		*ace = (canon_ace) {
+			.type = tagtype,
+			.perms = convert_permset_to_mode_t(permset),
+			.attr = ALLOW_ACE,
+			.trustee = sid,
+			.unix_ug = unix_ug,
+			.owner_type = owner_type,
+			.ace_flags = get_pai_flags(pal, ace, is_default_acl)
+		};
 
 		DLIST_ADD(l_head, ace);
 	}
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 6c8a31c..25c6d05 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -39,7 +39,7 @@
 #include "../libcli/security/dom_sid.h"
 #include "../libcli/security/security_token.h"
 #include "lib/id_cache.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 #include "serverid.h"
 #include "system/threads.h"
 
@@ -629,6 +629,7 @@ static bool init_smb_request(struct smb_request *req,
 	req->smb2req = NULL;
 	req->priv_paths = NULL;
 	req->chain = NULL;
+	req->posix_pathnames = lp_posix_pathnames();
 	smb_init_perfcount_data(&req->pcd);
 
 	/* Ensure we have at least wct words and 2 bytes of bcc. */
@@ -749,8 +750,7 @@ static bool push_queued_message(struct smb_request *req,
 	}
 #endif
 
-	DLIST_ADD_END(req->sconn->deferred_open_queue, msg,
-		      struct pending_message_list *);
+	DLIST_ADD_END(req->sconn->deferred_open_queue, msg);
 
 	DEBUG(10,("push_message: pushed message length %u on "
 		  "deferred_open_queue\n", (unsigned int)msg_len));
@@ -1430,6 +1430,54 @@ static void smb_dump(const char *name, int type, const char *data)
 	TALLOC_FREE(fname);
 }
 
+static void smb1srv_update_crypto_flags(struct smbXsrv_session *session,
+					struct smb_request *req,
+					uint8_t type,
+					bool *update_session_globalp,
+					bool *update_tcon_globalp)
+{
+	connection_struct *conn = req->conn;
+	struct smbXsrv_tcon *tcon = conn ? conn->tcon : NULL;
+	uint8_t encrypt_flag = SMBXSRV_PROCESSED_UNENCRYPTED_PACKET;
+	uint8_t sign_flag = SMBXSRV_PROCESSED_UNSIGNED_PACKET;
+	bool update_session = false;
+	bool update_tcon = false;
+
+	if (req->encrypted) {
+		encrypt_flag = SMBXSRV_PROCESSED_ENCRYPTED_PACKET;
+	}
+
+	if (srv_is_signing_active(req->xconn)) {
+		sign_flag = SMBXSRV_PROCESSED_SIGNED_PACKET;
+	} else if ((type == SMBecho) || (type == SMBsesssetupX)) {
+		/*
+		 * echo can be unsigned. Sesssion setup except final
+		 * session setup response too
+		 */
+		sign_flag &= ~SMBXSRV_PROCESSED_UNSIGNED_PACKET;
+	}
+
+	update_session |= smbXsrv_set_crypto_flag(
+		&session->global->encryption_flags, encrypt_flag);
+	update_session |= smbXsrv_set_crypto_flag(
+		&session->global->signing_flags, sign_flag);
+
+	if (tcon) {
+		update_tcon |= smbXsrv_set_crypto_flag(
+			&tcon->global->encryption_flags, encrypt_flag);
+		update_tcon |= smbXsrv_set_crypto_flag(
+			&tcon->global->signing_flags, sign_flag);
+	}
+
+	if (update_session) {
+		session->global->channels[0].encryption_cipher = SMB_ENCRYPTION_GSSAPI;
+	}
+
+	*update_session_globalp = update_session;
+	*update_tcon_globalp = update_tcon;
+	return;
+}
+
 /****************************************************************************
  Prepare everything for calling the actual request function, and potentially
  call the request function via the "new" interface.
@@ -1646,6 +1694,35 @@ static connection_struct *switch_message(uint8_t type, struct smb_request *req)
 		}
 	}
 
+	/*
+	 * Update encryption and signing state tracking flags that are
+	 * used by smbstatus to display signing and encryption status.
+	 */
+	if (session != NULL) {
+		bool update_session_global = false;
+		bool update_tcon_global = false;
+
+		smb1srv_update_crypto_flags(session, req, type,
+					    &update_session_global,
+					    &update_tcon_global);
+
+		if (update_session_global) {
+			status = smbXsrv_session_update(session);
+			if (!NT_STATUS_IS_OK(status)) {
+				reply_nterror(req, NT_STATUS_UNSUCCESSFUL);
+				return conn;
+			}
+		}
+
+		if (update_tcon_global) {
+			status = smbXsrv_tcon_update(req->conn->tcon);
+			if (!NT_STATUS_IS_OK(status)) {
+				reply_nterror(req, NT_STATUS_UNSUCCESSFUL);
+				return conn;
+			}
+		}
+	}
+
 	smb_messages[type].fn(req);
 	return req->conn;
 }
@@ -1893,7 +1970,7 @@ static void process_smb(struct smbXsrv_connection *xconn,
 		if (smbd_is_smb2_header(inbuf, nread)) {
 			const uint8_t *inpdu = inbuf + NBT_HDR_SIZE;
 			size_t pdulen = nread - NBT_HDR_SIZE;
-			smbd_smb2_first_negprot(xconn, inpdu, pdulen);
+			smbd_smb2_process_negprot(xconn, 0, inpdu, pdulen);
 			return;
 		} else if (nread >= smb_size && valid_smb_header(inbuf)
 				&& CVAL(inbuf, smb_com) != 0x72) {
@@ -2693,6 +2770,7 @@ static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
 {
 	struct smbd_release_ip_state *state;
 	struct ctdbd_connection *cconn;
+	int ret;
 
 	cconn = messaging_ctdbd_connection();
 	if (cconn == NULL) {
@@ -2712,7 +2790,11 @@ static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	return ctdbd_register_ips(cconn, srv, clnt, release_ip, state);
+	ret = ctdbd_register_ips(cconn, srv, clnt, release_ip, state);
+	if (ret != 0) {
+		return map_nt_error_from_unix(ret);
+	}
+	return NT_STATUS_OK;
 }
 
 static void msg_kill_client_ip(struct messaging_context *msg_ctx,
@@ -3319,7 +3401,8 @@ bool fork_echo_handler(struct smbXsrv_connection *xconn)
 		close(listener_pipe[0]);
 		set_blocking(listener_pipe[1], false);
 
-		status = smbd_reinit_after_fork(xconn->msg_ctx, xconn->ev_ctx, true);
+		status = smbd_reinit_after_fork(xconn->msg_ctx, xconn->ev_ctx,
+						true, "smbd-echo");
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(1, ("reinit_after_fork failed: %s\n",
 				  nt_errstr(status)));
@@ -3479,6 +3562,10 @@ NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn,
 
 	conn->protocol = protocol;
 
+	if (conn->client->session_table != NULL) {
+		return NT_STATUS_OK;
+	}
+
 	if (protocol >= PROTOCOL_SMB2_02) {
 		status = smb2srv_session_table_init(conn);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -3785,7 +3872,7 @@ NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
 	}
 
 	/* for now we only have one connection */
-	DLIST_ADD_END(client->connections, xconn, NULL);
+	DLIST_ADD_END(client->connections, xconn);
 	xconn->client = client;
 	talloc_steal(client, xconn);
 
@@ -3814,10 +3901,12 @@ void smbd_process(struct tevent_context *ev_ctx,
 	const char *remaddr = NULL;
 	int ret;
 	NTSTATUS status;
+	struct timeval tv = timeval_current();
+	NTTIME now = timeval_to_nttime(&tv);
 
-	client = talloc_zero(ev_ctx, struct smbXsrv_client);
-	if (client == NULL) {
-		DEBUG(0,("talloc_zero(struct smbXsrv_client)\n"));
+	status = smbXsrv_client_create(ev_ctx, ev_ctx, msg_ctx, now, &client);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("smbXsrv_client_create(): %s\n", nt_errstr(status));
 		exit_server_cleanly("talloc_zero(struct smbXsrv_client).\n");
 	}
 
@@ -3826,9 +3915,6 @@ void smbd_process(struct tevent_context *ev_ctx,
 	 */
 	global_smbXsrv_client = client;
 
-	client->ev_ctx = ev_ctx;
-	client->msg_ctx = msg_ctx;
-
 	sconn = talloc_zero(client, struct smbd_server_connection);
 	if (sconn == NULL) {
 		exit_server("failed to create smbd_server_connection");
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 2eac3ec..9b9c924 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -66,6 +66,9 @@ void srv_set_signing(struct smbXsrv_connection *conn,
 
 /* The following definitions come from smbd/aio.c  */
 
+int get_outstanding_aio_calls(void);
+void increment_outstanding_aio_calls(void);
+void decrement_outstanding_aio_calls(void);
 struct aio_extra;
 bool aio_write_through_requested(struct aio_extra *aio_ex);
 NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
@@ -168,7 +171,6 @@ bool connections_snum_used(struct smbd_server_connection *unused, int snum);
 
 /* The following definitions come from smbd/dfree.c  */
 
-void disk_norm(uint64_t *bsize,uint64_t *dfree,uint64_t *dsize);
 uint64_t sys_disk_free(connection_struct *conn, const char *path,
                               uint64_t *bsize,uint64_t *dfree,uint64_t *dsize);
 uint64_t get_dfree_info(connection_struct *conn,
@@ -229,6 +231,8 @@ long TellDir(struct smb_Dir *dirp);
 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset);
 NTSTATUS can_delete_directory(struct connection_struct *conn,
 				const char *dirname);
+bool have_file_open_below(connection_struct *conn,
+			const struct smb_filename *name);
 
 /* The following definitions come from smbd/dmapi.c  */
 
@@ -825,7 +829,8 @@ bool fork_echo_handler(struct smbXsrv_connection *xconn);
 
 /* The following definitions come from smbd/quotas.c  */
 
-bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
+bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
+		 uint64_t *dfree, uint64_t *dsize);
 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
 
 /* The following definitions come from smbd/reply.c  */
@@ -842,6 +847,15 @@ size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
 			int flags,
 			NTSTATUS *err,
 			bool *contains_wcard);
+size_t srvstr_get_path_wcard_posix(TALLOC_CTX *ctx,
+			const char *inbuf,
+			uint16_t smb_flags2,
+			char **pp_dest,
+			const char *src,
+			size_t src_len,
+			int flags,
+			NTSTATUS *err,
+			bool *contains_wcard);
 size_t srvstr_get_path(TALLOC_CTX *ctx,
 			const char *inbuf,
 			uint16_t smb_flags2,
@@ -850,6 +864,14 @@ size_t srvstr_get_path(TALLOC_CTX *ctx,
 			size_t src_len,
 			int flags,
 			NTSTATUS *err);
+size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
+			const char *inbuf,
+			uint16_t smb_flags2,
+			char **pp_dest,
+			const char *src,
+			size_t src_len,
+			int flags,
+			NTSTATUS *err);
 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
 				 char **pp_dest, const char *src, int flags,
 				 NTSTATUS *err, bool *contains_wcard);
@@ -1076,6 +1098,8 @@ int sys_statvfs(const char *path, vfs_statvfs_struct *statbuf);
 
 /* The following definitions come from smbd/trans2.c  */
 
+NTSTATUS check_access_fsp(const struct files_struct *fsp,
+			  uint32_t access_mask);
 NTSTATUS check_access(connection_struct *conn,
 				files_struct *fsp,
 				const struct smb_filename *smb_fname,
diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c
index c64b63a..8e41416 100644
--- a/source3/smbd/quotas.c
+++ b/source3/smbd/quotas.c
@@ -171,17 +171,12 @@ static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t
 	}
 
 	/*
-	 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
-	 * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
-	 * something sensible.
+	 * gqr.status returns 1 if quotas exist, 2 if there is
+	 * no quota set, and 3 if no permission to get the quota.
+	 * If 3, return something sensible.
 	 */
 
 	switch (gqr.status) {
-	case 0:
-		DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", gqr.status));
-		ret = False;
-		goto out;
-
 	case 1:
 		DEBUG(9,("nfs_quotas: Good quota data\n"));
 		D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
@@ -197,8 +192,10 @@ static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t
 		break;
 
 	default:
-		DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", gqr.status ));
-		break;
+		DEBUG(9, ("nfs_quotas: Unknown Remote Quota Status \"%i\"\n",
+				gqr.status));
+		ret = false;
+		goto out;
 	}
 
 	DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
@@ -239,10 +236,8 @@ try to get the disk space from disk quotas (SunOS & Solaris2 version)
 Quota code by Peter Urbanec (amiga at cse.unsw.edu.au).
 ****************************************************************************/
 
-bool disk_quotas(const char *path,
-		uint64_t *bsize,
-		uint64_t *dfree,
-		uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
+		 uint64_t *dfree, uint64_t *dsize)
 {
 	uid_t euser_id;
 	int ret;
@@ -431,7 +426,8 @@ bool disk_quotas(const char *path,
 try to get the disk space from disk quotas - default version
 ****************************************************************************/
 
-bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
+		 uint64_t *dfree, uint64_t *dsize)
 {
   int r;
   struct dqblk D;
@@ -661,7 +657,8 @@ bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *d
 
 #else /* WITH_QUOTAS */
 
-bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
+		 uint64_t *dfree, uint64_t *dsize)
 {
 	(*bsize) = 512; /* This value should be ignored */
 
@@ -679,7 +676,8 @@ bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsiz
 /* wrapper to the new sys_quota interface
    this file should be removed later
    */
-bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
+		 uint64_t *dfree, uint64_t *dsize)
 {
 	int r;
 	SMB_DISK_QUOTA D;
@@ -688,7 +686,7 @@ bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsiz
 	id.uid = geteuid();
 
 	ZERO_STRUCT(D);
-  	r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
+	r = SMB_VFS_GET_QUOTA(conn, path, SMB_USER_QUOTA_TYPE, id, &D);
 
 	/* Use softlimit to determine disk space, except when it has been exceeded */
 	*bsize = D.bsize;
@@ -714,8 +712,9 @@ bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsiz
 	} else if (D.softlimit==0 && D.hardlimit==0) {
 		goto try_group_quota;
 	} else {
-		if (D.softlimit == 0)
+		if (D.softlimit == 0) {
 			D.softlimit = D.hardlimit;
+		}
 		*dfree = D.softlimit - D.curblocks;
 		*dsize = D.softlimit;
 	}
@@ -726,7 +725,7 @@ try_group_quota:
 	id.gid = getegid();
 
 	ZERO_STRUCT(D);
-  	r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
+	r = SMB_VFS_GET_QUOTA(conn, path, SMB_GROUP_QUOTA_TYPE, id, &D);
 
 	/* Use softlimit to determine disk space, except when it has been exceeded */
 	*bsize = D.bsize;
@@ -752,8 +751,9 @@ try_group_quota:
 	} else if (D.softlimit==0 && D.hardlimit==0) {
 		return False;
 	} else {
-		if (D.softlimit == 0)
+		if (D.softlimit == 0) {
 			D.softlimit = D.hardlimit;
+		}
 		*dfree = D.softlimit - D.curblocks;
 		*dsize = D.softlimit;
 	}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index c9d0d81..77d5b6e 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -43,7 +43,7 @@
 #include "../lib/tsocket/tsocket.h"
 #include "lib/tevent_wait.h"
 #include "libcli/smb/smb_signing.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 
 /****************************************************************************
  Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
@@ -253,15 +253,17 @@ NTSTATUS check_path_syntax_posix(char *path)
 
 /****************************************************************************
  Pull a string and check the path allowing a wilcard - provide for error return.
+ Passes in posix flag.
 ****************************************************************************/
 
-size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
+static size_t srvstr_get_path_wcard_internal(TALLOC_CTX *ctx,
 			const char *base_ptr,
 			uint16_t smb_flags2,
 			char **pp_dest,
 			const char *src,
 			size_t src_len,
 			int flags,
+			bool posix_pathnames,
 			NTSTATUS *err,
 			bool *contains_wcard)
 {
@@ -288,7 +290,7 @@ size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
 		return ret;
 	}
 
-	if (lp_posix_pathnames()) {
+	if (posix_pathnames) {
 		*err = check_path_syntax_posix(*pp_dest);
 	} else {
 		*err = check_path_syntax_wcard(*pp_dest, contains_wcard);
@@ -298,6 +300,59 @@ size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
 }
 
 /****************************************************************************
+ Pull a string and check the path allowing a wilcard - provide for error return.
+****************************************************************************/
+
+size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
+			const char *base_ptr,
+			uint16_t smb_flags2,
+			char **pp_dest,
+			const char *src,
+			size_t src_len,
+			int flags,
+			NTSTATUS *err,
+			bool *contains_wcard)
+{
+	return srvstr_get_path_wcard_internal(ctx,
+			base_ptr,
+			smb_flags2,
+			pp_dest,
+			src,
+			src_len,
+			flags,
+			false,
+			err,
+			contains_wcard);
+}
+
+/****************************************************************************
+ Pull a string and check the path allowing a wilcard - provide for error return.
+ posix_pathnames version.
+****************************************************************************/
+
+size_t srvstr_get_path_wcard_posix(TALLOC_CTX *ctx,
+			const char *base_ptr,
+			uint16_t smb_flags2,
+			char **pp_dest,
+			const char *src,
+			size_t src_len,
+			int flags,
+			NTSTATUS *err,
+			bool *contains_wcard)
+{
+	return srvstr_get_path_wcard_internal(ctx,
+			base_ptr,
+			smb_flags2,
+			pp_dest,
+			src,
+			src_len,
+			flags,
+			true,
+			err,
+			contains_wcard);
+}
+
+/****************************************************************************
  Pull a string and check the path - provide for error return.
 ****************************************************************************/
 
@@ -311,10 +366,46 @@ size_t srvstr_get_path(TALLOC_CTX *ctx,
 			NTSTATUS *err)
 {
 	bool ignore;
-	return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
-				     src_len, flags, err, &ignore);
+	return srvstr_get_path_wcard_internal(ctx,
+			base_ptr,
+			smb_flags2,
+			pp_dest,
+			src,
+			src_len,
+			flags,
+			false,
+			err,
+			&ignore);
 }
 
+/****************************************************************************
+ Pull a string and check the path - provide for error return.
+ posix_pathnames version.
+****************************************************************************/
+
+size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
+			const char *base_ptr,
+			uint16_t smb_flags2,
+			char **pp_dest,
+			const char *src,
+			size_t src_len,
+			int flags,
+			NTSTATUS *err)
+{
+	bool ignore;
+	return srvstr_get_path_wcard_internal(ctx,
+			base_ptr,
+			smb_flags2,
+			pp_dest,
+			src,
+			src_len,
+			flags,
+			true,
+			err,
+			&ignore);
+}
+
+
 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
 				 char **pp_dest, const char *src, int flags,
 				 NTSTATUS *err, bool *contains_wcard)
@@ -326,9 +417,29 @@ size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
 		return 0;
 	}
 
-	return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf,
-				     req->flags2, pp_dest, src, bufrem, flags,
-				     err, contains_wcard);
+	if (req->posix_pathnames) {
+		return srvstr_get_path_wcard_internal(mem_ctx,
+				(const char *)req->inbuf,
+				req->flags2,
+				pp_dest,
+				src,
+				bufrem,
+				flags,
+				true,
+				err,
+				contains_wcard);
+	} else {
+		return srvstr_get_path_wcard_internal(mem_ctx,
+				(const char *)req->inbuf,
+				req->flags2,
+				pp_dest,
+				src,
+				bufrem,
+				flags,
+				false,
+				err,
+				contains_wcard);
+	}
 }
 
 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
@@ -1165,6 +1276,7 @@ void reply_checkpath(struct smb_request *req)
 	struct smb_filename *smb_fname = NULL;
 	char *name = NULL;
 	NTSTATUS status;
+	uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBcheckpath);
@@ -1185,7 +1297,7 @@ void reply_checkpath(struct smb_request *req)
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				name,
-				0,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 
@@ -1279,11 +1391,13 @@ void reply_getatr(struct smb_request *req)
 		size = 0;
 		mtime = 0;
 	} else {
+		uint32_t ucf_flags = (req->posix_pathnames ?
+				UCF_POSIX_PATHNAMES : 0);
 		status = filename_convert(ctx,
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				fname,
-				0,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -1364,6 +1478,7 @@ void reply_setatr(struct smb_request *req)
 	time_t mtime;
 	const char *p;
 	NTSTATUS status;
+	uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBsetatr);
@@ -1386,7 +1501,7 @@ void reply_setatr(struct smb_request *req)
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				fname,
-				0,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -1640,7 +1755,7 @@ void reply_search(struct smb_request *req)
 		goto out;
 	}
 
-	if (lp_posix_pathnames()) {
+	if (req->posix_pathnames) {
 		reply_unknown_new(req, req->cmd);
 		goto out;
 	}
@@ -1668,10 +1783,12 @@ void reply_search(struct smb_request *req)
 	/* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
 
 	if (status_len == 0) {
+		uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 		nt_status = filename_convert(ctx, conn,
 					     req->flags2 & FLAGS2_DFS_PATHNAMES,
 					     path,
-					     UCF_ALWAYS_ALLOW_WCARD_LCOMP,
+					     ucf_flags,
 					     &mask_contains_wcard,
 					     &smb_fname);
 		if (!NT_STATUS_IS_OK(nt_status)) {
@@ -1749,7 +1866,9 @@ void reply_search(struct smb_request *req)
 		 * For a 'continue' search we have no string. So
 		 * check from the initial saved string.
 		 */
-		mask_contains_wcard = ms_has_wild(mask);
+		if (!req->posix_pathnames) {
+			mask_contains_wcard = ms_has_wild(mask);
+		}
 		dirtype = dptr_attr(sconn, dptr_num);
 	}
 
@@ -1904,7 +2023,7 @@ void reply_fclose(struct smb_request *req)
 
 	START_PROFILE(SMBfclose);
 
-	if (lp_posix_pathnames()) {
+	if (req->posix_pathnames) {
 		reply_unknown_new(req, req->cmd);
 		END_PROFILE(SMBfclose);
 		return;
@@ -1967,6 +2086,8 @@ void reply_open(struct smb_request *req)
 	uint32_t create_options = 0;
 	uint32_t private_flags = 0;
 	NTSTATUS status;
+	uint32_t ucf_flags = UCF_PREP_CREATEFILE |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBopen);
@@ -1999,7 +2120,7 @@ void reply_open(struct smb_request *req)
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				fname,
-				UCF_PREP_CREATEFILE,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -2119,6 +2240,8 @@ void reply_open_and_X(struct smb_request *req)
 	uint32_t create_disposition;
 	uint32_t create_options = 0;
 	uint32_t private_flags = 0;
+	uint32_t ucf_flags = UCF_PREP_CREATEFILE |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBopenX);
@@ -2169,7 +2292,7 @@ void reply_open_and_X(struct smb_request *req)
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				fname,
-				UCF_PREP_CREATEFILE,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -2377,6 +2500,8 @@ void reply_mknew(struct smb_request *req)
 	uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
 	uint32_t create_disposition;
 	uint32_t create_options = 0;
+	uint32_t ucf_flags = UCF_PREP_CREATEFILE |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBcreate);
@@ -2404,7 +2529,7 @@ void reply_mknew(struct smb_request *req)
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				fname,
-				UCF_PREP_CREATEFILE,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -2508,6 +2633,8 @@ void reply_ctemp(struct smb_request *req)
 	char *s;
 	NTSTATUS status;
 	int i;
+	uint32_t ucf_flags = UCF_PREP_CREATEFILE |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBctemp);
@@ -2547,7 +2674,7 @@ void reply_ctemp(struct smb_request *req)
 		status = filename_convert(ctx, conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				fname,
-				UCF_PREP_CREATEFILE,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -2661,7 +2788,7 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
 	if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
 			(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
 		/* Only bother to read the DOS attribute if we might deny the
-		   rename on the grounds of attribute missmatch. */
+		   rename on the grounds of attribute mismatch. */
 		uint32_t fmode = dos_mode(conn, fsp->fsp_name);
 		if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
 			return NT_STATUS_NO_SUCH_FILE;
@@ -2669,14 +2796,24 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
 	}
 
 	if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
-		if (fsp->posix_flags & (FSP_POSIX_FLAGS_OPEN|FSP_POSIX_FLAGS_RENAME)) {
+		if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
 			return NT_STATUS_OK;
 		}
 
 		/* If no pathnames are open below this
 		   directory, allow the rename. */
 
-		if (file_find_subpath(fsp)) {
+		if (lp_strict_rename(SNUM(conn))) {
+			/*
+			 * Strict rename, check open file db.
+			 */
+			if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
+				return NT_STATUS_ACCESS_DENIED;
+			}
+		} else if (file_find_subpath(fsp)) {
+			/*
+			 * No strict rename, just look in local process.
+			 */
 			return NT_STATUS_ACCESS_DENIED;
 		}
 		return NT_STATUS_OK;
@@ -2703,7 +2840,7 @@ static NTSTATUS do_unlink(connection_struct *conn,
 	uint32_t dirtype_orig = dirtype;
 	NTSTATUS status;
 	int ret;
-	bool posix_paths = lp_posix_pathnames();
+	bool posix_paths = (req != NULL && req->posix_pathnames);
 
 	DEBUG(10,("do_unlink: %s, dirtype = %d\n",
 		  smb_fname_str_dbg(smb_fname),
@@ -3041,6 +3178,8 @@ void reply_unlink(struct smb_request *req)
 	uint32_t dirtype;
 	NTSTATUS status;
 	bool path_contains_wcard = False;
+	uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBunlink);
@@ -3063,7 +3202,7 @@ void reply_unlink(struct smb_request *req)
 	status = filename_convert(ctx, conn,
 				  req->flags2 & FLAGS2_DFS_PATHNAMES,
 				  name,
-				  UCF_COND_ALLOW_WCARD_LCOMP,
+				  ucf_flags,
 				  &path_contains_wcard,
 				  &smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -5949,6 +6088,8 @@ void reply_mkdir(struct smb_request *req)
 	struct smb_filename *smb_dname = NULL;
 	char *directory = NULL;
 	NTSTATUS status;
+	uint32_t ucf_flags = UCF_PREP_CREATEFILE |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBmkdir);
@@ -5963,7 +6104,7 @@ void reply_mkdir(struct smb_request *req)
 	status = filename_convert(ctx, conn,
 				 req->flags2 & FLAGS2_DFS_PATHNAMES,
 				 directory,
-				 UCF_PREP_CREATEFILE,
+				 ucf_flags,
 				 NULL,
 				 &smb_dname);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -6019,6 +6160,7 @@ void reply_rmdir(struct smb_request *req)
 	TALLOC_CTX *ctx = talloc_tos();
 	files_struct *fsp = NULL;
 	int info = 0;
+	uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	struct smbd_server_connection *sconn = req->sconn;
 
 	START_PROFILE(SMBrmdir);
@@ -6033,7 +6175,7 @@ void reply_rmdir(struct smb_request *req)
 	status = filename_convert(ctx, conn,
 				 req->flags2 & FLAGS2_DFS_PATHNAMES,
 				 directory,
-				 0,
+				 ucf_flags,
 				 NULL,
 				 &smb_dname);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -6448,12 +6590,12 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
 
 	/*
 	 * Check for special case with case preserving and not
-	 * case sensitive. If the old last component differs from the original
+	 * case sensitive. If the new last component differs from the original
 	 * last component only by case, then we should allow
 	 * the rename (user is trying to change the case of the
 	 * filename).
 	 */
-	if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
+	if (!conn->case_sensitive && conn->case_preserve &&
 	    strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
 	    strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
 		char *last_slash;
@@ -6713,7 +6855,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 	char *talloced = NULL;
 	long offset = 0;
 	int create_options = 0;
-	bool posix_pathnames = lp_posix_pathnames();
+	bool posix_pathnames = (req != NULL && req->posix_pathnames);
 	int rc;
 
 	/*
@@ -7055,8 +7197,12 @@ void reply_mv(struct smb_request *req)
 	TALLOC_CTX *ctx = talloc_tos();
 	struct smb_filename *smb_fname_src = NULL;
 	struct smb_filename *smb_fname_dst = NULL;
-	uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
-	uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
+	uint32_t src_ucf_flags = (req->posix_pathnames ?
+		(UCF_UNIX_NAME_LOOKUP|UCF_POSIX_PATHNAMES) :
+		UCF_COND_ALLOW_WCARD_LCOMP);
+	uint32_t dst_ucf_flags = UCF_SAVE_LCOMP |
+		(req->posix_pathnames ? UCF_POSIX_PATHNAMES :
+		 UCF_COND_ALLOW_WCARD_LCOMP);
 	bool stream_rename = false;
 
 	START_PROFILE(SMBmv);
@@ -7083,7 +7229,7 @@ void reply_mv(struct smb_request *req)
 		goto out;
 	}
 
-	if (!lp_posix_pathnames()) {
+	if (!req->posix_pathnames) {
 		/* The newname must begin with a ':' if the
 		   name contains a ':'. */
 		if (strchr_m(name, ':')) {
@@ -7367,6 +7513,10 @@ void reply_copy(struct smb_request *req)
 	bool source_has_wild = False;
 	bool dest_has_wild = False;
 	NTSTATUS status;
+	uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
+		(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
+	uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
+		(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	START_PROFILE(SMBcopy);
@@ -7406,7 +7556,7 @@ void reply_copy(struct smb_request *req)
 	status = filename_convert(ctx, conn,
 				  req->flags2 & FLAGS2_DFS_PATHNAMES,
 				  fname_src,
-				  UCF_COND_ALLOW_WCARD_LCOMP,
+				  ucf_flags_src,
 				  &source_has_wild,
 				  &smb_fname_src);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -7422,7 +7572,7 @@ void reply_copy(struct smb_request *req)
 	status = filename_convert(ctx, conn,
 				  req->flags2 & FLAGS2_DFS_PATHNAMES,
 				  fname_dst,
-				  UCF_COND_ALLOW_WCARD_LCOMP,
+				  ucf_flags_dst,
 				  &dest_has_wild,
 				  &smb_fname_dst);
 	if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/scavenger.c b/source3/smbd/scavenger.c
index 6989466..9f58f62 100644
--- a/source3/smbd/scavenger.c
+++ b/source3/smbd/scavenger.c
@@ -26,7 +26,7 @@
 #include "smbd/scavenger.h"
 #include "locking/proto.h"
 #include "lib/util/util_process.h"
-#include "lib/sys_rw.h"
+#include "lib/util/sys_rw_data.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_SCAVENGER
@@ -144,21 +144,17 @@ static int smbd_scavenger_server_id_destructor(struct server_id *id)
 
 static bool scavenger_say_hello(int fd, struct server_id self)
 {
-	const uint8_t *msg = (const uint8_t *)&self;
-	size_t remaining = sizeof(self);
-	size_t ofs = 0;
+	ssize_t ret;
 	struct server_id_buf tmp;
 
-	while (remaining > 0) {
-		ssize_t ret;
-
-		ret = sys_write(fd, msg + ofs, remaining);
-		if (ret == -1) {
-			DEBUG(2, ("Failed to write to pipe: %s\n",
-				  strerror(errno)));
-			return false;
-		}
-		remaining -= ret;
+	ret = write_data(fd, &self, sizeof(self));
+	if (ret == -1) {
+		DEBUG(2, ("Failed to write to pipe: %s\n", strerror(errno)));
+		return false;
+	}
+	if (ret < sizeof(self)) {
+		DBG_WARNING("Could not write serverid\n");
+		return false;
 	}
 
 	DEBUG(4, ("scavenger_say_hello: self[%s]\n",
@@ -168,21 +164,18 @@ static bool scavenger_say_hello(int fd, struct server_id self)
 
 static bool scavenger_wait_hello(int fd, struct server_id *child)
 {
-	uint8_t *msg = (uint8_t *)child;
-	size_t remaining = sizeof(*child);
-	size_t ofs = 0;
 	struct server_id_buf tmp;
+	ssize_t ret;
 
-	while (remaining > 0) {
-		ssize_t ret;
-
-		ret = sys_read(fd, msg + ofs, remaining);
-		if (ret == -1) {
-			DEBUG(2, ("Failed to read from pipe: %s\n",
-				  strerror(errno)));
-			return false;
-		}
-		remaining -= ret;
+	ret = read_data(fd, child, sizeof(struct server_id));
+	if (ret == -1) {
+		DEBUG(2, ("Failed to read from pipe: %s\n",
+			  strerror(errno)));
+		return false;
+	}
+	if (ret < sizeof(struct server_id)) {
+		DBG_WARNING("Could not read serverid\n");
+		return false;
 	}
 
 	DEBUG(4, ("scavenger_say_hello: child[%s]\n",
@@ -196,7 +189,6 @@ static bool smbd_scavenger_start(struct smbd_scavenger_state *state)
 	struct tevent_fd *fde = NULL;
 	int fds[2];
 	int ret;
-	uint64_t unique_id;
 	bool ok;
 
 	SMB_ASSERT(server_id_equal(&state->parent_id, &self));
@@ -234,8 +226,6 @@ static bool smbd_scavenger_start(struct smbd_scavenger_state *state)
 	smb_set_close_on_exec(fds[0]);
 	smb_set_close_on_exec(fds[1]);
 
-	unique_id = serverid_get_random_unique_id();
-
 	ret = fork();
 	if (ret == -1) {
 		int err = errno;
@@ -252,9 +242,8 @@ static bool smbd_scavenger_start(struct smbd_scavenger_state *state)
 
 		close(fds[0]);
 
-		set_my_unique_id(unique_id);
-
-		status = smbd_reinit_after_fork(state->msg, state->ev, true);
+		status = smbd_reinit_after_fork(state->msg, state->ev,
+						true, "smbd-scavenger");
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(2, ("reinit_after_fork failed: %s\n",
 				  nt_errstr(status)));
@@ -262,8 +251,6 @@ static bool smbd_scavenger_start(struct smbd_scavenger_state *state)
 			return false;
 		}
 
-		prctl_set_comment("smbd-scavenger");
-
 		state->am_scavenger = true;
 		*state->scavenger_id = messaging_server_id(state->msg);
 
diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c
index e088d74..d2c8951 100644
--- a/source3/smbd/seal.c
+++ b/source3/smbd/seal.c
@@ -20,9 +20,7 @@
 #include "includes.h"
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
-#include "../libcli/auth/spnego.h"
 #include "../libcli/smb/smb_seal.h"
-#include "../lib/util/asn1.h"
 #include "auth.h"
 #include "libsmb/libsmb.h"
 #include "../lib/tsocket/tsocket.h"
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 8c77500..42fcad6 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -48,8 +48,13 @@
 #include "lib/smbd_shim.h"
 #include "scavenger.h"
 #include "locking/leases_db.h"
-#include "../../ctdb/include/ctdb_protocol.h"
 #include "smbd/notifyd/notifyd.h"
+#include "smbd/smbd_cleanupd.h"
+#include "lib/util/sys_rw.h"
+
+#ifdef CLUSTER_SUPPORT
+#include "ctdb_protocol.h"
+#endif
 
 struct smbd_open_socket;
 struct smbd_child_pid;
@@ -67,6 +72,8 @@ struct smbd_parent_context {
 	struct smbd_child_pid *children;
 	size_t num_children;
 
+	struct server_id cleanupd;
+
 	struct tevent_timer *cleanup_te;
 };
 
@@ -94,10 +101,6 @@ extern void start_fssd(struct tevent_context *ev_ctx,
 extern void start_mdssd(struct tevent_context *ev_ctx,
 			struct messaging_context *msg_ctx);
 
-#ifdef WITH_DFS
-extern int dcelogin_atmost_once;
-#endif /* WITH_DFS */
-
 /*******************************************************************
  What to do when smb.conf is updated.
  ********************************************************************/
@@ -265,6 +268,7 @@ static void smbd_parent_id_cache_delete(struct messaging_context *ctx,
 	messaging_send_to_children(ctx, msg_type, msg_data);
 }
 
+#ifdef CLUSTER_SUPPORT
 static int smbd_parent_ctdb_reconfigured(
 	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
 	const uint8_t *msg, size_t msglen, void *private_data)
@@ -279,11 +283,14 @@ static int smbd_parent_ctdb_reconfigured(
 	 * Someone from the family died, validate our locks
 	 */
 
-	messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
-			   MSG_SMB_BRL_VALIDATE, NULL, 0);
+	if (am_parent) {
+		messaging_send_buf(msg_ctx, am_parent->cleanupd,
+				   MSG_SMB_BRL_VALIDATE, NULL, 0);
+	}
 
 	return 0;
 }
+#endif
 
 static void add_child_pid(struct smbd_parent_context *parent,
 			  pid_t pid)
@@ -389,7 +396,7 @@ static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive)
 		return true;
 	}
 
-	status = reinit_after_fork(msg, ev, true);
+	status = reinit_after_fork(msg, ev, true, "smbd-notifyd");
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(1, ("%s: reinit_after_fork failed: %s\n",
 			  __func__, nt_errstr(status)));
@@ -404,6 +411,118 @@ static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive)
 	return tevent_req_poll(req, ev);
 }
 
+static void cleanupd_stopped(struct tevent_req *req);
+
+static bool cleanupd_init(struct messaging_context *msg, bool interactive,
+			  struct server_id *ppid)
+{
+	struct tevent_context *ev = messaging_tevent_context(msg);
+	struct server_id parent_id = messaging_server_id(msg);
+	struct tevent_req *req;
+	pid_t pid;
+	NTSTATUS status;
+	ssize_t rwret;
+	int ret;
+	bool ok;
+	char c;
+	int up_pipe[2];
+
+	if (interactive) {
+		req = smbd_cleanupd_send(msg, ev, msg, parent_id.pid);
+		*ppid = messaging_server_id(msg);
+		return (req != NULL);
+	}
+
+	ret = pipe(up_pipe);
+	if (ret == -1) {
+		DBG_WARNING("pipe failed: %s\n", strerror(errno));
+		return false;
+	}
+
+	pid = fork();
+	if (pid == -1) {
+		DBG_WARNING("fork failed: %s\n", strerror(errno));
+		close(up_pipe[0]);
+		close(up_pipe[1]);
+		return false;
+	}
+
+	if (pid != 0) {
+
+		close(up_pipe[1]);
+		rwret = sys_read(up_pipe[0], &c, 1);
+		close(up_pipe[0]);
+
+		if (rwret == -1) {
+			DBG_WARNING("sys_read failed: %s\n", strerror(errno));
+			return false;
+		}
+		if (rwret == 0) {
+			DBG_WARNING("cleanupd could not start\n");
+			return false;
+		}
+		if (c != 0) {
+			DBG_WARNING("cleanupd returned %d\n", (int)c);
+			return false;
+		}
+
+		DBG_DEBUG("Started cleanupd pid=%d\n", (int)pid);
+
+		*ppid = pid_to_procid(pid);
+		return true;
+	}
+
+	close(up_pipe[0]);
+
+	status = reinit_after_fork(msg, ev, true, "cleanupd");
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("reinit_after_fork failed: %s\n",
+			    nt_errstr(status));
+		c = 1;
+		sys_write(up_pipe[1], &c, 1);
+
+		exit(1);
+	}
+
+	req = smbd_cleanupd_send(msg, ev, msg, parent_id.pid);
+	if (req == NULL) {
+		DBG_WARNING("smbd_cleanupd_send failed\n");
+		c = 2;
+		sys_write(up_pipe[1], &c, 1);
+
+		exit(1);
+	}
+
+	tevent_req_set_callback(req, cleanupd_stopped, msg);
+
+	c = 0;
+	rwret = sys_write(up_pipe[1], &c, 1);
+	close(up_pipe[1]);
+
+	if (rwret == -1) {
+		DBG_WARNING("sys_write failed: %s\n", strerror(errno));
+		exit(1);
+	}
+	if (rwret != 1) {
+		DBG_WARNING("sys_write could not write result\n");
+		exit(1);
+	}
+
+	ok = tevent_req_poll(req, ev);
+	if (!ok) {
+		DBG_WARNING("tevent_req_poll returned %s\n", strerror(errno));
+	}
+	exit(0);
+}
+
+static void cleanupd_stopped(struct tevent_req *req)
+{
+	NTSTATUS status;
+
+	status = smbd_cleanupd_recv(req);
+	DBG_WARNING("cleanupd stopped: %s\n", nt_errstr(status));
+}
+
 /*
   at most every smbd:cleanuptime seconds (default 20), we scan the BRL
   and locking database for entries to cleanup. As a side effect this
@@ -426,11 +545,8 @@ static void cleanup_timeout_fn(struct tevent_context *event_ctx,
 
 	parent->cleanup_te = NULL;
 
-	DEBUG(1,("Cleaning up brl and lock database after unclean shutdown\n"));
-	message_send_all(parent->msg_ctx, MSG_SMB_UNLOCK, NULL, 0, NULL);
-	messaging_send_buf(parent->msg_ctx,
-			   messaging_server_id(parent->msg_ctx),
-			   MSG_SMB_BRL_VALIDATE, NULL, 0);
+	messaging_send_buf(parent->msg_ctx, parent->cleanupd,
+			   MSG_SMB_UNLOCK, NULL, 0);
 }
 
 static void remove_child_pid(struct smbd_parent_context *parent,
@@ -438,19 +554,18 @@ static void remove_child_pid(struct smbd_parent_context *parent,
 			     bool unclean_shutdown)
 {
 	struct smbd_child_pid *child;
-	struct server_id child_id;
-	int ret;
-
-	child_id = pid_to_procid(pid);
-
-	ret = messaging_cleanup(parent->msg_ctx, pid);
+	struct iovec iov[2];
+	NTSTATUS status;
 
-	if ((ret != 0) && (ret != ENOENT)) {
-		DEBUG(10, ("%s: messaging_cleanup returned %s\n",
-			   __func__, strerror(ret)));
-	}
+	iov[0] = (struct iovec) { .iov_base = (uint8_t *)&pid,
+				  .iov_len = sizeof(pid) };
+	iov[1] = (struct iovec) { .iov_base = (uint8_t *)&unclean_shutdown,
+				  .iov_len = sizeof(bool) };
 
-	smbprofile_cleanup(pid);
+	status = messaging_send_iov(parent->msg_ctx, parent->cleanupd,
+				    MSG_SMB_NOTIFY_CLEANUP,
+				    iov, ARRAY_SIZE(iov), NULL, 0);
+	DEBUG(10, ("messaging_send_iov returned %s\n", nt_errstr(status)));
 
 	for (child = parent->children; child != NULL; child = child->next) {
 		if (child->pid == pid) {
@@ -486,11 +601,6 @@ static void remove_child_pid(struct smbd_parent_context *parent,
 			DEBUG(1,("Scheduled cleanup of brl and lock database after unclean shutdown\n"));
 		}
 	}
-
-	if (!serverid_deregister(child_id)) {
-		DEBUG(1, ("Could not remove pid %d from serverid.tdb\n",
-			  (int)pid));
-	}
 }
 
 /****************************************************************************
@@ -575,7 +685,6 @@ static void smbd_accept_connection(struct tevent_context *ev,
 	socklen_t in_addrlen = sizeof(addr);
 	int fd;
 	pid_t pid = 0;
-	uint64_t unique_id;
 
 	fd = accept(s->fd, (struct sockaddr *)(void *)&addr,&in_addrlen);
 	if (fd == -1 && errno == EINTR)
@@ -588,7 +697,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
 	}
 
 	if (s->parent->interactive) {
-		reinit_after_fork(msg_ctx, ev, true);
+		reinit_after_fork(msg_ctx, ev, true, NULL);
 		smbd_process(ev, msg_ctx, fd, true);
 		exit_server_cleanly("end of interactive mode");
 		return;
@@ -599,12 +708,6 @@ static void smbd_accept_connection(struct tevent_context *ev,
 		return;
 	}
 
-	/*
-	 * Generate a unique id in the parent process so that we use
-	 * the global random state in the parent.
-	 */
-	unique_id = serverid_get_random_unique_id();
-
 	pid = fork();
 	if (pid == 0) {
 		NTSTATUS status = NT_STATUS_OK;
@@ -616,13 +719,11 @@ static void smbd_accept_connection(struct tevent_context *ev,
 		talloc_free(s->parent);
 		s = NULL;
 
-		set_my_unique_id(unique_id);
-
 		/* Stop zombies, the parent explicitly handles
 		 * them, counting worker smbds. */
 		CatchChild();
 
-		status = smbd_reinit_after_fork(msg_ctx, ev, true);
+		status = smbd_reinit_after_fork(msg_ctx, ev, true, NULL);
 		if (!NT_STATUS_IS_OK(status)) {
 			if (NT_STATUS_EQUAL(status,
 					    NT_STATUS_TOO_MANY_OPENED_FILES)) {
@@ -705,7 +806,7 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent,
 			       ifss,
 			       true);
 	if (s->fd == -1) {
-		DEBUG(0,("smbd_open_once_socket: open_socket_in: "
+		DEBUG(0,("smbd_open_one_socket: open_socket_in: "
 			"%s\n", strerror(errno)));
 		TALLOC_FREE(s);
 		/*
@@ -723,7 +824,7 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent,
 	set_blocking(s->fd, False);
 
 	if (listen(s->fd, SMBD_LISTEN_BACKLOG) == -1) {
-		DEBUG(0,("open_sockets_smbd: listen: "
+		DEBUG(0,("smbd_open_one_socket: listen: "
 			"%s\n", strerror(errno)));
 			close(s->fd);
 		TALLOC_FREE(s);
@@ -736,7 +837,7 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent,
 			       smbd_accept_connection,
 			       s);
 	if (!s->fde) {
-		DEBUG(0,("open_sockets_smbd: "
+		DEBUG(0,("smbd_open_one_socket: "
 			 "tevent_add_fd: %s\n",
 			 strerror(errno)));
 		close(s->fd);
@@ -745,7 +846,7 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent,
 	}
 	tevent_fd_set_close_fn(s->fde, smbd_open_socket_close_fn);
 
-	DLIST_ADD_END(parent->sockets, s, struct smbd_open_socket *);
+	DLIST_ADD_END(parent->sockets, s);
 
 	return true;
 }
@@ -901,8 +1002,6 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 	messaging_register(msg_ctx, NULL, MSG_SMB_STAT_CACHE_DELETE,
 			   smb_stat_cache_delete);
 	messaging_register(msg_ctx, NULL, MSG_DEBUG, smbd_msg_debug);
-	messaging_register(msg_ctx, NULL, MSG_SMB_BRL_VALIDATE,
-			   brl_revalidate);
 	messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS,
 			   smb_parent_send_to_children);
 	messaging_register(msg_ctx, NULL, MSG_SMB_KILL_CLIENT_IP,
@@ -915,6 +1014,7 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 	messaging_register(msg_ctx, NULL,
 			   ID_CACHE_KILL, smbd_parent_id_cache_kill);
 
+#ifdef CLUSTER_SUPPORT
 	if (lp_clustering()) {
 		struct ctdbd_connection *conn = messaging_ctdbd_connection();
 
@@ -923,6 +1023,7 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 		register_with_ctdbd(conn, CTDB_SRVID_SAMBA_NOTIFY,
 				    smbd_parent_ctdb_reconfigured, msg_ctx);
 	}
+#endif
 
 #ifdef DEVELOPER
 	messaging_register(msg_ctx, NULL, MSG_SMB_INJECT_FAULT,
@@ -1220,8 +1321,9 @@ extern void build_options(bool screen);
 		exit(1);
 	}
 
-	/* we want to re-seed early to prevent time delays causing
-           client problems at a later date. (tridge) */
+	/*
+	 * We want to die early if we can't open /dev/urandom
+	 */
 	generate_random_buffer(NULL, 0);
 
 	/* get initial effective uid and gid */
@@ -1363,8 +1465,6 @@ extern void build_options(bool screen);
 		become_daemon(Fork, no_process_group, log_stdout);
 	}
 
-        set_my_unique_id(serverid_get_random_unique_id());
-
 #if HAVE_SETPGID
 	/*
 	 * If we're interactive we want to set our own process group for
@@ -1383,9 +1483,7 @@ extern void build_options(bool screen);
 	if (is_daemon)
 		pidfile_create(lp_pid_directory(), "smbd");
 
-	status = reinit_after_fork(msg_ctx,
-				   ev_ctx,
-				   false);
+	status = reinit_after_fork(msg_ctx, ev_ctx, false, NULL);
 	if (!NT_STATUS_IS_OK(status)) {
 		exit_daemon("reinit_after_fork() failed", map_errno_from_nt_status(status));
 	}
@@ -1485,6 +1583,10 @@ extern void build_options(bool screen);
 		exit_daemon("Samba cannot init notification", EACCES);
 	}
 
+	if (!cleanupd_init(msg_ctx, interactive, &parent->cleanupd)) {
+		exit_daemon("Samba cannot init the cleanupd", EACCES);
+	}
+
 	if (!messaging_parent_dgm_cleanup_init(msg_ctx)) {
 		exit(1);
 	}
diff --git a/source3/smbd/server_exit.c b/source3/smbd/server_exit.c
index 700f595..bf50394 100644
--- a/source3/smbd/server_exit.c
+++ b/source3/smbd/server_exit.c
@@ -178,12 +178,6 @@ static void exit_server_common(enum server_exit_reason how,
 		serverid_deregister(messaging_server_id(msg_ctx));
 	}
 
-#ifdef WITH_DFS
-	if (dcelogin_atmost_once) {
-		dfs_unlogin();
-	}
-#endif
-
 #ifdef USE_DMAPI
 	/* Destroy Samba DMAPI session only if we are master smbd process */
 	if (am_parent) {
@@ -275,8 +269,8 @@ void smbd_exit_server_cleanly(const char *const explanation)
  */
 NTSTATUS smbd_reinit_after_fork(struct messaging_context *msg_ctx,
 				struct tevent_context *ev_ctx,
-				bool parent_longlived)
+				bool parent_longlived, const char *comment)
 {
 	am_parent = NULL;
-	return reinit_after_fork(msg_ctx, ev_ctx, parent_longlived);
+	return reinit_after_fork(msg_ctx, ev_ctx, parent_longlived, comment);
 }
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index d68bcb6..fbc4013 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -26,11 +26,6 @@
 #include "../lib/tsocket/tsocket.h"
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
-#include "../libcli/auth/spnego.h"
-#include "../auth/ntlmssp/ntlmssp.h"
-#include "../librpc/gen_ndr/krb5pac.h"
-#include "libads/kerberos_proto.h"
-#include "../lib/util/asn1.h"
 #include "auth.h"
 #include "messages.h"
 #include "smbprofile.h"
@@ -138,6 +133,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 	struct smbXsrv_session *session = NULL;
 	uint16_t smb_bufsize = SVAL(req->vwv+2, 0);
 	uint32_t client_caps = IVAL(req->vwv+10, 0);
+	struct smbXsrv_session_auth0 *auth;
 
 	DEBUG(3,("Doing spnego session setup\n"));
 
@@ -216,7 +212,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 		if (NT_STATUS_IS_OK(status)) {
 			session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
 			status = NT_STATUS_MORE_PROCESSING_REQUIRED;
-			TALLOC_FREE(session->gensec);
+			TALLOC_FREE(session->pending_auth);
 		}
 		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 			reply_nterror(req, nt_status_squash(status));
@@ -234,19 +230,31 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 		}
 	}
 
-	if (!session->gensec) {
+	status = smbXsrv_session_find_auth(session, xconn, now, &auth);
+	if (!NT_STATUS_IS_OK(status)) {
+		status = smbXsrv_session_create_auth(session, xconn, now,
+						     0, /* flags */
+						     0, /* security */
+						     &auth);
+		if (!NT_STATUS_IS_OK(status)) {
+			reply_nterror(req, nt_status_squash(status));
+			return;
+		}
+	}
+
+	if (auth->gensec == NULL) {
 		status = auth_generic_prepare(session, xconn->remote_address,
-					      &session->gensec);
+					      &auth->gensec);
 		if (!NT_STATUS_IS_OK(status)) {
 			TALLOC_FREE(session);
 			reply_nterror(req, nt_status_squash(status));
 			return;
 		}
 
-		gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
-		gensec_want_feature(session->gensec, GENSEC_FEATURE_UNIX_TOKEN);
+		gensec_want_feature(auth->gensec, GENSEC_FEATURE_SESSION_KEY);
+		gensec_want_feature(auth->gensec, GENSEC_FEATURE_UNIX_TOKEN);
 
-		status = gensec_start_mech_by_oid(session->gensec,
+		status = gensec_start_mech_by_oid(auth->gensec,
 						  GENSEC_OID_SPNEGO);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(0, ("Failed to start SPNEGO handler!\n"));
@@ -257,7 +265,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 	}
 
 	become_root();
-	status = gensec_update(session->gensec,
+	status = gensec_update(auth->gensec,
 			       talloc_tos(),
 			       in_blob, &out_blob);
 	unbecome_root();
@@ -271,7 +279,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 	if (NT_STATUS_IS_OK(status) && session->global->auth_session_info == NULL) {
 		struct auth_session_info *session_info = NULL;
 
-		status = gensec_session_info(session->gensec,
+		status = gensec_session_info(auth->gensec,
 					     session,
 					     &session_info);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -357,7 +365,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 		session->global->auth_time = now;
 		if (client_caps & CAP_DYNAMIC_REAUTH) {
 			session->global->expiration_time =
-				gensec_expire_time(session->gensec);
+				gensec_expire_time(auth->gensec);
 		} else {
 			session->global->expiration_time =
 				GENSEC_EXPIRE_TIME_INFINITY;
@@ -397,7 +405,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 	} else if (NT_STATUS_IS_OK(status)) {
 		struct auth_session_info *session_info = NULL;
 
-		status = gensec_session_info(session->gensec,
+		status = gensec_session_info(auth->gensec,
 					     session,
 					     &session_info);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -445,7 +453,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 		session->global->auth_time = now;
 		if (client_caps & CAP_DYNAMIC_REAUTH) {
 			session->global->expiration_time =
-				gensec_expire_time(session->gensec);
+				gensec_expire_time(auth->gensec);
 		} else {
 			session->global->expiration_time =
 				GENSEC_EXPIRE_TIME_INFINITY;
diff --git a/source3/smbd/smb2_break.c b/source3/smbd/smb2_break.c
index 5eab0a1..4c5d62e 100644
--- a/source3/smbd/smb2_break.c
+++ b/source3/smbd/smb2_break.c
@@ -450,10 +450,10 @@ void send_break_message_smb2(files_struct *fsp,
 	 */
 	xconn = fsp->conn->sconn->client->connections;
 
-	status = smb2srv_session_lookup(xconn,
-					fsp->vuid,
-					now,
-					&session);
+	status = smb2srv_session_lookup_conn(xconn,
+					     fsp->vuid,
+					     now,
+					     &session);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED) ||
 	    (session == NULL))
 	{
diff --git a/source3/smbd/smb2_close.c b/source3/smbd/smb2_close.c
index 367c9fa..5830228 100644
--- a/source3/smbd/smb2_close.c
+++ b/source3/smbd/smb2_close.c
@@ -322,7 +322,6 @@ static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
 	state->in_flags = in_flags;
 
 	if (in_fsp->num_aio_requests != 0) {
-
 		in_fsp->deferred_close = tevent_wait_send(in_fsp, ev);
 		if (tevent_req_nomem(in_fsp->deferred_close, req)) {
 			return tevent_req_post(req, ev);
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 76d6d69..17bddc1 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -379,6 +379,7 @@ static NTSTATUS smbd_smb2_create_durable_lease_check(
 	const struct smb2_lease *lease_ptr)
 {
 	struct smb_filename *smb_fname = NULL;
+	uint32_t ucf_flags = UCF_PREP_CREATEFILE;
 	NTSTATUS status;
 
 	if (lease_ptr == NULL) {
@@ -404,7 +405,7 @@ static NTSTATUS smbd_smb2_create_durable_lease_check(
 	}
 
 	status = filename_convert(talloc_tos(), fsp->conn, false,
-				  requested_filename, UCF_PREP_CREATEFILE,
+				  requested_filename, ucf_flags,
 				  NULL, &smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(10, ("filename_convert returned %s\n",
@@ -473,7 +474,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	struct smb2_create_blob *dhnq = NULL;
 	struct smb2_create_blob *dh2q = NULL;
 	struct smb2_create_blob *rqls = NULL;
-	struct smbXsrv_open *op = NULL;
+	bool replay_operation = false;
 
 	if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
 		requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
@@ -554,10 +555,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		 * (Note that the cases of an additional dh2q or dh2c blob
 		 *  which require a different error code, have been treated
 		 *  above.)
-		 *
-		 * TODO:
-		 * This is only true for the oplock case:
-		 * For leases, lease request is required additionally.
 		 */
 
 		if (dhnq) {
@@ -594,10 +591,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		 * (Note that the cases of an additional dhnq, dhnc or dh2q
 		 *  blob which require a different error code, have been
 		 *  treated above.)
-		 *
-		 * TODO:
-		 * This is only true for the oplock case:
-		 * For leases, lease request is required additionally!
 		 */
 
 		num_blobs_allowed = 1;
@@ -675,7 +668,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		struct smb2_lease lease;
 		struct smb2_lease *lease_ptr = NULL;
 		ssize_t lease_len = -1;
+		bool need_replay_cache = false;
+		struct smbXsrv_open *op = NULL;
+#if 0
 		struct smb2_create_blob *svhdx = NULL;
+#endif
 
 		exta = smb2_create_blob_find(&in_context_blobs,
 					     SMB2_CREATE_TAG_EXTA);
@@ -689,6 +686,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					     SMB2_CREATE_TAG_TWRP);
 		qfid = smb2_create_blob_find(&in_context_blobs,
 					     SMB2_CREATE_TAG_QFID);
+#if 0
 		if (smb2req->xconn->protocol >= PROTOCOL_SMB3_02) {
 			/*
 			 * This was introduced with SMB3_02
@@ -696,6 +694,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			svhdx = smb2_create_blob_find(&in_context_blobs,
 						      SVHDX_OPEN_DEVICE_CONTEXT);
 		}
+#endif
 
 		fname = talloc_strdup(state, in_name);
 		if (tevent_req_nomem(fname, req)) {
@@ -781,6 +780,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			const uint8_t *p = dh2q->data.data;
 			uint32_t durable_v2_timeout = 0;
 			DATA_BLOB create_guid_blob;
+			const uint8_t *hdr;
+			uint32_t flags;
 
 			if (dh2q->data.length != 32) {
 				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -807,6 +808,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			update_open = true;
 
 			/*
+			 * And we need to create a cache for replaying the
+			 * create.
+			 */
+			need_replay_cache = true;
+
+			/*
 			 * durable handle v2 request processed below
 			 */
 			durable_requested = true;
@@ -819,6 +826,38 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 				 */
 				durable_timeout_msec = (60*1000);
 			}
+
+			/*
+			 * Check for replay operation.
+			 * Only consider it when we have dh2q.
+			 * If we do not have a replay operation, verify that
+			 * the create_guid is not cached for replay.
+			 */
+			hdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
+			flags = IVAL(hdr, SMB2_HDR_FLAGS);
+			replay_operation =
+				!!(flags & SMB2_HDR_FLAG_REPLAY_OPERATION);
+
+			status = smb2srv_open_lookup_replay_cache(
+					smb2req->xconn, create_guid,
+					0 /* now */, &op);
+
+			if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+				replay_operation = false;
+			} else if (tevent_req_nterror(req, status)) {
+				DBG_WARNING("smb2srv_open_lookup_replay_cache "
+					    "failed: %s\n", nt_errstr(status));
+				return tevent_req_post(req, ev);
+			} else if (!replay_operation) {
+				/*
+				 * If a create without replay operation flag
+				 * is sent but with a create_guid that is
+				 * currently in the replay cache -- fail.
+				 */
+				status = NT_STATUS_DUPLICATE_OBJECTID;
+				(void)tevent_req_nterror(req, status);
+				return tevent_req_post(req, ev);
+			}
 		}
 
 		if (dhnc) {
@@ -914,13 +953,32 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 				DEBUG(10, ("v2 lease key only for SMB3\n"));
 				lease_ptr = NULL;
 			}
-		}
 
-		if (svhdx != NULL) {
-			/* SharedVHD is not yet supported */
-			tevent_req_nterror(
-				req, NT_STATUS_INVALID_DEVICE_REQUEST);
-			return tevent_req_post(req, ev);
+			/*
+			 * Replay with a lease is only allowed if the
+			 * established open carries a lease with the
+			 * same lease key.
+			 */
+			if (replay_operation) {
+				struct smb2_lease *op_ls =
+						&op->compat->lease->lease;
+				int op_oplock = op->compat->oplock_type;
+
+				if (map_samba_oplock_levels_to_smb2(op_oplock)
+				    != SMB2_OPLOCK_LEVEL_LEASE)
+				{
+					status = NT_STATUS_ACCESS_DENIED;
+					(void)tevent_req_nterror(req, status);
+					return tevent_req_post(req, ev);
+				}
+				if (!smb2_lease_key_equal(&lease.lease_key,
+							  &op_ls->lease_key))
+				{
+					status = NT_STATUS_ACCESS_DENIED;
+					(void)tevent_req_nterror(req, status);
+					return tevent_req_post(req, ev);
+				}
+			}
 		}
 
 		/* these are ignored for SMB2 */
@@ -933,9 +991,16 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		/*
 		 * For the backend file open procedure, there are
-		 * two possible modes: durable_reconnect or not.
+		 * three possible modes: replay operation (in which case
+		 * there is nothing else to do), durable_reconnect or
+		 * new open.
 		 */
-		if (do_durable_reconnect) {
+		if (replay_operation) {
+			result = op->compat;
+			result->op = op;
+			update_open = false;
+			info = op->create_action;
+		} else if (do_durable_reconnect) {
 			DATA_BLOB new_cookie = data_blob_null;
 			NTTIME now = timeval_to_nttime(&smb2req->request_time);
 
@@ -1007,6 +1072,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			info = FILE_WAS_OPENED;
 		} else {
 			struct smb_filename *smb_fname = NULL;
+			uint32_t ucf_flags = UCF_PREP_CREATEFILE;
 
 			if (requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
 				if (lease_ptr == NULL) {
@@ -1034,7 +1100,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 						  smb1req->conn,
 						  smb1req->flags2 & FLAGS2_DFS_PATHNAMES,
 						  fname,
-						  UCF_PREP_CREATEFILE,
+						  ucf_flags,
 						  NULL, /* ppath_contains_wcards */
 						  &smb_fname);
 			if (!NT_STATUS_IS_OK(status)) {
@@ -1144,7 +1210,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			}
 		}
 
-		if (durable_requested &&
+		if (!replay_operation && durable_requested &&
 		    (fsp_lease_type(result) & SMB2_LEASE_HANDLE))
 		{
 			status = SMB_VFS_DURABLE_COOKIE(result,
@@ -1154,7 +1220,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 				op->global->backend_cookie = data_blob_null;
 			}
 		}
-		if (op->global->backend_cookie.length > 0) {
+		if (!replay_operation && op->global->backend_cookie.length > 0)
+		{
 			update_open = true;
 
 			op->global->durable = true;
@@ -1163,6 +1230,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		if (update_open) {
 			op->global->create_guid = _create_guid;
+			if (need_replay_cache) {
+				op->flags |= SMBXSRV_OPEN_NEED_REPLAY_CACHE;
+			}
 
 			status = smbXsrv_open_update(op);
 			DEBUG(10, ("smb2_create_send: smbXsrv_open_update "
@@ -1188,7 +1258,18 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			}
 		}
 
-		if (dh2q && op->global->durable) {
+		if (dh2q && op->global->durable &&
+		    /*
+		     * For replay operations, we return the dh2q blob
+		     * in the case of oplocks not based on the state of
+		     * the open, but on whether it could have been granted
+		     * for the request data. In the case of leases instead,
+		     * the state of the open is used...
+		     */
+		    (!replay_operation ||
+		     in_oplock_level == SMB2_OPLOCK_LEVEL_BATCH ||
+		     in_oplock_level == SMB2_OPLOCK_LEVEL_LEASE))
+		{
 			uint8_t p[8] = { 0, };
 			DATA_BLOB blob = data_blob_const(p, sizeof(p));
 			uint32_t durable_v2_response_flags = 0;
@@ -1260,7 +1341,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 	smb2req->compat_chain_fsp = smb1req->chain_fsp;
 
-	if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
+	if (replay_operation) {
+		state->out_oplock_level = in_oplock_level;
+	} else if (lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
 		state->out_oplock_level	= in_oplock_level;
 	} else {
 		state->out_oplock_level	= map_samba_oplock_levels_to_smb2(result->oplock_type);
@@ -1272,6 +1355,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	} else {
 		state->out_create_action = info;
 	}
+	result->op->create_action = state->out_create_action;
 	state->out_file_attributes = dos_mode(result->conn,
 					   result->fsp_name);
 
diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c
index 04a8710..00b0535 100644
--- a/source3/smbd/smb2_flush.c
+++ b/source3/smbd/smb2_flush.c
@@ -110,15 +110,18 @@ struct smbd_smb2_flush_state {
 	struct smbd_smb2_request *smb2req;
 };
 
+static void smbd_smb2_flush_done(struct tevent_req *subreq);
+
 static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
 					       struct tevent_context *ev,
 					       struct smbd_smb2_request *smb2req,
 					       struct files_struct *fsp)
 {
 	struct tevent_req *req;
+	struct tevent_req *subreq;
 	struct smbd_smb2_flush_state *state;
-	NTSTATUS status;
 	struct smb_request *smbreq;
+	int ret;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct smbd_smb2_flush_state);
@@ -145,16 +148,59 @@ static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	status = sync_file(smbreq->conn, fsp, true);
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(5,("smbd_smb2_flush: sync_file for %s returned %s\n",
-			 fsp_str_dbg(fsp), nt_errstr(status)));
-		tevent_req_nterror(req, status);
+	if (fsp->fh->fd == -1) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
+		return tevent_req_post(req, ev);
+	}
+
+	if (!lp_strict_sync(SNUM(smbreq->conn))) {
+		/*
+		 * No strict sync. Don't really do
+		 * anything here.
+		 */
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	ret = flush_write_cache(fsp, SAMBA_SYNC_FLUSH);
+	if (ret == -1) {
+		tevent_req_nterror(req,  map_nt_error_from_unix(errno));
+		return tevent_req_post(req, ev);
+	}
+
+	subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
+	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
 
+	tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
+
+	/* Ensure any close request knows about this outstanding IO. */
+	if (!aio_add_req_to_fsp(fsp, req)) {
+		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+		return tevent_req_post(req, ev);
+	}
+
+	increment_outstanding_aio_calls();
+	return req;
+
+}
+
+static void smbd_smb2_flush_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	int ret, err;
+
+	decrement_outstanding_aio_calls();
+
+	ret = SMB_VFS_FSYNC_RECV(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
 	tevent_req_done(req);
-	return tevent_req_post(req, ev);
 }
 
 static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
diff --git a/source3/smbd/smb2_ioctl_filesys.c b/source3/smbd/smb2_ioctl_filesys.c
index 187deaf..6e4a785 100644
--- a/source3/smbd/smb2_ioctl_filesys.c
+++ b/source3/smbd/smb2_ioctl_filesys.c
@@ -94,8 +94,7 @@ static NTSTATUS fsctl_set_cmprn(TALLOC_CTX *mem_ctx,
 	}
 
 	/* WRITE_DATA permission is required, WRITE_ATTRIBUTES is not */
-	status = check_access(fsp->conn, fsp, NULL,
-			      FILE_WRITE_DATA);
+	status = check_access_fsp(fsp, FILE_WRITE_DATA);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -141,7 +140,7 @@ static NTSTATUS fsctl_zero_data(TALLOC_CTX *mem_ctx,
 	}
 
 	/* WRITE_DATA permission is required */
-	status = check_access(fsp->conn, fsp, NULL, FILE_WRITE_DATA);
+	status = check_access_fsp(fsp, FILE_WRITE_DATA);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -333,7 +332,7 @@ static NTSTATUS fsctl_qar(TALLOC_CTX *mem_ctx,
 	}
 
 	/* READ_DATA permission is required */
-	status = check_access(fsp->conn, fsp, NULL, FILE_READ_DATA);
+	status = check_access_fsp(fsp, FILE_READ_DATA);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
diff --git a/source3/smbd/smb2_ioctl_network_fs.c b/source3/smbd/smb2_ioctl_network_fs.c
index 01798ac..d8590de 100644
--- a/source3/smbd/smb2_ioctl_network_fs.c
+++ b/source3/smbd/smb2_ioctl_network_fs.c
@@ -29,6 +29,7 @@
 #include "../librpc/ndr/libndr.h"
 #include "librpc/gen_ndr/ndr_ioctl.h"
 #include "smb2_ioctl_private.h"
+#include "../lib/tsocket/tsocket.h"
 
 #define COPYCHUNK_MAX_CHUNKS	256		/* 2k8r2 & win8 = 256 */
 #define COPYCHUNK_MAX_CHUNK_LEN	1048576		/* 2k8r2 & win8 = 1048576 */
@@ -379,6 +380,118 @@ static NTSTATUS fsctl_srv_copychunk_recv(struct tevent_req *req,
 	return status;
 }
 
+static NTSTATUS fsctl_network_iface_info(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct smbXsrv_connection *xconn,
+					 DATA_BLOB *in_input,
+					 uint32_t in_max_output,
+					 DATA_BLOB *out_output)
+{
+	struct fsctl_net_iface_info *array = NULL;
+	struct fsctl_net_iface_info *first = NULL;
+	struct fsctl_net_iface_info *last = NULL;
+	size_t i;
+	size_t num_ifaces = iface_count();
+	enum ndr_err_code ndr_err;
+
+	if (in_input->length != 0) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	*out_output = data_blob_null;
+
+	array = talloc_zero_array(mem_ctx,
+				  struct fsctl_net_iface_info,
+				  num_ifaces);
+	if (array == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	for (i=0; i < num_ifaces; i++) {
+		struct fsctl_net_iface_info *cur = &array[i];
+		const struct interface *iface = get_interface(i);
+		const struct sockaddr_storage *ifss = &iface->ip;
+		const void *ifptr = ifss;
+		const struct sockaddr *ifsa = (const struct sockaddr *)ifptr;
+		struct tsocket_address *a = NULL;
+		char *addr;
+		bool ok;
+		int ret;
+
+		ret = tsocket_address_bsd_from_sockaddr(array,
+					ifsa, sizeof(struct sockaddr_storage),
+					&a);
+		if (ret != 0) {
+			return map_nt_error_from_unix_common(errno);
+		}
+
+		ok = tsocket_address_is_inet(a, "ip");
+		if (!ok) {
+			continue;
+		}
+
+		addr = tsocket_address_inet_addr_string(a, array);
+		if (addr == NULL) {
+			TALLOC_FREE(array);
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		cur->ifindex = iface->if_index;
+		if (cur->ifindex == 0) {
+			/*
+			 * Did not get interface index from kernel,
+			 * nor from the config. ==> Apply a common
+			 * default value for these cases.
+			 */
+			cur->ifindex = UINT32_MAX;
+		}
+		cur->capability = iface->capability;
+		cur->linkspeed = iface->linkspeed;
+		if (cur->linkspeed == 0) {
+			DBG_DEBUG("Link speed 0 on interface [%s] - skipping "
+				  "address [%s].\n", iface->name, addr);
+			continue;
+		}
+
+		ok = tsocket_address_is_inet(a, "ipv4");
+		if (ok) {
+			cur->sockaddr.family = FSCTL_NET_IFACE_AF_INET;
+			cur->sockaddr.saddr.saddr_in.ipv4 = addr;
+		}
+		ok = tsocket_address_is_inet(a, "ipv6");
+		if (ok) {
+			cur->sockaddr.family = FSCTL_NET_IFACE_AF_INET6;
+			cur->sockaddr.saddr.saddr_in6.ipv6 = addr;
+		}
+
+		if (first == NULL) {
+			first = cur;
+		}
+		if (last != NULL) {
+			last->next = cur;
+		}
+		last = cur;
+	}
+
+	if (first == NULL) {
+		TALLOC_FREE(array);
+		return NT_STATUS_OK;
+	}
+
+	if (DEBUGLEVEL >= 10) {
+		NDR_PRINT_DEBUG(fsctl_net_iface_info, first);
+	}
+
+	ndr_err = ndr_push_struct_blob(out_output, mem_ctx, first,
+			(ndr_push_flags_fn_t)ndr_push_fsctl_net_iface_info);
+	TALLOC_FREE(array);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return ndr_map_error2ntstatus(ndr_err);
+	}
+
+	return NT_STATUS_OK;
+}
+
 static NTSTATUS fsctl_validate_neg_info(TALLOC_CTX *mem_ctx,
 				        struct tevent_context *ev,
 				        struct smbXsrv_connection *conn,
@@ -541,6 +654,29 @@ struct tevent_req *smb2_ioctl_network_fs(uint32_t ctl_code,
 					req);
 		return req;
 		break;
+	case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
+		if (!state->smbreq->xconn->client->server_multi_channel_enabled)
+		{
+			if (IS_IPC(state->smbreq->conn)) {
+				status = NT_STATUS_FS_DRIVER_REQUIRED;
+			} else {
+				status = NT_STATUS_INVALID_DEVICE_REQUEST;
+			}
+
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
+
+		status = fsctl_network_iface_info(state, ev,
+						  state->smbreq->xconn,
+						  &state->in_input,
+						  state->in_max_output,
+						  &state->out_output);
+		if (!tevent_req_nterror(req, status)) {
+			tevent_req_done(req);
+		}
+		return tevent_req_post(req, ev);
+		break;
 	case FSCTL_VALIDATE_NEGOTIATE_INFO:
 		status = fsctl_validate_neg_info(state, ev,
 						 state->smbreq->xconn,
diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c
index 18382a9..e48d2b8 100644
--- a/source3/smbd/smb2_negprot.c
+++ b/source3/smbd/smb2_negprot.c
@@ -60,7 +60,7 @@ static void reply_smb20xx(struct smb_request *req, uint16_t dialect)
 
 	req->outbuf = NULL;
 
-	smbd_smb2_first_negprot(req->xconn, smb2_inpdu, len);
+	smbd_smb2_process_negprot(req->xconn, 0, smb2_inpdu, len);
 	return;
 }
 
@@ -258,8 +258,15 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 		}
 	}
 
-	if (get_remote_arch() != RA_SAMBA) {
+	switch (get_remote_arch()) {
+	case RA_VISTA:
+	case RA_SAMBA:
+	case RA_CIFSFS:
+	case RA_OSX:
+		break;
+	default:
 		set_remote_arch(RA_VISTA);
+		break;
 	}
 
 	fstr_sprintf(remote_proto, "SMB%X_%02X",
@@ -485,6 +492,14 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 		xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM;
 	}
 
+	if (protocol >= PROTOCOL_SMB2_22 &&
+	    xconn->client->server_multi_channel_enabled)
+	{
+		if (in_capabilities & SMB2_CAP_MULTI_CHANNEL) {
+			capabilities |= SMB2_CAP_MULTI_CHANNEL;
+		}
+	}
+
 	security_offset = SMB2_HDR_BODY + 0x40;
 
 #if 1
@@ -579,6 +594,8 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 	req->sconn->using_smb2 = true;
 
 	if (dialect != SMB2_DIALECT_REVISION_2FF) {
+		struct smbXsrv_client_global0 *global0 = NULL;
+
 		status = smbXsrv_connection_init_tables(xconn, protocol);
 		if (!NT_STATUS_IS_OK(status)) {
 			return smbd_smb2_request_error(req, status);
@@ -605,6 +622,62 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 		xconn->smb2.server.max_trans = max_trans;
 		xconn->smb2.server.max_read  = max_read;
 		xconn->smb2.server.max_write = max_write;
+
+		if (xconn->protocol < PROTOCOL_SMB2_10) {
+			/*
+			 * SMB2_02 doesn't support client guids
+			 */
+			return smbd_smb2_request_done(req, outbody, &outdyn);
+		}
+
+		if (!xconn->client->server_multi_channel_enabled) {
+			/*
+			 * Only deal with the client guid database
+			 * if multi-channel is enabled.
+			 */
+			return smbd_smb2_request_done(req, outbody, &outdyn);
+		}
+
+		if (xconn->smb2.client.guid_verified) {
+			/*
+			 * The connection was passed from another
+			 * smbd process.
+			 */
+			return smbd_smb2_request_done(req, outbody, &outdyn);
+		}
+
+		status = smb2srv_client_lookup_global(xconn->client,
+						xconn->smb2.client.guid,
+						req, &global0);
+		/*
+		 * TODO: check for races...
+		 */
+		if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECTID_NOT_FOUND)) {
+			/*
+			 * This stores the new client information in
+			 * smbXsrv_client_global.tdb
+			 */
+			xconn->client->global->client_guid =
+						xconn->smb2.client.guid;
+			status = smbXsrv_client_update(xconn->client);
+			if (!NT_STATUS_IS_OK(status)) {
+				return status;
+			}
+
+			xconn->smb2.client.guid_verified = true;
+		} else if (NT_STATUS_IS_OK(status)) {
+			status = smb2srv_client_connection_pass(req,
+								global0);
+			if (!NT_STATUS_IS_OK(status)) {
+				return smbd_smb2_request_error(req, status);
+			}
+
+			smbd_server_connection_terminate(xconn,
+							 "passed connection");
+			return NT_STATUS_OBJECTID_EXISTS;
+		} else {
+			return smbd_smb2_request_error(req, status);
+		}
 	}
 
 	return smbd_smb2_request_done(req, outbody, &outdyn);
diff --git a/source3/smbd/smb2_query_directory.c b/source3/smbd/smb2_query_directory.c
index 81f2e17..4b6ca1b 100644
--- a/source3/smbd/smb2_query_directory.c
+++ b/source3/smbd/smb2_query_directory.c
@@ -225,7 +225,7 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
 	uint32_t dirtype = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY;
 	bool dont_descend = false;
 	bool ask_sharemode = true;
-	bool wcard_has_wild;
+	bool wcard_has_wild = false;
 	struct tm tm;
 	char *p;
 
@@ -325,7 +325,9 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
 		dptr_CloseDir(fsp);
 	}
 
-	wcard_has_wild = ms_has_wild(in_file_name);
+	if (!smbreq->posix_pathnames) {
+		wcard_has_wild = ms_has_wild(in_file_name);
+	}
 
 	/* Ensure we've canonicalized any search path if not a wildcard. */
 	if (!wcard_has_wild) {
@@ -333,6 +335,10 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
 		const char *fullpath;
 		char tmpbuf[PATH_MAX];
 		char *to_free = NULL;
+		uint32_t ucf_flags = UCF_SAVE_LCOMP |
+				     UCF_ALWAYS_ALLOW_WCARD_LCOMP |
+				     (smbreq->posix_pathnames ?
+					UCF_POSIX_PATHNAMES : 0);
 
 		if (ISDOT(fsp->fsp_name->base_name)) {
 			fullpath = in_file_name;
@@ -353,7 +359,7 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
 				conn,
 				false, /* Not a DFS path. */
 				fullpath,
-				UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP,
+				ucf_flags,
 				&wcard_has_wild,
 				&smb_fname);
 
diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c
index 03cd54b..89527f3 100644
--- a/source3/smbd/smb2_read.c
+++ b/source3/smbd/smb2_read.c
@@ -26,7 +26,7 @@
 #include "libcli/security/security.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "rpc_server/srv_pipe_hnd.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 
 static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx,
 					      struct tevent_context *ev,
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 09633a3..68d637e 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -200,11 +200,12 @@ bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
 	return true;
 }
 
-static NTSTATUS smbd_initialize_smb2(struct smbXsrv_connection *xconn)
+static NTSTATUS smbd_initialize_smb2(struct smbXsrv_connection *xconn,
+				     uint64_t expected_seq_low)
 {
 	TALLOC_FREE(xconn->transport.fde);
 
-	xconn->smb2.credits.seq_low = 0;
+	xconn->smb2.credits.seq_low = expected_seq_low;
 	xconn->smb2.credits.seq_range = 1;
 	xconn->smb2.credits.granted = 1;
 	xconn->smb2.credits.max = lp_smb2_max_credits();
@@ -393,7 +394,8 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *xconn,
 				goto inval;
 			}
 
-			status = smb2srv_session_lookup(xconn, uid, now, &s);
+			status = smb2srv_session_lookup_conn(xconn, uid, now,
+							     &s);
 			if (s == NULL) {
 				DEBUG(1, ("invalid session[%llu] in "
 					  "SMB2_TRANSFORM header\n",
@@ -1048,7 +1050,7 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
 		return NT_STATUS_INVALID_PARAMETER_MIX;
 	}
 
-	DLIST_ADD_END(xconn->smb2.requests, req, struct smbd_smb2_request *);
+	DLIST_ADD_END(xconn->smb2.requests, req);
 
 	return NT_STATUS_OK;
 }
@@ -1057,8 +1059,21 @@ void smbd_server_connection_terminate_ex(struct smbXsrv_connection *xconn,
 					 const char *reason,
 					 const char *location)
 {
-	DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
-		  reason, location));
+	struct smbXsrv_client *client = xconn->client;
+
+	DEBUG(10,("smbd_server_connection_terminate_ex: conn[%s] reason[%s] at %s\n",
+		  smbXsrv_connection_dbg(xconn), reason, location));
+
+	if (client->connections->next != NULL) {
+		/* TODO: cancel pending requests */
+		DLIST_REMOVE(client->connections, xconn);
+		TALLOC_FREE(xconn);
+		return;
+	}
+
+	/*
+	 * The last connection was disconnected
+	 */
 	exit_server_cleanly(reason);
 }
 
@@ -1289,7 +1304,7 @@ static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request
 	nreq->queue_entry.mem_ctx = nreq;
 	nreq->queue_entry.vector = nreq->out.vector;
 	nreq->queue_entry.count = nreq->out.vector_count;
-	DLIST_ADD_END(xconn->smb2.send_queue, &nreq->queue_entry, NULL);
+	DLIST_ADD_END(xconn->smb2.send_queue, &nreq->queue_entry);
 	xconn->smb2.send_queue_len++;
 
 	status = smbd_smb2_flush_send_queue(xconn);
@@ -1676,7 +1691,7 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
 	state->queue_entry.mem_ctx = state;
 	state->queue_entry.vector = state->vector;
 	state->queue_entry.count = ARRAY_SIZE(state->vector);
-	DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry, NULL);
+	DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry);
 	xconn->smb2.send_queue_len++;
 
 	status = smbd_smb2_flush_send_queue(xconn);
@@ -1833,10 +1848,26 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
 
 	req->last_session_id = 0;
 
-	/* lookup an existing session */
-	status = smb2srv_session_lookup(req->xconn,
-					in_session_id, now,
-					&session);
+	/* look an existing session up */
+	switch (in_opcode) {
+	case SMB2_OP_SESSSETUP:
+		/*
+		 * For a session bind request, we don't have the
+		 * channel set up at this point yet, so we defer
+		 * the verification that the connection belongs
+		 * to the session to the session setup code, which
+		 * can look at the session binding flags.
+		 */
+		status = smb2srv_session_lookup_client(req->xconn->client,
+						       in_session_id, now,
+						       &session);
+		break;
+	default:
+		status = smb2srv_session_lookup_conn(req->xconn,
+						     in_session_id, now,
+						     &session);
+		break;
+	}
 	if (session) {
 		req->session = session;
 		req->last_session_id = in_session_id;
@@ -1986,6 +2017,96 @@ NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
 	return NT_STATUS_OK;
 }
 
+bool smbXsrv_is_encrypted(uint8_t encryption_flags)
+{
+	return (!(encryption_flags & SMBXSRV_PROCESSED_UNENCRYPTED_PACKET)
+		&&
+		(encryption_flags & (SMBXSRV_PROCESSED_ENCRYPTED_PACKET |
+				     SMBXSRV_ENCRYPTION_DESIRED |
+				     SMBXSRV_ENCRYPTION_REQUIRED)));
+}
+
+bool smbXsrv_is_partially_encrypted(uint8_t encryption_flags)
+{
+	return ((encryption_flags & SMBXSRV_PROCESSED_ENCRYPTED_PACKET) &&
+		(encryption_flags & SMBXSRV_PROCESSED_UNENCRYPTED_PACKET));
+}
+
+/* Set a flag if not already set, return true if set */
+bool smbXsrv_set_crypto_flag(uint8_t *flags, uint8_t flag)
+{
+	if ((flag == 0) || (*flags & flag)) {
+		return false;
+	}
+
+	*flags |= flag;
+	return true;
+}
+
+/*
+ * Update encryption state tracking flags, this can be used to
+ * determine whether whether the session or tcon is "encrypted".
+ */
+static void smb2srv_update_crypto_flags(struct smbd_smb2_request *req,
+					uint16_t opcode,
+					bool *update_session_globalp,
+					bool *update_tcon_globalp)
+{
+	/* Default: assume unecrypted and unsigned */
+	struct smbXsrv_session *session = req->session;
+	struct smbXsrv_tcon *tcon = req->tcon;
+	uint8_t encrypt_flag = SMBXSRV_PROCESSED_UNENCRYPTED_PACKET;
+	uint8_t sign_flag = SMBXSRV_PROCESSED_UNSIGNED_PACKET;
+	bool update_session = false;
+	bool update_tcon = false;
+
+	if (req->was_encrypted && req->do_encryption) {
+		encrypt_flag = SMBXSRV_PROCESSED_ENCRYPTED_PACKET;
+		sign_flag = SMBXSRV_PROCESSED_SIGNED_PACKET;
+	} else {
+		/* Unencrypted packet, can be signed */
+		if (req->do_signing) {
+			sign_flag = SMBXSRV_PROCESSED_SIGNED_PACKET;
+		} else if (opcode == SMB2_OP_CANCEL) {
+			/* Cancel requests are allowed to skip signing */
+			sign_flag &= ~SMBXSRV_PROCESSED_UNSIGNED_PACKET;
+		}
+	}
+
+	update_session |= smbXsrv_set_crypto_flag(
+		&session->global->encryption_flags, encrypt_flag);
+	update_session |= smbXsrv_set_crypto_flag(
+		&session->global->signing_flags, sign_flag);
+
+	if (tcon) {
+		update_tcon |= smbXsrv_set_crypto_flag(
+			&tcon->global->encryption_flags, encrypt_flag);
+		update_tcon |= smbXsrv_set_crypto_flag(
+			&tcon->global->signing_flags, sign_flag);
+	}
+
+	*update_session_globalp = update_session;
+	*update_tcon_globalp = update_tcon;
+	return;
+}
+
+bool smbXsrv_is_signed(uint8_t signing_flags)
+{
+	/*
+	 * Signing is always enabled, so unless we got an unsigned
+	 * packet and at least one signed packet that was not
+	 * encrypted, the session or tcon is "signed".
+	 */
+	return (!(signing_flags & SMBXSRV_PROCESSED_UNSIGNED_PACKET) &&
+		(signing_flags & SMBXSRV_PROCESSED_SIGNED_PACKET));
+}
+
+bool smbXsrv_is_partially_signed(uint8_t signing_flags)
+{
+	return ((signing_flags & SMBXSRV_PROCESSED_UNSIGNED_PACKET) &&
+		(signing_flags & SMBXSRV_PROCESSED_SIGNED_PACKET));
+}
+
 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 {
 	struct smbXsrv_connection *xconn = req->xconn;
@@ -2048,9 +2169,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 	session_status = smbd_smb2_request_check_session(req);
 	x = req->session;
 	if (x != NULL) {
-		signing_required = x->global->signing_required;
-		encryption_desired = x->encryption_desired;
-		encryption_required = x->global->encryption_required;
+		signing_required = x->global->signing_flags & SMBXSRV_SIGNING_REQUIRED;
+		encryption_desired = x->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED;
+		encryption_required = x->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED;
 	}
 
 	req->do_signing = false;
@@ -2104,6 +2225,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 	if (opcode == SMB2_OP_CANCEL) {
 		allowed_flags |= SMB2_HDR_FLAG_ASYNC;
 	}
+	if (xconn->protocol >= PROTOCOL_SMB2_22) {
+		allowed_flags |= SMB2_HDR_FLAG_REPLAY_OPERATION;
+	}
 	if ((flags & ~allowed_flags) != 0) {
 		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
 	}
@@ -2206,10 +2330,10 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 		if (!NT_STATUS_IS_OK(status)) {
 			return smbd_smb2_request_error(req, status);
 		}
-		if (req->tcon->encryption_desired) {
+		if (req->tcon->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED) {
 			encryption_desired = true;
 		}
-		if (req->tcon->global->encryption_required) {
+		if (req->tcon->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED) {
 			encryption_required = true;
 		}
 		if (encryption_required && !req->was_encrypted) {
@@ -2222,6 +2346,28 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 		req->do_encryption = true;
 	}
 
+	if (req->session) {
+		bool update_session_global = false;
+		bool update_tcon_global = false;
+
+		smb2srv_update_crypto_flags(req, opcode,
+					    &update_session_global,
+					    &update_tcon_global);
+
+		if (update_session_global) {
+			status = smbXsrv_session_update(x);
+			if (!NT_STATUS_IS_OK(status)) {
+				return smbd_smb2_request_error(req, status);
+			}
+		}
+		if (update_tcon_global) {
+			status = smbXsrv_tcon_update(req->tcon);
+			if (!NT_STATUS_IS_OK(status)) {
+				return smbd_smb2_request_error(req, status);
+			}
+		}
+	}
+
 	if (call->fileid_ofs != 0) {
 		size_t needed = call->fileid_ofs + 16;
 		const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
@@ -2619,7 +2765,7 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
 	req->queue_entry.mem_ctx = req;
 	req->queue_entry.vector = req->out.vector;
 	req->queue_entry.count = req->out.vector_count;
-	DLIST_ADD_END(xconn->smb2.send_queue, &req->queue_entry, NULL);
+	DLIST_ADD_END(xconn->smb2.send_queue, &req->queue_entry);
 	xconn->smb2.send_queue_len++;
 
 	status = smbd_smb2_flush_send_queue(xconn);
@@ -2784,9 +2930,9 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
 	uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
 	size_t unread_bytes = smbd_smb2_unread_bytes(req);
 
-	DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
-		  req->current_idx, nt_errstr(status), info ? " +info" : "",
-		  location));
+	DBG_NOTICE("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| "
+		   "at %s\n", req->current_idx, nt_errstr(status),
+		   info ? " +info" : "", location);
 
 	if (unread_bytes) {
 		/* Recvfile error. Drain incoming socket. */
@@ -2864,8 +3010,8 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
 
 	if (session != NULL) {
 		session_wire_id = session->global->session_wire_id;
-		do_encryption = session->encryption_desired;
-		if (tcon->encryption_desired) {
+		do_encryption = session->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED;
+		if (tcon->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED) {
 			do_encryption = true;
 		}
 	}
@@ -2961,7 +3107,7 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
 	state->queue_entry.mem_ctx = state;
 	state->queue_entry.vector = state->vector;
 	state->queue_entry.count = ARRAY_SIZE(state->vector);
-	DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry, NULL);
+	DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry);
 	xconn->smb2.send_queue_len++;
 
 	status = smbd_smb2_flush_send_queue(xconn);
@@ -3143,8 +3289,9 @@ static NTSTATUS smbd_smb2_request_next_incoming(struct smbXsrv_connection *xconn
 	return NT_STATUS_OK;
 }
 
-void smbd_smb2_first_negprot(struct smbXsrv_connection *xconn,
-			     const uint8_t *inpdu, size_t size)
+void smbd_smb2_process_negprot(struct smbXsrv_connection *xconn,
+			       uint64_t expected_seq_low,
+			       const uint8_t *inpdu, size_t size)
 {
 	struct smbd_server_connection *sconn = xconn->client->sconn;
 	NTSTATUS status;
@@ -3153,7 +3300,7 @@ void smbd_smb2_first_negprot(struct smbXsrv_connection *xconn,
 	DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
 		 (unsigned int)size));
 
-	status = smbd_initialize_smb2(xconn);
+	status = smbd_initialize_smb2(xconn, expected_seq_low);
 	if (!NT_STATUS_IS_OK(status)) {
 		smbd_server_connection_terminate(xconn, nt_errstr(status));
 		return;
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index 11d381f..a95f8a1 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -177,6 +177,7 @@ static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq)
 }
 
 static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
+					struct smbXsrv_session_auth0 **_auth,
 					struct smbd_smb2_request *smb2req,
 					uint8_t in_security_mode,
 					struct auth_session_info *session_info,
@@ -187,7 +188,9 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
 	bool guest = false;
 	uint8_t session_key[16];
 	struct smbXsrv_session *x = session;
+	struct smbXsrv_session_auth0 *auth = *_auth;
 	struct smbXsrv_connection *xconn = smb2req->xconn;
+	size_t i;
 	struct _derivation {
 		DATA_BLOB label;
 		DATA_BLOB context;
@@ -199,14 +202,15 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
 		struct _derivation application;
 	} derivation = { };
 
+	*_auth = NULL;
+
 	if (xconn->protocol >= PROTOCOL_SMB3_10) {
 		struct smbXsrv_preauth *preauth;
 		struct _derivation *d;
 		DATA_BLOB p;
 		struct hc_sha512state sctx;
-		size_t i;
 
-		preauth = talloc_move(smb2req, &session->preauth);
+		preauth = talloc_move(smb2req, &auth->preauth);
 
 		samba_SHA512_Init(&sctx);
 		samba_SHA512_Update(&sctx, preauth->sha512_value,
@@ -259,17 +263,17 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
 
 	if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
 	    lp_server_signing() == SMB_SIGNING_REQUIRED) {
-		x->global->signing_required = true;
+		x->global->signing_flags = SMBXSRV_SIGNING_REQUIRED;
 	}
 
 	if ((lp_smb_encrypt(-1) >= SMB_SIGNING_DESIRED) &&
 	    (xconn->smb2.client.capabilities & SMB2_CAP_ENCRYPTION)) {
-		x->encryption_desired = true;
+		x->global->encryption_flags = SMBXSRV_ENCRYPTION_DESIRED;
 	}
 
 	if (lp_smb_encrypt(-1) == SMB_SIGNING_REQUIRED) {
-		x->encryption_desired = true;
-		x->global->encryption_required = true;
+		x->global->encryption_flags = SMBXSRV_ENCRYPTION_REQUIRED |
+			SMBXSRV_ENCRYPTION_DESIRED;
 	}
 
 	if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
@@ -277,25 +281,27 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
 		*out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
 		*out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
 		/* force no signing */
-		x->global->signing_required = false;
+		x->global->signing_flags &= ~SMBXSRV_SIGNING_REQUIRED;
 		guest = true;
 	}
 
-	if (guest && x->global->encryption_required) {
+	if (guest && (x->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED)) {
 		DEBUG(1,("reject guest session as encryption is required\n"));
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
 	if (xconn->smb2.server.cipher == 0) {
-		if (x->global->encryption_required) {
+		if (x->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED) {
 			DEBUG(1,("reject session with dialect[0x%04X] "
 				 "as encryption is required\n",
 				 xconn->smb2.server.dialect));
 			return NT_STATUS_ACCESS_DENIED;
 		}
+	} else {
+		x->global->channels[0].encryption_cipher = xconn->smb2.server.cipher;
 	}
 
-	if (x->encryption_desired) {
+	if (x->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED) {
 		*out_session_flags |= SMB2_SESSION_FLAG_ENCRYPT_DATA;
 	}
 
@@ -435,12 +441,18 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
 	reload_services(smb2req->sconn, conn_snum_used, true);
 
 	session->status = NT_STATUS_OK;
-	session->global->auth_session_info = session_info;
+	session->global->auth_session_info = talloc_move(session->global,
+							 &session_info);
 	session->global->auth_session_info_seqnum += 1;
-	session->global->channels[0].auth_session_info_seqnum =
-		session->global->auth_session_info_seqnum;
+	for (i=0; i < session->global->num_channels; i++) {
+		struct smbXsrv_channel_global0 *_c =
+			&session->global->channels[i];
+
+		_c->auth_session_info_seqnum =
+			session->global->auth_session_info_seqnum;
+	}
 	session->global->auth_time = timeval_to_nttime(&smb2req->request_time);
-	session->global->expiration_time = gensec_expire_time(session->gensec);
+	session->global->expiration_time = gensec_expire_time(auth->gensec);
 
 	if (!session_claim(session)) {
 		DEBUG(1, ("smb2: Failed to claim session "
@@ -449,6 +461,7 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
 		return NT_STATUS_LOGON_FAILURE;
 	}
 
+	TALLOC_FREE(auth);
 	status = smbXsrv_session_update(session);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
@@ -473,6 +486,7 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
 }
 
 static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session,
+					struct smbXsrv_session_auth0 **_auth,
 					struct smbd_smb2_request *smb2req,
 					struct auth_session_info *session_info,
 					uint16_t *out_session_flags,
@@ -480,6 +494,11 @@ static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session,
 {
 	NTSTATUS status;
 	struct smbXsrv_session *x = session;
+	struct smbXsrv_session_auth0 *auth = *_auth;
+	struct smbXsrv_connection *xconn = smb2req->xconn;
+	size_t i;
+
+	*_auth = NULL;
 
 	data_blob_clear_free(&session_info->session_key);
 	session_info->session_key = data_blob_dup_talloc(session_info,
@@ -502,13 +521,20 @@ static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session,
 
 	session->status = NT_STATUS_OK;
 	TALLOC_FREE(session->global->auth_session_info);
-	session->global->auth_session_info = session_info;
+	session->global->auth_session_info = talloc_move(session->global,
+							 &session_info);
 	session->global->auth_session_info_seqnum += 1;
-	session->global->channels[0].auth_session_info_seqnum =
-		session->global->auth_session_info_seqnum;
+	for (i=0; i < session->global->num_channels; i++) {
+		struct smbXsrv_channel_global0 *_c =
+			&session->global->channels[i];
+
+		_c->auth_session_info_seqnum =
+			session->global->auth_session_info_seqnum;
+	}
 	session->global->auth_time = timeval_to_nttime(&smb2req->request_time);
-	session->global->expiration_time = gensec_expire_time(session->gensec);
+	session->global->expiration_time = gensec_expire_time(auth->gensec);
 
+	TALLOC_FREE(auth);
 	status = smbXsrv_session_update(session);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
@@ -517,7 +543,7 @@ static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session,
 		return NT_STATUS_LOGON_FAILURE;
 	}
 
-	conn_clear_vuid_caches(smb2req->sconn, session->compat->vuid);
+	conn_clear_vuid_caches(xconn->client->sconn, session->compat->vuid);
 
 	if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
 		smb2req->do_signing = true;
@@ -528,6 +554,116 @@ static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session,
 	return NT_STATUS_OK;
 }
 
+static NTSTATUS smbd_smb2_bind_auth_return(struct smbXsrv_session *session,
+					   struct smbXsrv_session_auth0 **_auth,
+					   struct smbd_smb2_request *smb2req,
+					   struct auth_session_info *session_info,
+					   uint16_t *out_session_flags,
+					   uint64_t *out_session_id)
+{
+	NTSTATUS status;
+	struct smbXsrv_session *x = session;
+	struct smbXsrv_session_auth0 *auth = *_auth;
+	struct smbXsrv_connection *xconn = smb2req->xconn;
+	struct smbXsrv_channel_global0 *c = NULL;
+	uint8_t session_key[16];
+	size_t i;
+	struct _derivation {
+		DATA_BLOB label;
+		DATA_BLOB context;
+	};
+	struct {
+		struct _derivation signing;
+	} derivation = { };
+	bool ok;
+
+	*_auth = NULL;
+
+	if (xconn->protocol >= PROTOCOL_SMB3_10) {
+		struct smbXsrv_preauth *preauth;
+		struct _derivation *d;
+		DATA_BLOB p;
+		struct hc_sha512state sctx;
+
+		preauth = talloc_move(smb2req, &auth->preauth);
+
+		samba_SHA512_Init(&sctx);
+		samba_SHA512_Update(&sctx, preauth->sha512_value,
+				    sizeof(preauth->sha512_value));
+		for (i = 1; i < smb2req->in.vector_count; i++) {
+			samba_SHA512_Update(&sctx,
+					    smb2req->in.vector[i].iov_base,
+					    smb2req->in.vector[i].iov_len);
+		}
+		samba_SHA512_Final(preauth->sha512_value, &sctx);
+
+		p = data_blob_const(preauth->sha512_value,
+				    sizeof(preauth->sha512_value));
+
+		d = &derivation.signing;
+		d->label = data_blob_string_const_null("SMBSigningKey");
+		d->context = p;
+
+	} else if (xconn->protocol >= PROTOCOL_SMB2_24) {
+		struct _derivation *d;
+
+		d = &derivation.signing;
+		d->label = data_blob_string_const_null("SMB2AESCMAC");
+		d->context = data_blob_string_const_null("SmbSign");
+	}
+
+	status = smbXsrv_session_find_channel(session, xconn, &c);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	ok = security_token_is_sid(session_info->security_token,
+			&x->global->auth_session_info->security_token->sids[0]);
+	if (!ok) {
+		return NT_STATUS_NOT_SUPPORTED;
+	}
+
+	if (session_info->session_key.length == 0) {
+		/* See [MS-SMB2] 3.3.5.2.4 for the return code. */
+		return NT_STATUS_NOT_SUPPORTED;
+	}
+
+	ZERO_STRUCT(session_key);
+	memcpy(session_key, session_info->session_key.data,
+	       MIN(session_info->session_key.length, sizeof(session_key)));
+
+	c->signing_key = data_blob_talloc(x->global,
+					  session_key,
+					  sizeof(session_key));
+	if (c->signing_key.data == NULL) {
+		ZERO_STRUCT(session_key);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	if (xconn->protocol >= PROTOCOL_SMB2_24) {
+		struct _derivation *d = &derivation.signing;
+
+		smb2_key_derivation(session_key, sizeof(session_key),
+				    d->label.data, d->label.length,
+				    d->context.data, d->context.length,
+				    c->signing_key.data);
+	}
+	ZERO_STRUCT(session_key);
+
+	TALLOC_FREE(auth);
+	status = smbXsrv_session_update(session);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
+			  (unsigned long long)session->compat->vuid,
+			  nt_errstr(status)));
+		return NT_STATUS_LOGON_FAILURE;
+	}
+
+	*out_session_id = session->global->session_wire_id;
+
+	return NT_STATUS_OK;
+}
+
 struct smbd_smb2_session_setup_state {
 	struct tevent_context *ev;
 	struct smbd_smb2_request *smb2req;
@@ -537,6 +673,7 @@ struct smbd_smb2_session_setup_state {
 	uint64_t in_previous_session_id;
 	DATA_BLOB in_security_buffer;
 	struct smbXsrv_session *session;
+	struct smbXsrv_session_auth0 *auth;
 	struct auth_session_info *session_info;
 	uint16_t out_session_flags;
 	DATA_BLOB out_security_buffer;
@@ -561,6 +698,8 @@ static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
 	NTSTATUS status;
 	NTTIME now = timeval_to_nttime(&smb2req->request_time);
 	struct tevent_req *subreq;
+	struct smbXsrv_channel_global0 *c = NULL;
+	enum security_user_level seclvl;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct smbd_smb2_session_setup_state);
@@ -581,13 +720,87 @@ static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
 			return tevent_req_post(req, ev);
 		}
 
+		if (!smb2req->xconn->client->server_multi_channel_enabled) {
+			tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
+			return tevent_req_post(req, ev);
+		}
+
+		if (in_session_id == 0) {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
+		}
+
+		if (smb2req->session == NULL) {
+			tevent_req_nterror(req, NT_STATUS_USER_SESSION_DELETED);
+			return tevent_req_post(req, ev);
+		}
+
+		if (!smb2req->do_signing) {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
+		}
+
+		status = smbXsrv_session_find_channel(smb2req->session,
+						      smb2req->xconn,
+						      &c);
+		if (NT_STATUS_IS_OK(status)) {
+			if (c->signing_key.length == 0) {
+				goto auth;
+			}
+			tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
+			return tevent_req_post(req, ev);
+		}
+
 		/*
-		 * We do not support multi channel.
+		 * OLD: 3.00 NEW 3.02 => INVALID_PARAMETER
+		 * OLD: 3.02 NEW 3.00 => INVALID_PARAMETER
+		 * OLD: 2.10 NEW 3.02 => ACCESS_DENIED
+		 * OLD: 3.02 NEW 2.10 => ACCESS_DENIED
 		 */
-		tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
-		return tevent_req_post(req, ev);
+		if (smb2req->session->global->connection_dialect
+		    < SMB2_DIALECT_REVISION_222)
+		{
+			tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+			return tevent_req_post(req, ev);
+		}
+		if (smb2req->xconn->smb2.server.dialect
+		    < SMB2_DIALECT_REVISION_222)
+		{
+			tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+			return tevent_req_post(req, ev);
+		}
+		if (smb2req->session->global->connection_dialect
+		    != smb2req->xconn->smb2.server.dialect)
+		{
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
+		}
+
+		seclvl = security_session_user_level(
+				smb2req->session->global->auth_session_info,
+				NULL);
+		if (seclvl < SECURITY_USER) {
+			tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
+			return tevent_req_post(req, ev);
+		}
+
+		status = smbXsrv_session_add_channel(smb2req->session,
+						     smb2req->xconn,
+						     &c);
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
+
+		status = smbXsrv_session_update(smb2req->session);
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
 	}
 
+auth:
+
 	if (state->in_session_id == 0) {
 		/* create a new session */
 		status = smbXsrv_session_create(state->smb2req->xconn,
@@ -607,38 +820,62 @@ static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
 		if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
 			status = NT_STATUS_OK;
 		}
-		if (NT_STATUS_IS_OK(status)) {
+		if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+			status = NT_STATUS_OK;
+		}
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
+		if (!(in_flags & SMB2_SESSION_FLAG_BINDING)) {
 			state->session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
-			status = NT_STATUS_MORE_PROCESSING_REQUIRED;
-			TALLOC_FREE(state->session->gensec);
 		}
-		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-			tevent_req_nterror(req, status);
+	}
+
+	status = smbXsrv_session_find_channel(smb2req->session,
+					      smb2req->xconn, &c);
+	if (!NT_STATUS_IS_OK(status)) {
+		tevent_req_nterror(req, status);
+		return tevent_req_post(req, ev);
+	}
+
+	status = smbXsrv_session_find_auth(state->session, smb2req->xconn,
+					   now, &state->auth);
+	if (!NT_STATUS_IS_OK(status)) {
+		status = smbXsrv_session_create_auth(state->session,
+						     smb2req->xconn, now,
+						     in_flags, in_security_mode,
+						     &state->auth);
+		if (tevent_req_nterror(req, status)) {
 			return tevent_req_post(req, ev);
 		}
 	}
 
-	if (state->session->gensec == NULL) {
-		status = auth_generic_prepare(state->session,
+	if (state->auth->gensec == NULL) {
+		status = auth_generic_prepare(state->auth,
 					      state->smb2req->xconn->remote_address,
-					      &state->session->gensec);
+					      &state->auth->gensec);
 		if (tevent_req_nterror(req, status)) {
 			return tevent_req_post(req, ev);
 		}
 
-		gensec_want_feature(state->session->gensec, GENSEC_FEATURE_SESSION_KEY);
-		gensec_want_feature(state->session->gensec, GENSEC_FEATURE_UNIX_TOKEN);
+		gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_SESSION_KEY);
+		gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_UNIX_TOKEN);
 
-		status = gensec_start_mech_by_oid(state->session->gensec,
+		status = gensec_start_mech_by_oid(state->auth->gensec,
 						  GENSEC_OID_SPNEGO);
 		if (tevent_req_nterror(req, status)) {
 			return tevent_req_post(req, ev);
 		}
 	}
 
+	status = smbXsrv_session_update(state->session);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
 	become_root();
 	subreq = gensec_update_send(state, state->ev,
-				    state->session->gensec,
+				    state->auth->gensec,
 				    state->in_security_buffer);
 	unbecome_root();
 	if (tevent_req_nomem(subreq, req)) {
@@ -672,13 +909,13 @@ static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq)
 
 	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 		state->out_session_id = state->session->global->session_wire_id;
-		state->smb2req->preauth = state->session->preauth;
+		state->smb2req->preauth = state->auth->preauth;
 		tevent_req_nterror(req, status);
 		return;
 	}
 
-	status = gensec_session_info(state->session->gensec,
-				     state->session->global,
+	status = gensec_session_info(state->auth->gensec,
+				     state,
 				     &state->session_info);
 	if (tevent_req_nterror(req, status)) {
 		return;
@@ -728,8 +965,23 @@ static void smbd_smb2_session_setup_auth_return(struct tevent_req *req)
 		struct smbd_smb2_session_setup_state);
 	NTSTATUS status;
 
+	if (state->in_flags & SMB2_SESSION_FLAG_BINDING) {
+		status = smbd_smb2_bind_auth_return(state->session,
+						    &state->auth,
+						    state->smb2req,
+						    state->session_info,
+						    &state->out_session_flags,
+						    &state->out_session_id);
+		if (tevent_req_nterror(req, status)) {
+			return;
+		}
+		tevent_req_done(req);
+		return;
+	}
+
 	if (state->session->global->auth_session_info != NULL) {
 		status = smbd_smb2_reauth_generic_return(state->session,
+							 &state->auth,
 							 state->smb2req,
 							 state->session_info,
 							 &state->out_session_flags,
@@ -742,6 +994,7 @@ static void smbd_smb2_session_setup_auth_return(struct tevent_req *req)
 	}
 
 	status = smbd_smb2_auth_generic_return(state->session,
+					       &state->auth,
 					       state->smb2req,
 					       state->in_security_mode,
 					       state->session_info,
diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c
index 99e2f21..61e2a36 100644
--- a/source3/smbd/smb2_tcon.c
+++ b/source3/smbd/smb2_tcon.c
@@ -193,8 +193,8 @@ static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
 	connection_struct *compat_conn = NULL;
 	struct user_struct *compat_vuser = req->session->compat;
 	NTSTATUS status;
-	bool encryption_desired = req->session->encryption_desired;
-	bool encryption_required = req->session->global->encryption_required;
+	bool encryption_desired = req->session->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED;
+	bool encryption_required = req->session->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED;
 	bool guest_session = false;
 	bool require_signed_tcon = false;
 
@@ -298,8 +298,12 @@ static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
 		return status;
 	}
 
-	tcon->encryption_desired = encryption_desired;
-	tcon->global->encryption_required = encryption_required;
+	if (encryption_desired) {
+		tcon->global->encryption_flags |= SMBXSRV_ENCRYPTION_DESIRED;
+	}
+	if (encryption_required) {
+		tcon->global->encryption_flags |= SMBXSRV_ENCRYPTION_REQUIRED;
+	}
 
 	compat_conn = make_connection_smb2(req,
 					tcon, snum,
diff --git a/source3/smbd/smbXsrv_client.c b/source3/smbd/smbXsrv_client.c
new file mode 100644
index 0000000..7286b6e
--- /dev/null
+++ b/source3/smbd/smbXsrv_client.c
@@ -0,0 +1,781 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2014
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include <tevent.h>
+#include "smbd/smbd.h"
+#include "smbd/globals.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_rbt.h"
+#include "dbwrap/dbwrap_open.h"
+#include "dbwrap/dbwrap_watch.h"
+#include "session.h"
+#include "auth.h"
+#include "auth/gensec/gensec.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../libcli/security/security.h"
+#include "messages.h"
+#include "lib/util/util_tdb.h"
+#include "librpc/gen_ndr/ndr_smbXsrv.h"
+#include "serverid.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/util/iov_buf.h"
+
+struct smbXsrv_client_table {
+	struct {
+		uint32_t max_clients;
+		uint32_t num_clients;
+	} local;
+	struct {
+		struct db_context *db_ctx;
+	} global;
+};
+
+static struct db_context *smbXsrv_client_global_db_ctx = NULL;
+
+NTSTATUS smbXsrv_client_global_init(void)
+{
+	const char *global_path = NULL;
+	struct db_context *db_ctx = NULL;
+
+	if (smbXsrv_client_global_db_ctx != NULL) {
+		return NT_STATUS_OK;
+	}
+
+	/*
+	 * This contains secret information like client keys!
+	 */
+	global_path = lock_path("smbXsrv_client_global.tdb");
+	if (global_path == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	db_ctx = db_open(NULL, global_path,
+			 0, /* hash_size */
+			 TDB_DEFAULT |
+			 TDB_CLEAR_IF_FIRST |
+			 TDB_INCOMPATIBLE_HASH,
+			 O_RDWR | O_CREAT, 0600,
+			 DBWRAP_LOCK_ORDER_1,
+			 DBWRAP_FLAG_NONE);
+	if (db_ctx == NULL) {
+		NTSTATUS status;
+
+		status = map_nt_error_from_unix_common(errno);
+
+		return status;
+	}
+
+	smbXsrv_client_global_db_ctx = db_ctx;
+
+	return NT_STATUS_OK;
+}
+
+/*
+ * NOTE:
+ * We need to store the keys in big endian so that dbwrap_rbt's memcmp
+ * has the same result as integer comparison between the uint32_t
+ * values.
+ *
+ * TODO: implement string based key
+ */
+
+#define SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE 16
+
+static TDB_DATA smbXsrv_client_global_id_to_key(const struct GUID *client_guid,
+						uint8_t *key_buf)
+{
+	TDB_DATA key = { .dsize = 0, };
+	NTSTATUS status;
+	DATA_BLOB b;
+
+	status = GUID_to_ndr_blob(client_guid, talloc_tos(), &b);
+	if (!NT_STATUS_IS_OK(status)) {
+		return key;
+	}
+	memcpy(key_buf, b.data, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE);
+	data_blob_free(&b);
+
+	key = make_tdb_data(key_buf, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE);
+
+	return key;
+}
+
+static struct db_record *smbXsrv_client_global_fetch_locked(
+			struct db_context *db,
+			const struct GUID *client_guid,
+			TALLOC_CTX *mem_ctx)
+{
+	TDB_DATA key;
+	uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE];
+	struct db_record *rec = NULL;
+
+	key = smbXsrv_client_global_id_to_key(client_guid, key_buf);
+
+	rec = dbwrap_fetch_locked(db, mem_ctx, key);
+
+	if (rec == NULL) {
+		DBG_DEBUG("Failed to lock guid [%s], key '%s'\n",
+			  GUID_string(talloc_tos(), client_guid),
+			  hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
+	}
+
+	return rec;
+}
+
+static NTSTATUS smbXsrv_client_table_create(TALLOC_CTX *mem_ctx,
+					    struct messaging_context *msg_ctx,
+					    uint32_t max_clients,
+					    struct smbXsrv_client_table **_table)
+{
+	struct smbXsrv_client_table *table;
+	NTSTATUS status;
+
+	if (max_clients > 1) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	table = talloc_zero(mem_ctx, struct smbXsrv_client_table);
+	if (table == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	table->local.max_clients = max_clients;
+
+	status = smbXsrv_client_global_init();
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(table);
+		return status;
+	}
+
+	table->global.db_ctx = smbXsrv_client_global_db_ctx;
+
+	dbwrap_watch_db(table->global.db_ctx, msg_ctx);
+
+	*_table = table;
+	return NT_STATUS_OK;
+}
+
+static int smbXsrv_client_global_destructor(struct smbXsrv_client_global0 *global)
+{
+	return 0;
+}
+
+static void smbXsrv_client_global_verify_record(struct db_record *db_rec,
+					bool *is_free,
+					bool *was_free,
+					TALLOC_CTX *mem_ctx,
+					struct smbXsrv_client_global0 **_g)
+{
+	TDB_DATA key;
+	TDB_DATA val;
+	DATA_BLOB blob;
+	struct smbXsrv_client_globalB global_blob;
+	enum ndr_err_code ndr_err;
+	struct smbXsrv_client_global0 *global = NULL;
+	bool exists;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	*is_free = false;
+
+	if (was_free) {
+		*was_free = false;
+	}
+	if (_g) {
+		*_g = NULL;
+	}
+
+	key = dbwrap_record_get_key(db_rec);
+
+	val = dbwrap_record_get_value(db_rec);
+	if (val.dsize == 0) {
+		TALLOC_FREE(frame);
+		*is_free = true;
+		if (was_free) {
+			*was_free = true;
+		}
+		return;
+	}
+
+	blob = data_blob_const(val.dptr, val.dsize);
+
+	ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
+			(ndr_pull_flags_fn_t)ndr_pull_smbXsrv_client_globalB);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+		DBG_WARNING("smbXsrv_client_global_verify_record: "
+			    "key '%s' ndr_pull_struct_blob - %s\n",
+			    hex_encode_talloc(frame, key.dptr, key.dsize),
+			    nt_errstr(status));
+		TALLOC_FREE(frame);
+		return;
+	}
+
+	DBG_DEBUG("client_global:\n");
+	if (DEBUGLVL(DBGLVL_DEBUG)) {
+		NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
+	}
+
+	if (global_blob.version != SMBXSRV_VERSION_0) {
+		DBG_ERR("key '%s' use unsupported version %u\n",
+			hex_encode_talloc(frame, key.dptr, key.dsize),
+			global_blob.version);
+		NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
+		TALLOC_FREE(frame);
+		return;
+	}
+
+	global = global_blob.info.info0;
+
+	exists = serverid_exists(&global->server_id);
+	if (!exists) {
+		struct server_id_buf tmp;
+
+		DBG_NOTICE("key '%s' server_id %s does not exist.\n",
+			   hex_encode_talloc(frame, key.dptr, key.dsize),
+			   server_id_str_buf(global->server_id, &tmp));
+		if (DEBUGLVL(DBGLVL_NOTICE)) {
+			NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
+		}
+		TALLOC_FREE(frame);
+		dbwrap_record_delete(db_rec);
+		*is_free = true;
+		return;
+	}
+
+	if (_g) {
+		*_g = talloc_move(mem_ctx, &global);
+	}
+	TALLOC_FREE(frame);
+}
+
+NTSTATUS smb2srv_client_lookup_global(struct smbXsrv_client *client,
+				      struct GUID client_guid,
+				      TALLOC_CTX *mem_ctx,
+				      struct smbXsrv_client_global0 **_global)
+{
+	struct smbXsrv_client_table *table = client->table;
+	struct smbXsrv_client_global0 *global = NULL;
+	bool is_free = false;
+	struct db_record *db_rec;
+
+	db_rec = smbXsrv_client_global_fetch_locked(table->global.db_ctx,
+						    &client_guid,
+						    talloc_tos());
+	if (db_rec == NULL) {
+		return NT_STATUS_INTERNAL_DB_ERROR;
+	}
+
+	smbXsrv_client_global_verify_record(db_rec,
+					    &is_free,
+					    NULL,
+					    mem_ctx,
+					    &global);
+	TALLOC_FREE(db_rec);
+
+	if (is_free) {
+		return NT_STATUS_OBJECTID_NOT_FOUND;
+	}
+
+	*_global = global;
+	return NT_STATUS_OK;
+}
+
+NTSTATUS smb2srv_client_connection_pass(struct smbd_smb2_request *smb2req,
+					struct smbXsrv_client_global0 *global)
+{
+	DATA_BLOB blob;
+	enum ndr_err_code ndr_err;
+	NTSTATUS status;
+	struct smbXsrv_connection_pass0 pass_info0;
+	struct smbXsrv_connection_passB pass_blob;
+	ssize_t reqlen;
+	struct iovec iov;
+
+	pass_info0.initial_connect_time = global->initial_connect_time;
+	pass_info0.client_guid = global->client_guid;
+
+	reqlen = iov_buflen(smb2req->in.vector, smb2req->in.vector_count);
+	if (reqlen == -1) {
+		return NT_STATUS_INVALID_BUFFER_SIZE;
+	}
+
+	pass_info0.negotiate_request.length = reqlen;
+	pass_info0.negotiate_request.data = talloc_array(talloc_tos(), uint8_t,
+							 reqlen);
+	if (pass_info0.negotiate_request.data == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	iov_buf(smb2req->in.vector, smb2req->in.vector_count,
+		pass_info0.negotiate_request.data,
+		pass_info0.negotiate_request.length);
+
+	ZERO_STRUCT(pass_blob);
+	pass_blob.version = smbXsrv_version_global_current();
+	pass_blob.info.info0 = &pass_info0;
+
+	if (DEBUGLVL(DBGLVL_DEBUG)) {
+		NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
+	}
+
+	ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &pass_blob,
+			(ndr_push_flags_fn_t)ndr_push_smbXsrv_connection_passB);
+	data_blob_free(&pass_info0.negotiate_request);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		status = ndr_map_error2ntstatus(ndr_err);
+		return status;
+	}
+
+	iov.iov_base = blob.data;
+	iov.iov_len = blob.length;
+
+	status = messaging_send_iov(smb2req->xconn->msg_ctx,
+				    global->server_id,
+				    MSG_SMBXSRV_CONNECTION_PASS,
+				    &iov, 1,
+				    &smb2req->xconn->transport.sock, 1);
+	data_blob_free(&blob);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS smbXsrv_client_global_store(struct smbXsrv_client_global0 *global)
+{
+	struct smbXsrv_client_globalB global_blob;
+	DATA_BLOB blob = data_blob_null;
+	TDB_DATA key;
+	TDB_DATA val;
+	NTSTATUS status;
+	enum ndr_err_code ndr_err;
+	bool saved_stored = global->stored;
+
+	/*
+	 * TODO: if we use other versions than '0'
+	 * we would add glue code here, that would be able to
+	 * store the information in the old format.
+	 */
+
+	if (global->db_rec == NULL) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	key = dbwrap_record_get_key(global->db_rec);
+	val = dbwrap_record_get_value(global->db_rec);
+
+	ZERO_STRUCT(global_blob);
+	global_blob.version = smbXsrv_version_global_current();
+	if (val.dsize >= 8) {
+		global_blob.seqnum = IVAL(val.dptr, 4);
+	}
+	global_blob.seqnum += 1;
+	global_blob.info.info0 = global;
+
+	global->stored = true;
+	ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
+			(ndr_push_flags_fn_t)ndr_push_smbXsrv_client_globalB);
+	global->stored = saved_stored;
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		status = ndr_map_error2ntstatus(ndr_err);
+		DBG_WARNING("key '%s' ndr_push - %s\n",
+			hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
+			nt_errstr(status));
+		TALLOC_FREE(global->db_rec);
+		return status;
+	}
+
+	val = make_tdb_data(blob.data, blob.length);
+	status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("key '%s' store - %s\n",
+			hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
+			nt_errstr(status));
+		TALLOC_FREE(global->db_rec);
+		return status;
+	}
+
+	global->stored = true;
+
+	if (DEBUGLVL(DBGLVL_DEBUG)) {
+		DBG_DEBUG("key '%s' stored\n",
+			hex_encode_talloc(global->db_rec, key.dptr, key.dsize));
+		NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
+	}
+
+	TALLOC_FREE(global->db_rec);
+
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS smbXsrv_client_global_remove(struct smbXsrv_client_global0 *global)
+{
+	TDB_DATA key;
+	NTSTATUS status;
+
+	/*
+	 * TODO: if we use other versions than '0'
+	 * we would add glue code here, that would be able to
+	 * store the information in the old format.
+	 */
+
+	if (global->db_rec == NULL) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	key = dbwrap_record_get_key(global->db_rec);
+
+	status = dbwrap_record_delete(global->db_rec);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("key '%s' delete - %s\n",
+			hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
+			nt_errstr(status));
+		TALLOC_FREE(global->db_rec);
+		return status;
+	}
+	global->stored = false;
+	DBG_DEBUG("key '%s' delete\n",
+		  hex_encode_talloc(global->db_rec, key.dptr, key.dsize));
+
+	TALLOC_FREE(global->db_rec);
+
+	return NT_STATUS_OK;
+}
+
+static int smbXsrv_client_destructor(struct smbXsrv_client *client)
+{
+	NTSTATUS status;
+
+	status = smbXsrv_client_remove(client);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("smbXsrv_client_remove() failed: %s\n",
+			nt_errstr(status));
+	}
+
+	TALLOC_FREE(client->global);
+
+	return 0;
+}
+
+static bool smbXsrv_client_connection_pass_filter(struct messaging_rec *rec, void *private_data);
+static void smbXsrv_client_connection_pass_loop(struct tevent_req *subreq);
+
+NTSTATUS smbXsrv_client_create(TALLOC_CTX *mem_ctx,
+			       struct tevent_context *ev_ctx,
+			       struct messaging_context *msg_ctx,
+			       NTTIME now,
+			       struct smbXsrv_client **_client)
+{
+	struct smbXsrv_client_table *table;
+	struct smbXsrv_client *client = NULL;
+	struct smbXsrv_client_global0 *global = NULL;
+	NTSTATUS status;
+	struct tevent_req *subreq = NULL;
+
+	status = smbXsrv_client_table_create(mem_ctx,
+					     msg_ctx,
+					     1, /* max_clients */
+					     &table);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	if (table->local.num_clients >= table->local.max_clients) {
+		TALLOC_FREE(table);
+		return NT_STATUS_INSUFFICIENT_RESOURCES;
+	}
+
+	client = talloc_zero(mem_ctx, struct smbXsrv_client);
+	if (client == NULL) {
+		TALLOC_FREE(table);
+		return NT_STATUS_NO_MEMORY;
+	}
+	client->ev_ctx = ev_ctx;
+	client->msg_ctx = msg_ctx;
+
+	client->server_multi_channel_enabled = lp_server_multi_channel_support();
+
+	client->table = talloc_move(client, &table);
+	table = client->table;
+
+	global = talloc_zero(client, struct smbXsrv_client_global0);
+	if (global == NULL) {
+		TALLOC_FREE(client);
+		return NT_STATUS_NO_MEMORY;
+	}
+	talloc_set_destructor(global, smbXsrv_client_global_destructor);
+	client->global = global;
+
+	global->initial_connect_time = now;
+
+	global->server_id = messaging_server_id(client->msg_ctx);
+
+	table->local.num_clients += 1;
+
+	talloc_set_destructor(client, smbXsrv_client_destructor);
+
+	if (DEBUGLVL(DBGLVL_DEBUG)) {
+		struct smbXsrv_clientB client_blob;
+
+		ZERO_STRUCT(client_blob);
+		client_blob.version = SMBXSRV_VERSION_0;
+		client_blob.info.info0 = client;
+
+		DBG_DEBUG("client_guid[%s] stored\n",
+			  GUID_string(talloc_tos(), &global->client_guid));
+		NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
+	}
+
+	subreq = messaging_filtered_read_send(client, client->ev_ctx, client->msg_ctx,
+					      smbXsrv_client_connection_pass_filter,
+					      client);
+	if (subreq == NULL) {
+		TALLOC_FREE(client);
+		return NT_STATUS_NO_MEMORY;
+	}
+	tevent_req_set_callback(subreq, smbXsrv_client_connection_pass_loop, client);
+
+	*_client = client;
+	return NT_STATUS_OK;
+}
+
+static bool smbXsrv_client_connection_pass_filter(struct messaging_rec *rec, void *private_data)
+{
+	if (rec->msg_type != MSG_SMBXSRV_CONNECTION_PASS) {
+		return false;
+	}
+
+	if (rec->num_fds != 1) {
+		return false;
+	}
+
+	if (rec->buf.length < SMB2_HDR_BODY) {
+		return false;
+	}
+
+	/* TODO: verify client_guid...? */
+
+	return true;
+}
+
+static void smbXsrv_client_connection_pass_loop(struct tevent_req *subreq)
+{
+	struct smbXsrv_client *client =
+		tevent_req_callback_data(subreq,
+		struct smbXsrv_client);
+	struct smbXsrv_connection *xconn = NULL;
+	int ret;
+	struct messaging_rec *rec = NULL;
+	struct smbXsrv_connection_passB pass_blob;
+	enum ndr_err_code ndr_err;
+	struct smbXsrv_connection_pass0 *pass_info0 = NULL;
+	NTSTATUS status;
+	int sock_fd = -1;
+	uint64_t seq_low;
+
+	ret = messaging_filtered_read_recv(subreq, talloc_tos(), &rec);
+	TALLOC_FREE(subreq);
+	if (ret != 0) {
+		goto next;
+	}
+
+	ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &pass_blob,
+			(ndr_pull_flags_fn_t)ndr_pull_smbXsrv_connection_passB);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		status = ndr_map_error2ntstatus(ndr_err);
+		DBG_WARNING("ndr_pull_struct_blob - %s\n", nt_errstr(status));
+		goto next;
+	}
+
+	DBG_DEBUG("MSG_SMBXSRV_CLIENT_CLOSE\n");
+	if (DEBUGLVL(DBGLVL_DEBUG)) {
+		NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
+	}
+
+	if (pass_blob.version != SMBXSRV_VERSION_0) {
+		DBG_ERR("ignore invalid version %u\n", pass_blob.version);
+		NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
+		goto next;
+	}
+
+	pass_info0 = pass_blob.info.info0;
+	if (pass_info0 == NULL) {
+		DBG_ERR("ignore NULL info %u\n", pass_blob.version);
+		NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
+		goto next;
+	}
+
+	if (!GUID_equal(&client->global->client_guid, &pass_info0->client_guid))
+	{
+		DBG_WARNING("client's client_guid [%s] != passed guid [%s]\n",
+			GUID_string(talloc_tos(), &client->global->client_guid),
+			GUID_string(talloc_tos(), &pass_info0->client_guid));
+		if (DEBUGLVL(DBGLVL_WARNING)) {
+			NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
+		}
+		goto next;
+	}
+
+	if (client->global->initial_connect_time !=
+	    pass_info0->initial_connect_time)
+	{
+		DBG_WARNING("client's initial connect time [%s] (%llu) != "
+			"passed initial connect time [%s] (%llu)\n",
+			nt_time_string(talloc_tos(),
+				       client->global->initial_connect_time),
+			(unsigned long long)client->global->initial_connect_time,
+			nt_time_string(talloc_tos(),
+				       pass_info0->initial_connect_time),
+			(unsigned long long)pass_info0->initial_connect_time);
+		if (DEBUGLVL(DBGLVL_WARNING)) {
+			NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
+		}
+		goto next;
+	}
+
+	SMB_ASSERT(rec->num_fds == 1);
+	sock_fd = rec->fds[0];
+
+	DBG_ERR("got connection sockfd[%d]\n", sock_fd);
+	NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
+	status = smbd_add_connection(client, sock_fd, &xconn);
+	if (!NT_STATUS_IS_OK(status)) {
+		close(sock_fd);
+		sock_fd = -1;
+		DBG_ERR("smbd_add_connection => %s\n", nt_errstr(status));
+		NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
+		goto next;
+	}
+
+	/*
+	 * Set seq_low to mid received in negprot
+	 */
+	seq_low = BVAL(pass_info0->negotiate_request.data,
+		       SMB2_HDR_MESSAGE_ID);
+
+	xconn->smb2.client.guid_verified = true;
+	smbd_smb2_process_negprot(xconn, seq_low,
+				  pass_info0->negotiate_request.data,
+				  pass_info0->negotiate_request.length);
+
+next:
+	TALLOC_FREE(rec);
+
+	subreq = messaging_filtered_read_send(client, client->ev_ctx, client->msg_ctx,
+					      smbXsrv_client_connection_pass_filter,
+					      client);
+	if (subreq == NULL) {
+		const char *r;
+		r = "messaging_read_send(MSG_SMBXSRV_CONNECTION_PASS failed";
+		exit_server_cleanly(r);
+		return;
+	}
+	tevent_req_set_callback(subreq, smbXsrv_client_connection_pass_loop, client);
+}
+
+NTSTATUS smbXsrv_client_update(struct smbXsrv_client *client)
+{
+	struct smbXsrv_client_table *table = client->table;
+	NTSTATUS status;
+
+	if (client->global->db_rec != NULL) {
+		DBG_ERR("guid [%s]: Called with db_rec != NULL'\n",
+			GUID_string(talloc_tos(),
+			&client->global->client_guid));
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	client->global->db_rec = smbXsrv_client_global_fetch_locked(
+					table->global.db_ctx,
+					&client->global->client_guid,
+					client->global /* TALLOC_CTX */);
+	if (client->global->db_rec == NULL) {
+		return NT_STATUS_INTERNAL_DB_ERROR;
+	}
+
+	status = smbXsrv_client_global_store(client->global);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("client_guid[%s] store failed - %s\n",
+			GUID_string(talloc_tos(), &client->global->client_guid),
+			nt_errstr(status));
+		return status;
+	}
+
+	if (DEBUGLVL(DBGLVL_DEBUG)) {
+		struct smbXsrv_clientB client_blob;
+
+		ZERO_STRUCT(client_blob);
+		client_blob.version = SMBXSRV_VERSION_0;
+		client_blob.info.info0 = client;
+
+		DBG_DEBUG("client_guid[%s] stored\n",
+			GUID_string(talloc_tos(), &client->global->client_guid));
+		NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
+	}
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS smbXsrv_client_remove(struct smbXsrv_client *client)
+{
+	struct smbXsrv_client_table *table = client->table;
+	NTSTATUS status;
+
+	if (client->global->db_rec != NULL) {
+		DBG_ERR("client_guid[%s]: Called with db_rec != NULL'\n",
+			GUID_string(talloc_tos(), &client->global->client_guid));
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	if (!client->global->stored) {
+		return NT_STATUS_OK;
+	}
+
+	client->global->db_rec = smbXsrv_client_global_fetch_locked(
+					table->global.db_ctx,
+					&client->global->client_guid,
+					client->global /* TALLOC_CTX */);
+	if (client->global->db_rec == NULL) {
+		return NT_STATUS_INTERNAL_DB_ERROR;
+	}
+
+	status = smbXsrv_client_global_remove(client->global);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("client_guid[%s] store failed - %s\n",
+			GUID_string(talloc_tos(), &client->global->client_guid),
+			nt_errstr(status));
+		return status;
+	}
+
+	if (DEBUGLVL(DBGLVL_DEBUG)) {
+		struct smbXsrv_clientB client_blob;
+
+		ZERO_STRUCT(client_blob);
+		client_blob.version = SMBXSRV_VERSION_0;
+		client_blob.info.info0 = client;
+
+		DBG_DEBUG("client_guid[%s] stored\n",
+			GUID_string(talloc_tos(), &client->global->client_guid));
+		NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
+	}
+
+	return NT_STATUS_OK;
+}
diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c
index 1fe8b1b..a7cea18 100644
--- a/source3/smbd/smbXsrv_open.c
+++ b/source3/smbd/smbXsrv_open.c
@@ -34,6 +34,7 @@
 struct smbXsrv_open_table {
 	struct {
 		struct db_context *db_ctx;
+		struct db_context *replay_cache_db_ctx;
 		uint32_t lowest_id;
 		uint32_t highest_id;
 		uint32_t max_opens;
@@ -151,6 +152,48 @@ static NTSTATUS smbXsrv_open_local_key_to_id(TDB_DATA key, uint32_t *id)
 	return NT_STATUS_OK;
 }
 
+static struct db_record *smbXsrv_open_global_fetch_locked(
+			struct db_context *db,
+			uint32_t id,
+			TALLOC_CTX *mem_ctx)
+{
+	TDB_DATA key;
+	uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
+	struct db_record *rec = NULL;
+
+	key = smbXsrv_open_global_id_to_key(id, key_buf);
+
+	rec = dbwrap_fetch_locked(db, mem_ctx, key);
+
+	if (rec == NULL) {
+		DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
+			  hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
+	}
+
+	return rec;
+}
+
+static struct db_record *smbXsrv_open_local_fetch_locked(
+			struct db_context *db,
+			uint32_t id,
+			TALLOC_CTX *mem_ctx)
+{
+	TDB_DATA key;
+	uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
+	struct db_record *rec = NULL;
+
+	key = smbXsrv_open_local_id_to_key(id, key_buf);
+
+	rec = dbwrap_fetch_locked(db, mem_ctx, key);
+
+	if (rec == NULL) {
+		DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
+			  hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
+	}
+
+	return rec;
+}
+
 static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn,
 					uint32_t lowest_id,
 					uint32_t highest_id,
@@ -183,6 +226,11 @@ static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn,
 		TALLOC_FREE(table);
 		return NT_STATUS_NO_MEMORY;
 	}
+	table->local.replay_cache_db_ctx = db_open_rbt(table);
+	if (table->local.replay_cache_db_ctx == NULL) {
+		TALLOC_FREE(table);
+		return NT_STATUS_NO_MEMORY;
+	}
 	table->local.lowest_id = lowest_id;
 	table->local.highest_id = highest_id;
 	table->local.max_opens = max_opens;
@@ -275,8 +323,6 @@ static NTSTATUS smbXsrv_open_local_allocate_id(struct db_context *db,
 
 	for (i = 0; i < (range / 2); i++) {
 		uint32_t id;
-		uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 		TDB_DATA val;
 		struct db_record *rec = NULL;
 
@@ -290,9 +336,7 @@ static NTSTATUS smbXsrv_open_local_allocate_id(struct db_context *db,
 			id = highest_id;
 		}
 
-		key = smbXsrv_open_local_id_to_key(id, key_buf);
-
-		rec = dbwrap_fetch_locked(db, mem_ctx, key);
+		rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx);
 		if (rec == NULL) {
 			return NT_STATUS_INSUFFICIENT_RESOURCES;
 		}
@@ -342,16 +386,12 @@ static NTSTATUS smbXsrv_open_local_allocate_id(struct db_context *db,
 
 	if (NT_STATUS_IS_OK(state.status)) {
 		uint32_t id;
-		uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 		TDB_DATA val;
 		struct db_record *rec = NULL;
 
 		id = state.useable_id;
 
-		key = smbXsrv_open_local_id_to_key(id, key_buf);
-
-		rec = dbwrap_fetch_locked(db, mem_ctx, key);
+		rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx);
 		if (rec == NULL) {
 			return NT_STATUS_INSUFFICIENT_RESOURCES;
 		}
@@ -494,8 +534,6 @@ static NTSTATUS smbXsrv_open_global_allocate(struct db_context *db,
 		bool is_free = false;
 		bool was_free = false;
 		uint32_t id;
-		uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 
 		if (i >= min_tries && last_free != 0) {
 			id = last_free;
@@ -509,9 +547,7 @@ static NTSTATUS smbXsrv_open_global_allocate(struct db_context *db,
 			id--;
 		}
 
-		key = smbXsrv_open_global_id_to_key(id, key_buf);
-
-		global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
+		global->db_rec = smbXsrv_open_global_fetch_locked(db, id, mem_ctx);
 		if (global->db_rec == NULL) {
 			talloc_free(global);
 			return NT_STATUS_INSUFFICIENT_RESOURCES;
@@ -717,8 +753,6 @@ static NTSTATUS smbXsrv_open_global_lookup(struct smbXsrv_open_table *table,
 					   TALLOC_CTX *mem_ctx,
 					   struct smbXsrv_open_global0 **_global)
 {
-	TDB_DATA key;
-	uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
 	struct db_record *global_rec = NULL;
 	bool is_free = false;
 
@@ -728,15 +762,10 @@ static NTSTATUS smbXsrv_open_global_lookup(struct smbXsrv_open_table *table,
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	key = smbXsrv_open_global_id_to_key(open_global_id, key_buf);
-
-	global_rec = dbwrap_fetch_locked(table->global.db_ctx, mem_ctx, key);
+	global_rec = smbXsrv_open_global_fetch_locked(table->global.db_ctx,
+						      open_global_id,
+						      mem_ctx);
 	if (global_rec == NULL) {
-		DEBUG(0, ("smbXsrv_open_global_lookup(0x%08x): "
-			  "Failed to lock global key '%s'\n",
-			  open_global_id,
-			  hex_encode_talloc(talloc_tos(), key.dptr,
-					    key.dsize)));
 		return NT_STATUS_INTERNAL_DB_ERROR;
 	}
 
@@ -905,12 +934,83 @@ uint32_t smbXsrv_open_hash(struct smbXsrv_open *_open)
 	return ret;
 }
 
+static NTSTATUS smbXsrv_open_set_replay_cache(struct smbXsrv_open *op)
+{
+	struct GUID *create_guid;
+	struct GUID_txt_buf buf;
+	char *guid_string;
+	struct db_context *db = op->table->local.replay_cache_db_ctx;
+	NTSTATUS status;
+
+	if (!(op->flags & SMBXSRV_OPEN_NEED_REPLAY_CACHE)) {
+		return NT_STATUS_OK;
+	}
+
+	if (op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE) {
+		return NT_STATUS_OK;
+	}
+
+	create_guid = &op->global->create_guid;
+	if (GUID_all_zero(create_guid)) {
+		return NT_STATUS_OK;
+	}
+
+	guid_string = GUID_buf_string(create_guid, &buf);
+	if (guid_string == NULL) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	status = dbwrap_store_uint32_bystring(db, guid_string, op->local_id);
+
+	if (NT_STATUS_IS_OK(status)) {
+		op->flags |= SMBXSRV_OPEN_HAVE_REPLAY_CACHE;
+		op->flags &= ~SMBXSRV_OPEN_NEED_REPLAY_CACHE;
+	}
+
+	return status;
+}
+
+static NTSTATUS smbXsrv_open_clear_replay_cache(struct smbXsrv_open *op)
+{
+	struct GUID *create_guid;
+	struct GUID_txt_buf buf;
+	char *guid_string;
+	struct db_context *db;
+	NTSTATUS status;
+
+	if (op->table == NULL) {
+		return NT_STATUS_OK;
+	}
+
+	db = op->table->local.replay_cache_db_ctx;
+
+	if (!(op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE)) {
+		return NT_STATUS_OK;
+	}
+
+	create_guid = &op->global->create_guid;
+	if (GUID_all_zero(create_guid)) {
+		return NT_STATUS_OK;
+	}
+
+	guid_string = GUID_buf_string(create_guid, &buf);
+	if (guid_string == NULL) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	status = dbwrap_purge_bystring(db, guid_string);
+
+	if (NT_STATUS_IS_OK(status)) {
+		op->flags &= ~SMBXSRV_OPEN_HAVE_REPLAY_CACHE;
+	}
+
+	return status;
+}
+
 NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op)
 {
 	struct smbXsrv_open_table *table = op->table;
 	NTSTATUS status;
-	uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
-	TDB_DATA key;
 
 	if (op->global->db_rec != NULL) {
 		DEBUG(0, ("smbXsrv_open_update(0x%08x): "
@@ -919,17 +1019,11 @@ NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op)
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	key = smbXsrv_open_global_id_to_key(op->global->open_global_id,
-					    key_buf);
-
-	op->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
-						 op->global, key);
+	op->global->db_rec = smbXsrv_open_global_fetch_locked(
+						table->global.db_ctx,
+						op->global->open_global_id,
+						op->global /* TALLOC_CTX */);
 	if (op->global->db_rec == NULL) {
-		DEBUG(0, ("smbXsrv_open_update(0x%08x): "
-			  "Failed to lock global key '%s'\n",
-			  op->global->open_global_id,
-			  hex_encode_talloc(talloc_tos(), key.dptr,
-					    key.dsize)));
 		return NT_STATUS_INTERNAL_DB_ERROR;
 	}
 
@@ -942,6 +1036,13 @@ NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op)
 		return status;
 	}
 
+	status = smbXsrv_open_set_replay_cache(op);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("smbXsrv_open_set_replay_cache failed: %s\n",
+			nt_errstr(status));
+		return status;
+	}
+
 	if (CHECK_DEBUGLVL(10)) {
 		struct smbXsrv_openB open_blob;
 
@@ -965,8 +1066,14 @@ NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now)
 	NTSTATUS status;
 	NTSTATUS error = NT_STATUS_OK;
 
+	error = smbXsrv_open_clear_replay_cache(op);
+	if (!NT_STATUS_IS_OK(error)) {
+		DBG_ERR("smbXsrv_open_clear_replay_cache failed: %s\n",
+			nt_errstr(error));
+	}
+
 	if (op->table == NULL) {
-		return NT_STATUS_OK;
+		return error;
 	}
 
 	table = op->table;
@@ -979,21 +1086,11 @@ NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now)
 	global_rec = op->global->db_rec;
 	op->global->db_rec = NULL;
 	if (global_rec == NULL) {
-		uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
-		TDB_DATA key;
-
-		key = smbXsrv_open_global_id_to_key(
-						op->global->open_global_id,
-						key_buf);
-
-		global_rec = dbwrap_fetch_locked(table->global.db_ctx,
-						 op->global, key);
+		global_rec = smbXsrv_open_global_fetch_locked(
+					table->global.db_ctx,
+					op->global->open_global_id,
+					op->global /* TALLOC_CTX */);
 		if (global_rec == NULL) {
-			DEBUG(0, ("smbXsrv_open_close(0x%08x): "
-				  "Failed to lock global key '%s'\n",
-				  op->global->open_global_id,
-				  hex_encode_talloc(global_rec, key.dptr,
-						    key.dsize)));
 			error = NT_STATUS_INTERNAL_ERROR;
 		}
 	}
@@ -1052,19 +1149,10 @@ NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now)
 
 	local_rec = op->db_rec;
 	if (local_rec == NULL) {
-		uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
-
-		key = smbXsrv_open_local_id_to_key(op->local_id, key_buf);
-
-		local_rec = dbwrap_fetch_locked(table->local.db_ctx,
-						op, key);
+		local_rec = smbXsrv_open_local_fetch_locked(table->local.db_ctx,
+							    op->local_id,
+							    op /* TALLOC_CTX*/);
 		if (local_rec == NULL) {
-			DEBUG(0, ("smbXsrv_open_close(0x%08x): "
-				  "Failed to lock local key '%s'\n",
-				  op->global->open_global_id,
-				  hex_encode_talloc(local_rec, key.dptr,
-						    key.dsize)));
 			error = NT_STATUS_INTERNAL_ERROR;
 		}
 	}
@@ -1161,6 +1249,7 @@ NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn,
 	uint64_t local_zeros = volatile_id & 0xFFFFFFFF00000000LLU;
 	uint32_t global_id = persistent_id & UINT32_MAX;
 	uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU;
+	NTSTATUS status;
 
 	if (local_zeros != 0) {
 		return NT_STATUS_FILE_CLOSED;
@@ -1174,7 +1263,65 @@ NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn,
 		return NT_STATUS_FILE_CLOSED;
 	}
 
-	return smbXsrv_open_local_lookup(table, local_id, global_id, now, _open);
+	status = smbXsrv_open_local_lookup(table, local_id, global_id, now,
+					   _open);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	/*
+	 * Clear the replay cache for this create_guid if it exists:
+	 * This is based on the assumption that this lookup will be
+	 * triggered by a client request using the file-id for lookup.
+	 * Hence the client has proven that it has in fact seen the
+	 * reply to its initial create call. So subsequent create replays
+	 * should be treated as invalid. Hence the index for create_guid
+	 * lookup needs to be removed.
+	 */
+	status = smbXsrv_open_clear_replay_cache(*_open);
+
+	return status;
+}
+
+NTSTATUS smb2srv_open_lookup_replay_cache(struct smbXsrv_connection *conn,
+					  const struct GUID *create_guid,
+					  NTTIME now, /* TODO: needed ? */
+					  struct smbXsrv_open **_open)
+{
+	NTSTATUS status;
+	char *guid_string;
+	struct GUID_txt_buf buf;
+	uint32_t local_id = 0;
+	struct smbXsrv_open_table *table = conn->client->open_table;
+	struct db_context *db = table->local.replay_cache_db_ctx;
+
+	if (GUID_all_zero(create_guid)) {
+		return NT_STATUS_NOT_FOUND;
+	}
+
+	guid_string = GUID_buf_string(create_guid, &buf);
+	if (guid_string == NULL) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	status = dbwrap_fetch_uint32_bystring(db, guid_string, &local_id);
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+		return status;
+	}
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("failed to fetch local_id from replay cache: %s\n",
+			nt_errstr(status));
+		return status;
+	}
+
+	status = smbXsrv_open_local_lookup(table, local_id, 0, /* global_id */
+					   now, _open);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("smbXsrv_open_local_lookup failed for local_id %u\n",
+			(unsigned)local_id);
+	}
+
+	return status;
 }
 
 NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
@@ -1403,21 +1550,16 @@ NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id)
 	NTSTATUS status = NT_STATUS_OK;
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct smbXsrv_open_global0 *op = NULL;
-	uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
-	TDB_DATA key;
 	TDB_DATA val;
 	struct db_record *rec;
 	bool delete_open = false;
 	uint32_t global_id = persistent_id & UINT32_MAX;
 
-	key = smbXsrv_open_global_id_to_key(global_id, key_buf);
-	rec = dbwrap_fetch_locked(smbXsrv_open_global_db_ctx, frame, key);
+	rec = smbXsrv_open_global_fetch_locked(smbXsrv_open_global_db_ctx,
+					       global_id,
+					       frame);
 	if (rec == NULL) {
 		status = NT_STATUS_NOT_FOUND;
-		DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
-			  "failed to fetch record from %s - %s\n",
-			   global_id, dbwrap_name(smbXsrv_open_global_db_ctx),
-			   nt_errstr(status)));
 		goto done;
 	}
 
diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index 3201670..a5aee8c 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -51,10 +51,6 @@ struct smbXsrv_session_table {
 	} global;
 };
 
-static NTSTATUS smb2srv_session_lookup_raw(struct smbXsrv_session_table *table,
-					   uint64_t session_id, NTTIME now,
-					   struct smbXsrv_session **session);
-
 static struct db_context *smbXsrv_session_global_db_ctx = NULL;
 
 NTSTATUS smbXsrv_session_global_init(void)
@@ -165,6 +161,48 @@ static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id)
 	return NT_STATUS_OK;
 }
 
+static struct db_record *smbXsrv_session_global_fetch_locked(
+			struct db_context *db,
+			uint32_t id,
+			TALLOC_CTX *mem_ctx)
+{
+	TDB_DATA key;
+	uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
+	struct db_record *rec = NULL;
+
+	key = smbXsrv_session_global_id_to_key(id, key_buf);
+
+	rec = dbwrap_fetch_locked(db, mem_ctx, key);
+
+	if (rec == NULL) {
+		DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
+			  hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
+	}
+
+	return rec;
+}
+
+static struct db_record *smbXsrv_session_local_fetch_locked(
+			struct db_context *db,
+			uint32_t id,
+			TALLOC_CTX *mem_ctx)
+{
+	TDB_DATA key;
+	uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
+	struct db_record *rec = NULL;
+
+	key = smbXsrv_session_local_id_to_key(id, key_buf);
+
+	rec = dbwrap_fetch_locked(db, mem_ctx, key);
+
+	if (rec == NULL) {
+		DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
+			  hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
+	}
+
+	return rec;
+}
+
 static void smbXsrv_session_close_loop(struct tevent_req *subreq);
 
 static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
@@ -280,9 +318,9 @@ static void smbXsrv_session_close_loop(struct tevent_req *subreq)
 		goto next;
 	}
 
-	status = smb2srv_session_lookup_raw(client->session_table,
-					    close_info0->old_session_wire_id,
-					    now, &session);
+	status = smb2srv_session_lookup_client(client,
+					       close_info0->old_session_wire_id,
+					       now, &session);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
 		DEBUG(4,("smbXsrv_session_close_loop: "
 			 "old_session_wire_id %llu not found\n",
@@ -466,8 +504,6 @@ static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
 
 	for (i = 0; i < (range / 2); i++) {
 		uint32_t id;
-		uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 		TDB_DATA val;
 		struct db_record *rec = NULL;
 
@@ -481,9 +517,7 @@ static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
 			id = highest_id;
 		}
 
-		key = smbXsrv_session_local_id_to_key(id, key_buf);
-
-		rec = dbwrap_fetch_locked(db, mem_ctx, key);
+		rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx);
 		if (rec == NULL) {
 			return NT_STATUS_INSUFFICIENT_RESOURCES;
 		}
@@ -533,16 +567,12 @@ static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
 
 	if (NT_STATUS_IS_OK(state.status)) {
 		uint32_t id;
-		uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 		TDB_DATA val;
 		struct db_record *rec = NULL;
 
 		id = state.useable_id;
 
-		key = smbXsrv_session_local_id_to_key(id, key_buf);
-
-		rec = dbwrap_fetch_locked(db, mem_ctx, key);
+		rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx);
 		if (rec == NULL) {
 			return NT_STATUS_INSUFFICIENT_RESOURCES;
 		}
@@ -584,6 +614,8 @@ static void smbXsrv_session_local_fetch_parser(TDB_DATA key, TDB_DATA data,
 }
 
 static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table,
+					     /* conn: optional */
+					     struct smbXsrv_connection *conn,
 					     uint32_t session_local_id,
 					     NTTIME now,
 					     struct smbXsrv_session **_session)
@@ -629,6 +661,19 @@ static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table
 		return NT_STATUS_USER_SESSION_DELETED;
 	}
 
+	/*
+	 * If a connection is specified check if the session is
+	 * valid on the channel.
+	 */
+	if (conn != NULL) {
+		struct smbXsrv_channel_global0 *c = NULL;
+
+		status = smbXsrv_session_find_channel(state.session, conn, &c);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+	}
+
 	state.session->idle_time = now;
 
 	if (!NT_STATUS_IS_OK(state.session->status)) {
@@ -682,8 +727,6 @@ static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
 		bool is_free = false;
 		bool was_free = false;
 		uint32_t id;
-		uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 
 		if (i >= min_tries && last_free != 0) {
 			id = last_free;
@@ -697,9 +740,8 @@ static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
 			id--;
 		}
 
-		key = smbXsrv_session_global_id_to_key(id, key_buf);
-
-		global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
+		global->db_rec = smbXsrv_session_global_fetch_locked(db, id,
+								     mem_ctx);
 		if (global->db_rec == NULL) {
 			talloc_free(global);
 			return NT_STATUS_INSUFFICIENT_RESOURCES;
@@ -920,8 +962,6 @@ struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx,
 	uint64_t global_zeros = previous_session_id & 0xFFFFFFFF00000000LLU;
 	struct smbXsrv_session_table *table = conn->client->session_table;
 	struct security_token *current_token = NULL;
-	uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
-	TDB_DATA key;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct smb2srv_session_close_previous_state);
@@ -958,10 +998,10 @@ struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	key = smbXsrv_session_global_id_to_key(global_id, key_buf);
-
-	state->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
-					    state, key);
+	state->db_rec = smbXsrv_session_global_fetch_locked(
+							table->global.db_ctx,
+							global_id,
+							state /* TALLOC_CTX */);
 	if (state->db_rec == NULL) {
 		tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
 		return tevent_req_post(req, ev);
@@ -1152,7 +1192,7 @@ NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
 	void *ptr = NULL;
 	TDB_DATA val;
 	struct smbXsrv_session_global0 *global = NULL;
-	struct smbXsrv_channel_global0 *channels = NULL;
+	struct smbXsrv_channel_global0 *channel = NULL;
 	NTSTATUS status;
 
 	if (table->local.num_sessions >= table->local.max_sessions) {
@@ -1168,15 +1208,6 @@ NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
 	session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
 	session->client = conn->client;
 
-	if (conn->protocol >= PROTOCOL_SMB3_10) {
-		session->preauth = talloc(session, struct smbXsrv_preauth);
-		if (session->preauth == NULL) {
-			TALLOC_FREE(session);
-			return NT_STATUS_NO_MEMORY;
-		}
-		*session->preauth = conn->smb2.preauth;
-	}
-
 	status = smbXsrv_session_global_allocate(table->global.db_ctx,
 						 session,
 						 &global);
@@ -1188,8 +1219,6 @@ NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
 
 	if (conn->protocol >= PROTOCOL_SMB2_02) {
 		uint64_t id = global->session_global_id;
-		uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 
 		global->connection_dialect = conn->smb2.server.dialect;
 
@@ -1203,10 +1232,10 @@ NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
 
 		session->local_id = global->session_global_id;
 
-		key = smbXsrv_session_local_id_to_key(session->local_id, key_buf);
-
-		local_rec = dbwrap_fetch_locked(table->local.db_ctx,
-						session, key);
+		local_rec = smbXsrv_session_local_fetch_locked(
+						table->local.db_ctx,
+						session->local_id,
+						session /* TALLOC_CTX */);
 		if (local_rec == NULL) {
 			TALLOC_FREE(session);
 			return NT_STATUS_NO_MEMORY;
@@ -1236,36 +1265,11 @@ NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
 	global->creation_time = now;
 	global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY;
 
-	global->num_channels = 1;
-	channels = talloc_zero_array(global,
-				     struct smbXsrv_channel_global0,
-				     global->num_channels);
-	if (channels == NULL) {
-		TALLOC_FREE(session);
-		return NT_STATUS_NO_MEMORY;
-	}
-	global->channels = channels;
-
-	channels[0].server_id = messaging_server_id(conn->msg_ctx);
-	channels[0].local_address = tsocket_address_string(conn->local_address,
-							   channels);
-	if (channels[0].local_address == NULL) {
-		TALLOC_FREE(session);
-		return NT_STATUS_NO_MEMORY;
-	}
-	channels[0].remote_address = tsocket_address_string(conn->remote_address,
-							    channels);
-	if (channels[0].remote_address == NULL) {
-		TALLOC_FREE(session);
-		return NT_STATUS_NO_MEMORY;
-	}
-	channels[0].remote_name = talloc_strdup(channels, conn->remote_hostname);
-	if (channels[0].remote_name == NULL) {
+	status = smbXsrv_session_add_channel(session, conn, &channel);
+	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(session);
-		return NT_STATUS_NO_MEMORY;
+		return status;
 	}
-	channels[0].signing_key = data_blob_null;
-	channels[0].connection = conn;
 
 	ptr = session;
 	val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
@@ -1305,12 +1309,60 @@ NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
 	return NT_STATUS_OK;
 }
 
+NTSTATUS smbXsrv_session_add_channel(struct smbXsrv_session *session,
+				     struct smbXsrv_connection *conn,
+				     struct smbXsrv_channel_global0 **_c)
+{
+	struct smbXsrv_session_global0 *global = session->global;
+	struct smbXsrv_channel_global0 *c = NULL;
+
+	if (global->num_channels > 31) {
+		/*
+		 * Windows 2012 and 2012R2 allow up to 32 channels
+		 */
+		return NT_STATUS_INSUFFICIENT_RESOURCES;
+	}
+
+	c = talloc_realloc(global,
+			   global->channels,
+			   struct smbXsrv_channel_global0,
+			   global->num_channels + 1);
+	if (c == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	global->channels = c;
+
+	c = &global->channels[global->num_channels];
+	ZERO_STRUCTP(c);
+
+	c->server_id = messaging_server_id(conn->msg_ctx);
+	c->local_address = tsocket_address_string(conn->local_address,
+						  global->channels);
+	if (c->local_address == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	c->remote_address = tsocket_address_string(conn->remote_address,
+						   global->channels);
+	if (c->remote_address == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	c->remote_name = talloc_strdup(global->channels,
+				       conn->remote_hostname);
+	if (c->remote_name == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	c->connection = conn;
+
+	global->num_channels += 1;
+
+	*_c = c;
+	return NT_STATUS_OK;
+}
+
 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
 {
 	struct smbXsrv_session_table *table = session->table;
 	NTSTATUS status;
-	uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
-	TDB_DATA key;
 
 	if (session->global->db_rec != NULL) {
 		DEBUG(0, ("smbXsrv_session_update(0x%08x): "
@@ -1319,18 +1371,11 @@ NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	key = smbXsrv_session_global_id_to_key(
+	session->global->db_rec = smbXsrv_session_global_fetch_locked(
+					table->global.db_ctx,
 					session->global->session_global_id,
-					key_buf);
-
-	session->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
-						      session->global, key);
+					session->global /* TALLOC_CTX */);
 	if (session->global->db_rec == NULL) {
-		DEBUG(0, ("smbXsrv_session_update(0x%08x): "
-			  "Failed to lock global key '%s'\n",
-			  session->global->session_global_id,
-			  hex_encode_talloc(talloc_tos(), key.dptr,
-					    key.dsize)));
 		return NT_STATUS_INTERNAL_DB_ERROR;
 	}
 
@@ -1376,6 +1421,79 @@ NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session,
 	return NT_STATUS_USER_SESSION_DELETED;
 }
 
+NTSTATUS smbXsrv_session_find_auth(const struct smbXsrv_session *session,
+				   const struct smbXsrv_connection *conn,
+				   NTTIME now,
+				   struct smbXsrv_session_auth0 **_a)
+{
+	struct smbXsrv_session_auth0 *a;
+
+	for (a = session->pending_auth; a != NULL; a = a->next) {
+		if (a->connection == conn) {
+			if (now != 0) {
+				a->idle_time = now;
+			}
+			*_a = a;
+			return NT_STATUS_OK;
+		}
+	}
+
+	return NT_STATUS_USER_SESSION_DELETED;
+}
+
+static int smbXsrv_session_auth0_destructor(struct smbXsrv_session_auth0 *a)
+{
+	if (a->session == NULL) {
+		return 0;
+	}
+
+	DLIST_REMOVE(a->session->pending_auth, a);
+	a->session = NULL;
+	return 0;
+}
+
+NTSTATUS smbXsrv_session_create_auth(struct smbXsrv_session *session,
+				     struct smbXsrv_connection *conn,
+				     NTTIME now,
+				     uint8_t in_flags,
+				     uint8_t in_security_mode,
+				     struct smbXsrv_session_auth0 **_a)
+{
+	struct smbXsrv_session_auth0 *a;
+	NTSTATUS status;
+
+	status = smbXsrv_session_find_auth(session, conn, 0, &a);
+	if (NT_STATUS_IS_OK(status)) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	a = talloc_zero(session, struct smbXsrv_session_auth0);
+	if (a == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	a->session = session;
+	a->connection = conn;
+	a->in_flags = in_flags;
+	a->in_security_mode = in_security_mode;
+	a->creation_time = now;
+	a->idle_time = now;
+
+	if (conn->protocol >= PROTOCOL_SMB3_10) {
+		a->preauth = talloc(a, struct smbXsrv_preauth);
+		if (a->preauth == NULL) {
+			TALLOC_FREE(session);
+			return NT_STATUS_NO_MEMORY;
+		}
+		*a->preauth = conn->smb2.preauth;
+	}
+
+	talloc_set_destructor(a, smbXsrv_session_auth0_destructor);
+	DLIST_ADD_END(session->pending_auth, a);
+
+	*_a = a;
+	return NT_STATUS_OK;
+}
+
 struct smb2srv_session_shutdown_state {
 	struct tevent_queue *wait_queue;
 };
@@ -1521,21 +1639,11 @@ NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
 	global_rec = session->global->db_rec;
 	session->global->db_rec = NULL;
 	if (global_rec == NULL) {
-		uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
-		TDB_DATA key;
-
-		key = smbXsrv_session_global_id_to_key(
+		global_rec = smbXsrv_session_global_fetch_locked(
+					table->global.db_ctx,
 					session->global->session_global_id,
-					key_buf);
-
-		global_rec = dbwrap_fetch_locked(table->global.db_ctx,
-						 session->global, key);
+					session->global /* TALLOC_CTX */);
 		if (global_rec == NULL) {
-			DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
-				  "Failed to lock global key '%s'\n",
-				  session->global->session_global_id,
-				  hex_encode_talloc(global_rec, key.dptr,
-						    key.dsize)));
 			error = NT_STATUS_INTERNAL_ERROR;
 		}
 	}
@@ -1558,20 +1666,11 @@ NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
 
 	local_rec = session->db_rec;
 	if (local_rec == NULL) {
-		uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
-
-		key = smbXsrv_session_local_id_to_key(session->local_id,
-						      key_buf);
-
-		local_rec = dbwrap_fetch_locked(table->local.db_ctx,
-						session, key);
+		local_rec = smbXsrv_session_local_fetch_locked(
+						table->local.db_ctx,
+						session->local_id,
+						session /* TALLOC_CTX */);
 		if (local_rec == NULL) {
-			DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
-				  "Failed to lock local key '%s'\n",
-				  session->global->session_global_id,
-				  hex_encode_talloc(local_rec, key.dptr,
-						    key.dsize)));
 			error = NT_STATUS_INTERNAL_ERROR;
 		}
 	}
@@ -1719,7 +1818,8 @@ NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
 	struct smbXsrv_session_table *table = conn->client->session_table;
 	uint32_t local_id = vuid;
 
-	return smbXsrv_session_local_lookup(table, local_id, now, session);
+	return smbXsrv_session_local_lookup(table, conn, local_id, now,
+					    session);
 }
 
 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
@@ -1732,6 +1832,8 @@ NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
 }
 
 static NTSTATUS smb2srv_session_lookup_raw(struct smbXsrv_session_table *table,
+					   /* conn: optional */
+					   struct smbXsrv_connection *conn,
 					   uint64_t session_id, NTTIME now,
 					   struct smbXsrv_session **session)
 {
@@ -1742,15 +1844,26 @@ static NTSTATUS smb2srv_session_lookup_raw(struct smbXsrv_session_table *table,
 		return NT_STATUS_USER_SESSION_DELETED;
 	}
 
-	return smbXsrv_session_local_lookup(table, local_id, now, session);
+	return smbXsrv_session_local_lookup(table, conn, local_id, now,
+					    session);
 }
 
-NTSTATUS smb2srv_session_lookup(struct smbXsrv_connection *conn,
-				uint64_t session_id, NTTIME now,
-				struct smbXsrv_session **session)
+NTSTATUS smb2srv_session_lookup_conn(struct smbXsrv_connection *conn,
+				     uint64_t session_id, NTTIME now,
+				     struct smbXsrv_session **session)
 {
 	struct smbXsrv_session_table *table = conn->client->session_table;
-	return smb2srv_session_lookup_raw(table, session_id, now, session);
+	return smb2srv_session_lookup_raw(table, conn, session_id, now,
+					  session);
+}
+
+NTSTATUS smb2srv_session_lookup_client(struct smbXsrv_client *client,
+				       uint64_t session_id, NTTIME now,
+				       struct smbXsrv_session **session)
+{
+	struct smbXsrv_session_table *table = client->session_table;
+	return smb2srv_session_lookup_raw(table, NULL, session_id, now,
+					  session);
 }
 
 struct smbXsrv_session_global_traverse_state {
diff --git a/source3/smbd/smbXsrv_tcon.c b/source3/smbd/smbXsrv_tcon.c
index 1d2a141..ddd03f6 100644
--- a/source3/smbd/smbXsrv_tcon.c
+++ b/source3/smbd/smbXsrv_tcon.c
@@ -150,6 +150,48 @@ static NTSTATUS smbXsrv_tcon_local_key_to_id(TDB_DATA key, uint32_t *id)
 	return NT_STATUS_OK;
 }
 
+static struct db_record *smbXsrv_tcon_global_fetch_locked(
+			struct db_context *db,
+			uint32_t id,
+			TALLOC_CTX *mem_ctx)
+{
+	TDB_DATA key;
+	uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE];
+	struct db_record *rec = NULL;
+
+	key = smbXsrv_tcon_global_id_to_key(id, key_buf);
+
+	rec = dbwrap_fetch_locked(db, mem_ctx, key);
+
+	if (rec == NULL) {
+		DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
+			  hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
+	}
+
+	return rec;
+}
+
+static struct db_record *smbXsrv_tcon_local_fetch_locked(
+			struct db_context *db,
+			uint32_t id,
+			TALLOC_CTX *mem_ctx)
+{
+	TDB_DATA key;
+	uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
+	struct db_record *rec = NULL;
+
+	key = smbXsrv_tcon_local_id_to_key(id, key_buf);
+
+	rec = dbwrap_fetch_locked(db, mem_ctx, key);
+
+	if (rec == NULL) {
+		DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
+			  hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
+	}
+
+	return rec;
+}
+
 static NTSTATUS smbXsrv_tcon_table_init(TALLOC_CTX *mem_ctx,
 					struct smbXsrv_tcon_table *table,
 					uint32_t lowest_id,
@@ -266,8 +308,6 @@ static NTSTATUS smb1srv_tcon_local_allocate_id(struct db_context *db,
 
 	for (i = 0; i < (range / 2); i++) {
 		uint32_t id;
-		uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 		TDB_DATA val;
 		struct db_record *rec = NULL;
 
@@ -281,9 +321,7 @@ static NTSTATUS smb1srv_tcon_local_allocate_id(struct db_context *db,
 			id = highest_id;
 		}
 
-		key = smbXsrv_tcon_local_id_to_key(id, key_buf);
-
-		rec = dbwrap_fetch_locked(db, mem_ctx, key);
+		rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx);
 		if (rec == NULL) {
 			return NT_STATUS_INSUFFICIENT_RESOURCES;
 		}
@@ -333,16 +371,12 @@ static NTSTATUS smb1srv_tcon_local_allocate_id(struct db_context *db,
 
 	if (NT_STATUS_IS_OK(state.status)) {
 		uint32_t id;
-		uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 		TDB_DATA val;
 		struct db_record *rec = NULL;
 
 		id = state.useable_id;
 
-		key = smbXsrv_tcon_local_id_to_key(id, key_buf);
-
-		rec = dbwrap_fetch_locked(db, mem_ctx, key);
+		rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx);
 		if (rec == NULL) {
 			return NT_STATUS_INSUFFICIENT_RESOURCES;
 		}
@@ -473,8 +507,6 @@ static NTSTATUS smbXsrv_tcon_global_allocate(struct db_context *db,
 		bool is_free = false;
 		bool was_free = false;
 		uint32_t id;
-		uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 
 		if (i >= min_tries && last_free != 0) {
 			id = last_free;
@@ -488,9 +520,8 @@ static NTSTATUS smbXsrv_tcon_global_allocate(struct db_context *db,
 			id--;
 		}
 
-		key = smbXsrv_tcon_global_id_to_key(id, key_buf);
-
-		global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
+		global->db_rec = smbXsrv_tcon_global_fetch_locked(db, id,
+								  mem_ctx);
 		if (global->db_rec == NULL) {
 			talloc_free(global);
 			return NT_STATUS_INSUFFICIENT_RESOURCES;
@@ -737,17 +768,14 @@ static NTSTATUS smbXsrv_tcon_create(struct smbXsrv_tcon_table *table,
 
 	if (protocol >= PROTOCOL_SMB2_02) {
 		uint64_t id = global->tcon_global_id;
-		uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
 
 		global->tcon_wire_id = id;
 
 		tcon->local_id = global->tcon_global_id;
 
-		key = smbXsrv_tcon_local_id_to_key(tcon->local_id, key_buf);
-
-		local_rec = dbwrap_fetch_locked(table->local.db_ctx,
-						tcon, key);
+		local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
+							tcon->local_id,
+							tcon /* TALLOC_CTX */);
 		if (local_rec == NULL) {
 			TALLOC_FREE(tcon);
 			return NT_STATUS_NO_MEMORY;
@@ -820,8 +848,6 @@ NTSTATUS smbXsrv_tcon_update(struct smbXsrv_tcon *tcon)
 {
 	struct smbXsrv_tcon_table *table = tcon->table;
 	NTSTATUS status;
-	uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE];
-	TDB_DATA key;
 
 	if (tcon->global->db_rec != NULL) {
 		DEBUG(0, ("smbXsrv_tcon_update(0x%08x): "
@@ -830,17 +856,11 @@ NTSTATUS smbXsrv_tcon_update(struct smbXsrv_tcon *tcon)
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	key = smbXsrv_tcon_global_id_to_key(tcon->global->tcon_global_id,
-					    key_buf);
-
-	tcon->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
-						   tcon->global, key);
+	tcon->global->db_rec = smbXsrv_tcon_global_fetch_locked(
+						table->global.db_ctx,
+						tcon->global->tcon_global_id,
+						tcon->global /* TALLOC_CTX */);
 	if (tcon->global->db_rec == NULL) {
-		DEBUG(0, ("smbXsrv_tcon_update(0x%08x): "
-			  "Failed to lock global key '%s'\n",
-			  tcon->global->tcon_global_id,
-			  hex_encode_talloc(talloc_tos(), key.dptr,
-					    key.dsize)));
 		return NT_STATUS_INTERNAL_DB_ERROR;
 	}
 
@@ -888,22 +908,11 @@ NTSTATUS smbXsrv_tcon_disconnect(struct smbXsrv_tcon *tcon, uint64_t vuid)
 	global_rec = tcon->global->db_rec;
 	tcon->global->db_rec = NULL;
 	if (global_rec == NULL) {
-		uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE];
-		TDB_DATA key;
-
-		key = smbXsrv_tcon_global_id_to_key(
+		global_rec = smbXsrv_tcon_global_fetch_locked(
+						table->global.db_ctx,
 						tcon->global->tcon_global_id,
-						key_buf);
-
-		global_rec = dbwrap_fetch_locked(table->global.db_ctx,
-						 tcon->global, key);
+						tcon->global /* TALLOC_CTX */);
 		if (global_rec == NULL) {
-			DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
-				  "Failed to lock global key '%s'\n",
-				  tcon->global->tcon_global_id,
-				  tcon->global->share_name,
-				  hex_encode_talloc(global_rec, key.dptr,
-						    key.dsize)));
 			error = NT_STATUS_INTERNAL_ERROR;
 		}
 	}
@@ -927,20 +936,10 @@ NTSTATUS smbXsrv_tcon_disconnect(struct smbXsrv_tcon *tcon, uint64_t vuid)
 
 	local_rec = tcon->db_rec;
 	if (local_rec == NULL) {
-		uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
-		TDB_DATA key;
-
-		key = smbXsrv_tcon_local_id_to_key(tcon->local_id, key_buf);
-
-		local_rec = dbwrap_fetch_locked(table->local.db_ctx,
-						tcon, key);
+		local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
+							tcon->local_id,
+							tcon /* TALLOC_CTX */);
 		if (local_rec == NULL) {
-			DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
-				  "Failed to lock local key '%s'\n",
-				  tcon->global->tcon_global_id,
-				  tcon->global->share_name,
-				  hex_encode_talloc(local_rec, key.dptr,
-						    key.dsize)));
 			error = NT_STATUS_INTERNAL_ERROR;
 		}
 	}
diff --git a/source3/smbd/smbd_cleanupd.c b/source3/smbd/smbd_cleanupd.c
new file mode 100644
index 0000000..c940ef1
--- /dev/null
+++ b/source3/smbd/smbd_cleanupd.c
@@ -0,0 +1,156 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smbd_cleanupd.h"
+#include "lib/util_procid.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/util/debug.h"
+#include "smbprofile.h"
+#include "serverid.h"
+#include "locking/proto.h"
+
+struct smbd_cleanupd_state {
+	pid_t parent_pid;
+};
+
+static void smbd_cleanupd_shutdown(struct messaging_context *msg,
+				   void *private_data, uint32_t msg_type,
+				   struct server_id server_id,
+				   DATA_BLOB *data);
+static void smbd_cleanupd_process_exited(struct messaging_context *msg,
+					 void *private_data, uint32_t msg_type,
+					 struct server_id server_id,
+					 DATA_BLOB *data);
+static void smbd_cleanupd_unlock(struct messaging_context *msg,
+				 void *private_data, uint32_t msg_type,
+				 struct server_id server_id,
+				 DATA_BLOB *data);
+
+struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      struct messaging_context *msg,
+				      pid_t parent_pid)
+{
+	struct tevent_req *req;
+	struct smbd_cleanupd_state *state;
+	NTSTATUS status;
+
+	req = tevent_req_create(mem_ctx, &state, struct smbd_cleanupd_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->parent_pid = parent_pid;
+
+	status = messaging_register(msg, req, MSG_SHUTDOWN,
+				    smbd_cleanupd_shutdown);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	status = messaging_register(msg, req, MSG_SMB_NOTIFY_CLEANUP,
+				    smbd_cleanupd_process_exited);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	status = messaging_register(msg, NULL, MSG_SMB_UNLOCK,
+				    smbd_cleanupd_unlock);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	return req;
+}
+
+static void smbd_cleanupd_shutdown(struct messaging_context *msg,
+				   void *private_data, uint32_t msg_type,
+				   struct server_id server_id,
+				   DATA_BLOB *data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	tevent_req_done(req);
+}
+
+static void smbd_cleanupd_unlock(struct messaging_context *msg,
+				 void *private_data, uint32_t msg_type,
+				 struct server_id server_id,
+				 DATA_BLOB *data)
+{
+	DBG_WARNING("Cleaning up brl and lock database after unclean "
+		    "shutdown\n");
+
+	message_send_all(msg, MSG_SMB_UNLOCK, NULL, 0, NULL);
+
+	brl_revalidate(msg, private_data, msg_type, server_id, data);
+}
+
+static void smbd_cleanupd_process_exited(struct messaging_context *msg,
+					 void *private_data, uint32_t msg_type,
+					 struct server_id server_id,
+					 DATA_BLOB *data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	struct smbd_cleanupd_state *state = tevent_req_data(
+		req, struct smbd_cleanupd_state);
+	pid_t pid;
+	struct server_id child_id;
+	bool unclean_shutdown;
+	int ret;
+
+	if (data->length != (sizeof(pid) + sizeof(unclean_shutdown))) {
+		DBG_WARNING("Got invalid length: %zu\n", data->length);
+		return;
+	}
+
+	memcpy(&pid, data->data, sizeof(pid));
+	memcpy(&unclean_shutdown, data->data + sizeof(pid),
+	       sizeof(unclean_shutdown));
+
+	DBG_DEBUG("%d exited %sclean\n", (int)pid,
+		  unclean_shutdown ? "un" : "");
+
+	/*
+	 * Get child_id before messaging_cleanup which wipes the
+	 * unique_id. Not that it really matters here for functionality (the
+	 * child should have properly cleaned up :-)) though, but it looks
+	 * nicer.
+	 */
+	child_id = pid_to_procid(pid);
+
+	smbprofile_cleanup(pid, state->parent_pid);
+
+	ret = messaging_cleanup(msg, pid);
+
+	if ((ret != 0) && (ret != ENOENT)) {
+		DBG_DEBUG("messaging_cleanup returned %s\n", strerror(ret));
+	}
+
+	if (!serverid_deregister(child_id)) {
+		DEBUG(1, ("Could not remove pid %d from serverid.tdb\n",
+			  (int)pid));
+	}
+}
+
+NTSTATUS smbd_cleanupd_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_ntstatus(req);
+}
diff --git a/source3/smbd/smbd_cleanupd.h b/source3/smbd/smbd_cleanupd.h
new file mode 100644
index 0000000..6e5d87f
--- /dev/null
+++ b/source3/smbd/smbd_cleanupd.h
@@ -0,0 +1,33 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SMBD_CLEANUPD_H__
+#define __SMBD_CLEANUPD_H__
+
+#include "replace.h"
+#include <tevent.h>
+#include "messages.h"
+
+struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      struct messaging_context *msg,
+				      pid_t parent_pid);
+NTSTATUS smbd_cleanupd_recv(struct tevent_req *req);
+
+#endif
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index ff1ef15..b65f581 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -82,6 +82,15 @@ static NTSTATUS refuse_symlink(connection_struct *conn,
 	return NT_STATUS_OK;
 }
 
+NTSTATUS check_access_fsp(const struct files_struct *fsp,
+			  uint32_t access_mask)
+{
+	if (!(fsp->access_mask & access_mask)) {
+		return NT_STATUS_ACCESS_DENIED;
+	}
+	return NT_STATUS_OK;
+}
+
 /********************************************************************
  The canonical "check access" based on object handle or path function.
 ********************************************************************/
@@ -91,20 +100,16 @@ NTSTATUS check_access(connection_struct *conn,
 				const struct smb_filename *smb_fname,
 				uint32_t access_mask)
 {
+	NTSTATUS status;
+
 	if (fsp) {
-		if (!(fsp->access_mask & access_mask)) {
-			return NT_STATUS_ACCESS_DENIED;
-		}
+		status = check_access_fsp(fsp, access_mask);
 	} else {
-		NTSTATUS status = smbd_check_access_rights(conn,
-					smb_fname,
-					false,
-					access_mask);
-		if (!NT_STATUS_IS_OK(status)) {
-			return status;
-		}
+		status = smbd_check_access_rights(conn, smb_fname,
+						  false, access_mask);
 	}
-	return NT_STATUS_OK;
+
+	return status;
 }
 
 /********************************************************************
@@ -423,7 +428,7 @@ static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struc
 			  "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
 			  (unsigned int)listp->ea.value.length));
 
-		DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
+		DLIST_ADD_END(ea_list_head, listp);
 
 	}
 
@@ -783,7 +788,7 @@ static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, siz
 		}
 
 		offset += (namelen + 1); /* Go past the name + terminating zero. */
-		DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+		DLIST_ADD_END(ea_list_head, eal);
 		DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
 	}
 
@@ -807,7 +812,7 @@ static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t d
 			return NULL;
 		}
 
-		DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+		DLIST_ADD_END(ea_list_head, eal);
 		offset += bytes_used;
 	}
 
@@ -1131,6 +1136,7 @@ static void call_trans2open(connection_struct *conn,
 	uint32_t create_disposition;
 	uint32_t create_options = 0;
 	uint32_t private_flags = 0;
+	uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	/*
@@ -1164,9 +1170,25 @@ static void call_trans2open(connection_struct *conn,
 		goto out;
 	}
 
-	srvstr_get_path(ctx, params, req->flags2, &fname, pname,
-			total_params - 28, STR_TERMINATE,
+	if (req->posix_pathnames) {
+		srvstr_get_path_posix(ctx,
+			params,
+			req->flags2,
+			&fname,
+			pname,
+			total_params - 28,
+			STR_TERMINATE,
+			&status);
+	} else {
+		srvstr_get_path(ctx,
+			params,
+			req->flags2,
+			&fname,
+			pname,
+			total_params - 28,
+			STR_TERMINATE,
 			&status);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		reply_nterror(req, status);
 		goto out;
@@ -1180,7 +1202,7 @@ static void call_trans2open(connection_struct *conn,
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				fname,
-				0,
+				ucf_flags,
 				NULL,
 				&smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -2511,7 +2533,8 @@ static void call_trans2findfirst(connection_struct *conn,
 	TALLOC_CTX *ctx = talloc_tos();
 	struct dptr_struct *dirptr = NULL;
 	struct smbd_server_connection *sconn = req->sconn;
-	uint32_t ucf_flags = (UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP);
+	uint32_t ucf_flags = UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP |
+			(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	bool backup_priv = false;
 	bool as_root = false;
 
@@ -2569,9 +2592,27 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
 			goto out;
 	}
 
-	srvstr_get_path_wcard(ctx, params, req->flags2, &directory,
-			      params+12, total_params - 12,
-			      STR_TERMINATE, &ntstatus, &mask_contains_wcard);
+	if (req->posix_pathnames) {
+		srvstr_get_path_wcard_posix(ctx,
+				params,
+				req->flags2,
+				&directory,
+				params+12,
+				total_params - 12,
+				STR_TERMINATE,
+				&ntstatus,
+				&mask_contains_wcard);
+	} else {
+		srvstr_get_path_wcard(ctx,
+				params,
+				req->flags2,
+				&directory,
+				params+12,
+				total_params - 12,
+				STR_TERMINATE,
+				&ntstatus,
+				&mask_contains_wcard);
+	}
 	if (!NT_STATUS_IS_OK(ntstatus)) {
 		reply_nterror(req, ntstatus);
 		goto out;
@@ -2927,10 +2968,27 @@ static void call_trans2findnext(connection_struct *conn,
 
 	if (!continue_bit) {
 		/* We only need resume_name if continue_bit is zero. */
-		srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name,
-			      params+12,
-			      total_params - 12, STR_TERMINATE, &ntstatus,
-			      &mask_contains_wcard);
+		if (req->posix_pathnames) {
+			srvstr_get_path_wcard_posix(ctx,
+				params,
+				req->flags2,
+				&resume_name,
+				params+12,
+				total_params - 12,
+				STR_TERMINATE,
+				&ntstatus,
+				&mask_contains_wcard);
+		} else {
+			srvstr_get_path_wcard(ctx,
+				params,
+				req->flags2,
+				&resume_name,
+				params+12,
+				total_params - 12,
+				STR_TERMINATE,
+				&ntstatus,
+				&mask_contains_wcard);
+		}
 		if (!NT_STATUS_IS_OK(ntstatus)) {
 			/* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
 			   complain (it thinks we're asking for the directory above the shared
@@ -3844,7 +3902,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
 					&conn->session_info->security_token->sids[i],
 					0);
 
-				sid_linearize(pdata + data_len, sid_len,
+				sid_linearize((uint8_t *)(pdata + data_len),
+					      sid_len,
 				    &conn->session_info->security_token->sids[i]);
 				data_len += sid_len;
 			}
@@ -5582,7 +5641,8 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
 	} else {
 		uint32_t name_hash;
 		char *fname = NULL;
-		uint32_t ucf_flags = 0;
+		uint32_t ucf_flags = (req->posix_pathnames ?
+				UCF_POSIX_PATHNAMES : 0);
 
 		/* qpathinfo */
 		if (total_params < 7) {
@@ -5606,9 +5666,25 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
 			}
 		}
 
-		srvstr_get_path(req, params, req->flags2, &fname, &params[6],
+		if (req->posix_pathnames) {
+			srvstr_get_path_posix(req,
+				params,
+				req->flags2,
+				&fname,
+				&params[6],
 				total_params - 6,
-				STR_TERMINATE, &status);
+				STR_TERMINATE,
+				&status);
+		} else {
+			srvstr_get_path(req,
+				params,
+				req->flags2,
+				&fname,
+				&params[6],
+				total_params - 6,
+				STR_TERMINATE,
+				&status);
+		}
 		if (!NT_STATUS_IS_OK(status)) {
 			reply_nterror(req, status);
 			return;
@@ -6412,6 +6488,7 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
 {
 	char *oldname = NULL;
 	struct smb_filename *smb_fname_old = NULL;
+	uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 	NTSTATUS status = NT_STATUS_OK;
 
@@ -6420,8 +6497,25 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
-	srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata,
-			total_data, STR_TERMINATE, &status);
+	if (req->posix_pathnames) {
+		srvstr_get_path_posix(ctx,
+			pdata,
+			req->flags2,
+			&oldname,
+			pdata,
+			total_data,
+			STR_TERMINATE,
+			&status);
+	} else {
+		srvstr_get_path(ctx,
+			pdata,
+			req->flags2,
+			&oldname,
+			pdata,
+			total_data,
+			STR_TERMINATE,
+			&status);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -6433,7 +6527,7 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				oldname,
-				0,
+				ucf_flags,
 				NULL,
 				&smb_fname_old);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -6459,6 +6553,8 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
 	uint32_t len;
 	char *newname = NULL;
 	struct smb_filename *smb_fname_dst = NULL;
+	uint32_t ucf_flags = UCF_SAVE_LCOMP |
+		(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	NTSTATUS status = NT_STATUS_OK;
 	TALLOC_CTX *ctx = talloc_tos();
 
@@ -6477,9 +6573,25 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
-	srvstr_get_path(ctx, pdata, req->flags2, &newname,
-				&pdata[20], len, STR_TERMINATE,
+	if (req->posix_pathnames) {
+		srvstr_get_path_posix(ctx,
+				pdata,
+				req->flags2,
+				&newname,
+				&pdata[20],
+				len,
+				STR_TERMINATE,
 				&status);
+	} else {
+		srvstr_get_path(ctx,
+				pdata,
+				req->flags2,
+				&newname,
+				&pdata[20],
+				len,
+				STR_TERMINATE,
+				&status);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -6491,7 +6603,7 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				newname,
-				UCF_SAVE_LCOMP,
+				ucf_flags,
 				NULL,
 				&smb_fname_dst);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -6551,6 +6663,8 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
 	char *newname = NULL;
 	struct smb_filename *smb_fname_dst = NULL;
 	NTSTATUS status = NT_STATUS_OK;
+	uint32_t ucf_flags = UCF_SAVE_LCOMP |
+		(req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	if (!fsp) {
@@ -6568,9 +6682,25 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
-	srvstr_get_path(ctx, pdata, req->flags2, &newname,
-				&pdata[20], len, STR_TERMINATE,
+	if (req->posix_pathnames) {
+		srvstr_get_path_posix(ctx,
+				pdata,
+				req->flags2,
+				&newname,
+				&pdata[20],
+				len,
+				STR_TERMINATE,
 				&status);
+	} else {
+		srvstr_get_path(ctx,
+				pdata,
+				req->flags2,
+				&newname,
+				&pdata[20],
+				len,
+				STR_TERMINATE,
+				&status);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -6582,7 +6712,7 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				newname,
-				UCF_SAVE_LCOMP,
+				ucf_flags,
 				NULL,
 				&smb_fname_dst);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -6642,9 +6772,27 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
-	srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12],
-			      len, 0, &status,
-			      &dest_has_wcard);
+	if (req->posix_pathnames) {
+		srvstr_get_path_wcard_posix(ctx,
+				pdata,
+				req->flags2,
+				&newname,
+				&pdata[12],
+				len,
+				0,
+				&status,
+				&dest_has_wcard);
+	} else {
+		srvstr_get_path_wcard(ctx,
+				pdata,
+				req->flags2,
+				&newname,
+				&pdata[12],
+				len,
+				0,
+				&status,
+				&dest_has_wcard);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -8468,7 +8616,8 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 		}
 	} else {
 		char *fname = NULL;
-		uint32_t ucf_flags = 0;
+		uint32_t ucf_flags = (req->posix_pathnames ?
+			UCF_POSIX_PATHNAMES : 0);
 
 		/* set path info */
 		if (total_params < 7) {
@@ -8477,9 +8626,25 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 		}
 
 		info_level = SVAL(params,0);
-		srvstr_get_path(req, params, req->flags2, &fname, &params[6],
-				total_params - 6, STR_TERMINATE,
+		if (req->posix_pathnames) {
+			srvstr_get_path_posix(req,
+				params,
+				req->flags2,
+				&fname,
+				&params[6],
+				total_params - 6,
+				STR_TERMINATE,
+				&status);
+		} else {
+			srvstr_get_path(req,
+				params,
+				req->flags2,
+				&fname,
+				&params[6],
+				total_params - 6,
+				STR_TERMINATE,
 				&status);
+		}
 		if (!NT_STATUS_IS_OK(status)) {
 			reply_nterror(req, status);
 			return;
@@ -8602,6 +8767,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
 	char *directory = NULL;
 	NTSTATUS status = NT_STATUS_OK;
 	struct ea_list *ea_list = NULL;
+	uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
 	TALLOC_CTX *ctx = talloc_tos();
 
 	if (!CAN_WRITE(conn)) {
@@ -8614,9 +8780,25 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
 		return;
 	}
 
-	srvstr_get_path(ctx, params, req->flags2, &directory, &params[4],
-			total_params - 4, STR_TERMINATE,
+	if (req->posix_pathnames) {
+		srvstr_get_path_posix(ctx,
+			params,
+			req->flags2,
+			&directory,
+			&params[4],
+			total_params - 4,
+			STR_TERMINATE,
 			&status);
+	} else {
+		srvstr_get_path(ctx,
+			params,
+			req->flags2,
+			&directory,
+			&params[4],
+			total_params - 4,
+			STR_TERMINATE,
+			&status);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		reply_nterror(req, status);
 		return;
@@ -8628,7 +8810,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
 				conn,
 				req->flags2 & FLAGS2_DFS_PATHNAMES,
 				directory,
-				0,
+				ucf_flags,
 				NULL,
 				&smb_dname);
 
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 1a2ee3d..89f0ae1 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -1404,12 +1404,12 @@ uint64_t smb_vfs_call_disk_free(struct vfs_handle_struct *handle,
 	return handle->fns->disk_free_fn(handle, path, bsize, dfree, dsize);
 }
 
-int smb_vfs_call_get_quota(struct vfs_handle_struct *handle,
+int smb_vfs_call_get_quota(struct vfs_handle_struct *handle, const char *path,
 			   enum SMB_QUOTA_TYPE qtype, unid_t id,
 			   SMB_DISK_QUOTA *qt)
 {
 	VFS_FIND(get_quota);
-	return handle->fns->get_quota_fn(handle, qtype, id, qt);
+	return handle->fns->get_quota_fn(handle, path, qtype, id, qt);
 }
 
 int smb_vfs_call_set_quota(struct vfs_handle_struct *handle,
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index e75f2aa..e323069 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -41,7 +41,7 @@
 #include "util_tdb.h"
 #include "../libcli/smb/read_smb.h"
 #include "../libcli/smb/smbXcli_base.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 
 extern char *optarg;
 extern int optind;
@@ -3264,8 +3264,7 @@ static bool run_trans2test(int dummy)
 		printf("ERROR: qfilename failed (%s)\n", nt_errstr(status));
 		correct = False;
 	}
-
-	if (strcmp(pname, fname)) {
+	else if (strcmp(pname, fname)) {
 		printf("qfilename gave different name? [%s] [%s]\n",
 		       fname, pname);
 		correct = False;
@@ -9043,7 +9042,7 @@ static bool run_local_sid_to_string(int dummy) {
 
 static bool run_local_binary_to_sid(int dummy) {
 	struct dom_sid *sid = talloc(NULL, struct dom_sid);
-	static const char good_binary_sid[] = {
+	static const uint8_t good_binary_sid[] = {
 		0x1, /* revision number */
 		15, /* num auths */
 		0x1, 0x1, 0x1, 0x1, 0x1, 0x1, /* id_auth */
@@ -9064,7 +9063,7 @@ static bool run_local_binary_to_sid(int dummy) {
 		0x1, 0x1, 0x1, 0x1, /* auth[14] */
 	};
 
-	static const char long_binary_sid[] = {
+	static const uint8_t long_binary_sid[] = {
 		0x1, /* revision number */
 		15, /* num auths */
 		0x1, 0x1, 0x1, 0x1, 0x1, 0x1, /* id_auth */
@@ -9088,7 +9087,7 @@ static bool run_local_binary_to_sid(int dummy) {
 		0x1, 0x1, 0x1, 0x1, /* auth[17] */
 	};
 
-	static const char long_binary_sid2[] = {
+	static const uint8_t long_binary_sid2[] = {
 		0x1, /* revision number */
 		32, /* num auths */
 		0x1, 0x1, 0x1, 0x1, 0x1, 0x1, /* id_auth */
diff --git a/source3/utils/net.c b/source3/utils/net.c
index 8182323..3d0940d 100644
--- a/source3/utils/net.c
+++ b/source3/utils/net.c
@@ -795,7 +795,7 @@ static struct functable net_func[] = {
 		{"port",	'p', POPT_ARG_INT,    &c->opt_port},
 		{"myname",	'n', POPT_ARG_STRING, &c->opt_requester_name},
 		{"server",	'S', POPT_ARG_STRING, &c->opt_host},
-		{"encrypt",	'e', POPT_ARG_NONE,   NULL, 'e', N_("Encrypt SMB transport (UNIX extended servers only)") },
+		{"encrypt",	'e', POPT_ARG_NONE,   NULL, 'e', N_("Encrypt SMB transport") },
 		{"container",	'c', POPT_ARG_STRING, &c->opt_container},
 		{"comment",	'C', POPT_ARG_STRING, &c->opt_comment},
 		{"maxusers",	'M', POPT_ARG_INT,    &c->opt_maxusers},
@@ -839,6 +839,8 @@ static struct functable net_func[] = {
 		{"wipe", 0, POPT_ARG_NONE, &c->opt_wipe},
 		/* Options for 'net registry import' */
 		{"precheck", 0, POPT_ARG_STRING, &c->opt_precheck},
+		/* Options for 'net ads join' */
+		{"no-dns-updates", 0, POPT_ARG_NONE, &c->opt_no_dns_updates},
 		POPT_COMMON_SAMBA
 		{ 0, 0, 0, 0}
 	};
@@ -948,11 +950,11 @@ static struct functable net_func[] = {
 	}
 
 	if (!c->opt_workgroup) {
-		c->opt_workgroup = smb_xstrdup(lp_workgroup());
+		c->opt_workgroup = talloc_strdup(c, lp_workgroup());
 	}
 
 	if (!c->opt_target_workgroup) {
-		c->opt_target_workgroup = smb_xstrdup(lp_workgroup());
+		c->opt_target_workgroup = talloc_strdup(c, lp_workgroup());
 	}
 
 	if (!init_names())
diff --git a/source3/utils/net.h b/source3/utils/net.h
index cded8e1..d6dfeb6 100644
--- a/source3/utils/net.h
+++ b/source3/utils/net.h
@@ -84,6 +84,7 @@ struct net_context {
 	const char *opt_output;
 	int opt_wipe;
 	const char *opt_precheck;
+	int opt_no_dns_updates;
 
 	int opt_have_ip;
 	struct sockaddr_storage opt_dest_ip;
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index 28553fc..ace5b27 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -177,6 +177,7 @@ static int net_ads_info(struct net_context *c, int argc, const char **argv)
 {
 	ADS_STRUCT *ads;
 	char addr[INET6_ADDRSTRLEN];
+	time_t pass_time;
 
 	if (c->display_usage) {
 		d_printf("%s\n"
@@ -206,6 +207,8 @@ static int net_ads_info(struct net_context *c, int argc, const char **argv)
 		d_fprintf( stderr, _("Failed to get server's current time!\n"));
 	}
 
+	pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
+
 	print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
 
 	d_printf(_("LDAP server: %s\n"), addr);
@@ -219,6 +222,9 @@ static int net_ads_info(struct net_context *c, int argc, const char **argv)
 	d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
 	d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
 
+	d_printf(_("Last machine account password change: %s\n"),
+		 http_timestring(talloc_tos(), pass_time));
+
 	ads_destroy(&ads);
 	return 0;
 }
@@ -1312,26 +1318,29 @@ static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_S
 
 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
 {
-	d_printf(_("net ads join [options]\n"
+	d_printf(_("net ads join [--no-dns-updates] [options]\n"
 	           "Valid options:\n"));
-	d_printf(_("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n"
-		   "                      The deault UPN is in the form host/netbiosname at REALM.\n"));
-	d_printf(_("   createcomputer=OU  Precreate the computer account in a specific OU.\n"
-		   "                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
-		   "                      E.g. \"createcomputer=Computers/Servers/Unix\"\n"
-		   "                      NB: A backslash '\\' is used as escape at multiple levels and may\n"
-		   "                          need to be doubled or even quadrupled.  It is not used as a separator.\n"));
-	d_printf(_("   machinepass=PASS   Set the machine password to a specific value during the join.\n"
-		   "                      The deault password is random.\n"));
-	d_printf(_("   osName=string      Set the operatingSystem attribute during the join.\n"));
-	d_printf(_("   osVer=string       Set the operatingSystemVersion attribute during the join.\n"
-		   "                      NB: osName and osVer must be specified together for either to take effect.\n"
-		   "                          Also, the operatingSystemService attribute is also set when along with\n"
-		   "                          the two other attributes.\n"));
-
-	d_printf(_("   osServicePack=string Set the operatingSystemServicePack "
-		   "attribute during the join. Note: if not specified then by "
-		   "default the samba version string is used instead.\n"));
+	d_printf(_("   createupn[=UPN]       Set the userPrincipalName attribute during the join.\n"
+		   "                         The default UPN is in the form host/netbiosname at REALM.\n"));
+	d_printf(_("   createcomputer=OU     Precreate the computer account in a specific OU.\n"
+		   "                         The OU string read from top to bottom without RDNs\n"
+		   "                         and delimited by a '/'.\n"
+		   "                         E.g. \"createcomputer=Computers/Servers/Unix\"\n"
+		   "                         NB: A backslash '\\' is used as escape at multiple\n"
+		   "                             levels and may need to be doubled or even\n"
+		   "                             quadrupled. It is not used as a separator.\n"));
+	d_printf(_("   machinepass=PASS      Set the machine password to a specific value during\n"
+		   "                         the join. The default password is random.\n"));
+	d_printf(_("   osName=string         Set the operatingSystem attribute during the join.\n"));
+	d_printf(_("   osVer=string          Set the operatingSystemVersion attribute during join.\n"
+		   "                         NB: osName and osVer must be specified together for\n"
+		   "                             either to take effect. The operatingSystemService\n"
+		   "                             attribute is then also set along with the two\n"
+		   "                             other attributes.\n"));
+	d_printf(_("   osServicePack=string  Set the operatingSystemServicePack attribute\n"
+		   "                         during the join.\n"
+		   "                         NB: If not specified then by default the samba\n"
+		   "                             version string is used instead.\n"));
 	return -1;
 }
 
@@ -1588,11 +1597,14 @@ int net_ads_join(struct net_context *c, int argc, const char **argv)
 	}
 
 	/*
-	 * We try doing the dns update (if it was compiled in).
+	 * We try doing the dns update (if it was compiled in
+	 * and if it was not disabled on the command line).
 	 * If the dns update fails, we still consider the join
 	 * operation as succeeded if we came this far.
 	 */
-	_net_ads_join_dns_updates(c, ctx, r);
+	if (!c->opt_no_dns_updates) {
+		_net_ads_join_dns_updates(c, ctx, r);
+	}
 
 	TALLOC_FREE(r);
 	TALLOC_FREE( ctx );
@@ -1898,6 +1910,7 @@ static int net_ads_printer_publish(struct net_context *c, int argc, const char *
 	char *prt_dn, *srv_dn, **srv_cn;
 	char *srv_cn_escaped = NULL, *printername_escaped = NULL;
 	LDAPMessage *res = NULL;
+	bool ok;
 
 	if (argc < 1 || c->display_usage) {
 		d_printf("%s\n%s",
@@ -1925,7 +1938,14 @@ static int net_ads_printer_publish(struct net_context *c, int argc, const char *
 
 	/* Get printer data from SPOOLSS */
 
-	resolve_name(servername, &server_ss, 0x20, false);
+	ok = resolve_name(servername, &server_ss, 0x20, false);
+	if (!ok) {
+		d_fprintf(stderr, _("Could not find server %s\n"),
+			  servername);
+		ads_destroy(&ads);
+		talloc_destroy(mem_ctx);
+		return -1;
+	}
 
 	nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
 					&server_ss, 0,
diff --git a/source3/utils/net_serverid.c b/source3/utils/net_serverid.c
index 9eb1cf4..f228c91 100644
--- a/source3/utils/net_serverid.c
+++ b/source3/utils/net_serverid.c
@@ -26,6 +26,7 @@
 #include "lib/conn_tdb.h"
 #include "smbd/globals.h"
 #include "util_tdb.h"
+#include "librpc/gen_ndr/ndr_open_files.h"
 
 static int net_serverid_list_fn(const struct server_id *id,
 				uint32_t msg_flags, void *priv)
@@ -50,7 +51,7 @@ static int net_serverid_wipe_fn(struct db_record *rec,
 {
 	NTSTATUS status;
 
-	if (id->vnn != get_my_vnn()) {
+	if (!procid_is_local(id)) {
 		return 0;
 	}
 	status = dbwrap_record_delete(rec);
@@ -303,9 +304,22 @@ static int wipedbs_traverse_open(struct smbXsrv_open_global0 *open,
 
 		if (state->verbose) {
 			TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
-			d_printf("open[global: %u] disconnected at "
+			enum ndr_err_code ndr_err;
+			struct vfs_default_durable_cookie cookie;
+
+			ndr_err = ndr_pull_struct_blob(
+				&open->backend_cookie, mem_ctx, &cookie,
+				(ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
+			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+				d_printf("ndr_pull_struct_blob failed\n");
+				ret = -1;
+				goto done;
+			}
+
+			d_printf("open[%s/%s id: 0x%" PRIx32 "] disconnected at "
 				 "[%s] %us ago with timeout of %us "
 				 "-%s reached\n",
+				 cookie.servicepath, cookie.base_name,
 				 open->open_global_id,
 				 nt_time_string(mem_ctx, open->disconnect_time),
 				 (unsigned)(tdiff/1000000),
@@ -401,6 +415,19 @@ static int wipedbs_traverse_set_exists(struct db_record *rec,
 	return 0;
 }
 
+static bool serverids_exist(const struct server_id *ids, int num_ids,
+			    bool *results)
+{
+	int i;
+
+	for (i=0; i<num_ids; i++) {
+		results[i] = serverid_exists(&ids[i]);
+	}
+
+	return true;
+}
+
+
 static NTSTATUS wipedbs_check_server_exists(struct wipedbs_state *state)
 {
 	NTSTATUS status;
@@ -641,6 +668,30 @@ done:
 	return ret;
 }
 
+static int net_serverid_exists(struct net_context *c, int argc,
+			       const char **argv)
+{
+	struct server_id pid;
+	bool ok;
+
+	if ((argc != 1) || (c->display_usage)) {
+		d_printf("Usage:\n"
+			 "net serverid exists <serverid>\n");
+		return -1;
+	}
+
+	pid = server_id_from_string(get_my_vnn(), argv[0]);
+	ok = serverid_exists(&pid);
+
+	if (ok) {
+		d_printf("%s exists\n", argv[0]);
+	} else {
+		d_printf("%s does not exist\n", argv[0]);
+	}
+
+	return 0;
+}
+
 int net_serverid(struct net_context *c, int argc, const char **argv)
 {
 	struct functable func[] = {
@@ -668,6 +719,13 @@ int net_serverid(struct net_context *c, int argc, const char **argv)
 			N_("net serverid wipedbs\n"
 			   "    Clean dead entries from temporary databases")
 		},
+		{
+			"exists",
+			net_serverid_exists,
+			NET_TRANSPORT_LOCAL,
+			N_("Show existence of a serverid"),
+			N_("net serverid exists <id>")
+		},
 		{NULL, NULL, 0, NULL, NULL}
 	};
 
diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
index a5fd249..b90f927 100644
--- a/source3/utils/ntlm_auth.c
+++ b/source3/utils/ntlm_auth.c
@@ -166,6 +166,7 @@ static DATA_BLOB opt_nt_response;
 static int request_lm_key;
 static int request_user_session_key;
 static int use_cached_creds;
+static int offline_logon;
 
 static const char *require_membership_of;
 static const char *require_membership_of_sid;
@@ -463,6 +464,10 @@ static bool check_plaintext_auth(const char *user, const char *pass,
 			sizeof(request.data.auth.require_membership_of_sid));
 	}
 
+	if (offline_logon) {
+		request.flags |= WBFLAG_PAM_CACHED_LOGIN;
+	}
+
 	result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH, &request, &response);
 
 	/* Display response */
@@ -2170,7 +2175,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod
 			uchar lm_key[8];
 			uchar user_session_key[16];
 			uint32_t flags = 0;
-
+			NTSTATUS nt_status;
 			if (full_username && !username) {
 				fstring fstr_user;
 				fstring fstr_domain;
@@ -2185,29 +2190,67 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod
 				domain = smb_xstrdup(fstr_domain);
 			}
 
-			if (!domain) {
-				domain = smb_xstrdup(get_winbind_domain());
-			}
+			if (opt_password) {
+				DATA_BLOB nt_session_key, lm_session_key;
+				struct samr_Password lm_pw, nt_pw;
+				TALLOC_CTX *mem_ctx = talloc_new(NULL);
+				ZERO_STRUCT(user_session_key);
+				ZERO_STRUCT(lm_key);
+
+				nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
+				nt_status = ntlm_password_check(mem_ctx,
+								true, true, 0,
+								&challenge,
+								&lm_response,
+								&nt_response,
+								username,
+								username,
+								domain,
+								&lm_pw, &nt_pw,
+								&nt_session_key,
+								&lm_session_key);
+				error_string = smb_xstrdup(get_friendly_nt_error_msg(nt_status));
+				if (ntlm_server_1_user_session_key) {
+					if (nt_session_key.length == sizeof(user_session_key)) {
+						memcpy(user_session_key,
+						       nt_session_key.data,
+						       sizeof(user_session_key));
+					}
+				}
+				if (ntlm_server_1_lm_session_key) {
+					if (lm_session_key.length == sizeof(lm_key)) {
+						memcpy(lm_key,
+						       lm_session_key.data,
+						       sizeof(lm_key));
+					}
+				}
+				TALLOC_FREE(mem_ctx);
 
-			if (ntlm_server_1_lm_session_key) 
-				flags |= WBFLAG_PAM_LMKEY;
-
-			if (ntlm_server_1_user_session_key) 
-				flags |= WBFLAG_PAM_USER_SESSION_KEY;
-
-			if (!NT_STATUS_IS_OK(
-				    contact_winbind_auth_crap(username, 
-							      domain, 
-							      lp_netbios_name(),
-							      &challenge, 
-							      &lm_response, 
-							      &nt_response, 
-							      flags, 0,
-							      lm_key, 
-							      user_session_key,
-							      &error_string,
-							      NULL))) {
+			} else {
+				if (!domain) {
+					domain = smb_xstrdup(get_winbind_domain());
+				}
 
+				if (ntlm_server_1_lm_session_key)
+					flags |= WBFLAG_PAM_LMKEY;
+
+				if (ntlm_server_1_user_session_key)
+					flags |= WBFLAG_PAM_USER_SESSION_KEY;
+
+				nt_status = contact_winbind_auth_crap(username,
+								      domain,
+								      lp_netbios_name(),
+								      &challenge,
+								      &lm_response,
+								      &nt_response,
+								      flags, 0,
+								      lm_key,
+								      user_session_key,
+								      &error_string,
+								      NULL);
+			}
+
+			if (!NT_STATUS_IS_OK(nt_status)) {
 				x_fprintf(x_stdout, "Authenticated: No\n");
 				x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
 			} else {
@@ -2713,7 +2756,8 @@ enum {
 	OPT_USE_CACHED_CREDS,
 	OPT_PAM_WINBIND_CONF,
 	OPT_TARGET_SERVICE,
-	OPT_TARGET_HOSTNAME
+	OPT_TARGET_HOSTNAME,
+	OPT_OFFLINE_LOGON
 };
 
  int main(int argc, const char **argv)
@@ -2750,6 +2794,9 @@ enum {
 		{ "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
 		{ "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
 		{ "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
+		{ "offline-logon", 0, POPT_ARG_NONE, &offline_logon,
+		  OPT_OFFLINE_LOGON,
+		  "Use cached passwords when DC is offline"},
 		{ "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
 		  OPT_DIAGNOSTICS,
 		  "Perform diagnostics on the authentication chain"},
diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c
index 1f44fb0..a353bae 100644
--- a/source3/utils/pdbedit.c
+++ b/source3/utils/pdbedit.c
@@ -55,9 +55,10 @@
 #define BIT_LOGONHOURS	0x10000000
 #define BIT_KICKOFFTIME	0x20000000
 #define BIT_DESCRIPTION 0x40000000
+#define BIT_PWSETNTHASH 0x80000000
 
 #define MASK_ALWAYS_GOOD	0x0000001F
-#define MASK_USER_GOOD		0x60405FE0
+#define MASK_USER_GOOD		0xE0405FE0
 
 static int get_sid_from_cli_string(struct dom_sid *sid, const char *str_sid)
 {
@@ -317,6 +318,12 @@ static int print_sam_info (struct samu *sam_pwent, bool verbosity, bool smbpwdst
 		hours = pdb_get_hours(sam_pwent);
 		pdb_sethexhours(temp, hours);
 		printf ("Logon hours         : %s\n", temp);
+		if (smbpwdstyle){
+			pdb_sethexpwd(temp, pdb_get_lanman_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));
+			printf ("LM hash             : %s\n", temp);
+			pdb_sethexpwd(temp, pdb_get_nt_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));
+			printf ("NT hash             : %s\n", temp);
+		}	
 
 	} else if (smbpwdstyle) {
 		char lm_passwd[33];
@@ -499,7 +506,7 @@ static int set_user_info(const char *username, const char *fullname,
 			 const char *profile, const char *account_control,
 			 const char *user_sid, const char *user_domain,
 			 const bool badpw, const bool hours,
-			 const char *kickoff_time)
+			 const char *kickoff_time, const char *str_hex_pwd)
 {
 	bool updated_autolock = False, updated_badpw = False;
 	struct samu *sam_pwent;
@@ -601,9 +608,33 @@ static int set_user_info(const char *username, const char *fullname,
 
 		pdb_set_kickoff_time(sam_pwent, value, PDB_CHANGED);
 	}
+	if (str_hex_pwd) {
+		unsigned char  new_nt_p16[NT_HASH_LEN];
+	        if(strlen(str_hex_pwd) != (NT_HASH_LEN *2)){
+			fprintf(stderr, "Invalid hash\n");
+			return -1;
+		}
+					 
+		pdb_gethexpwd(str_hex_pwd, new_nt_p16);
+		
+		if (!pdb_set_nt_passwd (sam_pwent, new_nt_p16 , PDB_CHANGED)) {
+			fprintf(stderr, "Failed to set password from nt-hash\n");
+			return -1;
+		}	
+
+		if (!pdb_set_pass_last_set_time (sam_pwent, time(NULL), PDB_CHANGED)){
+			fprintf(stderr, "Failed to set last password set time\n");
+			return -1;
+		}	
+		if (!pdb_update_history(sam_pwent, new_nt_p16)){
+			fprintf(stderr, "Failed to update password history\n");
+			return -1;
+		}
+	}
 
 	if (NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) {
-		print_user_info(username, True, False);
+		
+		print_user_info(username, True, (str_hex_pwd != NULL ));
 	} else {
 		fprintf (stderr, "Unable to modify entry!\n");
 		TALLOC_FREE(sam_pwent);
@@ -1021,6 +1052,7 @@ int main(int argc, const char **argv)
 	static int pw_from_stdin = False;
 	struct pdb_methods *bin, *bout;
 	static char *kickoff_time = NULL;
+	static char *str_hex_pwd = NULL;
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
 	poptContext pc;
@@ -1058,6 +1090,7 @@ int main(int argc, const char **argv)
 		{"time-format", 0, POPT_ARG_STRING, &pwd_time_format, 0, "The time format for time parameters", NULL },
 		{"password-from-stdin", 't', POPT_ARG_NONE, &pw_from_stdin, 0, "get password from standard in", NULL},
 		{"kickoff-time", 'K', POPT_ARG_STRING, &kickoff_time, 0, "set the kickoff time", NULL},
+		{"set-nt-hash", 0, POPT_ARG_STRING, &str_hex_pwd, 0, "set password from nt-hash", NULL},
 		POPT_COMMON_SAMBA
 		POPT_TABLEEND
 	};
@@ -1118,7 +1151,9 @@ int main(int argc, const char **argv)
 			(badpw_reset ? BIT_BADPWRESET : 0) +
 			(hours_reset ? BIT_LOGONHOURS : 0) +
 			(kickoff_time ? BIT_KICKOFFTIME : 0) +
+			(str_hex_pwd ? BIT_PWSETNTHASH : 0 ) +
 			(acct_desc ? BIT_DESCRIPTION : 0);
+			
 
 	if (setparms & BIT_BACKEND) {
 		/* HACK: set the global passdb backend by overwriting globals.
@@ -1315,7 +1350,7 @@ int main(int argc, const char **argv)
 						     profile_path, account_control,
 						     user_sid, user_domain,
 						     badpw_reset, hours_reset,
-						     kickoff_time);
+						     kickoff_time, str_hex_pwd);
 			}
 		}
 	}
diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c
index d1eb7dd..ad602b3 100644
--- a/source3/utils/smbcontrol.c
+++ b/source3/utils/smbcontrol.c
@@ -325,7 +325,7 @@ static int stack_trace_server(const struct server_id *id,
 			      uint32_t msg_flags,
 			      void *priv)
 {
-	if (id->vnn == get_my_vnn()) {
+	if (procid_is_local(id)) {
 		print_stack_trace(procid_to_pid(id), (int *)priv);
 	}
 	return 0;
diff --git a/source3/utils/smbfilter.c b/source3/utils/smbfilter.c
index 9b871be..9068448 100644
--- a/source3/utils/smbfilter.c
+++ b/source3/utils/smbfilter.c
@@ -22,7 +22,7 @@
 #include "system/select.h"
 #include "../lib/util/select.h"
 #include "libsmb/nmblib.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw_data.h"
 
 #define SECURITY_MASK 0
 #define SECURITY_SET  0
diff --git a/source3/utils/smbget.c b/source3/utils/smbget.c
index 127d6b1..4909fa2 100644
--- a/source3/utils/smbget.c
+++ b/source3/utils/smbget.c
@@ -1,6 +1,6 @@
 /*
-   smbget: a wget-like utility with support for recursive downloading and 
-   	smb:// urls
+   smbget: a wget-like utility with support for recursive downloading of
+	smb:// urls
    Copyright (C) 2003-2004 Jelmer Vernooij <jelmer at samba.org>
 
    This program is free software; you can redistribute it and/or modify
@@ -21,51 +21,61 @@
 #include "popt_common.h"
 #include "libsmbclient.h"
 
-#if _FILE_OFFSET_BITS==64
-#define OFF_T_FORMAT "%lld"
-#define OFF_T_FORMAT_CAST long long
-#else
-#define OFF_T_FORMAT "%ld"
-#define OFF_T_FORMAT_CAST long
-#endif
-
 static int columns = 0;
 
-static int debuglevel, update;
-static char *outputfile;
-
-
 static time_t total_start_time = 0;
 static off_t total_bytes = 0;
 
 #define SMB_MAXPATHLEN MAXPATHLEN
 
-/* Number of bytes to read when checking whether local and remote file are really the same file */
-#define RESUME_CHECK_SIZE 				512
-#define RESUME_DOWNLOAD_OFFSET			1024
-#define RESUME_CHECK_OFFSET				RESUME_DOWNLOAD_OFFSET+RESUME_CHECK_SIZE
+/*
+ * Number of bytes to read when checking whether local and remote file
+ * are really the same file
+ */
+#define RESUME_CHECK_SIZE 	512
+#define RESUME_DOWNLOAD_OFFSET	1024
+#define RESUME_CHECK_OFFSET	(RESUME_DOWNLOAD_OFFSET+RESUME_CHECK_SIZE)
 /* Number of bytes to read at once */
-#define SMB_DEFAULT_BLOCKSIZE 					64000
-
-static const char *username = NULL, *password = NULL, *workgroup = NULL;
-static int nonprompt = 0, quiet = 0, dots = 0, keep_permissions = 0, verbose = 0, send_stdout = 0;
-static int blocksize = SMB_DEFAULT_BLOCKSIZE;
-
-static int smb_download_file(const char *base, const char *name, int recursive,
-			     int resume, int toplevel, char *outfile);
+#define SMB_DEFAULT_BLOCKSIZE 	64000
+
+struct opt {
+	char *workgroup;
+	bool username_specified;
+	char *username;
+	bool password_specified;
+	char *password;
+
+	char *outputfile;
+	size_t blocksize;
+
+	bool nonprompt;
+	bool quiet;
+	bool dots;
+	bool verbose;
+	bool send_stdout;
+	bool update;
+	int debuglevel;
+};
+static struct opt opt = { .blocksize = SMB_DEFAULT_BLOCKSIZE };
+
+static bool smb_download_file(const char *base, const char *name,
+			      bool recursive, bool resume, bool toplevel,
+			      char *outfile);
 
 static int get_num_cols(void)
 {
 #ifdef TIOCGWINSZ
 	struct winsize ws;
-	if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) {
+	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) {
 		return 0;
 	}
 	return ws.ws_col;
 #else
 #warning No support for TIOCGWINSZ
 	char *cols = getenv("COLUMNS");
-	if(!cols) return 0;
+	if (!cols) {
+		return 0;
+	}
 	return atoi(cols);
 #endif
 }
@@ -84,17 +94,17 @@ static void human_readable(off_t s, char *buffer, int l)
 	} else if (s > 1024) {
 		snprintf(buffer, l, "%.2fkB", 1.0 * s / 1024);
 	} else {
-		snprintf(buffer, l, OFF_T_FORMAT"b", (OFF_T_FORMAT_CAST)s);
+		snprintf(buffer, l, "%jdb", (intmax_t)s);
 	}
 }
 
-static void get_auth_data(const char *srv, const char *shr, char *wg, int wglen, char *un, int unlen, char *pw, int pwlen)
+static void get_auth_data(const char *srv, const char *shr, char *wg, int wglen,
+			  char *un, int unlen, char *pw, int pwlen)
 {
-	static char hasasked = 0;
+	static bool hasasked = false;
 	static char *savedwg;
 	static char *savedun;
 	static char *savedpw;
-	char *wgtmp, *usertmp;
 	char tmp[128];
 
 	if (hasasked) {
@@ -103,144 +113,164 @@ static void get_auth_data(const char *srv, const char *shr, char *wg, int wglen,
 		strncpy(pw, savedpw, pwlen - 1);
 		return;
 	}
-	hasasked = 1;
+	hasasked = true;
 
-	if(!nonprompt && !username) {
+	if (!opt.nonprompt && !opt.username_specified) {
 		printf("Username for %s at %s [guest] ", shr, srv);
 		if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
 			return;
 		}
-		if ((strlen(tmp) > 0) && (tmp[strlen(tmp)-1] == '\n')) {
-			tmp[strlen(tmp)-1] = '\0';
+		if ((strlen(tmp) > 0) && (tmp[strlen(tmp) - 1] == '\n')) {
+			tmp[strlen(tmp) - 1] = '\0';
 		}
-		strncpy(un, tmp, unlen-1);
-	} else if(username) strncpy(un, username, unlen-1);
+		strncpy(un, tmp, unlen - 1);
+	} else if (opt.username != NULL) {
+		strncpy(un, opt.username, unlen - 1);
+	}
 
-	if(!nonprompt && !password) {
+	if (!opt.nonprompt && !opt.password_specified) {
 		char *prompt;
-		if (asprintf(&prompt, "Password for %s at %s: ", shr, srv) == -1) {
+		if (asprintf(&prompt, "Password for %s at %s: ", shr, srv) ==
+		    -1) {
 			return;
 		}
-		(void) samba_getpass(prompt, pw, pwlen, false, false);
+		(void)samba_getpass(prompt, pw, pwlen, false, false);
 		free(prompt);
-	} else if(password) strncpy(pw, password, pwlen-1);
+	} else if (opt.password != NULL) {
+		strncpy(pw, opt.password, pwlen-1);
+	}
 
-	if(workgroup)strncpy(wg, workgroup, wglen-1);
+	if (opt.workgroup != NULL) {
+		strncpy(wg, opt.workgroup, wglen-1);
+	}
 
 	/* save the values found for later */
 	savedwg = SMB_STRDUP(wg);
 	savedun = SMB_STRDUP(un);
 	savedpw = SMB_STRDUP(pw);
 
-	wgtmp = SMB_STRNDUP(wg, wglen); 
-	usertmp = SMB_STRNDUP(un, unlen);
-	if(!quiet)printf("Using workgroup %s, %s%s\n", wgtmp, *usertmp?"user ":"guest user", usertmp);
-	free(wgtmp); free(usertmp);
+	if (!opt.quiet) {
+		char *wgtmp, *usertmp;
+		wgtmp = SMB_STRNDUP(wg, wglen);
+		usertmp = SMB_STRNDUP(un, unlen);
+		printf("Using workgroup %s, %s%s\n",
+		       wgtmp,
+		       *usertmp ? "user " : "guest user",
+		       usertmp);
+		free(wgtmp);
+		free(usertmp);
+	}
 }
 
-/* Return 1 on error, 0 on success. */
-
-static int smb_download_dir(const char *base, const char *name, int resume)
+static bool smb_download_dir(const char *base, const char *name, int resume)
 {
 	char path[SMB_MAXPATHLEN];
 	int dirhandle;
 	struct smbc_dirent *dirent;
 	const char *relname = name;
 	char *tmpname;
-	struct stat remotestat;
-	int ret = 0;
+	bool ok = false;
 
-	snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (base[0] && name[0] && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name);
+	snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base,
+		 (base[0] && name[0] && name[0] != '/' &&
+		  base[strlen(base)-1] != '/') ? "/" : "",
+		 name);
 
 	/* List files in directory and call smb_download_file on them */
 	dirhandle = smbc_opendir(path);
-	if(dirhandle < 1) {
+	if (dirhandle < 1) {
 		if (errno == ENOTDIR) {
-			return smb_download_file(base, name, 1, resume,
-						 0, NULL);
+			return smb_download_file(base, name, true, resume,
+						 false, NULL);
 		}
-		fprintf(stderr, "Can't open directory %s: %s\n", path, strerror(errno));
-		return 1;
+		fprintf(stderr, "Can't open directory %s: %s\n", path,
+			strerror(errno));
+		return false;
 	}
 
-	while(*relname == '/')relname++;
+	while (*relname == '/') {
+		relname++;
+	}
 	mkdir(relname, 0755);
 
 	tmpname = SMB_STRDUP(name);
 
-	while((dirent = smbc_readdir(dirhandle))) {
+	while ((dirent = smbc_readdir(dirhandle))) {
 		char *newname;
-		if(!strcmp(dirent->name, ".") || !strcmp(dirent->name, ".."))continue;
+		if (!strcmp(dirent->name, ".") || !strcmp(dirent->name, "..")) {
+			continue;
+		}
 		if (asprintf(&newname, "%s/%s", tmpname, dirent->name) == -1) {
 			free(tmpname);
-			return 1;
+			return false;
 		}
-		switch(dirent->smbc_type) {
+		switch (dirent->smbc_type) {
 		case SMBC_DIR:
-			ret = smb_download_dir(base, newname, resume);
+			ok = smb_download_dir(base, newname, resume);
 			break;
 
 		case SMBC_WORKGROUP:
-			ret = smb_download_dir("smb://", dirent->name, resume);
+			ok = smb_download_dir("smb://", dirent->name, resume);
 			break;
 
 		case SMBC_SERVER:
-			ret = smb_download_dir("smb://", dirent->name, resume);
+			ok = smb_download_dir("smb://", dirent->name, resume);
 			break;
 
 		case SMBC_FILE:
-			ret = smb_download_file(base, newname, 1, resume, 0,
-						NULL);
+			ok = smb_download_file(base, newname, true, resume,
+						false, NULL);
 			break;
 
 		case SMBC_FILE_SHARE:
-			ret = smb_download_dir(base, newname, resume);
+			ok = smb_download_dir(base, newname, resume);
 			break;
 
 		case SMBC_PRINTER_SHARE:
-			if(!quiet)printf("Ignoring printer share %s\n", dirent->name);
+			if (!opt.quiet) {
+				printf("Ignoring printer share %s\n",
+				       dirent->name);
+			}
 			break;
 
 		case SMBC_COMMS_SHARE:
-			if(!quiet)printf("Ignoring comms share %s\n", dirent->name);
+			if (!opt.quiet) {
+				printf("Ignoring comms share %s\n",
+				       dirent->name);
+			}
 			break;
 
 		case SMBC_IPC_SHARE:
-			if(!quiet)printf("Ignoring ipc$ share %s\n", dirent->name);
+			if (!opt.quiet) {
+				printf("Ignoring ipc$ share %s\n",
+				       dirent->name);
+			}
 			break;
 
 		default:
-			fprintf(stderr, "Ignoring file '%s' of type '%d'\n", newname, dirent->smbc_type);
+			fprintf(stderr, "Ignoring file '%s' of type '%d'\n",
+				newname, dirent->smbc_type);
 			break;
 		}
-		free(newname);
-	}
-	free(tmpname);
-
-	if(keep_permissions) {
-		if(smbc_fstat(dirhandle, &remotestat) < 0) {
-			fprintf(stderr, "Unable to get stats on %s on remote server\n", path);
-			smbc_closedir(dirhandle);
-			return 1;
-		}
 
-		if(chmod(relname, remotestat.st_mode) < 0) {
-			fprintf(stderr, "Unable to change mode of local dir %s to %o\n", relname,
-				(unsigned int)remotestat.st_mode);
-			smbc_closedir(dirhandle);
-			return 1;
+		if (!ok) {
+			fprintf(stderr, "Failed to download %s: %s\n",
+				newname, strerror(errno));
+			return false;
 		}
+		free(newname);
 	}
+	free(tmpname);
 
 	smbc_closedir(dirhandle);
-	return ret;
+	return ok;
 }
 
 static char *print_time(long t)
 {
 	static char buffer[100];
 	int secs, mins, hours;
-	if(t < -1) {
+	if (t < -1) {
 		strncpy(buffer, "Unknown", sizeof(buffer));
 		return buffer;
 	}
@@ -248,51 +278,64 @@ static char *print_time(long t)
 	secs = (int)t % 60;
 	mins = (int)t / 60 % 60;
 	hours = (int)t / (60 * 60);
-	snprintf(buffer, sizeof(buffer)-1, "%02d:%02d:%02d", hours, mins, secs);
+	snprintf(buffer, sizeof(buffer) - 1, "%02d:%02d:%02d", hours, mins,
+		 secs);
 	return buffer;
 }
 
-static void print_progress(const char *name, time_t start, time_t now, off_t start_pos, off_t pos, off_t total)
+static void print_progress(const char *name, time_t start, time_t now,
+			   off_t start_pos, off_t pos, off_t total)
 {
 	double avg = 0.0;
-	long  eta = -1; 
+	long eta = -1;
 	double prcnt = 0.0;
 	char hpos[20], htotal[20], havg[20];
 	char *status, *filename;
 	int len;
-	if(now - start)avg = 1.0 * (pos - start_pos) / (now - start);
+	if (now - start) {
+		avg = 1.0 * (pos - start_pos) / (now - start);
+	}
 	eta = (total - pos) / avg;
-	if(total)prcnt = 100.0 * pos / total;
+	if (total) {
+		prcnt = 100.0 * pos / total;
+	}
 
 	human_readable(pos, hpos, sizeof(hpos));
 	human_readable(total, htotal, sizeof(htotal));
 	human_readable(avg, havg, sizeof(havg));
 
-	len = asprintf(&status, "%s of %s (%.2f%%) at %s/s ETA: %s", hpos, htotal, prcnt, havg, print_time(eta));
+	len = asprintf(&status, "%s of %s (%.2f%%) at %s/s ETA: %s", hpos,
+		       htotal, prcnt, havg, print_time(eta));
 	if (len == -1) {
 		return;
 	}
 
-	if(columns) {
-		int required = strlen(name), available = columns - len - strlen("[] ");
-		if(required > available) {
-			if (asprintf(&filename, "...%s", name + required - available + 3) == -1) {
+	if (columns) {
+		int required = strlen(name),
+		    available = columns - len - strlen("[] ");
+		if (required > available) {
+			if (asprintf(&filename, "...%s",
+				     name + required - available + 3) == -1) {
 				return;
 			}
 		} else {
 			filename = SMB_STRNDUP(name, available);
 		}
-	} else filename = SMB_STRDUP(name);
+	} else {
+		filename = SMB_STRDUP(name);
+	}
 
 	fprintf(stderr, "\r[%s] %s", filename, status);
 
-	free(filename); free(status);
+	free(filename);
+	free(status);
 }
 
-/* Return 1 on error, 0 on success. */
+/* Return false on error, true on success. */
 
-static int smb_download_file(const char *base, const char *name, int recursive,
-			     int resume, int toplevel, char *outfile)
+static bool smb_download_file(const char *base, const char *name,
+			      bool recursive, bool resume, bool toplevel,
+			      char *outfile)
 {
 	int remotehandle, localhandle;
 	time_t start_time = time_mono(NULL);
@@ -300,158 +343,221 @@ static int smb_download_file(const char *base, const char *name, int recursive,
 	char path[SMB_MAXPATHLEN];
 	char checkbuf[2][RESUME_CHECK_SIZE];
 	char *readbuf = NULL;
-	off_t offset_download = 0, offset_check = 0, curpos = 0, start_offset = 0;
+	off_t offset_download = 0, offset_check = 0, curpos = 0,
+	      start_offset = 0;
 	struct stat localstat, remotestat;
 
-	snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (*base && *name && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name);
+	snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base,
+		 (*base && *name && name[0] != '/' &&
+		  base[strlen(base)-1] != '/') ? "/" : "",
+		 name);
 
 	remotehandle = smbc_open(path, O_RDONLY, 0755);
 
-	if(remotehandle < 0) {
-		switch(errno) {
-		case EISDIR: 
-			if(!recursive) {
-				fprintf(stderr, "%s is a directory. Specify -R to download recursively\n", path);
-				return 1;
+	if (remotehandle < 0) {
+		switch (errno) {
+		case EISDIR:
+			if (!recursive) {
+				fprintf(stderr,
+					"%s is a directory. Specify -R "
+					"to download recursively\n",
+					path);
+				return false;
 			}
 			return smb_download_dir(base, name, resume);
 
 		case ENOENT:
-			fprintf(stderr, "%s can't be found on the remote server\n", path);
-			return 1;
+			fprintf(stderr,
+				"%s can't be found on the remote server\n",
+				path);
+			return false;
 
 		case ENOMEM:
 			fprintf(stderr, "Not enough memory\n");
-			return 1;
+			return false;
 
 		case ENODEV:
-			fprintf(stderr, "The share name used in %s does not exist\n", path);
-			return 1;
+			fprintf(stderr,
+				"The share name used in %s does not exist\n",
+				path);
+			return false;
 
 		case EACCES:
-			fprintf(stderr, "You don't have enough permissions to access %s\n", path);
-			return 1;
+			fprintf(stderr, "You don't have enough permissions "
+				"to access %s\n",
+				path);
+			return false;
 
 		default:
 			perror("smbc_open");
-			return 1;
+			return false;
 		}
-	} 
+	}
 
-	if(smbc_fstat(remotehandle, &remotestat) < 0) {
+	if (smbc_fstat(remotehandle, &remotestat) < 0) {
 		fprintf(stderr, "Can't stat %s: %s\n", path, strerror(errno));
-		return 1;
+		return false;
 	}
 
-	if(outfile) newpath = outfile;
-	else if(!name[0]) {
+	if (outfile) {
+		newpath = outfile;
+	} else if (!name[0]) {
 		newpath = strrchr(base, '/');
-		if(newpath)newpath++; else newpath = base;
-	} else newpath = name;
+		if (newpath) {
+			newpath++;
+		} else {
+			newpath = base;
+		}
+	} else {
+		newpath = name;
+	}
 
 	if (!toplevel && (newpath[0] == '/')) {
 		newpath++;
 	}
 
 	/* Open local file according to the mode */
-	if(update) {
+	if (opt.update) {
 		/* if it is up-to-date, skip */
-		if(stat(newpath, &localstat) == 0 &&
-				localstat.st_mtime >= remotestat.st_mtime) {
-			if(verbose)
+		if (stat(newpath, &localstat) == 0 &&
+		    localstat.st_mtime >= remotestat.st_mtime) {
+			if (opt.verbose) {
 				printf("%s is up-to-date, skipping\n", newpath);
+			}
 			smbc_close(remotehandle);
-			return 0;
+			return true;
 		}
 		/* else open it for writing and truncate if it exists */
-		localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR | O_TRUNC, 0775);
-		if(localhandle < 0) {
+		localhandle = open(
+		    newpath, O_CREAT | O_NONBLOCK | O_RDWR | O_TRUNC, 0775);
+		if (localhandle < 0) {
 			fprintf(stderr, "Can't open %s : %s\n", newpath,
-					strerror(errno));
+				strerror(errno));
 			smbc_close(remotehandle);
-			return 1;
+			return false;
 		}
 		/* no offset */
-	} else if(!send_stdout) {
-		localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR | (!resume?O_EXCL:0), 0755);
-		if(localhandle < 0) {
-			fprintf(stderr, "Can't open %s: %s\n", newpath, strerror(errno));
+	} else if (!opt.send_stdout) {
+		localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR |
+						(!resume ? O_EXCL : 0),
+				   0755);
+		if (localhandle < 0) {
+			fprintf(stderr, "Can't open %s: %s\n", newpath,
+				strerror(errno));
 			smbc_close(remotehandle);
-			return 1;
+			return false;
 		}
 
 		if (fstat(localhandle, &localstat) != 0) {
-			fprintf(stderr, "Can't fstat %s: %s\n", newpath, strerror(errno));
+			fprintf(stderr, "Can't fstat %s: %s\n", newpath,
+				strerror(errno));
 			smbc_close(remotehandle);
 			close(localhandle);
-			return 1;
+			return false;
 		}
 
 		start_offset = localstat.st_size;
 
-		if(localstat.st_size && localstat.st_size == remotestat.st_size) {
-			if(verbose)fprintf(stderr, "%s is already downloaded completely.\n", path);
-			else if(!quiet)fprintf(stderr, "%s\n", path);
+		if (localstat.st_size &&
+		    localstat.st_size == remotestat.st_size) {
+			if (opt.verbose) {
+				fprintf(stderr, "%s is already downloaded "
+					"completely.\n",
+					path);
+			} else if (!opt.quiet) {
+				fprintf(stderr, "%s\n", path);
+			}
 			smbc_close(remotehandle);
 			close(localhandle);
-			return 0;
+			return true;
 		}
 
-		if(localstat.st_size > RESUME_CHECK_OFFSET && remotestat.st_size > RESUME_CHECK_OFFSET) {
-			offset_download = localstat.st_size - RESUME_DOWNLOAD_OFFSET;
+		if (localstat.st_size > RESUME_CHECK_OFFSET &&
+		    remotestat.st_size > RESUME_CHECK_OFFSET) {
+			offset_download =
+			    localstat.st_size - RESUME_DOWNLOAD_OFFSET;
 			offset_check = localstat.st_size - RESUME_CHECK_OFFSET;
-			if(verbose)printf("Trying to start resume of %s at "OFF_T_FORMAT"\n"
-				   "At the moment "OFF_T_FORMAT" of "OFF_T_FORMAT" bytes have been retrieved\n",
-				newpath, (OFF_T_FORMAT_CAST)offset_check, 
-				(OFF_T_FORMAT_CAST)localstat.st_size,
-				(OFF_T_FORMAT_CAST)remotestat.st_size);
+			if (opt.verbose) {
+				printf("Trying to start resume of %s at %jd\n"
+				       "At the moment %jd of %jd bytes have "
+				       "been retrieved\n",
+				       newpath, (intmax_t)offset_check,
+				       (intmax_t)localstat.st_size,
+				       (intmax_t)remotestat.st_size);
+			}
 		}
 
-		if(offset_check) { 
+		if (offset_check) {
 			off_t off1, off2;
-			/* First, check all bytes from offset_check to offset_download */
+			/* First, check all bytes from offset_check to
+			 * offset_download */
 			off1 = lseek(localhandle, offset_check, SEEK_SET);
-			if(off1 < 0) {
-				fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in local file %s\n",
-					(OFF_T_FORMAT_CAST)offset_check, newpath);
-				smbc_close(remotehandle); close(localhandle);
-				return 1;
+			if (off1 < 0) {
+				fprintf(stderr,
+					"Can't seek to %jd in local file %s\n",
+					(intmax_t)offset_check, newpath);
+				smbc_close(remotehandle);
+				close(localhandle);
+				return false;
 			}
 
-			off2 = smbc_lseek(remotehandle, offset_check, SEEK_SET); 
-			if(off2 < 0) {
-				fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in remote file %s\n",
-					(OFF_T_FORMAT_CAST)offset_check, newpath);
-				smbc_close(remotehandle); close(localhandle);
-				return 1;
+			off2 = smbc_lseek(remotehandle, offset_check, SEEK_SET);
+			if (off2 < 0) {
+				fprintf(stderr,
+					"Can't seek to %jd in remote file %s\n",
+					(intmax_t)offset_check, newpath);
+				smbc_close(remotehandle);
+				close(localhandle);
+				return false;
 			}
 
-			if(off1 != off2) {
-				fprintf(stderr, "Offset in local and remote files is different (local: "OFF_T_FORMAT", remote: "OFF_T_FORMAT")\n",
-					(OFF_T_FORMAT_CAST)off1,
-					(OFF_T_FORMAT_CAST)off2);
-				smbc_close(remotehandle); close(localhandle);
-				return 1;
+			if (off1 != off2) {
+				fprintf(stderr, "Offset in local and remote "
+					"files are different "
+					"(local: %jd, remote: %jd)\n",
+					(intmax_t)off1, (intmax_t)off2);
+				smbc_close(remotehandle);
+				close(localhandle);
+				return false;
 			}
 
-			if(smbc_read(remotehandle, checkbuf[0], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) {
-				fprintf(stderr, "Can't read %d bytes from remote file %s\n", RESUME_CHECK_SIZE, path);
-				smbc_close(remotehandle); close(localhandle);
-				return 1;
+			if (smbc_read(remotehandle, checkbuf[0],
+				      RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) {
+				fprintf(stderr, "Can't read %d bytes from "
+					"remote file %s\n",
+					RESUME_CHECK_SIZE, path);
+				smbc_close(remotehandle);
+				close(localhandle);
+				return false;
 			}
 
-			if(read(localhandle, checkbuf[1], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) {
-				fprintf(stderr, "Can't read %d bytes from local file %s\n", RESUME_CHECK_SIZE, name);
-				smbc_close(remotehandle); close(localhandle);
-				return 1;
+			if (read(localhandle, checkbuf[1], RESUME_CHECK_SIZE) !=
+			    RESUME_CHECK_SIZE) {
+				fprintf(stderr, "Can't read %d bytes from "
+					"local file %s\n",
+					RESUME_CHECK_SIZE, name);
+				smbc_close(remotehandle);
+				close(localhandle);
+				return false;
 			}
 
-			if(memcmp(checkbuf[0], checkbuf[1], RESUME_CHECK_SIZE) == 0) {
-				if(verbose)printf("Current local and remote file appear to be the same. Starting download from offset "OFF_T_FORMAT"\n", (OFF_T_FORMAT_CAST)offset_download);
+			if (memcmp(checkbuf[0], checkbuf[1],
+				   RESUME_CHECK_SIZE) == 0) {
+				if (opt.verbose) {
+					printf("Current local and remote file "
+					       "appear to be the same. "
+					       "Starting download from "
+					       "offset %jd\n",
+					       (intmax_t)offset_download);
+				}
 			} else {
-				fprintf(stderr, "Local and remote file appear to be different, not doing resume for %s\n", path);
-				smbc_close(remotehandle); close(localhandle);
-				return 1;
+				fprintf(stderr, "Local and remote file appear "
+					"to be different, not "
+					"doing resume for %s\n",
+					path);
+				smbc_close(remotehandle);
+				close(localhandle);
+				return false;
 			}
 		}
 	} else {
@@ -461,79 +567,91 @@ static int smb_download_file(const char *base, const char *name, int recursive,
 		offset_check = 0;
 	}
 
-	readbuf = (char *)SMB_MALLOC(blocksize);
+	readbuf = (char *)SMB_MALLOC(opt.blocksize);
 	if (!readbuf) {
+		fprintf(stderr, "Failed to allocate %zu bytes for read "
+				"buffer (%s)", opt.blocksize, strerror(errno));
 		if (localhandle != STDOUT_FILENO) {
 			close(localhandle);
 		}
-		return 1;
+		return false;
 	}
 
 	/* Now, download all bytes from offset_download to the end */
-	for(curpos = offset_download; curpos < remotestat.st_size; curpos+=blocksize) {
-		ssize_t bytesread = smbc_read(remotehandle, readbuf, blocksize);
+	for (curpos = offset_download; curpos < remotestat.st_size;
+	     curpos += opt.blocksize) {
+		ssize_t bytesread;
+		ssize_t byteswritten;
+
+		bytesread = smbc_read(remotehandle, readbuf, opt.blocksize);
 		if(bytesread < 0) {
-			fprintf(stderr, "Can't read %u bytes at offset "OFF_T_FORMAT", file %s\n", (unsigned int)blocksize, (OFF_T_FORMAT_CAST)curpos, path);
+			fprintf(stderr,
+				"Can't read %zu bytes at offset %jd, file %s\n",
+				opt.blocksize, (intmax_t)curpos, path);
 			smbc_close(remotehandle);
-			if (localhandle != STDOUT_FILENO) close(localhandle);
+			if (localhandle != STDOUT_FILENO) {
+				close(localhandle);
+			}
 			free(readbuf);
-			return 1;
+			return false;
 		}
 
 		total_bytes += bytesread;
 
-		if(write(localhandle, readbuf, bytesread) < 0) {
-			fprintf(stderr, "Can't write %u bytes to local file %s at offset "OFF_T_FORMAT"\n", (unsigned int)bytesread, path, (OFF_T_FORMAT_CAST)curpos);
+		byteswritten = write(localhandle, readbuf, bytesread);
+		if (byteswritten != bytesread) {
+			fprintf(stderr,
+				"Can't write %zd bytes to local file %s at "
+				"offset %jd\n", bytesread, path,
+				(intmax_t)curpos);
 			free(readbuf);
 			smbc_close(remotehandle);
-			if (localhandle != STDOUT_FILENO) close(localhandle);
-			return 1;
+			if (localhandle != STDOUT_FILENO) {
+				close(localhandle);
+			}
+			return false;
 		}
 
-		if(dots)fputc('.', stderr);
-		else if(!quiet) {
+		if (opt.dots) {
+			fputc('.', stderr);
+		} else if (!opt.quiet) {
 			print_progress(newpath, start_time, time_mono(NULL),
-					start_offset, curpos, remotestat.st_size);
+				       start_offset, curpos,
+				       remotestat.st_size);
 		}
 	}
 
 	free(readbuf);
 
-	if(dots){
+	if (opt.dots) {
 		fputc('\n', stderr);
 		printf("%s downloaded\n", path);
-	} else if(!quiet) {
+	} else if (!opt.quiet) {
 		int i;
 		fprintf(stderr, "\r%s", path);
-		if(columns) {
-			for(i = strlen(path); i < columns; i++) {
+		if (columns) {
+			for (i = strlen(path); i < columns; i++) {
 				fputc(' ', stderr);
 			}
 		}
 		fputc('\n', stderr);
 	}
 
-	if(keep_permissions && !send_stdout) {
-		if(fchmod(localhandle, remotestat.st_mode) < 0) {
-			fprintf(stderr, "Unable to change mode of local file %s to %o\n", path,
-				(unsigned int)remotestat.st_mode);
-			smbc_close(remotehandle);
-			close(localhandle);
-			return 1;
-		}
-	}
-
 	smbc_close(remotehandle);
-	if (localhandle != STDOUT_FILENO) close(localhandle);
-	return 0;
+	if (localhandle != STDOUT_FILENO) {
+		close(localhandle);
+	}
+	return true;
 }
 
 static void clean_exit(void)
 {
 	char bs[100];
 	human_readable(total_bytes, bs, sizeof(bs));
-	if(!quiet)fprintf(stderr, "Downloaded %s in %lu seconds\n", bs,
-		(unsigned long)(time_mono(NULL) - total_start_time));
+	if (!opt.quiet) {
+		fprintf(stderr, "Downloaded %s in %lu seconds\n", bs,
+			(unsigned long)(time_mono(NULL) - total_start_time));
+	}
 	exit(0);
 }
 
@@ -547,33 +665,48 @@ static int readrcfile(const char *name, const struct poptOption long_options[])
 	FILE *fd = fopen(name, "r");
 	int lineno = 0, i;
 	char var[101], val[101];
-	char found;
-	int *intdata; char **stringdata;
-	if(!fd) {
+	bool found;
+	int *intdata;
+	char **stringdata;
+	if (!fd) {
 		fprintf(stderr, "Can't open RC file %s\n", name);
 		return 1;
 	}
 
-	while(!feof(fd)) {
+	while (!feof(fd)) {
 		lineno++;
-		if(fscanf(fd, "%100s %100s\n", var, val) < 2) {
-			fprintf(stderr, "Can't parse line %d of %s, ignoring.\n", lineno, name);
+		if (fscanf(fd, "%100s %100s\n", var, val) < 2) {
+			fprintf(stderr,
+				"Can't parse line %d of %s, ignoring.\n",
+				lineno, name);
 			continue;
 		}
 
-		found = 0;
+		found = false;
 
-		for(i = 0; long_options[i].shortName; i++) {
-			if(!long_options[i].longName)continue;
-			if(strcmp(long_options[i].longName, var)) continue;
-			if(!long_options[i].arg)continue;
+		for (i = 0; long_options[i].argInfo; i++) {
+			if (!long_options[i].longName) {
+				continue;
+			}
+			if (strcmp(long_options[i].longName, var)) {
+				continue;
+			}
+			if (!long_options[i].arg) {
+				continue;
+			}
 
-			switch(long_options[i].argInfo) {
+			switch (long_options[i].argInfo) {
 			case POPT_ARG_NONE:
 				intdata = (int *)long_options[i].arg;
-				if(!strcmp(val, "on")) *intdata = 1;
-				else if(!strcmp(val, "off")) *intdata = 0;
-				else fprintf(stderr, "Illegal value %s for %s at line %d in %s\n", val, var, lineno, name);
+				if (!strcmp(val, "on")) {
+					*intdata = 1;
+				} else if (!strcmp(val, "off")) {
+					*intdata = 0;
+				} else {
+					fprintf(stderr, "Illegal value %s for "
+						"%s at line %d in %s\n",
+						val, var, lineno, name);
+				}
 				break;
 			case POPT_ARG_INT:
 				intdata = (int *)long_options[i].arg;
@@ -582,16 +715,30 @@ static int readrcfile(const char *name, const struct poptOption long_options[])
 			case POPT_ARG_STRING:
 				stringdata = (char **)long_options[i].arg;
 				*stringdata = SMB_STRDUP(val);
+				if (long_options[i].shortName == 'U') {
+					char *p;
+					opt.username_specified = true;
+					p = strchr(*stringdata, '%');
+					if (p != NULL) {
+						*p = '\0';
+						opt.password = p + 1;
+						opt.password_specified = true;
+					}
+				}
 				break;
 			default:
-				fprintf(stderr, "Invalid variable %s at line %d in %s\n", var, lineno, name);
+				fprintf(stderr, "Invalid variable %s at "
+					"line %d in %s\n",
+					var, lineno, name);
 				break;
 			}
 
-			found = 1;
+			found = true;
 		}
-		if(!found) {
-			fprintf(stderr, "Invalid variable %s at line %d in %s\n", var, lineno, name);
+		if (!found) {
+			fprintf(stderr,
+				"Invalid variable %s at line %d in %s\n", var,
+				lineno, name);
 		}
 	}
 
@@ -599,7 +746,7 @@ static int readrcfile(const char *name, const struct poptOption long_options[])
 	return 0;
 }
 
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
 {
 	int c = 0;
 	const char *file = NULL;
@@ -607,27 +754,32 @@ int main(int argc, const char **argv)
 	bool smb_encrypt = false;
 	int resume = 0, recursive = 0;
 	TALLOC_CTX *frame = talloc_stackframe();
-	int ret = 0;
+	bool ret = true;
+	char *p;
+	const char **argv_const = discard_const_p(const char *, argv);
 	struct poptOption long_options[] = {
-		{"guest", 'a', POPT_ARG_NONE, NULL, 'a', "Work as user guest" },	
-		{"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },	
-		{"resume", 'r', POPT_ARG_NONE, &resume, 0, "Automatically resume aborted files" },
-		{"update", 'U',  POPT_ARG_NONE, &update, 0, "Download only when remote file is newer than local file or local file is missing"},
-		{"recursive", 'R',  POPT_ARG_NONE, &recursive, 0, "Recursively download files" },
-		{"username", 'u', POPT_ARG_STRING, &username, 'u', "Username to use" },
-		{"password", 'p', POPT_ARG_STRING, &password, 'p', "Password to use" },
-		{"workgroup", 'w', POPT_ARG_STRING, &workgroup, 'w', "Workgroup to use (optional)" },
-		{"nonprompt", 'n', POPT_ARG_NONE, &nonprompt, 'n', "Don't ask anything (non-interactive)" },
-		{"debuglevel", 'd', POPT_ARG_INT, &debuglevel, 'd', "Debuglevel to use" },
-		{"outputfile", 'o', POPT_ARG_STRING, &outputfile, 'o', "Write downloaded data to specified file" },
-		{"stdout", 'O', POPT_ARG_NONE, &send_stdout, 'O', "Write data to stdout" },
-		{"dots", 'D', POPT_ARG_NONE, &dots, 'D', "Show dots as progress indication" },
-		{"quiet", 'q', POPT_ARG_NONE, &quiet, 'q', "Be quiet" },
-		{"verbose", 'v', POPT_ARG_NONE, &verbose, 'v', "Be verbose" },
-		{"keep-permissions", 'P', POPT_ARG_NONE, &keep_permissions, 'P', "Keep permissions" },
-		{"blocksize", 'b', POPT_ARG_INT, &blocksize, 'b', "Change number of bytes in a block"},
-		{"rcfile", 'f', POPT_ARG_STRING, NULL, 'f', "Use specified rc file"},
 		POPT_AUTOHELP
+
+		{"workgroup",  'w', POPT_ARG_STRING, &opt.workgroup,   'w', "Workgroup to use (optional)" },
+		{"user",       'U', POPT_ARG_STRING, &opt.username,    'U', "Username to use" },
+		{"guest",      'a', POPT_ARG_NONE,   NULL,             'a', "Work as user guest" },
+
+		{"nonprompt",  'n', POPT_ARG_NONE,   NULL,             'n',  "Don't ask anything (non-interactive)" },
+		{"debuglevel", 'd', POPT_ARG_INT,    &opt.debuglevel,  'd', "Debuglevel to use" },
+
+		{"encrypt",    'e', POPT_ARG_NONE,   NULL,             'e', "Encrypt SMB transport" },
+		{"resume",     'r', POPT_ARG_NONE,   NULL,             'r',  "Automatically resume aborted files" },
+		{"update",     'u', POPT_ARG_NONE,   NULL,             'u',  "Download only when remote file is newer than local file or local file is missing"},
+		{"recursive",  'R', POPT_ARG_NONE,   NULL,             'R',  "Recursively download files" },
+		{"blocksize",  'b', POPT_ARG_INT,    &opt.blocksize,   'b', "Change number of bytes in a block"},
+
+		{"outputfile", 'o', POPT_ARG_STRING, &opt.outputfile,  'o', "Write downloaded data to specified file" },
+		{"stdout",     'O', POPT_ARG_NONE,   NULL,             'O',  "Write data to stdout" },
+		{"dots",       'D', POPT_ARG_NONE,   NULL,             'D',  "Show dots as progress indication" },
+		{"quiet",      'q', POPT_ARG_NONE,   NULL,             'q',  "Be quiet" },
+		{"verbose",    'v', POPT_ARG_NONE,   NULL,             'v',  "Be verbose" },
+		{"rcfile",     'f', POPT_ARG_STRING, NULL,             'f', "Use specified rc file"},
+
 		POPT_TABLEEND
 	};
 	poptContext pc;
@@ -638,8 +790,9 @@ int main(int argc, const char **argv)
 	if (asprintf(&rcfile, "%s/.smbgetrc", getenv("HOME")) == -1) {
 		return 1;
 	}
-	if(access(rcfile, F_OK) == 0) 
+	if (access(rcfile, F_OK) == 0) {
 		readrcfile(rcfile, long_options);
+	}
 	free(rcfile);
 
 #ifdef SIGWINCH
@@ -648,37 +801,86 @@ int main(int argc, const char **argv)
 	signal(SIGINT, signal_quit);
 	signal(SIGTERM, signal_quit);
 
-	pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+	pc = poptGetContext(argv[0], argc, argv_const, long_options, 0);
 
-	while((c = poptGetNextOpt(pc)) >= 0) {
-		switch(c) {
+	while ((c = poptGetNextOpt(pc)) > 0) {
+		switch (c) {
 		case 'f':
 			readrcfile(poptGetOptArg(pc), long_options);
 			break;
 		case 'a':
-			username = ""; password = "";
+			opt.username_specified = true;
+			opt.username = talloc_strdup(frame, "");
+			opt.password_specified = true;
+			opt.password = talloc_strdup(frame, "");
 			break;
 		case 'e':
 			smb_encrypt = true;
 			break;
+		case 'U':
+			opt.username_specified = true;
+			opt.username = talloc_strdup(frame, opt.username);
+			p = strchr(opt.username,'%');
+			if (p != NULL) {
+				*p = '\0';
+				opt.password = p + 1;
+				opt.password_specified = true;
+			}
+			break;
+		case 'n':
+			opt.nonprompt = true;
+			break;
+		case 'r':
+			resume = true;
+			break;
+		case 'u':
+			opt.update = true;
+			break;
+		case 'R':
+			recursive = true;
+			break;
+		case 'O':
+			opt.send_stdout = true;
+			break;
+		case 'D':
+			opt.dots = true;
+			break;
+		case 'q':
+			opt.quiet = true;
+			break;
+		case 'v':
+			opt.verbose = true;
+			break;
 		}
 	}
 
-	if((send_stdout || resume || outputfile) && update) {
-		fprintf(stderr, "The -o, -R or -O and -U options can not be used together.\n");
+	if (c < -1) {
+		fprintf(stderr, "%s: %s\n",
+			poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+			poptStrerror(c));
 		return 1;
 	}
-	if((send_stdout || outputfile) && recursive) {
-		fprintf(stderr, "The -o or -O and -R options can not be used together.\n");
+
+	if ((opt.send_stdout || resume || opt.outputfile) && opt.update) {
+		fprintf(stderr, "The -o, -R or -O and -U options can not be "
+			"used together.\n");
+		return 1;
+	}
+	if ((opt.send_stdout || opt.outputfile) && recursive) {
+		fprintf(stderr, "The -o or -O and -R options can not be "
+			"used together.\n");
 		return 1;
 	}
 
-	if(outputfile && send_stdout) {
-		fprintf(stderr, "The -o and -O options cannot be used together.\n");
+	if (opt.outputfile && opt.send_stdout) {
+		fprintf(stderr, "The -o and -O options can not be "
+			"used together.\n");
 		return 1;
 	}
 
-	if(smbc_init(get_auth_data, debuglevel) < 0) {
+	popt_burn_cmdline_password(argc, argv);
+
+	if (smbc_init(get_auth_data, opt.debuglevel) < 0) {
 		fprintf(stderr, "Unable to initialize libsmbclient\n");
 		return 1;
 	}
@@ -686,25 +888,26 @@ int main(int argc, const char **argv)
 	if (smb_encrypt) {
 		SMBCCTX *smb_ctx = smbc_set_context(NULL);
 		smbc_option_set(smb_ctx,
-			discard_const_p(char, "smb_encrypt_level"),
-			"require");
+				discard_const_p(char, "smb_encrypt_level"),
+				"require");
 	}
 
 	columns = get_num_cols();
 
 	total_start_time = time_mono(NULL);
 
-	while ( (file = poptGetArg(pc)) ) {
-		if (!recursive) 
+	while ((file = poptGetArg(pc))) {
+		if (!recursive) {
 			ret = smb_download_file(file, "", recursive, resume,
-						1, outputfile);
-		else 
+						true, opt.outputfile);
+		} else {
 			ret = smb_download_dir(file, "", resume);
+		}
 	}
 
 	TALLOC_FREE(frame);
-	if ( ret == 0){
+	if (ret) {
 		clean_exit();
 	}
-	return ret;
+	return ret?0:1;
 }
diff --git a/source3/utils/smbta-util.c b/source3/utils/smbta-util.c
deleted file mode 100644
index 7cc0a6e..0000000
--- a/source3/utils/smbta-util.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
-   smbta-util: tool for controlling encryption with
-	vfs_smb_traffic_analyzer
-   Copyright (C) 2010 Holger Hetterich <hhetter at novell.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include "includes.h"
-#include "secrets.h"
-
-static void delete_key(void);
-
-
-static void help(void)
-{
-printf("-h 		print this help message.\n");
-printf("-f <file>	install the key from a file and activate\n");
-printf("		encryption.\n");
-printf("-g <file>	generate a key, save it to a file, and activate encryption.\n");
-printf("-u		uninstall a key, and deactivate encryption.\n");
-printf("-c <file>	create a file from an installed key.\n");
-printf("-s		check if a key is installed, and print the key to stdout.\n");
-printf("\n");
-}
-
-static void check_key(void)
-{	size_t size;
-	char *akey;
-	if (!secrets_init()) {
-		printf("Error opening secrets database.");
-		exit(1);
-        }
-	akey = (char *) secrets_fetch("smb_traffic_analyzer_key", &size);
-	if (akey != NULL) {
-		printf("A key is installed: %s\n",akey);
-		printf("Encryption activated.\n");
-		free(akey);
-		exit(0);
-	} else printf("No key is installed.\n");
-	exit(1);
-}
-
-static void create_keyfile(char *filename, char *key)
-{
-	FILE *keyfile;
-	keyfile = fopen(filename, "w");
-	if (keyfile == NULL) {
-		printf("error creating the keyfile!\n");
-		exit(1);
-	}
-	fprintf(keyfile, "%s", key);
-	fclose(keyfile);
-	printf("File '%s' has been created.\n", filename);
-}
-
-/**
- * Load a key from a file. The caller has to free the
- * returned string.
- */
-static void load_key_from_file(char *filename, char *key)
-{
-	FILE *keyfile;
-	int l;
-	keyfile = fopen(filename, "r");
-	if (keyfile == NULL) {
-		printf("Error opening the keyfile!\n");
-		exit(1);
-	}
-	l = fscanf(keyfile, "%s", key);
-	if (l != 1 || strlen(key) != 16) {
-		printf("Key file in wrong format\n");
-		fclose(keyfile);
-		exit(1);
-	}
-	fclose(keyfile);
-}
-
-static void create_file_from_key(char *filename)
-{
-	size_t size;
-	char *akey = (char *) secrets_fetch("smb_traffic_analyzer_key", &size);
-	if (akey == NULL) {
-		printf("No key is installed! Can't create file.\n");
-		exit(1);
-	}
-	create_keyfile(filename, akey);
-	free(akey);
-}
-
-/**
- * Generate a random key. The user has to free the returned
- * string.
- */
-static void generate_key(char *key)
-{
-	int f;
-	srand( (unsigned)time( NULL ) );
-	for ( f = 0; f < 16; f++) {
-		*(key+f) = (rand() % 128) +32;
-	}
-	*(key+16)='\0';
-	printf("Random key generated.\n");
-}
-
-static void create_new_key_and_activate( char *filename )
-{
-	char key[17] = {0};
-
-	if (!secrets_init()) {
-		printf("Error opening secrets database.");
-		exit(1);
-	}
-
-	generate_key(key);
-	delete_key();
-	secrets_store("smb_traffic_analyzer_key", key, strlen(key)+1 );
-	printf("Key installed, encryption activated.\n");
-	create_file_from_key(filename);
-}
-
-static void delete_key(void)
-{
-	size_t size;
-	char *akey = (char *) secrets_fetch("smb_traffic_analyzer_key", &size);
-	if (akey != NULL) {
-		free(akey);
-		secrets_delete("smb_traffic_analyzer_key");
-		printf("Removed installed key. Encryption deactivated.\n");
-	} else {
-	printf("No key is installed.\n");
-	}
-}
-
-
-static void load_key_from_file_and_activate( char *filename)
-{
-	char key[17] = {0};
-	char *akey;
-	size_t size;
-	load_key_from_file(filename, key);
-	printf("Loaded key from %s.\n",filename);
-	akey = (char *) secrets_fetch("smb_traffic_analyzer_key", &size);
-	if (akey != NULL) {
-		printf("Removing the old key.\n");
-		delete_key();
-		SAFE_FREE(akey);
-	}
-	printf("Installing the key from file %s\n",filename);
-	secrets_store("smb_traffic_analyzer_key", key, strlen(key)+1);
-}
-
-static void process_arguments(int argc, char **argv)
-{
-	char co;
-	while ((co = getopt(argc, argv, "hf:g:uc:s")) != EOF) {
-		switch(co) {
-		case 'h':
-			help();
-			exit(0);
-		case 's':
-			check_key();
-			break;
-		case 'g':
-			create_new_key_and_activate(optarg);
-			break;
-		case 'u':
-			delete_key();
-			break;
-		case 'c':
-			create_file_from_key(optarg);
-			break;
-		case 'f':
-			load_key_from_file_and_activate(optarg);
-			break;
-		default:
-			help();
-			break;
-		}
-	}
-}
-
-int main(int argc, char **argv)
-{
-	sec_init();
-	smb_init_locale();
-
-	if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
-		fprintf(stderr, "Can't load %s - run testparm to debug it\n",
-						get_dyn_CONFIGFILE());
-	exit(1);
-	}
-
-	if (argc == 1) {
-		help();
-		exit(1);
-	}
-
-	process_arguments(argc, argv);
-	exit(0);
-}
diff --git a/source3/utils/status.c b/source3/utils/status.c
index f81ab5f..9aefd5e 100644
--- a/source3/utils/status.c
+++ b/source3/utils/status.c
@@ -31,6 +31,7 @@
  */
 
 #include "includes.h"
+#include "smbd/globals.h"
 #include "system/filesys.h"
 #include "popt_common.h"
 #include "dbwrap/dbwrap.h"
@@ -266,11 +267,45 @@ static void print_brl(struct file_id id,
 	TALLOC_FREE(share_mode);
 }
 
+static const char *session_dialect_str(uint16_t dialect)
+{
+	static fstring unkown_dialect;
+
+	switch(dialect){
+	case SMB2_DIALECT_REVISION_000:
+		return "NT1";
+	case SMB2_DIALECT_REVISION_202:
+		return "SMB2_02";
+	case SMB2_DIALECT_REVISION_210:
+		return "SMB2_10";
+	case SMB2_DIALECT_REVISION_222:
+		return "SMB2_22";
+	case SMB2_DIALECT_REVISION_224:
+		return "SMB2_24";
+	case SMB3_DIALECT_REVISION_300:
+		return "SMB3_00";
+	case SMB3_DIALECT_REVISION_302:
+		return "SMB3_02";
+	case SMB3_DIALECT_REVISION_310:
+		return "SMB3_10";
+	case SMB3_DIALECT_REVISION_311:
+		return "SMB3_11";
+	}
+
+	fstr_sprintf(unkown_dialect, "Unknown (0x%04x)", dialect);
+	return unkown_dialect;
+}
+
 static int traverse_connections(const struct connections_key *key,
 				const struct connections_data *crec,
-				void *state)
+				void *private_data)
 {
+	TALLOC_CTX *mem_ctx = (TALLOC_CTX *)private_data;
 	struct server_id_buf tmp;
+	char *timestr = NULL;
+	int result = 0;
+	const char *encryption = "-";
+	const char *signing = "-";
 
 	if (crec->cnum == TID_FIELD_INVALID)
 		return 0;
@@ -280,19 +315,61 @@ static int traverse_connections(const struct connections_key *key,
 		return 0;
 	}
 
-	d_printf("%-10s   %s   %-12s  %s",
+	timestr = timestring(mem_ctx, crec->start);
+	if (timestr == NULL) {
+		return -1;
+	}
+
+	if (smbXsrv_is_encrypted(crec->encryption_flags)) {
+		switch (crec->cipher) {
+		case SMB_ENCRYPTION_GSSAPI:
+			encryption = "GSSAPI";
+			break;
+		case SMB2_ENCRYPTION_AES128_CCM:
+			encryption = "AES-128-CCM";
+			break;
+		case SMB2_ENCRYPTION_AES128_GCM:
+			encryption = "AES-128-GCM";
+			break;
+		default:
+			encryption = "???";
+			result = -1;
+			break;
+		}
+	}
+
+	if (smbXsrv_is_signed(crec->signing_flags)) {
+		if (crec->dialect >= SMB3_DIALECT_REVISION_302) {
+			signing = "AES-128-CMAC";
+		} else if (crec->dialect >= SMB2_DIALECT_REVISION_202) {
+			signing = "HMAC-SHA256";
+		} else {
+			signing = "HMAC-MD5";
+		}
+	}
+
+	d_printf("%-12s %-7s %-13s %-32s %-12s %-12s\n",
 		 crec->servicename, server_id_str_buf(crec->pid, &tmp),
 		 crec->machine,
-		 time_to_asc(crec->start));
+		 timestr,
+		 encryption,
+		 signing);
 
-	return 0;
+	TALLOC_FREE(timestr);
+
+	return result;
 }
 
 static int traverse_sessionid(const char *key, struct sessionid *session,
 			      void *private_data)
 {
+	TALLOC_CTX *mem_ctx = (TALLOC_CTX *)private_data;
 	fstring uid_str, gid_str;
 	struct server_id_buf tmp;
+	char *machine_hostname = NULL;
+	int result = 0;
+	const char *encryption = "-";
+	const char *signing = "-";
 
 	if (do_checks &&
 	    (!process_exists(session->pid) ||
@@ -322,12 +399,74 @@ static int traverse_sessionid(const char *key, struct sessionid *session,
 		}
 	}
 
-	d_printf("%-7s   %-12s  %-12s  %-12s (%s) %-12s\n",
+	machine_hostname = talloc_asprintf(mem_ctx, "%s (%s)",
+					   session->remote_machine,
+					   session->hostname);
+	if (machine_hostname == NULL) {
+		return -1;
+	}
+
+	if (smbXsrv_is_encrypted(session->encryption_flags)) {
+		switch (session->cipher) {
+		case SMB2_ENCRYPTION_AES128_CCM:
+			encryption = "AES-128-CCM";
+			break;
+		case SMB2_ENCRYPTION_AES128_GCM:
+			encryption = "AES-128-GCM";
+			break;
+		default:
+			encryption = "???";
+			result = -1;
+			break;
+		}
+	} else if (smbXsrv_is_partially_encrypted(session->encryption_flags)) {
+		switch (session->cipher) {
+		case SMB_ENCRYPTION_GSSAPI:
+			encryption = "partial(GSSAPI)";
+			break;
+		case SMB2_ENCRYPTION_AES128_CCM:
+			encryption = "partial(AES-128-CCM)";
+			break;
+		case SMB2_ENCRYPTION_AES128_GCM:
+			encryption = "partial(AES-128-GCM)";
+			break;
+		default:
+			encryption = "???";
+			result = -1;
+			break;
+		}
+	}
+
+	if (smbXsrv_is_signed(session->signing_flags)) {
+		if (session->connection_dialect >= SMB3_DIALECT_REVISION_302) {
+			signing = "AES-128-CMAC";
+		} else if (session->connection_dialect >= SMB2_DIALECT_REVISION_202) {
+			signing = "HMAC-SHA256";
+		} else {
+			signing = "HMAC-MD5";
+		}
+	} else if (smbXsrv_is_partially_signed(session->signing_flags)) {
+		if (session->connection_dialect >= SMB3_DIALECT_REVISION_302) {
+			signing = "partial(AES-128-CMAC)";
+		} else if (session->connection_dialect >= SMB2_DIALECT_REVISION_202) {
+			signing = "partial(HMAC-SHA256)";
+		} else {
+			signing = "partial(HMAC-MD5)";
+		}
+	}
+
+
+	d_printf("%-7s %-12s %-12s %-41s %-17s %-20s %-21s\n",
 		 server_id_str_buf(session->pid, &tmp),
 		 uid_str, gid_str,
-		 session->remote_machine, session->hostname, session->protocol_ver);
+		 machine_hostname,
+		 session_dialect_str(session->connection_dialect),
+		 encryption,
+		 signing);
 
-	return 0;
+	TALLOC_FREE(machine_hostname);
+
+	return result;
 }
 
 
@@ -456,18 +595,15 @@ int main(int argc, const char *argv[])
 	}
 
 
-	if (lp_clustering()) {
-		/*
-		 * This implicitly initializes the global ctdbd
-		 * connection, usable by the db_open() calls further
-		 * down.
-		 */
-		msg_ctx = messaging_init(NULL, samba_tevent_context_init(NULL));
-		if (msg_ctx == NULL) {
-			fprintf(stderr, "messaging_init failed\n");
-			ret = -1;
-			goto done;
-		}
+	/*
+	 * This implicitly initializes the global ctdbd connection,
+	 * usable by the db_open() calls further down.
+	 */
+	msg_ctx = messaging_init(NULL, samba_tevent_context_init(NULL));
+	if (msg_ctx == NULL) {
+		fprintf(stderr, "messaging_init failed\n");
+		ret = -1;
+		goto done;
 	}
 
 	if (!lp_load_global(get_dyn_CONFIGFILE())) {
@@ -492,10 +628,10 @@ int main(int argc, const char *argv[])
 
 	if ( show_processes ) {
 		d_printf("\nSamba version %s\n",samba_version_string());
-		d_printf("PID     Username      Group         Machine            Protocol Version       \n");
-		d_printf("------------------------------------------------------------------------------\n");
+		d_printf("%-7s %-12s %-12s %-41s %-17s %-20s %-21s\n", "PID", "Username", "Group", "Machine", "Protocol Version", "Encryption", "Signing");
+		d_printf("----------------------------------------------------------------------------------------------------------------------------------------\n");
 
-		sessionid_traverse_read(traverse_sessionid, NULL);
+		sessionid_traverse_read(traverse_sessionid, frame);
 
 		if (processes_only) {
 			goto done;
@@ -503,25 +639,14 @@ int main(int argc, const char *argv[])
 	}
 
 	if ( show_shares ) {
-		if (verbose) {
-			db_path = lock_path("connections.tdb");
-			if (db_path == NULL) {
-				d_printf("Out of memory - exiting\n");
-				ret = -1;
-				goto done;
-			}
-			d_printf("Opened %s\n", db_path);
-			TALLOC_FREE(db_path);
-		}
-
 		if (brief) {
 			goto done;
 		}
 
-		d_printf("\nService      pid     machine       Connected at\n");
-		d_printf("-------------------------------------------------------\n");
+		d_printf("\n%-12s %-7s %-13s %-32s %-12s %-12s\n", "Service", "pid", "Machine", "Connected at", "Encryption", "Signing");
+		d_printf("---------------------------------------------------------------------------------------------\n");
 
-		connections_forall_read(traverse_connections, NULL);
+		connections_forall_read(traverse_connections, frame);
 
 		d_printf("\n");
 
@@ -582,16 +707,6 @@ int main(int argc, const char *argv[])
 	if (show_notify) {
 		struct notify_context *n;
 
-		if (msg_ctx == NULL) {
-			msg_ctx = messaging_init(
-				NULL, samba_tevent_context_init(NULL));
-			if (msg_ctx == NULL) {
-				fprintf(stderr, "messaging_init failed\n");
-				ret = -1;
-				goto done;
-			}
-		}
-
 		n = notify_init(talloc_tos(), msg_ctx,
 				messaging_tevent_context(msg_ctx));
 		if (n == NULL) {
diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c
index 5f7ab63..bc9d785 100644
--- a/source3/winbindd/idmap_ad.c
+++ b/source3/winbindd/idmap_ad.c
@@ -962,6 +962,7 @@ static struct nss_info_methods nss_sfu20_methods = {
  Initialize the plugins
  ***********************************************************************/
 
+static_decl_idmap;
 NTSTATUS idmap_ad_init(void)
 {
 	static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
diff --git a/source3/winbindd/idmap_autorid.c b/source3/winbindd/idmap_autorid.c
index eeac2b0..76dccaa 100644
--- a/source3/winbindd/idmap_autorid.c
+++ b/source3/winbindd/idmap_autorid.c
@@ -824,6 +824,7 @@ static struct idmap_methods autorid_methods = {
 	.allocate_id	 = idmap_autorid_allocate_id
 };
 
+static_decl_idmap;
 NTSTATUS idmap_autorid_init(void)
 {
 	return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
diff --git a/source3/winbindd/idmap_hash/idmap_hash.c b/source3/winbindd/idmap_hash/idmap_hash.c
index 1dbd300..51bbf5b 100644
--- a/source3/winbindd/idmap_hash/idmap_hash.c
+++ b/source3/winbindd/idmap_hash/idmap_hash.c
@@ -366,6 +366,7 @@ static struct nss_info_methods hash_nss_methods = {
  state.
  **********************************************************************/
 
+static_decl_idmap;
 NTSTATUS idmap_hash_init(void)
 {
 	static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
diff --git a/source3/winbindd/idmap_nss.c b/source3/winbindd/idmap_nss.c
index e65a499..24f8217 100644
--- a/source3/winbindd/idmap_nss.c
+++ b/source3/winbindd/idmap_nss.c
@@ -30,16 +30,16 @@
 #define DBGC_CLASS DBGC_IDMAP
 
 /*****************************
- Initialise idmap database. 
+ Initialise idmap database.
 *****************************/
 
 static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom)
-{	
+{
 	return NT_STATUS_OK;
 }
 
 /**********************************
- lookup a set of unix ids. 
+ lookup a set of unix ids.
 **********************************/
 
 static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
@@ -120,7 +120,7 @@ static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_ma
 }
 
 /**********************************
- lookup a set of sids. 
+ lookup a set of sids.
 **********************************/
 
 static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
diff --git a/source3/winbindd/idmap_rfc2307.c b/source3/winbindd/idmap_rfc2307.c
index e9d04c3..3ef10f6 100644
--- a/source3/winbindd/idmap_rfc2307.c
+++ b/source3/winbindd/idmap_rfc2307.c
@@ -38,7 +38,6 @@ struct idmap_rfc2307_context {
 	const char *bind_path_user;
 	const char *bind_path_group;
 	const char *ldap_domain;
-	bool cn_realm;
 	bool user_cn;
 	const char *realm;
 
@@ -82,9 +81,6 @@ static NTSTATUS idmap_rfc2307_ads_check_connection(struct idmap_domain *dom)
 	status = ads_idmap_cached_connection(&ctx->ads, dom_name);
 	if (ADS_ERR_OK(status)) {
 		ctx->ldap = ctx->ads->ldap.ld;
-		if (ctx->cn_realm) {
-			ctx->realm = ctx->ads->server.realm;
-		}
 	} else {
 		DEBUG(1, ("Could not connect to domain %s: %s\n", dom->name,
 			  ads_errstr(status)));
@@ -172,7 +168,7 @@ static NTSTATUS idmap_rfc2307_init_ldap(struct idmap_rfc2307_context *ctx,
 	NTSTATUS ret;
 	char *url;
 	char *secret = NULL;
-	const char *ldap_url, *user_dn, *ldap_realm;
+	const char *ldap_url, *user_dn;
 	TALLOC_CTX *mem_ctx = ctx;
 
 	ldap_url = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
@@ -204,21 +200,6 @@ static NTSTATUS idmap_rfc2307_init_ldap(struct idmap_rfc2307_context *ctx,
 
 	ctx->search = idmap_rfc2307_ldap_search;
 
-	if (ctx->cn_realm) {
-		ldap_realm = lp_parm_const_string(-1, config_option,
-						  "ldap_realm", NULL);
-		if (!ldap_realm) {
-			DEBUG(1, ("ERROR: cn_realm set, "
-				  "but ldap_realm is missing\n"));
-			ret = NT_STATUS_UNSUCCESSFUL;
-			goto done;
-		}
-		ctx->realm = talloc_strdup(mem_ctx, ldap_realm);
-		if (!ctx->realm) {
-			ret = NT_STATUS_NO_MEMORY;
-		}
-	}
-
 done:
 	talloc_free(url);
 	return ret;
@@ -276,7 +257,7 @@ static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context *ctx,
 			continue;
 		}
 
-		if (ctx->cn_realm) {
+		if (ctx->realm != NULL) {
 			/* Strip @realm from user or group name */
 			char *delim;
 
@@ -487,7 +468,7 @@ static NTSTATUS idmap_rfc_2307_sids_to_names(TALLOC_CTX *mem_ctx,
 		switch(lsa_type) {
 		case SID_NAME_USER:
 			id->xid.type = map->type = ID_TYPE_UID;
-			if (ctx->user_cn && ctx->cn_realm) {
+			if (ctx->user_cn && ctx->realm != NULL) {
 				name = talloc_asprintf(mem_ctx, "%s@%s",
 						       name, ctx->realm);
 			}
@@ -497,7 +478,7 @@ static NTSTATUS idmap_rfc_2307_sids_to_names(TALLOC_CTX *mem_ctx,
 		case SID_NAME_DOM_GRP:
 		case SID_NAME_ALIAS:
 		case SID_NAME_WKN_GRP:
-			if (ctx->cn_realm) {
+			if (ctx->realm != NULL) {
 				name = talloc_asprintf(mem_ctx, "%s@%s",
 						       name, ctx->realm);
 			}
@@ -781,7 +762,7 @@ static NTSTATUS idmap_rfc2307_initialize(struct idmap_domain *domain)
 {
 	struct idmap_rfc2307_context *ctx;
 	char *cfg_opt;
-	const char *bind_path_user, *bind_path_group, *ldap_server;
+	const char *bind_path_user, *bind_path_group, *ldap_server, *realm;
 	NTSTATUS status;
 
 	ctx = talloc_zero(domain, struct idmap_rfc2307_context);
@@ -842,7 +823,15 @@ static NTSTATUS idmap_rfc2307_initialize(struct idmap_domain *domain)
 		goto err;
 	}
 
-	ctx->cn_realm = lp_parm_bool(-1, cfg_opt, "cn_realm", false);
+	realm = lp_parm_const_string(-1, cfg_opt, "realm", NULL);
+	if (realm) {
+		ctx->realm = talloc_strdup(ctx, realm);
+		if (ctx->realm == NULL) {
+			status = NT_STATUS_NO_MEMORY;
+			goto err;
+		}
+	}
+
 	ctx->user_cn = lp_parm_bool(-1, cfg_opt, "user_cn", false);
 
 	domain->private_data = ctx;
@@ -861,6 +850,7 @@ static struct idmap_methods rfc2307_methods = {
 	.sids_to_unixids = idmap_rfc2307_sids_to_unixids,
 };
 
+static_decl_idmap;
 NTSTATUS idmap_rfc2307_init(void)
 {
 	return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rfc2307",
diff --git a/source3/winbindd/idmap_rid.c b/source3/winbindd/idmap_rid.c
index 099f68c..d68dbf7 100644
--- a/source3/winbindd/idmap_rid.c
+++ b/source3/winbindd/idmap_rid.c
@@ -94,7 +94,7 @@ static NTSTATUS idmap_rid_id_to_sid(struct idmap_domain *dom, struct id_map *map
 }
 
 /**********************************
- Single sid to id lookup function. 
+ Single sid to id lookup function.
 **********************************/
 
 static NTSTATUS idmap_rid_sid_to_id(struct idmap_domain *dom, struct id_map *map)
@@ -123,7 +123,7 @@ static NTSTATUS idmap_rid_sid_to_id(struct idmap_domain *dom, struct id_map *map
 }
 
 /**********************************
- lookup a set of unix ids. 
+ lookup a set of unix ids.
 **********************************/
 
 static NTSTATUS idmap_rid_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
@@ -151,7 +151,7 @@ static NTSTATUS idmap_rid_unixids_to_sids(struct idmap_domain *dom, struct id_ma
 }
 
 /**********************************
- lookup a set of sids. 
+ lookup a set of sids.
 **********************************/
 
 static NTSTATUS idmap_rid_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
@@ -185,6 +185,7 @@ static struct idmap_methods rid_methods = {
 	.sids_to_unixids = idmap_rid_sids_to_unixids,
 };
 
+static_decl_idmap;
 NTSTATUS idmap_rid_init(void)
 {
 	return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rid", &rid_methods);
diff --git a/source3/winbindd/idmap_script.c b/source3/winbindd/idmap_script.c
index 3a0d685..e758b4e 100644
--- a/source3/winbindd/idmap_script.c
+++ b/source3/winbindd/idmap_script.c
@@ -388,6 +388,7 @@ static struct idmap_methods db_methods = {
 	.sids_to_unixids = idmap_script_sids_to_unixids,
 };
 
+static_decl_idmap;
 NTSTATUS idmap_script_init(void)
 {
 	return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "script", &db_methods);
diff --git a/source3/winbindd/idmap_tdb2.c b/source3/winbindd/idmap_tdb2.c
index ddd4dbf..1b75936 100644
--- a/source3/winbindd/idmap_tdb2.c
+++ b/source3/winbindd/idmap_tdb2.c
@@ -609,6 +609,7 @@ static struct idmap_methods db_methods = {
 	.allocate_id     = idmap_tdb_common_get_new_id
 };
 
+static_decl_idmap;
 NTSTATUS idmap_tdb2_init(void)
 {
 	return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb2", &db_methods);
diff --git a/source3/winbindd/idmap_util.c b/source3/winbindd/idmap_util.c
index dc7d37c..f90565f 100644
--- a/source3/winbindd/idmap_util.c
+++ b/source3/winbindd/idmap_util.c
@@ -32,7 +32,7 @@
 /*****************************************************************
  Returns the SID mapped to the given UID.
  If mapping is not possible returns an error.
-*****************************************************************/  
+*****************************************************************/
 
 NTSTATUS idmap_uid_to_sid(struct dom_sid *sid, uid_t uid)
 {
@@ -95,7 +95,7 @@ backend:
 /*****************************************************************
  Returns SID mapped to the given GID.
  If mapping is not possible returns an error.
-*****************************************************************/  
+*****************************************************************/
 
 NTSTATUS idmap_gid_to_sid(struct dom_sid *sid, gid_t gid)
 {
diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c
index e3962de..940a06b 100644
--- a/source3/winbindd/wb_sids2xids.c
+++ b/source3/winbindd/wb_sids2xids.c
@@ -184,16 +184,22 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq)
 		struct lsa_DomainInfo *info;
 		struct lsa_TranslatedName *n = &names->names[i];
 		struct wbint_TransID *t = &state->ids.ids[i];
+		int domain_index;
 
 		sid_copy(&dom_sid, &state->non_cached[i]);
 		sid_split_rid(&dom_sid, &t->rid);
 
 		info = &domains->domains[n->sid_index];
 		t->type = lsa_SidType_to_id_type(n->sid_type);
-		t->domain_index = init_lsa_ref_domain_list(state,
-							   state->idmap_doms,
-							   info->name.string,
-							   &dom_sid);
+
+		domain_index = init_lsa_ref_domain_list(
+			state, state->idmap_doms, info->name.string, &dom_sid);
+		if (domain_index == -1) {
+			tevent_req_oom(req);
+			return;
+		}
+		t->domain_index = domain_index;
+
 		t->xid.id = UINT32_MAX;
 		t->xid.type = t->type;
 	}
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index c878ce2..d555127 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -99,12 +99,20 @@ struct messaging_context *winbind_messaging_context(void)
 struct imessaging_context *winbind_imessaging_context(void)
 {
 	static struct imessaging_context *msg = NULL;
+	struct messaging_context *msg_ctx;
+	struct server_id myself;
 	struct loadparm_context *lp_ctx;
 
 	if (msg != NULL) {
 		return msg;
 	}
 
+	msg_ctx = server_messaging_context();
+	if (msg_ctx == NULL) {
+		smb_panic("server_messaging_context failed\n");
+	}
+	myself = messaging_server_id(msg_ctx);
+
 	lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
 	if (lp_ctx == NULL) {
 		smb_panic("Could not load smb.conf to init winbindd's imessaging context.\n");
@@ -114,7 +122,8 @@ struct imessaging_context *winbind_imessaging_context(void)
 	 * Note we MUST use the NULL context here, not the autofree context,
 	 * to avoid side effects in forked children exiting.
 	 */
-	msg = imessaging_init(NULL, lp_ctx, procid_self(), winbind_event_context(), false);
+	msg = imessaging_init(NULL, lp_ctx, myself, winbind_event_context(),
+			      false);
 	talloc_unlink(NULL, lp_ctx);
 
 	if (msg == NULL) {
@@ -1754,7 +1763,7 @@ int main(int argc, const char **argv)
 
 	status = reinit_after_fork(winbind_messaging_context(),
 				   winbind_event_context(),
-				   false);
+				   false, NULL);
 	if (!NT_STATUS_IS_OK(status)) {
 		exit_daemon("Winbindd reinit_after_fork() failed", map_errno_from_nt_status(status));
 	}
diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
index 791b05f..a9a23db 100644
--- a/source3/winbindd/winbindd_ads.c
+++ b/source3/winbindd/winbindd_ads.c
@@ -646,7 +646,7 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
 		TALLOC_FREE(user);
 
 		if (info->full_name == NULL) {
-			/* this might fail so we dont check the return code */
+			/* this might fail so we don't check the return code */
 			wcache_query_user_fullname(domain,
 						   mem_ctx,
 						   sid,
diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c
index 3562217..cf3ed71 100644
--- a/source3/winbindd/winbindd_cache.c
+++ b/source3/winbindd/winbindd_cache.c
@@ -3100,7 +3100,7 @@ void wcache_invalidate_samlogon(struct winbindd_domain *domain,
         fstring key_str, sid_string;
 	struct winbind_cache *cache;
 
-	/* dont clear cached U/SID and UG/SID entries when we want to logon
+	/* don't clear cached U/SID and UG/SID entries when we want to logon
 	 * offline - gd */
 
 	if (lp_winbind_offline_logon()) {
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index 1964fcff..f593d24 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -3152,7 +3152,7 @@ retry:
 
 	if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
 		result = NT_STATUS_DOWNGRADE_DETECTED;
-		DEBUG(1, ("Unwilling to make LSA connection to domain %s"
+		DEBUG(1, ("Unwilling to make LSA connection to domain %s "
 			  "without connection level security, "
 			  "must set 'winbind sealed pipes = false' and "
 			  "'require strong key = false' to proceed: %s\n",
@@ -3285,7 +3285,6 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
 	sec_chan_type = cli_credentials_get_secure_channel_type(creds);
 	if (sec_chan_type == SEC_CHAN_NULL) {
 		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-		goto no_schannel;
 	}
 
 	result = rpccli_create_netlogon_creds_with_creds(creds,
@@ -3324,7 +3323,6 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
 	conn->netlogon_flags = netlogon_creds->negotiate_flags;
 	TALLOC_FREE(netlogon_creds);
 
- no_schannel:
 	if (!(conn->netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
 		if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
 			result = NT_STATUS_DOWNGRADE_DETECTED;
diff --git a/source3/winbindd/winbindd_cred_cache.c b/source3/winbindd/winbindd_cred_cache.c
index 3ca45d7..e113f99 100644
--- a/source3/winbindd/winbindd_cred_cache.c
+++ b/source3/winbindd/winbindd_cred_cache.c
@@ -501,9 +501,6 @@ NTSTATUS add_ccache_to_list(const char *princ_name,
 	struct WINBINDD_CCACHE_ENTRY *entry = NULL;
 	struct timeval t;
 	NTSTATUS ntret;
-#ifdef HAVE_KRB5
-	int ret;
-#endif
 
 	if ((username == NULL && princ_name == NULL) ||
 	    ccname == NULL || uid < 0) {
@@ -516,27 +513,6 @@ NTSTATUS add_ccache_to_list(const char *princ_name,
 		return NT_STATUS_NO_MORE_ENTRIES;
 	}
 
-	/* If it is cached login, destroy krb5 ticket
-	 * to avoid surprise. */
-#ifdef HAVE_KRB5
-	if (postponed_request) {
-		/* ignore KRB5_FCC_NOFILE error here */
-		ret = ads_kdestroy(ccname);
-		if (ret == KRB5_FCC_NOFILE) {
-			ret = 0;
-		}
-		if (ret) {
-			DEBUG(0, ("add_ccache_to_list: failed to destroy "
-				   "user krb5 ccache %s with %s\n", ccname,
-				   error_message(ret)));
-			return krb5_to_nt_status(ret);
-		}
-		DEBUG(10, ("add_ccache_to_list: successfully destroyed "
-			   "krb5 ccache %s for user %s\n", ccname,
-			   username));
-	}
-#endif
-
 	/* Reference count old entries */
 	entry = get_ccache_by_username(username);
 	if (entry) {
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
index 350ec7d..17a89a7 100644
--- a/source3/winbindd/winbindd_dual.c
+++ b/source3/winbindd/winbindd_dual.c
@@ -38,8 +38,8 @@
 #include "messages.h"
 #include "../lib/util/tevent_unix.h"
 #include "lib/param/loadparm.h"
-#include "lib/sys_rw.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/sys_rw_data.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
@@ -1254,7 +1254,7 @@ NTSTATUS winbindd_reinit_after_fork(const struct winbindd_child *myself,
 	status = reinit_after_fork(
 		winbind_messaging_context(),
 		winbind_event_context(),
-		true);
+		true, NULL);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("reinit_after_fork() failed\n"));
 		return status;
diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c
index 29831aa..df43d20 100644
--- a/source3/winbindd/winbindd_misc.c
+++ b/source3/winbindd/winbindd_misc.c
@@ -181,11 +181,12 @@ enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *
 		}
 
 		extra_data = talloc_asprintf_append_buffer(
-			extra_data, "%s\\%s\\%s\n",
-			trusts.array[i].netbios_name,
-			trusts.array[i].dns_name,
-			sid_string_talloc(state->mem_ctx,
-					  trusts.array[i].sid));
+		    extra_data, "%s\\%s\\%s\\%u\\%u\\%u\n",
+		    trusts.array[i].netbios_name, trusts.array[i].dns_name,
+		    sid_string_talloc(state->mem_ctx, trusts.array[i].sid),
+		    trusts.array[i].trust_flags,
+		    (uint32_t)trusts.array[i].trust_type,
+		    trusts.array[i].trust_attributes);
 	}
 
 	/* add our primary domain */
@@ -213,7 +214,7 @@ enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *
 		extra_data[extra_data_len-1] = '\0';
 
 		state->response->extra_data.data = extra_data;
-		state->response->length += extra_data_len+1;
+		state->response->length += extra_data_len;
 	}
 
 	return WINBINDD_OK;
diff --git a/source3/winbindd/winbindd_msrpc.c b/source3/winbindd/winbindd_msrpc.c
index 4080b12..4121747 100644
--- a/source3/winbindd/winbindd_msrpc.c
+++ b/source3/winbindd/winbindd_msrpc.c
@@ -443,7 +443,7 @@ static NTSTATUS msrpc_query_user(struct winbindd_domain *domain,
 						     user->base.full_name.string);
 
 		if (user_info->full_name == NULL) {
-			/* this might fail so we dont check the return code */
+			/* this might fail so we don't check the return code */
 			wcache_query_user_fullname(domain,
 						   mem_ctx,
 						   user_sid,
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 21a8954..8910423 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1380,8 +1380,8 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 		}
 		netr_attempts = 0;
 		if (domain->conn.netlogon_creds == NULL) {
-			DEBUG(3, ("No security credentials available for "
-				  "domain [%s]\n", domainname));
+			DBG_NOTICE("No security credentials available for "
+				  "domain [%s]\n", domainname);
 			result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 		} else if (interactive && username != NULL && password != NULL) {
 			result = rpccli_netlogon_password_logon(domain->conn.netlogon_creds,
@@ -1431,8 +1431,9 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 		   rpc changetrustpw' */
 
 		if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
-			DEBUG(3,("winbind_samlogon_retry_loop: sam_logon returned "
-				 "ACCESS_DENIED.  Maybe the trust account "
+			DEBUG(1,("winbind_samlogon_retry_loop: sam_logon returned "
+				 "ACCESS_DENIED.  Maybe the DC has Restrict "
+				 "NTLM set or the trust account "
 				"password was changed and we didn't know it. "
 				 "Killing connections to domain %s\n",
 				domainname));
@@ -1840,7 +1841,7 @@ process_result:
 						      cached_info3->base.full_name.string);
 			} else {
 
-				/* this might fail so we dont check the return code */
+				/* this might fail so we don't check the return code */
 				wcache_query_user_fullname(domain,
 						info3,
 						&user_sid,
@@ -2001,7 +2002,7 @@ process_result:
 						      cached_info3->base.full_name.string);
 			} else {
 
-				/* this might fail so we dont check the return code */
+				/* this might fail so we don't check the return code */
 				wcache_query_user_fullname(domain,
 						*info3,
 						&user_sid,
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 57ee40c..dfc5ea3 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -34,6 +34,10 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
+static struct winbindd_domain *
+add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc,
+			    struct winbindd_methods *methods);
+
 extern struct winbindd_methods cache_methods;
 
 /**
@@ -119,14 +123,40 @@ static bool is_in_internal_domain(const struct dom_sid *sid)
    If the domain already exists in the list,
    return it and don't re-initialize.  */
 
-static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
-						  struct winbindd_methods *methods,
-						  const struct dom_sid *sid)
+static struct winbindd_domain *
+add_trusted_domain(const char *domain_name, const char *alt_name,
+		   struct winbindd_methods *methods, const struct dom_sid *sid)
+{
+	struct winbindd_tdc_domain tdc;
+
+	ZERO_STRUCT(tdc);
+
+	tdc.domain_name = domain_name;
+	tdc.dns_name = alt_name;
+	if (sid) {
+		sid_copy(&tdc.sid, sid);
+	}
+
+	return add_trusted_domain_from_tdc(&tdc, methods);
+}
+
+/* Add a trusted domain out of a trusted domain cache
+   entry
+*/
+static struct winbindd_domain *
+add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc,
+			    struct winbindd_methods *methods)
 {
 	struct winbindd_domain *domain;
 	const char *alternative_name = NULL;
 	const char **ignored_domains, **dom;
 	int role = lp_server_role();
+	const char *domain_name = tdc->domain_name;
+	const struct dom_sid *sid = &tdc->sid;
+
+	if (is_null_sid(sid)) {
+		sid = NULL;
+	}
 
 	ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
 	for (dom=ignored_domains; dom && *dom; dom++) {
@@ -138,8 +168,8 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
 
 	/* use alt_name if available to allow DNS lookups */
 
-	if (alt_name && *alt_name) {
-		alternative_name = alt_name;
+	if (tdc->dns_name && *tdc->dns_name) {
+		alternative_name = tdc->dns_name;
 	}
 
 	/* We can't call domain_list() as this function is called from
@@ -151,8 +181,7 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
 			break;
 		}
 
-		if (alternative_name && *alternative_name)
-		{
+		if (alternative_name) {
 			if (strequal(alternative_name, domain->name) ||
 			    strequal(alternative_name, domain->alt_name))
 			{
@@ -160,12 +189,7 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
 			}
 		}
 
-		if (sid)
-		{
-			if (is_null_sid(sid)) {
-				continue;
-			}
-
+		if (sid != NULL) {
 			if (dom_sid_equal(sid, &domain->sid)) {
 				break;
 			}
@@ -219,13 +243,16 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
 	domain->internal = is_internal_domain(sid);
 	domain->sequence_number = DOM_SEQUENCE_NONE;
 	domain->last_seq_check = 0;
-	domain->initialized = False;
+	domain->initialized = false;
 	domain->online = is_internal_domain(sid);
 	domain->check_online_timeout = 0;
 	domain->dc_probe_pid = (pid_t)-1;
-	if (sid) {
+	if (sid != NULL) {
 		sid_copy(&domain->sid, sid);
 	}
+	domain->domain_flags = tdc->trust_flags;
+	domain->domain_type = tdc->trust_type;
+	domain->domain_trust_attribs = tdc->trust_attribs;
 
 	/* Is this our primary domain ? */
 	if (strequal(domain_name, get_global_sam_name()) &&
@@ -243,18 +270,22 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
 		if (lp_security() == SEC_ADS) {
 			domain->active_directory = true;
 		}
+	} else if (!domain->internal) {
+		if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
+			domain->active_directory = true;
+		}
 	}
 
 	/* Link to domain list */
-	DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
+	DLIST_ADD_END(_domain_list, domain);
 
 	wcache_tdc_add_domain( domain );
 
 	setup_domain_child(domain);
 
-	DEBUG(2,("Added domain %s %s %s\n",
-		 domain->name, domain->alt_name,
-		 &domain->sid?sid_string_dbg(&domain->sid):""));
+	DEBUG(2,
+	      ("Added domain %s %s %s\n", domain->name, domain->alt_name,
+	       !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
 
 	return domain;
 }
@@ -312,24 +343,37 @@ static void trustdom_list_done(struct tevent_req *req)
 	struct winbindd_response *response;
 	int res, err;
 	char *p;
+	struct winbindd_tdc_domain trust_params = {0};
+	ptrdiff_t extra_len;
 
 	res = wb_domain_request_recv(req, state, &response, &err);
 	if ((res == -1) || (response->result != WINBINDD_OK)) {
-		DEBUG(1, ("Could not receive trustdoms\n"));
+		DBG_WARNING("Could not receive trustdoms\n");
+		TALLOC_FREE(state);
+		return;
+	}
+
+	if (response->length < sizeof(struct winbindd_response)) {
+		DBG_ERR("ill-formed trustdom response - short length\n");
 		TALLOC_FREE(state);
 		return;
 	}
 
+	extra_len = response->length - sizeof(struct winbindd_response);
+
 	p = (char *)response->extra_data.data;
 
-	while ((p != NULL) && (*p != '\0')) {
+	while ((p - (char *)response->extra_data.data) < extra_len) {
 		char *q, *sidstr, *alt_name;
-		struct dom_sid sid;
-		char *alternate_name = NULL;
+
+		DBG_DEBUG("parsing response line '%s'\n", p);
+
+		ZERO_STRUCT(trust_params);
+		trust_params.domain_name = p;
 
 		alt_name = strchr(p, '\\');
 		if (alt_name == NULL) {
-			DEBUG(0, ("Got invalid trustdom response\n"));
+			DBG_ERR("Got invalid trustdom response\n");
 			break;
 		}
 
@@ -338,26 +382,52 @@ static void trustdom_list_done(struct tevent_req *req)
 
 		sidstr = strchr(alt_name, '\\');
 		if (sidstr == NULL) {
-			DEBUG(0, ("Got invalid trustdom response\n"));
+			DBG_ERR("Got invalid trustdom response\n");
 			break;
 		}
 
 		*sidstr = '\0';
 		sidstr += 1;
 
-		q = strchr(sidstr, '\n');
-		if (q != NULL)
-			*q = '\0';
+		/* use the real alt_name if we have one, else pass in NULL */
+		if (!strequal(alt_name, "(null)")) {
+			trust_params.dns_name = alt_name;
+		}
+
+		q = strtok(sidstr, "\\");
+		if (q == NULL) {
+			DBG_ERR("Got invalid trustdom response\n");
+			break;
+		}
 
-		if (!string_to_sid(&sid, sidstr)) {
+		if (!string_to_sid(&trust_params.sid, sidstr)) {
 			DEBUG(0, ("Got invalid trustdom response\n"));
 			break;
 		}
 
-		/* use the real alt_name if we have one, else pass in NULL */
+		q = strtok(NULL, "\\");
+		if (q == NULL) {
+			DBG_ERR("Got invalid trustdom response\n");
+			break;
+		}
+
+		trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
+
+		q = strtok(NULL, "\\");
+		if (q == NULL) {
+			DBG_ERR("Got invalid trustdom response\n");
+			break;
+		}
+
+		trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
+
+		q = strtok(NULL, "\n");
+		if (q == NULL) {
+			DBG_ERR("Got invalid trustdom response\n");
+			break;
+		}
 
-		if ( !strequal( alt_name, "(null)" ) )
-			alternate_name = alt_name;
+		trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
 
 		/*
 		 * We always call add_trusted_domain() cause on an existing
@@ -365,13 +435,10 @@ static void trustdom_list_done(struct tevent_req *req)
 		 * This is important because we need the SID for sibling
 		 * domains.
 		 */
-		(void)add_trusted_domain(p, alternate_name,
-					    &cache_methods,
-					    &sid);
+		(void)add_trusted_domain_from_tdc(&trust_params,
+						  &cache_methods);
 
-		p=q;
-		if (p != NULL)
-			p += 1;
+		p = q + strlen(q) + 1;
 	}
 
 	/*
@@ -438,10 +505,8 @@ static void rescan_forest_root_trusts( void )
 		d = find_domain_from_name_noinit( dom_list[i].domain_name );
 
 		if ( !d ) {
-			d = add_trusted_domain( dom_list[i].domain_name,
-						dom_list[i].dns_name,
-						&cache_methods,
-						&dom_list[i].sid );
+			d = add_trusted_domain_from_tdc(&dom_list[i],
+							&cache_methods);
 		}
 
 		if (d == NULL) {
@@ -507,10 +572,8 @@ static void rescan_forest_trusts( void )
 			   about it */
 
 			if ( !d ) {
-				d = add_trusted_domain( dom_list[i].domain_name,
-							dom_list[i].dns_name,
-							&cache_methods,
-							&dom_list[i].sid );
+				d = add_trusted_domain_from_tdc(&dom_list[i],
+								&cache_methods);
 			}
 
 			if (d == NULL) {
diff --git a/source3/winbindd/wscript_build b/source3/winbindd/wscript_build
index 2f7e74d..3ee280c 100644
--- a/source3/winbindd/wscript_build
+++ b/source3/winbindd/wscript_build
@@ -2,7 +2,7 @@
 
 bld.SAMBA3_LIBRARY('idmap',
                    source='idmap.c idmap_util.c',
-                   deps='samba-util',
+                   deps='samba-util pdb',
                    allow_undefined_symbols=True,
                    private_library=True)
 
@@ -16,12 +16,13 @@ bld.SAMBA3_SUBSYSTEM('IDMAP_TDB_COMMON',
 
 bld.SAMBA3_SUBSYSTEM('IDMAP_HASH',
                     source='idmap_hash/idmap_hash.c idmap_hash/mapfile.c',
-                    deps='samba-util krb5samba')
+                    deps='samba-util krb5samba',
+                    enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_hash'))
 
 bld.SAMBA3_SUBSYSTEM('IDMAP_AD',
                     source='idmap_ad.c',
                     deps='ads nss_info',
-                    enabled=bld.CONFIG_SET("HAVE_LDAP"))
+                    enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad'))
 
 bld.SAMBA3_MODULE('idmap_ad',
                  subsystem='idmap',
@@ -30,7 +31,7 @@ bld.SAMBA3_MODULE('idmap_ad',
                  deps='IDMAP_AD',
                  init_function='',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_ad'),
-                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad') and bld.CONFIG_SET("HAVE_LDAP"))
+                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad'))
 
 bld.SAMBA3_MODULE('idmap_rfc2307',
                  subsystem='idmap',
@@ -39,7 +40,7 @@ bld.SAMBA3_MODULE('idmap_rfc2307',
                  init_function='',
                  deps='ads',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_rfc2307'),
-                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_rfc2307') and bld.CONFIG_SET("HAVE_LDAP"))
+                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_rfc2307'))
 
 bld.SAMBA3_MODULE('idmap_rid',
                  subsystem='idmap',
@@ -79,6 +80,7 @@ bld.SAMBA3_MODULE('idmap_tdb',
                  source='idmap_tdb.c',
                  deps='samba-util tdb IDMAP_TDB_COMMON',
                  init_function='',
+                 allow_undefined_symbols=True,
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_tdb'),
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_tdb'))
 
@@ -141,7 +143,7 @@ bld.SAMBA3_MODULE('nss_info_rfc2307',
                  allow_undefined_symbols=True,
                  init_function='',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_ad'),
-                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad') and bld.CONFIG_SET("HAVE_LDAP"))
+                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad'))
 
 bld.SAMBA3_MODULE('nss_info_sfu20',
                  subsystem='nss_info',
@@ -150,7 +152,7 @@ bld.SAMBA3_MODULE('nss_info_sfu20',
                  allow_undefined_symbols=True,
                  init_function='',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_ad'),
-                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad') and bld.CONFIG_SET("HAVE_LDAP"))
+                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad'))
 
 bld.SAMBA3_MODULE('nss_info_sfu',
                  subsystem='nss_info',
diff --git a/source3/wscript b/source3/wscript
index 4e940fa..52f5876 100644
--- a/source3/wscript
+++ b/source3/wscript
@@ -11,15 +11,29 @@ import build.charset
 import samba_utils, samba_version
 import samba3
 
-Options.default_prefix = '/usr/local/samba'
+default_prefix = Options.default_prefix = '/usr/local/samba'
 
 def set_options(opt):
 
     opt.add_option('--with-static-modules',
-                   help=("Comma-separated list of names of modules to statically link in"),
+                   help=("Comma-separated list of names of modules to statically link in. "+
+                         "May include !module to disable 'module'. "+
+                         "Can be '!FORCED' to disable all non-required static only modules. "+
+                         "Can be '!DEFAULT' to disable all modules defaulting to a static build. "+
+                         "Can be 'ALL' to build all default shared modules static. "+
+                         "The most specific one wins, while the order is ignored "+
+                         "and --with-static-modules is evaluated before "+
+                         "--with-shared-modules"),
                    action="store", dest='static_modules', default=None)
     opt.add_option('--with-shared-modules',
-                   help=("Comma-separated list of names of modules to build shared"),
+                   help=("Comma-separated list of names of modules to build shared. "+
+                         "May include !module to disable 'module'. "+
+                         "Can be '!FORCED' to disable all non-required shared only modules. "+
+                         "Can be '!DEFAULT' to disable all modules defaulting to a shared build. "+
+                         "Can be 'ALL' to build all default static modules shared. "+
+                         "The most specific one wins, while the order is ignored "+
+                         "and --with-static-modules is evaluated before "+
+                         "--with-shared-modules"),
                    action="store", dest='shared_modules', default=None)
 
     opt.SAMBA3_ADD_OPTION('winbind')
@@ -28,7 +42,6 @@ def set_options(opt):
     opt.SAMBA3_ADD_OPTION('cups', with_name="enable", without_name="disable")
     opt.SAMBA3_ADD_OPTION('iprint', with_name="enable", without_name="disable")
     opt.SAMBA3_ADD_OPTION('pam')
-    opt.SAMBA3_ADD_OPTION('pam_smbpass')
     opt.SAMBA3_ADD_OPTION('quotas')
     opt.SAMBA3_ADD_OPTION('sendfile-support')
     opt.SAMBA3_ADD_OPTION('utmp')
@@ -39,7 +52,6 @@ def set_options(opt):
     opt.SAMBA3_ADD_OPTION('dnsupdate')
     opt.SAMBA3_ADD_OPTION('syslog')
     opt.SAMBA3_ADD_OPTION('automount')
-    opt.SAMBA3_ADD_OPTION('aio-support')
     opt.SAMBA3_ADD_OPTION('dmapi', default=None) # None means autodetection
     opt.SAMBA3_ADD_OPTION('fam', default=None) # None means autodetection
     opt.SAMBA3_ADD_OPTION('profiling-data', default=False)
@@ -69,6 +81,9 @@ def configure(conf):
 
     default_static_modules = []
     default_shared_modules = []
+    required_static_modules = []
+    forced_static_modules = []
+    forced_shared_modules = []
 
     if Options.options.developer:
         conf.ADD_CFLAGS('-DDEVELOPER -DDEBUG_PASSWORD')
@@ -77,6 +92,9 @@ def configure(conf):
     if sys.platform != 'openbsd5':
         conf.ADD_LDFLAGS("-Wl,--export-dynamic", testflags=True)
 
+    # We crash without vfs_default
+    required_static_modules.extend(TO_LIST('vfs_default'))
+
     conf.CHECK_HEADERS('execinfo.h libexc.h libunwind.h netdb.h')
     conf.CHECK_HEADERS('linux/falloc.h linux/ioctl.h')
 
@@ -194,14 +212,14 @@ main() {
 
     # check for libarchive (tar command in smbclient)
     # None means autodetect, True/False means enable/disable
-    conf.env['archive_lib'] = ''
+    conf.SET_TARGET_TYPE('archive', 'EMPTY')
     if Options.options.with_libarchive is not False:
         libarchive_mandatory = Options.options.with_libarchive == True
         Logs.info("Checking for libarchive existence")
-        if conf.CHECK_BUNDLED_SYSTEM('libarchive', minversion='3.1.2'):
-            conf.env['archive_lib'] = 'libarchive'
+        if conf.CHECK_HEADERS('archive.h') and conf.CHECK_LIB('archive', shlib=True):
+            conf.CHECK_FUNCS_IN('archive_read_support_filter_all archive_read_free', 'archive')
         elif libarchive_mandatory:
-            conf.fatal('libarchive support requested, but no suitable pkgconfig found')
+            conf.fatal('libarchive support requested, but not found')
 
     # check for DMAPI libs
     if Options.options.with_dmapi == False:
@@ -357,7 +375,7 @@ int main(int argc, char **argv) {
                     msg="Checking for LL suffix on long long integers")
 
     conf.CHECK_FUNCS('''
-_acl __acl atexit 
+_acl __acl atexit
  _chdir __chdir chflags chmod _close __close _closedir
 __closedir crypt16 devnm dirfd
 DNSServiceRegister _dup __dup _dup2 __dup2 endmntent execl
@@ -435,12 +453,12 @@ utimensat vsyslog _write __write __xstat
 
     if Options.options.with_acl_support:
         if (host_os.rfind('hpux') > -1):
-		Logs.info('Using HPUX ACLs')
+                Logs.info('Using HPUX ACLs')
                 conf.DEFINE('HAVE_HPUX_ACLS',1)
                 conf.DEFINE('POSIX_ACL_NEEDS_MASK',1)
                 default_static_modules.extend(TO_LIST('vfs_hpuxacl'))
-	elif (host_os.rfind('aix') > -1):
-		Logs.info('Using AIX ACLs')
+        elif (host_os.rfind('aix') > -1):
+                Logs.info('Using AIX ACLs')
                 conf.DEFINE('HAVE_AIX_ACLS',1)
                 default_static_modules.extend(TO_LIST('vfs_aixacl vfs_aixacl2'))
         elif (host_os.rfind('darwin') > -1):
@@ -469,7 +487,8 @@ return acl_get_perm_np(permset_d, perm);
                         'HAVE_ACL_GET_PERM_NP',
                         headers='sys/types.h sys/acl.h', link=True,
                         msg="Checking whether acl_get_perm_np() is available")
-                default_static_modules.extend(TO_LIST('vfs_posixacl'))
+                # source3/lib/sysacls.c calls posixacl_sys_acl_get_file()
+                required_static_modules.extend(TO_LIST('vfs_posixacl'))
                 conf.CHECK_VARIABLE('ACL_EVERYONE', headers='sys/acl.h')
             elif conf.CHECK_FUNCS_IN(['facl'], 'sec'):
                 Logs.info('Using solaris or UnixWare ACLs')
@@ -523,34 +542,13 @@ return acl_get_perm_np(permset_d, perm);
     conf.CHECK_DECLS('readahead', headers='fcntl.h', always=True)
 
     conf.CHECK_CODE('int fd = openat(AT_FDCWD, ".", O_RDONLY);',
-		'HAVE_OPENAT',
-		msg='Checking for openat',
-		headers='fcntl.h')
-
-    if Options.options.with_aio_support:
-        conf.CHECK_FUNCS_IN('aio_read', 'aio')
-        conf.CHECK_FUNCS_IN('aio_read', 'rt')
-        conf.CHECK_CODE('struct aiocb a; return aio_read(&a);',
-                        'HAVE_AIO',
-                        msg='Checking for asynchronous io support',
-                        headers='sys/types.h aio.h',
-                        lib='aio rt')
-        if conf.CONFIG_SET('HAVE_AIO'):
-            conf.CHECK_CODE('struct aiocb a; return aio_read(&a);', 'HAVE_AIO_READ', msg='Checking for aio_read', headers='aio.h', lib='aio rt')
-            conf.CHECK_CODE('struct aiocb a; return aio_write(&a);', 'HAVE_AIO_WRITE', msg='Checking for aio_write', headers='aio.h', lib='aio rt')
-            conf.CHECK_CODE('struct aiocb a; return aio_fsync(1, &a);', 'HAVE_AIO_FSYNC', msg='Checking for aio_fsync', headers='aio.h', lib='aio rt')
-            conf.CHECK_CODE('struct aiocb a; return aio_return(&a);', 'HAVE_AIO_RETURN', msg='Checking for aio_return', headers='aio.h', lib='aio rt')
-            conf.CHECK_CODE('struct aiocb a; return aio_error(&a);', 'HAVE_AIO_ERROR', msg='Checking for aio_error', headers='aio.h', lib='aio rt')
-            conf.CHECK_CODE('struct aiocb a; return aio_cancel(1, &a);', 'HAVE_AIO_CANCEL', msg='Checking for aio_cancel', headers='aio.h', lib='aio rt')
-            conf.CHECK_CODE('const struct aiocb * const a[1]; struct timespec t; return aio_suspend(&a, 1, &t);', 'HAVE_AIO_SUSPEND', msg='Checking for aio_suspend', headers='aio.h', lib='aio rt')
-        if not conf.CONFIG_SET('HAVE_AIO'):
-            conf.DEFINE('HAVE_NO_AIO', '1')
-    else:
-        conf.DEFINE('HAVE_NO_AIO', '1')
+                'HAVE_OPENAT',
+                msg='Checking for openat',
+                headers='fcntl.h')
 
     if host_os.rfind('linux') > -1:
-	conf.CHECK_FUNCS_IN('io_submit', 'aio')
-	conf.CHECK_CODE('''
+        conf.CHECK_FUNCS_IN('io_submit', 'aio')
+        conf.CHECK_CODE('''
 struct io_event ioev;
 struct iocb *ioc;
 io_context_t ctx;
@@ -566,10 +564,10 @@ io_set_callback(ioc, (io_callback_t)(0));
 io_submit(ctx, 1, &ioc);
 io_getevents(ctx, 1, 1, &ioev, &ts);
 ''',
-			'HAVE_LINUX_KERNEL_AIO',
-			msg='Checking for linux kernel asynchronous io support',
-			headers='unistd.h stdlib.h sys/types.h fcntl.h sys/eventfd.h libaio.h',
-			lib='aio')
+            'HAVE_LINUX_KERNEL_AIO',
+            msg='Checking for linux kernel asynchronous io support',
+            headers='unistd.h stdlib.h sys/types.h fcntl.h sys/eventfd.h libaio.h',
+            lib='aio')
 
     conf.CHECK_CODE('''
 struct msghdr msg;
@@ -797,6 +795,8 @@ msg.msg_accrightslen = sizeof(fd);
         conf.DEFINE('WITH_ADS', '1')
         conf.env['HAVE_ADS'] = '1'
         Logs.info("Building with Active Directory support.")
+        # these have broken dependencies
+        forced_shared_modules.extend(TO_LIST('idmap_ad idmap_rfc2307'))
     elif Options.options.with_ads == False:
         Logs.info("Building without Active Directory support (--without-ads).")
     else:
@@ -943,9 +943,6 @@ int i; i = PAM_RADIO_TYPE;
             conf.DEFINE('WITH_PAM', 1)
             conf.DEFINE('WITH_PAM_MODULES', 1)
 
-    if Options.options.with_pam_smbpass:
-        conf.env.with_pam_smbpass = True
-
     seteuid = False
 
 #
@@ -1286,7 +1283,7 @@ main() {
                             hdr.trl_cnt = 0;
                             hdtrl.iov_base = (void *)0;
                             hdtrl.iov_len = 0;
-			    ret = sendfile(fromfd, tofd, offset, &nwritten, &hdr, 0);
+                            ret = sendfile(fromfd, tofd, offset, &nwritten, &hdr, 0);
                             ''',
                             '_HAVE_SENDFILE',
                             msg='Checking for darwin sendfile support')
@@ -1377,6 +1374,7 @@ main() {
     conf.CHECK_FUNCS_IN('getspnam', 'security')
     conf.CHECK_FUNCS_IN('getspnam', 'sec')
 
+    legacy_quota_libs = ''
     if Options.options.with_quotas:
         # For quotas on Veritas VxFS filesystems
         conf.CHECK_HEADERS('sys/fs/vx_quota.h')
@@ -1403,7 +1401,7 @@ main() {
                 msg='for XFS QUOTA in <sys/quota.h>',
                 execute=False,
                 local_include=False)
-        
+
         # For IRIX like dqb_isoftlimit instead of dqb_fsoftlimit in struc dqblk
         conf.CHECK_STRUCTURE_MEMBER('struct dqblk', 'dqb_fsoftlimit', define='HAVE_DQB_FSOFTLIMIT',
                                 headers='sys/quota.h')
@@ -1443,7 +1441,7 @@ main() {
 
         conf.CHECK_CODE('''
                      clnt_create("", RQUOTAPROG, RQUOTAVERS, "udp");
-''', 
+''',
                         headers="rpc/rpc.h rpc/types.h rpcsvc/rquota.h rpc/nettype.h rpc/xdr.h", 
                         define='HAVE_NFS_QUOTAS',
                         msg='for NFS QUOTAS',
@@ -1457,6 +1455,29 @@ main() {
             conf.DEFINE('HAVE_SYS_QUOTAS', '1')
             conf.DEFINE('WITH_QUOTAS', '1')
 
+        #
+        # check if Legacy quota code can be brought in
+        # if standard interfaces are not supported
+        #
+        if not conf.CONFIG_SET('WITH_QUOTAS'):
+            if host_os.rfind('sunos5') > -1:
+                conf.DEFINE('SUNOS5', '1')
+                legacy_quota_libs = 'nsl'
+            conf.CHECK_CODE('''
+            #define WITH_QUOTAS 1
+            #define AUTOCONF_TEST 1
+            #include "../tests/oldquotas.c"
+            ''',
+                            cflags=conf.env['WERROR_CFLAGS'],
+                            define='WITH_QUOTAS',
+                            lib=legacy_quota_libs,
+                            msg='Checking whether legacy quota code can be used',
+                            execute=False,
+                            addmain=False)
+            if not conf.CONFIG_SET('WITH_QUOTAS'):
+                legacy_quota_libs = ''
+    conf.env['legacy_quota_libs'] = legacy_quota_libs
+
     #
     # cluster support (CTDB)
     #
@@ -1465,15 +1486,8 @@ main() {
         conf.env.with_ctdb = False
     else:
         Logs.info("building with cluster support")
-        conf.env['CTDB_CFLAGS'] = '-DCLUSTER_SUPPORT=1'
-        conf.env['CTDB_INCLUDE'] = conf.srcdir + '/ctdb/include'
         conf.env.with_ctdb = True
-
-    conf.CHECK_CODE('__attribute__((destructor)) static void cleanup(void) { }',
-                    'HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR',
-                    addmain=False,
-                    link=False,
-                    msg='Checking whether we can compile with __attribute__((destructor))')
+        conf.DEFINE('CLUSTER_SUPPORT', 1)
 
     conf.CHECK_CODE('void seekdir(DIR *d, long loc) { return; }',
                     'SEEKDIR_RETURNS_VOID',
@@ -1492,8 +1506,8 @@ main() {
             conf.undefine('WITH_PTHREADPOOL')
 
     if (conf.CHECK_HEADERS('linux/ioctl.h sys/ioctl.h linux/fs.h') and
-	conf.CHECK_DECLS('FS_IOC_GETFLAGS FS_COMPR_FL', headers='linux/fs.h')):
-	    conf.DEFINE('HAVE_LINUX_IOCTL', '1')
+        conf.CHECK_DECLS('FS_IOC_GETFLAGS FS_COMPR_FL', headers='linux/fs.h')):
+            conf.DEFINE('HAVE_LINUX_IOCTL', '1')
 
     conf.env['CCFLAGS_CEPHFS'] = "-D_FILE_OFFSET_BITS=64"
     if Options.options.libcephfs_dir:
@@ -1519,7 +1533,7 @@ main() {
         conf.undefine('HAVE_GLUSTERFS')
 
     if Options.options.enable_vxfs:
-	conf.DEFINE('HAVE_VXFS', '1')
+        conf.DEFINE('HAVE_VXFS', '1')
 
     if conf.CHECK_CFG(package='dbus-1', args='--cflags --libs',
                       msg='Checking for dbus', uselib_store="DBUS-1"):
@@ -1559,7 +1573,7 @@ main() {
         versions = ['1.0', '0.16', '0.14']
         for version in versions:
             testlib = 'tracker-sparql-' + version
-            if conf.check_cfg(package=testlib,
+            if conf.CHECK_CFG(package=testlib,
                               args='--cflags --libs',
                               mandatory=False):
                 conf.SET_TARGET_TYPE(testlib, 'SYSLIB')
@@ -1572,36 +1586,36 @@ main() {
             conf.fatal("Spotlight support requested but tracker-sparql library missing")
         Logs.info("building with Spotlight support")
 
+    forced_static_modules.extend(TO_LIST('auth_domain auth_builtin auth_sam auth_winbind'))
     default_static_modules.extend(TO_LIST('''pdb_smbpasswd pdb_tdbsam pdb_wbc_sam
-                                      auth_sam auth_unix auth_winbind auth_wbc
-                                      auth_domain auth_builtin vfs_default
+                                      auth_unix auth_wbc
                                       nss_info_template idmap_tdb idmap_passdb
                                       idmap_nss'''))
 
-    default_shared_modules.extend(TO_LIST('''vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk
+    default_shared_modules.extend(TO_LIST('''
+                                      vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk
                                       vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap
-                                      vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 
-                                      auth_script vfs_readahead vfs_xattr_tdb vfs_posix_eadb
+                                      vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2
+                                      vfs_readahead vfs_xattr_tdb vfs_posix_eadb
                                       vfs_streams_xattr vfs_streams_depot vfs_acl_xattr vfs_acl_tdb
-                                      vfs_smb_traffic_analyzer vfs_preopen vfs_catia vfs_scannedonly
-				      vfs_media_harmony vfs_unityed_media vfs_fruit vfs_shell_snap
-				      vfs_commit
-				      vfs_worm
-                                      vfs_crossrename vfs_linux_xfs_sgid
-                                      vfs_time_audit idmap_autorid idmap_tdb2
-                                      idmap_ad
-				      idmap_script
-                                      idmap_rid idmap_hash idmap_rfc2307'''))
+                                      vfs_preopen vfs_catia
+                                      vfs_media_harmony vfs_unityed_media vfs_fruit vfs_shell_snap
+                                      vfs_commit vfs_worm vfs_crossrename vfs_linux_xfs_sgid
+                                      vfs_time_audit vfs_offline
+                                  '''))
+    default_shared_modules.extend(TO_LIST('auth_script idmap_tdb2 idmap_script'))
+    # these have broken dependencies
+    forced_shared_modules.extend(TO_LIST('idmap_autorid idmap_rid idmap_hash'))
 
     if Options.options.developer:
         default_static_modules.extend(TO_LIST('charset_weird'))
         default_shared_modules.extend(TO_LIST('perfcount_test'))
         default_shared_modules.extend(TO_LIST('vfs_skel_opaque vfs_skel_transparent vfs_shadow_copy_test'))
         default_shared_modules.extend(TO_LIST('auth_skel pdb_test'))
+        default_shared_modules.extend(TO_LIST('vfs_fake_dfq'))
 
     if Options.options.enable_selftest or Options.options.developer:
-	default_shared_modules.extend(TO_LIST('vfs_fake_acls vfs_nfs4acl_xattr'))
-        
+        default_shared_modules.extend(TO_LIST('vfs_fake_acls vfs_nfs4acl_xattr'))
 
     if conf.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'):
         default_static_modules.extend(TO_LIST('pdb_samba_dsdb auth_samba4 vfs_dfs_samba4'))
@@ -1621,9 +1635,6 @@ main() {
     if Options.options.with_pthreadpool:
         default_shared_modules.extend(TO_LIST('vfs_aio_pthread'))
 
-    if conf.CONFIG_SET('HAVE_AIO'):
-        default_shared_modules.extend(TO_LIST('vfs_aio_posix'))
-
     if conf.CONFIG_SET('HAVE_LINUX_KERNEL_AIO'):
         default_shared_modules.extend(TO_LIST('vfs_aio_linux'))
 
@@ -1638,10 +1649,7 @@ main() {
 
     if (conf.CONFIG_SET('HAVE_LINUX_IOCTL')
       and conf.CONFIG_SET('HAVE_BASENAME') and conf.CONFIG_SET('HAVE_DIRNAME')):
-	default_shared_modules.extend(TO_LIST('vfs_btrfs'))
-
-    if conf.CONFIG_SET('SAMBA_FAM_LIBS'):
-        default_shared_modules.extend(TO_LIST('vfs_notify_fam'))
+        default_shared_modules.extend(TO_LIST('vfs_btrfs'))
 
     if conf.CONFIG_SET("HAVE_CEPH"):
         default_shared_modules.extend(TO_LIST('vfs_ceph'))
@@ -1653,7 +1661,7 @@ main() {
         default_shared_modules.extend(TO_LIST('vfs_vxfs'))
 
     if conf.CONFIG_SET('HAVE_DBUS'):
-	default_shared_modules.extend(TO_LIST('vfs_snapper'))
+        default_shared_modules.extend(TO_LIST('vfs_snapper'))
 
     explicit_shared_modules = TO_LIST(Options.options.shared_modules, delimiter=',')
     explicit_static_modules = TO_LIST(Options.options.static_modules, delimiter=',')
@@ -1671,23 +1679,66 @@ main() {
     replace_list_item(explicit_shared_modules, 'pdb_ldap', 'pdb_ldapsam')
     replace_list_item(explicit_static_modules, 'pdb_ldap', 'pdb_ldapsam')
 
-    final_static_modules = default_static_modules
-    final_shared_modules = default_shared_modules
+    final_static_modules = []
+    final_static_modules.extend(TO_LIST(required_static_modules))
+    final_shared_modules = []
+
+    if '!FORCED' not in explicit_static_modules:
+        final_static_modules.extend(TO_LIST(forced_static_modules))
+    if '!FORCED' not in explicit_shared_modules:
+        final_shared_modules.extend(TO_LIST(forced_shared_modules))
+    if '!DEFAULT' not in explicit_static_modules:
+        final_static_modules.extend(TO_LIST(default_static_modules))
+    if '!DEFAULT' not in explicit_shared_modules:
+        final_shared_modules.extend(TO_LIST(default_shared_modules))
+
+    if 'ALL' in explicit_static_modules:
+        for m in default_shared_modules:
+            if m in final_shared_modules:
+                final_shared_modules.remove(m)
+            final_static_modules.append(m)
+    if 'ALL' in explicit_shared_modules:
+        for m in default_static_modules:
+            if m in final_static_modules:
+                final_static_modules.remove(m)
+            final_shared_modules.append(m)
 
     for m in explicit_static_modules:
+        if m in ['ALL','!DEFAULT','!FORCED']:
+            continue
+        if m.startswith('!'):
+            m = m[1:]
+            if m in required_static_modules:
+                raise Utils.WafError('These modules are REQUIRED as static modules: %s' %
+                                     ' '.join(required_static_modules))
+            if m in final_static_modules:
+                final_static_modules.remove(m)
+            continue
+        if m in forced_shared_modules:
+            raise Utils.WafError('These modules MUST be configured as shared modules: %s' %
+                                 ' '.join(forced_shared_modules))
         if m in final_shared_modules:
             final_shared_modules.remove(m)
-        final_static_modules.append(m)
+        if m not in final_static_modules:
+            final_static_modules.append(m)
     for m in explicit_shared_modules:
+        if m in ['ALL','!DEFAULT','!FORCED']:
+            continue
+        if m.startswith('!'):
+            m = m[1:]
+            if m in final_shared_modules:
+                final_shared_modules.remove(m)
+            continue
+        if m in required_static_modules:
+            raise Utils.WafError('These modules are REQUIRED as static modules: %s' %
+                                 ' '.join(required_static_modules))
+        if m in forced_static_modules:
+            raise Utils.WafError('These module MUST be configured as static modules: %s' %
+                                 ' '.join(forced_static_modules))
         if m in final_static_modules:
             final_static_modules.remove(m)
-        final_shared_modules.append(m)
-
-    if ("auth_domain" not in final_static_modules) or \
-            ("auth_builtin" not in final_static_modules) or \
-            ("auth_sam" not in final_static_modules) or \
-            ("auth_winbind" not in final_static_modules):
-        raise Utils.WafError('These auth modules MUST be configured as static modules: auth_domain, auth_builtin, auth_sam, auth_winbind')
+        if m not in final_shared_modules:
+            final_shared_modules.append(m)
 
     conf.env['static_modules'] = final_static_modules
     conf.env['shared_modules'] = final_shared_modules
@@ -1731,6 +1782,8 @@ main() {
             for entry in shared_list[p]:
                 conf.DEFINE('%s_init' % entry, 'samba_init_module')
                 conf.env[shared_env].append('%s' % entry)
+        Logs.info("%s: %s" % (static_env, ','.join(conf.env[static_env])))
+        Logs.info("%s: %s" % (shared_env, ','.join(conf.env[shared_env])))
 
     conf.SAMBA_CONFIG_H('include/config.h')
 
diff --git a/source3/wscript_build b/source3/wscript_build
index ba670d3..7c9723a 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -105,30 +105,21 @@ bld.SAMBA3_SUBSYSTEM('TLDAP',
 # when modules are not linked statically. In the latter case
 # symbols will not be present in the libpdb anyway so no hurt is
 # done to the version script.
-static_pdb_match = ['tdbsam', 'smbpasswd', 'wbc_sam']
 private_pdb_match = []
-
-# AD DC module when linked statically will pull in few source4/winbind
-# dependencies which are not used outside AD DC module
-static_pdb_match.append('samba_dsdb')
 private_pdb_match.append('!idmap_init')
 private_pdb_match.append('!idmap_sids_to_xids')
 private_pdb_match.append('!idmap_xids_to_sids')
 
-# ldap module is actually three modules merged together: ldapsam, ipa, and nds
-static_pdb_match = static_pdb_match + ['ldap', 'ipa', 'nds']
 ldapsam_pdb_match = ['!priv2ld', '!smbldap_search_domain_info',
                      '!ldapsam_*', '!groupmap_attr_list*', '!get_userattr_list',
                      '!dominfo_attr_list', '!get_attr_key2string',
                      '!sidmap_attr_list', '!attrib_map_*', '!idpool_attr_list',
                      '!get_attr_list']
 private_pdb_match.append('!pdb_nds_*')
-private_pdb_match.append('!pdb_init_ldapsam')
 private_pdb_match.append('!pdb_ldapsam_init*')
+private_pdb_match.append('!pdb_*_init')
 private_pdb_match = private_pdb_match + ldapsam_pdb_match
 
-private_pdb_match = private_pdb_match + map(lambda x: '!pdb_%s_init' % x, static_pdb_match)
-
 bld.SAMBA3_LIBRARY('samba-passdb',
                    source='',
                    deps='pdb',
@@ -142,7 +133,7 @@ bld.SAMBA3_LIBRARY('samba-passdb',
                    passdb/lookup_sid.h''',
                    abi_match=private_pdb_match,
                    abi_directory='passdb/ABI',
-                   vnum='0.24.1')
+                   vnum='0.25.0')
 
 bld.SAMBA3_SUBSYSTEM('pdb',
                    source='''passdb/pdb_get_set.c
@@ -180,7 +171,16 @@ bld.SAMBA3_SUBSYSTEM('param',
                    lib/sharesec.c
                    lib/ldap_debug_handler.c
                    lib/util_names.c''',
-                   deps='samba-util PARAM_UTIL ldap lber LOADPARM_CTX samba3core smbconf param_local.h param_global.h cups''')
+                   deps='''samba-util
+                   PARAM_UTIL
+                   ldap
+                   lber
+                   LOADPARM_CTX
+                   samba3core
+                   smbconf
+                   param_local.h
+                   param_global.h
+                   cups''')
 
 # this includes only the low level parse code, not stuff
 # that requires knowledge of security contexts
@@ -247,26 +247,24 @@ bld.SAMBA3_SUBSYSTEM('KRBCLIENT',
                      source='libads/kerberos.c libads/ads_status.c',
                      public_deps='krb5samba k5crypto gssapi LIBTSOCKET CLDAP LIBNMB')
 
-bld.SAMBA3_LIBRARY('sys_rw',
-                   source='lib/sys_rw.c lib/sys_rw_data.c',
-                   deps='replace iov_buf',
-                   private_library=True)
-
 bld.SAMBA3_SUBSYSTEM('samba3util',
                    source='''lib/system.c
                    lib/sendfile.c
                    lib/recvfile.c
                    lib/time.c
                    lib/util_sid.c
+                   lib/util_specialsids.c
                    lib/util_file.c
                    lib/util.c
+                   lib/util_path.c
+                   lib/util_procid.c
                    lib/util_sock.c
                    lib/util_tsock.c
                    lib/util_transfer_file.c
                    lib/sock_exec.c''',
                    deps='ndr LIBTSOCKET samba-security NDR_SECURITY samba-util util_tdb sys_rw iov_buf')
 
-if bld.CONFIG_GET("CTDB_CFLAGS") and bld.CONFIG_GET("CTDB_INCLUDE"):
+if bld.env.with_ctdb:
     SAMBA_CLUSTER_SUPPORT_SOURCES='''
                      lib/cluster_support.c
                      lib/dbwrap/dbwrap_ctdb.c
@@ -291,8 +289,6 @@ else:
 bld.SAMBA3_LIBRARY('samba-cluster-support',
                    source=SAMBA_CLUSTER_SUPPORT_SOURCES,
                    deps=SAMBA_CLUSTER_SUPPORT_DEPS,
-                   cflags=bld.CONFIG_GET("CTDB_CFLAGS"),
-                   includes=bld.CONFIG_GET("CTDB_INCLUDE"),
                    allow_undefined_symbols=True,
                    private_library=True)
 
@@ -304,7 +300,8 @@ bld.SAMBA3_SUBSYSTEM('TDB_LIB',
 
 bld.SAMBA3_LIBRARY('messages_dgm',
                    source='''lib/messages_dgm.c lib/messages_dgm_ref.c''',
-                   deps='talloc UNIX_MSG POLL_FUNCS_TEVENT samba-debug',
+                   deps='''talloc UNIX_MSG POLL_FUNCS_TEVENT samba-debug
+                           genrand''',
                    private_library=True)
 
 bld.SAMBA3_LIBRARY('messages_util',
@@ -595,6 +592,7 @@ bld.SAMBA3_LIBRARY('smbd_base',
                    smbd/smb2_setinfo.c
                    smbd/smb2_break.c
                    smbd/smbXsrv_version.c
+                   smbd/smbXsrv_client.c
                    smbd/smbXsrv_session.c
                    smbd/smbXsrv_tcon.c
                    smbd/smbXsrv_open.c
@@ -641,6 +639,7 @@ bld.SAMBA3_LIBRARY('smbd_base',
                    notifyd
                    ''' +
                    bld.env['dmapi_lib'] +
+                   bld.env['legacy_quota_libs'] +
                    NOTIFY_DEPS,
                    private_library=True)
 
@@ -811,7 +810,7 @@ bld.SAMBA3_LIBRARY('CHARSET3',
 
 bld.SAMBA3_SUBSYSTEM('errors3',
                      source='libsmb/errormap.c libsmb/smberr.c lib/errmap_unix.c',
-                     deps='errors')
+                     deps='samba-errors')
 
 bld.SAMBA3_SUBSYSTEM('LIBCLI_SAMR',
                     source='rpc_client/cli_samr.c',
@@ -863,7 +862,7 @@ bld.SAMBA3_SUBSYSTEM('LIBLSA',
 ########################## BINARIES #################################
 
 bld.SAMBA3_BINARY('smbd/smbd',
-                 source='smbd/server.c',
+                 source='smbd/server.c smbd/smbd_cleanupd.c',
                  deps='smbd_base EPMD LSASD FSSD MDSSD',
                  install_path='${SBINDIR}')
 
@@ -1077,7 +1076,8 @@ bld.SAMBA3_BINARY('client/smbclient',
                  msrpc3
                  RPC_NDR_SRVSVC
                  cli_smb_common
-                 ''' + bld.env['archive_lib'])
+		 archive
+                 ''')
 
 bld.SAMBA3_BINARY('net',
                  source='''utils/net.c
@@ -1192,6 +1192,7 @@ bld.SAMBA3_BINARY('smbspool_krb5_wrapper',
                  DYNCONFIG
                  cups
                  ''',
+                 install_path='${LIBEXECDIR}/samba',
                  enabled=bld.CONFIG_SET('HAVE_CUPS'))
 
 bld.SAMBA3_BINARY('testparm',
@@ -1201,13 +1202,6 @@ bld.SAMBA3_BINARY('testparm',
                  param
                  popt_samba3''')
 
-bld.SAMBA3_BINARY('smbta-util',
-                 source='utils/smbta-util.c',
-                 deps='''
-                 talloc
-                 secrets3
-                 param''')
-
 smbstatus_source = 'utils/status.c smbd/notify_msg.c'
 
 if bld.CONFIG_GET("WITH_PROFILE"):
@@ -1319,6 +1313,7 @@ bld.SAMBA3_BINARY('smbtorture' + bld.env.suffix3,
                  LOCKING
                  NDR_OPEN_FILES
                  idmap
+                 IDMAP_TDB_COMMON
                  samba-cluster-support
                  ''',
                  cflags='-DWINBINDD_SOCKET_DIR=\"%s\"' % bld.env.WINBINDD_SOCKET_DIR,
@@ -1495,13 +1490,13 @@ bld.SAMBA3_BINARY('vlp',
 
 bld.SAMBA3_PYTHON('pysmbd',
                   source='smbd/pysmbd.c',
-                  deps='smbd_base pyrpc_util',
+                  deps='smbd_base pyrpc_util pytalloc-util',
                   realname='samba/samba3/smbd.so'
                   )
 
 bld.SAMBA3_PYTHON('pylibsmb',
                   source='libsmb/pylibsmb.c',
-                  deps='smbclient samba-credentials',
+                  deps='smbclient samba-credentials pytalloc-util',
                   realname='samba/samba3/libsmb_samba_internal.so'
                   )
 
@@ -1535,7 +1530,6 @@ bld.RECURSE('librpc')
 bld.RECURSE('librpc/idl')
 bld.RECURSE('libsmb')
 bld.RECURSE('modules')
-bld.RECURSE('pam_smbpass')
 bld.RECURSE('param')
 bld.RECURSE('passdb')
 bld.RECURSE('rpc_server')
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index a12447a..e0b2bf2 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -87,7 +87,9 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 {
 	struct gensec_gssapi_state *gensec_gssapi_state;
 	krb5_error_code ret;
+#ifdef SAMBA4_USES_HEIMDAL
 	const char *realm;
+#endif
 
 	gensec_gssapi_state = talloc_zero(gensec_security, struct gensec_gssapi_state);
 	if (!gensec_gssapi_state) {
@@ -276,6 +278,7 @@ static NTSTATUS gensec_gssapi_client_creds(struct gensec_security *gensec_securi
 	case KRB5KDC_ERR_CLIENT_REVOKED:
 		DEBUG(1, ("Account locked out: %s\n", error_string));
 		return NT_STATUS_ACCOUNT_LOCKED_OUT;
+	case KRB5_REALM_UNKNOWN:
 	case KRB5_KDC_UNREACH:
 		DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
 		return NT_STATUS_NO_LOGON_SERVERS;
@@ -416,8 +419,8 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
 		{
 #ifdef SAMBA4_USES_HEIMDAL
 			struct gsskrb5_send_to_kdc send_to_kdc;
-#endif
 			krb5_error_code ret;
+#endif
 
 			nt_status = gensec_gssapi_client_creds(gensec_security, ev);
 			if (!NT_STATUS_IS_OK(nt_status)) {
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index b1ecd18..2af6b14 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -285,9 +285,15 @@ static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_s
 	const char *error_string;
 	const char *principal;
 	const char *hostname;
-	krb5_data in_data;
+	krb5_data in_data = { .length = 0 };
+	krb5_data *in_data_p = NULL;
 	struct tevent_context *previous_ev;
 
+	if (lpcfg_parm_bool(gensec_security->settings->lp_ctx,
+			    NULL, "gensec_krb5", "send_authenticator_checksum", true)) {
+		in_data_p = &in_data;
+	}
+	
 	gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 
 	principal = gensec_get_target_principal(gensec_security);
@@ -313,7 +319,6 @@ static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_s
 		DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_string));
 		return NT_STATUS_UNSUCCESSFUL;
 	}
-	in_data.length = 0;
 	
 	/* Do this every time, in case we have weird recursive issues here */
 	ret = smb_krb5_context_set_event_ctx(gensec_krb5_state->smb_krb5_context, ev, &previous_ev);
@@ -330,7 +335,7 @@ static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_s
 						&gensec_krb5_state->auth_context,
 						gensec_krb5_state->ap_req_options, 
 						target_principal,
-						&in_data, ccache_container->ccache, 
+						in_data_p, ccache_container->ccache, 
 						&gensec_krb5_state->enc_ticket);
 			krb5_free_principal(gensec_krb5_state->smb_krb5_context->krb5_context, 
 					    target_principal);
@@ -341,7 +346,7 @@ static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_s
 				  gensec_krb5_state->ap_req_options,
 				  gensec_get_target_service(gensec_security),
 				  hostname,
-				  &in_data, ccache_container->ccache, 
+				  in_data_p, ccache_container->ccache, 
 				  &gensec_krb5_state->enc_ticket);
 	}
 
@@ -417,14 +422,17 @@ static DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLO
 	if (!asn1_pop_tag(data)) goto err;
 
 
-	ret = data_blob_talloc(mem_ctx, data->data, data->length);
+	if (!asn1_extract_blob(data, mem_ctx, &ret)) {
+		goto err;
+	}
 	asn1_free(data);
 
 	return ret;
 
   err:
 
-	DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs));
+	DEBUG(1, ("Failed to build krb5 wrapper at offset %d\n",
+		  (int)asn1_current_ofs(data)));
 	asn1_free(data);
 	return ret;
 }
@@ -449,7 +457,7 @@ static bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *
 	data_remaining = asn1_tag_remaining(data);
 
 	if (data_remaining < 3) {
-		data->has_error = true;
+		asn1_set_error(data);
 	} else {
 		if (!asn1_read(data, tok_id, 2)) goto err;
 		data_remaining -= 2;
@@ -459,7 +467,7 @@ static bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *
 
 	if (!asn1_end_tag(data)) goto err;
 
-	ret = !data->has_error;
+	ret = !asn1_has_error(data);
 
   err:
 
diff --git a/source4/auth/gensec/pygensec.c b/source4/auth/gensec/pygensec.c
index 2c98776..3399869 100644
--- a/source4/auth/gensec/pygensec.c
+++ b/source4/auth/gensec/pygensec.c
@@ -79,43 +79,37 @@ static struct gensec_settings *settings_from_object(TALLOC_CTX *mem_ctx, PyObjec
 static PyObject *py_gensec_start_client(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
 	NTSTATUS status;
-	pytalloc_Object *self;
+	PyObject *self;
 	struct gensec_settings *settings;
 	const char *kwnames[] = { "settings", NULL };
 	PyObject *py_settings = Py_None;
 	struct gensec_security *gensec;
+	TALLOC_CTX *frame;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", discard_const_p(char *, kwnames), &py_settings))
 		return NULL;
 
-	self = (pytalloc_Object*)type->tp_alloc(type, 0);
-	if (self == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-	self->talloc_ctx = talloc_new(NULL);
-	if (self->talloc_ctx == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
+	frame = talloc_stackframe();
 
 	if (py_settings != Py_None) {
-		settings = settings_from_object(self->talloc_ctx, py_settings);
+		settings = settings_from_object(frame, py_settings);
 		if (settings == NULL) {
-			PyObject_DEL(self);
+			PyErr_NoMemory();
+			TALLOC_FREE(frame);
 			return NULL;
 		}
 	} else {
-		settings = talloc_zero(self->talloc_ctx, struct gensec_settings);
+		settings = talloc_zero(frame, struct gensec_settings);
 		if (settings == NULL) {
-			PyObject_DEL(self);
+			PyErr_NoMemory();
+			TALLOC_FREE(frame);
 			return NULL;
 		}
 
 		settings->lp_ctx = loadparm_init_global(true);
 		if (settings->lp_ctx == NULL) {
 			PyErr_NoMemory();
-			PyObject_DEL(self);
+			TALLOC_FREE(frame);
 			return NULL;
 		}
 	}
@@ -123,18 +117,19 @@ static PyObject *py_gensec_start_client(PyTypeObject *type, PyObject *args, PyOb
 	status = gensec_init();
 	if (!NT_STATUS_IS_OK(status)) {
 		PyErr_SetNTSTATUS(status);
-		PyObject_DEL(self);
+		TALLOC_FREE(frame);
 		return NULL;
 	}
 
-	status = gensec_client_start(self->talloc_ctx, &gensec, settings);
+	status = gensec_client_start(frame, &gensec, settings);
 	if (!NT_STATUS_IS_OK(status)) {
 		PyErr_SetNTSTATUS(status);
-		PyObject_DEL(self);
+		TALLOC_FREE(frame);
 		return NULL;
 	}
 
-	self->ptr = gensec;
+	self = pytalloc_steal(type, gensec);
+	TALLOC_FREE(frame);
 
 	return (PyObject *)self;
 }
@@ -142,45 +137,39 @@ static PyObject *py_gensec_start_client(PyTypeObject *type, PyObject *args, PyOb
 static PyObject *py_gensec_start_server(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
 	NTSTATUS status;
-	pytalloc_Object *self;
+	PyObject *self;
 	struct gensec_settings *settings = NULL;
 	const char *kwnames[] = { "settings", "auth_context", NULL };
 	PyObject *py_settings = Py_None;
 	PyObject *py_auth_context = Py_None;
 	struct gensec_security *gensec;
 	struct auth4_context *auth_context = NULL;
+	TALLOC_CTX *frame;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", discard_const_p(char *, kwnames), &py_settings, &py_auth_context))
 		return NULL;
 
-	self = (pytalloc_Object*)type->tp_alloc(type, 0);
-	if (self == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-	self->talloc_ctx = talloc_new(NULL);
-	if (self->talloc_ctx == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
+	frame = talloc_stackframe();
 
 	if (py_settings != Py_None) {
-		settings = settings_from_object(self->talloc_ctx, py_settings);
+		settings = settings_from_object(frame, py_settings);
 		if (settings == NULL) {
-			PyObject_DEL(self);
+			PyErr_NoMemory();
+			TALLOC_FREE(frame);
 			return NULL;
 		}
 	} else {
-		settings = talloc_zero(self->talloc_ctx, struct gensec_settings);
+		settings = talloc_zero(frame, struct gensec_settings);
 		if (settings == NULL) {
-			PyObject_DEL(self);
+			PyErr_NoMemory();
+			TALLOC_FREE(frame);
 			return NULL;
 		}
 
 		settings->lp_ctx = loadparm_init_global(true);
 		if (settings->lp_ctx == NULL) {
 			PyErr_NoMemory();
-			PyObject_DEL(self);
+			TALLOC_FREE(frame);
 			return NULL;
 		}
 	}
@@ -198,20 +187,21 @@ static PyObject *py_gensec_start_server(PyTypeObject *type, PyObject *args, PyOb
 	status = gensec_init();
 	if (!NT_STATUS_IS_OK(status)) {
 		PyErr_SetNTSTATUS(status);
-		PyObject_DEL(self);
+		TALLOC_FREE(frame);
 		return NULL;
 	}
 
-	status = gensec_server_start(self->talloc_ctx, settings, auth_context, &gensec);
+	status = gensec_server_start(frame, settings, auth_context, &gensec);
 	if (!NT_STATUS_IS_OK(status)) {
 		PyErr_SetNTSTATUS(status);
-		PyObject_DEL(self);
+		TALLOC_FREE(frame);
 		return NULL;
 	}
 
-	self->ptr = gensec;
+	self = pytalloc_steal(type, gensec);
+	TALLOC_FREE(frame);
 
-	return (PyObject *)self;
+	return self;
 }
 
 static PyObject *py_gensec_set_target_hostname(PyObject *self, PyObject *args)
@@ -584,7 +574,6 @@ static PyTypeObject Py_Security = {
 	.tp_name = "gensec.Security",
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 	.tp_methods = py_gensec_security_methods,
-	.tp_basicsize = sizeof(pytalloc_Object),
 };
 
 void initgensec(void);
@@ -592,11 +581,7 @@ void initgensec(void)
 {
 	PyObject *m;
 
-	Py_Security.tp_base = pytalloc_GetObjectType();
-	if (Py_Security.tp_base == NULL)
-		return;
-
-	if (PyType_Ready(&Py_Security) < 0)
+	if (pytalloc_BaseObject_PyType_Ready(&Py_Security) < 0)
 		return;
 
 	m = Py_InitModule3("gensec", NULL, "Generic Security Interface.");
diff --git a/source4/auth/kerberos/kerberos-notes.txt b/source4/auth/kerberos/kerberos-notes.txt
index d7c65c6..6261532 100644
--- a/source4/auth/kerberos/kerberos-notes.txt
+++ b/source4/auth/kerberos/kerberos-notes.txt
@@ -6,7 +6,7 @@ Released under the GPLv3
 Important context for porting to MIT
 ------------------------------------
 
-This document should be read in conjuction with the Samba4 source code.  
+This document should be read in conjunction with the Samba4 source code.  
 DAL and KDC requirements are expressed (as an implementation against Heimdal's 
 HDB abstraction layer) in Samba4's source4/kdc/hdb-samba4.c in particular.
 hbd-samba4.c is the biggest piece of samba-to-krb glue layer, so the main
diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c
index 76d46bc..653e3d2 100644
--- a/source4/auth/kerberos/kerberos_util.c
+++ b/source4/auth/kerberos/kerberos_util.c
@@ -235,7 +235,9 @@ done:
 {
 	krb5_error_code ret;
 	const char *password;
+#ifdef SAMBA4_USES_HEIMDAL
 	const char *self_service;
+#endif
 	const char *target_service;
 	time_t kdc_time = 0;
 	krb5_principal princ;
@@ -267,7 +269,9 @@ done:
 		return ret;
 	}
 
+#ifdef SAMBA4_USES_HEIMDAL
 	self_service = cli_credentials_get_self_service(credentials);
+#endif
 	target_service = cli_credentials_get_target_service(credentials);
 
 	password = cli_credentials_get_password(credentials);
@@ -309,6 +313,8 @@ done:
 	 */
 	krb5_get_init_creds_opt_set_win2k(smb_krb5_context->krb5_context,
 					  krb_options, true);
+#else /* MIT */
+	krb5_get_init_creds_opt_set_canonicalize(krb_options, true);
 #endif
 
 	tries = 2;
@@ -426,7 +432,12 @@ done:
 									     ret, mem_ctx));
 		talloc_free(mem_ctx);
 		return ret;
-	} 
+	}
+
+	DEBUG(10,("kinit for %s succeeded\n",
+		cli_credentials_get_principal(credentials, mem_ctx)));
+
+
 	talloc_free(mem_ctx);
 	return 0;
 }
diff --git a/source4/auth/kerberos/wscript_build b/source4/auth/kerberos/wscript_build
index ffcb54c..0f886fa 100755
--- a/source4/auth/kerberos/wscript_build
+++ b/source4/auth/kerberos/wscript_build
@@ -9,7 +9,7 @@ bld.SAMBA_LIBRARY('authkrb5',
                   source='kerberos_pac.c',
                   autoproto='proto.h',
                   public_deps='ndr-krb5pac krb5samba samba_socket LIBCLI_RESOLVE asn1',
-                  deps='auth_sam_reply tevent LIBPACKET ndr ldb krb5samba KRB_INIT_CTX KRB5_PAC errors',
+                  deps='auth_sam_reply tevent LIBPACKET ndr ldb krb5samba KRB_INIT_CTX KRB5_PAC samba-errors',
                   private_library=True
                   )
 
diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c
index 1d1bc5e..eeb2336 100644
--- a/source4/auth/ntlm/auth.c
+++ b/source4/auth/ntlm/auth.c
@@ -32,6 +32,7 @@
 #include "system/kerberos.h"
 #include "auth/kerberos/kerberos.h"
 #include "auth/kerberos/kerberos_util.h"
+#include "libds/common/roles.h"
 
 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
 						   TALLOC_CTX *mem_ctx,
@@ -574,7 +575,7 @@ _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char *
 		}
 		method->auth_ctx	= ctx;
 		method->depth		= i;
-		DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
+		DLIST_ADD_END(ctx->methods, method);
 	}
 
 	ctx->check_ntlm_password = auth_check_password_wrapper;
diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c
index 43c7a3d..096359c 100644
--- a/source4/auth/ntlm/auth_sam.c
+++ b/source4/auth/ntlm/auth_sam.c
@@ -34,6 +34,7 @@
 #include "librpc/gen_ndr/ndr_irpc_c.h"
 #include "lib/messaging/irpc.h"
 #include "libcli/auth/libcli_auth.h"
+#include "libds/common/roles.h"
 
 NTSTATUS auth_sam_init(void);
 
diff --git a/source4/auth/ntlm/auth_unix.c b/source4/auth/ntlm/auth_unix.c
index 526b655..2b0512a 100644
--- a/source4/auth/ntlm/auth_unix.c
+++ b/source4/auth/ntlm/auth_unix.c
@@ -263,7 +263,7 @@ static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, con
 
 		pam_error = pam_end(*pamh, 0);
 		if (pam_error != PAM_SUCCESS) {
-			/* no vaild pamh here, can we reliably call pam_strerror ? */
+			/* no valid pamh here, can we reliably call pam_strerror ? */
 			DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
 				 pam_error));
 			return pam_to_nt_status(pam_error);
@@ -283,7 +283,7 @@ static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, con
 
 		pam_error = pam_end(*pamh, 0);
 		if (pam_error != PAM_SUCCESS) {
-			/* no vaild pamh here, can we reliably call pam_strerror ? */
+			/* no valid pamh here, can we reliably call pam_strerror ? */
 			DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
 				 pam_error));
 			return pam_to_nt_status(pam_error);
@@ -303,7 +303,7 @@ static NTSTATUS smb_pam_end(pam_handle_t *pamh)
 	if (pamh != NULL) {
 		pam_error = pam_end(pamh, 0);
 		if (pam_error != PAM_SUCCESS) {
-			/* no vaild pamh here, can we reliably call pam_strerror ? */
+			/* no valid pamh here, can we reliably call pam_strerror ? */
 			DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
 				 pam_error));
 			return pam_to_nt_status(pam_error);
diff --git a/source4/auth/ntlm/auth_winbind.c b/source4/auth/ntlm/auth_winbind.c
index 26d2d07..aed893d 100644
--- a/source4/auth/ntlm/auth_winbind.c
+++ b/source4/auth/ntlm/auth_winbind.c
@@ -193,9 +193,9 @@ static NTSTATUS winbind_check_password_wbclient(struct auth_method_context *ctx,
 	params.domain_name      = user_info->client.domain_name;
 	params.workstation_name = user_info->workstation_name;
 
-	d_fprintf(stderr, "looking up %s@%s logging in from %s\n",
+	DEBUG(5,("looking up %s@%s logging in from %s\n",
 		  params.account_name, params.domain_name,
-		  params.workstation_name);
+		  params.workstation_name));
 
 	memcpy(params.password.response.challenge,
 	       ctx->auth_ctx->challenge.data.data,
@@ -213,15 +213,20 @@ static NTSTATUS winbind_check_password_wbclient(struct auth_method_context *ctx,
 
 	wbc_status = wbcAuthenticateUserEx(&params, &info, &err);
 	if (wbc_status == WBC_ERR_AUTH_ERROR) {
-		DEBUG(1, ("error was %s (0x%08x)\nerror message was '%s'\n",
-		      err->nt_string, err->nt_status, err->display_string));
-
+		if (err) {
+			DEBUG(1, ("error was %s (0x%08x)\nerror message was '%s'\n",
+			      err->nt_string, err->nt_status, err->display_string));
+		}
 		nt_status = NT_STATUS(err->nt_status);
 		wbcFreeMemory(err);
 		NT_STATUS_NOT_OK_RETURN(nt_status);
 	} else if (!WBC_ERROR_IS_OK(wbc_status)) {
 		DEBUG(1, ("wbcAuthenticateUserEx: failed with %u - %s\n",
 			wbc_status, wbcErrorString(wbc_status)));
+		if (err) {
+			DEBUG(1, ("error was %s (0x%08x)\nerror message was '%s'\n",
+			      err->nt_string, err->nt_status, err->display_string));
+		}
 		return NT_STATUS_LOGON_FAILURE;
 	}
 	info3 = wbcAuthUserInfo_to_netr_SamInfo3(mem_ctx, info);
diff --git a/source4/auth/pyauth.c b/source4/auth/pyauth.c
index d79d417..61db907 100644
--- a/source4/auth/pyauth.c
+++ b/source4/auth/pyauth.c
@@ -36,13 +36,6 @@ void initauth(void);
 
 staticforward PyTypeObject PyAuthContext;
 
-/* There's no Py_ssize_t in 2.4, apparently */
-#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
-typedef int Py_ssize_t;
-typedef inquiry lenfunc;
-typedef intargfunc ssizeargfunc;
-#endif
-
 static PyObject *PyAuthSession_FromSession(struct auth_session_info *session)
 {
 	return py_return_ndr_struct("samba.dcerpc.auth", "session_info", session, session);
@@ -299,7 +292,6 @@ static PyObject *py_auth_context_new(PyTypeObject *type, PyObject *args, PyObjec
 
 static PyTypeObject PyAuthContext = {
 	.tp_name = "AuthContext",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 	.tp_new = py_auth_context_new,
 };
@@ -315,11 +307,7 @@ void initauth(void)
 {
 	PyObject *m;
 
-	PyAuthContext.tp_base = pytalloc_GetObjectType();
-	if (PyAuthContext.tp_base == NULL)
-		return;
-
-	if (PyType_Ready(&PyAuthContext) < 0)
+	if (pytalloc_BaseObject_PyType_Ready(&PyAuthContext) < 0)
 		return;
 
 	m = Py_InitModule3("auth", py_auth_methods,
diff --git a/source4/cldap_server/cldap_server.c b/source4/cldap_server/cldap_server.c
index 682d591..ced2a20 100644
--- a/source4/cldap_server/cldap_server.c
+++ b/source4/cldap_server/cldap_server.c
@@ -34,6 +34,7 @@
 #include "auth/auth.h"
 #include "param/param.h"
 #include "../lib/tsocket/tsocket.h"
+#include "libds/common/roles.h"
 
 NTSTATUS server_service_cldapd_init(void);
 
diff --git a/source4/client/cifsdd.c b/source4/client/cifsdd.c
index 7d412a5..48ffe18 100644
--- a/source4/client/cifsdd.c
+++ b/source4/client/cifsdd.c
@@ -571,7 +571,7 @@ int main(int argc, const char ** argv)
 	/* Block counts. */
 	set_arg_val("count", (uint64_t)-1);
 	set_arg_val("seek", (uint64_t)0);
-	set_arg_val("seek", (uint64_t)0);
+	set_arg_val("skip", (uint64_t)0);
 	/* Files. */
 	set_arg_val("if", NULL);
 	set_arg_val("of", NULL);
diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c
index 7a76fe5..4c21a5e 100644
--- a/source4/dns_server/dlz_bind9.c
+++ b/source4/dns_server/dlz_bind9.c
@@ -1438,10 +1438,20 @@ static bool b9_record_match(struct dlz_bind9_data *state,
 	switch (rec1->wType) {
 	case DNS_TYPE_A:
 		return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
-	case DNS_TYPE_AAAA:
-		inet_pton(AF_INET6, rec1->data.ipv6, &rec1_in_addr6);
-		inet_pton(AF_INET6, rec2->data.ipv6, &rec2_in_addr6);
+	case DNS_TYPE_AAAA: {
+		int ret;
+
+		ret = inet_pton(AF_INET6, rec1->data.ipv6, &rec1_in_addr6);
+		if (ret != 1) {
+			return false;
+		}
+		ret = inet_pton(AF_INET6, rec2->data.ipv6, &rec2_in_addr6);
+		if (ret != 1) {
+			return false;
+		}
+
 		return memcmp(&rec1_in_addr6, &rec2_in_addr6, sizeof(rec1_in_addr6)) == 0;
+	}
 	case DNS_TYPE_CNAME:
 		return dns_name_equal(rec1->data.cname, rec2->data.cname);
 	case DNS_TYPE_TXT:
diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 9e30b71..c251430 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -40,14 +40,26 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_DNS
 
-static WERROR create_response_rr(const struct dns_name_question *question,
-				 const struct dnsp_DnssrvRpcRecord *rec,
-				 struct dns_res_rec **answers, uint16_t *ancount)
+static WERROR add_response_rr(const char *name,
+			      const struct dnsp_DnssrvRpcRecord *rec,
+			      struct dns_res_rec **answers)
 {
 	struct dns_res_rec *ans = *answers;
-	uint16_t ai = *ancount;
+	uint16_t ai = talloc_array_length(ans);
 	enum ndr_err_code ndr_err;
 
+	if (ai == UINT16_MAX) {
+		return WERR_BUFFER_OVERFLOW;
+	}
+
+	/*
+	 * "ans" is always non-NULL and thus its own talloc context
+	 */
+	ans = talloc_realloc(ans, ans, struct dns_res_rec, ai+1);
+	if (ans == NULL) {
+		return WERR_NOMEM;
+	}
+
 	ZERO_STRUCT(ans[ai]);
 
 	switch (rec->wType) {
@@ -90,6 +102,7 @@ static WERROR create_response_rr(const struct dns_name_question *question,
 		break;
 	case DNS_QTYPE_PTR:
 		ans[ai].rdata.ptr_record = talloc_strdup(ans, rec->data.ptr);
+		W_ERROR_HAVE_NO_MEMORY(ans[ai].rdata.ptr_record);
 		break;
 	case DNS_QTYPE_MX:
 		ans[ai].rdata.mx_record.preference = rec->data.mx.wPriority;
@@ -112,16 +125,140 @@ static WERROR create_response_rr(const struct dns_name_question *question,
 		return DNS_ERR(NOT_IMPLEMENTED);
 	}
 
-	ans[ai].name = talloc_strdup(ans, question->name);
+	ans[ai].name = talloc_strdup(ans, name);
 	W_ERROR_HAVE_NO_MEMORY(ans[ai].name);
 	ans[ai].rr_type = rec->wType;
 	ans[ai].rr_class = DNS_QCLASS_IN;
 	ans[ai].ttl = rec->dwTtlSeconds;
 	ans[ai].length = UINT16_MAX;
-	ai++;
 
 	*answers = ans;
-	*ancount = ai;
+
+	return WERR_OK;
+}
+
+static WERROR add_dns_res_rec(struct dns_res_rec **pdst,
+			      const struct dns_res_rec *src)
+{
+	struct dns_res_rec *dst = *pdst;
+	uint16_t di = talloc_array_length(dst);
+	enum ndr_err_code ndr_err;
+
+	if (di == UINT16_MAX) {
+		return WERR_BUFFER_OVERFLOW;
+	}
+
+	dst = talloc_realloc(dst, dst, struct dns_res_rec, di+1);
+	if (dst == NULL) {
+		return WERR_NOMEM;
+	}
+
+	ZERO_STRUCT(dst[di]);
+
+	dst[di] = (struct dns_res_rec) {
+		.name = talloc_strdup(dst, src->name),
+		.rr_type = src->rr_type,
+		.rr_class = src->rr_class,
+		.ttl = src->ttl,
+		.length = src->length
+	};
+
+	if (dst[di].name == NULL) {
+		return WERR_NOMEM;
+	}
+
+	switch (src->rr_type) {
+	case DNS_QTYPE_CNAME:
+		dst[di].rdata.cname_record = talloc_strdup(
+			dst, src->rdata.cname_record);
+		if (dst[di].rdata.cname_record == NULL) {
+			return WERR_NOMEM;
+		}
+		break;
+	case DNS_QTYPE_A:
+		dst[di].rdata.ipv4_record = talloc_strdup(
+			dst, src->rdata.ipv4_record);
+		if (dst[di].rdata.ipv4_record == NULL) {
+			return WERR_NOMEM;
+		}
+		break;
+	case DNS_QTYPE_AAAA:
+		dst[di].rdata.ipv6_record = talloc_strdup(
+			dst, src->rdata.ipv6_record);
+		if (dst[di].rdata.ipv6_record == NULL) {
+			return WERR_NOMEM;
+		}
+		break;
+	case DNS_TYPE_NS:
+		dst[di].rdata.ns_record = talloc_strdup(
+			dst, src->rdata.ns_record);
+		if (dst[di].rdata.ns_record == NULL) {
+			return WERR_NOMEM;
+		}
+		break;
+	case DNS_QTYPE_SRV:
+		dst[di].rdata.srv_record = (struct dns_srv_record) {
+			.priority = src->rdata.srv_record.priority,
+			.weight   = src->rdata.srv_record.weight,
+			.port     = src->rdata.srv_record.port,
+			.target   = talloc_strdup(
+				dst, src->rdata.srv_record.target)
+		};
+		if (dst[di].rdata.srv_record.target == NULL) {
+			return WERR_NOMEM;
+		}
+		break;
+	case DNS_QTYPE_SOA:
+		dst[di].rdata.soa_record = (struct dns_soa_record) {
+			.mname	 = talloc_strdup(
+				dst, src->rdata.soa_record.mname),
+			.rname	 = talloc_strdup(
+				dst, src->rdata.soa_record.rname),
+			.serial	 = src->rdata.soa_record.serial,
+			.refresh = src->rdata.soa_record.refresh,
+			.retry   = src->rdata.soa_record.retry,
+			.expire  = src->rdata.soa_record.expire,
+			.minimum = src->rdata.soa_record.minimum
+		};
+
+		if ((dst[di].rdata.soa_record.mname == NULL) ||
+		    (dst[di].rdata.soa_record.rname == NULL)) {
+			return WERR_NOMEM;
+		}
+
+		break;
+	case DNS_QTYPE_PTR:
+		dst[di].rdata.ptr_record = talloc_strdup(
+			dst, src->rdata.ptr_record);
+		if (dst[di].rdata.ptr_record == NULL) {
+			return WERR_NOMEM;
+		}
+		break;
+	case DNS_QTYPE_MX:
+		dst[di].rdata.mx_record = (struct dns_mx_record) {
+			.preference = src->rdata.mx_record.preference,
+			.exchange   = talloc_strdup(
+				src, src->rdata.mx_record.exchange)
+		};
+
+		if (dst[di].rdata.mx_record.exchange == NULL) {
+			return WERR_NOMEM;
+		}
+		break;
+	case DNS_QTYPE_TXT:
+		ndr_err = ndr_dnsp_string_list_copy(dst,
+						    &src->rdata.txt_record.txt,
+						    &dst[di].rdata.txt_record.txt);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			return WERR_NOMEM;
+		}
+		break;
+	default:
+		DBG_WARNING("Got unhandled type %u query.\n", src->rr_type);
+		return DNS_ERR(NOT_IMPLEMENTED);
+	}
+
+	*pdst = dst;
 
 	return WERR_OK;
 }
@@ -135,8 +272,8 @@ struct ask_forwarder_state {
 static void ask_forwarder_done(struct tevent_req *subreq);
 
 static struct tevent_req *ask_forwarder_send(
-	struct dns_server *dns,
 	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct dns_server *dns,
 	const char *forwarder, struct dns_name_question *question)
 {
 	struct tevent_req *req, *subreq;
@@ -199,12 +336,14 @@ static void ask_forwarder_done(struct tevent_req *subreq)
 		req, struct ask_forwarder_state);
 	DATA_BLOB in_blob;
 	enum ndr_err_code ndr_err;
-	WERROR ret;
+	int ret;
 
 	ret = dns_udp_request_recv(subreq, state,
 				   &in_blob.data, &in_blob.length);
 	TALLOC_FREE(subreq);
-	if (tevent_req_werror(req, ret)) {
+
+	if (ret != 0) {
+		tevent_req_werror(req, unix_to_werror(ret));
 		return;
 	}
 
@@ -249,97 +388,309 @@ static WERROR ask_forwarder_recv(
 	return WERR_OK;
 }
 
-static WERROR handle_question(struct dns_server *dns,
-			      TALLOC_CTX *mem_ctx,
-			      const struct dns_name_question *question,
-			      struct dns_res_rec **answers, uint16_t *ancount)
+static WERROR add_zone_authority_record(struct dns_server *dns,
+					TALLOC_CTX *mem_ctx,
+					const struct dns_name_question *question,
+					struct dns_res_rec **nsrecs)
 {
-	struct dns_res_rec *ans = *answers;
-	WERROR werror, werror_return;
-	unsigned int ri;
+	const char *zone = NULL;
 	struct dnsp_DnssrvRpcRecord *recs;
-	uint16_t rec_count, ai = *ancount;
+	struct dns_res_rec *ns = *nsrecs;
+	uint16_t rec_count;
 	struct ldb_dn *dn = NULL;
+	unsigned int ri;
+	WERROR werror;
 
-	werror = dns_name2dn(dns, mem_ctx, question->name, &dn);
-	W_ERROR_NOT_OK_RETURN(werror);
+	zone = dns_get_authoritative_zone(dns, question->name);
+	DEBUG(10, ("Creating zone authority record for '%s'\n", zone));
+
+	werror = dns_name2dn(dns, mem_ctx, zone, &dn);
+	if (!W_ERROR_IS_OK(werror)) {
+		return werror;
+	}
 
 	werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rec_count);
-	W_ERROR_NOT_OK_RETURN(werror);
+	if (!W_ERROR_IS_OK(werror)) {
+		return werror;
+	}
 
-	ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, rec_count + ai);
-	if (ans == NULL) {
-		return WERR_NOMEM;
+	for (ri = 0; ri < rec_count; ri++) {
+		if (recs[ri].wType == DNS_TYPE_SOA) {
+			werror = add_response_rr(zone, &recs[ri], &ns);
+			if (!W_ERROR_IS_OK(werror)) {
+				return werror;
+			}
+		}
 	}
 
-	/* Set up for an NXDOMAIN reply if no match is found */
-	werror_return = DNS_ERR(NAME_ERROR);
+	*nsrecs = ns;
 
-	for (ri = 0; ri < rec_count; ri++) {
-		if ((recs[ri].wType == DNS_TYPE_CNAME) &&
-		    ((question->question_type == DNS_QTYPE_A) ||
-		     (question->question_type == DNS_QTYPE_AAAA))) {
-			struct dns_name_question *new_q =
-				talloc(mem_ctx, struct dns_name_question);
+	return WERR_OK;
+}
 
-			if (new_q == NULL) {
-				return WERR_NOMEM;
-			}
+static struct tevent_req *handle_authoritative_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct dns_server *dns, const char *forwarder,
+	struct dns_name_question *question,
+	struct dns_res_rec **answers, struct dns_res_rec **nsrecs);
+static WERROR handle_authoritative_recv(struct tevent_req *req);
+
+struct handle_dnsrpcrec_state {
+	struct dns_res_rec **answers;
+	struct dns_res_rec **nsrecs;
+};
 
-			/* We reply with one more record, so grow the array */
-			ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec,
-					     rec_count + 1);
-			if (ans == NULL) {
-				TALLOC_FREE(new_q);
-				return WERR_NOMEM;
-			}
+static void handle_dnsrpcrec_gotauth(struct tevent_req *subreq);
+static void handle_dnsrpcrec_gotforwarded(struct tevent_req *subreq);
 
-			/* First put in the CNAME record */
-			werror = create_response_rr(question, &recs[ri], &ans, &ai);
-			if (!W_ERROR_IS_OK(werror)) {
-				return werror;
-			}
+static struct tevent_req *handle_dnsrpcrec_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct dns_server *dns, const char *forwarder,
+	const struct dns_name_question *question,
+	struct dnsp_DnssrvRpcRecord *rec,
+	struct dns_res_rec **answers, struct dns_res_rec **nsrecs)
+{
+	struct tevent_req *req, *subreq;
+	struct handle_dnsrpcrec_state *state;
+	struct dns_name_question *new_q;
+	bool resolve_cname;
+	WERROR werr;
 
-			/* And then look up the name it points at.. */
+	req = tevent_req_create(mem_ctx, &state,
+				struct handle_dnsrpcrec_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->answers = answers;
+	state->nsrecs = nsrecs;
 
-			/* First build up the new question */
-			new_q->question_type = question->question_type;
-			new_q->question_class = question->question_class;
-			if (new_q->question_type == DNS_QTYPE_A) {
-				new_q->name = talloc_strdup(new_q, recs[ri].data.ipv4);
-			} else if (new_q->question_type == DNS_QTYPE_AAAA) {
-				new_q->name = talloc_strdup(new_q, recs[ri].data.ipv6);
-			}
-			if (new_q->name == NULL) {
-				TALLOC_FREE(new_q);
-				return WERR_NOMEM;
-			}
-			/* and then call the lookup again */
-			werror = handle_question(dns, mem_ctx, new_q, &ans, &ai);
-			if (!W_ERROR_IS_OK(werror)) {
-				return werror;
-			}
-			werror_return = WERR_OK;
+	resolve_cname = ((rec->wType == DNS_TYPE_CNAME) &&
+			 ((question->question_type == DNS_QTYPE_A) ||
+			  (question->question_type == DNS_QTYPE_AAAA)));
 
+	if (!resolve_cname) {
+		if ((question->question_type != DNS_QTYPE_ALL) &&
+		    (rec->wType !=
+		     (enum dns_record_type) question->question_type)) {
+			tevent_req_done(req);
+			return tevent_req_post(req, ev);
+		}
 
-			continue;
+		werr = add_response_rr(question->name, rec, state->answers);
+		if (tevent_req_werror(req, werr)) {
+			return tevent_req_post(req, ev);
 		}
-		if ((question->question_type != DNS_QTYPE_ALL) &&
-		    (recs[ri].wType != (enum dns_record_type) question->question_type)) {
-			werror_return = WERR_OK;
-			continue;
+
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	werr = add_response_rr(question->name, rec, state->answers);
+	if (tevent_req_werror(req, werr)) {
+		return tevent_req_post(req, ev);
+	}
+
+	new_q = talloc(state, struct dns_name_question);
+	if (tevent_req_nomem(new_q, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	*new_q = (struct dns_name_question) {
+		.question_type = question->question_type,
+		.question_class = question->question_class,
+		.name = rec->data.cname
+	};
+
+	if (dns_authorative_for_zone(dns, new_q->name)) {
+		subreq = handle_authoritative_send(
+			state, ev, dns, forwarder, new_q,
+			state->answers, state->nsrecs);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
 		}
-		werror = create_response_rr(question, &recs[ri], &ans, &ai);
-		if (!W_ERROR_IS_OK(werror)) {
-			return werror;
+		tevent_req_set_callback(subreq, handle_dnsrpcrec_gotauth, req);
+		return req;
+	}
+
+	subreq = ask_forwarder_send(state, ev, dns, forwarder, new_q);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, handle_dnsrpcrec_gotforwarded, req);
+
+	return req;
+}
+
+static void handle_dnsrpcrec_gotauth(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	WERROR werr;
+
+	werr = handle_authoritative_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (tevent_req_werror(req, werr)) {
+		return;
+	}
+	tevent_req_done(req);
+}
+
+static void handle_dnsrpcrec_gotforwarded(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct handle_dnsrpcrec_state *state = tevent_req_data(
+		req, struct handle_dnsrpcrec_state);
+	struct dns_res_rec *answers, *nsrecs, *additional;
+	uint16_t ancount = 0;
+	uint16_t nscount = 0;
+	uint16_t arcount = 0;
+	uint16_t i;
+	WERROR werr;
+
+	werr = ask_forwarder_recv(subreq, state, &answers, &ancount,
+				  &nsrecs, &nscount, &additional, &arcount);
+	if (tevent_req_werror(req, werr)) {
+		return;
+	}
+
+	for (i=0; i<ancount; i++) {
+		werr = add_dns_res_rec(state->answers, &answers[i]);
+		if (tevent_req_werror(req, werr)) {
+			return;
 		}
-		werror_return = WERR_OK;
 	}
 
-	*ancount = ai;
-	*answers = ans;
+	for (i=0; i<nscount; i++) {
+		werr = add_dns_res_rec(state->nsrecs, &nsrecs[i]);
+		if (tevent_req_werror(req, werr)) {
+			return;
+		}
+	}
 
-	return werror_return;
+	tevent_req_done(req);
+}
+
+static WERROR handle_dnsrpcrec_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_werror(req);
+}
+
+struct handle_authoritative_state {
+	struct tevent_context *ev;
+	struct dns_server *dns;
+	struct dns_name_question *question;
+	const char *forwarder;
+
+	struct dnsp_DnssrvRpcRecord *recs;
+	uint16_t rec_count;
+	uint16_t recs_done;
+
+	struct dns_res_rec **answers;
+	struct dns_res_rec **nsrecs;
+};
+
+static void handle_authoritative_done(struct tevent_req *subreq);
+
+static struct tevent_req *handle_authoritative_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct dns_server *dns, const char *forwarder,
+	struct dns_name_question *question,
+	struct dns_res_rec **answers, struct dns_res_rec **nsrecs)
+{
+	struct tevent_req *req, *subreq;
+	struct handle_authoritative_state *state;
+	struct ldb_dn *dn = NULL;
+	WERROR werr;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct handle_authoritative_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->dns = dns;
+	state->question = question;
+	state->forwarder = forwarder;
+	state->answers = answers;
+	state->nsrecs = nsrecs;
+
+	werr = dns_name2dn(dns, state, question->name, &dn);
+	if (tevent_req_werror(req, werr)) {
+		return tevent_req_post(req, ev);
+	}
+
+	werr = dns_lookup_records(dns, state, dn, &state->recs,
+				  &state->rec_count);
+	TALLOC_FREE(dn);
+	if (tevent_req_werror(req, werr)) {
+		return tevent_req_post(req, ev);
+	}
+
+	if (state->rec_count == 0) {
+		tevent_req_werror(req, DNS_ERR(NAME_ERROR));
+		return tevent_req_post(req, ev);
+	}
+
+	subreq = handle_dnsrpcrec_send(
+		state, state->ev, state->dns, state->forwarder,
+		state->question, &state->recs[state->recs_done],
+		state->answers, state->nsrecs);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, handle_authoritative_done, req);
+	return req;
+}
+
+static void handle_authoritative_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct handle_authoritative_state *state = tevent_req_data(
+		req, struct handle_authoritative_state);
+	WERROR werr;
+
+	werr = handle_dnsrpcrec_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (tevent_req_werror(req, werr)) {
+		return;
+	}
+
+	state->recs_done += 1;
+
+	if (state->recs_done == state->rec_count) {
+		tevent_req_done(req);
+		return;
+	}
+
+	subreq = handle_dnsrpcrec_send(
+		state, state->ev, state->dns, state->forwarder,
+		state->question, &state->recs[state->recs_done],
+		state->answers, state->nsrecs);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, handle_authoritative_done, req);
+}
+
+static WERROR handle_authoritative_recv(struct tevent_req *req)
+{
+	struct handle_authoritative_state *state = tevent_req_data(
+		req, struct handle_authoritative_state);
+	WERROR werr;
+
+	if (tevent_req_is_werror(req, &werr)) {
+		return werr;
+	}
+
+	werr = add_zone_authority_record(state->dns, state, state->question,
+					 state->nsrecs);
+	if (!W_ERROR_IS_OK(werr)) {
+		return werr;
+	}
+
+	return WERR_OK;
 }
 
 static NTSTATUS create_tkey(struct dns_server *dns,
@@ -569,6 +920,7 @@ struct dns_server_process_query_state {
 	uint16_t arcount;
 };
 
+static void dns_server_process_query_got_auth(struct tevent_req *subreq);
 static void dns_server_process_query_got_response(struct tevent_req *subreq);
 
 struct tevent_req *dns_server_process_query_send(
@@ -608,16 +960,32 @@ struct tevent_req *dns_server_process_query_send(
 	}
 
 	if (dns_authorative_for_zone(dns, in->questions[0].name)) {
-		WERROR err;
 
 		req_state->flags |= DNS_FLAG_AUTHORITATIVE;
-		err = handle_question(dns, state, &in->questions[0],
-				      &state->answers, &state->ancount);
-		if (tevent_req_werror(req, err)) {
+
+		/*
+		 * Initialize the response arrays, so that we can use
+		 * them as their own talloc contexts when doing the
+		 * realloc
+		 */
+		state->answers = talloc_array(state, struct dns_res_rec, 0);
+		if (tevent_req_nomem(state->answers, req)) {
 			return tevent_req_post(req, ev);
 		}
-		tevent_req_done(req);
-		return tevent_req_post(req, ev);
+		state->nsrecs = talloc_array(state, struct dns_res_rec, 0);
+		if (tevent_req_nomem(state->nsrecs, req)) {
+			return tevent_req_post(req, ev);
+		}
+
+		subreq = handle_authoritative_send(
+			state, ev, dns, lpcfg_dns_forwarder(dns->task->lp_ctx),
+			&in->questions[0], &state->answers, &state->nsrecs);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(
+			subreq, dns_server_process_query_got_auth, req);
+		return req;
 	}
 
 	if ((req_state->flags & DNS_FLAG_RECURSION_DESIRED) &&
@@ -626,8 +994,7 @@ struct tevent_req *dns_server_process_query_send(
 			  in->questions[0].name));
 
 		subreq = ask_forwarder_send(
-			dns,
-			state, ev, lpcfg_dns_forwarder(dns->task->lp_ctx),
+			state, ev, dns, lpcfg_dns_forwarder(dns->task->lp_ctx),
 			&in->questions[0]);
 		if (tevent_req_nomem(subreq, req)) {
 			return tevent_req_post(req, ev);
@@ -660,6 +1027,26 @@ static void dns_server_process_query_got_response(struct tevent_req *subreq)
 	tevent_req_done(req);
 }
 
+static void dns_server_process_query_got_auth(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct dns_server_process_query_state *state = tevent_req_data(
+		req, struct dns_server_process_query_state);
+	WERROR werr;
+
+	werr = handle_authoritative_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (tevent_req_werror(req, werr)) {
+		return;
+	}
+	state->ancount = talloc_array_length(state->answers);
+	state->nscount = talloc_array_length(state->nsrecs);
+	state->arcount = talloc_array_length(state->additional);
+
+	tevent_req_done(req);
+}
+
 WERROR dns_server_process_query_recv(
 	struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	struct dns_res_rec **answers,    uint16_t *ancount,
@@ -668,10 +1055,14 @@ WERROR dns_server_process_query_recv(
 {
 	struct dns_server_process_query_state *state = tevent_req_data(
 		req, struct dns_server_process_query_state);
-	WERROR err;
+	WERROR err = WERR_OK;
 
 	if (tevent_req_is_werror(req, &err)) {
-		return err;
+
+		if ((!W_ERROR_EQUAL(err, DNS_ERR(NAME_ERROR))) &&
+		    (!W_ERROR_EQUAL(err, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST))) {
+			return err;
+		}
 	}
 	*answers = talloc_move(mem_ctx, &state->answers);
 	*ancount = state->ancount;
@@ -679,5 +1070,5 @@ WERROR dns_server_process_query_recv(
 	*nscount = state->nscount;
 	*additional = talloc_move(mem_ctx, &state->additional);
 	*arcount = state->arcount;
-	return WERR_OK;
+	return err;
 }
diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c
index 3e18287..a2dc151 100644
--- a/source4/dns_server/dns_server.c
+++ b/source4/dns_server/dns_server.c
@@ -47,6 +47,7 @@
 #include "auth/credentials/credentials.h"
 #include "librpc/gen_ndr/ndr_irpc.h"
 #include "lib/messaging/irpc.h"
+#include "libds/common/roles.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_DNS
@@ -234,9 +235,13 @@ static WERROR dns_process_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	if (tevent_req_is_werror(req, &ret)) {
 		return ret;
 	}
-	if (state->dns_err != DNS_RCODE_OK) {
+	if ((state->dns_err != DNS_RCODE_OK) &&
+	    (state->dns_err != DNS_RCODE_NXDOMAIN)) {
 		goto drop;
 	}
+	if (state->dns_err != DNS_RCODE_OK) {
+		state->out_packet.operation |= state->dns_err;
+	}
 	state->out_packet.operation |= state->state.flags;
 
 	if (state->state.sign) {
@@ -721,27 +726,6 @@ static NTSTATUS dns_startup_interfaces(struct dns_server *dns,
 	return NT_STATUS_OK;
 }
 
-static int dns_server_sort_zones(struct ldb_message **m1, struct ldb_message **m2)
-{
-	const char *n1, *n2;
-	size_t l1, l2;
-
-	n1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
-	n2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
-
-	l1 = strlen(n1);
-	l2 = strlen(n2);
-
-	/* If the string lengths are not equal just sort by length */
-	if (l1 != l2) {
-		/* If m1 is the larger zone name, return it first */
-		return l2 - l1;
-	}
-
-	/*TODO: We need to compare DNs here, we want the DomainDNSZones first */
-	return 0;
-}
-
 static struct dns_server_tkey_store *tkey_store_init(TALLOC_CTX *mem_ctx,
 						     uint16_t size)
 {
@@ -765,51 +749,14 @@ static struct dns_server_tkey_store *tkey_store_init(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS dns_server_reload_zones(struct dns_server *dns)
 {
-	int ret;
-	static const char * const attrs[] = { "name", NULL};
-	struct ldb_result *res;
-	int i;
+	NTSTATUS status;
 	struct dns_server_zone *new_list = NULL;
 	struct dns_server_zone *old_list = NULL;
 	struct dns_server_zone *old_zone;
-
-	// TODO: this search does not work against windows
-	ret = dsdb_search(dns->samdb, dns, &res, NULL, LDB_SCOPE_SUBTREE,
-			  attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS, "(objectClass=dnsZone)");
-	if (ret != LDB_SUCCESS) {
-		return NT_STATUS_INTERNAL_DB_CORRUPTION;
-	}
-
-	TYPESAFE_QSORT(res->msgs, res->count, dns_server_sort_zones);
-
-	for (i=0; i < res->count; i++) {
-		struct dns_server_zone *z;
-
-		z = talloc_zero(dns, struct dns_server_zone);
-		if (z == NULL) {
-			return NT_STATUS_NO_MEMORY;
-		}
-
-		z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
-		z->dn = talloc_move(z, &res->msgs[i]->dn);
-		/*
-		 * Ignore the RootDNSServers zone and zones that we don't support yet
-		 * RootDNSServers should never be returned (Windows DNS server don't)
-		 * ..TrustAnchors should never be returned as is, (Windows returns
-		 * TrustAnchors) and for the moment we don't support DNSSEC so we'd better
-		 * not return this zone.
-		 */
-		if ((strcmp(z->name, "RootDNSServers") == 0) ||
-		    (strcmp(z->name, "..TrustAnchors") == 0))
-		{
-			DEBUG(10, ("Ignoring zone %s\n", z->name));
-			talloc_free(z);
-			continue;
-		}
-		DLIST_ADD_END(new_list, z, NULL);
+	status = dns_common_zones(dns->samdb, dns, &new_list);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
 	}
-
-	old_list = dns->zones;
 	dns->zones = new_list;
 	while ((old_zone = DLIST_TAIL(old_list)) != NULL) {
 		DLIST_REMOVE(old_list, old_zone);
diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h
index 3423ee0..e5c15ec 100644
--- a/source4/dns_server/dns_server.h
+++ b/source4/dns_server/dns_server.h
@@ -24,15 +24,9 @@
 
 #include "librpc/gen_ndr/dns.h"
 #include "librpc/gen_ndr/ndr_dnsp.h"
+#include "dnsserver_common.h"
 
 struct tsocket_address;
-
-struct dns_server_zone {
-	struct dns_server_zone *prev, *next;
-	const char *name;
-	struct ldb_dn *dn;
-};
-
 struct dns_server_tkey {
 	const char *name;
 	enum dns_tkey_mode mode;
@@ -87,12 +81,13 @@ WERROR dns_server_process_update(struct dns_server *dns,
 				 struct dns_res_rec **updates,    uint16_t *update_count,
 				 struct dns_res_rec **additional, uint16_t *arcount);
 
-bool dns_name_match(const char *zone, const char *name, size_t *host_part_len);
 bool dns_name_equal(const char *name1, const char *name2);
 bool dns_records_match(struct dnsp_DnssrvRpcRecord *rec1,
 		       struct dnsp_DnssrvRpcRecord *rec2);
 bool dns_authorative_for_zone(struct dns_server *dns,
 			      const char *name);
+const char *dns_get_authoritative_zone(struct dns_server *dns,
+				       const char *name);
 WERROR dns_lookup_records(struct dns_server *dns,
 			  TALLOC_CTX *mem_ctx,
 			  struct ldb_dn *dn,
diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c
index c757c15..ce450b5 100644
--- a/source4/dns_server/dns_utils.c
+++ b/source4/dns_server/dns_utils.c
@@ -33,47 +33,6 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_DNS
 
-bool dns_name_match(const char *zone, const char *name, size_t *host_part_len)
-{
-	size_t zl = strlen(zone);
-	size_t nl = strlen(name);
-	ssize_t zi, ni;
-	static const size_t fixup = 'a' - 'A';
-
-	if (zl > nl) {
-		return false;
-	}
-
-	for (zi = zl, ni = nl; zi >= 0; zi--, ni--) {
-		char zc = zone[zi];
-		char nc = name[ni];
-
-		/* convert to lower case */
-		if (zc >= 'A' && zc <= 'Z') {
-			zc += fixup;
-		}
-		if (nc >= 'A' && nc <= 'Z') {
-			nc += fixup;
-		}
-
-		if (zc != nc) {
-			return false;
-		}
-	}
-
-	if (ni >= 0) {
-		if (name[ni] != '.') {
-			return false;
-		}
-
-		ni--;
-	}
-
-	*host_part_len = ni+1;
-
-	return true;
-}
-
 /* Names are equal if they match and there's nothing left over */
 bool dns_name_equal(const char *name1, const char *name2)
 {
@@ -199,54 +158,29 @@ bool dns_authorative_for_zone(struct dns_server *dns,
 	return true;
 }
 
-WERROR dns_name2dn(struct dns_server *dns,
-		   TALLOC_CTX *mem_ctx,
-		   const char *name,
-		   struct ldb_dn **_dn)
+const char *dns_get_authoritative_zone(struct dns_server *dns,
+				       const char *name)
 {
-	struct ldb_dn *base;
-	struct ldb_dn *dn;
 	const struct dns_server_zone *z;
 	size_t host_part_len = 0;
 
-	if (name == NULL) {
-		return DNS_ERR(FORMAT_ERROR);
-	}
-
-	/*TODO: Check if 'name' is a valid DNS name */
-
-	if (strcmp(name, "") == 0) {
-		base = ldb_get_default_basedn(dns->samdb);
-		dn = ldb_dn_copy(mem_ctx, base);
-		ldb_dn_add_child_fmt(dn, "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System");
-		*_dn = dn;
-		return WERR_OK;
-	}
-
 	for (z = dns->zones; z != NULL; z = z->next) {
 		bool match;
-
 		match = dns_name_match(z->name, name, &host_part_len);
 		if (match) {
-			break;
+			return z->name;
 		}
 	}
+	return NULL;
+}
 
-	if (z == NULL) {
-		return DNS_ERR(NAME_ERROR);
-	}
-
-	if (host_part_len == 0) {
-		dn = ldb_dn_copy(mem_ctx, z->dn);
-		ldb_dn_add_child_fmt(dn, "DC=@");
-		*_dn = dn;
-		return WERR_OK;
-	}
-
-	dn = ldb_dn_copy(mem_ctx, z->dn);
-	ldb_dn_add_child_fmt(dn, "DC=%*.*s", (int)host_part_len, (int)host_part_len, name);
-	*_dn = dn;
-	return WERR_OK;
+WERROR dns_name2dn(struct dns_server *dns,
+		   TALLOC_CTX *mem_ctx,
+		   const char *name,
+		   struct ldb_dn **dn)
+{
+	return dns_common_name2dn(dns->samdb, dns->zones,
+				  mem_ctx, name, dn);
 }
 
 WERROR dns_generate_options(struct dns_server *dns,
@@ -259,7 +193,7 @@ WERROR dns_generate_options(struct dns_server *dns,
 	if (o == NULL) {
 		return WERR_NOMEM;
 	}
-	o->name = '\0';
+	o->name = NULL;
 	o->rr_type = DNS_QTYPE_OPT;
 	/* This is ugly, but RFC2671 wants the payload size in this field */
 	o->rr_class = (enum dns_qclass) dns->max_payload;
diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index c49d6ec..095f01a 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -5,6 +5,7 @@
 
    Copyright (C) 2010 Kai Blin
    Copyright (C) 2014 Stefan Metzmacher
+   Copyright (C) 2015 Andrew Bartlett
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -30,6 +31,7 @@
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/common/util.h"
 #include "dns_server/dnsserver_common.h"
+#include "lib/util/dlinklist.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_DNS
@@ -147,15 +149,15 @@ WERROR dns_common_lookup(struct ldb_context *samdb,
 	el = ldb_msg_find_element(msg, "dnsRecord");
 	if (el == NULL) {
 		TALLOC_FREE(msg);
+		/*
+		 * records produced by older Samba releases
+		 * keep dnsNode objects without dnsRecord and
+		 * without setting dNSTombstoned=TRUE.
+		 *
+		 * We just pretend they're tombstones.
+		 */
 		if (tombstoned != NULL) {
 			struct dnsp_DnssrvRpcRecord *recs;
-			/*
-			 * records produced by older Samba releases
-			 * keep dnsNode objects without dnsRecord and
-			 * without setting dNSTombstoned=TRUE.
-			 *
-			 * We just pretend they're tombstones.
-			 */
 			recs = talloc_array(mem_ctx,
 					    struct dnsp_DnssrvRpcRecord,
 					    1);
@@ -177,8 +179,14 @@ WERROR dns_common_lookup(struct ldb_context *samdb,
 			*records = recs;
 			*num_records = 1;
 			return WERR_OK;
+		} else {
+			/*
+			 * Because we are not looking for a tombstone
+			 * in this codepath, we just pretend it does
+			 * not exist at all.
+			 */
+			return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
 		}
-		return DNS_ERR(NAME_ERROR);
 	}
 
 	werr = dns_common_extract(el, mem_ctx, records, num_records);
@@ -340,3 +348,171 @@ WERROR dns_common_replace(struct ldb_context *samdb,
 
 	return WERR_OK;
 }
+
+bool dns_name_match(const char *zone, const char *name, size_t *host_part_len)
+{
+	size_t zl = strlen(zone);
+	size_t nl = strlen(name);
+	ssize_t zi, ni;
+	static const size_t fixup = 'a' - 'A';
+
+	if (zl > nl) {
+		return false;
+	}
+
+	for (zi = zl, ni = nl; zi >= 0; zi--, ni--) {
+		char zc = zone[zi];
+		char nc = name[ni];
+
+		/* convert to lower case */
+		if (zc >= 'A' && zc <= 'Z') {
+			zc += fixup;
+		}
+		if (nc >= 'A' && nc <= 'Z') {
+			nc += fixup;
+		}
+
+		if (zc != nc) {
+			return false;
+		}
+	}
+
+	if (ni >= 0) {
+		if (name[ni] != '.') {
+			return false;
+		}
+
+		ni--;
+	}
+
+	*host_part_len = ni+1;
+
+	return true;
+}
+
+WERROR dns_common_name2dn(struct ldb_context *samdb,
+			  struct dns_server_zone *zones,
+			  TALLOC_CTX *mem_ctx,
+			  const char *name,
+			  struct ldb_dn **_dn)
+{
+	struct ldb_dn *base;
+	struct ldb_dn *dn;
+	const struct dns_server_zone *z;
+	size_t host_part_len = 0;
+
+	if (name == NULL) {
+		return DNS_ERR(FORMAT_ERROR);
+	}
+
+	/*TODO: Check if 'name' is a valid DNS name */
+
+	if (strcmp(name, "") == 0) {
+		base = ldb_get_default_basedn(samdb);
+		dn = ldb_dn_copy(mem_ctx, base);
+		ldb_dn_add_child_fmt(dn, "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System");
+		*_dn = dn;
+		return WERR_OK;
+	}
+
+	for (z = zones; z != NULL; z = z->next) {
+		bool match;
+
+		match = dns_name_match(z->name, name, &host_part_len);
+		if (match) {
+			break;
+		}
+	}
+
+	if (z == NULL) {
+		return DNS_ERR(NAME_ERROR);
+	}
+
+	if (host_part_len == 0) {
+		dn = ldb_dn_copy(mem_ctx, z->dn);
+		ldb_dn_add_child_fmt(dn, "DC=@");
+		*_dn = dn;
+		return WERR_OK;
+	}
+
+	dn = ldb_dn_copy(mem_ctx, z->dn);
+	ldb_dn_add_child_fmt(dn, "DC=%*.*s", (int)host_part_len, (int)host_part_len, name);
+	*_dn = dn;
+	return WERR_OK;
+}
+
+static int dns_common_sort_zones(struct ldb_message **m1, struct ldb_message **m2)
+{
+	const char *n1, *n2;
+	size_t l1, l2;
+
+	n1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
+	n2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
+
+	l1 = strlen(n1);
+	l2 = strlen(n2);
+
+	/* If the string lengths are not equal just sort by length */
+	if (l1 != l2) {
+		/* If m1 is the larger zone name, return it first */
+		return l2 - l1;
+	}
+
+	/*TODO: We need to compare DNs here, we want the DomainDNSZones first */
+	return 0;
+}
+
+NTSTATUS dns_common_zones(struct ldb_context *samdb,
+			  TALLOC_CTX *mem_ctx,
+			  struct dns_server_zone **zones_ret)
+{
+	int ret;
+	static const char * const attrs[] = { "name", NULL};
+	struct ldb_result *res;
+	int i;
+	struct dns_server_zone *new_list = NULL;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	// TODO: this search does not work against windows
+	ret = dsdb_search(samdb, frame, &res, NULL, LDB_SCOPE_SUBTREE,
+			  attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS, "(objectClass=dnsZone)");
+	if (ret != LDB_SUCCESS) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+
+	TYPESAFE_QSORT(res->msgs, res->count, dns_common_sort_zones);
+
+	for (i=0; i < res->count; i++) {
+		struct dns_server_zone *z;
+
+		z = talloc_zero(mem_ctx, struct dns_server_zone);
+		if (z == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
+		talloc_steal(z, z->name);
+		z->dn = talloc_move(z, &res->msgs[i]->dn);
+		/*
+		 * Ignore the RootDNSServers zone and zones that we don't support yet
+		 * RootDNSServers should never be returned (Windows DNS server don't)
+		 * ..TrustAnchors should never be returned as is, (Windows returns
+		 * TrustAnchors) and for the moment we don't support DNSSEC so we'd better
+		 * not return this zone.
+		 */
+		if ((strcmp(z->name, "RootDNSServers") == 0) ||
+		    (strcmp(z->name, "..TrustAnchors") == 0))
+		{
+			DEBUG(10, ("Ignoring zone %s\n", z->name));
+			talloc_free(z);
+			continue;
+		}
+		DLIST_ADD_END(new_list, z);
+	}
+
+	*zones_ret = new_list;
+	TALLOC_FREE(frame);
+	return NT_STATUS_OK;
+}
diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h
index becd243..ad91f61 100644
--- a/source4/dns_server/dnsserver_common.h
+++ b/source4/dns_server/dnsserver_common.h
@@ -26,6 +26,14 @@ uint8_t werr_to_dns_err(WERROR werr);
 #define DNS_ERR(err_str) WERR_DNS_ERROR_RCODE_##err_str
 
 struct ldb_message_element;
+struct ldb_context;
+struct dnsp_DnssrvRpcRecord;
+
+struct dns_server_zone {
+	struct dns_server_zone *prev, *next;
+	const char *name;
+	struct ldb_dn *dn;
+};
 
 WERROR dns_common_extract(const struct ldb_message_element *el,
 			  TALLOC_CTX *mem_ctx,
@@ -46,5 +54,13 @@ WERROR dns_common_replace(struct ldb_context *samdb,
 			  uint32_t serial,
 			  struct dnsp_DnssrvRpcRecord *records,
 			  uint16_t rec_count);
-
+bool dns_name_match(const char *zone, const char *name, size_t *host_part_len);
+WERROR dns_common_name2dn(struct ldb_context *samdb,
+			  struct dns_server_zone *zones,
+			  TALLOC_CTX *mem_ctx,
+			  const char *name,
+			  struct ldb_dn **_dn);
+NTSTATUS dns_common_zones(struct ldb_context *samdb,
+			  TALLOC_CTX *mem_ctx,
+			  struct dns_server_zone **zones_ret);
 #endif /* __DNSSERVER_COMMON_H__ */
diff --git a/source4/dns_server/pydns.c b/source4/dns_server/pydns.c
new file mode 100644
index 0000000..9842f24
--- /dev/null
+++ b/source4/dns_server/pydns.c
@@ -0,0 +1,319 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Python DNS server wrapper
+
+   Copyright (C) 2015 Andrew Bartlett
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+#include "includes.h"
+#include <pyldb.h>
+#include <pytalloc.h>
+#include "dns_server/dnsserver_common.h"
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/util.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "librpc/rpc/pyrpc_util.h"
+
+/* FIXME: These should be in a header file somewhere */
+#define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
+	if (!py_check_dcerpc_type(py_ldb, "ldb", "Ldb")) { \
+		PyErr_SetString(py_ldb_get_exception(), "Ldb connection object required"); \
+		return NULL; \
+	} \
+	ldb = pyldb_Ldb_AsLdbContext(py_ldb);
+
+#define PyErr_LDB_DN_OR_RAISE(py_ldb_dn, dn) \
+	if (!py_check_dcerpc_type(py_ldb_dn, "ldb", "Dn")) { \
+		PyErr_SetString(py_ldb_get_exception(), "ldb Dn object required"); \
+		return NULL; \
+	} \
+	dn = pyldb_Dn_AsDn(py_ldb_dn);
+
+static PyObject *py_ldb_get_exception(void)
+{
+	PyObject *mod = PyImport_ImportModule("ldb");
+	if (mod == NULL)
+		return NULL;
+
+	return PyObject_GetAttrString(mod, "LdbError");
+}
+
+static PyObject *py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord *records,
+						  uint16_t num_records)
+{
+	PyObject *py_dns_list;
+	int i;
+	py_dns_list = PyList_New(num_records);
+	if (py_dns_list == NULL) {
+		return NULL;
+	}
+	for (i = 0; i < num_records; i++) {
+		PyObject *py_dns_record;
+		py_dns_record = py_return_ndr_struct("samba.dcerpc.dnsp", "DnssrvRpcRecord", records, &records[i]);
+		PyList_SetItem(py_dns_list, i, py_dns_record);
+	}
+	return py_dns_list;
+}
+
+static int py_dnsp_DnssrvRpcRecord_get_array(PyObject *value,
+					     TALLOC_CTX *mem_ctx,
+					     struct dnsp_DnssrvRpcRecord **records,
+					     uint16_t *num_records)
+{
+	int i;
+	struct dnsp_DnssrvRpcRecord *recs;
+	PY_CHECK_TYPE(&PyList_Type, value, return -1;);
+	recs = talloc_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
+			    PyList_GET_SIZE(value));
+	if (recs == NULL) {
+		PyErr_NoMemory();
+		return -1;
+	}
+	for (i = 0; i < PyList_GET_SIZE(value); i++) {
+		bool type_correct;
+		PyObject *item = PyList_GET_ITEM(value, i);
+		type_correct = py_check_dcerpc_type(item, "samba.dcerpc.dnsp", "DnssrvRpcRecord");
+		if (type_correct == false) {
+			return -1;
+		}
+		if (talloc_reference(mem_ctx, pytalloc_get_mem_ctx(item)) == NULL) {
+			PyErr_NoMemory();
+			return -1;
+		}
+		recs[i] = *(struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(item);
+	}
+	*records = recs;
+	*num_records = PyList_GET_SIZE(value);
+	return 0;
+}
+
+static PyObject *py_dsdb_dns_lookup(PyObject *self, PyObject *args)
+{
+	struct ldb_context *samdb;
+	PyObject *py_ldb;
+	char *dns_name;
+	TALLOC_CTX *frame;
+	NTSTATUS status;
+	WERROR werr;
+	struct dns_server_zone *zones_list;
+	struct ldb_dn *dn;
+	struct dnsp_DnssrvRpcRecord *records;
+	uint16_t num_records;
+
+	if (!PyArg_ParseTuple(args, "Os", &py_ldb, &dns_name)) {
+		return NULL;
+	}
+	PyErr_LDB_OR_RAISE(py_ldb, samdb);
+
+	frame = talloc_stackframe();
+
+	status = dns_common_zones(samdb, frame, &zones_list);
+	if (!NT_STATUS_IS_OK(status)) {
+		PyErr_SetNTSTATUS(status);
+		return NULL;
+	}
+
+	werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
+	if (!W_ERROR_IS_OK(werr)) {
+		PyErr_SetWERROR(werr);
+		return NULL;
+	}
+
+	werr = dns_common_lookup(samdb,
+				 frame,
+				 dn,
+				 &records,
+				 &num_records,
+				 NULL);
+	if (!W_ERROR_IS_OK(werr)) {
+		PyErr_SetWERROR(werr);
+		return NULL;
+	}
+
+	return py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
+}
+
+static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args)
+{
+	PyObject *py_dns_el;
+	TALLOC_CTX *frame;
+	WERROR werr;
+	struct ldb_message_element *dns_el;
+	struct dnsp_DnssrvRpcRecord *records;
+	uint16_t num_records;
+
+	if (!PyArg_ParseTuple(args, "O", &py_dns_el)) {
+		return NULL;
+	}
+
+	if (!py_check_dcerpc_type(py_dns_el, "ldb", "MessageElement")) {
+		PyErr_SetString(py_ldb_get_exception(),
+				"ldb MessageElement object required");
+		return NULL;
+	}
+	dns_el = pyldb_MessageElement_AsMessageElement(py_dns_el);
+
+	frame = talloc_stackframe();
+
+	werr = dns_common_extract(dns_el,
+				  frame,
+				  &records,
+				  &num_records);
+	if (!W_ERROR_IS_OK(werr)) {
+		PyErr_SetWERROR(werr);
+		return NULL;
+	}
+
+	return py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
+}
+
+static PyObject *py_dsdb_dns_replace(PyObject *self, PyObject *args)
+{
+	struct ldb_context *samdb;
+	PyObject *py_ldb, *py_dns_records;
+	char *dns_name;
+	TALLOC_CTX *frame;
+	NTSTATUS status;
+	WERROR werr;
+	int ret;
+	struct dns_server_zone *zones_list;
+	struct ldb_dn *dn;
+	struct dnsp_DnssrvRpcRecord *records;
+	uint16_t num_records;
+
+	/*
+	 * TODO: This is a shocking abuse, but matches what the
+	 * internal DNS server does, it should be pushed into
+	 * dns_common_replace()
+	 */
+	static const int serial = 110;
+
+	if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &dns_name, &py_dns_records)) {
+		return NULL;
+	}
+	PyErr_LDB_OR_RAISE(py_ldb, samdb);
+
+	frame = talloc_stackframe();
+
+	status = dns_common_zones(samdb, frame, &zones_list);
+	if (!NT_STATUS_IS_OK(status)) {
+		PyErr_SetNTSTATUS(status);
+		return NULL;
+	}
+
+	werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
+	if (!W_ERROR_IS_OK(werr)) {
+		PyErr_SetWERROR(werr);
+		return NULL;
+	}
+
+	ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
+						frame,
+						&records, &num_records);
+	if (ret != 0) {
+		return NULL;
+	}
+
+	werr = dns_common_replace(samdb,
+				  frame,
+				  dn,
+				  false, /* Not adding a record */
+				  serial,
+				  records,
+				  num_records);
+	if (!W_ERROR_IS_OK(werr)) {
+		PyErr_SetWERROR(werr);
+		return NULL;
+	}
+
+	Py_RETURN_NONE;
+}
+
+static PyObject *py_dsdb_dns_replace_by_dn(PyObject *self, PyObject *args)
+{
+	struct ldb_context *samdb;
+	PyObject *py_ldb, *py_dn, *py_dns_records;
+	TALLOC_CTX *frame;
+	WERROR werr;
+	int ret;
+	struct ldb_dn *dn;
+	struct dnsp_DnssrvRpcRecord *records;
+	uint16_t num_records;
+
+	/*
+	 * TODO: This is a shocking abuse, but matches what the
+	 * internal DNS server does, it should be pushed into
+	 * dns_common_replace()
+	 */
+	static const int serial = 110;
+
+	if (!PyArg_ParseTuple(args, "OOO", &py_ldb, &py_dn, &py_dns_records)) {
+		return NULL;
+	}
+	PyErr_LDB_OR_RAISE(py_ldb, samdb);
+
+	PyErr_LDB_DN_OR_RAISE(py_dn, dn);
+
+	frame = talloc_stackframe();
+
+	ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
+						frame,
+						&records, &num_records);
+	if (ret != 0) {
+		return NULL;
+	}
+
+	werr = dns_common_replace(samdb,
+				  frame,
+				  dn,
+				  false, /* Not adding a record */
+				  serial,
+				  records,
+				  num_records);
+	if (!W_ERROR_IS_OK(werr)) {
+		PyErr_SetWERROR(werr);
+		return NULL;
+	}
+
+	Py_RETURN_NONE;
+}
+
+static PyMethodDef py_dsdb_dns_methods[] = {
+
+	{ "lookup", (PyCFunction)py_dsdb_dns_lookup,
+		METH_VARARGS, "Get the DNS database entries for a DNS name"},
+	{ "replace", (PyCFunction)py_dsdb_dns_replace,
+		METH_VARARGS, "Replace the DNS database entries for a DNS name"},
+	{ "replace_by_dn", (PyCFunction)py_dsdb_dns_replace_by_dn,
+		METH_VARARGS, "Replace the DNS database entries for a LDB DN"},
+	{ "extract", (PyCFunction)py_dsdb_dns_extract,
+		METH_VARARGS, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"},
+	{ NULL }
+};
+
+void initdsdb_dns(void);
+
+void initdsdb_dns(void)
+{
+	PyObject *m;
+
+	m = Py_InitModule3("dsdb_dns", py_dsdb_dns_methods,
+			   "Python bindings for the DNS objects in the directory service databases.");
+	if (m == NULL)
+		return;
+}
diff --git a/source4/dns_server/wscript_build b/source4/dns_server/wscript_build
index a4f0f0c..75f3499 100644
--- a/source4/dns_server/wscript_build
+++ b/source4/dns_server/wscript_build
@@ -2,7 +2,7 @@
 
 bld.SAMBA_LIBRARY('dnsserver_common',
         source='dnsserver_common.c',
-        deps='samba-util errors ldbsamba clidns',
+        deps='samba-util samba-errors ldbsamba clidns',
         private_library=True,
         enabled=bld.AD_DC_BUILD_IS_ENABLED())
 
@@ -53,3 +53,9 @@ bld.SAMBA_LIBRARY('dlz_bind9_for_torture',
                   private_library=True,
                   deps='samba-hostconfig samdb-common gensec popt dnsserver_common',
                   enabled=bld.AD_DC_BUILD_IS_ENABLED())
+
+
+bld.SAMBA_PYTHON('python_dsdb_dns',
+	         source='pydns.c',
+	         deps='samdb pyldb-util pyrpc_util dnsserver_common pytalloc-util',
+	         realname='samba/dsdb_dns.so')
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
index 6447d06..c1b5d5a 100644
--- a/source4/dsdb/common/util.c
+++ b/source4/dsdb/common/util.c
@@ -360,7 +360,7 @@ struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_messa
 	if (sid == NULL) {
 		return NULL;
 	}
-	ok = sid_blob_parse(*v, sid);
+	ok = sid_parse(v->data, v->length, sid);
 	if (!ok) {
 		talloc_free(sid);
 		return NULL;
diff --git a/source4/dsdb/common/util_trusts.c b/source4/dsdb/common/util_trusts.c
index 73221eb..0e69ba2 100644
--- a/source4/dsdb/common/util_trusts.c
+++ b/source4/dsdb/common/util_trusts.c
@@ -2856,7 +2856,7 @@ NTSTATUS dsdb_trust_routing_table_load(struct ldb_context *sam_ctx,
 			return status;
 		}
 
-		DLIST_ADD_END(table->domains, d, NULL);
+		DLIST_ADD_END(table->domains, d);
 
 		if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
 			struct ForestTrustInfo *fti = NULL;
diff --git a/source4/dsdb/dns/dns_update.c b/source4/dsdb/dns/dns_update.c
index 972459a..292a825 100644
--- a/source4/dsdb/dns/dns_update.c
+++ b/source4/dsdb/dns/dns_update.c
@@ -39,6 +39,7 @@
 #include "libcli/composite/composite.h"
 #include "libcli/security/dom_sid.h"
 #include "librpc/gen_ndr/ndr_irpc.h"
+#include "libds/common/roles.h"
 
 NTSTATUS server_service_dnsupdate_init(void);
 
diff --git a/source4/dsdb/kcc/kcc_drs_replica_info.c b/source4/dsdb/kcc/kcc_drs_replica_info.c
index ef64f82..3f16de8 100644
--- a/source4/dsdb/kcc/kcc_drs_replica_info.c
+++ b/source4/dsdb/kcc/kcc_drs_replica_info.c
@@ -468,7 +468,7 @@ static WERROR get_ncs_list(TALLOC_CTX *mem_ctx,
 		nc_list_elem = talloc_zero(mem_ctx, struct ncList);
 		W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
 		nc_list_elem->dn = nc_dn;
-		DLIST_ADD_END(*nc_list, nc_list_elem, struct ncList*);
+		DLIST_ADD_END(*nc_list, nc_list_elem);
 	} else {
 		/* ncs := getNCs() from ldb database.
 		 * getNCs() must return an array containing
diff --git a/source4/dsdb/kcc/kcc_service.c b/source4/dsdb/kcc/kcc_service.c
index 2c1a922..985692f 100644
--- a/source4/dsdb/kcc/kcc_service.c
+++ b/source4/dsdb/kcc/kcc_service.c
@@ -34,6 +34,7 @@
 #include "librpc/gen_ndr/ndr_drsuapi.h"
 #include "librpc/gen_ndr/ndr_drsblobs.h"
 #include "param/param.h"
+#include "libds/common/roles.h"
 
 /*
   establish system creds
diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c
index 9a3b509..f663b43 100644
--- a/source4/dsdb/pydsdb.c
+++ b/source4/dsdb/pydsdb.c
@@ -31,13 +31,6 @@
 
 void initdsdb(void);
 
-/* There's no Py_ssize_t in 2.4, apparently */
-#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
-typedef int Py_ssize_t;
-typedef inquiry lenfunc;
-typedef intargfunc ssizeargfunc;
-#endif
-
 /* FIXME: These should be in a header file somewhere */
 #define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
 	if (!py_check_dcerpc_type(py_ldb, "ldb", "Ldb")) { \
@@ -529,11 +522,6 @@ static PyObject *py_dsdb_DsReplicaAttribute(PyObject *self, PyObject *args)
 
 	PyErr_LDB_OR_RAISE(py_ldb, ldb);
 
-	if (!PyList_Check(el_list)) {
-		PyErr_Format(PyExc_TypeError, "ldif_elements must be a list");
-		return NULL;
-	}
-
 	schema = dsdb_get_schema(ldb, NULL);
 	if (!schema) {
 		PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb");
@@ -555,32 +543,47 @@ static PyObject *py_dsdb_DsReplicaAttribute(PyObject *self, PyObject *args)
 		return NULL;
 	}
 
-	el = talloc_zero(tmp_ctx, struct ldb_message_element);
-	if (el == NULL) {
-		PyErr_NoMemory();
-		talloc_free(tmp_ctx);
-		return NULL;
-	}
-
-	el->name = ldap_display_name;
-	el->num_values = PyList_Size(el_list);
+	/* If we were not given an LdbMessageElement */
+	if (!PyList_Check(el_list)) {
+		if (!py_check_dcerpc_type(el_list, "ldb", "MessageElement")) {
+			PyErr_SetString(py_ldb_get_exception(),
+					"list of strings or ldb MessageElement object required");
+			return NULL;
+		}
+		/*
+		 * NOTE:
+		 * el may not be a valid talloc context, it
+		 * could be part of an array
+		 */
+		el = pyldb_MessageElement_AsMessageElement(el_list);
+	} else {
+		el = talloc_zero(tmp_ctx, struct ldb_message_element);
+		if (el == NULL) {
+			PyErr_NoMemory();
+			talloc_free(tmp_ctx);
+			return NULL;
+		}
 
-	el->values = talloc_array(el, struct ldb_val, el->num_values);
-	if (el->values == NULL) {
-		PyErr_NoMemory();
-		talloc_free(tmp_ctx);
-		return NULL;
-	}
+		el->name = ldap_display_name;
+		el->num_values = PyList_Size(el_list);
 
-	for (i = 0; i < el->num_values; i++) {
-		PyObject *item = PyList_GetItem(el_list, i);
-		if (!PyString_Check(item)) {
-			PyErr_Format(PyExc_TypeError, "ldif_elements should be strings");
+		el->values = talloc_array(el, struct ldb_val, el->num_values);
+		if (el->values == NULL) {
+			PyErr_NoMemory();
 			talloc_free(tmp_ctx);
 			return NULL;
 		}
-		el->values[i].data = (uint8_t *)PyString_AsString(item);
-		el->values[i].length = PyString_Size(item);
+
+		for (i = 0; i < el->num_values; i++) {
+			PyObject *item = PyList_GetItem(el_list, i);
+			if (!PyString_Check(item)) {
+				PyErr_Format(PyExc_TypeError, "ldif_elements should be strings");
+				talloc_free(tmp_ctx);
+				return NULL;
+			}
+			el->values[i].data = (uint8_t *)PyString_AsString(item);
+			el->values[i].length = PyString_Size(item);
+		}
 	}
 
 	attr = talloc_zero(tmp_ctx, struct drsuapi_DsReplicaAttribute);
@@ -606,17 +609,20 @@ static PyObject *py_dsdb_DsReplicaAttribute(PyObject *self, PyObject *args)
  */
 static PyObject *py_dsdb_normalise_attributes(PyObject *self, PyObject *args)
 {
-	PyObject *py_ldb, *el_list, *ret;
+	PyObject *py_ldb, *el_list, *py_ret;
 	struct ldb_context *ldb;
 	char *ldap_display_name;
 	const struct dsdb_attribute *a;
 	struct dsdb_schema *schema;
 	struct dsdb_syntax_ctx syntax_ctx;
-	struct ldb_message_element *el;
+	struct ldb_message_element *el, *new_el;
 	struct drsuapi_DsReplicaAttribute *attr;
+	PyLdbMessageElementObject *ret;
 	TALLOC_CTX *tmp_ctx;
 	WERROR werr;
 	Py_ssize_t i;
+	PyTypeObject *py_type = NULL;
+	PyObject *module = NULL;
 
 	if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &ldap_display_name, &el_list)) {
 		return NULL;
@@ -624,11 +630,6 @@ static PyObject *py_dsdb_normalise_attributes(PyObject *self, PyObject *args)
 
 	PyErr_LDB_OR_RAISE(py_ldb, ldb);
 
-	if (!PyList_Check(el_list)) {
-		PyErr_Format(PyExc_TypeError, "ldif_elements must be a list");
-		return NULL;
-	}
-
 	schema = dsdb_get_schema(ldb, NULL);
 	if (!schema) {
 		PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb");
@@ -650,38 +651,59 @@ static PyObject *py_dsdb_normalise_attributes(PyObject *self, PyObject *args)
 		return NULL;
 	}
 
-	el = talloc_zero(tmp_ctx, struct ldb_message_element);
-	if (el == NULL) {
-		PyErr_NoMemory();
-		talloc_free(tmp_ctx);
-		return NULL;
-	}
-
-	el->name = ldap_display_name;
-	el->num_values = PyList_Size(el_list);
+	if (!PyList_Check(el_list)) {
+		if (!py_check_dcerpc_type(el_list, "ldb", "MessageElement")) {
+			PyErr_SetString(py_ldb_get_exception(),
+					"list of strings or ldb MessageElement object required");
+			return NULL;
+		}
+		/*
+		 * NOTE:
+		 * el may not be a valid talloc context, it
+		 * could be part of an array
+		 */
+		el = pyldb_MessageElement_AsMessageElement(el_list);
+	} else {
+		el = talloc_zero(tmp_ctx, struct ldb_message_element);
+		if (el == NULL) {
+			PyErr_NoMemory();
+			talloc_free(tmp_ctx);
+			return NULL;
+		}
 
-	el->values = talloc_array(el, struct ldb_val, el->num_values);
-	if (el->values == NULL) {
-		PyErr_NoMemory();
-		talloc_free(tmp_ctx);
-		return NULL;
-	}
+		el->name = ldap_display_name;
+		el->num_values = PyList_Size(el_list);
 
-	for (i = 0; i < el->num_values; i++) {
-		PyObject *item = PyList_GetItem(el_list, i);
-		if (!PyString_Check(item)) {
-			PyErr_Format(PyExc_TypeError, "ldif_elements should be strings");
+		el->values = talloc_array(el, struct ldb_val, el->num_values);
+		if (el->values == NULL) {
+			PyErr_NoMemory();
 			talloc_free(tmp_ctx);
 			return NULL;
 		}
-		el->values[i].data = (uint8_t *)PyString_AsString(item);
-		el->values[i].length = PyString_Size(item);
+
+		for (i = 0; i < el->num_values; i++) {
+			PyObject *item = PyList_GetItem(el_list, i);
+			if (!PyString_Check(item)) {
+				PyErr_Format(PyExc_TypeError, "ldif_elements should be strings");
+				talloc_free(tmp_ctx);
+				return NULL;
+			}
+			el->values[i].data = (uint8_t *)PyString_AsString(item);
+			el->values[i].length = PyString_Size(item);
+		}
+	}
+
+	new_el = talloc_zero(tmp_ctx, struct ldb_message_element);
+	if (new_el == NULL) {
+		PyErr_NoMemory();
+		talloc_free(tmp_ctx);
+		return NULL;
 	}
 
 	/* Normalise "objectClass" attribute if needed */
 	if (ldb_attr_cmp(a->lDAPDisplayName, "objectClass") == 0) {
 		int iret;
-		iret = dsdb_sort_objectClass_attr(ldb, schema, el, tmp_ctx, el);
+		iret = dsdb_sort_objectClass_attr(ldb, schema, el, new_el, new_el);
 		if (iret != LDB_SUCCESS) {
 			PyErr_SetString(PyExc_RuntimeError, ldb_errstring(ldb));
 			talloc_free(tmp_ctx);
@@ -704,14 +726,31 @@ static PyObject *py_dsdb_normalise_attributes(PyObject *self, PyObject *args)
 	PyErr_WERROR_NOT_OK_RAISE(werr);
 
 	/* now convert back again */
-	werr = a->syntax->drsuapi_to_ldb(&syntax_ctx, a, attr, el, el);
+	werr = a->syntax->drsuapi_to_ldb(&syntax_ctx, a, attr, new_el, new_el);
 	PyErr_WERROR_NOT_OK_RAISE(werr);
 
-	ret = py_return_ndr_struct("ldb", "MessageElement", el, el);
+	module = PyImport_ImportModule("ldb");
+	if (module == NULL) {
+		return NULL;
+	}
+
+	py_type = (PyTypeObject *)PyObject_GetAttrString(module, "MessageElement");
+	if (py_type == NULL) {
+		return NULL;
+	}
+	py_ret = py_type->tp_alloc(py_type, 0);
+	ret = (PyLdbMessageElementObject *)py_ret;
+
+	ret->mem_ctx = talloc_new(NULL);
+	if (talloc_reference(ret->mem_ctx, new_el) == NULL) {
+		PyErr_NoMemory();
+		return NULL;
+	}
+	ret->el = new_el;
 
 	talloc_free(tmp_ctx);
 
-	return ret;
+	return py_ret;
 }
 
 
@@ -1180,6 +1219,8 @@ void initdsdb(void)
 	ADD_DSDB_FLAG(DS_DOMAIN_FUNCTION_2003);
 	ADD_DSDB_FLAG(DS_DOMAIN_FUNCTION_2008);
 	ADD_DSDB_FLAG(DS_DOMAIN_FUNCTION_2008_R2);
+	ADD_DSDB_FLAG(DS_DOMAIN_FUNCTION_2012);
+	ADD_DSDB_FLAG(DS_DOMAIN_FUNCTION_2012_R2);
 
         /* nc replica flags */
 	ADD_DSDB_FLAG(INSTANCE_TYPE_IS_NC_HEAD);
diff --git a/source4/dsdb/repl/drepl_notify.c b/source4/dsdb/repl/drepl_notify.c
index 3f2c851..ee2e4c8 100644
--- a/source4/dsdb/repl/drepl_notify.c
+++ b/source4/dsdb/repl/drepl_notify.c
@@ -323,7 +323,7 @@ static WERROR dreplsrv_schedule_notify_sync(struct dreplsrv_service *service,
 	op->replica_flags = replica_flags;
 	op->schedule_time = time(NULL);
 
-	DLIST_ADD_END(service->ops.notifies, op, struct dreplsrv_notify_operation *);
+	DLIST_ADD_END(service->ops.notifies, op);
 	talloc_steal(service, op);
 	return WERR_OK;
 }
diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c
index a047881..a1e8dcb 100644
--- a/source4/dsdb/repl/drepl_out_helpers.c
+++ b/source4/dsdb/repl/drepl_out_helpers.c
@@ -740,6 +740,9 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
 	if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
 		dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
 	}
+	if (state->op->options & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
+		dsdb_repl_flags |= DSDB_REPL_FLAG_EXPECT_NO_SECRETS;
+	}
 
 	status = dsdb_replicated_objects_convert(service->samdb,
 						 working_schema ? working_schema : schema,
diff --git a/source4/dsdb/repl/drepl_out_pull.c b/source4/dsdb/repl/drepl_out_pull.c
index e64c91d..2da2673 100644
--- a/source4/dsdb/repl/drepl_out_pull.c
+++ b/source4/dsdb/repl/drepl_out_pull.c
@@ -127,7 +127,7 @@ WERROR dreplsrv_schedule_partition_pull_source(struct dreplsrv_service *s,
 	op->cb_data	= cb_data;
 	op->schedule_time = time(NULL);
 
-	DLIST_ADD_END(s->ops.pending, op, struct dreplsrv_out_operation *);
+	DLIST_ADD_END(s->ops.pending, op);
 
 	return WERR_OK;
 }
diff --git a/source4/dsdb/repl/drepl_partitions.c b/source4/dsdb/repl/drepl_partitions.c
index c822ba9..65b4843 100644
--- a/source4/dsdb/repl/drepl_partitions.c
+++ b/source4/dsdb/repl/drepl_partitions.c
@@ -345,7 +345,7 @@ WERROR dreplsrv_out_connection_attach(struct dreplsrv_service *s,
 			return ntstatus_to_werror(nt_status);
 		}
 
-		DLIST_ADD_END(s->connections, conn, struct dreplsrv_out_connection *);
+		DLIST_ADD_END(s->connections, conn);
 
 		DEBUG(4,("dreplsrv_out_connection_attach(%s): create\n", hostname));
 	} else {
@@ -425,7 +425,7 @@ static WERROR dreplsrv_partition_add_source_dsa(struct dreplsrv_service *s,
 		}
 	}
 
-	DLIST_ADD_END(*listp, source, struct dreplsrv_partition_source_dsa *);
+	DLIST_ADD_END(*listp, source);
 	return WERR_OK;
 }
 
diff --git a/source4/dsdb/repl/drepl_service.c b/source4/dsdb/repl/drepl_service.c
index bd33377..2176da2 100644
--- a/source4/dsdb/repl/drepl_service.c
+++ b/source4/dsdb/repl/drepl_service.c
@@ -33,6 +33,7 @@
 #include "librpc/gen_ndr/ndr_drsblobs.h"
 #include "librpc/gen_ndr/ndr_irpc.h"
 #include "param/param.h"
+#include "libds/common/roles.h"
 
 /**
  * Call-back data for _drepl_replica_sync_done_cb()
diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c
index 97b8b2a..a112e18 100644
--- a/source4/dsdb/repl/replicated_objects.c
+++ b/source4/dsdb/repl/replicated_objects.c
@@ -138,7 +138,7 @@ WERROR dsdb_repl_resolve_working_schema(struct ldb_context *ldb,
 		}
 
 		schema_list_item->obj = cur;
-		DLIST_ADD_END(schema_list, schema_list_item, struct schema_list);
+		DLIST_ADD_END(schema_list, schema_list_item);
 	}
 
 	/* resolve objects until all are resolved and in local schema */
@@ -188,6 +188,7 @@ WERROR dsdb_repl_resolve_working_schema(struct ldb_context *ldb,
 			 * an object. We should convert more objects on next pass.
 			 */
 			werr = dsdb_convert_object_ex(ldb, working_schema,
+						      NULL,
 						      pfm_remote,
 						      cur, &empty_key,
 						      ignore_attids,
@@ -338,6 +339,7 @@ static bool dsdb_attid_in_list(const uint32_t attid_list[], uint32_t attid)
 
 WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 			      const struct dsdb_schema *schema,
+			      struct ldb_dn *partition_dn,
 			      const struct dsdb_schema_prefixmap *pfm_remote,
 			      const struct drsuapi_DsReplicaObjectListItemEx *in,
 			      const DATA_BLOB *gensec_skey,
@@ -347,7 +349,7 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 			      struct dsdb_extended_replicated_object *out)
 {
 	NTSTATUS nt_status;
-	WERROR status;
+	WERROR status = WERR_OK;
 	uint32_t i;
 	struct ldb_message *msg;
 	struct replPropertyMetaDataBlob *md;
@@ -444,15 +446,42 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 		}
 
 		for (j=0; j<a->value_ctr.num_values; j++) {
-			status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob, gensec_skey, rid, a);
-			W_ERROR_NOT_OK_RETURN(status);
+			status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob,
+							   gensec_skey, rid,
+							   dsdb_repl_flags, a);
+			if (!W_ERROR_IS_OK(status)) {
+				break;
+			}
+		}
+		if (W_ERROR_EQUAL(status, WERR_TOO_MANY_SECRETS)) {
+			WERROR get_name_status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
+									       a, msg->elements, e, NULL);
+			if (W_ERROR_IS_OK(get_name_status)) {
+				DEBUG(0, ("Unxpectedly got secret value %s on %s from DRS server\n",
+					  e->name, ldb_dn_get_linearized(msg->dn)));
+			} else {
+				DEBUG(0, ("Unxpectedly got secret value on %s from DRS server",
+					  ldb_dn_get_linearized(msg->dn)));
+			}
+		} else if (!W_ERROR_IS_OK(status)) {
+			return status;
 		}
 
+		/*
+		 * This function also fills in the local attid value,
+		 * based on comparing the remote and local prefixMap
+		 * tables.  If we don't convert the value, then we can
+		 * have invalid values in the replPropertyMetaData we
+		 * store on disk, as the prefixMap is per host, not
+		 * per-domain.  This may be why Microsoft added the
+		 * msDS-IntID feature, however this is not used for
+		 * extra attributes in the schema partition itself.
+		 */
 		status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
-						       a, msg->elements, e);
+						       a, msg->elements, e,
+						       &m->attid);
 		W_ERROR_NOT_OK_RETURN(status);
 
-		m->attid			= a->attid;
 		m->version			= d->version;
 		m->originating_change_time	= d->originating_change_time;
 		m->originating_invocation_id	= d->originating_invocation_id;
@@ -531,6 +560,17 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 	}
 
 	instanceType = ldb_msg_find_attr_as_int(msg, "instanceType", 0);
+
+	if (instanceType & INSTANCE_TYPE_IS_NC_HEAD && partition_dn) {
+		int partition_dn_cmp = ldb_dn_compare(partition_dn, msg->dn);
+		if (partition_dn_cmp != 0) {
+			DEBUG(4, ("Remote server advised us of a new partition %s while processing %s, ignoring\n",
+				  ldb_dn_get_linearized(msg->dn),
+				  ldb_dn_get_linearized(partition_dn)));
+			return WERR_DS_ADD_REPLICA_INHIBITED;
+		}
+	}
+
 	if (dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
 		/* the instanceType type for partial_replica
 		   replication is sent via DRS with TYPE_WRITE set, but
@@ -661,10 +701,10 @@ WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
 	out->source_dsa		= source_dsa;
 	out->uptodateness_vector= uptodateness_vector;
 
-	out->num_objects	= object_count;
+	out->num_objects	= 0;
 	out->objects		= talloc_array(out,
 					       struct dsdb_extended_replicated_object,
-					       out->num_objects);
+					       object_count);
 	W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->objects, out);
 
 	/* pass the linked attributes down to the repl_meta_data
@@ -673,16 +713,30 @@ WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
 	out->linked_attributes       = linked_attributes;
 
 	for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
-		if (i == out->num_objects) {
+		if (i == object_count) {
 			talloc_free(out);
 			return WERR_FOOBAR;
 		}
 
-		status = dsdb_convert_object_ex(ldb, schema, pfm_remote,
+		status = dsdb_convert_object_ex(ldb, schema, out->partition_dn,
+						pfm_remote,
 						cur, gensec_skey,
 						NULL,
 						dsdb_repl_flags,
-						out->objects, &out->objects[i]);
+						out->objects,
+						&out->objects[out->num_objects]);
+
+		/*
+		 * Check to see if we have been advised of a
+		 * subdomain or new application partition.  We don't
+		 * want to start on that here, instead the caller
+		 * should consider if it would like to replicate it
+		 * based on the cross-ref object.
+		 */
+		if (W_ERROR_EQUAL(status, WERR_DS_ADD_REPLICA_INHIBITED)) {
+			continue;
+		}
+
 		if (!W_ERROR_IS_OK(status)) {
 			talloc_free(out);
 			DEBUG(0,("Failed to convert object %s: %s\n",
@@ -690,8 +744,18 @@ WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
 				 win_errstr(status)));
 			return status;
 		}
+
+		/* Assuming we didn't skip or error, increment the number of objects */
+		out->num_objects++;
+	}
+	out->objects = talloc_realloc(out, out->objects,
+				      struct dsdb_extended_replicated_object,
+				      out->num_objects);
+	if (out->num_objects != 0 && out->objects == NULL) {
+		talloc_free(out);
+		return WERR_FOOBAR;
 	}
-	if (i != out->num_objects) {
+	if (i != object_count) {
 		talloc_free(out);
 		return WERR_FOOBAR;
 	}
@@ -902,7 +966,7 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
 
 		ret = ldb_build_mod_req(&req, ldb, objects,
 				msg,
-				LDB_SCOPE_BASE,
+				NULL,
 				NULL,
 				ldb_op_default_callback,
 				NULL);
@@ -984,7 +1048,7 @@ static WERROR dsdb_origin_object_convert(struct ldb_context *ldb,
 		e = &msg->elements[i];
 
 		status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, schema->prefixmap,
-						       a, msg->elements, e);
+						       a, msg->elements, e, NULL);
 		W_ERROR_NOT_OK_RETURN(status);
 	}
 
diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c
index 78e6461..62e560f 100644
--- a/source4/dsdb/samdb/ldb_modules/acl.c
+++ b/source4/dsdb/samdb/ldb_modules/acl.c
@@ -867,7 +867,7 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req)
 					     &objectclass->schemaIDGUID, req);
 	if (ret != LDB_SUCCESS) {
 		ldb_asprintf_errstring(ldb_module_get_ctx(module),
-				       "acl: unable to find or validate structural objectClass on %s\n",
+				       "acl: unable to get access to %s\n",
 				       ldb_dn_get_linearized(req->op.add.message->dn));
 		return ret;
 	}
diff --git a/source4/dsdb/samdb/ldb_modules/descriptor.c b/source4/dsdb/samdb/ldb_modules/descriptor.c
index cc0a9c2..2baf4af 100644
--- a/source4/dsdb/samdb/ldb_modules/descriptor.c
+++ b/source4/dsdb/samdb/ldb_modules/descriptor.c
@@ -1049,9 +1049,9 @@ static int descriptor_extended_sec_desc_propagation(struct ldb_module *module,
 	}
 
 	if (parent_change != NULL) {
-		DLIST_ADD_END(parent_change->children, c, NULL);
+		DLIST_ADD_END(parent_change->children, c);
 	} else {
-		DLIST_ADD_END(descriptor_private->changes, c, NULL);
+		DLIST_ADD_END(descriptor_private->changes, c);
 	}
 
 	return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
diff --git a/source4/dsdb/samdb/ldb_modules/dns_notify.c b/source4/dsdb/samdb/ldb_modules/dns_notify.c
index 2481a41..3a91eef 100644
--- a/source4/dsdb/samdb/ldb_modules/dns_notify.c
+++ b/source4/dsdb/samdb/ldb_modules/dns_notify.c
@@ -37,7 +37,7 @@
 #include "lib/messaging/irpc.h"
 #include "librpc/gen_ndr/ndr_irpc_c.h"
 #include "param/param.h"
-#include "dlinklist.h"
+#include "util/dlinklist.h"
 
 struct dns_notify_watched_dn {
 	struct dns_notify_watched_dn *next, *prev;
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
index 4127036..b7ca636 100644
--- a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
+++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
@@ -35,6 +35,7 @@
 #include <ldb_module.h>
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/samdb/ldb_modules/util.h"
+#include "lib/ldb-samba/ldb_matching_rules.h"
 
 /*
   TODO: if relax is not set then we need to reject the fancy RMD_* and
@@ -406,7 +407,8 @@ static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *privat
 
 	if (tree->operation == LDB_OP_EQUALITY) {
 		dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.equality.value);
-	} else if (tree->operation == LDB_OP_EXTENDED) {
+	} else if (tree->operation == LDB_OP_EXTENDED
+		   && (strcmp(tree->u.extended.rule_id, SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL) == 0)) {
 		dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.extended.value);
 	}
 	if (dn == NULL) {
diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c
index 63ccbde..8063162 100644
--- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c
+++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c
@@ -219,7 +219,7 @@ static int la_store_op(struct la_context *ac,
 
 	/* Do deletes before adds */
 	if (op == LA_OP_ADD) {
-		DLIST_ADD_END(ac->ops, os, struct la_op_store *);
+		DLIST_ADD_END(ac->ops, os);
 	} else {
 		/* By adding to the head of the list, we do deletes before
 		 * adds when processing a replace */
diff --git a/source4/dsdb/samdb/ldb_modules/operational.c b/source4/dsdb/samdb/ldb_modules/operational.c
index 8390230..c5fd8e2 100644
--- a/source4/dsdb/samdb/ldb_modules/operational.c
+++ b/source4/dsdb/samdb/ldb_modules/operational.c
@@ -462,7 +462,7 @@ static int construct_msds_isrodc_with_dn(struct ldb_module *module,
 	ldb = ldb_module_get_ctx(module);
 	if (!ldb) {
 		DEBUG(4, (__location__ ": Failed to get ldb \n"));
-		return ldb_operr(ldb);
+		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
 	dn = ldb_dn_new(msg, ldb, (const char *)object_category->values[0].data);
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 3310d30..6ba2caa 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -890,6 +890,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req)
 	bool allow_add_guid = false;
 	bool remove_current_guid = false;
 	bool is_urgent = false;
+	bool is_schema_nc = false;
 	struct ldb_message_element *objectclass_el;
 	struct replmd_private *replmd_private =
 		talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
@@ -1007,6 +1008,8 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
+	is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
+
 	for (i=0; i < msg->num_elements; i++) {
 		struct ldb_message_element *e = &msg->elements[i];
 		struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
@@ -1041,8 +1044,8 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req)
 			continue;
 		}
 
-		m->attid			= sa->attributeID_id;
-		m->version			= 1;
+		m->attid   = dsdb_attribute_get_attid(sa, is_schema_nc);
+		m->version = 1;
 		if (m->attid == 0x20030) {
 			const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
 			const char* rdn;
@@ -1209,12 +1212,14 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
 				      uint64_t *seq_num,
 				      const struct GUID *our_invocation_id,
 				      NTTIME now,
+				      bool is_schema_nc,
 				      struct ldb_request *req)
 {
 	uint32_t i;
 	const struct dsdb_attribute *a;
 	struct replPropertyMetaData1 *md1;
 	bool may_skip = false;
+	uint32_t attid;
 
 	a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
 	if (a == NULL) {
@@ -1229,6 +1234,8 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
+	attid = dsdb_attribute_get_attid(a, is_schema_nc);
+
 	if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
 		return LDB_SUCCESS;
 	}
@@ -1272,7 +1279,22 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
 	}
 
 	for (i=0; i<omd->ctr.ctr1.count; i++) {
-		if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
+		/*
+		 * First check if we find it under the msDS-IntID,
+		 * then check if we find it under the OID and
+		 * prefixMap ID.
+		 *
+		 * This allows the administrator to simply re-write
+		 * the attributes and so restore replication, which is
+		 * likely what they will try to do.
+		 */
+		if (attid == omd->ctr.ctr1.array[i].attid) {
+			break;
+		}
+
+		if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
+			break;
+		}
 	}
 
 	if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
@@ -1311,7 +1333,7 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
 
 	md1 = &omd->ctr.ctr1.array[i];
 	md1->version++;
-	md1->attid                     = a->attributeID_id;
+	md1->attid = attid;
 	if (md1->attid == 0x20030) {
 		const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
 		const char* rdn;
@@ -1365,7 +1387,7 @@ static int replmd_update_rpmd(struct ldb_module *module,
 			      struct ldb_request *req,
 			      const char * const *rename_attrs,
 			      struct ldb_message *msg, uint64_t *seq_num,
-			      time_t t,
+			      time_t t, bool is_schema_nc,
 			      bool *is_urgent, bool *rodc)
 {
 	const struct ldb_val *omd_value;
@@ -1524,7 +1546,9 @@ static int replmd_update_rpmd(struct ldb_module *module,
 			struct ldb_message_element *old_el;
 			old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
 			ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
-							 our_invocation_id, now, req);
+							 our_invocation_id,
+							 now, is_schema_nc,
+							 req);
 			if (ret != LDB_SUCCESS) {
 				return ret;
 			}
@@ -2486,6 +2510,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
 	time_t t = time(NULL);
 	int ret;
 	bool is_urgent = false, rodc = false;
+	bool is_schema_nc = false;
 	unsigned int functional_level;
 	const struct ldb_message_element *guid_el = NULL;
 	struct ldb_control *sd_propagation_control;
@@ -2541,8 +2566,11 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
 	ldb_msg_remove_attr(msg, "whenChanged");
 	ldb_msg_remove_attr(msg, "uSNChanged");
 
+	is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
+
 	ret = replmd_update_rpmd(module, ac->schema, req, NULL,
-				 msg, &ac->seq_num, t, &is_urgent, &rodc);
+				 msg, &ac->seq_num, t, is_schema_nc,
+				 &is_urgent, &rodc);
 	if (rodc && (ret == LDB_ERR_REFERRAL)) {
 		struct loadparm_context *lp_ctx;
 		char *referral;
@@ -2690,7 +2718,6 @@ static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
 	struct ldb_context *ldb;
-	struct replmd_replicated_request *ac;
 	struct ldb_request *down_req;
 	struct ldb_message *msg;
 	const struct dsdb_attribute *rdn_attr;
@@ -2700,8 +2727,13 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
 	time_t t = time(NULL);
 	int ret;
 	bool is_urgent = false, rodc = false;
+	bool is_schema_nc;
+	struct replmd_replicated_request *ac =
+		talloc_get_type(req->context, struct replmd_replicated_request);
+	struct replmd_private *replmd_private =
+		talloc_get_type(ldb_module_get_private(ac->module),
+				struct replmd_private);
 
-	ac = talloc_get_type(req->context, struct replmd_replicated_request);
 	ldb = ldb_module_get_ctx(ac->module);
 
 	if (ares->error != LDB_SUCCESS) {
@@ -2729,6 +2761,8 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
 
 	msg->dn = ac->req->op.rename.newdn;
 
+	is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
+
 	rdn_name = ldb_dn_get_rdn_name(msg->dn);
 	if (rdn_name == NULL) {
 		talloc_free(ares);
@@ -2814,7 +2848,8 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
 	attrs[4] = NULL;
 
 	ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
-				 msg, &ac->seq_num, t, &is_urgent, &rodc);
+				 msg, &ac->seq_num, t,
+				 is_schema_nc, &is_urgent, &rodc);
 	if (rodc && (ret == LDB_ERR_REFERRAL)) {
 		struct ldb_dn *olddn = ac->req->op.rename.olddn;
 		struct loadparm_context *lp_ctx;
@@ -3159,16 +3194,17 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 					    ldb_dn_escape_value(tmp_ctx, *rdn_value),
 					    GUID_string(tmp_ctx, &guid));
 		if (!retb) {
-			DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
-				 ldb_dn_get_linearized(new_dn)));
+			ldb_asprintf_errstring(ldb, __location__
+					       ": Unable to add a formatted child to dn: %s",
+					       ldb_dn_get_linearized(new_dn));
 			talloc_free(tmp_ctx);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
 
 		ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
 		if (ret != LDB_SUCCESS) {
-			DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
-			ldb_module_oom(module);
+			ldb_asprintf_errstring(ldb, __location__
+					       ": Failed to add isDeleted string to the msg");
 			talloc_free(tmp_ctx);
 			return ret;
 		}
@@ -3182,8 +3218,9 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 		struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
 		retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
 		if (!retb) {
-			DEBUG(0,(__location__ ": Unable to add a prepare rdn of %s",
-				 ldb_dn_get_linearized(rdn)));
+			ldb_asprintf_errstring(ldb, __location__
+					       ": Unable to add a prepare rdn of %s",
+					       ldb_dn_get_linearized(rdn));
 			talloc_free(tmp_ctx);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
@@ -3191,9 +3228,10 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 
 		retb = ldb_dn_add_child(new_dn, rdn);
 		if (!retb) {
-			DEBUG(0,(__location__ ": Unable to add rdn %s to base dn: %s",
-				 ldb_dn_get_linearized(rdn),
-				 ldb_dn_get_linearized(new_dn)));
+			ldb_asprintf_errstring(ldb, __location__
+					       ": Unable to add rdn %s to base dn: %s",
+					       ldb_dn_get_linearized(rdn),
+					       ldb_dn_get_linearized(new_dn));
 			talloc_free(tmp_ctx);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
@@ -3217,29 +3255,48 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 	 */
 
 	if (deletion_state == OBJECT_NOT_DELETED) {
+		struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
+		char *parent_dn_str = NULL;
+
 		/* we need the storage form of the parent GUID */
 		ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
-					    ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
+					    parent_dn, NULL,
 					    DSDB_FLAG_NEXT_MODULE |
 					    DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
 					    DSDB_SEARCH_REVEAL_INTERNALS|
 					    DSDB_SEARCH_SHOW_RECYCLED, req);
 		if (ret != LDB_SUCCESS) {
 			ldb_asprintf_errstring(ldb_module_get_ctx(module),
-					       "repmd_delete: Failed to %s %s, because we failed to find it's parent (%s): %s",
+					       "repmd_delete: Failed to %s %s, "
+					       "because we failed to find it's parent (%s): %s",
 					       re_delete ? "re-delete" : "delete",
 					       ldb_dn_get_linearized(old_dn),
-					       ldb_dn_get_linearized(ldb_dn_get_parent(tmp_ctx, old_dn)),
+					       ldb_dn_get_linearized(parent_dn),
 					       ldb_errstring(ldb_module_get_ctx(module)));
 			talloc_free(tmp_ctx);
 			return ret;
 		}
 
+		/*
+		 * Now we can use the DB version,
+		 * it will have the extended DN info in it
+		 */
+		parent_dn = parent_res->msgs[0]->dn;
+		parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
+							       parent_dn,
+							       1);
+		if (parent_dn_str == NULL) {
+			talloc_free(tmp_ctx);
+			return ldb_module_oom(module);
+		}
+
 		ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
-						   ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
+					       parent_dn_str);
 		if (ret != LDB_SUCCESS) {
-			DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
-			ldb_module_oom(module);
+			ldb_asprintf_errstring(ldb, __location__
+					       ": Failed to add lastKnownParent "
+					       "string when deleting %s",
+					       ldb_dn_get_linearized(old_dn));
 			talloc_free(tmp_ctx);
 			return ret;
 		}
@@ -3248,8 +3305,10 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 		if (next_deletion_state == OBJECT_DELETED) {
 			ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
 			if (ret != LDB_SUCCESS) {
-				DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
-				ldb_module_oom(module);
+				ldb_asprintf_errstring(ldb, __location__
+						       ": Failed to add msDS-LastKnownRDN "
+						       "string when deleting %s",
+						       ldb_dn_get_linearized(old_dn));
 				talloc_free(tmp_ctx);
 				return ret;
 			}
@@ -3316,6 +3375,14 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 				 */
 				ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
 				if (ret != LDB_SUCCESS) {
+					const char *old_dn_str
+						= ldb_dn_get_linearized(old_dn);
+					ldb_asprintf_errstring(ldb,
+							       __location__
+							       ": Failed to remove backlink of "
+							       "%s when deleting %s",
+							       el->name,
+							       old_dn_str);
 					talloc_free(tmp_ctx);
 					return LDB_ERR_OPERATIONS_ERROR;
 				}
diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c
index f26bc94..ff13458 100644
--- a/source4/dsdb/samdb/ldb_modules/rootdse.c
+++ b/source4/dsdb/samdb/ldb_modules/rootdse.c
@@ -831,7 +831,7 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
 
 	if (do_attribute_explicit(req->op.search.attrs, "netlogon")) {
 		ret = rootdse_handle_netlogon(ac);
-		/* We have to return an empty result, so dont forward `ret' */
+		/* We have to return an empty result, so don't forward `ret' */
 		if (ret != LDB_SUCCESS) {
 			return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
 		}
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index df285d9..2394bd9 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -42,6 +42,7 @@
 #include "ldb_wrap.h"
 #include "param/param.h"
 #include "libds/common/flag_mapping.h"
+#include "system/network.h"
 
 struct samldb_ctx;
 enum samldb_add_type {
@@ -695,7 +696,7 @@ static int samldb_fill_object(struct samldb_ctx *ac)
 						  "rdnAttId", "cn");
 		if (ret != LDB_SUCCESS) return ret;
 
-		/* do not allow to mark an attributeSchema as RODC filtered if it
+		/* do not allow one to mark an attributeSchema as RODC filtered if it
 		 * is system-critical */
 		if (check_rodc_critical_attribute(ac->msg)) {
 			ldb_asprintf_errstring(ldb, "Refusing schema add of %s - cannot combine critical class with RODC filtering",
@@ -796,7 +797,7 @@ static int samldb_fill_object(struct samldb_ctx *ac)
 			}
 		}
 
-		/* do not allow to mark an attributeSchema as RODC filtered if it
+		/* do not allow one to mark an attributeSchema as RODC filtered if it
 		 * is system-critical */
 		if (check_rodc_critical_attribute(ac->msg)) {
 			ldb_asprintf_errstring(ldb,
@@ -2644,6 +2645,270 @@ static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac)
 	return LDB_SUCCESS;
 }
 
+/*
+ * Return zero if the number of zero bits in the address (looking from low to
+ * high) is equal to or greater than the length minus the mask. Otherwise it
+ * returns -1.
+ */
+static int check_cidr_zero_bits(uint8_t *address, unsigned int len,
+				unsigned int mask)
+{
+	/* <address> is an integer in big-endian form, <len> bits long. All
+	   bits between <mask> and <len> must be zero. */
+	int i;
+	unsigned int byte_len;
+	unsigned int byte_mask;
+	unsigned int bit_mask;
+	if (len == 32) {
+		DBG_INFO("Looking at address %02x%02x%02x%02x, mask %u\n",
+			 address[0], address[1], address[2], address[3],
+			  mask);
+	} else if (len == 128){
+		DBG_INFO("Looking at address "
+			 "%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
+			 "%02x%02x-%02x%02x-%02x%02x-%02x%02x, mask %u\n",
+			 address[0], address[1], address[2], address[3],
+			 address[4], address[5], address[6], address[7],
+			 address[8], address[9], address[10], address[11],
+			 address[12], address[13], address[14], address[15],
+			 mask);
+	}
+
+	if (mask > len){
+		DBG_INFO("mask %u is too big (> %u)\n", mask, len);
+		return -1;
+	}
+	if (mask == len){
+		/* single address subnet.
+		 * In IPv4 all 255s is invalid by the bitmask != address rule
+		 * in MS-ADTS. IPv6 does not suffer.
+		 */
+		if (len == 32){
+			if (address[0] == 255 &&
+			    address[1] == 255 &&
+			    address[2] == 255 &&
+			    address[3] == 255){
+				return -1;
+			}
+		}
+		return 0;
+	}
+
+	byte_len = len / 8;
+	byte_mask = mask / 8;
+
+	for (i = byte_len - 1; i > byte_mask; i--){
+		DBG_DEBUG("checking byte %d %02x\n", i, address[i]);
+		if (address[i] != 0){
+			return -1;
+		}
+	}
+	bit_mask = (1 << (8 - (mask & 7))) - 1;
+	DBG_DEBUG("checking bitmask %02x & %02x overlap %02x\n", bit_mask, address[byte_mask],
+		  bit_mask & address[byte_mask]);
+	if (address[byte_mask] & bit_mask){
+		return -1;
+	}
+
+	/* According to MS-ADTS, the mask can't exactly equal the bitmask for
+	 * IPv4 (but this is fine for v6). That is 255.255.80.0/17 is bad,
+	 * because the bitmask implied by "/17" is 255.255.80.0.
+	 *
+	 * The bit_mask used in the previous check is the complement of what
+	 * we want here.
+	 */
+	if (len == 32 && address[byte_mask] == (uint8_t)~bit_mask){
+		bool ok = false;
+		for (i = 0; i < byte_mask; i++){
+			if (address[i] != 255){
+				ok = true;
+				break;
+			}
+		}
+		if (ok == false){
+			return -1;
+		}
+	}
+	return 0;
+}
+
+
+
+static int check_address_roundtrip(const char *address, int family,
+				   const uint8_t *address_bytes,
+				   char *buffer, int buffer_len)
+{
+	/*
+	 * Check that the address is in the canonical RFC5952 format for IPv6,
+	 * and lacks extra leading zeros for each dotted decimal for IPv4.
+	 * Handily this is what inet_ntop() gives you.
+	 */
+	const char *address_redux = inet_ntop(family, address_bytes,
+					      buffer, buffer_len);
+	if (address_redux == NULL){
+		DBG_INFO("Address round trip %s failed unexpectedly"
+			 " with errno %d\n", address, errno);
+		return -1;
+	}
+	if (strcasecmp(address, address_redux) != 0){
+		DBG_INFO("Address %s round trips to %s; fail!\n",
+			 address, address_redux);
+		/* If the address family is IPv6, and the address is in a
+		   certain range
+
+		 */
+		if (strchr(address_redux, '.') != NULL){
+			DEBUG(0, ("The IPv6 address '%s' has the misfortune of "
+				  "lying in a range that was once used for "
+				  "IPv4 embedding (that is, it might also be "
+				  "represented as '%s').\n", address,
+				  address_redux));
+		}
+		return -1;
+	}
+	return 0;
+}
+
+
+
+/*
+ * MS-ADTS v20150630 6.1.1.2.2.2.1 Subnet Object, refers to RFC1166 and
+ * RFC2373. It specifies something seemingly indistinguishable from an RFC4632
+ * CIDR address range without saying so explicitly. Here we follow the CIDR
+ * spec.
+ *
+ * Return 0 on success, -1 on error.
+ */
+static int verify_cidr(const char *cidr)
+{
+	char *address = NULL, *slash = NULL, *endptr = NULL;
+	bool has_colon, has_dot;
+	int res, ret;
+	unsigned long mask;
+	uint8_t *address_bytes = NULL;
+	char *address_redux = NULL;
+	unsigned int address_len;
+	TALLOC_CTX *frame = NULL;
+
+	DBG_DEBUG("CIDR is %s\n", cidr);
+	frame = talloc_stackframe();
+	address = talloc_strdup(frame, cidr);
+	if (address == NULL){
+		goto error;
+	}
+
+	/* there must be a '/' */
+	slash = strchr(address, '/');
+	if (slash == NULL){
+		goto error;
+	}
+	/* terminate the address for strchr, inet_pton */
+	*slash = '\0';
+
+	mask = strtoul(slash + 1, &endptr, 10);
+	if (mask == 0){
+		DBG_INFO("Windows does not like the zero mask, "
+			 "so nor do we: %s\n", cidr);
+		goto error;
+	}
+
+	if (*endptr != '\0' || endptr == slash + 1){
+		DBG_INFO("CIDR mask is not a proper integer: %s\n", cidr);
+		goto error;
+	}
+
+	address_bytes = talloc_size(frame, sizeof(struct in6_addr));
+	if (address_bytes == NULL){
+		goto error;
+	}
+
+	address_redux = talloc_size(frame, INET6_ADDRSTRLEN);
+	if (address_redux == NULL){
+		goto error;
+	}
+
+	DBG_INFO("found address %s, mask %lu\n", address, mask);
+	has_colon = (strchr(address, ':') == NULL) ? false : true;
+	has_dot = (strchr(address, '.') == NULL) ? false : true;
+	if (has_dot && has_colon){
+		/* This seems to be an IPv4 address embedded in IPv6, which is
+		   icky. We don't support it. */
+		DBG_INFO("Refusing to consider cidr '%s' with dots and colons\n",
+			  cidr);
+		goto error;
+	} else if (has_colon){	/* looks like IPv6 */
+		res = inet_pton(AF_INET6, address, address_bytes);
+		if (res != 1) {
+			DBG_INFO("Address in %s fails to parse as IPv6\n", cidr);
+			goto error;
+		}
+		address_len = 128;
+		if (check_address_roundtrip(address, AF_INET6, address_bytes,
+					    address_redux, INET6_ADDRSTRLEN)){
+			goto error;
+		}
+	} else if (has_dot) {
+		/* looks like IPv4 */
+		if (strcmp(address, "0.0.0.0") == 0){
+			DBG_INFO("Windows does not like the zero IPv4 address, "
+				 "so nor do we.\n");
+			goto error;
+		}
+		res = inet_pton(AF_INET, address, address_bytes);
+		if (res != 1) {
+			DBG_INFO("Address in %s fails to parse as IPv4\n", cidr);
+			goto error;
+		}
+		address_len = 32;
+
+		if (check_address_roundtrip(address, AF_INET, address_bytes,
+					    address_redux, INET_ADDRSTRLEN)){
+			goto error;
+		}
+	} else {
+		/* This doesn't look like an IP address at all. */
+		goto error;
+	}
+
+	ret = check_cidr_zero_bits(address_bytes, address_len, mask);
+	talloc_free(frame);
+	return ret;
+  error:
+	talloc_free(frame);
+	return -1;
+}
+
+
+static int samldb_verify_subnet(struct samldb_ctx *ac)
+{
+	struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+	const char *cidr = NULL;
+	const struct ldb_val *rdn_value = NULL;
+
+	rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
+	if (rdn_value == NULL) {
+		ldb_set_errstring(ldb, "samldb: ldb_dn_get_rdn_val "
+				  "failed");
+		return LDB_ERR_UNWILLING_TO_PERFORM;
+	}
+
+	cidr = ldb_dn_escape_value(ac, *rdn_value);
+	DBG_INFO("looking at cidr '%s'\n", cidr);
+	if (cidr == NULL) {
+		ldb_set_errstring(ldb,
+				  "samldb: adding an empty subnet cidr seems wrong");
+		return LDB_ERR_UNWILLING_TO_PERFORM;
+	}
+
+	if (verify_cidr(cidr)){
+		ldb_set_errstring(ldb,
+				  "samldb: subnet value is invalid");
+		return LDB_ERR_INVALID_DN_SYNTAX;
+	}
+
+	return LDB_SUCCESS;
+}
+
 
 /* add */
 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
@@ -2752,6 +3017,17 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req)
 		return samldb_fill_object(ac);
 	}
 
+	if (samdb_find_attribute(ldb, ac->msg,
+				 "objectclass", "subnet") != NULL) {
+		ret = samldb_verify_subnet(ac);
+		if (ret != LDB_SUCCESS) {
+			talloc_free(ac);
+			return ret;
+		}
+		/* We are just checking the value is valid, and there are no
+		   values to fill in. */
+	}
+
 	talloc_free(ac);
 
 	/* nothing matched, go on */
@@ -3099,6 +3375,15 @@ static int check_rename_constraints(struct ldb_message *msg,
 		return LDB_ERR_UNWILLING_TO_PERFORM;
 	}
 
+	/* subnet objects */
+	if (samdb_find_attribute(ldb, msg, "objectclass", "subnet") != NULL) {
+		ret = samldb_verify_subnet(ac);
+		if (ret != LDB_SUCCESS) {
+			talloc_free(ac);
+			return ret;
+		}
+	}
+
 	/* systemFlags */
 
 	dn1 = ldb_dn_get_parent(ac, olddn);
diff --git a/source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c b/source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c
index 2cf262a..52c8aad 100644
--- a/source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c
+++ b/source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c
@@ -126,7 +126,7 @@ static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool do_de
 	item->do_delete = do_delete;
 	talloc_free(res);
 
-	DLIST_ADD_END(data->changed_dns, item, struct dn_list *);
+	DLIST_ADD_END(data->changed_dns, item);
 	return LDB_SUCCESS;
 }
 
diff --git a/source4/dsdb/samdb/ldb_modules/update_keytab.c b/source4/dsdb/samdb/ldb_modules/update_keytab.c
index 42c3fa8..780eb81 100644
--- a/source4/dsdb/samdb/ldb_modules/update_keytab.c
+++ b/source4/dsdb/samdb/ldb_modules/update_keytab.c
@@ -122,7 +122,7 @@ static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool do_de
 	item->do_delete = do_delete;
 	talloc_free(res);
 
-	DLIST_ADD_END(data->changed_dns, item, struct dn_list *);
+	DLIST_ADD_END(data->changed_dns, item);
 	return LDB_SUCCESS;
 }
 
diff --git a/source4/dsdb/samdb/ldb_modules/wscript_build_server b/source4/dsdb/samdb/ldb_modules/wscript_build_server
index b54d27f..8fa9939 100755
--- a/source4/dsdb/samdb/ldb_modules/wscript_build_server
+++ b/source4/dsdb/samdb/ldb_modules/wscript_build_server
@@ -325,7 +325,7 @@ bld.SAMBA_MODULE('ldb_acl',
 	init_function='ldb_acl_module_init',
 	module_init_name='ldb_init_module',
 	internal_module=False,
-	deps='talloc samba-security samdb DSDB_MODULE_HELPERS krb5samba'
+	deps='talloc samba-util samba-security samdb DSDB_MODULE_HELPERS krb5samba'
 	)
 
 
diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h
index 324045a..0a1d90d 100644
--- a/source4/dsdb/samdb/samdb.h
+++ b/source4/dsdb/samdb/samdb.h
@@ -62,6 +62,7 @@ struct dsdb_control_current_partition {
 #define DSDB_REPL_FLAG_PRIORITISE_INCOMING 1
 #define DSDB_REPL_FLAG_PARTIAL_REPLICA     2
 #define DSDB_REPL_FLAG_ADD_NCNAME	   4
+#define DSDB_REPL_FLAG_EXPECT_NO_SECRETS   8
 
 
 #define DSDB_CONTROL_REPLICATED_UPDATE_OID "1.3.6.1.4.1.7165.4.3.3"
diff --git a/source4/dsdb/schema/schema_query.c b/source4/dsdb/schema/schema_query.c
index 013878d..d448cdf 100644
--- a/source4/dsdb/schema/schema_query.c
+++ b/source4/dsdb/schema/schema_query.c
@@ -530,7 +530,7 @@ int dsdb_sort_objectClass_attr(struct ldb_context *ldb,
 
 		/* Don't add top to list, we will do that later */
 		if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
-			DLIST_ADD_END(unsorted, current, struct class_list *);
+			DLIST_ADD_END(unsorted, current);
 		}
 	}
 
@@ -538,7 +538,7 @@ int dsdb_sort_objectClass_attr(struct ldb_context *ldb,
 	/* Add top here, to prevent duplicates */
 	current = talloc(tmp_mem_ctx, struct class_list);
 	current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
-	DLIST_ADD_END(sorted, current, struct class_list *);
+	DLIST_ADD_END(sorted, current);
 
 	/* For each object: find parent chain */
 	for (current = unsorted; current != NULL; current = current->next) {
@@ -554,7 +554,7 @@ int dsdb_sort_objectClass_attr(struct ldb_context *ldb,
 
 		new_parent = talloc(tmp_mem_ctx, struct class_list);
 		new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
-		DLIST_ADD_END(unsorted, new_parent, struct class_list *);
+		DLIST_ADD_END(unsorted, new_parent);
 	}
 
 	/* For each object: order by hierarchy */
@@ -582,7 +582,7 @@ int dsdb_sort_objectClass_attr(struct ldb_context *ldb,
 
 		if (current_lowest != NULL) {
 			DLIST_REMOVE(unsorted,current_lowest);
-			DLIST_ADD_END(sorted,current_lowest, struct class_list *);
+			DLIST_ADD_END(sorted,current_lowest);
 		}
 	}
 
diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c
index f9c50b8..5cf1664 100644
--- a/source4/dsdb/schema/schema_syntax.c
+++ b/source4/dsdb/schema/schema_syntax.c
@@ -2701,7 +2701,8 @@ WERROR dsdb_attribute_drsuapi_to_ldb(struct ldb_context *ldb,
 				     const struct dsdb_schema_prefixmap *pfm_remote,
 				     const struct drsuapi_DsReplicaAttribute *in,
 				     TALLOC_CTX *mem_ctx,
-				     struct ldb_message_element *out)
+				     struct ldb_message_element *out,
+				     enum drsuapi_DsAttributeId *local_attid_as_enum)
 {
 	const struct dsdb_attribute *sa;
 	struct dsdb_syntax_ctx syntax_ctx;
@@ -2737,6 +2738,15 @@ WERROR dsdb_attribute_drsuapi_to_ldb(struct ldb_context *ldb,
 		return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
 	}
 
+	/*
+	 * We return the same class of attid as we were given.  That
+	 * is, we trust the remote server not to use an
+	 * msDS-IntId value in the schema partition
+	 */
+	if (local_attid_as_enum != NULL) {
+		*local_attid_as_enum = (enum drsuapi_DsAttributeId)attid_local;
+	}
+
 	return sa->syntax->drsuapi_to_ldb(&syntax_ctx, sa, in, mem_ctx, out);
 }
 
diff --git a/source4/dsdb/tests/python/acl.py b/source4/dsdb/tests/python/acl.py
index d8e8962..ec042ee 100755
--- a/source4/dsdb/tests/python/acl.py
+++ b/source4/dsdb/tests/python/acl.py
@@ -702,7 +702,7 @@ class AclSearchTests(AclTests):
         res = anonymous.search("", expression="(objectClass=*)", scope=SCOPE_BASE)
         self.assertEquals(len(res), 1)
         #verify some of the attributes
-        #dont care about values
+        #don't care about values
         self.assertTrue("ldapServiceName" in res[0])
         self.assertTrue("namingContexts" in res[0])
         self.assertTrue("isSynchronized" in res[0])
diff --git a/source4/dsdb/tests/python/ldap_schema.py b/source4/dsdb/tests/python/ldap_schema.py
index 1de6519..2d20b48 100755
--- a/source4/dsdb/tests/python/ldap_schema.py
+++ b/source4/dsdb/tests/python/ldap_schema.py
@@ -41,6 +41,8 @@ from ldb import FLAG_MOD_REPLACE
 from samba.samdb import SamDB
 from samba.dsdb import DS_DOMAIN_FUNCTION_2003
 from samba.tests import delete_force
+from samba.ndr import ndr_unpack
+from samba.dcerpc import drsblobs
 
 parser = optparse.OptionParser("ldap_schema.py [options] <host>")
 sambaopts = options.SambaOptions(parser)
@@ -124,10 +126,16 @@ schemaUpdateNow: 1
         # Search for created attribute
         res = []
         res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE,
-                              attrs=["lDAPDisplayName","schemaIDGUID"])
+                              attrs=["lDAPDisplayName","schemaIDGUID", "msDS-IntID"])
         self.assertEquals(len(res), 1)
         self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
         self.assertTrue("schemaIDGUID" in res[0])
+        if "msDS-IntId" in res[0]:
+            msDS_IntId = int(res[0]["msDS-IntId"][0])
+            if msDS_IntId < 0:
+                msDS_IntId += (1 << 32)
+        else:
+            msDS_IntId = None
 
         class_name = "test-Class" + time.strftime("%s", time.gmtime())
         class_ldap_display_name = class_name.replace("-", "")
@@ -211,9 +219,24 @@ name: """ + object_name + """
         self.ldb.add_ldif(ldif)
 
         # Search for created object
-        res = []
-        res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["dn"])
-        self.assertEquals(len(res), 1)
+        obj_res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["replPropertyMetaData"])
+
+        self.assertEquals(len(obj_res), 1)
+        self.assertTrue("replPropertyMetaData" in obj_res[0])
+        val = obj_res[0]["replPropertyMetaData"][0]
+        repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(val))
+        obj = repl.ctr
+
+        # Windows 2000 functional level won't have this.  It is too
+        # hard to work it out from the prefixmap however, so we skip
+        # this test in that case.
+        if msDS_IntId is not None:
+            found = False
+            for o in repl.ctr.array:
+                if o.attid == msDS_IntId:
+                    found = True
+                    break
+            self.assertTrue(found, "Did not find 0x%08x in replPropertyMetaData" % msDS_IntId)
         # Delete the object
         delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn))
 
diff --git a/source4/dsdb/tests/python/sites.py b/source4/dsdb/tests/python/sites.py
index 402d676..acbf1c1 100755
--- a/source4/dsdb/tests/python/sites.py
+++ b/source4/dsdb/tests/python/sites.py
@@ -27,12 +27,14 @@ from samba.tests.subunitrun import TestProgram, SubunitOptions
 
 import samba.getopt as options
 from samba import sites
+from samba import subnets
 from samba.auth import system_session
 from samba.samdb import SamDB
 import samba.tests
 from samba.dcerpc import security
+from ldb import SCOPE_SUBTREE
 
-parser = optparse.OptionParser("dirsync.py [options] <host>")
+parser = optparse.OptionParser(__file__ + " [options] <host>")
 sambaopts = options.SambaOptions(parser)
 parser.add_option_group(sambaopts)
 parser.add_option_group(options.VersionOptions(parser))
@@ -52,11 +54,8 @@ if len(args) < 1:
 host = args[0]
 if not "://" in host:
     ldaphost = "ldap://%s" % host
-    ldapshost = "ldaps://%s" % host
 else:
     ldaphost = host
-    start = host.rindex("://")
-    host = host.lstrip(start+3)
 
 lp = sambaopts.get_loadparm()
 creds = credopts.get_credentials(lp)
@@ -69,10 +68,11 @@ class SitesBaseTests(samba.tests.TestCase):
 
     def setUp(self):
         super(SitesBaseTests, self).setUp()
-        self.ldb_admin = ldb
-        self.base_dn = ldb.domain_dn()
-        self.domain_sid = security.dom_sid(ldb.get_domain_sid())
-        self.configuration_dn = self.ldb_admin.get_config_basedn().get_linearized()
+        self.ldb = SamDB(ldaphost, credentials=creds,
+                         session_info=system_session(lp), lp=lp)
+        self.base_dn = self.ldb.domain_dn()
+        self.domain_sid = security.dom_sid(self.ldb.get_domain_sid())
+        self.configuration_dn = self.ldb.get_config_basedn().get_linearized()
 
     def get_user_dn(self, name):
         return "CN=%s,CN=Users,%s" % (name, self.base_dn)
@@ -81,40 +81,427 @@ class SitesBaseTests(samba.tests.TestCase):
 #tests on sites
 class SimpleSitesTests(SitesBaseTests):
 
-    def test_create(self):
-        """test creation of 1 site"""
+    def test_create_and_delete(self):
+        """test creation and deletion of 1 site"""
 
-        self.ldb_admin.transaction_start()
-        ok = sites.create_site(self.ldb_admin, self.ldb_admin.get_config_basedn(),
-                            "testsamba")
-        self.ldb_admin.transaction_commit()
+        sites.create_site(self.ldb, self.ldb.get_config_basedn(),
+                          "testsamba")
 
         self.assertRaises(sites.SiteAlreadyExistsException,
-                            sites.create_site, self.ldb_admin, self.ldb_admin.get_config_basedn(),
-                            "testsamba")
+                          sites.create_site, self.ldb,
+                          self.ldb.get_config_basedn(),
+                          "testsamba")
 
-    def test_delete(self):
-        """test removal of 1 site"""
-
-        self.ldb_admin.transaction_start()
-        ok = sites.delete_site(self.ldb_admin, self.ldb_admin.get_config_basedn(),
-                            "testsamba")
-
-        self.ldb_admin.transaction_commit()
+        sites.delete_site(self.ldb, self.ldb.get_config_basedn(),
+                          "testsamba")
 
         self.assertRaises(sites.SiteNotFoundException,
-                            sites.delete_site, self.ldb_admin, self.ldb_admin.get_config_basedn(),
-                            "testsamba")
-
+                          sites.delete_site, self.ldb,
+                          self.ldb.get_config_basedn(),
+                          "testsamba")
 
     def test_delete_not_empty(self):
         """test removal of 1 site with servers"""
 
         self.assertRaises(sites.SiteServerNotEmptyException,
-                            sites.delete_site, self.ldb_admin, self.ldb_admin.get_config_basedn(),
-                            "Default-First-Site-Name")
+                          sites.delete_site, self.ldb,
+                          self.ldb.get_config_basedn(),
+                          "Default-First-Site-Name")
+
+
+# tests for subnets
+class SimpleSubnetTests(SitesBaseTests):
+
+    def setUp(self):
+        super(SimpleSubnetTests, self).setUp()
+        self.basedn = self.ldb.get_config_basedn()
+        self.sitename = "testsite"
+        self.sitename2 = "testsite2"
+        self.ldb.transaction_start()
+        sites.create_site(self.ldb, self.basedn, self.sitename)
+        sites.create_site(self.ldb, self.basedn, self.sitename2)
+        self.ldb.transaction_commit()
+
+    def tearDown(self):
+        self.ldb.transaction_start()
+        sites.delete_site(self.ldb, self.basedn, self.sitename)
+        sites.delete_site(self.ldb, self.basedn, self.sitename2)
+        self.ldb.transaction_commit()
+        super(SimpleSubnetTests, self).tearDown()
+
+    def test_create_delete(self):
+        """Create a subnet and delete it again."""
+        basedn = self.ldb.get_config_basedn()
+        cidr = "10.11.12.0/24"
+
+        subnets.create_subnet(self.ldb, basedn, cidr, self.sitename)
+
+        self.assertRaises(subnets.SubnetAlreadyExists,
+                          subnets.create_subnet, self.ldb, basedn, cidr,
+                          self.sitename)
+
+        subnets.delete_subnet(self.ldb, basedn, cidr)
+
+        ret = self.ldb.search(base=basedn, scope=SCOPE_SUBTREE,
+                              expression='(&(objectclass=subnet)(cn=%s))' % cidr)
+
+        self.assertEqual(len(ret), 0, 'Failed to delete subnet %s' % cidr)
+
+    def test_create_shift_delete(self):
+        """Create a subnet, shift it to another site, then delete it."""
+        basedn = self.ldb.get_config_basedn()
+        cidr = "10.11.12.0/24"
+
+        subnets.create_subnet(self.ldb, basedn, cidr, self.sitename)
+
+        subnets.set_subnet_site(self.ldb, basedn, cidr, self.sitename2)
+
+        ret = self.ldb.search(base=basedn, scope=SCOPE_SUBTREE,
+                              expression='(&(objectclass=subnet)(cn=%s))' % cidr)
+
+        sites = ret[0]['siteObject']
+        self.assertEqual(len(sites), 1)
+        self.assertEqual(sites[0],
+                         'CN=testsite2,CN=Sites,%s' % self.ldb.get_config_basedn())
+
+        self.assertRaises(subnets.SubnetAlreadyExists,
+                          subnets.create_subnet, self.ldb, basedn, cidr,
+                          self.sitename)
+
+        subnets.delete_subnet(self.ldb, basedn, cidr)
+
+        ret = self.ldb.search(base=basedn, scope=SCOPE_SUBTREE,
+                              expression='(&(objectclass=subnet)(cn=%s))' % cidr)
+
+        self.assertEqual(len(ret), 0, 'Failed to delete subnet %s' % cidr)
+
+    def test_delete_subnet_that_does_not_exist(self):
+        """Ensure we can't delete a site that isn't there."""
+        basedn = self.ldb.get_config_basedn()
+        cidr = "10.15.0.0/16"
+
+        self.assertRaises(subnets.SubnetNotFound,
+                          subnets.delete_subnet, self.ldb, basedn, cidr)
+
+    def test_create_bad_ranges(self):
+        """These CIDR ranges all have something wrong with them, and they
+        should all fail."""
+        basedn = self.ldb.get_config_basedn()
+
+        cidrs = [
+            # IPv4
+            # insufficient zeros
+            "10.11.12.0/14",
+            "110.0.0.0/6",
+            "1.0.0.0/0",
+            "10.11.13.1/24",
+            "1.2.3.4/29",
+            "10.11.12.0/21",
+            # out of range mask
+            "110.0.0.0/33",
+            "110.0.0.0/-1",
+            "4.0.0.0/111",
+            # out of range address
+            "310.0.0.0/24",
+            "10.0.0.256/32",
+            "1.1.-20.0/24",
+            # badly formed
+            "1.0.0.0/1e",
+            "1.0.0.0/24.0",
+            "1.0.0.0/1/1",
+            "1.0.0.0",
+            "1.c.0.0/24",
+            "1.2.0.0.0/27",
+            "1.23.0/24",
+            "1.23.0.-7/24",
+            "1.-23.0.7/24",
+            "1.23.-0.7/24",
+            "1.23.0.0/0x10",
+            # IPv6 insufficient zeros -- this could be a subtle one
+            # due to the vagaries of endianness in the 16 bit groups.
+            "aaaa:bbbb:cccc:dddd:eeee:ffff:2222:1100/119",
+            "aaaa:bbbb::/31",
+            "a:b::/31",
+            "c000::/1",
+            "a::b00/119",
+            "1::1/127",
+            "1::2/126",
+            "1::100/119",
+            "1::8000/112",
+            # out of range mask
+            "a:b::/130",
+            "a:b::/-1",
+            "::/129",
+            # An IPv4 address can't be exactly the bitmask (MS ADTS)
+            "128.0.0.0/1",
+            "192.0.0.0/2",
+            "255.192.0.0/10",
+            "255.255.255.0/24",
+            "255.255.255.255/32",
+            "0.0.0.0/0",
+            # The address can't have leading zeros (not RFC 4632, but MS ADTS)
+            "00.1.2.0/24",
+            "003.1.2.0/24",
+            "022.1.0.0/16",
+            "00000000000000000000000003.1.2.0/24",
+            "09876::abfc/126",
+            "0aaaa:bbbb::/32",
+            "009876::abfc/126",
+            "000a:bbbb::/32",
+
+            # How about extraneous zeros later on
+            "3.01.2.0/24",
+            "3.1.2.00/24",
+            "22.001.0.0/16",
+            "3.01.02.0/24",
+            "100a:0bbb:0023::/48",
+            "100a::0023/128",
+
+            # Windows doesn't like the zero IPv4 address
+            "0.0.0.0/8",
+            # or the zero mask on IPv6
+            "::/0",
+
+            # various violations of RFC5952
+            "0:0:0:0:0:0:0:0/8",
+            "0::0/0",
+            "::0:0/48",
+            "::0:4/128",
+            "0::/8",
+            "0::4f/128",
+            "0::42:0:0:0:0/64",
+            "4f::0/48",
+
+            # badly formed -- mostly the wrong arrangement of colons
+            "a::b::0/120",
+            "a::abcdf:0/120",
+            "a::g:0/120",
+            "::0::3/48",
+            "2001:3::110::3/118",
+            "aaaa:bbbb:cccc:dddd:eeee:ffff:2222:1111:0000/128",
+            "a:::5:0/120",
+
+            # non-canonical representations (vs RFC 5952)
+            # "2001:0:c633:63::1:0/120"  is correct
+            "2001:0:c633:63:0:0:1:0/120",
+            "2001::c633:63:0:0:1:0/120",
+            "2001:0:c633:63:0:0:1::/120",
+
+            # "10:0:0:42::/64" is correct
+            "10::42:0:0:0:0/64",
+            "10:0:0:42:0:0:0:0/64",
+
+            # "1::4:5:0:0:8/127" is correct
+            "1:0:0:4:5:0:0:8/127",
+            "1:0:0:4:5::8/127",
+
+            # "2001:db8:0:1:1:1:1:1/128" is correct
+            "2001:db8::1:1:1:1:1/128",
+
+            # IP4 embedded - rejected
+            "a::10.0.0.0/120",
+            "a::10.9.8.7/128",
+
+            # The next ones tinker indirectly with IPv4 embedding,
+            # where Windows has some odd behaviour.
+            #
+            # Samba's libreplace inet_ntop6 expects IPv4 embedding
+            # with addresses in these forms:
+            #
+            #     ::wx:yz
+            #     ::FFFF:wx:yz
+            #
+            # these will be stringified with trailing dottted decimal, thus:
+            #
+            #     ::w.x.y.z
+            #     ::ffff:w.x.y.z
+            #
+            # and this will cause the address to be rejected by Samba,
+            # because it uses a inet_pton / inet_ntop round trip to
+            # ascertain correctness.
+
+            "::ffff:0:0/96", #this one fails on WIN2012r2
+            "::ffff:aaaa:a000/120",
+            "::ffff:10:0/120",
+            "::ffff:2:300/120",
+            "::3:0/120",
+            "::2:30/124",
+            "::ffff:2:30/124",
+
+            # completely wrong
+            None,
+            "bob",
+            3.1415,
+            False,
+            "10.11.16.0/24\x00hidden bytes past a zero",
+            self,
+        ]
+
+        failures = []
+        for cidr in cidrs:
+            try:
+                subnets.create_subnet(self.ldb, basedn, cidr, self.sitename)
+            except subnets.SubnetInvalid:
+                print >> sys.stderr, "%s fails properly" % (cidr,)
+                continue
+
+            # we are here because it succeeded when it shouldn't have.
+            print >> sys.stderr, "CIDR %s fails to fail" % (cidr,)
+            failures.append(cidr)
+            subnets.delete_subnet(self.ldb, basedn, cidr)
+
+        if failures:
+            print "These bad subnet names were accepted:"
+            for cidr in failures:
+                print "    %s" % cidr
+            self.fail()
+
+    def test_create_good_ranges(self):
+        """All of these CIDRs are good, and the subnet creation should
+        succeed."""
+        basedn = self.ldb.get_config_basedn()
+
+        cidrs = [
+            # IPv4
+            "10.11.12.0/24",
+            "10.11.12.0/23",
+            "10.11.12.0/25",
+            "110.0.0.0/7",
+            "1.0.0.0/32",
+            "10.11.13.0/32",
+            "10.11.13.1/32",
+            "99.0.97.0/24",
+            "1.2.3.4/30",
+            "10.11.12.0/22",
+            "0.12.13.0/24",
+            # IPv6
+            "aaaa:bbbb:cccc:dddd:eeee:ffff:2222:1100/120",
+            "aaaa:bbbb:cccc:dddd:eeee:ffff:2222:11f0/124",
+            "aaaa:bbbb:cccc:dddd:eeee:ffff:2222:11fc/126",
+            # don't forget upper case
+            "FFFF:FFFF:FFFF:FFFF:ABCD:EfFF:FFFF:FFeF/128",
+            "9876::ab00/120",
+            "9876::abf0/124",
+            "9876::abfc/126",
+            "aaaa:bbbb::/32",
+            "aaaa:bbba::/31",
+            "aaaa:ba00::/23",
+            "aaaa:bb00::/24",
+            "aaaa:bb00::/77",
+            "::/48",
+            "a:b::/32",
+            "c000::/2",
+            "a::b00/120",
+            "1::2/127",
+            # this pattern of address suffix == mask is forbidden with
+            # IPv4 but OK for IPv6.
+            "8000::/1",
+            "c000::/2",
+            "ffff:ffff:ffc0::/42",
+            "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF/128",
+            # leading zeros are forbidden, but implicit IPv6 zeros
+            # (via "::") are OK.
+            "::1000/116",
+            "::8000/113",
+            # taken to the logical conclusion, "::/0" should be OK, but no.
+            "::/48",
+
+            # Try some reserved ranges, which it might be reasonable
+            # to exclude, but which are not excluded in practice.
+            "129.0.0.0/16",
+            "129.255.0.0/16",
+            "100.64.0.0/10",
+            "127.0.0.0/8",
+            "127.0.0.0/24",
+            "169.254.0.0/16",
+            "169.254.1.0/24",
+            "192.0.0.0/24",
+            "192.0.2.0/24",
+            "198.18.0.0/15",
+            "198.51.100.0/24",
+            "203.0.113.0/24",
+            "224.0.0.0/4",
+            "130.129.0.0/16",
+            "130.255.0.0/16",
+            "192.12.0.0/24",
+            "223.255.255.0/24",
+            "240.255.255.0/24",
+            "224.0.0.0/8",
+            "::/96",
+            "100::/64",
+            "2001:10::/28",
+            "fec0::/10",
+            "ff00::/8",
+            "::1/128",
+            "2001:db8::/32",
+            "2001:10::/28",
+            "2002::/24",
+            "2002:a00::/24",
+            "2002:7f00::/24",
+            "2002:a9fe::/32",
+            "2002:ac10::/28",
+            "2002:c000::/40",
+            "2002:c000:200::/40",
+            "2002:c0a8::/32",
+            "2002:c612::/31",
+            "2002:c633:6400::/40",
+            "2002:cb00:7100::/40",
+            "2002:e000::/20",
+            "2002:f000::/20",
+            "2002:ffff:ffff::/48",
+            "2001::/40",
+            "2001:0:a00::/40",
+            "2001:0:7f00::/40",
+            "2001:0:a9fe::/48",
+            "2001:0:ac10::/44",
+            "2001:0:c000::/56",
+            "2001:0:c000:200::/56",
+            "2001:0:c0a8::/48",
+            "2001:0:c612::/47",
+            "2001:0:c633:6400::/56",
+            "2001:0:cb00:7100::/56",
+            "2001:0:e000::/36",
+            "2001:0:f000::/36",
+            "2001:0:ffff:ffff::/64",
+
+            # non-RFC-5952 versions of these are tested in create_bad_ranges
+            "2001:0:c633:63::1:0/120",
+            "10:0:0:42::/64",
+            "1::4:5:0:0:8/127",
+            "2001:db8:0:1:1:1:1:1/128",
+
+            # The "well-known prefix" 64::ff9b is another IPv4
+            # embedding scheme. Let's try that.
+            "64:ff9b::aaaa:aaaa/127",
+            "64:ff9b::/120",
+            "64:ff9b::ffff:2:3/128",
+        ]
+        failures = []
+
+        for cidr in cidrs:
+            try:
+                subnets.create_subnet(self.ldb, basedn, cidr, self.sitename)
+            except subnets.SubnetInvalid, e:
+                print e
+                failures.append(cidr)
+                continue
+
+            ret = self.ldb.search(base=basedn, scope=SCOPE_SUBTREE,
+                                  expression=('(&(objectclass=subnet)(cn=%s))' %
+                                              cidr))
+
+            if len(ret) != 1:
+                print "%s was not created" % cidr
+                failures.append(cidr)
+                continue
+            subnets.delete_subnet(self.ldb, basedn, cidr)
+
+        if failures:
+            print "These good subnet names were not accepted:"
+            for cidr in failures:
+                print "    %s" % cidr
+            self.fail()
 
 
-ldb = SamDB(ldapshost, credentials=creds, session_info=system_session(lp), lp=lp)
 
 TestProgram(module=__name__, opts=subunitopts)
diff --git a/source4/dsdb/wscript_build b/source4/dsdb/wscript_build
index d045a81..28ca845 100755
--- a/source4/dsdb/wscript_build
+++ b/source4/dsdb/wscript_build
@@ -9,7 +9,7 @@ bld.SAMBA_LIBRARY('samdb',
 	public_deps='krb5',
 	public_headers='',
 	vnum='0.0.1',
-	deps='ndr NDR_DRSUAPI NDR_DRSBLOBS auth_system_session LIBCLI_AUTH ndr SAMDB_SCHEMA ldbsamba samdb-common LIBCLI_DRSUAPI cli-ldap-common samba-util com_err authkrb5 samba-credentials ldbwrap errors krb5samba',
+	deps='ndr NDR_DRSUAPI NDR_DRSBLOBS auth_system_session LIBCLI_AUTH ndr SAMDB_SCHEMA ldbsamba samdb-common LIBCLI_DRSUAPI cli-ldap-common samba-util com_err authkrb5 samba-credentials ldbwrap samba-errors krb5samba ldb',
 	)
 
 bld.SAMBA_LIBRARY('samdb-common',
@@ -53,7 +53,7 @@ bld.SAMBA_MODULE('service_dns_update',
 	source='dns/dns_update.c',
 	subsystem='service',
 	init_function='server_service_dnsupdate_init',
-	deps='samdb UTIL_RUNCMD samba-util ldb samdb-common errors talloc auth_system_session samba-hostconfig',
+	deps='samdb UTIL_RUNCMD samba-util ldb samdb-common samba-errors talloc auth_system_session samba-hostconfig',
 	internal_module=False,
 	enabled=bld.AD_DC_BUILD_IS_ENABLED()
 	)
diff --git a/source4/echo_server/echo_server.c b/source4/echo_server/echo_server.c
index 5444bc7..a3e6974 100644
--- a/source4/echo_server/echo_server.c
+++ b/source4/echo_server/echo_server.c
@@ -31,6 +31,7 @@
 #include "libcli/util/ntstatus.h"
 /* tsocket-related functions */
 #include "lib/tsocket/tsocket.h"
+#include "libds/common/roles.h"
 
 NTSTATUS server_service_echo_init(void);
 
@@ -264,7 +265,7 @@ static NTSTATUS echo_startup_interfaces(struct echo_server *echo,
 
 	model_ops = process_model_startup("single");
 	if (model_ops == NULL) {
-		DEBUG(0, ("Can't find 'single' proces model_ops\n"));
+		DEBUG(0, ("Can't find 'single' process model_ops\n"));
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
diff --git a/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c b/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c
index 5a00e12..cfe27ac 100644
--- a/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c
+++ b/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c
@@ -510,13 +510,8 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
 	    return ret;
 	}
 
-	if (authenticator->cksum == NULL) {
-	    krb5_free_authenticator(context, &authenticator);
-	    *minor_status = 0;
-	    return GSS_S_BAD_BINDINGS;
-	}
-
-        if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
+        if (authenticator->cksum != NULL
+	    && authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
             ret = _gsskrb5_verify_8003_checksum(minor_status,
 						input_chan_bindings,
 						authenticator->cksum,
@@ -528,44 +523,48 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
 		return ret;
 	    }
         } else {
-	    krb5_crypto crypto;
-
-	    kret = krb5_crypto_init(context,
-				    ctx->auth_context->keyblock,
-				    0, &crypto);
-	    if(kret) {
+	    if (authenticator->cksum != NULL) {
+		krb5_crypto crypto;
+
+		kret = krb5_crypto_init(context,
+					ctx->auth_context->keyblock,
+					0, &crypto);
+		if(kret) {
+		    krb5_free_authenticator(context, &authenticator);
+
+		    ret = GSS_S_FAILURE;
+		    *minor_status = kret;
+		    return ret;
+		}
+
+		/*
+		 * Windows accepts Samba3's use of a kerberos, rather than
+		 * GSSAPI checksum here
+		 */
+
+		kret = krb5_verify_checksum(context,
+					    crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
+					    authenticator->cksum);
 		krb5_free_authenticator(context, &authenticator);
+		krb5_crypto_destroy(context, crypto);
 
-		ret = GSS_S_FAILURE;
-		*minor_status = kret;
-		return ret;
+		if(kret) {
+		    ret = GSS_S_BAD_SIG;
+		    *minor_status = kret;
+		    return ret;
+		}
 	    }
 
 	    /*
-	     * Windows accepts Samba3's use of a kerberos, rather than
-	     * GSSAPI checksum here
+	     * If there is no checksum or a kerberos checksum (which Windows
+	     * and Samba accept), we use the ap_options to guess the mutual
+	     * flag.
 	     */
 
-	    kret = krb5_verify_checksum(context,
-					crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
-					authenticator->cksum);
-	    krb5_free_authenticator(context, &authenticator);
-	    krb5_crypto_destroy(context, crypto);
-
-	    if(kret) {
-		ret = GSS_S_BAD_SIG;
-		*minor_status = kret;
-		return ret;
-	    }
-
-	    /*
-	     * Samba style get some flags (but not DCE-STYLE), use
-	     * ap_options to guess the mutual flag.
-	     */
- 	    ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
+	    ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
 	    if (ap_options & AP_OPTS_MUTUAL_REQUIRED)
 		ctx->flags |= GSS_C_MUTUAL_FLAG;
-        }
+	}
     }
 
     if(ctx->flags & GSS_C_MUTUAL_FLAG) {
diff --git a/source4/heimdal/lib/roken/resolve.c b/source4/heimdal/lib/roken/resolve.c
index b27f37a..0cfe0b0 100644
--- a/source4/heimdal/lib/roken/resolve.c
+++ b/source4/heimdal/lib/roken/resolve.c
@@ -588,6 +588,7 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type)
 
     len = min(len, size);
     r = parse_reply(reply, len);
+    resolve_free_handle(handle);
     free(reply);
     return r;
 }
diff --git a/source4/heimdal_build/wscript_build b/source4/heimdal_build/wscript_build
index 4f1d895..c733b8f 100644
--- a/source4/heimdal_build/wscript_build
+++ b/source4/heimdal_build/wscript_build
@@ -69,7 +69,7 @@ def HEIMDAL_ASN1(name, source,
 
     t = bld(rule=asn1_rule,
             ext_out = '.x',
-            before = 'cc',
+            before = 'c',
             update_outputs = True,
             shell = True,
             source = source,
@@ -123,7 +123,7 @@ def HEIMDAL_ASN1(name, source,
     includes = to_list(includes)
     includes.append(os.path.dirname(out_files[0]))
 
-    t = bld(features       = 'cc',
+    t = bld(features       = 'c',
             source         = cfile,
             target         = name,
             samba_cflags   = CURRENT_CFLAGS(bld, name, ''),
@@ -241,7 +241,7 @@ def HEIMDAL_LIBRARY(libname, source, deps, vnum, version_script, includes=''):
         bundled_name = libname
     version = "%s_%s" % (Utils.g_module.APPNAME, Utils.g_module.VERSION)
 
-    features = 'cc cshlib symlink_lib install_lib'
+    features = 'c cshlib symlink_lib install_lib'
 
     bld.set_group('main')
     t = bld(
@@ -277,7 +277,7 @@ def HEIMDAL_SUBSYSTEM(modname, source,
     bld.set_group(group)
 
     return bld(
-        features       = 'cc',
+        features       = 'c',
         source         = source,
         target         = modname,
         samba_cflags   = CURRENT_CFLAGS(bld, modname, cflags, allow_warnings=True),
@@ -306,7 +306,7 @@ def HEIMDAL_BINARY(binname, source,
     if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
         return
 
-    features = 'cc cprogram symlink_bin install_bin'
+    features = 'c cprogram symlink_bin install_bin'
 
     obj_target = binname + '.objlist'
 
diff --git a/source4/heimdal_build/wscript_configure b/source4/heimdal_build/wscript_configure
index 2635b8a..79b461c 100755
--- a/source4/heimdal_build/wscript_configure
+++ b/source4/heimdal_build/wscript_configure
@@ -187,9 +187,6 @@ if krb5_config:
     finally:
         f.close()
 
-if conf.CHECK_BUNDLED_SYSTEM('com_err', checkfunctions='com_right_r com_err', headers='com_err.h'):
-    conf.define('USING_SYSTEM_COM_ERR', 1)
-
 def check_system_heimdal_lib(name, functions='', headers='', onlyif=None):
     # Only use system library if the user requested the bundled one not be
     # used.
@@ -197,8 +194,9 @@ def check_system_heimdal_lib(name, functions='', headers='', onlyif=None):
         return False
     setattr(conf.env, "CPPPATH_%s" % name.upper(), heimdal_includedirs)
     setattr(conf.env, "LIBPATH_%s" % name.upper(), heimdal_libdirs)
-    conf.CHECK_BUNDLED_SYSTEM(name, checkfunctions=functions, headers=headers,
-        onlyif=onlyif)
+    if not conf.CHECK_BUNDLED_SYSTEM(name, checkfunctions=functions, headers=headers,
+                                     onlyif=onlyif):
+        return False
     conf.define('USING_SYSTEM_%s' % name.upper(), 1)
     return True
 
@@ -210,6 +208,8 @@ def check_system_heimdal_binary(name):
     conf.define('USING_SYSTEM_%s' % name.upper(), 1)
     return True
 
+check_system_heimdal_lib("com_err", "com_right_r com_err", "com_err.h")
+
 if check_system_heimdal_lib("roken", "rk_socket_set_reuseaddr", "roken.h"):
     conf.env.CPPPATH_ROKEN_HOSTCC = conf.env.CPPPATH_ROKEN
     conf.env.LIBPATH_ROKEN_HOSTCC = conf.env.LIBPATH_ROKEN
diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index 8da0da0..af9fa26 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -32,7 +32,7 @@
 #include "../lib/crypto/md4.h"
 #include "system/kerberos.h"
 #include "auth/kerberos/kerberos.h"
-#include <hdb.h>
+#include "kdc/sdb.h"
 #include "kdc/samba_kdc.h"
 #include "kdc/db-glue.h"
 
@@ -84,9 +84,9 @@ static time_t ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const cha
     return timegm(&tm);
 }
 
-static HDBFlags uf2HDBFlags(krb5_context context, uint32_t userAccountControl, enum samba_kdc_ent_type ent_type)
+static struct SDBFlags uf2SDBFlags(krb5_context context, uint32_t userAccountControl, enum samba_kdc_ent_type ent_type)
 {
-	HDBFlags flags = int2HDBFlags(0);
+	struct SDBFlags flags = int2SDBFlags(0);
 
 	/* we don't allow kadmin deletes */
 	flags.immutable = 1;
@@ -189,25 +189,13 @@ static HDBFlags uf2HDBFlags(krb5_context context, uint32_t userAccountControl, e
 static int samba_kdc_entry_destructor(struct samba_kdc_entry *p)
 {
 	if (p->entry_ex != NULL) {
-		hdb_entry_ex *entry_ex = p->entry_ex;
-		free_hdb_entry(&entry_ex->entry);
+		struct sdb_entry_ex *entry_ex = p->entry_ex;
+		free_sdb_entry(&entry_ex->entry);
 	}
 
 	return 0;
 }
 
-static void samba_kdc_free_entry(krb5_context context, hdb_entry_ex *entry_ex)
-{
-	/* this function is called only from hdb_free_entry().
-	 * Make sure we neutralize the destructor or we will
-	 * get a double free later when hdb_free_entry() will
-	 * try to call free_hdb_entry() */
-	talloc_set_destructor(entry_ex->ctx, NULL);
-
-	/* now proceed to free the talloc part */
-	talloc_free(entry_ex->ctx);
-}
-
 static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 						    struct samba_kdc_db_context *kdc_db_ctx,
 						    TALLOC_CTX *mem_ctx,
@@ -216,7 +204,7 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 						    bool is_rodc,
 						    uint32_t userAccountControl,
 						    enum samba_kdc_ent_type ent_type,
-						    hdb_entry_ex *entry_ex)
+						    struct sdb_entry_ex *entry_ex)
 {
 	krb5_error_code ret = 0;
 	enum ndr_err_code ndr_err;
@@ -377,7 +365,7 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 		if (kdc_db_ctx->rodc) {
 			/* We are on an RODC, but don't have keys for this account.  Signal this to the caller */
 			/* TODO:  We need to call a generalised version of auth_sam_trigger_repl_secret from here */
-			return HDB_ERR_NOT_FOUND_HERE;
+			return SDB_ERR_NOT_FOUND_HERE;
 		}
 
 		/* oh, no password.  Apparently (comment in
@@ -388,17 +376,14 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 
 	/* allocate space to decode into */
 	entry_ex->entry.keys.len = 0;
-	entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(Key));
+	entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(struct sdb_key));
 	if (entry_ex->entry.keys.val == NULL) {
 		ret = ENOMEM;
 		goto out;
 	}
 
 	if (hash && (supported_enctypes & ENC_RC4_HMAC_MD5)) {
-		Key key;
-
-		key.mkvno = 0;
-		key.salt = NULL; /* No salt for this enc type */
+		struct sdb_key key = {};
 
 		ret = smb_krb5_keyblock_init_contents(context,
 						      ENCTYPE_ARCFOUR_HMAC,
@@ -415,7 +400,7 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 
 	if (pkb4) {
 		for (i=0; i < pkb4->num_keys; i++) {
-			Key key;
+			struct sdb_key key = {};
 
 			if (!pkb4->keys[i].value) continue;
 
@@ -423,9 +408,6 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 				continue;
 			}
 
-			key.mkvno = 0;
-			key.salt = NULL;
-
 			if (pkb4->salt.string) {
 				DATA_BLOB salt;
 
@@ -464,7 +446,7 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 			}
 			if (ret) {
 				if (key.salt) {
-					free_Salt(key.salt);
+					kerberos_free_data_contents(context, &key.salt->salt);
 					free(key.salt);
 					key.salt = NULL;
 				}
@@ -476,7 +458,7 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 		}
 	} else if (pkb3) {
 		for (i=0; i < pkb3->num_keys; i++) {
-			Key key;
+			struct sdb_key key = {};
 
 			if (!pkb3->keys[i].value) continue;
 
@@ -484,9 +466,6 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 				continue;
 			}
 
-			key.mkvno = 0;
-			key.salt = NULL;
-
 			if (pkb3->salt.string) {
 				DATA_BLOB salt;
 
@@ -517,7 +496,7 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 							      &key.key);
 			if (ret) {
 				if (key.salt) {
-					free_Salt(key.salt);
+					kerberos_free_data_contents(context, &key.salt->salt);
 					free(key.salt);
 					key.salt = NULL;
 				}
@@ -605,7 +584,7 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 					       unsigned flags,
 					       struct ldb_dn *realm_dn,
 					       struct ldb_message *msg,
-					       hdb_entry_ex *entry_ex)
+					       struct sdb_entry_ex *entry_ex)
 {
 	struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
 	uint32_t userAccountControl;
@@ -651,7 +630,6 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 	}
 
 	p->kdc_db_ctx = kdc_db_ctx;
-	p->entry_ex = entry_ex;
 	p->realm_dn = talloc_reference(p, realm_dn);
 	if (!p->realm_dn) {
 		ret = ENOMEM;
@@ -660,11 +638,7 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 
 	talloc_set_destructor(p, samba_kdc_entry_destructor);
 
-	/* make sure we do not have bogus data in there */
-	memset(&entry_ex->entry, 0, sizeof(hdb_entry));
-
 	entry_ex->ctx = p;
-	entry_ex->free_entry = samba_kdc_free_entry;
 
 	userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
 
@@ -701,7 +675,7 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 	 */
 
 	if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
-		if (flags & (HDB_F_CANON)) {
+		if (flags & (SDB_F_CANON)) {
 			/*
 			 * When requested to do so, ensure that the
 			 * both realm values in the principal are set
@@ -738,9 +712,9 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 			krb5_clear_error_message(context);
 			goto out;
 		}
-	} else if (flags & HDB_F_CANON && flags & HDB_F_FOR_AS_REQ) {
+	} else if (flags & SDB_F_CANON && flags & SDB_F_FOR_AS_REQ) {
 		/*
-		 * HDB_F_CANON maps from the canonicalize flag in the
+		 * SDB_F_CANON maps from the canonicalize flag in the
 		 * packet, and has a different meaning between AS-REQ
 		 * and TGS-REQ.  We only change the principal in the AS-REQ case
 		 */
@@ -773,7 +747,7 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 	}
 
 	/* First try and figure out the flags based on the userAccountControl */
-	entry_ex->entry.flags = uf2HDBFlags(context, userAccountControl, ent_type);
+	entry_ex->entry.flags = uf2SDBFlags(context, userAccountControl, ent_type);
 
 	/* Windows 2008 seems to enforce this (very sensible) rule by
 	 * default - don't allow offline attacks on a user's password
@@ -794,11 +768,11 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 	 * KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
 	 */
 	if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER && entry_ex->entry.flags.server == 0) {
-		ret = HDB_ERR_NOENTRY;
+		ret = SDB_ERR_NOENTRY;
 		krb5_set_error_message(context, ret, "samba_kdc_message2entry: no servicePrincipalName present for this server, refusing with no-such-entry");
 		goto out;
 	}
-	if (flags & HDB_F_ADMIN_DATA) {
+	if (flags & SDB_F_ADMIN_DATA) {
 		/* These (created_by, modified_by) parts of the entry are not relevant for Samba4's use
 		 * of the Heimdal KDC.  They are stored in a the traditional
 		 * DB for audit purposes, and still form part of the structure
@@ -816,7 +790,7 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 			goto out;
 		}
 
-		entry_ex->entry.modified_by = (Event *) malloc(sizeof(Event));
+		entry_ex->entry.modified_by = (struct sdb_event *) malloc(sizeof(struct sdb_event));
 		if (entry_ex->entry.modified_by == NULL) {
 			ret = ENOMEM;
 			krb5_set_error_message(context, ret, "malloc: out of memory");
@@ -989,7 +963,7 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 out:
 	if (ret != 0) {
 		/* This doesn't free ent itself, that is for the eventual caller to do */
-		hdb_free_entry(context, entry_ex);
+		sdb_free_entry(entry_ex);
 		ZERO_STRUCTP(entry_ex);
 	} else {
 		talloc_steal(kdc_db_ctx, entry_ex->ctx);
@@ -1010,7 +984,7 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 					       unsigned flags,
 					       uint32_t kvno,
 					       struct ldb_message *msg,
-					       hdb_entry_ex *entry_ex)
+					       struct sdb_entry_ex *entry_ex)
 {
 	struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
 	const char *our_realm = lpcfg_realm(lp_ctx);
@@ -1048,14 +1022,14 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 	trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
 	if (!(trust_direction_flags & direction)) {
 		krb5_clear_error_message(context);
-		ret = HDB_ERR_NOENTRY;
+		ret = SDB_ERR_NOENTRY;
 		goto out;
 	}
 
 	dnsdomain = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
 	if (dnsdomain == NULL) {
 		krb5_clear_error_message(context);
-		ret = HDB_ERR_NOENTRY;
+		ret = SDB_ERR_NOENTRY;
 		goto out;
 	}
 	partner_realm = strupper_talloc(mem_ctx, dnsdomain);
@@ -1079,7 +1053,7 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 
 	if (password_val == NULL) {
 		krb5_clear_error_message(context);
-		ret = HDB_ERR_NOENTRY;
+		ret = SDB_ERR_NOENTRY;
 		goto out;
 	}
 
@@ -1098,16 +1072,14 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 	}
 
 	p->kdc_db_ctx = kdc_db_ctx;
-	p->entry_ex = entry_ex;
 	p->realm_dn = realm_dn;
 
 	talloc_set_destructor(p, samba_kdc_entry_destructor);
 
 	/* make sure we do not have bogus data in there */
-	memset(&entry_ex->entry, 0, sizeof(hdb_entry));
+	memset(&entry_ex->entry, 0, sizeof(struct sdb_entry));
 
 	entry_ex->ctx = p;
-	entry_ex->free_entry = samba_kdc_free_entry;
 
 	/* use 'whenCreated' */
 	entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
@@ -1185,7 +1157,7 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 	if (password_blob.previous.count == 0) {
 		/* there is no previous password */
 		use_previous = false;
-	} else if (!(flags & HDB_F_KVNO_SPECIFIED)) {
+	} else if (!(flags & SDB_F_KVNO_SPECIFIED)) {
 		/*
 		 * If not specified we use the lowest kvno
 		 * for the first hour after an update.
@@ -1223,7 +1195,7 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 	}
 
 	/* use the kvno the client specified, if available */
-	if (flags & HDB_F_KVNO_SPECIFIED) {
+	if (flags & SDB_F_KVNO_SPECIFIED) {
 		entry_ex->entry.kvno = kvno;
 	} else {
 		entry_ex->entry.kvno = *auth_kvno;
@@ -1282,11 +1254,11 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 	if (num_keys == 0) {
 		DEBUG(1,(__location__ ": no usable key found\n"));
 		krb5_clear_error_message(context);
-		ret = HDB_ERR_NOENTRY;
+		ret = SDB_ERR_NOENTRY;
 		goto out;
 	}
 
-	entry_ex->entry.keys.val = calloc(num_keys, sizeof(Key));
+	entry_ex->entry.keys.val = calloc(num_keys, sizeof(struct sdb_key));
 	if (entry_ex->entry.keys.val == NULL) {
 		krb5_clear_error_message(context);
 		ret = ENOMEM;
@@ -1294,7 +1266,7 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 	}
 
 	if (password_utf8.length != 0) {
-		Key key = {};
+		struct sdb_key key = {};
 		krb5_const_principal salt_principal = entry_ex->entry.principal;
 		krb5_data salt;
 		krb5_data cleartext_data;
@@ -1345,7 +1317,7 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 	}
 
 	if (password_hash != NULL) {
-		Key key = {};
+		struct sdb_key key = {};
 
 		ret = smb_krb5_keyblock_init_contents(context,
 						      ENCTYPE_ARCFOUR_HMAC,
@@ -1360,7 +1332,7 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
 		entry_ex->entry.keys.len++;
 	}
 
-	entry_ex->entry.flags = int2HDBFlags(0);
+	entry_ex->entry.flags = int2SDBFlags(0);
 	entry_ex->entry.flags.immutable = 1;
 	entry_ex->entry.flags.invalid = 0;
 	entry_ex->entry.flags.server = 1;
@@ -1396,7 +1368,7 @@ out:
 
 	if (ret != 0) {
 		/* This doesn't free ent itself, that is for the eventual caller to do */
-		hdb_free_entry(context, entry_ex);
+		sdb_free_entry(entry_ex);
 	} else {
 		talloc_steal(kdc_db_ctx, entry_ex->ctx);
 	}
@@ -1419,7 +1391,7 @@ static krb5_error_code samba_kdc_lookup_trust(krb5_context context, struct ldb_c
 	if (NT_STATUS_IS_OK(status)) {
 		return 0;
 	} else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-		return HDB_ERR_NOENTRY;
+		return SDB_ERR_NOENTRY;
 	} else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
 		int ret = ENOMEM;
 		krb5_set_error_message(context, ret, "get_sam_result_trust: out of memory");
@@ -1555,7 +1527,7 @@ static krb5_error_code samba_kdc_lookup_client(krb5_context context,
 	TALLOC_FREE(principal_string);
 
 	if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
-		return HDB_ERR_NOENTRY;
+		return SDB_ERR_NOENTRY;
 	} else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
 		return ENOMEM;
 	} else if (!NT_STATUS_IS_OK(nt_status)) {
@@ -1570,7 +1542,7 @@ static krb5_error_code samba_kdc_fetch_client(krb5_context context,
 					       TALLOC_CTX *mem_ctx,
 					       krb5_const_principal principal,
 					       unsigned flags,
-					       hdb_entry_ex *entry_ex) {
+					       struct sdb_entry_ex *entry_ex) {
 	struct ldb_dn *realm_dn;
 	krb5_error_code ret;
 	struct ldb_message *msg = NULL;
@@ -1595,7 +1567,7 @@ static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
 					      krb5_const_principal principal,
 					      unsigned flags,
 					      uint32_t kvno,
-					      hdb_entry_ex *entry_ex)
+					      struct sdb_entry_ex *entry_ex)
 {
 	struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
 	krb5_error_code ret;
@@ -1607,18 +1579,18 @@ static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
 	realm_from_princ_malloc = smb_krb5_principal_get_realm(context, principal);
 	if (realm_from_princ_malloc == NULL) {
 		/* can't happen */
-		return HDB_ERR_NOENTRY;
+		return SDB_ERR_NOENTRY;
 	}
 	realm_from_princ = talloc_strdup(mem_ctx, realm_from_princ_malloc);
 	free(realm_from_princ_malloc);
 	if (realm_from_princ == NULL) {
-		return HDB_ERR_NOENTRY;
+		return SDB_ERR_NOENTRY;
 	}
 
 	if (krb5_princ_size(context, principal) != 2
 	    || (principal_comp_strcmp(context, principal, 0, KRB5_TGS_NAME) != 0)) {
 		/* Not a krbtgt */
-		return HDB_ERR_NOENTRY;
+		return SDB_ERR_NOENTRY;
 	}
 
 	/* krbtgt case.  Either us or a trusted realm */
@@ -1635,11 +1607,11 @@ static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
 		/* w2k8r2 sometimes gives us a kvno of 255 for inter-domain
 		   trust tickets. We don't yet know what this means, but we do
 		   seem to need to treat it as unspecified */
-		if (flags & HDB_F_KVNO_SPECIFIED) {
+		if (flags & SDB_F_KVNO_SPECIFIED) {
 			krbtgt_number = SAMBA_KVNO_GET_KRBTGT(kvno);
 			if (kdc_db_ctx->rodc) {
 				if (krbtgt_number != kdc_db_ctx->my_krbtgt_number) {
-					return HDB_ERR_NOT_FOUND_HERE;
+					return SDB_ERR_NOT_FOUND_HERE;
 				}
 			}
 		} else {
@@ -1665,17 +1637,17 @@ static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
 		if (lret == LDB_ERR_NO_SUCH_OBJECT) {
 			krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
 				   (unsigned)(krbtgt_number));
-			krb5_set_error_message(context, HDB_ERR_NOENTRY,
+			krb5_set_error_message(context, SDB_ERR_NOENTRY,
 					       "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
 					       (unsigned)(krbtgt_number));
-			return HDB_ERR_NOENTRY;
+			return SDB_ERR_NOENTRY;
 		} else if (lret != LDB_SUCCESS) {
 			krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
 				   (unsigned)(krbtgt_number));
-			krb5_set_error_message(context, HDB_ERR_NOENTRY,
+			krb5_set_error_message(context, SDB_ERR_NOENTRY,
 					       "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
 					       (unsigned)(krbtgt_number));
-			return HDB_ERR_NOENTRY;
+			return SDB_ERR_NOENTRY;
 		}
 
 		ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
@@ -1704,10 +1676,10 @@ static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
 			krb5_warnx(context, "samba_kdc_fetch: not our realm for trusts ('%s', '%s')",
 				   realm_from_princ,
 				   realm_princ_comp);
-			krb5_set_error_message(context, HDB_ERR_NOENTRY, "samba_kdc_fetch: not our realm for trusts ('%s', '%s')",
+			krb5_set_error_message(context, SDB_ERR_NOENTRY, "samba_kdc_fetch: not our realm for trusts ('%s', '%s')",
 					       realm_from_princ,
 					       realm_princ_comp);
-			return HDB_ERR_NOENTRY;
+			return SDB_ERR_NOENTRY;
 		}
 
 		/* Trusted domains are under CN=system */
@@ -1771,7 +1743,7 @@ static krb5_error_code samba_kdc_lookup_server(krb5_context context,
 		free(principal_string);
 
 		if (!NT_STATUS_IS_OK(nt_status)) {
-			return HDB_ERR_NOENTRY;
+			return SDB_ERR_NOENTRY;
 		}
 
 		ldb_ret = dsdb_search_one(kdc_db_ctx->samdb,
@@ -1781,10 +1753,10 @@ static krb5_error_code samba_kdc_lookup_server(krb5_context context,
 					  DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
 					  "(objectClass=*)");
 		if (ldb_ret != LDB_SUCCESS) {
-			return HDB_ERR_NOENTRY;
+			return SDB_ERR_NOENTRY;
 		}
 		return 0;
-	} else if (!(flags & HDB_F_FOR_AS_REQ)
+	} else if (!(flags & SDB_F_FOR_AS_REQ)
 		   && smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
 		/*
 		 * The behaviour of accepting an
@@ -1888,21 +1860,21 @@ static krb5_error_code samba_kdc_lookup_server(krb5_context context,
 		if (lret == LDB_ERR_NO_SUCH_OBJECT) {
 			DEBUG(10, ("Failed to find an entry for %s filter:%s\n",
 				  name1, filter));
-			return HDB_ERR_NOENTRY;
+			return SDB_ERR_NOENTRY;
 		}
 		if (lret == LDB_ERR_CONSTRAINT_VIOLATION) {
 			DEBUG(10, ("Failed to find unique entry for %s filter:%s\n",
 				  name1, filter));
-			return HDB_ERR_NOENTRY;
+			return SDB_ERR_NOENTRY;
 		}
 		if (lret != LDB_SUCCESS) {
 			DEBUG(0, ("Failed single search for %s - %s\n",
 				  name1, ldb_errstring(kdc_db_ctx->samdb)));
-			return HDB_ERR_NOENTRY;
+			return SDB_ERR_NOENTRY;
 		}
 		return 0;
 	}
-	return HDB_ERR_NOENTRY;
+	return SDB_ERR_NOENTRY;
 }
 
 
@@ -1912,7 +1884,7 @@ static krb5_error_code samba_kdc_fetch_server(krb5_context context,
 					      TALLOC_CTX *mem_ctx,
 					      krb5_const_principal principal,
 					      unsigned flags,
-					      hdb_entry_ex *entry_ex)
+					      struct sdb_entry_ex *entry_ex)
 {
 	krb5_error_code ret;
 	struct ldb_dn *realm_dn;
@@ -1940,7 +1912,7 @@ static krb5_error_code samba_kdc_lookup_realm(krb5_context context,
 					      TALLOC_CTX *mem_ctx,
 					      krb5_const_principal principal,
 					      unsigned flags,
-					      hdb_entry_ex *entry_ex)
+					      struct sdb_entry_ex *entry_ex)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -1956,13 +1928,13 @@ static krb5_error_code samba_kdc_lookup_realm(krb5_context context,
 
 	num_comp = krb5_princ_size(context, principal);
 
-	if (flags & HDB_F_GET_CLIENT) {
-		if (flags & HDB_F_FOR_AS_REQ) {
+	if (flags & SDB_F_GET_CLIENT) {
+		if (flags & SDB_F_FOR_AS_REQ) {
 			check_realm = true;
 		}
 	}
-	if (flags & HDB_F_GET_SERVER) {
-		if (flags & HDB_F_FOR_TGS_REQ) {
+	if (flags & SDB_F_GET_SERVER) {
+		if (flags & SDB_F_FOR_TGS_REQ) {
 			check_realm = true;
 		}
 	}
@@ -1988,7 +1960,7 @@ static krb5_error_code samba_kdc_lookup_realm(krb5_context context,
 		 */
 		SAFE_FREE(_realm);
 		TALLOC_FREE(frame);
-		return HDB_ERR_NOENTRY;
+		return SDB_ERR_NOENTRY;
 	}
 
 	realm = talloc_strdup(frame, _realm);
@@ -1998,14 +1970,14 @@ static krb5_error_code samba_kdc_lookup_realm(krb5_context context,
 		return ENOMEM;
 	}
 
-	if (krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
+	if (smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
 		char *principal_string = NULL;
 		krb5_principal enterprise_principal = NULL;
 		char *enterprise_realm = NULL;
 
 		if (num_comp != 1) {
 			TALLOC_FREE(frame);
-			return HDB_ERR_NOENTRY;
+			return SDB_ERR_NOENTRY;
 		}
 
 		principal_string = smb_krb5_principal_get_comp_string(frame, context,
@@ -2036,7 +2008,7 @@ static krb5_error_code samba_kdc_lookup_realm(krb5_context context,
 		}
 	}
 
-	if (flags & HDB_F_GET_SERVER) {
+	if (flags & SDB_F_GET_SERVER) {
 		char *service_realm = NULL;
 
 		ret = principal_comp_strcmp(context, principal, 0, KRB5_TGS_NAME);
@@ -2132,16 +2104,16 @@ static krb5_error_code samba_kdc_lookup_realm(krb5_context context,
 		return ENOMEM;
 	}
 
-	ret = krb5_principal_set_realm(context,
-				       entry_ex->entry.principal,
-				       upper);
+	ret = smb_krb5_principal_set_realm(context,
+					   entry_ex->entry.principal,
+					   upper);
 	if (ret) {
 		TALLOC_FREE(frame);
 		return ret;
 	}
 
 	TALLOC_FREE(frame);
-	return HDB_ERR_WRONG_REALM;
+	return SDB_ERR_WRONG_REALM;
 }
 
 krb5_error_code samba_kdc_fetch(krb5_context context,
@@ -2149,9 +2121,9 @@ krb5_error_code samba_kdc_fetch(krb5_context context,
 				krb5_const_principal principal,
 				unsigned flags,
 				krb5_kvno kvno,
-				hdb_entry_ex *entry_ex)
+				struct sdb_entry_ex *entry_ex)
 {
-	krb5_error_code ret = HDB_ERR_NOENTRY;
+	krb5_error_code ret = SDB_ERR_NOENTRY;
 	TALLOC_CTX *mem_ctx;
 
 	mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
@@ -2167,24 +2139,24 @@ krb5_error_code samba_kdc_fetch(krb5_context context,
 		goto done;
 	}
 
-	ret = HDB_ERR_NOENTRY;
+	ret = SDB_ERR_NOENTRY;
 
-	if (flags & HDB_F_GET_CLIENT) {
+	if (flags & SDB_F_GET_CLIENT) {
 		ret = samba_kdc_fetch_client(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
-		if (ret != HDB_ERR_NOENTRY) goto done;
+		if (ret != SDB_ERR_NOENTRY) goto done;
 	}
-	if (flags & HDB_F_GET_SERVER) {
+	if (flags & SDB_F_GET_SERVER) {
 		/* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
 		ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry_ex);
-		if (ret != HDB_ERR_NOENTRY) goto done;
+		if (ret != SDB_ERR_NOENTRY) goto done;
 
 		/* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
 		ret = samba_kdc_fetch_server(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
-		if (ret != HDB_ERR_NOENTRY) goto done;
+		if (ret != SDB_ERR_NOENTRY) goto done;
 	}
-	if (flags & HDB_F_GET_KRBTGT) {
+	if (flags & SDB_F_GET_KRBTGT) {
 		ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry_ex);
-		if (ret != HDB_ERR_NOENTRY) goto done;
+		if (ret != SDB_ERR_NOENTRY) goto done;
 	}
 
 done:
@@ -2201,7 +2173,7 @@ struct samba_kdc_seq {
 
 static krb5_error_code samba_kdc_seq(krb5_context context,
 				     struct samba_kdc_db_context *kdc_db_ctx,
-				     hdb_entry_ex *entry)
+				     struct sdb_entry_ex *entry)
 {
 	krb5_error_code ret;
 	struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
@@ -2212,7 +2184,7 @@ static krb5_error_code samba_kdc_seq(krb5_context context,
 	TALLOC_CTX *mem_ctx;
 
 	if (!priv) {
-		return HDB_ERR_NOENTRY;
+		return SDB_ERR_NOENTRY;
 	}
 
 	mem_ctx = talloc_named(priv, 0, "samba_kdc_seq context");
@@ -2233,7 +2205,7 @@ static krb5_error_code samba_kdc_seq(krb5_context context,
 	}
 
 	if (sAMAccountName == NULL) {
-		ret = HDB_ERR_NOENTRY;
+		ret = SDB_ERR_NOENTRY;
 		goto out;
 	}
 
@@ -2245,7 +2217,7 @@ static krb5_error_code samba_kdc_seq(krb5_context context,
 
 	ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
 				      principal, SAMBA_KDC_ENT_TYPE_ANY,
-				      HDB_F_ADMIN_DATA|HDB_F_GET_ANY,
+				      SDB_F_ADMIN_DATA|SDB_F_GET_ANY,
 				      priv->realm_dn, msg, entry);
 
 out:
@@ -2265,7 +2237,7 @@ out:
 
 krb5_error_code samba_kdc_firstkey(krb5_context context,
 				   struct samba_kdc_db_context *kdc_db_ctx,
-				   hdb_entry_ex *entry)
+				   struct sdb_entry_ex *entry)
 {
 	struct ldb_context *ldb_ctx = kdc_db_ctx->samdb;
 	struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
@@ -2314,7 +2286,7 @@ krb5_error_code samba_kdc_firstkey(krb5_context context,
 
 	if (lret != LDB_SUCCESS) {
 		TALLOC_FREE(priv);
-		return HDB_ERR_NOENTRY;
+		return SDB_ERR_NOENTRY;
 	}
 
 	priv->count = res->count;
@@ -2336,7 +2308,7 @@ krb5_error_code samba_kdc_firstkey(krb5_context context,
 
 krb5_error_code samba_kdc_nextkey(krb5_context context,
 				  struct samba_kdc_db_context *kdc_db_ctx,
-				  hdb_entry_ex *entry)
+				  struct sdb_entry_ex *entry)
 {
 	return samba_kdc_seq(context, kdc_db_ctx, entry);
 }
@@ -2369,7 +2341,7 @@ samba_kdc_check_s4u2self(krb5_context context,
 	}
 
 	ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, target_principal,
-				      HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
+				      SDB_F_GET_CLIENT|SDB_F_GET_SERVER,
 				      delegation_check_attrs, &realm_dn, &msg);
 
 	if (ret != 0) {
diff --git a/source4/kdc/db-glue.h b/source4/kdc/db-glue.h
index 9a30521..aa630f5 100644
--- a/source4/kdc/db-glue.h
+++ b/source4/kdc/db-glue.h
@@ -21,20 +21,22 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+struct sdb_entry_ex;
+
 krb5_error_code samba_kdc_fetch(krb5_context context,
 				struct samba_kdc_db_context *kdc_db_ctx,
 				krb5_const_principal principal,
 				unsigned flags,
 				krb5_kvno kvno,
-				hdb_entry_ex *entry_ex);
+				struct sdb_entry_ex *entry_ex);
 
 krb5_error_code samba_kdc_firstkey(krb5_context context,
 				   struct samba_kdc_db_context *kdc_db_ctx,
-				   hdb_entry_ex *entry);
+				   struct sdb_entry_ex *entry);
 
 krb5_error_code samba_kdc_nextkey(krb5_context context,
 				  struct samba_kdc_db_context *kdc_db_ctx,
-				  hdb_entry_ex *entry);
+				  struct sdb_entry_ex *entry);
 
 krb5_error_code
 samba_kdc_check_s4u2self(krb5_context context,
diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c
index c4a4bb4..85d166f 100644
--- a/source4/kdc/hdb-samba4.c
+++ b/source4/kdc/hdb-samba4.c
@@ -37,6 +37,8 @@
 #include "kdc/db-glue.h"
 #include "auth/auth_sam.h"
 #include <ldb.h>
+#include "sdb.h"
+#include "sdb_hdb.h"
 
 static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags, mode_t mode)
 {
@@ -87,33 +89,97 @@ static krb5_error_code hdb_samba4_fetch_kvno(krb5_context context, HDB *db,
 					     hdb_entry_ex *entry_ex)
 {
 	struct samba_kdc_db_context *kdc_db_ctx;
+	struct sdb_entry_ex sdb_entry_ex = {};
+	krb5_error_code code, ret;
 
 	kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
 					   struct samba_kdc_db_context);
 
-	return samba_kdc_fetch(context, kdc_db_ctx, principal, flags, kvno, entry_ex);
+	ret = samba_kdc_fetch(context,
+			      kdc_db_ctx,
+			      principal,
+			      flags,
+			      kvno,
+			      &sdb_entry_ex);
+	switch (ret) {
+	case 0:
+		code = 0;
+		break;
+	case SDB_ERR_WRONG_REALM:
+		/*
+		 * If SDB_ERR_WRONG_REALM is returned we need to process the
+		 * sdb_entry to fill the principal in the HDB entry.
+		 */
+		code = HDB_ERR_WRONG_REALM;
+		break;
+	case SDB_ERR_NOENTRY:
+		return HDB_ERR_NOENTRY;
+	default:
+		return HDB_ERR_NOT_FOUND_HERE;
+	}
+
+	ret = sdb_entry_ex_to_hdb_entry_ex(context, &sdb_entry_ex, entry_ex);
+	sdb_free_entry(&sdb_entry_ex);
+
+	if (code != 0 && ret != 0) {
+		code = ret;
+	}
+
+	return code;
 }
 
 static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsigned flags,
 					hdb_entry_ex *entry)
 {
 	struct samba_kdc_db_context *kdc_db_ctx;
+	struct sdb_entry_ex sdb_entry_ex = {};
+	krb5_error_code ret;
 
 	kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
 					   struct samba_kdc_db_context);
 
-	return samba_kdc_firstkey(context, kdc_db_ctx, entry);
+	ret = samba_kdc_firstkey(context, kdc_db_ctx, &sdb_entry_ex);
+	switch (ret) {
+	case 0:
+		break;
+	case SDB_ERR_WRONG_REALM:
+		return HDB_ERR_WRONG_REALM;
+	case SDB_ERR_NOENTRY:
+		return HDB_ERR_NOENTRY;
+	default:
+		return HDB_ERR_NOT_FOUND_HERE;
+	}
+
+	ret = sdb_entry_ex_to_hdb_entry_ex(context, &sdb_entry_ex, entry);
+	sdb_free_entry(&sdb_entry_ex);
+	return ret;
 }
 
 static krb5_error_code hdb_samba4_nextkey(krb5_context context, HDB *db, unsigned flags,
 				   hdb_entry_ex *entry)
 {
 	struct samba_kdc_db_context *kdc_db_ctx;
+	struct sdb_entry_ex sdb_entry_ex = {};
+	krb5_error_code ret;
 
 	kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
 					   struct samba_kdc_db_context);
 
-	return samba_kdc_nextkey(context, kdc_db_ctx, entry);
+	ret = samba_kdc_nextkey(context, kdc_db_ctx, &sdb_entry_ex);
+	switch (ret) {
+	case 0:
+		break;
+	case SDB_ERR_WRONG_REALM:
+		return HDB_ERR_WRONG_REALM;
+	case SDB_ERR_NOENTRY:
+		return HDB_ERR_NOENTRY;
+	default:
+		return HDB_ERR_NOT_FOUND_HERE;
+	}
+
+	ret = sdb_entry_ex_to_hdb_entry_ex(context, &sdb_entry_ex, entry);
+	sdb_free_entry(&sdb_entry_ex);
+	return ret;
 }
 
 static krb5_error_code hdb_samba4_destroy(krb5_context context, HDB *db)
@@ -129,15 +195,31 @@ hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db,
 {
 	struct samba_kdc_db_context *kdc_db_ctx;
 	struct samba_kdc_entry *skdc_entry;
+	krb5_error_code ret;
 
 	kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
 					   struct samba_kdc_db_context);
 	skdc_entry = talloc_get_type_abort(entry->ctx,
 					   struct samba_kdc_entry);
 
-	return samba_kdc_check_s4u2proxy(context, kdc_db_ctx,
-					 skdc_entry,
-					 target_principal);
+	ret = samba_kdc_check_s4u2proxy(context, kdc_db_ctx,
+					skdc_entry,
+					target_principal);
+	switch (ret) {
+	case 0:
+		break;
+	case SDB_ERR_WRONG_REALM:
+		ret = HDB_ERR_WRONG_REALM;
+		break;
+	case SDB_ERR_NOENTRY:
+		ret = HDB_ERR_NOENTRY;
+		break;
+	default:
+		ret = HDB_ERR_NOT_FOUND_HERE;
+		break;
+	}
+
+	return ret;
 }
 
 static krb5_error_code
@@ -147,15 +229,31 @@ hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db,
 {
 	struct samba_kdc_db_context *kdc_db_ctx;
 	struct samba_kdc_entry *skdc_entry;
+	krb5_error_code ret;
 
 	kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
 					   struct samba_kdc_db_context);
 	skdc_entry = talloc_get_type_abort(entry->ctx,
 					   struct samba_kdc_entry);
 
-	return samba_kdc_check_pkinit_ms_upn_match(context, kdc_db_ctx,
-						   skdc_entry,
-						   certificate_principal);
+	ret = samba_kdc_check_pkinit_ms_upn_match(context, kdc_db_ctx,
+						  skdc_entry,
+						  certificate_principal);
+	switch (ret) {
+	case 0:
+		break;
+	case SDB_ERR_WRONG_REALM:
+		ret = HDB_ERR_WRONG_REALM;
+		break;
+	case SDB_ERR_NOENTRY:
+		ret = HDB_ERR_NOENTRY;
+		break;
+	default:
+		ret = HDB_ERR_NOT_FOUND_HERE;
+		break;
+	}
+
+	return ret;
 }
 
 static krb5_error_code
@@ -165,15 +263,31 @@ hdb_samba4_check_s4u2self(krb5_context context, HDB *db,
 {
 	struct samba_kdc_db_context *kdc_db_ctx;
 	struct samba_kdc_entry *skdc_entry;
+	krb5_error_code ret;
 
 	kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
 					   struct samba_kdc_db_context);
 	skdc_entry = talloc_get_type_abort(entry->ctx,
 					   struct samba_kdc_entry);
 
-	return samba_kdc_check_s4u2self(context, kdc_db_ctx,
-				        skdc_entry,
-				        target_principal);
+	ret = samba_kdc_check_s4u2self(context, kdc_db_ctx,
+				       skdc_entry,
+				       target_principal);
+	switch (ret) {
+	case 0:
+		break;
+	case SDB_ERR_WRONG_REALM:
+		ret = HDB_ERR_WRONG_REALM;
+		break;
+	case SDB_ERR_NOENTRY:
+		ret = HDB_ERR_NOENTRY;
+		break;
+	default:
+		ret = HDB_ERR_NOT_FOUND_HERE;
+		break;
+	}
+
+	return ret;
 }
 
 static krb5_error_code hdb_samba4_auth_status(krb5_context context, HDB *db,
diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c
index bb476e1..4a9341f 100644
--- a/source4/kdc/kdc.c
+++ b/source4/kdc/kdc.c
@@ -35,6 +35,7 @@
 #include "kdc/pac-glue.h"
 #include "dsdb/samdb/samdb.h"
 #include "auth/session.h"
+#include "libds/common/roles.h"
 
 NTSTATUS server_service_kdc_init(void);
 
diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c
index 526841b..cdb0ac1 100644
--- a/source4/kdc/pac-glue.c
+++ b/source4/kdc/pac-glue.c
@@ -28,7 +28,6 @@
 #include "auth/auth_sam_reply.h"
 #include "system/kerberos.h"
 #include "auth/kerberos/kerberos.h"
-#include <hdb.h>
 #include "kdc/samba_kdc.h"
 #include "kdc/pac-glue.h"
 #include "param/param.h"
diff --git a/source4/kdc/sdb.c b/source4/kdc/sdb.c
new file mode 100644
index 0000000..d7c9952
--- /dev/null
+++ b/source4/kdc/sdb.c
@@ -0,0 +1,131 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Database Glue between Samba and the KDC
+
+   Copyright (C) Guenther Deschner <gd at samba.org> 2014
+   Copyright (C) Andreas Schneider <asn at samba.org> 2014
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/kerberos.h"
+#include "sdb.h"
+#include "lib/krb5_wrap/krb5_samba.h"
+
+void sdb_free_entry(struct sdb_entry_ex *ent)
+{
+	struct sdb_key *k;
+	size_t i;
+
+	if (ent->free_entry) {
+		(*ent->free_entry)(ent);
+	}
+
+	for (i = 0; i < ent->entry.keys.len; i++) {
+		k = &ent->entry.keys.val[i];
+
+		/*
+		 * Passing NULL as the Kerberos context is intentional here, as
+		 * both Heimdal and MIT libraries don't use the context when
+		 * clearing the keyblocks.
+		 */
+		krb5_free_keyblock_contents(NULL, &k->key);
+	}
+
+	free_sdb_entry(&ent->entry);
+}
+
+static void free_sdb_key(struct sdb_key *k)
+{
+	if (k == NULL) {
+		return;
+	}
+
+	if (k->mkvno) {
+		free(k->mkvno);
+	}
+
+	/* keyblock not alloced */
+
+	if (k->salt) {
+		kerberos_free_data_contents(NULL, &k->salt->salt);
+	}
+
+	ZERO_STRUCTP(k);
+}
+
+void free_sdb_entry(struct sdb_entry *s)
+{
+	unsigned int i;
+
+	/*
+	 * Passing NULL as the Kerberos context is intentional here, as both
+	 * Heimdal and MIT libraries don't use the context when clearing the
+	 * principals.
+	 */
+	krb5_free_principal(NULL, s->principal);
+
+	if (s->keys.len) {
+		for (i=0; i < s->keys.len; i++) {
+			free_sdb_key(&s->keys.val[i]);
+		}
+		free(s->keys.val);
+	}
+	krb5_free_principal(NULL, s->created_by.principal);
+	if (s->modified_by) {
+		krb5_free_principal(NULL, s->modified_by->principal);
+	}
+	SAFE_FREE(s->valid_start);
+	SAFE_FREE(s->valid_end);
+	SAFE_FREE(s->pw_end);
+	if (s->etypes) {
+		if (s->etypes->len) {
+			free(s->etypes->val);
+		}
+		free(s->etypes);
+	}
+
+	ZERO_STRUCTP(s);
+}
+
+struct SDBFlags int2SDBFlags(unsigned n)
+{
+	struct SDBFlags flags;
+
+	memset(&flags, 0, sizeof(flags));
+
+	flags.initial = (n >> 0) & 1;
+	flags.forwardable = (n >> 1) & 1;
+	flags.proxiable = (n >> 2) & 1;
+	flags.renewable = (n >> 3) & 1;
+	flags.postdate = (n >> 4) & 1;
+	flags.server = (n >> 5) & 1;
+	flags.client = (n >> 6) & 1;
+	flags.invalid = (n >> 7) & 1;
+	flags.require_preauth = (n >> 8) & 1;
+	flags.change_pw = (n >> 9) & 1;
+	flags.require_hwauth = (n >> 10) & 1;
+	flags.ok_as_delegate = (n >> 11) & 1;
+	flags.user_to_user = (n >> 12) & 1;
+	flags.immutable = (n >> 13) & 1;
+	flags.trusted_for_delegation = (n >> 14) & 1;
+	flags.allow_kerberos4 = (n >> 15) & 1;
+	flags.allow_digest = (n >> 16) & 1;
+	flags.locked_out = (n >> 17) & 1;
+	flags.do_not_store = (n >> 31) & 1;
+	return flags;
+}
diff --git a/source4/kdc/sdb.h b/source4/kdc/sdb.h
new file mode 100644
index 0000000..e4f2725
--- /dev/null
+++ b/source4/kdc/sdb.h
@@ -0,0 +1,126 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Database Glue between Samba and the KDC
+
+   Copyright (C) Guenther Deschner <gd at samba.org> 2014
+   Copyright (C) Andreas Schneider <asn at samba.org> 2014
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _KDC_SDB_H_
+#define _KDC_SDB_H_
+
+struct sdb_salt {
+	unsigned int type;
+	krb5_data salt;
+};
+
+struct sdb_key {
+	unsigned int *mkvno;
+	krb5_keyblock key;
+	struct sdb_salt *salt;
+};
+
+struct sdb_keys {
+	unsigned int len;
+	struct sdb_key *val;
+};
+
+struct sdb_event {
+	krb5_principal principal;
+	time_t time;
+};
+
+struct SDBFlags {
+	unsigned int initial:1;
+	unsigned int forwardable:1;
+	unsigned int proxiable:1;
+	unsigned int renewable:1;
+	unsigned int postdate:1;
+	unsigned int server:1;
+	unsigned int client:1;
+	unsigned int invalid:1;
+	unsigned int require_preauth:1;
+	unsigned int change_pw:1;
+	unsigned int require_hwauth:1;
+	unsigned int ok_as_delegate:1;
+	unsigned int user_to_user:1;
+	unsigned int immutable:1;
+	unsigned int trusted_for_delegation:1;
+	unsigned int allow_kerberos4:1;
+	unsigned int allow_digest:1;
+	unsigned int locked_out:1;
+	unsigned int _unused18:1;
+	unsigned int _unused19:1;
+	unsigned int _unused20:1;
+	unsigned int _unused21:1;
+	unsigned int _unused22:1;
+	unsigned int _unused23:1;
+	unsigned int _unused24:1;
+	unsigned int _unused25:1;
+	unsigned int _unused26:1;
+	unsigned int _unused27:1;
+	unsigned int _unused28:1;
+	unsigned int _unused29:1;
+	unsigned int _unused30:1;
+	unsigned int do_not_store:1;
+};
+
+struct sdb_entry {
+	krb5_principal principal;
+	unsigned int kvno;
+	struct sdb_keys keys;
+	struct sdb_event created_by;
+	struct sdb_event *modified_by;
+	time_t *valid_start;
+	time_t *valid_end;
+	time_t *pw_end;
+	unsigned int *max_life;
+	unsigned int *max_renew;
+	struct SDBFlags flags;
+	struct sdb_entry_etypes {
+		unsigned int len;
+		unsigned int *val;
+	} *etypes;
+};
+
+struct sdb_entry_ex {
+	void *ctx;
+	struct sdb_entry entry;
+	void (*free_entry)(struct sdb_entry_ex *);
+};
+
+#define SDB_ERR_NOENTRY 36150275
+#define SDB_ERR_NOT_FOUND_HERE 36150287
+#define SDB_ERR_WRONG_REALM 36150289
+
+#define SDB_F_DECRYPT		1	/* decrypt keys */
+#define SDB_F_GET_CLIENT	4	/* fetch client */
+#define SDB_F_GET_SERVER	8	/* fetch server */
+#define SDB_F_GET_KRBTGT	16	/* fetch krbtgt */
+#define SDB_F_GET_ANY		28	/* fetch any of client,server,krbtgt */
+#define SDB_F_CANON		32	/* want canonicalition */
+#define SDB_F_ADMIN_DATA	64	/* want data that kdc don't use  */
+#define SDB_F_KVNO_SPECIFIED	128	/* we want a particular KVNO */
+#define SDB_F_FOR_AS_REQ	4096	/* fetch is for a AS REQ */
+#define SDB_F_FOR_TGS_REQ	8192	/* fetch is for a TGS REQ */
+
+void sdb_free_entry(struct sdb_entry_ex *e);
+void free_sdb_entry(struct sdb_entry *s);
+struct SDBFlags int2SDBFlags(unsigned n);
+
+#endif /* _KDC_SDB_H_ */
diff --git a/source4/kdc/sdb_to_hdb.c b/source4/kdc/sdb_to_hdb.c
new file mode 100644
index 0000000..7ac0b0e
--- /dev/null
+++ b/source4/kdc/sdb_to_hdb.c
@@ -0,0 +1,347 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Database Glue between Samba and the KDC
+
+   Copyright (C) Guenther Deschner <gd at samba.org> 2014
+   Copyright (C) Andreas Schneider <asn at samba.org> 2014
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <hdb.h>
+#include "sdb.h"
+#include "sdb_hdb.h"
+#include "lib/krb5_wrap/krb5_samba.h"
+#include "kdc/samba_kdc.h"
+
+static void sdb_flags_to_hdb_flags(const struct SDBFlags *s,
+				   HDBFlags *h)
+{
+	SMB_ASSERT(sizeof(struct SDBFlags) == sizeof(HDBFlags));
+
+	h->initial = s->initial;
+	h->forwardable = s->forwardable;
+	h->proxiable = s->proxiable;
+	h->renewable = s->renewable;
+	h->postdate = s->postdate;
+	h->server = s->server;
+	h->client = s->client;
+	h->invalid = s->invalid;
+	h->require_preauth = s->require_preauth;
+	h->change_pw = s->change_pw;
+	h->require_hwauth = s->require_hwauth;
+	h->ok_as_delegate = s->ok_as_delegate;
+	h->user_to_user = s->user_to_user;
+	h->immutable = s->immutable;
+	h->trusted_for_delegation = s->trusted_for_delegation;
+	h->allow_kerberos4 = s->allow_kerberos4;
+	h->allow_digest = s->allow_digest;
+	h->locked_out = s->locked_out;
+	h->_unused18 = s->_unused18;
+	h->_unused19 = s->_unused19;
+	h->_unused20 = s->_unused20;
+	h->_unused21 = s->_unused21;
+	h->_unused22 = s->_unused22;
+	h->_unused23 = s->_unused23;
+	h->_unused24 = s->_unused24;
+	h->_unused25 = s->_unused25;
+	h->_unused26 = s->_unused26;
+	h->_unused27 = s->_unused27;
+	h->_unused28 = s->_unused28;
+	h->_unused29 = s->_unused29;
+	h->_unused30 = s->_unused30;
+	h->do_not_store = s->do_not_store;
+}
+
+static int sdb_salt_to_Salt(const struct sdb_salt *s, Salt *h)
+{
+	int ret;
+
+	h->type = s->type;
+	ret = krb5_copy_data_contents(&h->salt, s->salt.data, s->salt.length);
+	if (ret != 0) {
+		free_Salt(h);
+		return ENOMEM;
+	}
+	h->opaque = NULL;
+
+	return 0;
+}
+
+static int sdb_key_to_Key(const struct sdb_key *s, Key *h)
+{
+	int rc;
+
+	if (s->mkvno != NULL) {
+		h->mkvno = malloc(sizeof(unsigned int));
+		if (h->mkvno == NULL) {
+			goto error_nomem;
+		}
+		*h->mkvno = *s->mkvno;
+	} else {
+		h->mkvno = NULL;
+	}
+
+	h->key.keytype = s->key.keytype;
+	rc = krb5_copy_data_contents(&h->key.keyvalue,
+				      s->key.keyvalue.data,
+				      s->key.keyvalue.length);
+	if (rc != 0) {
+		goto error_nomem;
+	}
+
+	if (s->salt != NULL) {
+		h->salt = malloc(sizeof(Salt));
+		if (h->salt == NULL) {
+			goto error_nomem;
+		}
+
+		rc = sdb_salt_to_Salt(s->salt,
+				      h->salt);
+		if (rc != 0) {
+			goto error_nomem;
+		}
+	} else {
+		h->salt = NULL;
+	}
+
+	return 0;
+
+error_nomem:
+	free_Key(h);
+	return ENOMEM;
+}
+
+static int sdb_keys_to_Keys(const struct sdb_keys *s, Keys *h)
+{
+	int ret, i;
+
+	h->len = s->len;
+	if (s->val != NULL) {
+		h->val = malloc(h->len * sizeof(Key));
+		if (h->val == NULL) {
+			return ENOMEM;
+		}
+		for (i = 0; i < h->len; i++) {
+			ret = sdb_key_to_Key(&s->val[i],
+					     &h->val[i]);
+			if (ret != 0) {
+				free_Keys(h);
+				return ENOMEM;
+			}
+		}
+	} else {
+		h->val = NULL;
+	}
+
+	return 0;
+}
+
+static int sdb_event_to_Event(krb5_context context,
+			      const struct sdb_event *s, Event *h)
+{
+	int ret;
+
+	if (s->principal != NULL) {
+		ret = krb5_copy_principal(context,
+					  s->principal,
+					  &h->principal);
+		if (ret != 0) {
+			free_Event(h);
+			return ret;
+		}
+	} else {
+		h->principal = NULL;
+	}
+	h->time = s->time;
+
+	return 0;
+}
+
+
+static int sdb_entry_to_hdb_entry(krb5_context context,
+				  const struct sdb_entry *s,
+				  struct hdb_entry *h)
+{
+	unsigned int i;
+	int rc;
+
+	ZERO_STRUCTP(h);
+
+	rc = krb5_copy_principal(context,
+				 s->principal,
+				 &h->principal);
+	if (rc != 0) {
+		return rc;
+	}
+
+	h->kvno = s->kvno;
+
+	rc = sdb_keys_to_Keys(&s->keys, &h->keys);
+	if (rc != 0) {
+		goto error;
+	}
+
+	rc = sdb_event_to_Event(context,
+				 &s->created_by,
+				 &h->created_by);
+	if (rc != 0) {
+		goto error;
+	}
+
+	if (s->modified_by) {
+		h->modified_by = malloc(sizeof(Event));
+		if (h->modified_by == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+
+		rc = sdb_event_to_Event(context,
+					 s->modified_by,
+					 h->modified_by);
+		if (rc != 0) {
+			goto error;
+		}
+	} else {
+		h->modified_by = NULL;
+	}
+
+	if (s->valid_start != NULL) {
+		h->valid_start = malloc(sizeof(KerberosTime));
+		if (h->valid_start == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+		*h->valid_start = *s->valid_start;
+	} else {
+		h->valid_start = NULL;
+	}
+
+	if (s->valid_end != NULL) {
+		h->valid_end = malloc(sizeof(KerberosTime));
+		if (h->valid_end == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+		*h->valid_end = *s->valid_end;
+	} else {
+		h->valid_end = NULL;
+	}
+
+	if (s->pw_end != NULL) {
+		h->pw_end = malloc(sizeof(KerberosTime));
+		if (h->pw_end == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+		*h->pw_end = *s->pw_end;
+	} else {
+		h->pw_end = NULL;
+	}
+
+	if (s->max_life != NULL) {
+		h->max_life = malloc(sizeof(unsigned int));
+		if (h->max_life == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+		*h->max_life = *s->max_life;
+	} else {
+		h->max_life = NULL;
+	}
+
+	if (s->max_renew != NULL) {
+		h->max_renew = malloc(sizeof(unsigned int));
+		if (h->max_renew == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+		*h->max_renew = *s->max_renew;
+	} else {
+		h->max_renew = NULL;
+	}
+
+	sdb_flags_to_hdb_flags(&s->flags, &h->flags);
+
+	if (s->etypes) {
+		h->etypes = malloc(sizeof(*h->etypes));
+		if (h->etypes == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+		h->etypes->len = s->etypes->len;
+		h->etypes->val = calloc(h->etypes->len, sizeof(int));
+		if (h->etypes->val == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+		for (i = 0; i < h->etypes->len; i++) {
+			h->etypes->val[i] = s->etypes->val[i];
+		}
+	} else {
+		h->etypes = NULL;
+	}
+	h->generation = NULL;
+	h->extensions = NULL; /* really sure ? FIXME */
+
+	return 0;
+error:
+	free_hdb_entry(h);
+	return rc;
+}
+
+static int samba_kdc_hdb_entry_destructor(struct samba_kdc_entry *p)
+{
+	struct hdb_entry_ex *entry_ex = p->entry_ex;
+	free_hdb_entry(&entry_ex->entry);
+
+	return 0;
+}
+
+static void samba_kdc_free_hdb_entry(krb5_context context,
+				     struct hdb_entry_ex *entry_ex)
+{
+	/* this function is called only from hdb_free_entry().
+	 * Make sure we neutralize the destructor or we will
+	 * get a double free later when hdb_free_entry() will
+	 * try to call free_hdb_entry() */
+	talloc_set_destructor(entry_ex->ctx, NULL);
+
+	/* now proceed to free the talloc part */
+	talloc_free(entry_ex->ctx);
+}
+
+int sdb_entry_ex_to_hdb_entry_ex(krb5_context context,
+				 const struct sdb_entry_ex *s,
+				 struct hdb_entry_ex *h)
+{
+	struct samba_kdc_entry *skdc_entry;
+
+	ZERO_STRUCTP(h);
+
+	if (s->ctx != NULL) {
+		skdc_entry = talloc_get_type(s->ctx, struct samba_kdc_entry);
+
+		h->ctx		= skdc_entry;
+		h->free_entry	= samba_kdc_free_hdb_entry;
+
+		talloc_set_destructor(skdc_entry,
+				      samba_kdc_hdb_entry_destructor);
+	}
+
+	return sdb_entry_to_hdb_entry(context, &s->entry, &h->entry);
+}
diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
index 0871404..2abafa6 100755
--- a/source4/kdc/wscript_build
+++ b/source4/kdc/wscript_build
@@ -27,7 +27,7 @@ bld.SAMBA_MODULE('service_kdc',
 
 bld.SAMBA_LIBRARY('HDB_SAMBA4',
                   source='hdb-samba4.c hdb-samba4-plugin.c',
-                  deps='ldb auth4_sam auth_sam_reply samba-credentials hdb db-glue samba-hostconfig com_err',
+                  deps='ldb auth4_sam auth_sam_reply samba-credentials hdb db-glue samba-hostconfig com_err sdb_hdb',
                   includes=kdc_include,
                   private_library=True,
                   enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL')
@@ -58,11 +58,24 @@ bld.SAMBA_SUBSYSTEM('WDC_SAMBA4',
 	enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL')
 	)
 
+bld.SAMBA_SUBSYSTEM('sdb',
+	source='sdb.c',
+	includes=kdc_include,
+	deps='talloc krb5',
+	)
+
+bld.SAMBA_SUBSYSTEM('sdb_hdb',
+	source='sdb_to_hdb.c',
+	includes=kdc_include,
+	deps='talloc sdb hdb',
+	autoproto='sdb_hdb.h',
+	enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL')
+	)
 
 bld.SAMBA_SUBSYSTEM('PAC_GLUE',
 	source='pac-glue.c',
         includes=kdc_include,
-	deps='ldb auth4_sam auth_sam_reply samba-credentials hdb samba-hostconfig com_err'
+	deps='ldb auth4_sam auth_sam_reply samba-credentials samba-hostconfig com_err'
 	)
 
 bld.SAMBA_LIBRARY('pac',
@@ -74,7 +87,7 @@ bld.SAMBA_LIBRARY('pac',
 
 bld.SAMBA_LIBRARY('db-glue',
 	source='db-glue.c',
-	deps='ldb auth4_sam auth_sam_reply samba-credentials hdb samba-hostconfig com_err',
+	deps='ldb auth4_sam auth_sam_reply samba-credentials sdb samba-hostconfig com_err',
 	private_library=True,
         includes=kdc_include,
 	)
diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c
index fd2b579..7efb7ed 100644
--- a/source4/ldap_server/ldap_backend.c
+++ b/source4/ldap_server/ldap_backend.c
@@ -255,7 +255,7 @@ struct ldapsrv_reply *ldapsrv_init_reply(struct ldapsrv_call *call, uint8_t type
 
 void ldapsrv_queue_reply(struct ldapsrv_call *call, struct ldapsrv_reply *reply)
 {
-	DLIST_ADD_END(call->replies, reply, struct ldapsrv_reply *);
+	DLIST_ADD_END(call->replies, reply);
 }
 
 static NTSTATUS ldapsrv_unwilling(struct ldapsrv_call *call, int error)
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
index d849ed3..3afbcdb 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -46,6 +46,7 @@
 #include "../lib/tsocket/tsocket.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "../libcli/util/tstream.h"
+#include "libds/common/roles.h"
 
 static void ldapsrv_terminate_connection_done(struct tevent_req *subreq);
 
diff --git a/source4/lib/com/dcom/dcom.h b/source4/lib/com/dcom/dcom.h
index 56d6eac..cb549b1 100644
--- a/source4/lib/com/dcom/dcom.h
+++ b/source4/lib/com/dcom/dcom.h
@@ -50,7 +50,7 @@ typedef enum ndr_err_code (*unmarshal_fn)(TALLOC_CTX *mem_ctx, struct OBJREF *o,
 struct dcom_client_context *dcom_client_init(struct com_context *ctx, struct cli_credentials *credentials);
 struct dcom_object_exporter *object_exporter_by_oxid(struct com_context *ctx, uint64_t oxid);
 struct dcom_object_exporter *object_exporter_by_ip(struct com_context *ctx, struct IUnknown *ip);
-WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct IUnknown ***ip, WERROR *results);
+WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct IUnknown ***ip, HRESULT *results);
 WERROR dcom_get_class_object(struct com_context *ctx, struct GUID *clsid, const char *server, struct GUID *iid, struct IUnknown **ip);
 NTSTATUS dcom_get_pipe(struct IUnknown *iface, struct dcerpc_pipe **pp);
 NTSTATUS dcom_OBJREF_from_IUnknown(struct OBJREF *o, struct IUnknown *p);
diff --git a/source4/lib/com/dcom/main.c b/source4/lib/com/dcom/main.c
index ea1e4f8..a652678 100644
--- a/source4/lib/com/dcom/main.c
+++ b/source4/lib/com/dcom/main.c
@@ -240,7 +240,7 @@ struct dcom_object_exporter *object_exporter_by_ip(struct com_context *ctx, stru
 	return object_exporter_by_oxid(ctx, ip->obj.u_objref.u_standard.std.oxid);
 }
 
-WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct IUnknown ***ip, WERROR *results)
+WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct IUnknown ***ip, HRESULT *results)
 {
 	uint16_t protseq[] = DCOM_NEGOTIATED_PROTOCOLS;
 	struct dcerpc_pipe *p;
@@ -249,7 +249,7 @@ WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const cha
 	struct RemoteActivation r;
 	struct DUALSTRINGARRAY *pds;
 	int i;
-	WERROR hr;
+	HRESULT hr;
 	uint64_t oxid;
 	struct GUID ipidRemUnknown;
 	struct IUnknown *ru_template;
@@ -301,8 +301,8 @@ WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const cha
 		hr = r.out.result;
 		goto end;
 	}
-	
-	if(!W_ERROR_IS_OK(hr)) {
+
+	if(!HRES_IS_OK(hr)) {
 		goto end;
 	}
 
diff --git a/source4/lib/http/http.c b/source4/lib/http/http.c
index c3bd728..c6976ee 100644
--- a/source4/lib/http/http.c
+++ b/source4/lib/http/http.c
@@ -357,7 +357,7 @@ static int http_add_header_internal(TALLOC_CTX *mem_ctx,
 	h = talloc(mem_ctx, struct http_header);
 	h->key = talloc_strdup(h, key);
 	h->value = talloc_strdup(h, value);
-	DLIST_ADD_END(*headers, h, NULL);
+	DLIST_ADD_END(*headers, h);
 	tail = DLIST_TAIL(*headers);
 	if (tail != h) {
 		DEBUG(0, ("%s: Error adding header\n", __func__));
diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c
index ff7238d..0fc180b 100644
--- a/source4/lib/messaging/messaging.c
+++ b/source4/lib/messaging/messaging.c
@@ -312,6 +312,7 @@ struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
 	bool ok;
 	int ret;
 	const char *lock_dir = NULL;
+	int tdb_flags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST;
 
 	if (ev == NULL) {
 		return NULL;
@@ -348,7 +349,7 @@ struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
 	}
 
 	msg->msg_dgm_ref = messaging_dgm_ref(
-		msg, ev, server_id.unique_id, msg->sock_dir, msg->lock_dir,
+		msg, ev, &server_id.unique_id, msg->sock_dir, msg->lock_dir,
 		imessaging_dgm_recv, msg, &ret);
 
 	if (msg->msg_dgm_ref == NULL) {
@@ -368,10 +369,9 @@ struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
 
 	msg->start_time    = timeval_current();
 
-	msg->names = server_id_db_init(
-		msg, server_id, lock_dir, 0,
-		TDB_INCOMPATIBLE_HASH|TDB_CLEAR_IF_FIRST|
-		lpcfg_tdb_flags(lp_ctx, 0));
+	tdb_flags |= lpcfg_tdb_flags(lp_ctx, 0);
+
+	msg->names = server_id_db_init(msg, server_id, lock_dir, 0, tdb_flags);
 	if (msg->names == NULL) {
 		goto fail;
 	}
diff --git a/source4/lib/messaging/pymessaging.c b/source4/lib/messaging/pymessaging.c
index 199532f..0eca139 100644
--- a/source4/lib/messaging/pymessaging.c
+++ b/source4/lib/messaging/pymessaging.c
@@ -147,7 +147,7 @@ static PyObject *py_imessaging_send(PyObject *self, PyObject *args, PyObject *kw
 	NTSTATUS status;
 	struct server_id server;
 	const char *kwnames[] = { "target", "msg_type", "data", NULL };
-	int length;
+	Py_ssize_t length;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ois#:send", 
 		discard_const_p(char *, kwnames), &target, &msg_type, &data.data, &length)) {
diff --git a/source4/lib/messaging/wscript_build b/source4/lib/messaging/wscript_build
index adcb2cc..86877af 100644
--- a/source4/lib/messaging/wscript_build
+++ b/source4/lib/messaging/wscript_build
@@ -9,7 +9,7 @@ bld.SAMBA_LIBRARY('MESSAGING',
 
 bld.SAMBA_PYTHON('python_messaging',
 	source='pymessaging.c',
-	deps='MESSAGING events pyparam_util',
+	deps='MESSAGING events pyparam_util pytalloc-util',
 	realname='samba/messaging.so'
 	)
 
diff --git a/source4/lib/registry/pyregistry.c b/source4/lib/registry/pyregistry.c
index 8f96710..78a0b1d 100644
--- a/source4/lib/registry/pyregistry.c
+++ b/source4/lib/registry/pyregistry.c
@@ -160,7 +160,6 @@ PyTypeObject PyRegistry = {
 	.tp_name = "Registry",
 	.tp_methods = registry_methods,
 	.tp_new = registry_new,
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 };
 
@@ -212,7 +211,7 @@ static PyObject *py_hive_key_set_value(PyObject *self, PyObject *args)
 	char *name;
 	uint32_t type;
 	DATA_BLOB value;
-	int value_length = 0;
+	Py_ssize_t value_length = 0;
 	WERROR result;
 	struct hive_key *key = PyHiveKey_AsHiveKey(self);
 
@@ -300,13 +299,11 @@ PyTypeObject PyHiveKey = {
 	.tp_name = "HiveKey",
 	.tp_methods = hive_key_methods,
 	.tp_new = hive_new,
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 };
 
 PyTypeObject PyRegistryKey = {
 	.tp_name = "RegistryKey",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 };
 
@@ -444,22 +441,14 @@ static PyMethodDef py_registry_methods[] = {
 void initregistry(void)
 {
 	PyObject *m;
-	PyTypeObject *talloc_type = pytalloc_GetObjectType();
 
-	if (talloc_type == NULL)
+	if (pytalloc_BaseObject_PyType_Ready(&PyHiveKey) < 0)
 		return;
 
-	PyHiveKey.tp_base = talloc_type;
-	PyRegistry.tp_base = talloc_type;
-	PyRegistryKey.tp_base = talloc_type;
-
-	if (PyType_Ready(&PyHiveKey) < 0)
-		return;
-
-	if (PyType_Ready(&PyRegistry) < 0)
+	if (pytalloc_BaseObject_PyType_Ready(&PyRegistry) < 0)
 		return;
 
-	if (PyType_Ready(&PyRegistryKey) < 0)
+	if (pytalloc_BaseObject_PyType_Ready(&PyRegistryKey) < 0)
 		return;
 
 	m = Py_InitModule3("registry", py_registry_methods, "Registry");
diff --git a/source4/lib/registry/registry.pc.in b/source4/lib/registry/registry.pc.in
deleted file mode 100644
index e923931..0000000
--- a/source4/lib/registry/registry.pc.in
+++ /dev/null
@@ -1,12 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: registry
-Description: Windows-style registry library
-Requires: talloc
-Requires.private: ldb
-Version: @PACKAGE_VERSION@
-Libs: @LIB_RPATH@ -L${libdir} -lregistry
-Cflags: -I${includedir}  -DHAVE_IMMEDIATE_STRUCTURES=1
diff --git a/source4/lib/registry/wscript_build b/source4/lib/registry/wscript_build
index 495969a..c558b22 100644
--- a/source4/lib/registry/wscript_build
+++ b/source4/lib/registry/wscript_build
@@ -12,10 +12,9 @@ bld.SAMBA_SUBSYSTEM('TDR_REGF',
 
 bld.SAMBA_LIBRARY('registry',
 	source='interface.c util.c samba.c patchfile_dotreg.c patchfile_preg.c patchfile.c regf.c hive.c local.c ldb.c rpc.c',
-	pc_files='registry.pc',
 	public_deps='dcerpc samba-util TDR_REGF ldb RPC_NDR_WINREG ldbsamba util_reg',
-	public_headers='registry.h',
-	vnum='0.0.1'
+	private_headers='registry.h',
+	private_library=True
 	)
 
 
diff --git a/source4/lib/socket/interface.c b/source4/lib/socket/interface.c
index 504a727..963c0aa 100644
--- a/source4/lib/socket/interface.c
+++ b/source4/lib/socket/interface.c
@@ -135,7 +135,7 @@ static void add_interface(TALLOC_CTX *mem_ctx, const struct iface_struct *ifs, s
 	   this needs to be a ADD_END, as some tests (such as the
 	   spoolss notify test) depend on the interfaces ordering
 	*/
-	DLIST_ADD_END(*interfaces, iface, NULL);
+	DLIST_ADD_END(*interfaces, iface);
 }
 
 /**
@@ -178,6 +178,15 @@ static void interpret_interface(TALLOC_CTX *mem_ctx,
 		return;
 	}
 
+	p = strchr_m(token, ';');
+	if (p != NULL) {
+		/*
+		 * skip smbd-specific extra data:
+		 * link speed, capabilities, and interface index
+		 */
+		*p = 0;
+	}
+
 	/* maybe it is a DNS name */
 	p = strchr_m(token,'/');
 	if (p == NULL) {
diff --git a/source4/lib/socket/wscript_build b/source4/lib/socket/wscript_build
index da0b380..1cb89c6 100644
--- a/source4/lib/socket/wscript_build
+++ b/source4/lib/socket/wscript_build
@@ -10,7 +10,7 @@ bld.SAMBA_LIBRARY('netif',
 bld.SAMBA_MODULE('socket_ip',
     source='socket_ip.c',
     subsystem='samba_socket',
-    deps='errors',
+    deps='samba-errors',
     internal_module=True
     )
 
diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c
index b36d650..b050369 100644
--- a/source4/lib/stream/packet.c
+++ b/source4/lib/stream/packet.c
@@ -541,7 +541,7 @@ _PUBLIC_ NTSTATUS packet_send_callback(struct packet_context *pc, DATA_BLOB blob
 	el = talloc(pc, struct send_element);
 	NT_STATUS_HAVE_NO_MEMORY(el);
 
-	DLIST_ADD_END(pc->send_queue, el, struct send_element *);
+	DLIST_ADD_END(pc->send_queue, el);
 	el->blob = blob;
 	el->nsent = 0;
 	el->send_callback = send_callback;
diff --git a/source4/lib/tls/tls.c b/source4/lib/tls/tls.c
index 2fe4ff7..ad8bbd4 100644
--- a/source4/lib/tls/tls.c
+++ b/source4/lib/tls/tls.c
@@ -31,7 +31,7 @@
 #if ENABLE_GNUTLS
 #include <gnutls/gnutls.h>
 
-#define DH_BITS 1024
+#define DH_BITS 2048
 
 #if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
 typedef gnutls_datum gnutls_datum_t;
@@ -42,6 +42,7 @@ struct tls_params {
 	gnutls_certificate_credentials x509_cred;
 	gnutls_dh_params dh_params;
 	bool tls_enabled;
+	const char *tls_priority;
 };
 #endif
 
@@ -390,6 +391,8 @@ struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx, struct loadparm_context *
 		return params;
 	}
 
+	params->tls_priority = lpcfg_tls_priority(lp_ctx);
+
 	if (!file_exist(cafile)) {
 		char *hostname = talloc_asprintf(mem_ctx, "%s.%s",
 						 lpcfg_netbios_name(lp_ctx),
@@ -499,6 +502,7 @@ struct socket_context *tls_init_server(struct tls_params *params,
 	int ret;
 	struct socket_context *new_sock;
 	NTSTATUS nt_status;
+	const char *error_pos;
 
 	nt_status = socket_create_with_ops(socket_ctx, &tls_socket_ops, &new_sock,
 					   SOCKET_TYPE_STREAM,
@@ -527,7 +531,16 @@ struct socket_context *tls_init_server(struct tls_params *params,
 
 	talloc_set_destructor(tls, tls_destructor);
 
-	TLSCHECK(gnutls_set_default_priority(tls->session));
+	ret = gnutls_priority_set_direct(tls->session,
+					 params->tls_priority,
+					 &error_pos);
+	if (ret != GNUTLS_E_SUCCESS) {
+		DEBUG(0,("TLS %s - %s.  Check 'tls priority' option at '%s'\n",
+			 __location__, gnutls_strerror(ret), error_pos));
+		talloc_free(new_sock);
+		return NULL;
+	}
+
 	TLSCHECK(gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
 					params->x509_cred));
 	gnutls_certificate_server_set_request(tls->session, GNUTLS_CERT_REQUEST);
@@ -563,69 +576,6 @@ failed:
 }
 
 
-/*
-  setup for a new client connection
-*/
-struct socket_context *tls_init_client(struct socket_context *socket_ctx,
-				       struct tevent_fd *fde,
-				       const char *ca_path)
-{
-	struct tls_context *tls;
-	int ret = 0;
-	struct socket_context *new_sock;
-	NTSTATUS nt_status;
-
-	nt_status = socket_create_with_ops(socket_ctx, &tls_socket_ops, &new_sock,
-					   SOCKET_TYPE_STREAM,
-					   socket_ctx->flags | SOCKET_FLAG_ENCRYPT);
-	if (!NT_STATUS_IS_OK(nt_status)) {
-		return NULL;
-	}
-
-	tls = talloc(new_sock, struct tls_context);
-	if (tls == NULL) return NULL;
-
-	tls->socket          = socket_ctx;
-	talloc_steal(tls, socket_ctx);
-	tls->fde             = fde;
-
-	new_sock->private_data    = tls;
-
-	gnutls_global_init();
-
-	gnutls_certificate_allocate_credentials(&tls->xcred);
-	gnutls_certificate_set_x509_trust_file(tls->xcred, ca_path, GNUTLS_X509_FMT_PEM);
-	TLSCHECK(gnutls_init(&tls->session, GNUTLS_CLIENT));
-	TLSCHECK(gnutls_set_default_priority(tls->session));
-	gnutls_priority_set_direct(tls->session, "NORMAL:+CTYPE-OPENPGP", NULL);
-	TLSCHECK(gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, tls->xcred));
-
-	talloc_set_destructor(tls, tls_destructor);
-
-	gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr)tls);
-	gnutls_transport_set_pull_function(tls->session, (gnutls_pull_func)tls_pull);
-	gnutls_transport_set_push_function(tls->session, (gnutls_push_func)tls_push);
-#if GNUTLS_VERSION_MAJOR < 3
-	gnutls_transport_set_lowat(tls->session, 0);
-#endif
-	tls->tls_detect = false;
-
-	tls->output_pending  = false;
-	tls->done_handshake  = false;
-	tls->have_first_byte = false;
-	tls->tls_enabled     = true;
-	tls->interrupted     = false;
-
-	new_sock->state = SOCKET_STATE_CLIENT_CONNECTED;
-
-	return new_sock;
-
-failed:
-	DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
-	tls->tls_enabled = false;
-	return new_sock;
-}
-
 static NTSTATUS tls_socket_set_option(struct socket_context *sock, const char *option, const char *val)
 {
 	set_socket_options(socket_get_fd(sock), option);
@@ -693,15 +643,5 @@ struct socket_context *tls_init_server(struct tls_params *params,
 }
 
 
-/*
-  setup for a new client connection
-*/
-struct socket_context *tls_init_client(struct socket_context *socket,
-				       struct tevent_fd *fde,
-				       const char *ca_path)
-{
-	return NULL;
-}
-
 #endif
 
diff --git a/source4/lib/tls/tls.h b/source4/lib/tls/tls.h
index e6c27f3..71e6cfb 100644
--- a/source4/lib/tls/tls.h
+++ b/source4/lib/tls/tls.h
@@ -51,13 +51,6 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx,
 		       const char *cafile);
 
 /*
-  call tls_init_client() on each new client connection
-*/
-struct socket_context *tls_init_client(struct socket_context *sock, 
-				    struct tevent_fd *fde,
-				    const char *cafile);
-
-/*
   return True if a connection used tls
 */
 bool tls_enabled(struct socket_context *tls);
diff --git a/source4/lib/tls/tls_tstream.c b/source4/lib/tls/tls_tstream.c
index 188a3b8..5c3e9f1 100644
--- a/source4/lib/tls/tls_tstream.c
+++ b/source4/lib/tls/tls_tstream.c
@@ -28,7 +28,7 @@
 #if ENABLE_GNUTLS
 #include <gnutls/gnutls.h>
 
-#define DH_BITS 1024
+#define DH_BITS 2048
 
 #if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
 typedef gnutls_datum gnutls_datum_t;
diff --git a/source4/lib/tls/wscript b/source4/lib/tls/wscript
index 83520a7..2083409 100644
--- a/source4/lib/tls/wscript
+++ b/source4/lib/tls/wscript
@@ -21,14 +21,28 @@ def configure(conf):
             conf.fatal("--disable-gnutls given: Building the AD DC requires GnuTLS (eg libgnutls-dev, gnutls-devel) for ldaps:// support and for the BackupKey protocol")
         return
 
-    if conf.CHECK_CFG(package='gnutls',
-                      args='"gnutls >= 3.0.0" --cflags --libs',
-                      msg='Checking for gnutls >= 3.0.0s', mandatory=False):
+    if Options.options.with_system_mitkrb5 and conf.env.AD_DC_BUILD_IS_ENABLED:
+        conf.CHECK_CFG(package='gnutls',
+                       args='"gnutls >= 3.4.7" --cflags --libs',
+                       msg='Checking for gnutls >= 3.4.7',
+                       mandatory=True)
+        conf.DEFINE('HAVE_GNUTLS_3_4_7', 1)
         conf.DEFINE('HAVE_GNUTLS3', 1)
     else:
-        conf.CHECK_CFG(package='gnutls',
-                       args='"gnutls >= 1.4.0 gnutls != 2.2.4 gnutls != 2.8.0 gnutls != 2.8.1" --cflags --libs',
-                       msg='Checking for gnutls >= 1.4.0 and broken versions', mandatory=False)
+        if conf.CHECK_CFG(package='gnutls',
+                          args='"gnutls >= 3.4.7" --cflags --libs',
+                          msg='Checking for gnutls >= 3.4.7',
+                          mandatory=False):
+            conf.DEFINE('HAVE_GNUTLS_3_4_7', 1)
+            conf.DEFINE('HAVE_GNUTLS3', 1)
+        elif conf.CHECK_CFG(package='gnutls',
+                            args='"gnutls >= 3.0.0" --cflags --libs',
+                            msg='Checking for gnutls >= 3.0.0s', mandatory=False):
+            conf.DEFINE('HAVE_GNUTLS3', 1)
+        else:
+            conf.CHECK_CFG(package='gnutls',
+                           args='"gnutls >= 1.4.0 gnutls != 2.2.4 gnutls != 2.8.0 gnutls != 2.8.1" --cflags --libs',
+                           msg='Checking for gnutls >= 1.4.0 and broken versions', mandatory=False)
 
     if 'HAVE_GNUTLS' in conf.env:
         conf.DEFINE('ENABLE_GNUTLS', 1)
diff --git a/source4/lib/wmi/tools/wmis.c b/source4/lib/wmi/tools/wmis.c
index 314fdd1..c4c8ed9 100644
--- a/source4/lib/wmi/tools/wmis.c
+++ b/source4/lib/wmi/tools/wmis.c
@@ -102,7 +102,8 @@ WERROR WBEM_ConnectServer(struct com_context *ctx, const char *server, const cha
 {
 	struct GUID clsid;
 	struct GUID iid;
-	WERROR result, coresult;
+	WERROR result;
+	HRESULT coresult;
 	struct IUnknown **mqi;
 	struct IWbemLevel1Login *pL;
 
diff --git a/source4/lib/wmi/wmi_wrap.c b/source4/lib/wmi/wmi_wrap.c
index dfbf636..a4aaf1b 100644
--- a/source4/lib/wmi/wmi_wrap.c
+++ b/source4/lib/wmi/wmi_wrap.c
@@ -239,7 +239,7 @@
    swig errors code.
 
    Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
-   allows to return the 'cast rank', for example, if you have this
+   allows one to return the 'cast rank', for example, if you have this
 
        int food(double)
        int fooi(int);
diff --git a/source4/lib/wmi/wmicore.c b/source4/lib/wmi/wmicore.c
index 7624946..dc9fee4 100644
--- a/source4/lib/wmi/wmicore.c
+++ b/source4/lib/wmi/wmicore.c
@@ -57,7 +57,8 @@ WERROR WBEM_ConnectServer(struct com_context *ctx, const char *server, const uin
 {
         struct GUID clsid;
         struct GUID iid;
-        WERROR result, coresult;
+        WERROR result;
+	HRESULT coresult;
         struct IUnknown **mqi;
         struct IWbemLevel1Login *pL;
 
diff --git a/source4/libcli/dgram/dgramsocket.c b/source4/libcli/dgram/dgramsocket.c
index cd6d3e4..b6e7dd1 100644
--- a/source4/libcli/dgram/dgramsocket.c
+++ b/source4/libcli/dgram/dgramsocket.c
@@ -231,7 +231,7 @@ NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
 		goto failed;
 	}
 
-	DLIST_ADD_END(dgmsock->send_queue, req, struct nbt_dgram_request *);
+	DLIST_ADD_END(dgmsock->send_queue, req);
 
 	TEVENT_FD_WRITEABLE(dgmsock->fde);
 
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
index 94367a1..97a83ce 100644
--- a/source4/libcli/ldap/ldap_client.c
+++ b/source4/libcli/ldap/ldap_client.c
@@ -223,7 +223,7 @@ static void ldap_connection_recv_next(struct ldap_connection *conn)
 	}
 
 	/*
-	 * The minimun size of a LDAP pdu is 7 bytes
+	 * The minimum size of a LDAP pdu is 7 bytes
 	 *
 	 * dumpasn1 -hh ldap-unbind-min.dat
 	 *
@@ -662,15 +662,50 @@ static void ldap_reconnect(struct ldap_connection *conn)
 	}
 }
 
+static void ldap_request_destructor_abandon(struct ldap_request *abandon)
+{
+	TALLOC_FREE(abandon);
+}
+
 /* destroy an open ldap request */
 static int ldap_request_destructor(struct ldap_request *req)
 {
 	if (req->state == LDAP_REQUEST_PENDING) {
+		struct ldap_message msg = {
+			.type = LDAP_TAG_AbandonRequest,
+			.r.AbandonRequest.messageid = req->messageid,
+		};
+		struct ldap_request *abandon = NULL;
+
 		DLIST_REMOVE(req->conn->pending, req);
+
+		abandon = ldap_request_send(req->conn, &msg);
+		if (abandon == NULL) {
+			ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
+			return 0;
+		}
+		abandon->async.fn = ldap_request_destructor_abandon;
+		abandon->async.private_data = NULL;
 	}
+
 	return 0;
 }
 
+static void ldap_request_timeout_abandon(struct ldap_request *abandon)
+{
+	struct ldap_request *req =
+		talloc_get_type_abort(abandon->async.private_data,
+		struct ldap_request);
+
+	if (req->state == LDAP_REQUEST_PENDING) {
+		DLIST_REMOVE(req->conn->pending, req);
+	}
+	req->state = LDAP_REQUEST_DONE;
+	if (req->async.fn) {
+		req->async.fn(req);
+	}
+}
+
 /*
   called on timeout of a ldap request
 */
@@ -683,7 +718,22 @@ static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer
 
 	req->status = NT_STATUS_IO_TIMEOUT;
 	if (req->state == LDAP_REQUEST_PENDING) {
+		struct ldap_message msg = {
+			.type = LDAP_TAG_AbandonRequest,
+			.r.AbandonRequest.messageid = req->messageid,
+		};
+		struct ldap_request *abandon = NULL;
+
+		abandon = ldap_request_send(req->conn, &msg);
+		if (abandon == NULL) {
+			ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
+			return;
+		}
+		talloc_reparent(req->conn, req, abandon);
+		abandon->async.fn = ldap_request_timeout_abandon;
+		abandon->async.private_data = req;
 		DLIST_REMOVE(req->conn->pending, req);
+		return;
 	}
 	req->state = LDAP_REQUEST_DONE;
 	if (req->async.fn) {
diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c
index f910acb..14a80af 100644
--- a/source4/libcli/ldap/ldap_controls.c
+++ b/source4/libcli/ldap/ldap_controls.c
@@ -512,10 +512,10 @@ static bool encode_verify_name_request(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -716,10 +716,10 @@ static bool encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -774,10 +774,10 @@ static bool encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -809,10 +809,10 @@ static bool encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -837,10 +837,10 @@ static bool encode_sd_flags_request(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -865,10 +865,10 @@ static bool encode_search_options_request(void *mem_ctx, void *in, DATA_BLOB *ou
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -897,10 +897,10 @@ static bool encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -935,10 +935,10 @@ static bool encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -971,10 +971,10 @@ static bool encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -1047,10 +1047,10 @@ static bool encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -1089,10 +1089,10 @@ static bool encode_vlv_response(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 
 	return true;
@@ -1140,10 +1140,10 @@ static bool encode_openldap_dereference(void *mem_ctx, void *in, DATA_BLOB *out)
 		return false;
 	}
 
-	*out = data_blob_talloc(mem_ctx, data->data, data->length);
-	if (out->data == NULL) {
+	if (!asn1_extract_blob(data, mem_ctx, out)) {
 		return false;
 	}
+
 	talloc_free(data);
 	return true;
 }
@@ -1256,6 +1256,7 @@ static const struct ldap_control_handler ldap_known_controls[] = {
 	{ LDB_CONTROL_SORT_RESP_OID, decode_server_sort_response, encode_server_sort_response },
 	{ LDB_CONTROL_ASQ_OID, decode_asq_control, encode_asq_control },
 	{ LDB_CONTROL_DIRSYNC_OID, decode_dirsync_request, encode_dirsync_request },
+	{ LDB_CONTROL_DIRSYNC_EX_OID, decode_dirsync_request, encode_dirsync_request },
 	{ LDB_CONTROL_VLV_REQ_OID, decode_vlv_request, encode_vlv_request },
 	{ LDB_CONTROL_VLV_RESP_OID, decode_vlv_response, encode_vlv_response },
 	{ LDB_CONTROL_PERMISSIVE_MODIFY_OID, decode_flag_request, encode_flag_request },
diff --git a/source4/libcli/ldap/wscript_build b/source4/libcli/ldap/wscript_build
index f79cc2b..1242673 100644
--- a/source4/libcli/ldap/wscript_build
+++ b/source4/libcli/ldap/wscript_build
@@ -3,8 +3,8 @@
 bld.SAMBA_LIBRARY('cli-ldap',
                   source='ldap_client.c ldap_bind.c ldap_ildap.c ldap_controls.c',
                   autoproto='ldap_proto.h',
-                  public_deps='errors tevent',
-                  public_headers='libcli_ldap.h:ldap-util.h',
+                  public_deps='samba-errors tevent',
+                  private_headers='libcli_ldap.h:ldap-util.h',
                   deps='cli_composite LIBSAMBA_TSOCKET samba_socket NDR_SAMR LIBTLS ndr LP_RESOLVE gensec cli-ldap-common',
                   private_library=True
                   )
diff --git a/source4/libcli/pysmb.c b/source4/libcli/pysmb.c
index dde37e0..edddd17 100644
--- a/source4/libcli/pysmb.c
+++ b/source4/libcli/pysmb.c
@@ -98,7 +98,7 @@ static NTSTATUS do_smb_connect(TALLOC_CTX *mem_ctx, struct smb_private_data *spd
 /*
  * Read SMB file and return the contents of the file as python string
  */
-static PyObject * py_smb_loadfile(pytalloc_Object *self, PyObject *args)
+static PyObject * py_smb_loadfile(PyObject *self, PyObject *args)
 {
 	struct smb_composite_loadfile io;
 	const char *filename;
@@ -113,8 +113,8 @@ static PyObject * py_smb_loadfile(pytalloc_Object *self, PyObject *args)
 
 	io.in.fname = filename;
 
-	spdata = self->ptr;
-	status = smb_composite_loadfile(spdata->tree, self->talloc_ctx, &io);
+	spdata = pytalloc_get_ptr(self);
+	status = smb_composite_loadfile(spdata->tree, pytalloc_get_mem_ctx(self), &io);
 	PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
 	return Py_BuildValue("s#", io.out.data, io.out.size);
@@ -123,7 +123,7 @@ static PyObject * py_smb_loadfile(pytalloc_Object *self, PyObject *args)
 /*
  * Create a SMB file with given string as the contents
  */
-static PyObject * py_smb_savefile(pytalloc_Object *self, PyObject *args)
+static PyObject * py_smb_savefile(PyObject *self, PyObject *args)
 {
 	struct smb_composite_savefile io;
 	const char *filename;
@@ -139,7 +139,7 @@ static PyObject * py_smb_savefile(pytalloc_Object *self, PyObject *args)
 	io.in.data = (unsigned char *)data;
 	io.in.size = strlen(data);
 
-	spdata = self->ptr;
+	spdata = pytalloc_get_ptr(self);
 	status = smb_composite_savefile(spdata->tree, &io);
 	PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
@@ -180,7 +180,7 @@ static void py_smb_list_callback(struct clilist_file_info *f, const char *mask,
 /*
  * List the directory contents for specified directory (Ignore '.' and '..' dirs)
  */
-static PyObject *py_smb_list(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_smb_list(PyObject *self, PyObject *args, PyObject *kwargs)
 {
 	struct smb_private_data *spdata;
 	PyObject *py_dirlist;
@@ -198,13 +198,13 @@ static PyObject *py_smb_list(pytalloc_Object *self, PyObject *args, PyObject *kw
 	}
 
 	if (user_mask == NULL) {
-		mask = talloc_asprintf(self->talloc_ctx, "%s\\*", base_dir);
+		mask = talloc_asprintf(pytalloc_get_mem_ctx(self), "%s\\*", base_dir);
 	} else {
-		mask = talloc_asprintf(self->talloc_ctx, "%s\\%s", base_dir, user_mask);
+		mask = talloc_asprintf(pytalloc_get_mem_ctx(self), "%s\\%s", base_dir, user_mask);
 	}
 	dos_format(mask);
 
-	spdata = self->ptr;
+	spdata = pytalloc_get_ptr(self);
 
 	if((py_dirlist = PyList_New(0)) == NULL) {
 		PyErr_NoMemory();
@@ -221,7 +221,7 @@ static PyObject *py_smb_list(pytalloc_Object *self, PyObject *args, PyObject *kw
 /*
  * Create a directory
  */
-static PyObject *py_smb_mkdir(pytalloc_Object *self, PyObject *args)
+static PyObject *py_smb_mkdir(PyObject *self, PyObject *args)
 {
 	NTSTATUS status;
 	const char *dirname;
@@ -231,7 +231,7 @@ static PyObject *py_smb_mkdir(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	spdata = self->ptr;	
+	spdata = pytalloc_get_ptr(self);
 	status = smbcli_mkdir(spdata->tree, dirname);
 	PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
@@ -241,7 +241,7 @@ static PyObject *py_smb_mkdir(pytalloc_Object *self, PyObject *args)
 /*
  * Remove a directory
  */
-static PyObject *py_smb_rmdir(pytalloc_Object *self, PyObject *args)
+static PyObject *py_smb_rmdir(PyObject *self, PyObject *args)
 {
 	NTSTATUS status;
 	const char *dirname;
@@ -251,7 +251,7 @@ static PyObject *py_smb_rmdir(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	spdata = self->ptr;	
+	spdata = pytalloc_get_ptr(self);
 	status = smbcli_rmdir(spdata->tree, dirname);
 	PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
@@ -261,7 +261,7 @@ static PyObject *py_smb_rmdir(pytalloc_Object *self, PyObject *args)
 /*
  * Remove a directory and all its contents
  */
-static PyObject *py_smb_deltree(pytalloc_Object *self, PyObject *args)
+static PyObject *py_smb_deltree(PyObject *self, PyObject *args)
 {
 	int status;
 	const char *dirname;
@@ -271,7 +271,7 @@ static PyObject *py_smb_deltree(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	spdata = self->ptr;
+	spdata = pytalloc_get_ptr(self);
 	status = smbcli_deltree(spdata->tree, dirname);
 	if (status <= 0) {
 		return NULL;
@@ -283,7 +283,7 @@ static PyObject *py_smb_deltree(pytalloc_Object *self, PyObject *args)
 /*
  * Check existence of a path
  */
-static PyObject *py_smb_chkpath(pytalloc_Object *self, PyObject *args)
+static PyObject *py_smb_chkpath(PyObject *self, PyObject *args)
 {
 	NTSTATUS status;
 	const char *path;
@@ -293,7 +293,7 @@ static PyObject *py_smb_chkpath(pytalloc_Object *self, PyObject *args)
 		return NULL;
 	}
 
-	spdata = self->ptr;	
+	spdata = pytalloc_get_ptr(self);
 	status = smbcli_chkpath(spdata->tree, path);
 
 	if (NT_STATUS_IS_OK(status)) {
@@ -306,7 +306,7 @@ static PyObject *py_smb_chkpath(pytalloc_Object *self, PyObject *args)
 /*
  * Read ACL on a given file/directory as a security descriptor object
  */
-static PyObject *py_smb_getacl(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_smb_getacl(PyObject *self, PyObject *args, PyObject *kwargs)
 {
 	NTSTATUS status;
 	union smb_open io;
@@ -323,7 +323,7 @@ static PyObject *py_smb_getacl(pytalloc_Object *self, PyObject *args, PyObject *
 
 	ZERO_STRUCT(io);
 
-	spdata = self->ptr;	
+	spdata = pytalloc_get_ptr(self);
 
 	io.generic.level = RAW_OPEN_NTCREATEX;
 	io.ntcreatex.in.root_fid.fnum = 0;
@@ -339,7 +339,7 @@ static PyObject *py_smb_getacl(pytalloc_Object *self, PyObject *args, PyObject *
 	io.ntcreatex.in.security_flags = 0;
 	io.ntcreatex.in.fname = filename;
 	
-	status = smb_raw_open(spdata->tree, self->talloc_ctx, &io);
+	status = smb_raw_open(spdata->tree, pytalloc_get_mem_ctx(self), &io);
 	PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
 	fnum = io.ntcreatex.out.file.fnum;
@@ -360,19 +360,19 @@ static PyObject *py_smb_getacl(pytalloc_Object *self, PyObject *args, PyObject *
 						SECINFO_PROTECTED_SACL |
 						SECINFO_UNPROTECTED_SACL;
 
-	status = smb_raw_query_secdesc(spdata->tree, self->talloc_ctx, &fio);
+	status = smb_raw_query_secdesc(spdata->tree, pytalloc_get_mem_ctx(self), &fio);
 	smbcli_close(spdata->tree, fnum);
 
 	PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
 	return py_return_ndr_struct("samba.dcerpc.security", "descriptor",
-				self->talloc_ctx, fio.query_secdesc.out.sd);
+				pytalloc_get_mem_ctx(self), fio.query_secdesc.out.sd);
 }
 
 /*
  * Set ACL on file/directory using given security descriptor object
  */
-static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_smb_setacl(PyObject *self, PyObject *args, PyObject *kwargs)
 {
 	NTSTATUS status;
 	union smb_open io;
@@ -388,7 +388,7 @@ static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *
 		return NULL;
 	}
 
-	spdata = self->ptr;
+	spdata = pytalloc_get_ptr(self);
 
 	sd = pytalloc_get_type(py_sd, struct security_descriptor);
 	if (!sd) {
@@ -400,7 +400,7 @@ static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *
 
 	ZERO_STRUCT(io);
 
-	spdata = self->ptr;	
+	spdata = pytalloc_get_ptr(self);
 
 	io.generic.level = RAW_OPEN_NTCREATEX;
 	io.ntcreatex.in.root_fid.fnum = 0;
@@ -416,7 +416,7 @@ static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *
 	io.ntcreatex.in.security_flags = 0;
 	io.ntcreatex.in.fname = filename;
 	
-	status = smb_raw_open(spdata->tree, self->talloc_ctx, &io);
+	status = smb_raw_open(spdata->tree, pytalloc_get_mem_ctx(self), &io);
 	PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
 	fnum = io.ntcreatex.out.file.fnum;
@@ -450,7 +450,7 @@ static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *
 /*
  * Open the file with the parameters passed in and return an object if OK
  */
-static PyObject *py_open_file(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_open_file(PyObject *self, PyObject *args, PyObject *kwargs)
 {
 	NTSTATUS status;
 	union smb_open io;
@@ -475,7 +475,7 @@ static PyObject *py_open_file(pytalloc_Object *self, PyObject *args, PyObject *k
 
 	ZERO_STRUCT(io);
 
-	spdata = self->ptr;	
+	spdata = pytalloc_get_ptr(self);
 
 	mem_ctx = talloc_new(NULL);
 
@@ -505,7 +505,7 @@ static PyObject *py_open_file(pytalloc_Object *self, PyObject *args, PyObject *k
 /*
  * Close the file based on the fnum passed in
  */
-static PyObject *py_close_file(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_close_file(PyObject *self, PyObject *args, PyObject *kwargs)
 {
 	struct smb_private_data *spdata;
 	int fnum;
@@ -514,7 +514,7 @@ static PyObject *py_close_file(pytalloc_Object *self, PyObject *args, PyObject *
 		return NULL;
 	}
 
-	spdata = self->ptr;	
+	spdata = pytalloc_get_ptr(self);
 
 	/*
 	 * Should check the status ...
@@ -525,10 +525,10 @@ static PyObject *py_close_file(pytalloc_Object *self, PyObject *args, PyObject *
 }
 
 static PyMethodDef py_smb_methods[] = {
-	{ "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
+	{ "loadfile", py_smb_loadfile, METH_VARARGS,
 		"loadfile(path) -> file contents as a string\n\n \
 		Read contents of a file." },
-	{ "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
+	{ "savefile", py_smb_savefile, METH_VARARGS,
 		"savefile(path, str) -> None\n\n \
 		Write string str to file." },
 	{ "list", (PyCFunction)py_smb_list, METH_VARARGS|METH_KEYWORDS,
@@ -539,16 +539,16 @@ static PyMethodDef py_smb_methods[] = {
 		\tsize: File size in bytes\n \
 		\tattrib: Attributes\n \
 		\tmtime: Modification time\n" },
-	{ "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
+	{ "mkdir", py_smb_mkdir, METH_VARARGS,
 		"mkdir(path) -> None\n\n \
 		Create a directory." },
-	{ "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
+	{ "rmdir", py_smb_rmdir, METH_VARARGS,
 		"rmdir(path) -> None\n\n \
 		Delete a directory." },
-	{ "deltree", (PyCFunction)py_smb_deltree, METH_VARARGS,
+	{ "deltree", py_smb_deltree, METH_VARARGS,
 		"deltree(path) -> None\n\n \
 		Delete a directory and all its contents." },
-	{ "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
+	{ "chkpath", py_smb_chkpath, METH_VARARGS,
 		"chkpath(path) -> True or False\n\n \
 		Return true if path exists, false otherwise." },
 	{ "get_acl", (PyCFunction)py_smb_getacl, METH_VARARGS,
@@ -573,9 +573,10 @@ static PyObject *py_smb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs
 	const char *kwnames[] = { "hostname", "service", "creds", "lp", NULL };
 	const char *hostname = NULL;
 	const char *service = NULL;
-	pytalloc_Object *smb;
+	PyObject *smb;
 	struct smb_private_data *spdata;
 	NTSTATUS status;
+	TALLOC_CTX *frame = NULL;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zz|OO",
 					discard_const_p(char *, kwnames),
@@ -583,51 +584,42 @@ static PyObject *py_smb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs
 		return NULL;
 	}
 
-	smb = (pytalloc_Object *)type->tp_alloc(type, 0);
-	if (smb == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-	smb->talloc_ctx = talloc_new(NULL);
-	if (smb->talloc_ctx == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
+	frame = talloc_stackframe();
 
-	spdata = talloc_zero(smb->talloc_ctx, struct smb_private_data);
+	spdata = talloc_zero(frame, struct smb_private_data);
 	if (spdata == NULL) {
 		PyErr_NoMemory();
-		Py_DECREF(smb);
+		TALLOC_FREE(frame);
 		return NULL;
 	}
 
-	spdata->lp_ctx = lpcfg_from_py_object(smb->talloc_ctx, py_lp);
+	spdata->lp_ctx = lpcfg_from_py_object(spdata, py_lp);
 	if (spdata->lp_ctx == NULL) {
-		Py_DECREF(smb);
+		TALLOC_FREE(frame);
 		return NULL;
 	}
 	spdata->creds = PyCredentials_AsCliCredentials(py_creds);
-	spdata->ev_ctx = s4_event_context_init(smb->talloc_ctx);
+	spdata->ev_ctx = s4_event_context_init(spdata);
 	if (spdata->ev_ctx == NULL) {
 		PyErr_NoMemory();
-		Py_DECREF(smb);
+		TALLOC_FREE(frame);
 		return NULL;
 	}
 
-	status = do_smb_connect(smb->talloc_ctx, spdata, hostname, service, &spdata->tree);
+	status = do_smb_connect(spdata, spdata, hostname, service, &spdata->tree);
 	PyErr_NTSTATUS_IS_ERR_RAISE(status);
 	if (spdata->tree == NULL) {
-		Py_DECREF(smb);
+		TALLOC_FREE(frame);
 		return NULL;
 	}
 
-	smb->ptr = spdata;
-	return (PyObject *)smb;
+	smb = pytalloc_steal(type, spdata);
+	TALLOC_FREE(frame);
+	return smb;
 }
 
 static PyTypeObject PySMB = {
 	.tp_name = "smb.SMB",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_new = py_smb_new,
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 	.tp_methods = py_smb_methods,
@@ -638,14 +630,8 @@ static PyTypeObject PySMB = {
 void initsmb(void)
 {
 	PyObject *m;
-	PyTypeObject *talloc_type = pytalloc_GetObjectType();
-	if (talloc_type == NULL) {
-		return;
-	}
-
-	PySMB.tp_base = talloc_type;
 
-	if (PyType_Ready(&PySMB) < 0) {
+	if (pytalloc_BaseObject_PyType_Ready(&PySMB) < 0) {
 		return;
 	}
 
diff --git a/source4/libcli/raw/smbclient-raw.pc.in b/source4/libcli/raw/smbclient-raw.pc.in
deleted file mode 100644
index 3c0c791..0000000
--- a/source4/libcli/raw/smbclient-raw.pc.in
+++ /dev/null
@@ -1,10 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: smbclient-raw
-Description: SMB client
-Version: @PACKAGE_VERSION@
-Libs: @LIB_RPATH@ -L${libdir} -lsmbclient-raw
-Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1
diff --git a/source4/libcli/resolve/resolve.c b/source4/libcli/resolve/resolve.c
index b5930aa..1390300 100644
--- a/source4/libcli/resolve/resolve.c
+++ b/source4/libcli/resolve/resolve.c
@@ -75,7 +75,7 @@ bool resolve_context_add_method(struct resolve_context *ctx, resolve_name_send_f
 	method->send_fn = send_fn;
 	method->recv_fn = recv_fn;
 	method->privdata = userdata;
-	DLIST_ADD_END(ctx->methods, method, struct resolve_method *);
+	DLIST_ADD_END(ctx->methods, method);
 	return true;
 }
 
diff --git a/source4/libcli/smb2/wscript_build b/source4/libcli/smb2/wscript_build
index 02fc5b8..a15753f 100644
--- a/source4/libcli/smb2/wscript_build
+++ b/source4/libcli/smb2/wscript_build
@@ -5,6 +5,6 @@ bld.SAMBA_SUBSYSTEM('LIBCLI_SMB2',
 	autoproto='smb2_proto.h',
 	deps='tevent-util cli_smb_common',
 	public_deps='smbclient-raw gensec samba-credentials tevent',
-	public_headers='smb2.h',
+	private_headers='smb2.h',
 	)
 
diff --git a/source4/libcli/wbclient/wscript_build b/source4/libcli/wbclient/wscript_build
index cf28887..f3cb3af 100644
--- a/source4/libcli/wbclient/wscript_build
+++ b/source4/libcli/wbclient/wscript_build
@@ -2,7 +2,7 @@
 
 bld.SAMBA_LIBRARY('LIBWBCLIENT_OLD',
                   source='wbclient.c',
-                  public_deps='errors events',
+                  public_deps='samba-errors events',
                   cflags='-DWINBINDD_SOCKET_DIR=\"%s\"' % bld.env.WINBINDD_SOCKET_DIR,
                   deps='WB_REQTRANS NDR_WINBIND MESSAGING RPC_NDR_WINBIND',
                   private_library=True
diff --git a/source4/libcli/wscript_build b/source4/libcli/wscript_build
index 59b0bc7..38a8f4e 100755
--- a/source4/libcli/wscript_build
+++ b/source4/libcli/wscript_build
@@ -28,12 +28,12 @@ bld.SAMBA_SUBSYSTEM('LIBCLI_SMB_COMPOSITE',
 	source='smb_composite/loadfile.c smb_composite/savefile.c smb_composite/connect.c smb_composite/sesssetup.c smb_composite/fetchfile.c smb_composite/appendacl.c smb_composite/fsinfo.c smb_composite/smb2.c',
 	deps='LIBCLI_SMB2 tevent-util',
 	public_deps='cli_composite samba-credentials gensec LIBCLI_RESOLVE tevent',
-	public_headers='smb_composite/smb_composite.h',
+	private_headers='smb_composite/smb_composite.h',
 	)
 
 bld.SAMBA_PYTHON('pysmb',
     source='pysmb.c',
-    deps='LIBCLI_SMB_COMPOSITE LIBCLI_SMB2 tevent-util pyparam_util',
+    deps='LIBCLI_SMB_COMPOSITE LIBCLI_SMB2 tevent-util pyparam_util pytalloc-util',
 	public_deps='cli_composite samba-credentials gensec LIBCLI_RESOLVE tevent param_options',
     realname='samba/smb.so'
     )
@@ -75,8 +75,8 @@ bld.SAMBA_SUBSYSTEM('LIBCLI_FINDDCS',
 
 bld.SAMBA_SUBSYSTEM('LIBCLI_SMB',
 	source='clireadwrite.c cliconnect.c clifile.c clilist.c clitrans2.c climessage.c clideltree.c',
-	public_headers='libcli.h:smb_cli.h',
-	public_deps='smbclient-raw errors LIBCLI_AUTH LIBCLI_SMB_COMPOSITE cli-nbt samba-security LIBCLI_RESOLVE LIBCLI_DGRAM LIBCLI_SMB2 LIBCLI_FINDDCS samba_socket'
+	private_headers='libcli.h:smb_cli.h',
+	public_deps='smbclient-raw samba-errors LIBCLI_AUTH LIBCLI_SMB_COMPOSITE cli-nbt samba-security LIBCLI_RESOLVE LIBCLI_DGRAM LIBCLI_SMB2 LIBCLI_FINDDCS samba_socket'
 	)
 
 
@@ -84,11 +84,9 @@ bld.SAMBA_LIBRARY('smbclient-raw',
 	source='raw/rawfile.c raw/smb_signing.c raw/clisocket.c raw/clitransport.c raw/clisession.c raw/clitree.c raw/clierror.c raw/rawrequest.c raw/rawreadwrite.c raw/rawsearch.c raw/rawsetfileinfo.c raw/raweas.c raw/rawtrans.c raw/clioplock.c raw/rawnegotiate.c raw/rawfsinfo.c raw/rawfileinfo.c raw/rawnotify.c raw/rawioctl.c raw/rawacl.c raw/rawdate.c raw/rawlpq.c raw/rawshadow.c',
 	autoproto='raw/raw_proto.h',
 	public_deps='samba_socket LIBPACKET LIBCRYPTO',
-	deps='cli_composite LIBCLI_RESOLVE samba-security ndr samba-util errors charset talloc LIBCLI_SMB_COMPOSITE tevent cli_smb_common',
-	public_headers='raw/request.h:smb_request.h raw/signing.h:smb_raw_signing.h raw/libcliraw.h:smb_cliraw.h raw/interfaces.h:smb_raw_interfaces.h raw/smb.h:smb_raw.h raw/trans2.h:smb_raw_trans2.h',
-	private_library=False,
-	pc_files='raw/smbclient-raw.pc',
-	vnum='0.0.1'
+	deps='cli_composite LIBCLI_RESOLVE samba-security ndr samba-util samba-errors charset talloc LIBCLI_SMB_COMPOSITE tevent cli_smb_common',
+	private_headers='raw/request.h:smb_request.h raw/signing.h:smb_raw_signing.h raw/libcliraw.h:smb_cliraw.h raw/interfaces.h:smb_raw_interfaces.h raw/smb.h:smb_raw.h raw/trans2.h:smb_raw_trans2.h',
+	private_library=True,
 	)
 
 bld.RECURSE('smb2')
diff --git a/source4/libnet/libnet_vampire.c b/source4/libnet/libnet_vampire.c
index 69195af..97c6d1a 100644
--- a/source4/libnet/libnet_vampire.c
+++ b/source4/libnet/libnet_vampire.c
@@ -553,6 +553,7 @@ NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
 	const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
 	struct dsdb_extended_replicated_objects *objs;
 	uint32_t req_replica_flags;
+	uint32_t dsdb_repl_flags = 0;
 	struct repsFromTo1 *s_dsa;
 	char *tmp_dns_name;
 	uint32_t i;
@@ -679,6 +680,14 @@ NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
+	if (req_replica_flags & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
+		dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
+	}
+
+	if (req_replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
+		dsdb_repl_flags |= DSDB_REPL_FLAG_EXPECT_NO_SECRETS;
+	}
+
 	status = dsdb_replicated_objects_convert(s->ldb,
 						 schema,
 						 c->partition->nc.dn,
@@ -690,7 +699,7 @@ NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
 						 s_dsa,
 						 uptodateness_vector,
 						 c->gensec_skey,
-						 0,
+						 dsdb_repl_flags,
 						 s, &objs);
 	if (!W_ERROR_IS_OK(status)) {
 		DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
@@ -748,285 +757,3 @@ NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS update_dnshostname_for_server(TALLOC_CTX *mem_ctx,
-					      struct ldb_context *ldb,
-					      const char *server_dn_str,
-					      const char *netbios_name,
-					      const char *realm)
-{
-	int ret;
-	struct ldb_message *msg;
-	struct ldb_message_element *el;
-	struct ldb_dn *server_dn;
-	const char *dNSHostName = strlower_talloc(mem_ctx,
-						  talloc_asprintf(mem_ctx,
-								  "%s.%s",
-								  netbios_name,
-								  realm));
-	msg = ldb_msg_new(mem_ctx);
-	if (msg == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	server_dn = ldb_dn_new(mem_ctx, ldb, server_dn_str);
-	if (!server_dn) {
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	msg->dn = server_dn;
-	ret = ldb_msg_add_empty(msg, "dNSHostName", LDB_FLAG_MOD_ADD, &el);
-	if (ret != LDB_SUCCESS) {
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	ret = ldb_msg_add_steal_string(msg,
-				       "dNSHostName",
-				       talloc_asprintf(el->values, "%s", dNSHostName));
-	if (ret != LDB_SUCCESS) {
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	ret = dsdb_modify(ldb, msg, DSDB_MODIFY_PERMISSIVE);
-	if (ret != LDB_SUCCESS) {
-		DEBUG(0,(__location__ ": Failed to add dnsHostName to the Server object: %s\n",
-			 ldb_errstring(ldb)));
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	return NT_STATUS_OK;
-}
-
-
-NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 
-			struct libnet_Vampire *r)
-{
-	struct libnet_JoinDomain *join;
-	struct libnet_Replicate rep;
-	NTSTATUS status;
-
-	const char *account_name;
-	const char *netbios_name;
-	
-	r->out.error_string = NULL;
-
-	join = talloc_zero(mem_ctx, struct libnet_JoinDomain);
-	if (!join) {
-		return NT_STATUS_NO_MEMORY;
-	}
-		
-	if (r->in.netbios_name != NULL) {
-		netbios_name = r->in.netbios_name;
-	} else {
-		netbios_name = talloc_reference(join, lpcfg_netbios_name(ctx->lp_ctx));
-		if (!netbios_name) {
-			talloc_free(join);
-			r->out.error_string = NULL;
-			return NT_STATUS_NO_MEMORY;
-		}
-	}
-
-	account_name = talloc_asprintf(join, "%s$", netbios_name);
-	if (!account_name) {
-		talloc_free(join);
-		r->out.error_string = NULL;
-		return NT_STATUS_NO_MEMORY;
-	}
-	
-	/* Re-use the domain we are joining as the domain for the user
-	 * to be authenticated with, unless they specified
-	 * otherwise */
-	cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
-
-	join->in.domain_name	= r->in.domain_name;
-	join->in.account_name	= account_name;
-	join->in.netbios_name	= netbios_name;
-	join->in.level		= LIBNET_JOINDOMAIN_AUTOMATIC;
-	join->in.acct_type	= ACB_WSTRUST;
-	join->in.recreate_account = false;
-	status = libnet_JoinDomain(ctx, join, join);
-	if (!NT_STATUS_IS_OK(status)) {
-		r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
-		talloc_free(join);
-		return status;
-	}
-
-	rep.in.domain_name   = join->out.domain_name;
-	rep.in.netbios_name  = netbios_name;
-	rep.in.targetdir     = r->in.targetdir;
-	rep.in.domain_sid    = join->out.domain_sid;
-	rep.in.realm         = join->out.realm;
-	rep.in.server        = dcerpc_binding_get_string_option(join->out.samr_binding,
-								"host");
-	rep.in.join_password = join->out.join_password;
-	rep.in.kvno          = join->out.kvno;
-
-	status = libnet_Replicate(ctx, mem_ctx, &rep);
-
-	r->out.domain_sid   = join->out.domain_sid;
-	r->out.domain_name  = join->out.domain_name;
-	r->out.error_string = rep.out.error_string;
-
-	return status;
-}
-
-
-
-NTSTATUS libnet_Replicate(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
-			  struct libnet_Replicate *r)
-{
-	struct provision_store_self_join_settings *set_secrets;
-	struct libnet_BecomeDC b;
-	struct libnet_vampire_cb_state *s;
-	struct ldb_message *msg;
-	const char *error_string;
-	int ldb_ret;
-	uint32_t i;
-	NTSTATUS status;
-	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
-	const char *account_name;
-	const char *netbios_name;
-
-	r->out.error_string = NULL;
-
-	netbios_name = r->in.netbios_name;
-	account_name = talloc_asprintf(tmp_ctx, "%s$", netbios_name);
-	if (!account_name) {
-		talloc_free(tmp_ctx);
-		r->out.error_string = NULL;
-		return NT_STATUS_NO_MEMORY;
-	}
-	
-	/* Re-use the domain we are joining as the domain for the user
-	 * to be authenticated with, unless they specified
-	 * otherwise */
-	cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
-
-	s = libnet_vampire_cb_state_init(mem_ctx, ctx->lp_ctx, ctx->event_ctx,
-					 netbios_name, r->in.domain_name, r->in.realm,
-					 r->in.targetdir);
-	if (!s) {
-		return NT_STATUS_NO_MEMORY;
-	}
-	talloc_steal(s, tmp_ctx);
-
-	ZERO_STRUCT(b);
-
-	/* Be more robust:
-	 * We now know the domain and realm for sure - if they didn't
-	 * put one on the command line, use this for the rest of the
-	 * join */
-	cli_credentials_set_realm(ctx->cred, r->in.realm, CRED_GUESS_ENV);
-	cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
-
-	/* Now set these values into the smb.conf - we probably had
-	 * empty or useless defaults here from whatever smb.conf we
-	 * started with */
-	lpcfg_set_cmdline(s->lp_ctx, "realm", r->in.realm);
-	lpcfg_set_cmdline(s->lp_ctx, "workgroup", r->in.domain_name);
-
-	b.in.domain_dns_name		= r->in.realm;
-	b.in.domain_netbios_name	= r->in.domain_name;
-	b.in.domain_sid			= r->in.domain_sid;
-	b.in.source_dsa_address		= r->in.server;
-	b.in.dest_dsa_netbios_name	= netbios_name;
-
-	b.in.callbacks.private_data	= s;
-	b.in.callbacks.check_options	= libnet_vampire_cb_check_options;
-	b.in.callbacks.prepare_db       = libnet_vampire_cb_prepare_db;
-	b.in.callbacks.schema_chunk	= libnet_vampire_cb_schema_chunk;
-	b.in.callbacks.config_chunk	= libnet_vampire_cb_store_chunk;
-	b.in.callbacks.domain_chunk	= libnet_vampire_cb_store_chunk;
-
-	b.in.rodc_join = lpcfg_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
-
-	status = libnet_BecomeDC(ctx, s, &b);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
-		talloc_free(s);
-		return status;
-	}
-
-	msg = ldb_msg_new(s);
-	if (!msg) {
-		printf("ldb_msg_new() failed\n");
-		talloc_free(s);
-		return NT_STATUS_NO_MEMORY;
-	}
-	msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
-	if (!msg->dn) {
-		printf("ldb_msg_new(@ROOTDSE) failed\n");
-		talloc_free(s);
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
-	if (ldb_ret != LDB_SUCCESS) {
-		printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
-		talloc_free(s);
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	for (i=0; i < msg->num_elements; i++) {
-		msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
-	}
-
-	printf("mark ROOTDSE with isSynchronized=TRUE\n");
-	ldb_ret = ldb_modify(s->ldb, msg);
-	if (ldb_ret != LDB_SUCCESS) {
-		printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
-		talloc_free(s);
-		return NT_STATUS_INTERNAL_DB_ERROR;
-	}
-	/* during dcpromo the 2nd computer adds dNSHostName attribute to his Server object
-	 * the attribute appears on the original DC after replication
-	 */
-	status = update_dnshostname_for_server(s, s->ldb, s->server_dn_str, s->netbios_name, s->realm);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("Failed to update dNSHostName on Server object - %s\n", nt_errstr(status));
-		talloc_free(s);
-		return status;
-	}
-	/* prepare the transaction - this prepares to commit all the changes in
-	   the ldb from the whole vampire.  Note that this 
-	   triggers the writing of the linked attribute backlinks.
-	*/
-	if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
-		printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
-		return NT_STATUS_INTERNAL_DB_ERROR;
-	}
-
-	set_secrets = talloc(s, struct provision_store_self_join_settings);
-	if (!set_secrets) {
-		r->out.error_string = NULL;
-		talloc_free(s);
-		return NT_STATUS_NO_MEMORY;
-	}
-	
-	ZERO_STRUCTP(set_secrets);
-	set_secrets->domain_name = r->in.domain_name;
-	set_secrets->realm = r->in.realm;
-	set_secrets->netbios_name = netbios_name;
-	set_secrets->secure_channel_type = SEC_CHAN_BDC;
-	set_secrets->machine_password = r->in.join_password;
-	set_secrets->key_version_number = r->in.kvno;
-	set_secrets->domain_sid = r->in.domain_sid;
-	
-	status = provision_store_self_join(ctx, s->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
-	if (!NT_STATUS_IS_OK(status)) {
-		r->out.error_string = talloc_steal(mem_ctx, error_string);
-		talloc_free(s);
-		return status;
-	}
-
-	/* commit the transaction now we know the secrets were written
-	 * out properly
-	*/
-	if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
-		printf("Failed to commit vampire transaction\n");
-		return NT_STATUS_INTERNAL_DB_ERROR;
-	}
-
-	talloc_free(s);
-
-	return NT_STATUS_OK;
-}
diff --git a/source4/libnet/py_net.c b/source4/libnet/py_net.c
index 3fcbf05..48009b2 100644
--- a/source4/libnet/py_net.c
+++ b/source4/libnet/py_net.c
@@ -293,61 +293,6 @@ static PyObject *py_net_user_delete(py_net_Object *self, PyObject *args, PyObjec
 static const char py_net_delete_user_doc[] = "delete_user(username)\n"
 "Delete a user.";
 
-static PyObject *py_dom_sid_FromSid(struct dom_sid *sid)
-{
-	PyObject *mod_security, *dom_sid_Type;
-
-	mod_security = PyImport_ImportModule("samba.dcerpc.security");
-	if (mod_security == NULL)
-		return NULL;
-
-	dom_sid_Type = PyObject_GetAttrString(mod_security, "dom_sid");
-	if (dom_sid_Type == NULL)
-		return NULL;
-
-	return pytalloc_reference((PyTypeObject *)dom_sid_Type, sid);
-}
-
-static PyObject *py_net_vampire(py_net_Object *self, PyObject *args, PyObject *kwargs)
-{
-	const char *kwnames[] = { "domain", "target_dir", NULL };
-	NTSTATUS status;
-	TALLOC_CTX *mem_ctx;
-	PyObject *ret;
-	struct libnet_Vampire r;
-
-	ZERO_STRUCT(r);
-
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|z", discard_const_p(char *, kwnames),
-	                                 &r.in.domain_name, &r.in.targetdir)) {
-		return NULL;
-	}
-
-	r.in.netbios_name  = lpcfg_netbios_name(self->libnet_ctx->lp_ctx);
-	r.out.error_string = NULL;
-
-	mem_ctx = talloc_new(NULL);
-	if (mem_ctx == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-
-	status = libnet_Vampire(self->libnet_ctx, mem_ctx, &r);
-
-	if (!NT_STATUS_IS_OK(status)) {
-		PyErr_SetString(PyExc_RuntimeError,
-		                r.out.error_string ? r.out.error_string : nt_errstr(status));
-		talloc_free(mem_ctx);
-		return NULL;
-	}
-
-	ret = Py_BuildValue("(sO)", r.out.domain_name, py_dom_sid_FromSid(r.out.domain_sid));
-
-	talloc_free(mem_ctx);
-
-	return ret;
-}
-
 struct replicate_state {
 	void *vampire_state;
 	dcerpc_InterfaceObject *drs_pipe;
@@ -593,9 +538,6 @@ static PyObject *py_net_finddc(py_net_Object *self, PyObject *args, PyObject *kw
 }
 
 
-static const char py_net_vampire_doc[] = "vampire(domain, target_dir=None)\n"
-					 "Vampire a domain.";
-
 static const char py_net_replicate_init_doc[] = "replicate_init(samdb, lp, drspipe)\n"
 					 "Setup for replicate_chunk calls.";
 
@@ -612,7 +554,6 @@ static PyMethodDef net_obj_methods[] = {
 	{"time", (PyCFunction)py_net_time, METH_VARARGS|METH_KEYWORDS, py_net_time_doc},
 	{"create_user", (PyCFunction)py_net_user_create, METH_VARARGS|METH_KEYWORDS, py_net_create_user_doc},
 	{"delete_user", (PyCFunction)py_net_user_delete, METH_VARARGS|METH_KEYWORDS, py_net_delete_user_doc},
-	{"vampire", (PyCFunction)py_net_vampire, METH_VARARGS|METH_KEYWORDS, py_net_vampire_doc},
 	{"replicate_init", (PyCFunction)py_net_replicate_init, METH_VARARGS|METH_KEYWORDS, py_net_replicate_init_doc},
 	{"replicate_chunk", (PyCFunction)py_net_replicate_chunk, METH_VARARGS|METH_KEYWORDS, py_net_replicate_chunk_doc},
 	{"finddc", (PyCFunction)py_net_finddc, METH_KEYWORDS, py_net_finddc_doc},
diff --git a/source4/libnet/wscript_build b/source4/libnet/wscript_build
index ed38c40..6cca50d 100644
--- a/source4/libnet/wscript_build
+++ b/source4/libnet/wscript_build
@@ -10,7 +10,7 @@ bld.SAMBA_LIBRARY('samba-net',
 
 bld.SAMBA_PYTHON('python_net',
 	source='py_net.c',
-	deps='samba-net pyrpc_util',
+	deps='samba-net pyrpc_util pytalloc-util',
 	realname='samba/net.so'
 	)
 
diff --git a/source4/librpc/dcerpc_atsvc.pc.in b/source4/librpc/dcerpc_atsvc.pc.in
deleted file mode 100644
index f781f23..0000000
--- a/source4/librpc/dcerpc_atsvc.pc.in
+++ /dev/null
@@ -1,11 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: dcerpc_atsvc
-Description: DCE/RPC client library - ATSVC
-Requires.private: dcerpc ndr
-Version: @PACKAGE_VERSION@
-Libs: @LIB_RPATH@ -L${libdir} -ldcerpc-atsvc
-Cflags: -I${includedir}  -DHAVE_IMMEDIATE_STRUCTURES=1
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 6ce0d35..33c3706 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -1245,7 +1245,7 @@ struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
 	subreq->async.callback = dcerpc_bind_fail_handler;
 	subreq->p = p;
 	subreq->recv_handler = dcerpc_bind_recv_handler;
-	DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
+	DLIST_ADD_END(p->conn->pending, subreq);
 	talloc_set_destructor(subreq, dcerpc_req_dequeue);
 
 	status = dcerpc_send_request(p->conn, &blob, true);
@@ -1603,7 +1603,7 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
 	req->request_data.length = stub_data->length;
 	req->request_data.data = stub_data->data;
 
-	DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
+	DLIST_ADD_END(p->conn->request_queue, req);
 	talloc_set_destructor(req, dcerpc_req_dequeue);
 
 	dcerpc_schedule_io_trigger(p->conn);
@@ -2141,7 +2141,7 @@ struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
 	subreq->async.callback = dcerpc_alter_context_fail_handler;
 	subreq->p = p;
 	subreq->recv_handler = dcerpc_alter_context_recv_handler;
-	DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
+	DLIST_ADD_END(p->conn->pending, subreq);
 	talloc_set_destructor(subreq, dcerpc_req_dequeue);
 
 	status = dcerpc_send_request(p->conn, &blob, true);
diff --git a/source4/librpc/rpc/pyrpc.c b/source4/librpc/rpc/pyrpc.c
index 243e96b..948cad2 100644
--- a/source4/librpc/rpc/pyrpc.c
+++ b/source4/librpc/rpc/pyrpc.c
@@ -200,7 +200,7 @@ static PyObject *py_iface_request(PyObject *self, PyObject *args, PyObject *kwar
 	DATA_BLOB data_in, data_out;
 	NTSTATUS status;
 	char *in_data;
-	int in_length;
+	Py_ssize_t in_length;
 	PyObject *ret;
 	PyObject *object = NULL;
 	struct GUID object_guid;
@@ -342,7 +342,6 @@ static PyObject *py_transfer_syntax_ndr_new(PyTypeObject *type, PyObject *args,
 static PyTypeObject py_transfer_syntax_ndr_SyntaxType = {
 	PyObject_HEAD_INIT(NULL) 0,
 	.tp_name = "base.transfer_syntax_ndr",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_doc = "transfer_syntax_ndr()\n",
 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 	.tp_new = py_transfer_syntax_ndr_new,
@@ -356,7 +355,6 @@ static PyObject *py_transfer_syntax_ndr64_new(PyTypeObject *type, PyObject *args
 static PyTypeObject py_transfer_syntax_ndr64_SyntaxType = {
 	PyObject_HEAD_INIT(NULL) 0,
 	.tp_name = "base.transfer_syntax_ndr64",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_doc = "transfer_syntax_ndr64()\n",
 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 	.tp_new = py_transfer_syntax_ndr64_new,
@@ -395,7 +393,6 @@ static PyObject *py_bind_time_features_syntax_new(PyTypeObject *type, PyObject *
 static PyTypeObject py_bind_time_features_syntax_SyntaxType = {
 	PyObject_HEAD_INIT(NULL) 0,
 	.tp_name = "base.bind_time_features_syntax",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_doc = "bind_time_features_syntax(features)\n",
 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 	.tp_new = py_bind_time_features_syntax_new,
@@ -415,8 +412,11 @@ void initbase(void)
 		return;
 
 	py_transfer_syntax_ndr_SyntaxType.tp_base = ndr_syntax_id_Type;
+	py_transfer_syntax_ndr_SyntaxType.tp_basicsize = pytalloc_BaseObject_size();
 	py_transfer_syntax_ndr64_SyntaxType.tp_base = ndr_syntax_id_Type;
+	py_transfer_syntax_ndr64_SyntaxType.tp_basicsize = pytalloc_BaseObject_size();
 	py_bind_time_features_syntax_SyntaxType.tp_base = ndr_syntax_id_Type;
+	py_bind_time_features_syntax_SyntaxType.tp_basicsize = pytalloc_BaseObject_size();
 
 	if (PyType_Ready(&dcerpc_InterfaceType) < 0)
 		return;
diff --git a/source4/librpc/rpc/pyrpc_util.c b/source4/librpc/rpc/pyrpc_util.c
index 226c884..b74eb4c 100644
--- a/source4/librpc/rpc/pyrpc_util.c
+++ b/source4/librpc/rpc/pyrpc_util.c
@@ -349,6 +349,9 @@ void PyErr_SetDCERPCStatus(struct dcerpc_pipe *p, NTSTATUS status)
 
   r_ctx is the context that is a parent of r. It will be referenced by
   the resulting python object
+
+  This MUST only be used by objects that are based on pytalloc_Object
+  otherwise the pytalloc_reference_ex() will fail.
  */
 PyObject *py_return_ndr_struct(const char *module_name, const char *type_name,
 			       TALLOC_CTX *r_ctx, void *r)
diff --git a/source4/librpc/wscript_build b/source4/librpc/wscript_build
index 4da3eaa..a28669a 100755
--- a/source4/librpc/wscript_build
+++ b/source4/librpc/wscript_build
@@ -99,17 +99,6 @@ bld.SAMBA_LIBRARY('dcerpc-samr',
 	header_path='gen_ndr'
 	)
 
-
-bld.SAMBA_LIBRARY('dcerpc-atsvc',
-	source='',
-	pc_files='dcerpc_atsvc.pc',
-	vnum='0.0.1',
-	public_deps='dcerpc ndr-standard RPC_NDR_ATSVC',
-	public_headers='../../librpc/gen_ndr/ndr_atsvc_c.h',
-	header_path='gen_ndr'
-	)
-
-
 bld.SAMBA_SUBSYSTEM('RPC_NDR_WINSIF',
 	source='gen_ndr/ndr_winsif_c.c',
 	public_deps='dcerpc NDR_WINSIF'
@@ -125,10 +114,7 @@ bld.SAMBA_LIBRARY('dcerpc',
 	deps='samba_socket LIBCLI_RESOLVE LIBCLI_SMB LIBCLI_SMB2 ndr NDR_DCERPC RPC_NDR_EPMAPPER NDR_SCHANNEL RPC_NDR_NETLOGON RPC_NDR_MGMT gensec LIBCLI_AUTH smbclient-raw LP_RESOLVE tevent-util dcerpc-binding param_options http',
 	autoproto='rpc/dcerpc_proto.h',
 	public_deps='samba-credentials tevent talloc',
-	public_headers='''rpc/dcerpc.h ../../librpc/gen_ndr/mgmt.h
-	../../librpc/gen_ndr/ndr_mgmt.h ../../librpc/gen_ndr/ndr_mgmt_c.h
-	../../librpc/gen_ndr/epmapper.h ../../librpc/gen_ndr/ndr_epmapper.h
-	../../librpc/gen_ndr/ndr_epmapper_c.h''',
+	public_headers='''rpc/dcerpc.h''',
 	# It's very important to keep this form of construction
 	# it force the sambawaf extension to put everything that match the first element
 	# (*gen_ndr*) into the dir named by the second element (gen_ndr).
@@ -220,7 +206,7 @@ bld.SAMBA_PYTHON('python_mgmt',
 
 bld.SAMBA_PYTHON('python_atsvc',
 	source='../../librpc/gen_ndr/py_atsvc.c',
-	deps='dcerpc-atsvc pytalloc-util pyrpc_util',
+	deps='RPC_NDR_ATSVC pytalloc-util pyrpc_util',
 	realname='samba/dcerpc/atsvc.so'
 	)
 
diff --git a/source4/nbt_server/dgram/netlogon.c b/source4/nbt_server/dgram/netlogon.c
index 0e5294c..c88ffb5 100644
--- a/source4/nbt_server/dgram/netlogon.c
+++ b/source4/nbt_server/dgram/netlogon.c
@@ -31,6 +31,7 @@
 #include "dsdb/samdb/ldb_modules/util.h"
 #include "libcli/security/security.h"
 #include "nbt_server/dgram/proto.h"
+#include "libds/common/roles.h"
 
 /*
   reply to a GETDC request
diff --git a/source4/nbt_server/register.c b/source4/nbt_server/register.c
index f5517b2..08caa11 100644
--- a/source4/nbt_server/register.c
+++ b/source4/nbt_server/register.c
@@ -30,6 +30,7 @@
 #include "librpc/gen_ndr/ndr_nbt.h"
 #include "dsdb/samdb/samdb.h"
 #include "param/param.h"
+#include "libds/common/roles.h"
 
 static void nbtd_start_refresh_timer(struct nbtd_iface_name *iname);
 
@@ -198,7 +199,7 @@ static void nbtd_register_name_iface(struct nbtd_interface *iface,
 	iname->registration_time = timeval_zero();
 	iname->wins_server       = NULL;
 
-	DLIST_ADD_END(iface->names, iname, struct nbtd_iface_name *);
+	DLIST_ADD_END(iface->names, iname);
 
 	if (nb_flags & NBT_NM_PERMANENT) {
 		/* permanent names are not announced and are immediately active */
diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c
index a60d5bd..98789c0 100644
--- a/source4/nbt_server/wins/winsserver.c
+++ b/source4/nbt_server/wins/winsserver.c
@@ -422,7 +422,7 @@ static void wins_register_wack(struct nbt_name_socket *nbtsock,
 	s->io.in.addresses	= winsdb_addr_string_list(s, rec->addresses);
 	if (s->io.in.addresses == NULL) goto failed;
 
-	DLIST_ADD_END(iface->wack_queue, s, struct nbtd_wins_wack_state *);
+	DLIST_ADD_END(iface->wack_queue, s);
 
 	talloc_set_destructor(s, nbtd_wins_wack_state_destructor);
 
diff --git a/source4/ntvfs/ntvfs_base.c b/source4/ntvfs/ntvfs_base.c
index 8058181..d037a0e 100644
--- a/source4/ntvfs/ntvfs_base.c
+++ b/source4/ntvfs/ntvfs_base.c
@@ -190,7 +190,7 @@ NTSTATUS ntvfs_init_connection(TALLOC_CTX *mem_ctx, struct share_config *scfg, e
 			return NT_STATUS_INTERNAL_ERROR;
 		}
 		ntvfs->depth = i;
-		DLIST_ADD_END(ctx->modules, ntvfs, struct ntvfs_module_context *);
+		DLIST_ADD_END(ctx->modules, ntvfs);
 	}
 
 	if (!ctx->modules) {
diff --git a/source4/ntvfs/posix/posix_eadb.h b/source4/ntvfs/posix/posix_eadb.h
index 752d322..14b9439 100644
--- a/source4/ntvfs/posix/posix_eadb.h
+++ b/source4/ntvfs/posix/posix_eadb.h
@@ -16,5 +16,5 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-struct pvfs_state *pvfs;
+struct pvfs_state;
 #include "source4/ntvfs/posix/posix_eadb_proto.h"
diff --git a/source4/ntvfs/posix/pvfs_notify.c b/source4/ntvfs/posix/pvfs_notify.c
index 316353f..91a151b 100644
--- a/source4/ntvfs/posix/pvfs_notify.c
+++ b/source4/ntvfs/posix/pvfs_notify.c
@@ -278,7 +278,7 @@ NTSTATUS pvfs_notify(struct ntvfs_module_context *ntvfs,
 	NT_STATUS_HAVE_NO_MEMORY(pending->req);	
 	pending->info = info;
 
-	DLIST_ADD_END(f->notify_buffer->pending, pending, struct notify_pending *);
+	DLIST_ADD_END(f->notify_buffer->pending, pending);
 
 	/* if the buffer is empty then start waiting */
 	if (f->notify_buffer->num_changes == 0 && 
diff --git a/source4/ntvfs/posix/python/pyposix_eadb.c b/source4/ntvfs/posix/python/pyposix_eadb.c
index ecc2d8a..a94440b 100644
--- a/source4/ntvfs/posix/python/pyposix_eadb.c
+++ b/source4/ntvfs/posix/python/pyposix_eadb.c
@@ -39,7 +39,7 @@ static PyObject *py_wrap_setxattr(PyObject *self, PyObject *args)
 {
 	char *filename, *attribute, *tdbname;
 	DATA_BLOB blob;
-	int blobsize;
+	Py_ssize_t blobsize;
 	NTSTATUS status;
 	TALLOC_CTX *mem_ctx;
 	struct tdb_wrap *eadb;
@@ -110,7 +110,7 @@ static PyObject *py_wrap_getxattr(PyObject *self, PyObject *args)
 static PyMethodDef py_posix_eadb_methods[] = {
 	{ "wrap_getxattr", (PyCFunction)py_wrap_getxattr, METH_VARARGS,
 		"wrap_getxattr(filename,attribute) -> blob\n"
-		"Retreive given attribute on the given file." },
+		"Retrieve given attribute on the given file." },
 	{ "wrap_setxattr", (PyCFunction)py_wrap_setxattr, METH_VARARGS,
 		"wrap_setxattr(filename,attribute,value)\n"
 		"Set the given attribute to the given value on the given file." },
diff --git a/source4/ntvfs/posix/python/pyxattr_native.c b/source4/ntvfs/posix/python/pyxattr_native.c
index 4f610a0..8dd98d2 100644
--- a/source4/ntvfs/posix/python/pyxattr_native.c
+++ b/source4/ntvfs/posix/python/pyxattr_native.c
@@ -38,7 +38,7 @@ static PyObject *py_wrap_setxattr(PyObject *self, PyObject *args)
 {
 	char *filename, *attribute;
 	int ret = 0;
-	int blobsize;
+	Py_ssize_t blobsize;
 	DATA_BLOB blob;
 
 	if (!PyArg_ParseTuple(args, "sss#", &filename, &attribute, &blob.data, 
@@ -98,7 +98,7 @@ static PyObject *py_wrap_getxattr(PyObject *self, PyObject *args)
 static PyMethodDef py_xattr_methods[] = {
 	{ "wrap_getxattr", (PyCFunction)py_wrap_getxattr, METH_VARARGS,
 		"wrap_getxattr(filename,attribute) -> blob\n"
-		"Retreive given attribute on the given file." },
+		"Retrieve given attribute on the given file." },
 	{ "wrap_setxattr", (PyCFunction)py_wrap_setxattr, METH_VARARGS,
 		"wrap_setxattr(filename,attribute,value)\n"
 		"Set the given attribute to the given value on the given file." },
diff --git a/source4/ntvfs/posix/python/pyxattr_tdb.c b/source4/ntvfs/posix/python/pyxattr_tdb.c
index d3390a3..56beedb 100644
--- a/source4/ntvfs/posix/python/pyxattr_tdb.c
+++ b/source4/ntvfs/posix/python/pyxattr_tdb.c
@@ -43,9 +43,10 @@ static PyObject *py_wrap_setxattr(PyObject *self, PyObject *args)
 {
 	char *filename, *attribute, *tdbname;
 	DATA_BLOB blob;
-	int blobsize;
+	Py_ssize_t blobsize;
 	int ret;
 	TALLOC_CTX *mem_ctx;
+	struct loadparm_context *lp_ctx;
 	struct db_context *eadb = NULL;
 	struct file_id id;
 	struct stat sbuf;
@@ -56,8 +57,11 @@ static PyObject *py_wrap_setxattr(PyObject *self, PyObject *args)
 
 	blob.length = blobsize;
 	mem_ctx = talloc_new(NULL);
-	eadb = db_open_tdb(mem_ctx, py_default_loadparm_context(mem_ctx), tdbname, 50000,
-			   TDB_DEFAULT, O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_2,
+
+	lp_ctx = py_default_loadparm_context(mem_ctx);
+	eadb = db_open_tdb(mem_ctx, tdbname, 50000,
+			   lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT),
+			   O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_2,
 			   DBWRAP_FLAG_NONE);
 
 	if (eadb == NULL) {
@@ -91,6 +95,7 @@ static PyObject *py_wrap_getxattr(PyObject *self, PyObject *args)
 {
 	char *filename, *attribute, *tdbname;
 	TALLOC_CTX *mem_ctx;
+	struct loadparm_context *lp_ctx;
 	DATA_BLOB blob;
 	PyObject *ret_obj;
 	int ret;
@@ -104,8 +109,10 @@ static PyObject *py_wrap_getxattr(PyObject *self, PyObject *args)
 
 	mem_ctx = talloc_new(NULL);
 
-	eadb = db_open_tdb(mem_ctx, py_default_loadparm_context(mem_ctx), tdbname, 50000,
-			   TDB_DEFAULT, O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_2,
+	lp_ctx = py_default_loadparm_context(mem_ctx);
+	eadb = db_open_tdb(mem_ctx, tdbname, 50000,
+			   lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT),
+			   O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_2,
 			   DBWRAP_FLAG_NONE);
 
 	if (eadb == NULL) {
@@ -139,7 +146,7 @@ static PyObject *py_wrap_getxattr(PyObject *self, PyObject *args)
 static PyMethodDef py_xattr_methods[] = {
 	{ "wrap_getxattr", (PyCFunction)py_wrap_getxattr, METH_VARARGS,
 		"wrap_getxattr(filename,attribute) -> blob\n"
-		"Retreive given attribute on the given file." },
+		"Retrieve given attribute on the given file." },
 	{ "wrap_setxattr", (PyCFunction)py_wrap_setxattr, METH_VARARGS,
 		"wrap_setxattr(filename,attribute,value)\n"
 		"Set the given attribute to the given value on the given file." },
diff --git a/source4/ntvfs/unixuid/vfs_unixuid.c b/source4/ntvfs/unixuid/vfs_unixuid.c
index 88f3b8b..ce7abfc 100644
--- a/source4/ntvfs/unixuid/vfs_unixuid.c
+++ b/source4/ntvfs/unixuid/vfs_unixuid.c
@@ -76,12 +76,15 @@ static NTSTATUS set_unix_security(struct security_unix_token *sec)
 	samba_seteuid(0);
 
 	if (samba_setgroups(sec->ngroups, sec->groups) != 0) {
+		DBG_ERR("*** samba_setgroups failed\n");
 		return NT_STATUS_ACCESS_DENIED;
 	}
 	if (samba_setegid(sec->gid) != 0) {
+		DBG_ERR("*** samba_setegid(%u) failed\n", sec->gid);
 		return NT_STATUS_ACCESS_DENIED;
 	}
 	if (samba_seteuid(sec->uid) != 0) {
+		DBG_ERR("*** samba_seteuid(%u) failed\n", sec->uid);
 		return NT_STATUS_ACCESS_DENIED;
 	}
 	return NT_STATUS_OK;
diff --git a/source4/param/pyparam.c b/source4/param/pyparam.c
index 14ffb2d..fde91e5 100644
--- a/source4/param/pyparam.c
+++ b/source4/param/pyparam.c
@@ -26,12 +26,6 @@
 
 void initparam(void);
 
-/* There's no Py_ssize_t in 2.4, apparently */
-#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
-typedef int Py_ssize_t;
-typedef inquiry lenfunc;
-#endif
-
 #define PyLoadparmContext_AsLoadparmContext(obj) pytalloc_get_type(obj, struct loadparm_context)
 #define PyLoadparmService_AsLoadparmService(obj) pytalloc_get_type(obj, struct loadparm_service)
 
@@ -148,7 +142,7 @@ static PyObject *py_lp_ctx_get_helper(struct loadparm_context *lp_ctx, const cha
 
 }
 
-static PyObject *py_lp_ctx_load(pytalloc_Object *self, PyObject *args)
+static PyObject *py_lp_ctx_load(PyObject *self, PyObject *args)
 {
 	char *filename;
 	bool ret;
@@ -164,7 +158,7 @@ static PyObject *py_lp_ctx_load(pytalloc_Object *self, PyObject *args)
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_lp_ctx_load_default(pytalloc_Object *self)
+static PyObject *py_lp_ctx_load_default(PyObject *self, PyObject *unused)
 {
 	bool ret;
         ret = lpcfg_load_default(PyLoadparmContext_AsLoadparmContext(self));
@@ -176,7 +170,7 @@ static PyObject *py_lp_ctx_load_default(pytalloc_Object *self)
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_lp_ctx_get(pytalloc_Object *self, PyObject *args)
+static PyObject *py_lp_ctx_get(PyObject *self, PyObject *args)
 {
 	char *param_name;
 	char *section_name = NULL;
@@ -190,7 +184,7 @@ static PyObject *py_lp_ctx_get(pytalloc_Object *self, PyObject *args)
 	return ret;
 }
 
-static PyObject *py_lp_ctx_is_myname(pytalloc_Object *self, PyObject *args)
+static PyObject *py_lp_ctx_is_myname(PyObject *self, PyObject *args)
 {
 	char *name;
 	if (!PyArg_ParseTuple(args, "s", &name))
@@ -199,7 +193,7 @@ static PyObject *py_lp_ctx_is_myname(pytalloc_Object *self, PyObject *args)
 	return PyBool_FromLong(lpcfg_is_myname(PyLoadparmContext_AsLoadparmContext(self), name));
 }
 
-static PyObject *py_lp_ctx_is_mydomain(pytalloc_Object *self, PyObject *args)
+static PyObject *py_lp_ctx_is_mydomain(PyObject *self, PyObject *args)
 {
 	char *name;
 	if (!PyArg_ParseTuple(args, "s", &name))
@@ -208,7 +202,7 @@ static PyObject *py_lp_ctx_is_mydomain(pytalloc_Object *self, PyObject *args)
 	return PyBool_FromLong(lpcfg_is_mydomain(PyLoadparmContext_AsLoadparmContext(self), name));
 }
 
-static PyObject *py_lp_ctx_set(pytalloc_Object *self, PyObject *args)
+static PyObject *py_lp_ctx_set(PyObject *self, PyObject *args)
 {
 	char *name, *value;
 	bool ret;
@@ -224,7 +218,7 @@ static PyObject *py_lp_ctx_set(pytalloc_Object *self, PyObject *args)
 	Py_RETURN_NONE;
 }
 
-static PyObject *py_lp_ctx_private_path(pytalloc_Object *self, PyObject *args)
+static PyObject *py_lp_ctx_private_path(PyObject *self, PyObject *args)
 {
 	char *name, *path;
 	PyObject *ret;
@@ -238,7 +232,7 @@ static PyObject *py_lp_ctx_private_path(pytalloc_Object *self, PyObject *args)
 	return ret;
 }
 
-static PyObject *py_lp_ctx_services(pytalloc_Object *self)
+static PyObject *py_lp_ctx_services(PyObject *self, PyObject *unused)
 {
 	struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self);
 	PyObject *ret;
@@ -253,7 +247,7 @@ static PyObject *py_lp_ctx_services(pytalloc_Object *self)
 	return ret;
 }
 
-static PyObject *py_lp_ctx_server_role(pytalloc_Object *self)
+static PyObject *py_lp_ctx_server_role(PyObject *self, PyObject *unused)
 {
 	struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self);
 	uint32_t role;
@@ -328,7 +322,7 @@ static PyObject *py_lp_dump_a_parameter(PyObject *self, PyObject *args)
 
 }
 
-static PyObject *py_samdb_url(PyObject *self)
+static PyObject *py_samdb_url(PyObject *self, PyObject *unused)
 {
 	struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self);
 	return PyString_FromFormat("tdb://%s/sam.ldb", lpcfg_private_dir(lp_ctx));
@@ -336,47 +330,47 @@ static PyObject *py_samdb_url(PyObject *self)
 
 
 static PyMethodDef py_lp_ctx_methods[] = {
-	{ "load", (PyCFunction)py_lp_ctx_load, METH_VARARGS, 
+	{ "load", py_lp_ctx_load, METH_VARARGS,
 		"S.load(filename) -> None\n"
 		"Load specified file." },
-	{ "load_default", (PyCFunction)py_lp_ctx_load_default, METH_NOARGS,
+	{ "load_default", py_lp_ctx_load_default, METH_NOARGS,
         	"S.load_default() -> None\n"
 		"Load default smb.conf file." },
-	{ "is_myname", (PyCFunction)py_lp_ctx_is_myname, METH_VARARGS,
+	{ "is_myname", py_lp_ctx_is_myname, METH_VARARGS,
 		"S.is_myname(name) -> bool\n"
 		"Check whether the specified name matches one of our netbios names." },
-	{ "is_mydomain", (PyCFunction)py_lp_ctx_is_mydomain, METH_VARARGS,
+	{ "is_mydomain", py_lp_ctx_is_mydomain, METH_VARARGS,
 		"S.is_mydomain(name) -> bool\n"
 		"Check whether the specified name matches our domain name." },
-	{ "get", (PyCFunction)py_lp_ctx_get, METH_VARARGS,
+	{ "get", py_lp_ctx_get, METH_VARARGS,
         	"S.get(name, service_name) -> value\n"
 		"Find specified parameter." },
-	{ "set", (PyCFunction)py_lp_ctx_set, METH_VARARGS,
+	{ "set", py_lp_ctx_set, METH_VARARGS,
 		"S.set(name, value) -> bool\n"
 		"Change a parameter." },
-	{ "private_path", (PyCFunction)py_lp_ctx_private_path, METH_VARARGS,
+	{ "private_path", py_lp_ctx_private_path, METH_VARARGS,
 		"S.private_path(name) -> path\n" },
-	{ "services", (PyCFunction)py_lp_ctx_services, METH_NOARGS,
+	{ "services", py_lp_ctx_services, METH_NOARGS,
 		"S.services() -> list" },
-	{ "server_role", (PyCFunction)py_lp_ctx_server_role, METH_NOARGS,
+	{ "server_role", py_lp_ctx_server_role, METH_NOARGS,
 		"S.server_role() -> value\n"
 		"Get the server role." },
-	{ "dump", (PyCFunction)py_lp_dump, METH_VARARGS, 
+	{ "dump", py_lp_dump, METH_VARARGS,
 		"S.dump(stream, show_defaults=False)" },
-	{ "dump_a_parameter", (PyCFunction)py_lp_dump_a_parameter, METH_VARARGS,
+	{ "dump_a_parameter", py_lp_dump_a_parameter, METH_VARARGS,
 		"S.dump_a_parameter(stream, name, service_name)" },
-	{ "samdb_url", (PyCFunction)py_samdb_url, METH_NOARGS,
+	{ "samdb_url", py_samdb_url, METH_NOARGS,
 	        "S.samdb_url() -> string\n"
 	        "Returns the current URL for sam.ldb." },
 	{ NULL }
 };
 
-static PyObject *py_lp_ctx_default_service(pytalloc_Object *self, void *closure)
+static PyObject *py_lp_ctx_default_service(PyObject *self, void *closure)
 {
 	return PyLoadparmService_FromService(lpcfg_default_service(PyLoadparmContext_AsLoadparmContext(self)));
 }
 
-static PyObject *py_lp_ctx_config_file(pytalloc_Object *self, void *closure)
+static PyObject *py_lp_ctx_config_file(PyObject *self, void *closure)
 {
 	const char *configfile = lpcfg_configfile(PyLoadparmContext_AsLoadparmContext(self));
 	if (configfile == NULL)
@@ -394,30 +388,15 @@ static PyGetSetDef py_lp_ctx_getset[] = {
 
 static PyObject *py_lp_ctx_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
-	pytalloc_Object *ret = (pytalloc_Object *)type->tp_alloc(type, 0);
-	if (ret == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-	ret->talloc_ctx = talloc_new(NULL);
-	if (ret->talloc_ctx == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-	ret->ptr = loadparm_init_global(false);
-	if (ret->ptr == NULL) {
-		PyErr_NoMemory();
-		return NULL;
-	}
-	return (PyObject *)ret;
+	return pytalloc_reference(type, loadparm_init_global(false));
 }
 
-static Py_ssize_t py_lp_ctx_len(pytalloc_Object *self)
+static Py_ssize_t py_lp_ctx_len(PyObject *self)
 {
 	return lpcfg_numservices(PyLoadparmContext_AsLoadparmContext(self));
 }
 
-static PyObject *py_lp_ctx_getitem(pytalloc_Object *self, PyObject *name)
+static PyObject *py_lp_ctx_getitem(PyObject *self, PyObject *name)
 {
 	struct loadparm_service *service;
 	if (!PyString_Check(name)) {
@@ -439,7 +418,6 @@ static PyMappingMethods py_lp_ctx_mapping = {
 
 PyTypeObject PyLoadparmContext = {
 	.tp_name = "param.LoadParm",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_getset = py_lp_ctx_getset,
 	.tp_methods = py_lp_ctx_methods,
 	.tp_new = py_lp_ctx_new,
@@ -485,7 +463,6 @@ static PyMethodDef py_lp_service_methods[] = {
 
 PyTypeObject PyLoadparmService = {
 	.tp_name = "param.LoadparmService",
-	.tp_basicsize = sizeof(pytalloc_Object),
 	.tp_methods = py_lp_service_methods,
 	.tp_flags = Py_TPFLAGS_DEFAULT,
 };
@@ -532,17 +509,11 @@ static PyMethodDef pyparam_methods[] = {
 void initparam(void)
 {
 	PyObject *m;
-	PyTypeObject *talloc_type = pytalloc_GetObjectType();
-	if (talloc_type == NULL)
-		return;
-
-	PyLoadparmContext.tp_base = talloc_type;
-	PyLoadparmService.tp_base = talloc_type;
 
-	if (PyType_Ready(&PyLoadparmContext) < 0)
+	if (pytalloc_BaseObject_PyType_Ready(&PyLoadparmContext) < 0)
 		return;
 
-	if (PyType_Ready(&PyLoadparmService) < 0)
+	if (pytalloc_BaseObject_PyType_Ready(&PyLoadparmService) < 0)
 		return;
 
 	m = Py_InitModule3("param", pyparam_methods, "Parsing and writing Samba configuration files.");
diff --git a/source4/param/secrets.c b/source4/param/secrets.c
index 92e338a..9874088 100644
--- a/source4/param/secrets.c
+++ b/source4/param/secrets.c
@@ -33,59 +33,6 @@
 #include "dsdb/samdb/samdb.h"
 
 /**
- * Use a TDB to store an incrementing random seed.
- *
- * Initialised to the current pid, the very first time Samba starts,
- * and incremented by one each time it is needed.  
- * 
- * @note Not called by systems with a working /dev/urandom.
- */
-static void get_rand_seed(struct tdb_wrap *secretsdb, int *new_seed) 
-{
-	*new_seed = getpid();
-	if (secretsdb != NULL) {
-		tdb_change_int32_atomic(secretsdb->tdb, "INFO/random_seed", new_seed, 1);
-	}
-}
-
-/**
- * open up the randseed database and set the random number generator callback
- */
-bool randseed_init(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
-{
-	char *fname;
-	uint8_t dummy;
-	struct tdb_wrap *tdb;
-
-	fname = lpcfg_private_path(mem_ctx, lp_ctx, "randseed.tdb");
-
-	tdb = tdb_wrap_open(mem_ctx, fname,
-			    lpcfg_tdb_hash_size(lp_ctx, fname),
-			    lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT),
-			    O_RDWR|O_CREAT, 0600);
-
-	if (!tdb) {
-		DEBUG(0,("Failed to open %s\n", fname));
-		talloc_free(fname);
-		return false;
-	}
-	talloc_free(fname);
-
-	/**
-	 * Set a reseed function for the crypto random generator 
-	 * 
-	 * This avoids a problem where systems without /dev/urandom
-	 * could send the same challenge to multiple clients
-	 */
-	set_rand_reseed_callback((void (*) (void *, int *))get_rand_seed, tdb);
-
-	/* Ensure that the reseed is done now, while we are root, etc */
-	generate_random_buffer(&dummy, sizeof(dummy));
-
-	return true;
-}
-
-/**
   connect to the secrets ldb
 */
 struct ldb_context *secrets_db_connect(TALLOC_CTX *mem_ctx,
diff --git a/source4/param/secrets.h b/source4/param/secrets.h
index 1e7849f..015ea12 100644
--- a/source4/param/secrets.h
+++ b/source4/param/secrets.h
@@ -28,14 +28,6 @@
 #define SECRETS_PRINCIPAL_SEARCH "(&(|(realm=%s)(flatname=%s))(servicePrincipalName=%s))"
 #define SECRETS_LDAP_FILTER "(&(objectclass=ldapSecret)(cn=SAMDB Credentials))"
 
-/**
- * Use a TDB to store an incrementing random seed.
- *
- * Initialised to the current pid, the very first time Samba starts,
- * and incremented by one each time it is needed.  
- * 
- * @note Not called by systems with a working /dev/urandom.
- */
 struct loadparm_context;
 struct tevent_context;
 struct ldb_message;
diff --git a/source4/param/share_ldb.c b/source4/param/share_ldb.c
index 0257cd1..cf8c5bb 100644
--- a/source4/param/share_ldb.c
+++ b/source4/param/share_ldb.c
@@ -445,7 +445,7 @@ static NTSTATUS sldb_set(struct share_context *ctx, const char *name, struct sha
 	TALLOC_CTX *tmp_ctx;
 	NTSTATUS ret;
 	bool do_rename = false;
-	char *newname;
+	char *newname = NULL;
 	int err, i;
 
 	if (!name) {
diff --git a/source4/param/tests/loadparm.c b/source4/param/tests/loadparm.c
index 87edc06..6a6e33e 100644
--- a/source4/param/tests/loadparm.c
+++ b/source4/param/tests/loadparm.c
@@ -22,6 +22,7 @@
 #include "param/param.h"
 #include "torture/torture.h"
 #include "torture/local/proto.h"
+#include "libds/common/roles.h"
 
 static bool test_create(struct torture_context *tctx)
 {
diff --git a/source4/param/wscript_build b/source4/param/wscript_build
index 4585a83..2ad753b 100644
--- a/source4/param/wscript_build
+++ b/source4/param/wscript_build
@@ -49,7 +49,7 @@ bld.SAMBA_SUBSYSTEM('param_options',
 
 bld.SAMBA_SUBSYSTEM('pyparam_util',
 	source='pyparam_util.c',
-	deps='LIBPYTHON samba-hostconfig',
+	deps='LIBPYTHON samba-hostconfig pytalloc-util',
 	pyext=True,
 	)
 
diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c
index 3edd1b6..5fb49b0 100644
--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c
+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c
@@ -4,6 +4,7 @@
    endpoint server for the backupkey interface
 
    Copyright (C) Matthieu Patou <mat at samba.org> 2010
+   Copyright (C) Andreas Schneider <asn at samba.org> 2015
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -29,30 +30,16 @@
 #include "param/param.h"
 #include "auth/session.h"
 #include "system/network.h"
-#include <com_err.h>
-#include <hx509.h>
-#include <hcrypto/rsa.h>
-#include <hcrypto/bn.h>
-#include <hcrypto/sha.h>
-#include <hcrypto/evp.h>
-#include <hcrypto/hmac.h>
-#include <der.h>
+
 #include "../lib/tsocket/tsocket.h"
 #include "../libcli/security/security.h"
 #include "librpc/gen_ndr/ndr_security.h"
-#include "lib/crypto/arcfour.h"
+#include "libds/common/roles.h"
+
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
-#if defined(HAVE_GCRYPT_H) && !defined(HAVE_GNUTLS3)
-#include <gcrypt.h>
-#endif
-
-
-static const unsigned rsa_with_var_num[] = { 1, 2, 840, 113549, 1, 1, 1 };
-/* Equivalent to asn1_oid_id_pkcs1_rsaEncryption*/
-static const AlgorithmIdentifier _hx509_signature_rsa_with_var_num = {
-	{ 7, discard_const_p(unsigned, rsa_with_var_num) }, NULL
-};
+#include <gnutls/crypto.h>
+#include <gnutls/abstract.h>
 
 static NTSTATUS set_lsa_secret(TALLOC_CTX *mem_ctx,
 			       struct ldb_context *ldb,
@@ -249,146 +236,112 @@ static NTSTATUS get_lsa_secret(TALLOC_CTX *mem_ctx,
 	return NT_STATUS_OK;
 }
 
-static DATA_BLOB *reverse_and_get_blob(TALLOC_CTX *mem_ctx, BIGNUM *bn)
+static int reverse_and_get_bignum(TALLOC_CTX *mem_ctx,
+				  DATA_BLOB blob,
+				  gnutls_datum_t *datum)
 {
-	DATA_BLOB blob;
-	DATA_BLOB *rev = talloc(mem_ctx, DATA_BLOB);
 	uint32_t i;
 
-	blob.length = BN_num_bytes(bn);
-	blob.data = talloc_array(mem_ctx, uint8_t, blob.length);
-
-	if (blob.data == NULL) {
-		return NULL;
+	datum->data = talloc_array(mem_ctx, uint8_t, blob.length);
+	if (datum->data == NULL) {
+		return -1;
 	}
 
-	BN_bn2bin(bn, blob.data);
-
-	rev->data = talloc_array(mem_ctx, uint8_t, blob.length);
-	if (rev->data == NULL) {
-		return NULL;
+	for(i = 0; i < blob.length; i++) {
+		datum->data[i] = blob.data[blob.length - i - 1];
 	}
+	datum->size = blob.length;
 
-	for(i=0; i < blob.length; i++) {
-		rev->data[i] = blob.data[blob.length - i -1];
-	}
-	rev->length = blob.length;
-	talloc_free(blob.data);
-	return rev;
-}
-
-static BIGNUM *reverse_and_get_bignum(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
-{
-	BIGNUM *ret;
-	DATA_BLOB rev;
-	uint32_t i;
-
-	rev.data = talloc_array(mem_ctx, uint8_t, blob->length);
-	if (rev.data == NULL) {
-		return NULL;
-	}
-
-	for(i=0; i < blob->length; i++) {
-		rev.data[i] = blob->data[blob->length - i -1];
-	}
-	rev.length = blob->length;
-
-	ret = BN_bin2bn(rev.data, rev.length, NULL);
-	talloc_free(rev.data);
-
-	return ret;
+	return 0;
 }
 
 static NTSTATUS get_pk_from_raw_keypair_params(TALLOC_CTX *ctx,
 				struct bkrp_exported_RSA_key_pair *keypair,
-				hx509_private_key *pk)
+				gnutls_privkey_t *pk)
 {
-	hx509_context hctx;
-	RSA *rsa;
-	struct hx509_private_key_ops *ops;
-	hx509_private_key privkey = NULL;
-
-	hx509_context_init(&hctx);
-	ops = hx509_find_private_alg(&_hx509_signature_rsa_with_var_num.algorithm);
-	if (ops == NULL) {
-		DEBUG(2, ("Not supported algorithm\n"));
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	if (hx509_private_key_init(&privkey, ops, NULL) != 0) {
-		hx509_context_free(&hctx);
-		return NT_STATUS_NO_MEMORY;
-	}
+	gnutls_x509_privkey_t x509_privkey = NULL;
+	gnutls_privkey_t privkey = NULL;
+	gnutls_datum_t m, e, d, p, q, u, e1, e2;
+	int rc;
 
-	rsa = RSA_new();
-	if (rsa ==NULL) {
-		hx509_private_key_free(&privkey);
-		hx509_context_free(&hctx);
+	rc = reverse_and_get_bignum(ctx, keypair->modulus, &m);
+	if (rc != 0) {
 		return NT_STATUS_INVALID_PARAMETER;
 	}
-
-	rsa->n = reverse_and_get_bignum(ctx, &(keypair->modulus));
-	if (rsa->n == NULL) {
-		RSA_free(rsa);
-		hx509_private_key_free(&privkey);
-		hx509_context_free(&hctx);
+	rc = reverse_and_get_bignum(ctx, keypair->public_exponent, &e);
+	if (rc != 0) {
 		return NT_STATUS_INVALID_PARAMETER;
 	}
-	rsa->d = reverse_and_get_bignum(ctx, &(keypair->private_exponent));
-	if (rsa->d == NULL) {
-		RSA_free(rsa);
-		hx509_private_key_free(&privkey);
-		hx509_context_free(&hctx);
+	rc = reverse_and_get_bignum(ctx, keypair->private_exponent, &d);
+	if (rc != 0) {
 		return NT_STATUS_INVALID_PARAMETER;
 	}
-	rsa->p = reverse_and_get_bignum(ctx, &(keypair->prime1));
-	if (rsa->p == NULL) {
-		RSA_free(rsa);
-		hx509_private_key_free(&privkey);
-		hx509_context_free(&hctx);
+
+	rc = reverse_and_get_bignum(ctx, keypair->prime1, &p);
+	if (rc != 0) {
 		return NT_STATUS_INVALID_PARAMETER;
 	}
-	rsa->q = reverse_and_get_bignum(ctx, &(keypair->prime2));
-	if (rsa->q == NULL) {
-		RSA_free(rsa);
-		hx509_private_key_free(&privkey);
-		hx509_context_free(&hctx);
+	rc = reverse_and_get_bignum(ctx, keypair->prime2, &q);
+	if (rc != 0) {
 		return NT_STATUS_INVALID_PARAMETER;
 	}
-	rsa->dmp1 = reverse_and_get_bignum(ctx, &(keypair->exponent1));
-	if (rsa->dmp1 == NULL) {
-		RSA_free(rsa);
-		hx509_private_key_free(&privkey);
-		hx509_context_free(&hctx);
+
+	rc = reverse_and_get_bignum(ctx, keypair->coefficient, &u);
+	if (rc != 0) {
 		return NT_STATUS_INVALID_PARAMETER;
 	}
-	rsa->dmq1 = reverse_and_get_bignum(ctx, &(keypair->exponent2));
-	if (rsa->dmq1 == NULL) {
-		RSA_free(rsa);
-		hx509_private_key_free(&privkey);
-		hx509_context_free(&hctx);
+
+	rc = reverse_and_get_bignum(ctx, keypair->exponent1, &e1);
+	if (rc != 0) {
 		return NT_STATUS_INVALID_PARAMETER;
 	}
-	rsa->iqmp = reverse_and_get_bignum(ctx, &(keypair->coefficient));
-	if (rsa->iqmp == NULL) {
-		RSA_free(rsa);
-		hx509_private_key_free(&privkey);
-		hx509_context_free(&hctx);
+	rc = reverse_and_get_bignum(ctx, keypair->exponent2, &e2);
+	if (rc != 0) {
 		return NT_STATUS_INVALID_PARAMETER;
 	}
-	rsa->e = reverse_and_get_bignum(ctx, &(keypair->public_exponent));
-	if (rsa->e == NULL) {
-		RSA_free(rsa);
-		hx509_private_key_free(&privkey);
-		hx509_context_free(&hctx);
-		return NT_STATUS_INVALID_PARAMETER;
+
+	rc = gnutls_x509_privkey_init(&x509_privkey);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_privkey_init failed - %s\n",
+			gnutls_strerror(rc));
+		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	*pk = privkey;
+	rc = gnutls_x509_privkey_import_rsa_raw2(x509_privkey,
+						 &m,
+						 &e,
+						 &d,
+						 &p,
+						 &q,
+						 &u,
+						 &e1,
+						 &e2);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_privkey_import_rsa_raw2 failed - %s\n",
+			gnutls_strerror(rc));
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	rc = gnutls_privkey_init(&privkey);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_privkey_init failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_privkey_deinit(x509_privkey);
+		return NT_STATUS_INTERNAL_ERROR;
+	}
 
-	hx509_private_key_assign_rsa(*pk, rsa);
+	rc = gnutls_privkey_import_x509(privkey,
+					x509_privkey,
+					GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_privkey_import_x509 failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_privkey_deinit(x509_privkey);
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	*pk = privkey;
 
-	hx509_context_free(&hctx);
 	return NT_STATUS_OK;
 }
 
@@ -399,102 +352,86 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx,
 					  uint32_t access_check_len,
 					  struct auth_session_info *session_info)
 {
-	heim_octet_string iv;
-	heim_octet_string access_check_os;
-	hx509_crypto crypto;
-
+	gnutls_cipher_hd_t cipher_handle = { 0 };
+	gnutls_cipher_algorithm_t cipher_algo;
 	DATA_BLOB blob_us;
-	uint32_t key_len;
-	uint32_t iv_len;
-	int res;
 	enum ndr_err_code ndr_err;
-	hx509_context hctx;
+	gnutls_datum_t key;
+	gnutls_datum_t iv;
 
 	struct dom_sid *access_sid = NULL;
 	struct dom_sid *caller_sid = NULL;
-
-	/* This one should not be freed */
-	const AlgorithmIdentifier *alg;
+	int rc;
 
 	switch (version) {
 	case 2:
-		key_len = 24;
-		iv_len = 8;
-		alg = hx509_crypto_des_rsdi_ede3_cbc();
+		cipher_algo = GNUTLS_CIPHER_3DES_CBC;
 		break;
-
 	case 3:
-		key_len = 32;
-		iv_len = 16;
-		alg =hx509_crypto_aes256_cbc();
+		cipher_algo = GNUTLS_CIPHER_AES_256_CBC;
 		break;
-
 	default:
 		return WERR_INVALID_DATA;
 	}
 
-	hx509_context_init(&hctx);
-	res = hx509_crypto_init(hctx, NULL,
-				&(alg->algorithm),
-				&crypto);
-	hx509_context_free(&hctx);
+	key.data = key_and_iv;
+	key.size = gnutls_cipher_get_key_size(cipher_algo);
 
-	if (res != 0) {
+	iv.data = key_and_iv + key.size;
+	iv.size = gnutls_cipher_get_iv_size(cipher_algo);
+
+	/* Allocate data structure for the plaintext */
+	blob_us = data_blob_talloc_zero(sub_ctx, access_check_len);
+	if (blob_us.data == NULL) {
 		return WERR_INVALID_DATA;
 	}
 
-	res = hx509_crypto_set_key_data(crypto, key_and_iv, key_len);
-
-	iv.data = talloc_memdup(sub_ctx, key_len + key_and_iv, iv_len);
-	iv.length = iv_len;
-
-	if (res != 0) {
-		hx509_crypto_destroy(crypto);
+	rc = gnutls_cipher_init(&cipher_handle,
+				cipher_algo,
+				&key,
+				&iv);
+	if (rc < 0) {
+		DBG_ERR("gnutls_cipher_init failed: %s\n",
+			gnutls_strerror(rc));
 		return WERR_INVALID_DATA;
 	}
 
-	hx509_crypto_set_padding(crypto, HX509_CRYPTO_PADDING_NONE);
-	res = hx509_crypto_decrypt(crypto,
-		access_check,
-		access_check_len,
-		&iv,
-		&access_check_os);
-
-	if (res != 0) {
-		hx509_crypto_destroy(crypto);
+	rc = gnutls_cipher_decrypt2(cipher_handle,
+				    access_check,
+				    access_check_len,
+				    blob_us.data,
+				    blob_us.length);
+	gnutls_cipher_deinit(cipher_handle);
+	if (rc < 0) {
+		DBG_ERR("gnutls_cipher_decrypt2 failed: %s\n",
+			gnutls_strerror(rc));
 		return WERR_INVALID_DATA;
 	}
 
-	blob_us.data = access_check_os.data;
-	blob_us.length = access_check_os.length;
-
-	hx509_crypto_destroy(crypto);
-
 	switch (version) {
 	case 2:
 	{
 		uint32_t hash_size = 20;
 		uint8_t hash[hash_size];
-		struct sha sctx;
+		gnutls_hash_hd_t dig_ctx;
 		struct bkrp_access_check_v2 uncrypted_accesscheckv2;
 
 		ndr_err = ndr_pull_struct_blob(&blob_us, sub_ctx, &uncrypted_accesscheckv2,
 					(ndr_pull_flags_fn_t)ndr_pull_bkrp_access_check_v2);
 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 			/* Unable to unmarshall */
-			der_free_octet_string(&access_check_os);
 			return WERR_INVALID_DATA;
 		}
 		if (uncrypted_accesscheckv2.magic != 0x1) {
 			/* wrong magic */
-			der_free_octet_string(&access_check_os);
 			return WERR_INVALID_DATA;
 		}
 
-		SHA1_Init(&sctx);
-		SHA1_Update(&sctx, blob_us.data, blob_us.length - hash_size);
-		SHA1_Final(hash, &sctx);
-		der_free_octet_string(&access_check_os);
+		gnutls_hash_init(&dig_ctx, GNUTLS_DIG_SHA1);
+		gnutls_hash(dig_ctx,
+			    blob_us.data,
+			    blob_us.length - hash_size);
+		gnutls_hash_deinit(dig_ctx, hash);
 		/*
 		 * We free it after the sha1 calculation because blob.data
 		 * point to the same area
@@ -511,26 +448,26 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx,
 	{
 		uint32_t hash_size = 64;
 		uint8_t hash[hash_size];
-		struct hc_sha512state sctx;
+		gnutls_hash_hd_t dig_ctx;
 		struct bkrp_access_check_v3 uncrypted_accesscheckv3;
 
 		ndr_err = ndr_pull_struct_blob(&blob_us, sub_ctx, &uncrypted_accesscheckv3,
 					(ndr_pull_flags_fn_t)ndr_pull_bkrp_access_check_v3);
 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 			/* Unable to unmarshall */
-			der_free_octet_string(&access_check_os);
 			return WERR_INVALID_DATA;
 		}
 		if (uncrypted_accesscheckv3.magic != 0x1) {
 			/* wrong magic */
-			der_free_octet_string(&access_check_os);
 			return WERR_INVALID_DATA;
 		}
 
-		SHA512_Init(&sctx);
-		SHA512_Update(&sctx, blob_us.data, blob_us.length - hash_size);
-		SHA512_Final(hash, &sctx);
-		der_free_octet_string(&access_check_os);
+		gnutls_hash_init(&dig_ctx, GNUTLS_DIG_SHA512);
+		gnutls_hash(dig_ctx,
+			    blob_us.data,
+			    blob_us.length - hash_size);
+		gnutls_hash_deinit(dig_ctx, hash);
+
 		/*
 		 * We free it after the sha1 calculation because blob.data
 		 * point to the same area
@@ -641,15 +578,14 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 		/* we do not have the real secret attribute, like if we are an RODC */
 		return WERR_INVALID_PARAMETER;
 	} else {
-		hx509_context hctx;
 		struct bkrp_exported_RSA_key_pair keypair;
-		hx509_private_key pk;
-		uint32_t i, res;
-		heim_octet_string reversed_secret;
-		heim_octet_string uncrypted_secret;
-		AlgorithmIdentifier alg;
+		gnutls_privkey_t privkey = NULL;
+		gnutls_datum_t reversed_secret;
+		gnutls_datum_t uncrypted_secret;
+		uint32_t i;
 		DATA_BLOB blob_us;
 		WERROR werr;
+		int rc;
 
 		ndr_err = ndr_pull_struct_blob(&lsa_secret, mem_ctx, &keypair, (ndr_pull_flags_fn_t)ndr_pull_bkrp_exported_RSA_key_pair);
 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
@@ -657,7 +593,9 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 			return WERR_FILE_NOT_FOUND;
 		}
 
-		status = get_pk_from_raw_keypair_params(mem_ctx, &keypair, &pk);
+		status = get_pk_from_raw_keypair_params(mem_ctx,
+							&keypair,
+							&privkey);
 		if (!NT_STATUS_IS_OK(status)) {
 			return WERR_INTERNAL_ERROR;
 		}
@@ -665,7 +603,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 		reversed_secret.data = talloc_array(mem_ctx, uint8_t,
 						    uncrypt_request.encrypted_secret_len);
 		if (reversed_secret.data == NULL) {
-			hx509_private_key_free(&pk);
+			gnutls_privkey_deinit(privkey);
 			return WERR_NOMEM;
 		}
 
@@ -675,31 +613,30 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 			uint8_t *uncrypt = uncrypt_request.encrypted_secret;
 			reversed[i] = uncrypt[uncrypt_request.encrypted_secret_len - 1 - i];
 		}
-		reversed_secret.length = uncrypt_request.encrypted_secret_len;
+		reversed_secret.size = uncrypt_request.encrypted_secret_len;
 
 		/*
 		 * Let's try to decrypt the secret now that
 		 * we have the private key ...
 		 */
-		hx509_context_init(&hctx);
-		res = hx509_private_key_private_decrypt(hctx, &reversed_secret,
-							 &alg.algorithm, pk,
-							 &uncrypted_secret);
-		hx509_context_free(&hctx);
-		hx509_private_key_free(&pk);
-		if (res != 0) {
+		rc = gnutls_privkey_decrypt_data(privkey,
+						 0,
+						 &reversed_secret,
+						 &uncrypted_secret);
+		gnutls_privkey_deinit(privkey);
+		if (rc != GNUTLS_E_SUCCESS) {
 			/* We are not able to decrypt the secret, looks like something is wrong */
 			return WERR_INVALID_PARAMETER;
 		}
 		blob_us.data = uncrypted_secret.data;
-		blob_us.length = uncrypted_secret.length;
+		blob_us.length = uncrypted_secret.size;
 
 		if (uncrypt_request.version == 2) {
 			struct bkrp_encrypted_secret_v2 uncrypted_secretv2;
 
 			ndr_err = ndr_pull_struct_blob(&blob_us, mem_ctx, &uncrypted_secretv2,
 					(ndr_pull_flags_fn_t)ndr_pull_bkrp_encrypted_secret_v2);
-			der_free_octet_string(&uncrypted_secret);
+			gnutls_free(uncrypted_secret.data);
 			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 				/* Unable to unmarshall */
 				return WERR_INVALID_DATA;
@@ -730,8 +667,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 
 			ndr_err = ndr_pull_struct_blob(&blob_us, mem_ctx, &uncrypted_secretv3,
 					(ndr_pull_flags_fn_t)ndr_pull_bkrp_encrypted_secret_v3);
-
-			der_free_octet_string(&uncrypted_secret);
+			gnutls_free(uncrypted_secret.data);
 			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 				/* Unable to unmarshall */
 				return WERR_INVALID_DATA;
@@ -796,413 +732,382 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 	return WERR_OK;
 }
 
-/*
- * Strictly, this function no longer uses Heimdal in order to generate an RSA
- * key, but GnuTLS.
- *
- * The resulting key is then imported into Heimdal's RSA structure.
- *
- * We use GnuTLS because it can reliably generate 2048 bit keys every time.
- * Windows clients strictly require 2048, no more since it won't fit and no
- * less either. Heimdal would almost always generate a smaller key.
- */
-static WERROR create_heimdal_rsa_key(TALLOC_CTX *ctx, hx509_context *hctx,
-				     hx509_private_key *pk, RSA **rsa)
+static DATA_BLOB *reverse_and_get_blob(TALLOC_CTX *mem_ctx,
+				       gnutls_datum_t *datum)
 {
-	int ret;
-	uint8_t *p0 = NULL;
-	const uint8_t *p;
-	size_t len;
-	int bits = 2048;
-	int RSA_returned_bits;
-	gnutls_x509_privkey gtls_key;
-	WERROR werr;
+	DATA_BLOB *blob;
+	size_t i;
 
-	*rsa = NULL;
-
-	gnutls_global_init();
-#if defined(HAVE_GCRYPT_H) && !defined(HAVE_GNUTLS3)
-	DEBUG(3,("Enabling QUICK mode in gcrypt\n"));
-	gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-#endif
-	ret = gnutls_x509_privkey_init(&gtls_key);
-	if (ret != 0) {
-		gnutls_global_deinit();
-		return WERR_INTERNAL_ERROR;
+	blob = talloc(mem_ctx, DATA_BLOB);
+	if (blob == NULL) {
+		return NULL;
 	}
 
-	/*
-	 * Unlike Heimdal's RSA_generate_key_ex(), this generates a
-	 * 2048 bit key 100% of the time.  The heimdal code had a ~1/8
-	 * chance of doing so, chewing vast quantities of computation
-	 * and entropy in the process.
-	 */
-
-	ret = gnutls_x509_privkey_generate(gtls_key, GNUTLS_PK_RSA, bits, 0);
-	if (ret != 0) {
-		werr = WERR_INTERNAL_ERROR;
-		goto done;
+	blob->length = datum->size;
+	if (datum->data[0] == '\0') {
+		/* The datum has a leading byte zero, skip it */
+		blob->length = datum->size - 1;
 	}
-
-	/* No need to check error code, this SHOULD fail */
-	gnutls_x509_privkey_export(gtls_key, GNUTLS_X509_FMT_DER, NULL, &len);
-
-	if (len < 1) {
-		werr = WERR_INTERNAL_ERROR;
-		goto done;
+	blob->data = talloc_zero_array(mem_ctx, uint8_t, blob->length);
+	if (blob->data == NULL) {
+		talloc_free(blob);
+		return NULL;
 	}
 
-	p0 = talloc_size(ctx, len);
-	if (p0 == NULL) {
-		werr = WERR_NOMEM;
-		goto done;
+	for (i = 0; i < blob->length; i++) {
+		blob->data[i] = datum->data[datum->size - i - 1];
 	}
-	p = p0;
 
-	/*
-	 * Only this GnuTLS export function correctly exports the key,
-	 * we can't use gnutls_rsa_params_export_raw() because while
-	 * it appears to be fixed in more recent versions, in the
-	 * Ubuntu 14.04 version 2.12.23 (at least) it incorrectly
-	 * exports one of the key parameters (qInv).  Additionally, we
-	 * would have to work around subtle differences in big number
-	 * representations.
-	 *
-	 * We need access to the RSA parameters directly (in the
-	 * parameter RSA **rsa) as the caller has to manually encode
-	 * them in a non-standard data structure.
-	 */
-	ret = gnutls_x509_privkey_export(gtls_key, GNUTLS_X509_FMT_DER, p0, &len);
+	return blob;
+}
 
-	if (ret != 0) {
-		werr = WERR_INTERNAL_ERROR;
-		goto done;
+static WERROR create_privkey_rsa(gnutls_privkey_t *pk)
+{
+	int bits = 2048;
+	gnutls_x509_privkey_t x509_privkey = NULL;
+	gnutls_privkey_t privkey = NULL;
+	int rc;
+
+	rc = gnutls_x509_privkey_init(&x509_privkey);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_privkey_init failed - %s\n",
+			gnutls_strerror(rc));
+		return WERR_INTERNAL_ERROR;
 	}
 
-	/*
-	 * To dump the key we can use :
-	 * rk_dumpdata("h5lkey", p0, len);
-	 */
-	ret = hx509_parse_private_key(*hctx, &_hx509_signature_rsa_with_var_num ,
-				       p0, len, HX509_KEY_FORMAT_DER, pk);
-
-	if (ret != 0) {
-		werr = WERR_INTERNAL_ERROR;
-		goto done;
+	rc = gnutls_x509_privkey_generate(x509_privkey,
+					  GNUTLS_PK_RSA,
+					  bits,
+					  0);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_privkey_generate failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_privkey_deinit(x509_privkey);
+		return WERR_INTERNAL_ERROR;
 	}
 
-	*rsa = d2i_RSAPrivateKey(NULL, &p, len);
-	TALLOC_FREE(p0);
-
-	if (*rsa == NULL) {
-		hx509_private_key_free(pk);
-		werr = WERR_INTERNAL_ERROR;
-		goto done;
+	rc = gnutls_privkey_init(&privkey);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_privkey_init failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_privkey_deinit(x509_privkey);
+		return WERR_INTERNAL_ERROR;
 	}
 
-	RSA_returned_bits = BN_num_bits((*rsa)->n);
-	DEBUG(6, ("GnuTLS returned an RSA private key with %d bits\n", RSA_returned_bits));
-
-	if (RSA_returned_bits != bits) {
-		DEBUG(0, ("GnuTLS unexpectedly returned an RSA private key with %d bits, needed %d\n", RSA_returned_bits, bits));
-		hx509_private_key_free(pk);
-		werr = WERR_INTERNAL_ERROR;
-		goto done;
+	rc = gnutls_privkey_import_x509(privkey,
+					x509_privkey,
+					GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_privkey_import_x509 failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_privkey_deinit(x509_privkey);
+		return WERR_INTERNAL_ERROR;
 	}
 
-	werr = WERR_OK;
-
-done:
-	if (p0 != NULL) {
-		memset(p0, 0, len);
-		TALLOC_FREE(p0);
-	}
+	*pk = privkey;
 
-	gnutls_x509_privkey_deinit(gtls_key);
-	gnutls_global_deinit();
-	return werr;
+	return WERR_OK;
 }
 
-static WERROR self_sign_cert(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request *req,
-				time_t lifetime, hx509_private_key *private_key,
-				hx509_cert *cert, DATA_BLOB *guidblob)
+static WERROR self_sign_cert(TALLOC_CTX *mem_ctx,
+			     time_t lifetime,
+			     const char *dn,
+			     gnutls_privkey_t issuer_privkey,
+			     gnutls_x509_crt_t *certificate,
+			     DATA_BLOB *guidblob)
 {
-	SubjectPublicKeyInfo spki;
-	hx509_name subject = NULL;
-	hx509_ca_tbs tbs;
-	struct heim_bit_string uniqueid;
-	struct heim_integer serialnumber;
-	int ret, i;
-
-	uniqueid.data = talloc_memdup(ctx, guidblob->data, guidblob->length);
-	if (uniqueid.data == NULL) {
+	gnutls_datum_t unique_id;
+	gnutls_datum_t serial_number;
+	gnutls_x509_crt_t issuer_cert;
+	gnutls_x509_privkey_t x509_issuer_privkey;
+	time_t activation = time(NULL);
+	time_t expiry = activation + lifetime;
+	const char *error_string;
+	uint8_t *reversed;
+	size_t i;
+	int rc;
+
+	unique_id.size = guidblob->length;
+	unique_id.data = talloc_memdup(mem_ctx,
+				       guidblob->data,
+				       guidblob->length);
+	if (unique_id.data == NULL) {
 		return WERR_NOMEM;
 	}
-	/* uniqueid is a bit string in which each byte represent 1 bit (1 or 0)
-	 * so as 1 byte is 8 bits we need to provision 8 times more space as in the
-	 * blob
-	 */
-	uniqueid.length = 8 * guidblob->length;
 
-	serialnumber.data = talloc_array(ctx, uint8_t,
-					    guidblob->length);
-	if (serialnumber.data == NULL) {
-		talloc_free(uniqueid.data);
+	reversed = talloc_array(mem_ctx, uint8_t, guidblob->length);
+	if (reversed == NULL) {
+		talloc_free(unique_id.data);
 		return WERR_NOMEM;
 	}
 
 	/* Native AD generates certificates with serialnumber in reversed notation */
 	for (i = 0; i < guidblob->length; i++) {
-		uint8_t *reversed = (uint8_t *)serialnumber.data;
 		uint8_t *uncrypt = guidblob->data;
-		reversed[i] = uncrypt[guidblob->length - 1 - i];
+		reversed[i] = uncrypt[guidblob->length - i - 1];
 	}
-	serialnumber.length = guidblob->length;
-	serialnumber.negative = 0;
-
-	memset(&spki, 0, sizeof(spki));
+	serial_number.size = guidblob->length;
+	serial_number.data = reversed;
 
-	ret = hx509_request_get_name(*hctx, *req, &subject);
-	if (ret !=0) {
-		goto fail_subject;
-	}
-	ret = hx509_request_get_SubjectPublicKeyInfo(*hctx, *req, &spki);
-	if (ret !=0) {
-		goto fail_spki;
+	/* Create certificate to sign */
+	rc = gnutls_x509_crt_init(&issuer_cert);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_init failed - %s\n",
+			gnutls_strerror(rc));
+		return WERR_NOMEM;
 	}
 
-	ret = hx509_ca_tbs_init(*hctx, &tbs);
-	if (ret !=0) {
-		goto fail_tbs;
+	rc = gnutls_x509_crt_set_dn(issuer_cert, dn, &error_string);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_set_dn failed - %s (%s)\n",
+			gnutls_strerror(rc),
+			error_string);
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
 	}
 
-	ret = hx509_ca_tbs_set_spki(*hctx, tbs, &spki);
-	if (ret !=0) {
-		goto fail;
-	}
-	ret = hx509_ca_tbs_set_subject(*hctx, tbs, subject);
-	if (ret !=0) {
-		goto fail;
-	}
-	ret = hx509_ca_tbs_set_ca(*hctx, tbs, 1);
-	if (ret !=0) {
-		goto fail;
-	}
-	ret = hx509_ca_tbs_set_notAfter_lifetime(*hctx, tbs, lifetime);
-	if (ret !=0) {
-		goto fail;
-	}
-	ret = hx509_ca_tbs_set_unique(*hctx, tbs, &uniqueid, &uniqueid);
-	if (ret !=0) {
-		goto fail;
-	}
-	ret = hx509_ca_tbs_set_serialnumber(*hctx, tbs, &serialnumber);
-	if (ret !=0) {
-		goto fail;
+	rc = gnutls_x509_crt_set_issuer_dn(issuer_cert, dn, &error_string);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_set_issuer_dn failed - %s (%s)\n",
+			gnutls_strerror(rc),
+			error_string);
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
 	}
-	ret = hx509_ca_sign_self(*hctx, tbs, *private_key, cert);
-	if (ret !=0) {
-		goto fail;
+
+	/* Get x509 privkey for subjectPublicKeyInfo */
+	rc = gnutls_x509_privkey_init(&x509_issuer_privkey);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_privkey_init failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
 	}
-	hx509_name_free(&subject);
-	free_SubjectPublicKeyInfo(&spki);
-	hx509_ca_tbs_free(&tbs);
 
-	return WERR_OK;
+	rc = gnutls_privkey_export_x509(issuer_privkey,
+					&x509_issuer_privkey);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_privkey_init failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_privkey_deinit(x509_issuer_privkey);
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
+	}
 
-fail:
-	hx509_ca_tbs_free(&tbs);
-fail_tbs:
-	free_SubjectPublicKeyInfo(&spki);
-fail_spki:
-	hx509_name_free(&subject);
-fail_subject:
-	talloc_free(uniqueid.data);
-	talloc_free(serialnumber.data);
-	return WERR_INTERNAL_ERROR;
-}
+	/* Set subjectPublicKeyInfo */
+	rc = gnutls_x509_crt_set_key(issuer_cert, x509_issuer_privkey);
+	gnutls_x509_privkey_deinit(x509_issuer_privkey);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_set_pubkey failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
+	}
 
-static WERROR create_req(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request *req,
-			 hx509_private_key *signer,RSA **rsa, const char *dn)
-{
-	int ret;
-	SubjectPublicKeyInfo key;
+	rc = gnutls_x509_crt_set_activation_time(issuer_cert, activation);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_set_activation_time failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
+	}
 
-	hx509_name name;
-	WERROR werr;
+	rc = gnutls_x509_crt_set_expiration_time(issuer_cert, expiry);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_set_expiration_time failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
+	}
 
-	werr = create_heimdal_rsa_key(ctx, hctx, signer, rsa);
-	if (!W_ERROR_IS_OK(werr)) {
-		return werr;
+	rc = gnutls_x509_crt_set_version(issuer_cert, 3);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_set_version failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
 	}
 
-	hx509_request_init(*hctx, req);
-	ret = hx509_parse_name(*hctx, dn, &name);
-	if (ret != 0) {
-		RSA_free(*rsa);
-		hx509_private_key_free(signer);
-		hx509_request_free(req);
-		hx509_name_free(&name);
-		return WERR_INTERNAL_ERROR;
+	rc = gnutls_x509_crt_set_subject_unique_id(issuer_cert,
+						   unique_id.data,
+						   unique_id.size);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_set_subject_key_id failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
 	}
 
-	ret = hx509_request_set_name(*hctx, *req, name);
-	if (ret != 0) {
-		RSA_free(*rsa);
-		hx509_private_key_free(signer);
-		hx509_request_free(req);
-		hx509_name_free(&name);
-		return WERR_INTERNAL_ERROR;
+	rc = gnutls_x509_crt_set_issuer_unique_id(issuer_cert,
+						  unique_id.data,
+						  unique_id.size);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_set_issuer_unique_id failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
 	}
-	hx509_name_free(&name);
 
-	ret = hx509_private_key2SPKI(*hctx, *signer, &key);
-	if (ret != 0) {
-		RSA_free(*rsa);
-		hx509_private_key_free(signer);
-		hx509_request_free(req);
-		return WERR_INTERNAL_ERROR;
+	rc = gnutls_x509_crt_set_serial(issuer_cert,
+					serial_number.data,
+					serial_number.size);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_set_serial failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_x509_crt_deinit(issuer_cert);
+		return WERR_INVALID_PARAM;
 	}
-	ret = hx509_request_set_SubjectPublicKeyInfo(*hctx, *req, &key);
-	if (ret != 0) {
-		RSA_free(*rsa);
-		hx509_private_key_free(signer);
-		free_SubjectPublicKeyInfo(&key);
-		hx509_request_free(req);
-		return WERR_INTERNAL_ERROR;
+
+	rc = gnutls_x509_crt_privkey_sign(issuer_cert,
+					  issuer_cert,
+					  issuer_privkey,
+					  GNUTLS_DIG_SHA1,
+					  0);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_privkey_sign failed - %s\n",
+			gnutls_strerror(rc));
+		return WERR_INVALID_PARAM;
 	}
 
-	free_SubjectPublicKeyInfo(&key);
+	*certificate = issuer_cert;
 
 	return WERR_OK;
 }
 
 /* Return an error when we fail to generate a certificate */
-static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_call, struct ldb_context *ldb_ctx, const char *dn)
+static WERROR generate_bkrp_cert(TALLOC_CTX *mem_ctx,
+				 struct dcesrv_call_state *dce_call,
+				 struct ldb_context *ldb_ctx,
+				 const char *dn)
 {
-	heim_octet_string data;
 	WERROR werr;
-	RSA *rsa;
-	hx509_context hctx;
-	hx509_private_key pk;
-	hx509_request req;
-	hx509_cert cert;
+	gnutls_privkey_t issuer_privkey = NULL;
+	gnutls_x509_crt_t cert = NULL;
+	gnutls_datum_t cert_blob;
+	gnutls_datum_t m, e, d, p, q, u, e1, e2;
 	DATA_BLOB blob;
 	DATA_BLOB blobkeypair;
 	DATA_BLOB *tmp;
-	int ret;
 	bool ok = true;
 	struct GUID guid = GUID_random();
 	NTSTATUS status;
 	char *secret_name;
 	struct bkrp_exported_RSA_key_pair keypair;
 	enum ndr_err_code ndr_err;
-	uint32_t nb_seconds_validity = 3600 * 24 * 365;
+	time_t nb_seconds_validity = 3600 * 24 * 365;
+	int rc;
 
 	DEBUG(6, ("Trying to generate a certificate\n"));
-	hx509_context_init(&hctx);
-	werr = create_req(ctx, &hctx, &req, &pk, &rsa, dn);
+	werr = create_privkey_rsa(&issuer_privkey);
 	if (!W_ERROR_IS_OK(werr)) {
-		hx509_context_free(&hctx);
 		return werr;
 	}
 
-	status = GUID_to_ndr_blob(&guid, ctx, &blob);
+	status = GUID_to_ndr_blob(&guid, mem_ctx, &blob);
 	if (!NT_STATUS_IS_OK(status)) {
-		hx509_context_free(&hctx);
-		hx509_private_key_free(&pk);
-		RSA_free(rsa);
+		gnutls_privkey_deinit(issuer_privkey);
 		return WERR_INVALID_DATA;
 	}
 
-	werr = self_sign_cert(ctx, &hctx, &req, nb_seconds_validity, &pk, &cert, &blob);
+	werr = self_sign_cert(mem_ctx,
+			      nb_seconds_validity,
+			      dn,
+			      issuer_privkey,
+			      &cert,
+			      &blob);
 	if (!W_ERROR_IS_OK(werr)) {
-		hx509_private_key_free(&pk);
-		hx509_context_free(&hctx);
+		gnutls_privkey_deinit(issuer_privkey);
 		return WERR_INVALID_DATA;
 	}
 
-	ret = hx509_cert_binary(hctx, cert, &data);
-	if (ret !=0) {
-		hx509_cert_free(cert);
-		hx509_private_key_free(&pk);
-		hx509_context_free(&hctx);
+	rc = gnutls_x509_crt_export2(cert, GNUTLS_X509_FMT_DER, &cert_blob);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_x509_crt_export2 failed - %s\n",
+			gnutls_strerror(rc));
+		gnutls_privkey_deinit(issuer_privkey);
+		gnutls_x509_crt_deinit(cert);
 		return WERR_INVALID_DATA;
 	}
 
-	keypair.cert.data = talloc_memdup(ctx, data.data, data.length);
-	keypair.cert.length = data.length;
+	keypair.cert.length = cert_blob.size;
+	keypair.cert.data = talloc_memdup(mem_ctx, cert_blob.data, cert_blob.size);
+	gnutls_x509_crt_deinit(cert);
+	gnutls_free(cert_blob.data);
+	if (keypair.cert.data == NULL) {
+		gnutls_privkey_deinit(issuer_privkey);
+		return WERR_NOMEM;
+	}
+
+	rc = gnutls_privkey_export_rsa_raw(issuer_privkey,
+					   &m,
+					   &e,
+					   &d,
+					   &p,
+					   &q,
+					   &u,
+					   &e1,
+					   &e2);
+	if (rc != GNUTLS_E_SUCCESS) {
+		gnutls_privkey_deinit(issuer_privkey);
+		return WERR_INVALID_DATA;
+	}
 
 	/*
 	 * Heimdal's bignum are big endian and the
 	 * structure expect it to be in little endian
 	 * so we reverse the buffer to make it work
 	 */
-	tmp = reverse_and_get_blob(ctx, rsa->e);
+	tmp = reverse_and_get_blob(mem_ctx, &e);
 	if (tmp == NULL) {
 		ok = false;
 	} else {
-		keypair.public_exponent = *tmp;
 		SMB_ASSERT(tmp->length <= 4);
-		/*
-		 * The value is now in little endian but if can happen that the length is
-		 * less than 4 bytes.
-		 * So if we have less than 4 bytes we pad with zeros so that it correctly
-		 * fit into the structure.
-		 */
-		if (tmp->length < 4) {
-			/*
-			 * We need the expo to fit 4 bytes
-			 */
-			keypair.public_exponent.data = talloc_zero_array(ctx, uint8_t, 4);
-			memcpy(keypair.public_exponent.data, tmp->data, tmp->length);
-			keypair.public_exponent.length = 4;
-		}
+		keypair.public_exponent = *tmp;
 	}
 
-	tmp = reverse_and_get_blob(ctx,rsa->d);
+	tmp = reverse_and_get_blob(mem_ctx, &d);
 	if (tmp == NULL) {
 		ok = false;
 	} else {
 		keypair.private_exponent = *tmp;
 	}
 
-	tmp = reverse_and_get_blob(ctx,rsa->n);
+	tmp = reverse_and_get_blob(mem_ctx, &m);
 	if (tmp == NULL) {
 		ok = false;
 	} else {
 		keypair.modulus = *tmp;
 	}
 
-	tmp = reverse_and_get_blob(ctx,rsa->p);
+	tmp = reverse_and_get_blob(mem_ctx, &p);
 	if (tmp == NULL) {
 		ok = false;
 	} else {
 		keypair.prime1 = *tmp;
 	}
 
-	tmp = reverse_and_get_blob(ctx,rsa->q);
+	tmp = reverse_and_get_blob(mem_ctx, &q);
 	if (tmp == NULL) {
 		ok = false;
 	} else {
 		keypair.prime2 = *tmp;
 	}
 
-	tmp = reverse_and_get_blob(ctx,rsa->dmp1);
+	tmp = reverse_and_get_blob(mem_ctx, &e1);
 	if (tmp == NULL) {
 		ok = false;
 	} else {
 		keypair.exponent1 = *tmp;
 	}
 
-	tmp = reverse_and_get_blob(ctx,rsa->dmq1);
+	tmp = reverse_and_get_blob(mem_ctx, &e2);
 	if (tmp == NULL) {
 		ok = false;
 	} else {
 		keypair.exponent2 = *tmp;
 	}
 
-	tmp = reverse_and_get_blob(ctx,rsa->iqmp);
+	tmp = reverse_and_get_blob(mem_ctx, &u);
 	if (tmp == NULL) {
 		ok = false;
 	} else {
@@ -1211,51 +1116,37 @@ static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_
 
 	/* One of the keypair allocation was wrong */
 	if (ok == false) {
-		der_free_octet_string(&data);
-		hx509_cert_free(cert);
-		hx509_private_key_free(&pk);
-		hx509_context_free(&hctx);
-		RSA_free(rsa);
+		gnutls_privkey_deinit(issuer_privkey);
 		return WERR_INVALID_DATA;
 	}
+
 	keypair.certificate_len = keypair.cert.length;
-	ndr_err = ndr_push_struct_blob(&blobkeypair, ctx, &keypair, (ndr_push_flags_fn_t)ndr_push_bkrp_exported_RSA_key_pair);
+	ndr_err = ndr_push_struct_blob(&blobkeypair,
+				       mem_ctx,
+				       &keypair,
+				       (ndr_push_flags_fn_t)ndr_push_bkrp_exported_RSA_key_pair);
+	gnutls_privkey_deinit(issuer_privkey);
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-		der_free_octet_string(&data);
-		hx509_cert_free(cert);
-		hx509_private_key_free(&pk);
-		hx509_context_free(&hctx);
-		RSA_free(rsa);
 		return WERR_INVALID_DATA;
 	}
 
-	secret_name = talloc_asprintf(ctx, "BCKUPKEY_%s", GUID_string(ctx, &guid));
+	secret_name = talloc_asprintf(mem_ctx, "BCKUPKEY_%s", GUID_string(mem_ctx, &guid));
 	if (secret_name == NULL) {
-		der_free_octet_string(&data);
-		hx509_cert_free(cert);
-		hx509_private_key_free(&pk);
-		hx509_context_free(&hctx);
-		RSA_free(rsa);
 		return WERR_OUTOFMEMORY;
 	}
 
-	status = set_lsa_secret(ctx, ldb_ctx, secret_name, &blobkeypair);
+	status = set_lsa_secret(mem_ctx, ldb_ctx, secret_name, &blobkeypair);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(2, ("Failed to save the secret %s\n", secret_name));
 	}
 	talloc_free(secret_name);
 
-	GUID_to_ndr_blob(&guid, ctx, &blob);
-	status = set_lsa_secret(ctx, ldb_ctx, "BCKUPKEY_PREFERRED", &blob);
+	GUID_to_ndr_blob(&guid, mem_ctx, &blob);
+	status = set_lsa_secret(mem_ctx, ldb_ctx, "BCKUPKEY_PREFERRED", &blob);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(2, ("Failed to save the secret BCKUPKEY_PREFERRED\n"));
 	}
 
-	der_free_octet_string(&data);
-	hx509_cert_free(cert);
-	hx509_private_key_free(&pk);
-	hx509_context_free(&hctx);
-	RSA_free(rsa);
 	return WERR_OK;
 }
 
@@ -1489,7 +1380,7 @@ static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 {
 	WERROR werr;
 	struct bkrp_server_side_wrapped decrypt_request;
-	DATA_BLOB sid_blob, encrypted_blob, symkey_blob;
+	DATA_BLOB sid_blob, encrypted_blob;
 	DATA_BLOB blob;
 	enum ndr_err_code ndr_err;
 	struct bkrp_dc_serverwrap_key server_key;
@@ -1498,8 +1389,10 @@ static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 	uint8_t symkey[20]; /* SHA-1 hash len */
 	uint8_t mackey[20]; /* SHA-1 hash len */
 	uint8_t mac[20]; /* SHA-1 hash len */
-	unsigned int hash_len;
-	HMAC_CTX ctx;
+	gnutls_hmac_hd_t hmac_hnd;
+	gnutls_cipher_hd_t cipher_hnd;
+	gnutls_datum_t cipher_key;
+	int rc;
 
 	blob.data = r->in.data_in;
 	blob.length = r->in.data_in_len;
@@ -1532,19 +1425,45 @@ static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
 	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
 	 */
-	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
-	     decrypt_request.r2, sizeof(decrypt_request.r2),
-	     symkey, &hash_len);
 
-	dump_data_pw("symkey: \n", symkey, hash_len);
+	gnutls_hmac_init(&hmac_hnd,
+			 GNUTLS_MAC_SHA1,
+			 server_key.key,
+			 sizeof(server_key.key));
+	gnutls_hmac(hmac_hnd,
+		    decrypt_request.r2,
+		    sizeof(decrypt_request.r2));
+	gnutls_hmac_output(hmac_hnd, symkey);
+
+	dump_data_pw("symkey: \n", symkey, sizeof(symkey));
 
 	/* rc4 decrypt sid and secret using sym key */
-	symkey_blob = data_blob_const(symkey, sizeof(symkey));
+	cipher_key.data = symkey;
+	cipher_key.size = sizeof(symkey);
 
 	encrypted_blob = data_blob_const(decrypt_request.rc4encryptedpayload,
 					 decrypt_request.ciphertext_length);
 
-	arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob);
+	rc = gnutls_cipher_init(&cipher_hnd,
+				GNUTLS_CIPHER_ARCFOUR_128,
+				&cipher_key,
+				NULL);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_cipher_init failed - %s\n",
+			gnutls_strerror(rc));
+		return WERR_INVALID_PARAM;
+	}
+	rc = gnutls_cipher_encrypt2(cipher_hnd,
+				    encrypted_blob.data,
+				    encrypted_blob.length,
+				    encrypted_blob.data,
+				    encrypted_blob.length);
+	gnutls_cipher_deinit(cipher_hnd);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_cipher_encrypt2 failed - %s\n",
+			gnutls_strerror(rc));
+		return WERR_INVALID_PARAM;
+	}
 
 	ndr_err = ndr_pull_struct_blob_all(&encrypted_blob, mem_ctx, &rc4payload,
 					   (ndr_pull_flags_fn_t)ndr_pull_bkrp_rc4encryptedpayload);
@@ -1562,9 +1481,10 @@ static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
 	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
 	 */
-	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
-	     rc4payload.r3, sizeof(rc4payload.r3),
-	     mackey, &hash_len);
+	gnutls_hmac(hmac_hnd,
+		    rc4payload.r3,
+		    sizeof(rc4payload.r3));
+	gnutls_hmac_deinit(hmac_hnd, mackey);
 
 	dump_data_pw("mackey: \n", mackey, sizeof(mackey));
 
@@ -1574,14 +1494,19 @@ static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
 		return WERR_INTERNAL_ERROR;
 	}
 
-	HMAC_CTX_init(&ctx);
-	HMAC_Init_ex(&ctx, mackey, hash_len, EVP_sha1(), NULL);
+	gnutls_hmac_init(&hmac_hnd,
+			 GNUTLS_MAC_SHA1,
+			 mackey,
+			 sizeof(mackey));
 	/* SID field */
-	HMAC_Update(&ctx, sid_blob.data, sid_blob.length);
+	gnutls_hmac(hmac_hnd,
+		    sid_blob.data,
+		    sid_blob.length);
 	/* Secret field */
-	HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length);
-	HMAC_Final(&ctx, mac, &hash_len);
-	HMAC_CTX_cleanup(&ctx);
+	gnutls_hmac(hmac_hnd,
+		    rc4payload.secret_data.data,
+		    rc4payload.secret_data.length);
+	gnutls_hmac_deinit(hmac_hnd, mac);
 
 	dump_data_pw("mac: \n", mac, sizeof(mac));
 	dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac));
@@ -1643,18 +1568,20 @@ static WERROR bkrp_generic_decrypt_data(struct dcesrv_call_state *dce_call, TALL
 static WERROR bkrp_server_wrap_encrypt_data(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
 					    struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx)
 {
-	DATA_BLOB sid_blob, encrypted_blob, symkey_blob, server_wrapped_blob;
+	DATA_BLOB sid_blob, encrypted_blob, server_wrapped_blob;
 	WERROR werr;
 	struct dom_sid *caller_sid;
 	uint8_t symkey[20]; /* SHA-1 hash len */
 	uint8_t mackey[20]; /* SHA-1 hash len */
-	unsigned int hash_len;
 	struct bkrp_rc4encryptedpayload rc4payload;
-	HMAC_CTX ctx;
+	gnutls_hmac_hd_t hmac_hnd;
 	struct bkrp_dc_serverwrap_key server_key;
 	enum ndr_err_code ndr_err;
 	struct bkrp_server_side_wrapped server_side_wrapped;
 	struct GUID guid;
+	gnutls_cipher_hd_t cipher_hnd;
+	gnutls_datum_t cipher_key;
+	int rc;
 
 	if (r->in.data_in_len == 0 || r->in.data_in == NULL) {
 		return WERR_INVALID_PARAM;
@@ -1715,19 +1642,25 @@ static WERROR bkrp_server_wrap_encrypt_data(struct dcesrv_call_state *dce_call,
 	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
 	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
 	 */
-	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
-	     server_side_wrapped.r2, sizeof(server_side_wrapped.r2),
-	     symkey, &hash_len);
+	gnutls_hmac_init(&hmac_hnd,
+			 GNUTLS_MAC_SHA1,
+			 server_key.key,
+			 sizeof(server_key.key));
+	gnutls_hmac(hmac_hnd,
+		    server_side_wrapped.r2,
+		    sizeof(server_side_wrapped.r2));
+	gnutls_hmac_output(hmac_hnd, symkey);
 
-	dump_data_pw("symkey: \n", symkey, hash_len);
+	dump_data_pw("symkey: \n", symkey, sizeof(symkey));
 
 	/*
 	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
 	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
 	 */
-	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
-	     rc4payload.r3, sizeof(rc4payload.r3),
-	     mackey, &hash_len);
+	gnutls_hmac(hmac_hnd,
+		    rc4payload.r3,
+		    sizeof(rc4payload.r3));
+	gnutls_hmac_deinit(hmac_hnd, mackey);
 
 	dump_data_pw("mackey: \n", mackey, sizeof(mackey));
 
@@ -1740,14 +1673,19 @@ static WERROR bkrp_server_wrap_encrypt_data(struct dcesrv_call_state *dce_call,
 	rc4payload.secret_data.data = r->in.data_in;
 	rc4payload.secret_data.length = r->in.data_in_len;
 
-	HMAC_CTX_init(&ctx);
-	HMAC_Init_ex(&ctx, mackey, 20, EVP_sha1(), NULL);
+	gnutls_hmac_init(&hmac_hnd,
+			 GNUTLS_MAC_SHA1,
+			 mackey,
+			 sizeof(mackey));
 	/* SID field */
-	HMAC_Update(&ctx, sid_blob.data, sid_blob.length);
+	gnutls_hmac(hmac_hnd,
+		    sid_blob.data,
+		    sid_blob.length);
 	/* Secret field */
-	HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length);
-	HMAC_Final(&ctx, rc4payload.mac, &hash_len);
-	HMAC_CTX_cleanup(&ctx);
+	gnutls_hmac(hmac_hnd,
+		    rc4payload.secret_data.data,
+		    rc4payload.secret_data.length);
+	gnutls_hmac_deinit(hmac_hnd, rc4payload.mac);
 
 	dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac));
 
@@ -1760,8 +1698,29 @@ static WERROR bkrp_server_wrap_encrypt_data(struct dcesrv_call_state *dce_call,
 	}
 
 	/* rc4 encrypt sid and secret using sym key */
-	symkey_blob = data_blob_const(symkey, sizeof(symkey));
-	arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob);
+	cipher_key.data = symkey;
+	cipher_key.size = sizeof(symkey);
+
+	rc = gnutls_cipher_init(&cipher_hnd,
+				GNUTLS_CIPHER_ARCFOUR_128,
+				&cipher_key,
+				NULL);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_cipher_init failed - %s\n",
+			gnutls_strerror(rc));
+		return WERR_INVALID_PARAM;
+	}
+	rc = gnutls_cipher_encrypt2(cipher_hnd,
+				    encrypted_blob.data,
+				    encrypted_blob.length,
+				    encrypted_blob.data,
+				    encrypted_blob.length);
+	gnutls_cipher_deinit(cipher_hnd);
+	if (rc != GNUTLS_E_SUCCESS) {
+		DBG_ERR("gnutls_cipher_encrypt2 failed - %s\n",
+			gnutls_strerror(rc));
+		return WERR_INVALID_PARAM;
+	}
 
 	/* create server wrap structure */
 
@@ -1792,6 +1751,8 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call,
 	/* At which level we start to add more debug of what is done in the protocol */
 	const int debuglevel = 4;
 
+	gnutls_global_init();
+
 	if (DEBUGLVL(debuglevel)) {
 		const struct tsocket_address *remote_address;
 		remote_address = dcesrv_connection_get_remote_address(dce_call->conn);
@@ -1846,6 +1807,7 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call,
 	}
 	/*else: I am a RODC so I don't handle backup key protocol */
 
+	gnutls_global_deinit();
 	talloc_unlink(mem_ctx, ldb_ctx);
 	return error;
 }
diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey_heimdal.c b/source4/rpc_server/backupkey/dcesrv_backupkey_heimdal.c
new file mode 100644
index 0000000..90cc4fb
--- /dev/null
+++ b/source4/rpc_server/backupkey/dcesrv_backupkey_heimdal.c
@@ -0,0 +1,1852 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   endpoint server for the backupkey interface
+
+   Copyright (C) Matthieu Patou <mat at samba.org> 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpc_server/dcerpc_server.h"
+#include "librpc/gen_ndr/ndr_backupkey.h"
+#include "dsdb/common/util.h"
+#include "dsdb/samdb/samdb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "../lib/util/util_ldb.h"
+#include "param/param.h"
+#include "auth/session.h"
+#include "system/network.h"
+#include <com_err.h>
+#include <hx509.h>
+#include <hcrypto/rsa.h>
+#include <hcrypto/bn.h>
+#include <hcrypto/sha.h>
+#include <hcrypto/evp.h>
+#include <hcrypto/hmac.h>
+#include <der.h>
+#include "../lib/tsocket/tsocket.h"
+#include "../libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/crypto/arcfour.h"
+#include "libds/common/roles.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#if defined(HAVE_GCRYPT_H) && !defined(HAVE_GNUTLS3)
+#include <gcrypt.h>
+#endif
+
+
+static const unsigned rsa_with_var_num[] = { 1, 2, 840, 113549, 1, 1, 1 };
+/* Equivalent to asn1_oid_id_pkcs1_rsaEncryption*/
+static const AlgorithmIdentifier _hx509_signature_rsa_with_var_num = {
+	{ 7, discard_const_p(unsigned, rsa_with_var_num) }, NULL
+};
+
+static NTSTATUS set_lsa_secret(TALLOC_CTX *mem_ctx,
+			       struct ldb_context *ldb,
+			       const char *name,
+			       const DATA_BLOB *lsa_secret)
+{
+	struct ldb_message *msg;
+	struct ldb_result *res;
+	struct ldb_dn *domain_dn;
+	struct ldb_dn *system_dn;
+	struct ldb_val val;
+	int ret;
+	char *name2;
+	struct timeval now = timeval_current();
+	NTTIME nt_now = timeval_to_nttime(&now);
+	const char *attrs[] = {
+		NULL
+	};
+
+	domain_dn = ldb_get_default_basedn(ldb);
+	if (!domain_dn) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	msg = ldb_msg_new(mem_ctx);
+	if (msg == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	/*
+	 * This function is a lot like dcesrv_lsa_CreateSecret
+	 * in the rpc_server/lsa directory
+	 * The reason why we duplicate the effort here is that:
+	 * * we want to keep the former function static
+	 * * we want to avoid the burden of doing LSA calls
+	 *   when we can just manipulate the secrets directly
+	 * * taillor the function to the particular needs of backup protocol
+	 */
+
+	system_dn = samdb_search_dn(ldb, msg, domain_dn, "(&(objectClass=container)(cn=System))");
+	if (system_dn == NULL) {
+		talloc_free(msg);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	name2 = talloc_asprintf(msg, "%s Secret", name);
+	if (name2 == NULL) {
+		talloc_free(msg);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ret = ldb_search(ldb, mem_ctx, &res, system_dn, LDB_SCOPE_SUBTREE, attrs,
+			   "(&(cn=%s)(objectclass=secret))",
+			   ldb_binary_encode_string(mem_ctx, name2));
+
+	if (ret != LDB_SUCCESS ||  res->count != 0 ) {
+		DEBUG(2, ("Secret %s already exists !\n", name2));
+		talloc_free(msg);
+		return NT_STATUS_OBJECT_NAME_COLLISION;
+	}
+
+	/*
+	 * We don't care about previous value as we are
+	 * here only if the key didn't exists before
+	 */
+
+	msg->dn = ldb_dn_copy(mem_ctx, system_dn);
+	if (msg->dn == NULL) {
+		talloc_free(msg);
+		return NT_STATUS_NO_MEMORY;
+	}
+	if (!ldb_dn_add_child_fmt(msg->dn, "cn=%s", name2)) {
+		talloc_free(msg);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ret = ldb_msg_add_string(msg, "cn", name2);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(msg);
+		return NT_STATUS_NO_MEMORY;
+	}
+	ret = ldb_msg_add_string(msg, "objectClass", "secret");
+	if (ret != LDB_SUCCESS) {
+		talloc_free(msg);
+		return NT_STATUS_NO_MEMORY;
+	}
+	ret = samdb_msg_add_uint64(ldb, mem_ctx, msg, "priorSetTime", nt_now);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(msg);
+		return NT_STATUS_NO_MEMORY;
+	}
+	val.data = lsa_secret->data;
+	val.length = lsa_secret->length;
+	ret = ldb_msg_add_value(msg, "currentValue", &val, NULL);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(msg);
+		return NT_STATUS_NO_MEMORY;
+	}
+	ret = samdb_msg_add_uint64(ldb, mem_ctx, msg, "lastSetTime", nt_now);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(msg);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	/*
+	 * create the secret with DSDB_MODIFY_RELAX
+	 * otherwise dsdb/samdb/ldb_modules/objectclass.c forbid
+	 * the create of LSA secret object
+	 */
+	ret = dsdb_add(ldb, msg, DSDB_MODIFY_RELAX);
+	if (ret != LDB_SUCCESS) {
+		DEBUG(2,("Failed to create secret record %s: %s\n",
+			ldb_dn_get_linearized(msg->dn),
+			ldb_errstring(ldb)));
+		talloc_free(msg);
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	talloc_free(msg);
+	return NT_STATUS_OK;
+}
+
+/* This function is pretty much like dcesrv_lsa_QuerySecret */
+static NTSTATUS get_lsa_secret(TALLOC_CTX *mem_ctx,
+			       struct ldb_context *ldb,
+			       const char *name,
+			       DATA_BLOB *lsa_secret)
+{
+	TALLOC_CTX *tmp_mem;
+	struct ldb_result *res;
+	struct ldb_dn *domain_dn;
+	struct ldb_dn *system_dn;
+	const struct ldb_val *val;
+	uint8_t *data;
+	const char *attrs[] = {
+		"currentValue",
+		NULL
+	};
+	int ret;
+
+	lsa_secret->data = NULL;
+	lsa_secret->length = 0;
+
+	domain_dn = ldb_get_default_basedn(ldb);
+	if (!domain_dn) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	tmp_mem = talloc_new(mem_ctx);
+	if (tmp_mem == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	system_dn = samdb_search_dn(ldb, tmp_mem, domain_dn, "(&(objectClass=container)(cn=System))");
+	if (system_dn == NULL) {
+		talloc_free(tmp_mem);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ret = ldb_search(ldb, mem_ctx, &res, system_dn, LDB_SCOPE_SUBTREE, attrs,
+			   "(&(cn=%s Secret)(objectclass=secret))",
+			   ldb_binary_encode_string(tmp_mem, name));
+
+	if (ret != LDB_SUCCESS) {
+		talloc_free(tmp_mem);
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+	if (res->count == 0) {
+		talloc_free(tmp_mem);
+		return NT_STATUS_RESOURCE_NAME_NOT_FOUND;
+	}
+	if (res->count > 1) {
+		DEBUG(2, ("Secret %s collision\n", name));
+		talloc_free(tmp_mem);
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+
+	val = ldb_msg_find_ldb_val(res->msgs[0], "currentValue");
+	if (val == NULL) {
+		/*
+		 * The secret object is here but we don't have the secret value
+		 * The most common case is a RODC
+		 */
+		*lsa_secret = data_blob_null;
+		talloc_free(tmp_mem);
+		return NT_STATUS_OK;
+	}
+
+	data = val->data;
+	lsa_secret->data = talloc_move(mem_ctx, &data);
+	lsa_secret->length = val->length;
+
+	talloc_free(tmp_mem);
+	return NT_STATUS_OK;
+}
+
+static DATA_BLOB *reverse_and_get_blob(TALLOC_CTX *mem_ctx, BIGNUM *bn)
+{
+	DATA_BLOB blob;
+	DATA_BLOB *rev = talloc(mem_ctx, DATA_BLOB);
+	uint32_t i;
+
+	blob.length = BN_num_bytes(bn);
+	blob.data = talloc_array(mem_ctx, uint8_t, blob.length);
+
+	if (blob.data == NULL) {
+		return NULL;
+	}
+
+	BN_bn2bin(bn, blob.data);
+
+	rev->data = talloc_array(mem_ctx, uint8_t, blob.length);
+	if (rev->data == NULL) {
+		return NULL;
+	}
+
+	for(i=0; i < blob.length; i++) {
+		rev->data[i] = blob.data[blob.length - i -1];
+	}
+	rev->length = blob.length;
+	talloc_free(blob.data);
+	return rev;
+}
+
+static BIGNUM *reverse_and_get_bignum(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
+{
+	BIGNUM *ret;
+	DATA_BLOB rev;
+	uint32_t i;
+
+	rev.data = talloc_array(mem_ctx, uint8_t, blob->length);
+	if (rev.data == NULL) {
+		return NULL;
+	}
+
+	for(i=0; i < blob->length; i++) {
+		rev.data[i] = blob->data[blob->length - i -1];
+	}
+	rev.length = blob->length;
+
+	ret = BN_bin2bn(rev.data, rev.length, NULL);
+	talloc_free(rev.data);
+
+	return ret;
+}
+
+static NTSTATUS get_pk_from_raw_keypair_params(TALLOC_CTX *ctx,
+				struct bkrp_exported_RSA_key_pair *keypair,
+				hx509_private_key *pk)
+{
+	hx509_context hctx;
+	RSA *rsa;
+	struct hx509_private_key_ops *ops;
+	hx509_private_key privkey = NULL;
+
+	hx509_context_init(&hctx);
+	ops = hx509_find_private_alg(&_hx509_signature_rsa_with_var_num.algorithm);
+	if (ops == NULL) {
+		DEBUG(2, ("Not supported algorithm\n"));
+		hx509_context_free(&hctx);
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	if (hx509_private_key_init(&privkey, ops, NULL) != 0) {
+		hx509_context_free(&hctx);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	rsa = RSA_new();
+	if (rsa ==NULL) {
+		hx509_private_key_free(&privkey);
+		hx509_context_free(&hctx);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	rsa->n = reverse_and_get_bignum(ctx, &(keypair->modulus));
+	if (rsa->n == NULL) {
+		RSA_free(rsa);
+		hx509_private_key_free(&privkey);
+		hx509_context_free(&hctx);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+	rsa->d = reverse_and_get_bignum(ctx, &(keypair->private_exponent));
+	if (rsa->d == NULL) {
+		RSA_free(rsa);
+		hx509_private_key_free(&privkey);
+		hx509_context_free(&hctx);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+	rsa->p = reverse_and_get_bignum(ctx, &(keypair->prime1));
+	if (rsa->p == NULL) {
+		RSA_free(rsa);
+		hx509_private_key_free(&privkey);
+		hx509_context_free(&hctx);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+	rsa->q = reverse_and_get_bignum(ctx, &(keypair->prime2));
+	if (rsa->q == NULL) {
+		RSA_free(rsa);
+		hx509_private_key_free(&privkey);
+		hx509_context_free(&hctx);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+	rsa->dmp1 = reverse_and_get_bignum(ctx, &(keypair->exponent1));
+	if (rsa->dmp1 == NULL) {
+		RSA_free(rsa);
+		hx509_private_key_free(&privkey);
+		hx509_context_free(&hctx);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+	rsa->dmq1 = reverse_and_get_bignum(ctx, &(keypair->exponent2));
+	if (rsa->dmq1 == NULL) {
+		RSA_free(rsa);
+		hx509_private_key_free(&privkey);
+		hx509_context_free(&hctx);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+	rsa->iqmp = reverse_and_get_bignum(ctx, &(keypair->coefficient));
+	if (rsa->iqmp == NULL) {
+		RSA_free(rsa);
+		hx509_private_key_free(&privkey);
+		hx509_context_free(&hctx);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+	rsa->e = reverse_and_get_bignum(ctx, &(keypair->public_exponent));
+	if (rsa->e == NULL) {
+		RSA_free(rsa);
+		hx509_private_key_free(&privkey);
+		hx509_context_free(&hctx);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	*pk = privkey;
+
+	hx509_private_key_assign_rsa(*pk, rsa);
+
+	hx509_context_free(&hctx);
+	return NT_STATUS_OK;
+}
+
+static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx,
+					  uint32_t version,
+					  uint8_t *key_and_iv,
+					  uint8_t *access_check,
+					  uint32_t access_check_len,
+					  struct auth_session_info *session_info)
+{
+	heim_octet_string iv;
+	heim_octet_string access_check_os;
+	hx509_crypto crypto;
+
+	DATA_BLOB blob_us;
+	uint32_t key_len;
+	uint32_t iv_len;
+	int res;
+	enum ndr_err_code ndr_err;
+	hx509_context hctx;
+
+	struct dom_sid *access_sid = NULL;
+	struct dom_sid *caller_sid = NULL;
+
+	/* This one should not be freed */
+	const AlgorithmIdentifier *alg;
+
+	switch (version) {
+	case 2:
+		key_len = 24;
+		iv_len = 8;
+		alg = hx509_crypto_des_rsdi_ede3_cbc();
+		break;
+
+	case 3:
+		key_len = 32;
+		iv_len = 16;
+		alg =hx509_crypto_aes256_cbc();
+		break;
+
+	default:
+		return WERR_INVALID_DATA;
+	}
+
+	hx509_context_init(&hctx);
+	res = hx509_crypto_init(hctx, NULL,
+				&(alg->algorithm),
+				&crypto);
+	hx509_context_free(&hctx);
+
+	if (res != 0) {
+		return WERR_INVALID_DATA;
+	}
+
+	res = hx509_crypto_set_key_data(crypto, key_and_iv, key_len);
+
+	iv.data = talloc_memdup(sub_ctx, key_len + key_and_iv, iv_len);
+	iv.length = iv_len;
+
+	if (res != 0) {
+		hx509_crypto_destroy(crypto);
+		return WERR_INVALID_DATA;
+	}
+
+	hx509_crypto_set_padding(crypto, HX509_CRYPTO_PADDING_NONE);
+	res = hx509_crypto_decrypt(crypto,
+		access_check,
+		access_check_len,
+		&iv,
+		&access_check_os);
+
+	if (res != 0) {
+		hx509_crypto_destroy(crypto);
+		return WERR_INVALID_DATA;
+	}
+
+	blob_us.data = access_check_os.data;
+	blob_us.length = access_check_os.length;
+
+	hx509_crypto_destroy(crypto);
+
+	switch (version) {
+	case 2:
+	{
+		uint32_t hash_size = 20;
+		uint8_t hash[hash_size];
+		struct sha sctx;
+		struct bkrp_access_check_v2 uncrypted_accesscheckv2;
+
+		ndr_err = ndr_pull_struct_blob(&blob_us, sub_ctx, &uncrypted_accesscheckv2,
+					(ndr_pull_flags_fn_t)ndr_pull_bkrp_access_check_v2);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			/* Unable to unmarshall */
+			der_free_octet_string(&access_check_os);
+			return WERR_INVALID_DATA;
+		}
+		if (uncrypted_accesscheckv2.magic != 0x1) {
+			/* wrong magic */
+			der_free_octet_string(&access_check_os);
+			return WERR_INVALID_DATA;
+		}
+
+		SHA1_Init(&sctx);
+		SHA1_Update(&sctx, blob_us.data, blob_us.length - hash_size);
+		SHA1_Final(hash, &sctx);
+		der_free_octet_string(&access_check_os);
+		/*
+		 * We free it after the sha1 calculation because blob.data
+		 * point to the same area
+		 */
+
+		if (memcmp(hash, uncrypted_accesscheckv2.hash, hash_size) != 0) {
+			DEBUG(2, ("Wrong hash value in the access check in backup key remote protocol\n"));
+			return WERR_INVALID_DATA;
+		}
+		access_sid = &(uncrypted_accesscheckv2.sid);
+		break;
+	}
+	case 3:
+	{
+		uint32_t hash_size = 64;
+		uint8_t hash[hash_size];
+		struct hc_sha512state sctx;
+		struct bkrp_access_check_v3 uncrypted_accesscheckv3;
+
+		ndr_err = ndr_pull_struct_blob(&blob_us, sub_ctx, &uncrypted_accesscheckv3,
+					(ndr_pull_flags_fn_t)ndr_pull_bkrp_access_check_v3);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			/* Unable to unmarshall */
+			der_free_octet_string(&access_check_os);
+			return WERR_INVALID_DATA;
+		}
+		if (uncrypted_accesscheckv3.magic != 0x1) {
+			/* wrong magic */
+			der_free_octet_string(&access_check_os);
+			return WERR_INVALID_DATA;
+		}
+
+		SHA512_Init(&sctx);
+		SHA512_Update(&sctx, blob_us.data, blob_us.length - hash_size);
+		SHA512_Final(hash, &sctx);
+		der_free_octet_string(&access_check_os);
+		/*
+		 * We free it after the sha1 calculation because blob.data
+		 * point to the same area
+		 */
+
+		if (memcmp(hash, uncrypted_accesscheckv3.hash, hash_size) != 0) {
+			DEBUG(2, ("Wrong hash value in the access check in backup key remote protocol\n"));
+			return WERR_INVALID_DATA;
+		}
+		access_sid = &(uncrypted_accesscheckv3.sid);
+		break;
+	}
+	default:
+		/* Never reached normally as we filtered at the switch / case level */
+		return WERR_INVALID_DATA;
+	}
+
+	caller_sid = &session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+
+	if (!dom_sid_equal(caller_sid, access_sid)) {
+		return WERR_INVALID_ACCESS;
+	}
+	return WERR_OK;
+}
+
+/*
+ * We have some data, such as saved website or IMAP passwords that the
+ * client has in profile on-disk.  This needs to be decrypted.  This
+ * version gives the server the data over the network (protected by
+ * the X.509 certificate and public key encryption, and asks that it
+ * be decrypted returned for short-term use, protected only by the
+ * negotiated transport encryption.
+ *
+ * The data is NOT stored in the LSA, but a X.509 certificate, public
+ * and private keys used to encrypt the data will be stored.  There is
+ * only one active encryption key pair and certificate per domain, it
+ * is pointed at with G$BCKUPKEY_PREFERRED in the LSA secrets store.
+ *
+ * The potentially multiple valid decrypting key pairs are in turn
+ * stored in the LSA secrets store as G$BCKUPKEY_keyGuidString.
+ *
+ */
+static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call,
+					    TALLOC_CTX *mem_ctx,
+					    struct bkrp_BackupKey *r,
+					    struct ldb_context *ldb_ctx)
+{
+	struct bkrp_client_side_wrapped uncrypt_request;
+	DATA_BLOB blob;
+	enum ndr_err_code ndr_err;
+	char *guid_string;
+	char *cert_secret_name;
+	DATA_BLOB lsa_secret;
+	DATA_BLOB *uncrypted_data = NULL;
+	NTSTATUS status;
+	uint32_t requested_version;
+
+	blob.data = r->in.data_in;
+	blob.length = r->in.data_in_len;
+
+	if (r->in.data_in_len < 4 || r->in.data_in == NULL) {
+		return WERR_INVALID_PARAM;
+	}
+
+	/*
+	 * We check for the version here, so we can actually print the
+	 * message as we are unlikely to parse it with NDR.
+	 */
+	requested_version = IVAL(r->in.data_in, 0);
+	if ((requested_version != BACKUPKEY_CLIENT_WRAP_VERSION2)
+	    && (requested_version != BACKUPKEY_CLIENT_WRAP_VERSION3)) {
+		DEBUG(1, ("Request for unknown BackupKey sub-protocol %d\n", requested_version));
+		return WERR_INVALID_PARAMETER;
+	}
+
+	ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &uncrypt_request,
+				       (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_wrapped);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return WERR_INVALID_PARAM;
+	}
+
+	if ((uncrypt_request.version != BACKUPKEY_CLIENT_WRAP_VERSION2)
+	    && (uncrypt_request.version != BACKUPKEY_CLIENT_WRAP_VERSION3)) {
+		DEBUG(1, ("Request for unknown BackupKey sub-protocol %d\n", uncrypt_request.version));
+		return WERR_INVALID_PARAMETER;
+	}
+
+	guid_string = GUID_string(mem_ctx, &uncrypt_request.guid);
+	if (guid_string == NULL) {
+		return WERR_NOMEM;
+	}
+
+	cert_secret_name = talloc_asprintf(mem_ctx,
+					   "BCKUPKEY_%s",
+					   guid_string);
+	if (cert_secret_name == NULL) {
+		return WERR_NOMEM;
+	}
+
+	status = get_lsa_secret(mem_ctx,
+				ldb_ctx,
+				cert_secret_name,
+				&lsa_secret);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(10, ("Error while fetching secret %s\n", cert_secret_name));
+		return WERR_INVALID_DATA;
+	} else if (lsa_secret.length == 0) {
+		/* we do not have the real secret attribute, like if we are an RODC */
+		return WERR_INVALID_PARAMETER;
+	} else {
+		hx509_context hctx;
+		struct bkrp_exported_RSA_key_pair keypair;
+		hx509_private_key pk;
+		uint32_t i, res;
+		heim_octet_string reversed_secret;
+		heim_octet_string uncrypted_secret;
+		AlgorithmIdentifier alg;
+		DATA_BLOB blob_us;
+		WERROR werr;
+
+		ndr_err = ndr_pull_struct_blob(&lsa_secret, mem_ctx, &keypair, (ndr_pull_flags_fn_t)ndr_pull_bkrp_exported_RSA_key_pair);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			DEBUG(2, ("Unable to parse the ndr encoded cert in key %s\n", cert_secret_name));
+			return WERR_FILE_NOT_FOUND;
+		}
+
+		status = get_pk_from_raw_keypair_params(mem_ctx, &keypair, &pk);
+		if (!NT_STATUS_IS_OK(status)) {
+			return WERR_INTERNAL_ERROR;
+		}
+
+		reversed_secret.data = talloc_array(mem_ctx, uint8_t,
+						    uncrypt_request.encrypted_secret_len);
+		if (reversed_secret.data == NULL) {
+			hx509_private_key_free(&pk);
+			return WERR_NOMEM;
+		}
+
+		/* The secret has to be reversed ... */
+		for(i=0; i< uncrypt_request.encrypted_secret_len; i++) {
+			uint8_t *reversed = (uint8_t *)reversed_secret.data;
+			uint8_t *uncrypt = uncrypt_request.encrypted_secret;
+			reversed[i] = uncrypt[uncrypt_request.encrypted_secret_len - 1 - i];
+		}
+		reversed_secret.length = uncrypt_request.encrypted_secret_len;
+
+		/*
+		 * Let's try to decrypt the secret now that
+		 * we have the private key ...
+		 */
+		hx509_context_init(&hctx);
+		res = hx509_private_key_private_decrypt(hctx, &reversed_secret,
+							 &alg.algorithm, pk,
+							 &uncrypted_secret);
+		hx509_context_free(&hctx);
+		hx509_private_key_free(&pk);
+		if (res != 0) {
+			/* We are not able to decrypt the secret, looks like something is wrong */
+			return WERR_INVALID_PARAMETER;
+		}
+		blob_us.data = uncrypted_secret.data;
+		blob_us.length = uncrypted_secret.length;
+
+		if (uncrypt_request.version == 2) {
+			struct bkrp_encrypted_secret_v2 uncrypted_secretv2;
+
+			ndr_err = ndr_pull_struct_blob(&blob_us, mem_ctx, &uncrypted_secretv2,
+					(ndr_pull_flags_fn_t)ndr_pull_bkrp_encrypted_secret_v2);
+			der_free_octet_string(&uncrypted_secret);
+			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+				/* Unable to unmarshall */
+				return WERR_INVALID_DATA;
+			}
+			if (uncrypted_secretv2.magic != 0x20) {
+				/* wrong magic */
+				return WERR_INVALID_DATA;
+			}
+
+			werr = get_and_verify_access_check(mem_ctx, 2,
+							   uncrypted_secretv2.payload_key,
+							   uncrypt_request.access_check,
+							   uncrypt_request.access_check_len,
+							   dce_call->conn->auth_state.session_info);
+			if (!W_ERROR_IS_OK(werr)) {
+				return werr;
+			}
+			uncrypted_data = talloc(mem_ctx, DATA_BLOB);
+			if (uncrypted_data == NULL) {
+				return WERR_INVALID_DATA;
+			}
+
+			uncrypted_data->data = uncrypted_secretv2.secret;
+			uncrypted_data->length = uncrypted_secretv2.secret_len;
+		}
+		if (uncrypt_request.version == 3) {
+			struct bkrp_encrypted_secret_v3 uncrypted_secretv3;
+
+			ndr_err = ndr_pull_struct_blob(&blob_us, mem_ctx, &uncrypted_secretv3,
+					(ndr_pull_flags_fn_t)ndr_pull_bkrp_encrypted_secret_v3);
+
+			der_free_octet_string(&uncrypted_secret);
+			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+				/* Unable to unmarshall */
+				return WERR_INVALID_DATA;
+			}
+
+			if (uncrypted_secretv3.magic1 != 0x30  ||
+			    uncrypted_secretv3.magic2 != 0x6610 ||
+			    uncrypted_secretv3.magic3 != 0x800e) {
+				/* wrong magic */
+				return WERR_INVALID_DATA;
+			}
+
+			/*
+			 * Confirm that the caller is permitted to
+			 * read this particular data.  Because one key
+			 * pair is used per domain, the caller could
+			 * have stolen the profile data on-disk and
+			 * would otherwise be able to read the
+			 * passwords.
+			 */
+
+			werr = get_and_verify_access_check(mem_ctx, 3,
+							   uncrypted_secretv3.payload_key,
+							   uncrypt_request.access_check,
+							   uncrypt_request.access_check_len,
+							   dce_call->conn->auth_state.session_info);
+			if (!W_ERROR_IS_OK(werr)) {
+				return werr;
+			}
+
+			uncrypted_data = talloc(mem_ctx, DATA_BLOB);
+			if (uncrypted_data == NULL) {
+				return WERR_INVALID_DATA;
+			}
+
+			uncrypted_data->data = uncrypted_secretv3.secret;
+			uncrypted_data->length = uncrypted_secretv3.secret_len;
+		}
+
+		/*
+		 * Yeah if we are here all looks pretty good:
+		 * - hash is ok
+		 * - user sid is the same as the one in access check
+		 * - we were able to decrypt the whole stuff
+		 */
+	}
+
+	if (uncrypted_data->data == NULL) {
+		return WERR_INVALID_DATA;
+	}
+
+	/* There is a magic value a the beginning of the data
+	 * we can use an adhoc structure but as the
+	 * parent structure is just an array of bytes it a lot of work
+	 * work just prepending 4 bytes
+	 */
+	*(r->out.data_out) = talloc_zero_array(mem_ctx, uint8_t, uncrypted_data->length + 4);
+	W_ERROR_HAVE_NO_MEMORY(*(r->out.data_out));
+	memcpy(4+*(r->out.data_out), uncrypted_data->data, uncrypted_data->length);
+	*(r->out.data_out_len) = uncrypted_data->length + 4;
+
+	return WERR_OK;
+}
+
+/*
+ * Strictly, this function no longer uses Heimdal in order to generate an RSA
+ * key, but GnuTLS.
+ *
+ * The resulting key is then imported into Heimdal's RSA structure.
+ *
+ * We use GnuTLS because it can reliably generate 2048 bit keys every time.
+ * Windows clients strictly require 2048, no more since it won't fit and no
+ * less either. Heimdal would almost always generate a smaller key.
+ */
+static WERROR create_heimdal_rsa_key(TALLOC_CTX *ctx, hx509_context *hctx,
+				     hx509_private_key *pk, RSA **rsa)
+{
+	int ret;
+	uint8_t *p0 = NULL;
+	const uint8_t *p;
+	size_t len;
+	int bits = 2048;
+	int RSA_returned_bits;
+	gnutls_x509_privkey_t gtls_key;
+	WERROR werr;
+
+	*rsa = NULL;
+
+	gnutls_global_init();
+#if defined(HAVE_GCRYPT_H) && !defined(HAVE_GNUTLS3)
+	DEBUG(3,("Enabling QUICK mode in gcrypt\n"));
+	gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#endif
+	ret = gnutls_x509_privkey_init(&gtls_key);
+	if (ret != 0) {
+		gnutls_global_deinit();
+		return WERR_INTERNAL_ERROR;
+	}
+
+	/*
+	 * Unlike Heimdal's RSA_generate_key_ex(), this generates a
+	 * 2048 bit key 100% of the time.  The heimdal code had a ~1/8
+	 * chance of doing so, chewing vast quantities of computation
+	 * and entropy in the process.
+	 */
+
+	ret = gnutls_x509_privkey_generate(gtls_key, GNUTLS_PK_RSA, bits, 0);
+	if (ret != 0) {
+		werr = WERR_INTERNAL_ERROR;
+		goto done;
+	}
+
+	/* No need to check error code, this SHOULD fail */
+	gnutls_x509_privkey_export(gtls_key, GNUTLS_X509_FMT_DER, NULL, &len);
+
+	if (len < 1) {
+		werr = WERR_INTERNAL_ERROR;
+		goto done;
+	}
+
+	p0 = talloc_size(ctx, len);
+	if (p0 == NULL) {
+		werr = WERR_NOMEM;
+		goto done;
+	}
+	p = p0;
+
+	/*
+	 * Only this GnuTLS export function correctly exports the key,
+	 * we can't use gnutls_rsa_params_export_raw() because while
+	 * it appears to be fixed in more recent versions, in the
+	 * Ubuntu 14.04 version 2.12.23 (at least) it incorrectly
+	 * exports one of the key parameters (qInv).  Additionally, we
+	 * would have to work around subtle differences in big number
+	 * representations.
+	 *
+	 * We need access to the RSA parameters directly (in the
+	 * parameter RSA **rsa) as the caller has to manually encode
+	 * them in a non-standard data structure.
+	 */
+	ret = gnutls_x509_privkey_export(gtls_key, GNUTLS_X509_FMT_DER, p0, &len);
+
+	if (ret != 0) {
+		werr = WERR_INTERNAL_ERROR;
+		goto done;
+	}
+
+	/*
+	 * To dump the key we can use :
+	 * rk_dumpdata("h5lkey", p0, len);
+	 */
+	ret = hx509_parse_private_key(*hctx, &_hx509_signature_rsa_with_var_num ,
+				       p0, len, HX509_KEY_FORMAT_DER, pk);
+
+	if (ret != 0) {
+		werr = WERR_INTERNAL_ERROR;
+		goto done;
+	}
+
+	*rsa = d2i_RSAPrivateKey(NULL, &p, len);
+	TALLOC_FREE(p0);
+
+	if (*rsa == NULL) {
+		hx509_private_key_free(pk);
+		werr = WERR_INTERNAL_ERROR;
+		goto done;
+	}
+
+	RSA_returned_bits = BN_num_bits((*rsa)->n);
+	DEBUG(6, ("GnuTLS returned an RSA private key with %d bits\n", RSA_returned_bits));
+
+	if (RSA_returned_bits != bits) {
+		DEBUG(0, ("GnuTLS unexpectedly returned an RSA private key with %d bits, needed %d\n", RSA_returned_bits, bits));
+		hx509_private_key_free(pk);
+		werr = WERR_INTERNAL_ERROR;
+		goto done;
+	}
+
+	werr = WERR_OK;
+
+done:
+	if (p0 != NULL) {
+		memset(p0, 0, len);
+		TALLOC_FREE(p0);
+	}
+
+	gnutls_x509_privkey_deinit(gtls_key);
+	gnutls_global_deinit();
+	return werr;
+}
+
+static WERROR self_sign_cert(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request *req,
+				time_t lifetime, hx509_private_key *private_key,
+				hx509_cert *cert, DATA_BLOB *guidblob)
+{
+	SubjectPublicKeyInfo spki;
+	hx509_name subject = NULL;
+	hx509_ca_tbs tbs;
+	struct heim_bit_string uniqueid;
+	struct heim_integer serialnumber;
+	int ret, i;
+
+	uniqueid.data = talloc_memdup(ctx, guidblob->data, guidblob->length);
+	if (uniqueid.data == NULL) {
+		return WERR_NOMEM;
+	}
+	/* uniqueid is a bit string in which each byte represent 1 bit (1 or 0)
+	 * so as 1 byte is 8 bits we need to provision 8 times more space as in the
+	 * blob
+	 */
+	uniqueid.length = 8 * guidblob->length;
+
+	serialnumber.data = talloc_array(ctx, uint8_t,
+					    guidblob->length);
+	if (serialnumber.data == NULL) {
+		talloc_free(uniqueid.data);
+		return WERR_NOMEM;
+	}
+
+	/* Native AD generates certificates with serialnumber in reversed notation */
+	for (i = 0; i < guidblob->length; i++) {
+		uint8_t *reversed = (uint8_t *)serialnumber.data;
+		uint8_t *uncrypt = guidblob->data;
+		reversed[i] = uncrypt[guidblob->length - 1 - i];
+	}
+	serialnumber.length = guidblob->length;
+	serialnumber.negative = 0;
+
+	memset(&spki, 0, sizeof(spki));
+
+	ret = hx509_request_get_name(*hctx, *req, &subject);
+	if (ret !=0) {
+		goto fail_subject;
+	}
+	ret = hx509_request_get_SubjectPublicKeyInfo(*hctx, *req, &spki);
+	if (ret !=0) {
+		goto fail_spki;
+	}
+
+	ret = hx509_ca_tbs_init(*hctx, &tbs);
+	if (ret !=0) {
+		goto fail_tbs;
+	}
+
+	ret = hx509_ca_tbs_set_spki(*hctx, tbs, &spki);
+	if (ret !=0) {
+		goto fail;
+	}
+	ret = hx509_ca_tbs_set_subject(*hctx, tbs, subject);
+	if (ret !=0) {
+		goto fail;
+	}
+	ret = hx509_ca_tbs_set_notAfter_lifetime(*hctx, tbs, lifetime);
+	if (ret !=0) {
+		goto fail;
+	}
+	ret = hx509_ca_tbs_set_unique(*hctx, tbs, &uniqueid, &uniqueid);
+	if (ret !=0) {
+		goto fail;
+	}
+	ret = hx509_ca_tbs_set_serialnumber(*hctx, tbs, &serialnumber);
+	if (ret !=0) {
+		goto fail;
+	}
+	ret = hx509_ca_sign_self(*hctx, tbs, *private_key, cert);
+	if (ret !=0) {
+		goto fail;
+	}
+	hx509_name_free(&subject);
+	free_SubjectPublicKeyInfo(&spki);
+	hx509_ca_tbs_free(&tbs);
+
+	return WERR_OK;
+
+fail:
+	hx509_ca_tbs_free(&tbs);
+fail_tbs:
+	free_SubjectPublicKeyInfo(&spki);
+fail_spki:
+	hx509_name_free(&subject);
+fail_subject:
+	talloc_free(uniqueid.data);
+	talloc_free(serialnumber.data);
+	return WERR_INTERNAL_ERROR;
+}
+
+static WERROR create_req(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request *req,
+			 hx509_private_key *signer,RSA **rsa, const char *dn)
+{
+	int ret;
+	SubjectPublicKeyInfo key;
+
+	hx509_name name;
+	WERROR werr;
+
+	werr = create_heimdal_rsa_key(ctx, hctx, signer, rsa);
+	if (!W_ERROR_IS_OK(werr)) {
+		return werr;
+	}
+
+	hx509_request_init(*hctx, req);
+	ret = hx509_parse_name(*hctx, dn, &name);
+	if (ret != 0) {
+		RSA_free(*rsa);
+		hx509_private_key_free(signer);
+		hx509_request_free(req);
+		hx509_name_free(&name);
+		return WERR_INTERNAL_ERROR;
+	}
+
+	ret = hx509_request_set_name(*hctx, *req, name);
+	if (ret != 0) {
+		RSA_free(*rsa);
+		hx509_private_key_free(signer);
+		hx509_request_free(req);
+		hx509_name_free(&name);
+		return WERR_INTERNAL_ERROR;
+	}
+	hx509_name_free(&name);
+
+	ret = hx509_private_key2SPKI(*hctx, *signer, &key);
+	if (ret != 0) {
+		RSA_free(*rsa);
+		hx509_private_key_free(signer);
+		hx509_request_free(req);
+		return WERR_INTERNAL_ERROR;
+	}
+	ret = hx509_request_set_SubjectPublicKeyInfo(*hctx, *req, &key);
+	if (ret != 0) {
+		RSA_free(*rsa);
+		hx509_private_key_free(signer);
+		free_SubjectPublicKeyInfo(&key);
+		hx509_request_free(req);
+		return WERR_INTERNAL_ERROR;
+	}
+
+	free_SubjectPublicKeyInfo(&key);
+
+	return WERR_OK;
+}
+
+/* Return an error when we fail to generate a certificate */
+static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_call, struct ldb_context *ldb_ctx, const char *dn)
+{
+	heim_octet_string data;
+	WERROR werr;
+	RSA *rsa;
+	hx509_context hctx;
+	hx509_private_key pk;
+	hx509_request req;
+	hx509_cert cert;
+	DATA_BLOB blob;
+	DATA_BLOB blobkeypair;
+	DATA_BLOB *tmp;
+	int ret;
+	bool ok = true;
+	struct GUID guid = GUID_random();
+	NTSTATUS status;
+	char *secret_name;
+	struct bkrp_exported_RSA_key_pair keypair;
+	enum ndr_err_code ndr_err;
+	uint32_t nb_seconds_validity = 3600 * 24 * 365;
+
+	DEBUG(6, ("Trying to generate a certificate\n"));
+	hx509_context_init(&hctx);
+	werr = create_req(ctx, &hctx, &req, &pk, &rsa, dn);
+	if (!W_ERROR_IS_OK(werr)) {
+		hx509_context_free(&hctx);
+		return werr;
+	}
+
+	status = GUID_to_ndr_blob(&guid, ctx, &blob);
+	if (!NT_STATUS_IS_OK(status)) {
+		hx509_context_free(&hctx);
+		hx509_private_key_free(&pk);
+		RSA_free(rsa);
+		return WERR_INVALID_DATA;
+	}
+
+	werr = self_sign_cert(ctx, &hctx, &req, nb_seconds_validity, &pk, &cert, &blob);
+	if (!W_ERROR_IS_OK(werr)) {
+		hx509_private_key_free(&pk);
+		hx509_context_free(&hctx);
+		return WERR_INVALID_DATA;
+	}
+
+	ret = hx509_cert_binary(hctx, cert, &data);
+	if (ret !=0) {
+		hx509_cert_free(cert);
+		hx509_private_key_free(&pk);
+		hx509_context_free(&hctx);
+		return WERR_INVALID_DATA;
+	}
+
+	keypair.cert.data = talloc_memdup(ctx, data.data, data.length);
+	keypair.cert.length = data.length;
+
+	/*
+	 * Heimdal's bignum are big endian and the
+	 * structure expect it to be in little endian
+	 * so we reverse the buffer to make it work
+	 */
+	tmp = reverse_and_get_blob(ctx, rsa->e);
+	if (tmp == NULL) {
+		ok = false;
+	} else {
+		keypair.public_exponent = *tmp;
+		SMB_ASSERT(tmp->length <= 4);
+		/*
+		 * The value is now in little endian but if can happen that the length is
+		 * less than 4 bytes.
+		 * So if we have less than 4 bytes we pad with zeros so that it correctly
+		 * fit into the structure.
+		 */
+		if (tmp->length < 4) {
+			/*
+			 * We need the expo to fit 4 bytes
+			 */
+			keypair.public_exponent.data = talloc_zero_array(ctx, uint8_t, 4);
+			memcpy(keypair.public_exponent.data, tmp->data, tmp->length);
+			keypair.public_exponent.length = 4;
+		}
+	}
+
+	tmp = reverse_and_get_blob(ctx,rsa->d);
+	if (tmp == NULL) {
+		ok = false;
+	} else {
+		keypair.private_exponent = *tmp;
+	}
+
+	tmp = reverse_and_get_blob(ctx,rsa->n);
+	if (tmp == NULL) {
+		ok = false;
+	} else {
+		keypair.modulus = *tmp;
+	}
+
+	tmp = reverse_and_get_blob(ctx,rsa->p);
+	if (tmp == NULL) {
+		ok = false;
+	} else {
+		keypair.prime1 = *tmp;
+	}
+
+	tmp = reverse_and_get_blob(ctx,rsa->q);
+	if (tmp == NULL) {
+		ok = false;
+	} else {
+		keypair.prime2 = *tmp;
+	}
+
+	tmp = reverse_and_get_blob(ctx,rsa->dmp1);
+	if (tmp == NULL) {
+		ok = false;
+	} else {
+		keypair.exponent1 = *tmp;
+	}
+
+	tmp = reverse_and_get_blob(ctx,rsa->dmq1);
+	if (tmp == NULL) {
+		ok = false;
+	} else {
+		keypair.exponent2 = *tmp;
+	}
+
+	tmp = reverse_and_get_blob(ctx,rsa->iqmp);
+	if (tmp == NULL) {
+		ok = false;
+	} else {
+		keypair.coefficient = *tmp;
+	}
+
+	/* One of the keypair allocation was wrong */
+	if (ok == false) {
+		der_free_octet_string(&data);
+		hx509_cert_free(cert);
+		hx509_private_key_free(&pk);
+		hx509_context_free(&hctx);
+		RSA_free(rsa);
+		return WERR_INVALID_DATA;
+	}
+	keypair.certificate_len = keypair.cert.length;
+	ndr_err = ndr_push_struct_blob(&blobkeypair, ctx, &keypair, (ndr_push_flags_fn_t)ndr_push_bkrp_exported_RSA_key_pair);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		der_free_octet_string(&data);
+		hx509_cert_free(cert);
+		hx509_private_key_free(&pk);
+		hx509_context_free(&hctx);
+		RSA_free(rsa);
+		return WERR_INVALID_DATA;
+	}
+
+	secret_name = talloc_asprintf(ctx, "BCKUPKEY_%s", GUID_string(ctx, &guid));
+	if (secret_name == NULL) {
+		der_free_octet_string(&data);
+		hx509_cert_free(cert);
+		hx509_private_key_free(&pk);
+		hx509_context_free(&hctx);
+		RSA_free(rsa);
+		return WERR_OUTOFMEMORY;
+	}
+
+	status = set_lsa_secret(ctx, ldb_ctx, secret_name, &blobkeypair);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(2, ("Failed to save the secret %s\n", secret_name));
+	}
+	talloc_free(secret_name);
+
+	GUID_to_ndr_blob(&guid, ctx, &blob);
+	status = set_lsa_secret(ctx, ldb_ctx, "BCKUPKEY_PREFERRED", &blob);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(2, ("Failed to save the secret BCKUPKEY_PREFERRED\n"));
+	}
+
+	der_free_octet_string(&data);
+	hx509_cert_free(cert);
+	hx509_private_key_free(&pk);
+	hx509_context_free(&hctx);
+	RSA_free(rsa);
+	return WERR_OK;
+}
+
+static WERROR bkrp_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+					    struct bkrp_BackupKey *r, struct ldb_context *ldb_ctx)
+{
+	struct GUID guid;
+	char *guid_string;
+	DATA_BLOB lsa_secret;
+	enum ndr_err_code ndr_err;
+	NTSTATUS status;
+
+	/*
+	 * here we basicaly need to return our certificate
+	 * search for lsa secret BCKUPKEY_PREFERRED first
+	 */
+
+	status = get_lsa_secret(mem_ctx,
+				ldb_ctx,
+				"BCKUPKEY_PREFERRED",
+				&lsa_secret);
+	if (NT_STATUS_EQUAL(status, NT_STATUS_RESOURCE_NAME_NOT_FOUND)) {
+		/* Ok we can be in this case if there was no certs */
+		struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+		char *dn = talloc_asprintf(mem_ctx, "CN=%s",
+					   lpcfg_realm(lp_ctx));
+
+		WERROR werr =  generate_bkrp_cert(mem_ctx, dce_call, ldb_ctx, dn);
+		if (!W_ERROR_IS_OK(werr)) {
+			return WERR_INVALID_PARAMETER;
+		}
+		status = get_lsa_secret(mem_ctx,
+					ldb_ctx,
+					"BCKUPKEY_PREFERRED",
+					&lsa_secret);
+
+		if (!NT_STATUS_IS_OK(status)) {
+			/* Ok we really don't manage to get this certs ...*/
+			DEBUG(2, ("Unable to locate BCKUPKEY_PREFERRED after cert generation\n"));
+			return WERR_FILE_NOT_FOUND;
+		}
+	} else if (!NT_STATUS_IS_OK(status)) {
+		return WERR_INTERNAL_ERROR;
+	}
+
+	if (lsa_secret.length == 0) {
+		DEBUG(1, ("No secret in BCKUPKEY_PREFERRED, are we an undetected RODC?\n"));
+		return WERR_INTERNAL_ERROR;
+	} else {
+		char *cert_secret_name;
+
+		status = GUID_from_ndr_blob(&lsa_secret, &guid);
+		if (!NT_STATUS_IS_OK(status)) {
+			return WERR_FILE_NOT_FOUND;
+		}
+
+		guid_string = GUID_string(mem_ctx, &guid);
+		if (guid_string == NULL) {
+			/* We return file not found because the client
+			 * expect this error
+			 */
+			return WERR_FILE_NOT_FOUND;
+		}
+
+		cert_secret_name = talloc_asprintf(mem_ctx,
+							"BCKUPKEY_%s",
+							guid_string);
+		status = get_lsa_secret(mem_ctx,
+					ldb_ctx,
+					cert_secret_name,
+					&lsa_secret);
+		if (!NT_STATUS_IS_OK(status)) {
+			return WERR_FILE_NOT_FOUND;
+		}
+
+		if (lsa_secret.length != 0) {
+			struct bkrp_exported_RSA_key_pair keypair;
+			ndr_err = ndr_pull_struct_blob(&lsa_secret, mem_ctx, &keypair,
+					(ndr_pull_flags_fn_t)ndr_pull_bkrp_exported_RSA_key_pair);
+			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+				return WERR_FILE_NOT_FOUND;
+			}
+			*(r->out.data_out_len) = keypair.cert.length;
+			*(r->out.data_out) = talloc_memdup(mem_ctx, keypair.cert.data, keypair.cert.length);
+			W_ERROR_HAVE_NO_MEMORY(*(r->out.data_out));
+			return WERR_OK;
+		} else {
+			DEBUG(1, ("No or broken secret called %s\n", cert_secret_name));
+			return WERR_INTERNAL_ERROR;
+		}
+	}
+
+	return WERR_NOT_SUPPORTED;
+}
+
+static WERROR generate_bkrp_server_wrap_key(TALLOC_CTX *ctx, struct ldb_context *ldb_ctx)
+{
+	struct GUID guid = GUID_random();
+	enum ndr_err_code ndr_err;
+	DATA_BLOB blob_wrap_key, guid_blob;
+	struct bkrp_dc_serverwrap_key wrap_key;
+	NTSTATUS status;
+	char *secret_name;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	generate_random_buffer(wrap_key.key, sizeof(wrap_key.key));
+
+	ndr_err = ndr_push_struct_blob(&blob_wrap_key, ctx, &wrap_key, (ndr_push_flags_fn_t)ndr_push_bkrp_dc_serverwrap_key);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		TALLOC_FREE(frame);
+		return WERR_INVALID_DATA;
+	}
+
+	secret_name = talloc_asprintf(frame, "BCKUPKEY_%s", GUID_string(ctx, &guid));
+	if (secret_name == NULL) {
+		TALLOC_FREE(frame);
+		return WERR_NOMEM;
+	}
+
+	status = set_lsa_secret(frame, ldb_ctx, secret_name, &blob_wrap_key);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(2, ("Failed to save the secret %s\n", secret_name));
+		TALLOC_FREE(frame);
+		return WERR_INTERNAL_ERROR;
+	}
+
+	status = GUID_to_ndr_blob(&guid, frame, &guid_blob);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(2, ("Failed to save the secret %s\n", secret_name));
+		TALLOC_FREE(frame);
+	}
+
+	status = set_lsa_secret(frame, ldb_ctx, "BCKUPKEY_P", &guid_blob);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(2, ("Failed to save the secret %s\n", secret_name));
+		TALLOC_FREE(frame);
+		return WERR_INTERNAL_ERROR;
+	}
+
+	TALLOC_FREE(frame);
+
+	return WERR_OK;
+}
+
+/*
+ * Find the specified decryption keys from the LSA secrets store as
+ * G$BCKUPKEY_keyGuidString.
+ */
+
+static WERROR bkrp_do_retrieve_server_wrap_key(TALLOC_CTX *mem_ctx, struct ldb_context *ldb_ctx,
+					       struct bkrp_dc_serverwrap_key *server_key,
+					       struct GUID *guid)
+{
+	NTSTATUS status;
+	DATA_BLOB lsa_secret;
+	char *secret_name;
+	char *guid_string;
+	enum ndr_err_code ndr_err;
+
+	guid_string = GUID_string(mem_ctx, guid);
+	if (guid_string == NULL) {
+		/* We return file not found because the client
+		 * expect this error
+		 */
+		return WERR_FILE_NOT_FOUND;
+	}
+
+	secret_name = talloc_asprintf(mem_ctx, "BCKUPKEY_%s", guid_string);
+	if (secret_name == NULL) {
+		return WERR_NOMEM;
+	}
+
+	status = get_lsa_secret(mem_ctx, ldb_ctx, secret_name, &lsa_secret);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(10, ("Error while fetching secret %s\n", secret_name));
+		return WERR_INVALID_DATA;
+	}
+	if (lsa_secret.length == 0) {
+		/* RODC case, we do not have secrets locally */
+		DEBUG(1, ("Unable to fetch value for secret %s, are we an undetected RODC?\n",
+			  secret_name));
+		return WERR_INTERNAL_ERROR;
+	}
+	ndr_err = ndr_pull_struct_blob(&lsa_secret, mem_ctx, server_key,
+				       (ndr_pull_flags_fn_t)ndr_pull_bkrp_dc_serverwrap_key);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		DEBUG(2, ("Unable to parse the ndr encoded server wrap key %s\n", secret_name));
+		return WERR_INVALID_DATA;
+	}
+
+	return WERR_OK;
+}
+
+/*
+ * Find the current, preferred ServerWrap Key by looking at
+ * G$BCKUPKEY_P in the LSA secrets store.
+ *
+ * Then find the current decryption keys from the LSA secrets store as
+ * G$BCKUPKEY_keyGuidString.
+ */
+
+static WERROR bkrp_do_retrieve_default_server_wrap_key(TALLOC_CTX *mem_ctx,
+						       struct ldb_context *ldb_ctx,
+						       struct bkrp_dc_serverwrap_key *server_key,
+						       struct GUID *returned_guid)
+{
+	NTSTATUS status;
+	DATA_BLOB guid_binary;
+
+	status = get_lsa_secret(mem_ctx, ldb_ctx, "BCKUPKEY_P", &guid_binary);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(10, ("Error while fetching secret BCKUPKEY_P to find current GUID\n"));
+		return WERR_FILE_NOT_FOUND;
+	} else if (guid_binary.length == 0) {
+		/* RODC case, we do not have secrets locally */
+		DEBUG(1, ("Unable to fetch value for secret BCKUPKEY_P, are we an undetected RODC?\n"));
+		return WERR_INTERNAL_ERROR;
+	}
+
+	status = GUID_from_ndr_blob(&guid_binary, returned_guid);
+	if (!NT_STATUS_IS_OK(status)) {
+		return WERR_FILE_NOT_FOUND;
+	}
+
+	return bkrp_do_retrieve_server_wrap_key(mem_ctx, ldb_ctx,
+						server_key, returned_guid);
+}
+
+static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+					    struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx)
+{
+	WERROR werr;
+	struct bkrp_server_side_wrapped decrypt_request;
+	DATA_BLOB sid_blob, encrypted_blob, symkey_blob;
+	DATA_BLOB blob;
+	enum ndr_err_code ndr_err;
+	struct bkrp_dc_serverwrap_key server_key;
+	struct bkrp_rc4encryptedpayload rc4payload;
+	struct dom_sid *caller_sid;
+	uint8_t symkey[20]; /* SHA-1 hash len */
+	uint8_t mackey[20]; /* SHA-1 hash len */
+	uint8_t mac[20]; /* SHA-1 hash len */
+	unsigned int hash_len;
+	HMAC_CTX ctx;
+
+	blob.data = r->in.data_in;
+	blob.length = r->in.data_in_len;
+
+	if (r->in.data_in_len == 0 || r->in.data_in == NULL) {
+		return WERR_INVALID_PARAM;
+	}
+
+	ndr_err = ndr_pull_struct_blob_all(&blob, mem_ctx, &decrypt_request,
+					   (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return WERR_INVALID_PARAM;
+	}
+
+	if (decrypt_request.magic != BACKUPKEY_SERVER_WRAP_VERSION) {
+		return WERR_INVALID_PARAM;
+	}
+
+	werr = bkrp_do_retrieve_server_wrap_key(mem_ctx, ldb_ctx, &server_key,
+						&decrypt_request.guid);
+	if (!W_ERROR_IS_OK(werr)) {
+		return werr;
+	}
+
+	dump_data_pw("server_key: \n", server_key.key, sizeof(server_key.key));
+
+	dump_data_pw("r2: \n", decrypt_request.r2, sizeof(decrypt_request.r2));
+
+	/*
+	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
+	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
+	 */
+	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
+	     decrypt_request.r2, sizeof(decrypt_request.r2),
+	     symkey, &hash_len);
+
+	dump_data_pw("symkey: \n", symkey, hash_len);
+
+	/* rc4 decrypt sid and secret using sym key */
+	symkey_blob = data_blob_const(symkey, sizeof(symkey));
+
+	encrypted_blob = data_blob_const(decrypt_request.rc4encryptedpayload,
+					 decrypt_request.ciphertext_length);
+
+	arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob);
+
+	ndr_err = ndr_pull_struct_blob_all(&encrypted_blob, mem_ctx, &rc4payload,
+					   (ndr_pull_flags_fn_t)ndr_pull_bkrp_rc4encryptedpayload);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return WERR_INVALID_PARAM;
+	}
+
+	if (decrypt_request.payload_length != rc4payload.secret_data.length) {
+		return WERR_INVALID_PARAM;
+	}
+
+	dump_data_pw("r3: \n", rc4payload.r3, sizeof(rc4payload.r3));
+
+	/*
+	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
+	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
+	 */
+	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
+	     rc4payload.r3, sizeof(rc4payload.r3),
+	     mackey, &hash_len);
+
+	dump_data_pw("mackey: \n", mackey, sizeof(mackey));
+
+	ndr_err = ndr_push_struct_blob(&sid_blob, mem_ctx, &rc4payload.sid,
+				       (ndr_push_flags_fn_t)ndr_push_dom_sid);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return WERR_INTERNAL_ERROR;
+	}
+
+	HMAC_CTX_init(&ctx);
+	HMAC_Init_ex(&ctx, mackey, hash_len, EVP_sha1(), NULL);
+	/* SID field */
+	HMAC_Update(&ctx, sid_blob.data, sid_blob.length);
+	/* Secret field */
+	HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length);
+	HMAC_Final(&ctx, mac, &hash_len);
+	HMAC_CTX_cleanup(&ctx);
+
+	dump_data_pw("mac: \n", mac, sizeof(mac));
+	dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac));
+
+	if (memcmp(mac, rc4payload.mac, sizeof(mac)) != 0) {
+		return WERR_INVALID_ACCESS;
+	}
+
+	caller_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+
+	if (!dom_sid_equal(&rc4payload.sid, caller_sid)) {
+		return WERR_INVALID_ACCESS;
+	}
+
+	*(r->out.data_out) = rc4payload.secret_data.data;
+	*(r->out.data_out_len) = rc4payload.secret_data.length;
+
+	return WERR_OK;
+}
+
+/*
+ * For BACKUPKEY_RESTORE_GUID we need to check the first 4 bytes to
+ * determine what type of restore is wanted.
+ *
+ * See MS-BKRP 3.1.4.1.4 BACKUPKEY_RESTORE_GUID point 1.
+ */
+
+static WERROR bkrp_generic_decrypt_data(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+					struct bkrp_BackupKey *r, struct ldb_context *ldb_ctx)
+{
+	if (r->in.data_in_len < 4 || r->in.data_in == NULL) {
+		return WERR_INVALID_PARAM;
+	}
+
+	if (IVAL(r->in.data_in, 0) == BACKUPKEY_SERVER_WRAP_VERSION) {
+		return bkrp_server_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx);
+	}
+
+	return bkrp_client_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx);
+}
+
+/*
+ * We have some data, such as saved website or IMAP passwords that the
+ * client would like to put into the profile on-disk.  This needs to
+ * be encrypted.  This version gives the server the data over the
+ * network (protected only by the negotiated transport encryption),
+ * and asks that it be encrypted and returned for long-term storage.
+ *
+ * The data is NOT stored in the LSA, but a key to encrypt the data
+ * will be stored.  There is only one active encryption key per domain,
+ * it is pointed at with G$BCKUPKEY_P in the LSA secrets store.
+ *
+ * The potentially multiple valid decryptiong keys (and the encryption
+ * key) are in turn stored in the LSA secrets store as
+ * G$BCKUPKEY_keyGuidString.
+ *
+ */
+
+static WERROR bkrp_server_wrap_encrypt_data(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+					    struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx)
+{
+	DATA_BLOB sid_blob, encrypted_blob, symkey_blob, server_wrapped_blob;
+	WERROR werr;
+	struct dom_sid *caller_sid;
+	uint8_t symkey[20]; /* SHA-1 hash len */
+	uint8_t mackey[20]; /* SHA-1 hash len */
+	unsigned int hash_len;
+	struct bkrp_rc4encryptedpayload rc4payload;
+	HMAC_CTX ctx;
+	struct bkrp_dc_serverwrap_key server_key;
+	enum ndr_err_code ndr_err;
+	struct bkrp_server_side_wrapped server_side_wrapped;
+	struct GUID guid;
+
+	if (r->in.data_in_len == 0 || r->in.data_in == NULL) {
+		return WERR_INVALID_PARAM;
+	}
+
+	werr = bkrp_do_retrieve_default_server_wrap_key(mem_ctx,
+							ldb_ctx, &server_key,
+							&guid);
+
+	if (!W_ERROR_IS_OK(werr)) {
+		if (W_ERROR_EQUAL(werr, WERR_FILE_NOT_FOUND)) {
+			/* Generate the server wrap key since one wasn't found */
+			werr =  generate_bkrp_server_wrap_key(mem_ctx,
+							      ldb_ctx);
+			if (!W_ERROR_IS_OK(werr)) {
+				return WERR_INVALID_PARAMETER;
+			}
+			werr = bkrp_do_retrieve_default_server_wrap_key(mem_ctx,
+									ldb_ctx,
+									&server_key,
+									&guid);
+
+			if (W_ERROR_EQUAL(werr, WERR_FILE_NOT_FOUND)) {
+				/* Ok we really don't manage to get this secret ...*/
+				return WERR_FILE_NOT_FOUND;
+			}
+		} else {
+			/* In theory we should NEVER reach this point as it
+			   should only appear in a rodc server */
+			/* we do not have the real secret attribute */
+			return WERR_INVALID_PARAMETER;
+		}
+	}
+
+	caller_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+
+	dump_data_pw("server_key: \n", server_key.key, sizeof(server_key.key));
+
+	/*
+	 * This is the key derivation step, so that the HMAC and RC4
+	 * operations over the user-supplied data are not able to
+	 * disclose the master key.  By using random data, the symkey
+	 * and mackey values are unique for this operation, and
+	 * discovering these (by reversing the RC4 over the
+	 * attacker-controlled data) does not return something able to
+	 * be used to decyrpt the encrypted data of other users
+	 */
+	generate_random_buffer(server_side_wrapped.r2, sizeof(server_side_wrapped.r2));
+
+	dump_data_pw("r2: \n", server_side_wrapped.r2, sizeof(server_side_wrapped.r2));
+
+	generate_random_buffer(rc4payload.r3, sizeof(rc4payload.r3));
+
+	dump_data_pw("r3: \n", rc4payload.r3, sizeof(rc4payload.r3));
+
+
+	/*
+	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
+	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
+	 */
+	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
+	     server_side_wrapped.r2, sizeof(server_side_wrapped.r2),
+	     symkey, &hash_len);
+
+	dump_data_pw("symkey: \n", symkey, hash_len);
+
+	/*
+	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
+	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
+	 */
+	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
+	     rc4payload.r3, sizeof(rc4payload.r3),
+	     mackey, &hash_len);
+
+	dump_data_pw("mackey: \n", mackey, sizeof(mackey));
+
+	ndr_err = ndr_push_struct_blob(&sid_blob, mem_ctx, caller_sid,
+				       (ndr_push_flags_fn_t)ndr_push_dom_sid);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return WERR_INTERNAL_ERROR;
+	}
+
+	rc4payload.secret_data.data = r->in.data_in;
+	rc4payload.secret_data.length = r->in.data_in_len;
+
+	HMAC_CTX_init(&ctx);
+	HMAC_Init_ex(&ctx, mackey, 20, EVP_sha1(), NULL);
+	/* SID field */
+	HMAC_Update(&ctx, sid_blob.data, sid_blob.length);
+	/* Secret field */
+	HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length);
+	HMAC_Final(&ctx, rc4payload.mac, &hash_len);
+	HMAC_CTX_cleanup(&ctx);
+
+	dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac));
+
+	rc4payload.sid = *caller_sid;
+
+	ndr_err = ndr_push_struct_blob(&encrypted_blob, mem_ctx, &rc4payload,
+				       (ndr_push_flags_fn_t)ndr_push_bkrp_rc4encryptedpayload);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return WERR_INTERNAL_ERROR;
+	}
+
+	/* rc4 encrypt sid and secret using sym key */
+	symkey_blob = data_blob_const(symkey, sizeof(symkey));
+	arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob);
+
+	/* create server wrap structure */
+
+	server_side_wrapped.payload_length = rc4payload.secret_data.length;
+	server_side_wrapped.ciphertext_length = encrypted_blob.length;
+	server_side_wrapped.guid = guid;
+	server_side_wrapped.rc4encryptedpayload = encrypted_blob.data;
+
+	ndr_err = ndr_push_struct_blob(&server_wrapped_blob, mem_ctx, &server_side_wrapped,
+				       (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return WERR_INTERNAL_ERROR;
+	}
+
+	*(r->out.data_out) = server_wrapped_blob.data;
+	*(r->out.data_out_len) = server_wrapped_blob.length;
+
+	return WERR_OK;
+}
+
+static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call,
+				    TALLOC_CTX *mem_ctx, struct bkrp_BackupKey *r)
+{
+	WERROR error = WERR_INVALID_PARAM;
+	struct ldb_context *ldb_ctx;
+	bool is_rodc;
+	const char *addr = "unknown";
+	/* At which level we start to add more debug of what is done in the protocol */
+	const int debuglevel = 4;
+
+	if (DEBUGLVL(debuglevel)) {
+		const struct tsocket_address *remote_address;
+		remote_address = dcesrv_connection_get_remote_address(dce_call->conn);
+		if (tsocket_address_is_inet(remote_address, "ip")) {
+			addr = tsocket_address_inet_addr_string(remote_address, mem_ctx);
+			W_ERROR_HAVE_NO_MEMORY(addr);
+		}
+	}
+
+	if (lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx) != ROLE_ACTIVE_DIRECTORY_DC) {
+		return WERR_NOT_SUPPORTED;
+	}
+
+	if (!dce_call->conn->auth_state.auth_info ||
+		dce_call->conn->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+		DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
+	}
+
+	ldb_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
+				dce_call->conn->dce_ctx->lp_ctx,
+				system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
+
+	if (samdb_rodc(ldb_ctx, &is_rodc) != LDB_SUCCESS) {
+		talloc_unlink(mem_ctx, ldb_ctx);
+		return WERR_INVALID_PARAM;
+	}
+
+	if (!is_rodc) {
+		if(strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent),
+			BACKUPKEY_RESTORE_GUID, strlen(BACKUPKEY_RESTORE_GUID)) == 0) {
+			DEBUG(debuglevel, ("Client %s requested to decrypt a wrapped secret\n", addr));
+			error = bkrp_generic_decrypt_data(dce_call, mem_ctx, r, ldb_ctx);
+		}
+
+		if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent),
+			BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID, strlen(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID)) == 0) {
+			DEBUG(debuglevel, ("Client %s requested certificate for client wrapped secret\n", addr));
+			error = bkrp_retrieve_client_wrap_key(dce_call, mem_ctx, r, ldb_ctx);
+		}
+
+		if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent),
+			BACKUPKEY_RESTORE_GUID_WIN2K, strlen(BACKUPKEY_RESTORE_GUID_WIN2K)) == 0) {
+			DEBUG(debuglevel, ("Client %s requested to decrypt a server side wrapped secret\n", addr));
+			error = bkrp_server_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx);
+		}
+
+		if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent),
+			BACKUPKEY_BACKUP_GUID, strlen(BACKUPKEY_BACKUP_GUID)) == 0) {
+			DEBUG(debuglevel, ("Client %s requested a server wrapped secret\n", addr));
+			error = bkrp_server_wrap_encrypt_data(dce_call, mem_ctx, r, ldb_ctx);
+		}
+	}
+	/*else: I am a RODC so I don't handle backup key protocol */
+
+	talloc_unlink(mem_ctx, ldb_ctx);
+	return error;
+}
+
+/* include the generated boilerplate */
+#include "librpc/gen_ndr/ndr_backupkey_s.c"
diff --git a/source4/rpc_server/common/reply.c b/source4/rpc_server/common/reply.c
index 007b680..59c289c 100644
--- a/source4/rpc_server/common/reply.c
+++ b/source4/rpc_server/common/reply.c
@@ -67,13 +67,13 @@ static void dcesrv_call_set_list(struct dcesrv_call_state *call,
 	case DCESRV_LIST_NONE:
 		break;
 	case DCESRV_LIST_CALL_LIST:
-		DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+		DLIST_ADD_END(call->conn->call_list, call);
 		break;
 	case DCESRV_LIST_FRAGMENTED_CALL_LIST:
-		DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
+		DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call);
 		break;
 	case DCESRV_LIST_PENDING_CALL_LIST:
-		DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
+		DLIST_ADD_END(call->conn->pending_call_list, call);
 		break;
 	}
 }
@@ -130,7 +130,7 @@ NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
 
 	dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+	DLIST_ADD_END(call->replies, rep);
 	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
 	if (call->conn->call_list && call->conn->call_list->replies) {
@@ -238,7 +238,7 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
 
 		dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-		DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+		DLIST_ADD_END(call->replies, rep);
 
 		stub.data += length;
 		stub.length -= length;
diff --git a/source4/rpc_server/common/server_info.c b/source4/rpc_server/common/server_info.c
index afbbb23..e23b108 100644
--- a/source4/rpc_server/common/server_info.c
+++ b/source4/rpc_server/common/server_info.c
@@ -27,6 +27,7 @@
 #include "param/param.h"
 #include "rpc_server/common/common.h"
 #include "rpc_server/common/share.h"
+#include "libds/common/roles.h"
 
 /* 
     Here are common server info functions used by some dcerpc server interfaces
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 7c1e2d3..df0ffc8 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -439,13 +439,13 @@ static void dcesrv_call_set_list(struct dcesrv_call_state *call,
 	case DCESRV_LIST_NONE:
 		break;
 	case DCESRV_LIST_CALL_LIST:
-		DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+		DLIST_ADD_END(call->conn->call_list, call);
 		break;
 	case DCESRV_LIST_FRAGMENTED_CALL_LIST:
-		DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
+		DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call);
 		break;
 	case DCESRV_LIST_PENDING_CALL_LIST:
-		DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
+		DLIST_ADD_END(call->conn->pending_call_list, call);
 		break;
 	}
 }
@@ -486,7 +486,7 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
 
 	dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+	DLIST_ADD_END(call->replies, rep);
 	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
 	if (call->conn->call_list && call->conn->call_list->replies) {
@@ -695,7 +695,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 
 	dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+	DLIST_ADD_END(call->replies, rep);
 	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
 	if (call->conn->call_list && call->conn->call_list->replies) {
@@ -860,7 +860,7 @@ static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call,
 
 	dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+	DLIST_ADD_END(call->replies, rep);
 	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
 	if (call->conn->call_list && call->conn->call_list->replies) {
@@ -1230,7 +1230,15 @@ _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
 
 	dce_ctx = talloc(mem_ctx, struct dcesrv_context);
 	NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
+
+	if (uid_wrapper_enabled()) {
+		setenv("UID_WRAPPER_MYUID", "1", 1);
+	}
 	dce_ctx->initial_euid = geteuid();
+	if (uid_wrapper_enabled()) {
+		unsetenv("UID_WRAPPER_MYUID");
+	}
+
 	dce_ctx->endpoint_list	= NULL;
 	dce_ctx->lp_ctx = lp_ctx;
 	dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
@@ -1385,7 +1393,7 @@ static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, cons
 	if (dce_conn->terminate == NULL) {
 		dce_conn->terminate = "dcesrv: defered terminating connection - no memory";
 	}
-	DLIST_ADD_END(dce_ctx->broken_connections, dce_conn, NULL);
+	DLIST_ADD_END(dce_ctx->broken_connections, dce_conn);
 }
 
 static void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
index be31500..a4b82e5 100644
--- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
+++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
@@ -26,7 +26,6 @@
 #include "lib/util/dlinklist.h"
 #include "librpc/gen_ndr/ndr_dnsserver.h"
 #include "dnsserver.h"
-#include "lib/ldb/include/ldb_private.h"
 
 struct dnsserver_state {
 	struct loadparm_context *lp_ctx;
@@ -63,14 +62,14 @@ static void dnsserver_reload_zones(struct dnsserver_state *dsstate)
 				if (z->zoneinfo == NULL) {
 					continue;
 				}
-				DLIST_ADD_END(new_list, z, NULL);
+				DLIST_ADD_END(new_list, z);
 				p->zones_count++;
 				dsstate->zones_count++;
 			} else {
 				/* Existing zone */
 				talloc_free(z);
 				DLIST_REMOVE(old_list, zmatch);
-				DLIST_ADD_END(new_list, zmatch, NULL);
+				DLIST_ADD_END(new_list, zmatch);
 			}
 			z = znext;
 		}
@@ -147,7 +146,7 @@ static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_c
 				if (z->zoneinfo == NULL) {
 					goto failed;
 				}
-				DLIST_ADD_END(dsstate->zones, z, NULL);
+				DLIST_ADD_END(dsstate->zones, z);
 				p->zones_count++;
 				dsstate->zones_count++;
 			} else {
diff --git a/source4/rpc_server/dnsserver/dnsdb.c b/source4/rpc_server/dnsserver/dnsdb.c
index e567f5a..0a76030 100644
--- a/source4/rpc_server/dnsserver/dnsdb.c
+++ b/source4/rpc_server/dnsserver/dnsdb.c
@@ -53,7 +53,7 @@ struct dnsserver_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ct
 	p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_DOMAIN_DEFAULT | DNS_DP_ENLISTED;
 	p->is_forest = false;
 
-	DLIST_ADD_END(partitions, p, NULL);
+	DLIST_ADD_END(partitions, p);
 
 	/* Forest Partition */
 	p = talloc_zero(mem_ctx, struct dnsserver_partition);
@@ -70,7 +70,7 @@ struct dnsserver_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ct
 	p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_FOREST_DEFAULT | DNS_DP_ENLISTED;
 	p->is_forest = true;
 
-	DLIST_ADD_END(partitions, p, NULL);
+	DLIST_ADD_END(partitions, p);
 
 	return partitions;
 
@@ -136,7 +136,7 @@ struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
 		}
 		z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
 
-		DLIST_ADD_END(zones, z, NULL);
+		DLIST_ADD_END(zones, z);
 		DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
 	}
 
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index d755306..319ef15 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c
+++ b/source4/rpc_server/drsuapi/getncchanges.c
@@ -376,6 +376,16 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
 				return werr;
 			}
 		}
+		if (attids[i] != obj->object.attribute_ctr.attributes[i].attid) {
+			DEBUG(0, ("Unable to replicate attribute %s on %s via DRS, incorrect attributeID:  "
+				  "0x%08x vs 0x%08x "
+				  "Run dbcheck!\n",
+				  sa->lDAPDisplayName,
+				  ldb_dn_get_linearized(msg->dn),
+				  attids[i],
+				  obj->object.attribute_ctr.attributes[i].attid));
+			return WERR_DS_DATABASE_ERROR;
+		}
 	}
 
 	return WERR_OK;
diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c
index c40322f..c55f679 100644
--- a/source4/rpc_server/lsa/dcesrv_lsa.c
+++ b/source4/rpc_server/lsa/dcesrv_lsa.c
@@ -33,6 +33,7 @@
 #include "libcli/security/session.h"
 #include "libcli/lsarpc/util_lsarpc.h"
 #include "lib/messaging/irpc.h"
+#include "libds/common/roles.h"
 
 /*
   this type allows us to distinguish handle types
diff --git a/source4/rpc_server/samr/dcesrv_samr.h b/source4/rpc_server/samr/dcesrv_samr.h
index 8193ee6..261bd05 100644
--- a/source4/rpc_server/samr/dcesrv_samr.h
+++ b/source4/rpc_server/samr/dcesrv_samr.h
@@ -20,6 +20,7 @@
 */
 
 #include "param/param.h"
+#include "libds/common/roles.h"
 
 /*
   this type allows us to distinguish handle types
diff --git a/source4/rpc_server/spoolss/dcesrv_spoolss.c b/source4/rpc_server/spoolss/dcesrv_spoolss.c
index 1492976..d88a61a 100644
--- a/source4/rpc_server/spoolss/dcesrv_spoolss.c
+++ b/source4/rpc_server/spoolss/dcesrv_spoolss.c
@@ -1168,7 +1168,7 @@ static WERROR dcesrv_spoolss_RemoteFindFirstPrinterChangeNotifyEx(struct dcesrv_
 	/*
 	 * TODO: for now just open a connection to the client and drop it again
 	 *       to keep the w2k3 PrintServer 
-	 *       happy to allow to open the Add Printer GUI
+	 *       happy to allow one to open the Add Printer GUI
 	 *       and the torture suite passing
 	 */
 
diff --git a/source4/rpc_server/wscript_build b/source4/rpc_server/wscript_build
index 3506a7c..aaf3d26 100755
--- a/source4/rpc_server/wscript_build
+++ b/source4/rpc_server/wscript_build
@@ -109,14 +109,22 @@ bld.SAMBA_MODULE('dcerpc_lsarpc',
 	)
 
 
-bld.SAMBA_MODULE('dcerpc_backupkey',
-	source='backupkey/dcesrv_backupkey.c ',
-	autoproto='backupkey/proto.h',
-	subsystem='dcerpc_server',
-	init_function='dcerpc_server_backupkey_init',
-	deps='samdb DCERPC_COMMON NDR_BACKUPKEY RPC_NDR_BACKUPKEY krb5 hx509 hcrypto gnutls gcrypt',
-	enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL')
-	)
+if bld.CONFIG_SET('HAVE_GNUTLS_3_4_7'):
+	bld.SAMBA_MODULE('dcerpc_backupkey',
+		source='backupkey/dcesrv_backupkey.c ',
+		autoproto='backupkey/proto.h',
+		subsystem='dcerpc_server',
+		init_function='dcerpc_server_backupkey_init',
+		deps='samdb DCERPC_COMMON NDR_BACKUPKEY RPC_NDR_BACKUPKEY gnutls',
+		)
+else:
+	bld.SAMBA_MODULE('dcerpc_backupkey',
+		source='backupkey/dcesrv_backupkey_heimdal.c ',
+		autoproto='backupkey/proto.h',
+		subsystem='dcerpc_server',
+		init_function='dcerpc_server_backupkey_init',
+		deps='samdb DCERPC_COMMON NDR_BACKUPKEY RPC_NDR_BACKUPKEY krb5 hx509 hcrypto gnutls gcrypt',
+		)
 
 
 bld.SAMBA_MODULE('dcerpc_spoolss',
diff --git a/source4/scripting/bin/gen_hresult.py b/source4/scripting/bin/gen_hresult.py
index 24d96c4..176c89d 100755
--- a/source4/scripting/bin/gen_hresult.py
+++ b/source4/scripting/bin/gen_hresult.py
@@ -66,7 +66,7 @@ def parseErrorDescriptions( input_file, isWinError ):
             err = Errors[-1]
             if err.err_define == None:
                 err.err_define = "HRES_" + content[0]
-	    else:
+            else:
                 if len(content) > 0:
                     desc =  escapeString(line.strip())
                     if len(desc):
diff --git a/source4/scripting/bin/gen_ntstatus.py b/source4/scripting/bin/gen_ntstatus.py
index 3625ad7..bf57fef 100755
--- a/source4/scripting/bin/gen_ntstatus.py
+++ b/source4/scripting/bin/gen_ntstatus.py
@@ -62,6 +62,8 @@ def transformErrorName( error_name ):
 def parseErrorDescriptions( file_contents, isWinError ):
     count = 0
     for line in file_contents:
+        if line == None or line == '\t' or line == "" or line == '\n':
+            continue
         content = line.strip().split(None,1)
         # start new error definition ?
         if line.startswith("0x"):
@@ -78,17 +80,17 @@ def parseErrorDescriptions( file_contents, isWinError ):
                 print "Error parsing file as line %d"%count
                 sys.exit()
             err = Errors[-1]
-            if err.err_define == None:    
+            if err.err_define == None:
                 err.err_define = transformErrorName(content[0])
-        else:
-            if len(content) > 0:
-                desc =  escapeString(line.strip())
-                if len(desc):
-                    if err.err_string == "":
-                        err.err_string = desc
-                    else:
-                        err.err_string = err.err_string + " " + desc
-        count = count + 1
+            else:
+                if len(content) > 0:
+                    desc =  escapeString(line.strip())
+                    if len(desc):
+                        if err.err_string == "":
+                            err.err_string = desc
+                        else:
+                            err.err_string = err.err_string + " " + desc
+            count = count + 1
     print "parsed %d lines generated %d error definitions"%(count,len(Errors))
 
 def parseErrCodeString(error_code_string):
@@ -147,21 +149,21 @@ def generateSourceFile(out_file):
     out_file.write(" * [MS-ERREF] http://msdn.microsoft.com/en-us/library/cc704588.aspx\n")
     out_file.write(" */\n")
     for err in ErrorsToCreatDescFor:
-	out_file.write("	{ N_(\"%s\"), %s },\n"%(err.err_string, err.err_define))
+        out_file.write("	{ N_(\"%s\"), %s },\n"%(err.err_string, err.err_define))
     out_file.write("\n\n")
     out_file.write("/*\n")
     out_file.write(" * New descriptions for new errors generated from\n")
     out_file.write(" * [MS-ERREF] http://msdn.microsoft.com/en-us/library/cc704588.aspx\n")
     out_file.write(" */\n")
     for err in ErrorsToUse:
-	out_file.write("	{ N_(\"%s\"), %s },\n"%(err.err_string, err.err_define))
+        out_file.write("	{ N_(\"%s\"), %s },\n"%(err.err_string, err.err_define))
     out_file.write("\n\n");
     out_file.write("/*\n")
     out_file.write(" * New descriptions for new errors generated from\n")
     out_file.write(" * [MS-ERREF] http://msdn.microsoft.com/en-us/library/cc704588.aspx\n")
     out_file.write(" */\n")
     for err in ErrorsToUse:
-	out_file.write("	{ \"%s\", %s },\n"%(err.err_define, err.err_define))
+        out_file.write("	{ \"%s\", %s },\n"%(err.err_define, err.err_define))
 
 def def_in_list(define, err_def_with_desc):
     for item in err_def_with_desc:
@@ -231,9 +233,11 @@ def main ():
     file_contents = open(input_file3,"r")
     has_already_desc = file_contents.readlines()
     processErrorDescription(has_already_desc)
+    print "writing new headerfile: %s"%headerfile_name
     out_file = open(headerfile_name,"w")
     generateHeaderFile(out_file)
     out_file.close()
+    print "writing new headerfile: %s"%sourcefile_name
     out_file = open(sourcefile_name,"w")
     generateSourceFile(out_file)
     out_file.close()
diff --git a/source4/scripting/bin/samba_dnsupdate b/source4/scripting/bin/samba_dnsupdate
index 7f94067..e34d148 100755
--- a/source4/scripting/bin/samba_dnsupdate
+++ b/source4/scripting/bin/samba_dnsupdate
@@ -110,9 +110,7 @@ if opts.verbose:
 def get_credentials(lp):
     """# get credentials if we haven't got them already."""
     from samba import credentials
-    global ccachename, creds
-    if creds is not None:
-        return
+    global ccachename
     creds = credentials.Credentials()
     creds.guess(lp)
     creds.set_machine_account(lp)
@@ -594,8 +592,15 @@ for d in dns_list:
             break
     if not found:
         rebuild_cache = True
-    if opts.all_names or not check_dns_name(d):
+    if opts.all_names:
+        update_list.append(d)
+        if opts.verbose:
+            print "force update: %s" % d
+    elif not check_dns_name(d):
         update_list.append(d)
+        if opts.verbose:
+            print "need update: %s" % d
+
 
 for c in cache_list:
     found = False
@@ -609,11 +614,16 @@ for c in cache_list:
     if not opts.all_names and not check_dns_name(c):
         continue
     delete_list.append(c)
+    if opts.verbose:
+        print "need delete: %s" % c
 
 if len(delete_list) == 0 and len(update_list) == 0 and not rebuild_cache:
     if opts.verbose:
         print "No DNS updates needed"
     sys.exit(0)
+else:
+    if opts.verbose:
+        print "%d DNS updates and %d DNS deletes needed" % (len(update_list), len(delete_list))
 
 # get our krb5 creds
 if len(delete_list) != 0 or len(update_list) != 0:
@@ -624,24 +634,40 @@ if len(delete_list) != 0 or len(update_list) != 0:
 for d in delete_list:
     if am_rodc:
         if d.name.lower() == domain.lower():
+            if opts.verbose:
+                print "skip delete (rodc): %s" % d
             continue
         if not d.type in [ 'A', 'AAAA' ]:
+            if opts.verbose:
+                print "delete (rodc): %s" % d
             call_rodc_update(d, op="delete")
         else:
+            if opts.verbose:
+                print "delete (nsupdate): %s" % d
             call_nsupdate(d, op="delete")
     else:
+        if opts.verbose:
+            print "delete (nsupdate): %s" % d
         call_nsupdate(d, op="delete")
 
 # ask nsupdate to add entries as needed
 for d in update_list:
     if am_rodc:
         if d.name.lower() == domain.lower():
+            if opts.verbose:
+                print "skip (rodc): %s" % d
             continue
         if not d.type in [ 'A', 'AAAA' ]:
+            if opts.verbose:
+                print "update (rodc): %s" % d
             call_rodc_update(d)
         else:
+            if opts.verbose:
+                print "update (nsupdate): %s" % d
             call_nsupdate(d)
     else:
+        if opts.verbose:
+            print "update(nsupdate): %s" % d
         call_nsupdate(d)
 
 if rebuild_cache:
diff --git a/source4/scripting/bin/samba_kcc b/source4/scripting/bin/samba_kcc
index b5476dc..05ca55a 100755
--- a/source4/scripting/bin/samba_kcc
+++ b/source4/scripting/bin/samba_kcc
@@ -46,13 +46,16 @@ from samba import getopt as options
 from samba.kcc.graph_utils import verify_and_dot, list_verify_tests
 from samba.kcc.graph_utils import GraphError
 
-
 import logging
 from samba.kcc.debug import logger, DEBUG, DEBUG_FN
 from samba.kcc import KCC
 
+# If DEFAULT_RNG_SEED is None, /dev/urandom or system time is used.
+DEFAULT_RNG_SEED = None
+
 
-def test_all_reps_from(lp, creds, unix_now, rng_seed=None):
+def test_all_reps_from(kcc, dburl, lp, creds, unix_now, rng_seed=None,
+                       ldif_file=None):
     """Run the KCC from all DSAs in read-only mode
 
     The behaviour depends on the global opts variable which contains
@@ -67,11 +70,8 @@ def test_all_reps_from(lp, creds, unix_now, rng_seed=None):
     :return None:
     """
     # This implies readonly and attempt_live_connections
-    kcc = KCC(unix_now, readonly=True,
-              verify=opts.verify, debug=opts.debug,
-              dot_file_dir=opts.dot_file_dir)
-    kcc.load_samdb(opts.dburl, lp, creds)
     dsas = kcc.list_dsas()
+    samdb = kcc.samdb
     needed_parts = {}
     current_parts = {}
 
@@ -86,12 +86,28 @@ def test_all_reps_from(lp, creds, unix_now, rng_seed=None):
     vertex_colours = []
 
     for dsa_dn in dsas:
-        if rng_seed:
+        if rng_seed is not None:
             random.seed(rng_seed)
         kcc = KCC(unix_now, readonly=True,
                   verify=opts.verify, debug=opts.debug,
                   dot_file_dir=opts.dot_file_dir)
-        kcc.run(opts.dburl, lp, creds, forced_local_dsa=dsa_dn,
+        if ldif_file is not None:
+            try:
+                # The dburl in this case is a temporary database.
+                # Its non-existence is ensured at the script startup.
+                # If it exists, it is from a previous iteration of
+                # this loop -- unless we're in an unfortunate race.
+                # Because this database is temporary, it lacks some
+                # detail and needs to be re-created anew to set the
+                # local dsa.
+                os.unlink(dburl)
+            except OSError:
+                pass
+
+            kcc.import_ldif(dburl, lp, ldif_file, dsa_dn)
+        else:
+            kcc.samdb = samdb
+        kcc.run(dburl, lp, creds, forced_local_dsa=dsa_dn,
                 forget_local_links=opts.forget_local_links,
                 forget_intersite_links=opts.forget_intersite_links,
                 attempt_live_connections=opts.attempt_live_connections)
@@ -185,7 +201,7 @@ parser.add_option("--dot-file-dir", default=None,
 
 parser.add_option("--seed",
                   help="random number seed",
-                  type=int)
+                  type=int, default=DEFAULT_RNG_SEED)
 
 parser.add_option("--importldif",
                   help="import topology ldif file",
@@ -241,6 +257,9 @@ if opts.list_verify_tests:
     list_verify_tests()
     sys.exit(0)
 
+if opts.test_all_reps_from:
+    opts.readonly = True
+
 if opts.debug:
     logger.setLevel(logging.DEBUG)
 elif opts.readonly:
@@ -248,11 +267,7 @@ elif opts.readonly:
 else:
     logger.setLevel(logging.WARNING)
 
-# initialize seed from optional input parameter
-if opts.seed:
-    random.seed(opts.seed)
-else:
-    random.seed(0xACE5CA11)
+random.seed(opts.seed)
 
 if opts.now:
     for timeformat in ("%Y%m%d%H%M%S%Z", "%Y%m%d%H%M%S"):
@@ -273,19 +288,18 @@ lp = sambaopts.get_loadparm()
 creds = credopts.get_credentials(lp, fallback_machine=True)
 
 if opts.dburl is None:
-    opts.dburl = lp.samdb_url()
-
-if opts.test_all_reps_from:
-    opts.readonly = True
-    rng_seed = opts.seed or 0xACE5CA11
-    test_all_reps_from(lp, creds, unix_now, rng_seed=rng_seed)
-    sys.exit()
+    if opts.importldif:
+        opts.dburl = opts.tmpdb
+    else:
+        opts.dburl = lp.samdb_url()
+elif opts.importldif:
+    logger.error("Don't use -H/--URL with --importldif, use --tmpdb instead")
+    sys.exit(1)
 
 # Instantiate Knowledge Consistency Checker and perform run
 kcc = KCC(unix_now, readonly=opts.readonly, verify=opts.verify,
           debug=opts.debug, dot_file_dir=opts.dot_file_dir)
 
-
 if opts.exportldif:
     rc = kcc.export_ldif(opts.dburl, lp, creds, opts.exportldif)
     sys.exit(rc)
@@ -294,14 +308,26 @@ if opts.importldif:
     if opts.tmpdb is None or opts.tmpdb.startswith('ldap'):
         logger.error("Specify a target temp database file with --tmpdb option")
         sys.exit(1)
+    if os.path.exists(opts.tmpdb):
+        logger.error("The temp database file (%s) specified with --tmpdb "
+                     "already exists. We refuse to clobber it." % opts.tmpdb)
+        sys.exit(1)
 
-    rc = kcc.import_ldif(opts.tmpdb, lp, creds, opts.importldif,
+    rc = kcc.import_ldif(opts.tmpdb, lp, opts.importldif,
                          forced_local_dsa=opts.forced_local_dsa)
     if rc != 0:
         sys.exit(rc)
 
+
+kcc.load_samdb(opts.dburl, lp, creds, force=False)
+
+if opts.test_all_reps_from:
+    test_all_reps_from(kcc, opts.dburl, lp, creds, unix_now,
+                       rng_seed=opts.seed,
+                       ldif_file=opts.importldif)
+    sys.exit()
+
 if opts.list_valid_dsas:
-    kcc.load_samdb(opts.dburl, lp, creds)
     print '\n'.join(kcc.list_dsas())
     sys.exit()
 
diff --git a/source4/scripting/bin/samba_upgradedns b/source4/scripting/bin/samba_upgradedns
index 689c9a4..5963712 100755
--- a/source4/scripting/bin/samba_upgradedns
+++ b/source4/scripting/bin/samba_upgradedns
@@ -412,22 +412,17 @@ if __name__ == '__main__':
     # Special stuff for DLZ backend
     if opts.dns_backend == "BIND9_DLZ":
         # Check if dns-HOSTNAME account exists and create it if required
-        try:
-            dn = 'samAccountName=dns-%s,CN=Principals' % hostname
-            msg = ldbs.secrets.search(expression='(dn=%s)' % dn, attrs=['secret'])
-            dnssecret = msg[0]['secret'][0]
-        except IndexError:
+        secrets_msgs = ldbs.secrets.search(expression='(samAccountName=dns-%s)' % hostname, attrs=['secret'])
+        if len(secrets_msgs) == 0:
 
             logger.info("Adding dns-%s account" % hostname)
 
-            try:
-                msg = ldbs.sam.search(base=domaindn, scope=ldb.SCOPE_DEFAULT,
-                                      expression='(sAMAccountName=dns-%s)' % (hostname),
-                                      attrs=[])
+            msg = ldbs.sam.search(base=domaindn, scope=ldb.SCOPE_DEFAULT,
+                                  expression='(sAMAccountName=dns-%s)' % (hostname),
+                                  attrs=[])
+            if len(msg) == 1:
                 dn = msg[0].dn
                 ldbs.sam.delete(dn)
-            except IndexError:
-                pass
 
             dnspass = samba.generate_random_password(128, 255)
             setup_add_ldif(ldbs.sam, setup_path("provision_dns_add_samba.ldif"), {
@@ -451,9 +446,20 @@ if __name__ == '__main__':
                                 dnsdomain=names.dnsdomain,
                                 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
                                 key_version_number=dns_key_version_number)
+
         else:
             logger.info("dns-%s account already exists" % hostname)
 
+        dns_keytab_path = os.path.join(paths.private_dir, paths.dns_keytab)
+        if os.path.isfile(dns_keytab_path) and paths.bind_gid is not None:
+            try:
+                os.chmod(dns_keytab_path, 0640)
+                os.chown(dns_keytab_path, -1, paths.bind_gid)
+            except OSError:
+                if not os.environ.has_key('SAMBA_SELFTEST'):
+                    logger.info("Failed to chown %s to bind gid %u",
+                                dns_keytab_path, paths.bind_gid)
+
         # This forces a re-creation of dns directory and all the files within
         # It's an overkill, but it's easier to re-create a samdb copy, rather
         # than trying to fix a broken copy.
diff --git a/source4/scripting/bin/samba_upgradeprovision b/source4/scripting/bin/samba_upgradeprovision
index 1893d03..bc6e36a 100755
--- a/source4/scripting/bin/samba_upgradeprovision
+++ b/source4/scripting/bin/samba_upgradeprovision
@@ -1232,7 +1232,7 @@ def rebuild_sd(samdb, names):
     During the different pre release of samba4 security descriptors
     (SD) were notarly broken (up to alpha11 included)
 
-    This function allows to get them back in order, this function works
+    This function allows one to get them back in order, this function works
     only after the database comparison that --full mode uses and which
     populates the dnToRecalculate and dnNotToRecalculate lists.
 
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 69330f2..3edfcbd 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -52,13 +52,20 @@ try:
 except KeyError:
     config_h = os.path.join(samba4bindir, "default/include/config.h")
 
-# see if we support ldaps
+# check available features
+config_hash = dict()
 f = open(config_h, 'r')
 try:
-    have_tls_support = ("ENABLE_GNUTLS 1" in f.read())
+    lines = f.readlines()
+    config_hash = dict((x[0], ' '.join(x[1:]))
+            for x in map(lambda line: line.strip().split(' ')[1:],
+                         filter(lambda line: (line[0:7] == '#define') and (len(line.split(' ')) > 2), lines)))
 finally:
     f.close()
 
+have_tls_support = ("ENABLE_GNUTLS" in config_hash)
+have_heimdal_support = ("SAMBA4_USES_HEIMDAL" in config_hash)
+
 if have_tls_support:
     for options in ['-U"$USERNAME%$PASSWORD"']:
         plantestsuite("samba4.ldb.ldaps with options %s(ad_dc_ntvfs)" % options, "ad_dc_ntvfs",
@@ -185,6 +192,7 @@ for env in ["ad_dc_ntvfs", "fl2000dc", "fl2003dc", "fl2008r2dc", "ad_dc"]:
     plansmbtorture4testsuite('rpc.lsa.secrets', env, ["%s:$SERVER[target_principal=$NETBIOSNAME\$]" % (transport, ), '-k', 'yes', '-U$USERNAME%$PASSWORD', '--workgroup=$DOMAIN'], "samba4.rpc.lsa.secrets on %s with Kerberos - netbios name principal dollar" % (transport,))
     plansmbtorture4testsuite('rpc.lsa.secrets', env, ["%s:$SERVER[target_principal=$NETBIOSNAME]" % (transport, ), '-k', 'yes', '-U$USERNAME%$PASSWORD', '--workgroup=$DOMAIN'], "samba4.rpc.lsa.secrets on %s with Kerberos - netbios name principal" % (transport,))
     plansmbtorture4testsuite('rpc.lsa.secrets.none*', env, ["%s:$SERVER" % transport, '-k', 'yes', '-U$USERNAME%$PASSWORD', '--workgroup=$DOMAIN', "--option=gensec:fake_gssapi_krb5=yes", '--option=gensec:gssapi_krb5=no', '--option=gensec:target_hostname=$NETBIOSNAME'], "samba4.rpc.lsa.secrets on %s with Kerberos - use Samba3 style login" % transport)
+    plansmbtorture4testsuite('rpc.lsa.secrets.none*', env, ["%s:$SERVER" % transport, '-k', 'yes', '-U$USERNAME%$PASSWORD', '--workgroup=$DOMAIN', "--option=gensec:fake_gssapi_krb5=yes", '--option=gensec:gssapi_krb5=no', '--option=gensec:target_hostname=$NETBIOSNAME', '--option=gensec_krb5:send_authenticator_checksum=false'], "samba4.rpc.lsa.secrets on %s with Kerberos - use raw-krb5-no-authenticator-checksum style login" % transport)
     plansmbtorture4testsuite('rpc.lsa.secrets.none*', env, ["%s:$SERVER" % transport, '-k', 'yes', '-U$USERNAME%$PASSWORD', '--workgroup=$DOMAIN', "--option=clientusespnegoprincipal=yes", '--option=gensec:fake_gssapi_krb5=yes', '--option=gensec:gssapi_krb5=no', '--option=gensec:target_hostname=$NETBIOSNAME'], "samba4.rpc.lsa.secrets on %s with Kerberos - use Samba3 style login, use target principal" % transport)
 
     # Winreg tests test bulk Kerberos encryption of DCE/RPC
@@ -311,12 +319,15 @@ for env in ["ad_member", "s4member", "ad_dc_ntvfs", "chgdcpass"]:
     plantestsuite("samba4.blackbox.smbclient(%s:local)" % env, "%s:local" % env, [os.path.join(samba4srcdir, "utils/tests/test_smbclient.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$DOMAIN', smbclient4])
 
 plantestsuite("samba4.blackbox.samba_tool(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(samba4srcdir, "utils/tests/test_samba_tool.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$DOMAIN', smbclient4])
-plantestsuite("samba4.blackbox.pkinit(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_pkinit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX/ad_dc_ntvfs', "aes256-cts-hmac-sha1-96", smbclient4, configuration])
-plantestsuite("samba4.blackbox.kinit(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kinit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', "aes256-cts-hmac-sha1-96", smbclient4, configuration])
-plantestsuite("samba4.blackbox.kinit(fl2000dc:local)", "fl2000dc:local", [os.path.join(bbdir, "test_kinit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', "arcfour-hmac-md5", smbclient4, configuration])
-plantestsuite("samba4.blackbox.kinit(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', "aes256-cts-hmac-sha1-96", smbclient4, configuration])
-plantestsuite("samba4.blackbox.kinit_trust(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit_trusts.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "forest", "aes256-cts-hmac-sha1-96"])
-plantestsuite("samba4.blackbox.kinit_trust(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_kinit_trusts.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external", "arcfour-hmac-md5"])
+
+if have_heimdal_support:
+    plantestsuite("samba4.blackbox.pkinit(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_pkinit_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX/ad_dc_ntvfs', "aes256-cts-hmac-sha1-96", smbclient4, configuration])
+    plantestsuite("samba4.blackbox.kinit(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kinit_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', "aes256-cts-hmac-sha1-96", smbclient4, configuration])
+    plantestsuite("samba4.blackbox.kinit(fl2000dc:local)", "fl2000dc:local", [os.path.join(bbdir, "test_kinit_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', "arcfour-hmac-md5", smbclient4, configuration])
+    plantestsuite("samba4.blackbox.kinit(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', "aes256-cts-hmac-sha1-96", smbclient4, configuration])
+    plantestsuite("samba4.blackbox.kinit_trust(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit_trusts_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "forest", "aes256-cts-hmac-sha1-96"])
+    plantestsuite("samba4.blackbox.kinit_trust(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_kinit_trusts_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external", "arcfour-hmac-md5"])
+
 plantestsuite("samba4.blackbox.trust_utils(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "forest"])
 plantestsuite("samba4.blackbox.trust_utils(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external"])
 plantestsuite("samba4.blackbox.ktpass(ad_dc_ntvfs)", "ad_dc_ntvfs", [os.path.join(bbdir, "test_ktpass.sh"), '$PREFIX/ad_dc_ntvfs'])
@@ -330,6 +341,7 @@ plantestsuite("samba4.blackbox.gentest(ad_dc_ntvfs)", "ad_dc_ntvfs", [os.path.jo
 plantestsuite("samba4.blackbox.rfc2307_mapping(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(samba4srcdir, "../nsswitch/tests/test_rfc2307_mapping.sh"), '$DOMAIN', '$USERNAME', '$PASSWORD', "$SERVER", "$UID_RFC2307TEST", "$GID_RFC2307TEST", configuration])
 plantestsuite("samba4.blackbox.chgdcpass", "chgdcpass", [os.path.join(bbdir, "test_chgdcpass.sh"), '$SERVER', "CHGDCPASS\$", '$REALM', '$DOMAIN', '$PREFIX', "aes256-cts-hmac-sha1-96", '$SELFTEST_PREFIX/chgdcpass', smbclient4])
 plantestsuite("samba4.blackbox.samba_upgradedns(chgdcpass:local)", "chgdcpass:local", [os.path.join(bbdir, "test_samba_upgradedns.sh"), '$SERVER', '$REALM', '$PREFIX', '$SELFTEST_PREFIX/chgdcpass'])
+plantestsuite("samba4.blackbox.net_ads(ad_member:local)", "ad_member:local", [os.path.join(bbdir, "test_net_ads.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD'])
 plantestsuite_loadlist("samba4.rpc.echo against NetBIOS alias", "ad_dc_ntvfs", [valgrindify(smbtorture4), "$LISTOPT", "$LOADLIST", 'ncacn_np:$NETBIOSALIAS', '-U$DOMAIN/$USERNAME%$PASSWORD', 'rpc.echo'])
 
 # Tests using the "Simple" NTVFS backend
@@ -478,6 +490,8 @@ planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.samba_tool.user")
 planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.samba_tool.group")
 planpythontestsuite("ad_dc:local", "samba.tests.samba_tool.ntacl")
 
+planpythontestsuite("ad_dc:local", "samba.tests.samba_tool.sites")
+
 planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.dcerpc.rpcecho")
 planoldpythontestsuite("ad_dc_ntvfs:local", "samba.tests.dcerpc.registry", extra_args=['-U"$USERNAME%$PASSWORD"'])
 planoldpythontestsuite("ad_dc_ntvfs", "samba.tests.dcerpc.dnsserver", extra_args=['-U"$USERNAME%$PASSWORD"'])
@@ -535,7 +549,6 @@ plantestsuite("samba4.blackbox.provision-backend", "none", ["PYTHON=%s" % python
 # Test renaming the DC
 plantestsuite("samba4.blackbox.renamedc.sh", "none", ["PYTHON=%s" % python, os.path.join(bbdir, "renamedc.sh"), '$PREFIX/provision'])
 
-# Demote the vampire DC, it must be the last test on the VAMPIRE DC
 for env in ['vampire_dc', 'promoted_dc']:
 
     # DRS python tests
@@ -563,7 +576,6 @@ for env in ['vampire_dc', 'promoted_dc']:
                            environ={'DC1': "$DC_SERVER", 'DC2': '$%s_SERVER' % env.upper()},
                            extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
 
-    plantestsuite("samba4.blackbox.samba_tool_demote(%s)" % env, env, [os.path.join(samba4srcdir, "utils/tests/test_demote.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$DOMAIN', '$DC_SERVER', '$PREFIX/%s' % env, smbclient4])
 
 for env in ["ad_dc_ntvfs", "s4member", "rodc", "promoted_dc", "ad_dc", "ad_member"]:
     plantestsuite("samba.blackbox.wbinfo(%s:local)" % env, "%s:local" % env, [os.path.join(samba4srcdir, "../nsswitch/tests/test_wbinfo.sh"), '$DOMAIN', '$DC_USERNAME', '$DC_PASSWORD', env])
@@ -598,11 +610,6 @@ for env in ["ad_dc_ntvfs", "rodc", "promoted_dc", "ad_dc", "fl2000dc", "fl2003dc
                                                '--option=torture:krb5-hostname=testallowed'] + extra_options,
                              "samba4.krb5.kdc with account ALLOWED permission to replicate to an RODC")
 
-# TODO: Verifying the databases really should be a part of the
-# environment teardown.
-# check the databases are all OK. PLEASE LEAVE THIS AS THE LAST TEST
-for env in ["ad_dc_ntvfs", "ad_dc", "fl2000dc", "fl2003dc", "fl2008r2dc", 'vampire_dc', 'promoted_dc']:
-    plantestsuite("samba4.blackbox.dbcheck(%s)" % env, env + ":local" , ["PYTHON=%s" % python, os.path.join(bbdir, "dbcheck.sh"), '$PREFIX/provision', configuration])
 
 for env in [
         'vampire_dc',
@@ -615,3 +622,13 @@ for env in [
                                 },
                            extra_path=[os.path.join(srcdir(), "samba/python"), ]
                            )
+
+# Demote the vampire DC, it must be the last test each DC, before the dbcheck
+for env in ['vampire_dc', 'promoted_dc', 'rodc']:
+    plantestsuite("samba4.blackbox.samba_tool_demote(%s)" % env, env, [os.path.join(samba4srcdir, "utils/tests/test_demote.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$DOMAIN', '$DC_SERVER', '$PREFIX/%s' % env, smbclient4])
+
+# TODO: Verifying the databases really should be a part of the
+# environment teardown.
+# check the databases are all OK. PLEASE LEAVE THIS AS THE LAST TEST
+for env in ["ad_dc_ntvfs", "ad_dc", "fl2000dc", "fl2003dc", "fl2008r2dc", 'vampire_dc', 'promoted_dc']:
+    plantestsuite("samba4.blackbox.dbcheck(%s)" % env, env + ":local" , ["PYTHON=%s" % python, os.path.join(bbdir, "dbcheck.sh"), '$PREFIX/provision', configuration])
diff --git a/source4/setup/wscript_build b/source4/setup/wscript_build
index cb83e3e..2717986 100644
--- a/source4/setup/wscript_build
+++ b/source4/setup/wscript_build
@@ -7,6 +7,6 @@ bld.INSTALL_FILES('${SETUPDIR}', 'dns_update_list')
 bld.INSTALL_FILES('${SETUPDIR}', 'spn_update_list')
 
 for p in '''schema-map-* DB_CONFIG *.inf *.ldif *.reg *.zone *.conf *.php *.txt
-            named.conf named.conf.update named.conf.dlz'''.split():
+            named.conf.update named.conf.dlz'''.split():
     bld.INSTALL_WILDCARD('${SETUPDIR}', p)
 
diff --git a/source4/smb_server/smb/wscript_build b/source4/smb_server/smb/wscript_build
index a17de06..3e3df21 100644
--- a/source4/smb_server/smb/wscript_build
+++ b/source4/smb_server/smb/wscript_build
@@ -5,6 +5,6 @@ bld.SAMBA_SUBSYSTEM('SMB_PROTOCOL',
 	autoproto='smb_proto.h',
 	deps='dfs_server_ad',
 	public_deps='ntvfs LIBPACKET samba-credentials samba_server_gensec',
-	enabled=bld.AD_DC_BUILD_IS_ENABLED()
+	enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER')
 	)
 
diff --git a/source4/smb_server/smb2/receive.c b/source4/smb_server/smb2/receive.c
index 9187310..3e5dc4d 100644
--- a/source4/smb_server/smb2/receive.c
+++ b/source4/smb_server/smb2/receive.c
@@ -618,7 +618,7 @@ NTSTATUS smb2srv_queue_pending(struct smb2srv_request *req)
 		return NT_STATUS_INSUFFICIENT_RESOURCES;
 	}
 
-	DLIST_ADD_END(req->smb_conn->requests2.list, req, struct smb2srv_request *);
+	DLIST_ADD_END(req->smb_conn->requests2.list, req);
 	req->pending_id = id;
 
 	talloc_set_destructor(req, smb2srv_request_deny_destructor);
diff --git a/source4/smb_server/smb2/wscript_build b/source4/smb_server/smb2/wscript_build
index 18a2b29..7866ee9 100644
--- a/source4/smb_server/smb2/wscript_build
+++ b/source4/smb_server/smb2/wscript_build
@@ -4,6 +4,6 @@ bld.SAMBA_SUBSYSTEM('SMB2_PROTOCOL',
 	source='receive.c negprot.c sesssetup.c tcon.c fileio.c fileinfo.c find.c keepalive.c',
 	autoproto='smb2_proto.h',
 	public_deps='ntvfs LIBPACKET LIBCLI_SMB2 samba_server_gensec NDR_DFSBLOBS',
-	enabled=bld.AD_DC_BUILD_IS_ENABLED()
+	enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER')
 	)
 
diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h
index ab55544..40af4a6 100644
--- a/source4/smb_server/smb_server.h
+++ b/source4/smb_server/smb_server.h
@@ -475,7 +475,7 @@ struct loadparm_context;
 #define SMBSRV_CALL_NTVFS_BACKEND(cmd) do { \
 	req->ntvfs->async_states->status = cmd; \
 	if (req->ntvfs->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { \
-		DLIST_ADD_END(req->smb_conn->requests, req, struct smbsrv_request *); \
+		DLIST_ADD_END(req->smb_conn->requests, req); \
 	} else { \
 		req->ntvfs->async_states->send_fn(req->ntvfs); \
 	} \
diff --git a/source4/smb_server/wscript_build b/source4/smb_server/wscript_build
index bfeba0e..78298d9 100644
--- a/source4/smb_server/wscript_build
+++ b/source4/smb_server/wscript_build
@@ -7,14 +7,14 @@ bld.SAMBA_MODULE('service_smb',
 	init_function='server_service_smb_init',
 	deps='SMB_SERVER netif shares samba-hostconfig',
 	internal_module=False,
-	enabled=bld.AD_DC_BUILD_IS_ENABLED()
+	enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER')
 	)
 
 bld.SAMBA_SUBSYSTEM('SMB_SERVER',
 	source='handle.c tcon.c session.c blob.c management.c smb_server.c',
 	autoproto='smb_server_proto.h',
 	public_deps='share LIBPACKET SMB_PROTOCOL SMB2_PROTOCOL',
-	enabled=bld.AD_DC_BUILD_IS_ENABLED()
+	enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER')
 	)
 
 bld.RECURSE('smb')
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index b55a1a7..d223776 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -277,9 +277,6 @@ static void standard_accept_connection(struct tevent_context *ev,
 		child_pipe[1] = -1;
 	}
 
-	/* Ensure that the forked children do not expose identical random streams */
-	set_need_random_reseed();
-
 	/* setup the process title */
 	c = socket_get_peer_addr(sock2, ev);
 	s = socket_get_my_addr(sock2, ev);
@@ -356,9 +353,6 @@ static void standard_new_task(struct tevent_context *ev,
 		child_pipe[1] = -1;
 	}
 
-	/* Ensure that the forked children do not expose identical random streams */
-	set_need_random_reseed();
-
 	setproctitle("task %s server_id[%d]", service_name, (int)pid);
 
 	/* setup this new task.  Cluster ID is PID based for this process model */
diff --git a/source4/smbd/server.c b/source4/smbd/server.c
index b0f67c9..bd70ac6 100644
--- a/source4/smbd/server.c
+++ b/source4/smbd/server.c
@@ -44,6 +44,7 @@
 #include "dynconfig/dynconfig.h"
 #include "lib/util/samba_modules.h"
 #include "nsswitch/winbind_client.h"
+#include "libds/common/roles.h"
 
 /*
   recursively delete a directory tree
@@ -370,7 +371,7 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[
 	umask(0);
 
 	DEBUG(0,("%s version %s started.\n", binary_name, SAMBA_VERSION_STRING));
-	DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2015\n"));
+	DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2016\n"));
 
 	if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) {
 		DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
@@ -392,12 +393,6 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[
 
 	pidfile_create(lpcfg_pid_directory(cmdline_lp_ctx), binary_name);
 
-	/* Set up a database to hold a random seed, in case we don't
-	 * have /dev/urandom */
-	if (!randseed_init(talloc_autofree_context(), cmdline_lp_ctx)) {
-		return 1;
-	}
-
 	if (lpcfg_server_role(cmdline_lp_ctx) == ROLE_ACTIVE_DIRECTORY_DC) {
 		if (!open_schannel_session_store(talloc_autofree_context(), cmdline_lp_ctx)) {
 			exit_daemon("Samba cannot open schannel store for secured NETLOGON operations.", EACCES);
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index 9cdbbc2..81ad3c5 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -44,7 +44,7 @@ NTSTATUS register_server_service(const char *name,
 	NT_STATUS_HAVE_NO_MEMORY(srv);
 	srv->service_name = name;
 	srv->task_init = task_init;
-	DLIST_ADD_END(registered_servers, srv, struct registered_server *);
+	DLIST_ADD_END(registered_servers, srv);
 	return NT_STATUS_OK;
 }
 
diff --git a/source4/torture/basic/aliases.c b/source4/torture/basic/aliases.c
index 2d1d411..acd33a4 100644
--- a/source4/torture/basic/aliases.c
+++ b/source4/torture/basic/aliases.c
@@ -386,8 +386,8 @@ struct torture_suite *torture_trans2_aliases(TALLOC_CTX *mem_ctx)
 {
 	struct torture_suite *suite = torture_suite_create(mem_ctx, "aliases");
 
-	torture_suite_add_1smb_test(suite, "QFILEINFO aliases", qfsinfo_aliases);
-	torture_suite_add_1smb_test(suite, "QFSINFO aliases", qfileinfo_aliases);
+	torture_suite_add_1smb_test(suite, "QFSINFO aliases", qfsinfo_aliases);
+	torture_suite_add_1smb_test(suite, "QFILEINFO aliases", qfileinfo_aliases);
 	torture_suite_add_1smb_test(suite, "QPATHINFO aliases", qpathinfo_aliases);
 	torture_suite_add_1smb_test(suite, "FINDFIRST aliases", findfirst_aliases);
 	torture_suite_add_1smb_test(suite, "setfileinfo_aliases", setfileinfo_aliases);
diff --git a/source4/torture/basic/base.c b/source4/torture/basic/base.c
index 6a792b2..e8ae4b6 100644
--- a/source4/torture/basic/base.c
+++ b/source4/torture/basic/base.c
@@ -447,7 +447,6 @@ static bool run_tcon_test(struct torture_context *tctx, struct smbcli_state *cli
 	if (NT_STATUS_IS_ERR(smbcli_tconX(cli, share, "?????", password))) {
 		torture_result(tctx, TORTURE_FAIL, "%s refused 2nd tree connect (%s)\n", host,
 		           smbcli_errstr(cli->tree));
-		talloc_free(cli);
 		return false;
 	}
 
diff --git a/source4/torture/basic/misc.c b/source4/torture/basic/misc.c
index 721727b..4e84e38 100644
--- a/source4/torture/basic/misc.c
+++ b/source4/torture/basic/misc.c
@@ -234,7 +234,7 @@ bool torture_holdcon(struct torture_context *tctx)
 /*
   open a file N times on the server and just hold them open
   used for testing performance when there are N file handles
-  alopenn
+  open
  */
 bool torture_holdopen(struct torture_context *tctx,
 		      struct smbcli_state *cli)
@@ -750,7 +750,7 @@ static void benchrw_callback(struct smbcli_request *req)
 	struct benchrw_state *state = req->async.private_data;
 	struct torture_context *tctx = state->tctx;
 	
-	/*dont send new requests when torture_numops is reached*/
+	/*don't send new requests when torture_numops is reached*/
 	if ((state->mode == READ_WRITE_DATA)
 	    && (state->completed >= torture_numops)) {
 		state->mode=MAX_OPS_REACHED;
diff --git a/source4/torture/drs/wscript_build b/source4/torture/drs/wscript_build
index 0e5578b..cfdd8a2 100644
--- a/source4/torture/drs/wscript_build
+++ b/source4/torture/drs/wscript_build
@@ -5,7 +5,7 @@ bld.SAMBA_MODULE('TORTURE_DRS',
 	autoproto='proto.h',
 	subsystem='smbtorture',
 	init_function='torture_drs_init',
-	deps='samba-util ldb POPT_SAMBA errors torture ldbsamba talloc dcerpc ndr NDR_DRSUAPI gensec samba-hostconfig RPC_NDR_DRSUAPI DSDB_MODULE_HELPERS asn1util samdb NDR_DRSBLOBS samba-credentials samdb-common LIBCLI_RESOLVE LP_RESOLVE torturemain',
+	deps='samba-util ldb POPT_SAMBA samba-errors torture ldbsamba talloc dcerpc ndr NDR_DRSUAPI gensec samba-hostconfig RPC_NDR_DRSUAPI DSDB_MODULE_HELPERS asn1util samdb NDR_DRSBLOBS samba-credentials samdb-common LIBCLI_RESOLVE LP_RESOLVE torturemain',
 	internal_module=True
 	)
 
diff --git a/source4/torture/gentest.c b/source4/torture/gentest.c
index 41b4aef..4cd2258 100644
--- a/source4/torture/gentest.c
+++ b/source4/torture/gentest.c
@@ -295,7 +295,12 @@ static unsigned int time_skew(void)
 		nt0 = servers[0].smb_tree[0]->session->transport->negotiate.server_time;
 		nt1 = servers[1].smb_tree[0]->session->transport->negotiate.server_time;
 	}
-	ret = labs(nt0 - nt1);
+	/* Samba's NTTIME is unsigned, abs() won't work! */
+	if (nt0 > nt1){
+		ret = nt0 - nt1;
+	} else {
+		ret = nt1 - nt0;
+	}
 	return ret + 300;
 }
 
diff --git a/source4/torture/ldap/cldap.c b/source4/torture/ldap/cldap.c
index 6a925cf..6a9e9e1 100644
--- a/source4/torture/ldap/cldap.c
+++ b/source4/torture/ldap/cldap.c
@@ -24,6 +24,7 @@
 #include "includes.h"
 #include "libcli/cldap/cldap.h"
 #include "libcli/ldap/ldap_client.h"
+#include "libcli/resolve/resolve.h"
 #include "param/param.h"
 #include "../lib/tsocket/tsocket.h"
 
@@ -87,10 +88,20 @@ static bool test_cldap_generic(struct torture_context *tctx, const char *dest)
 	const char *attrs2[] = { "currentTime", "highestCommittedUSN", "netlogon", NULL };
 	const char *attrs3[] = { "netlogon", NULL };
 	struct tsocket_address *dest_addr;
+	const char *ip;
+	struct nbt_name nbt_name;
 	int ret;
 
+	make_nbt_name_server(&nbt_name, dest);
+
+	status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+				 0, 0, &nbt_name, tctx, &ip, tctx->ev);
+	torture_assert_ntstatus_ok(tctx, status,
+			talloc_asprintf(tctx,"Failed to resolve %s: %s",
+					nbt_name.name, nt_errstr(status)));
+
 	ret = tsocket_address_inet_from_strings(tctx, "ip",
-						dest,
+						ip,
 						lpcfg_cldap_port(tctx->lp_ctx),
 						&dest_addr);
 	CHECK_VAL(ret, 0);
diff --git a/source4/torture/ldap/netlogon.c b/source4/torture/ldap/netlogon.c
index d632aaf..1b43ea7 100644
--- a/source4/torture/ldap/netlogon.c
+++ b/source4/torture/ldap/netlogon.c
@@ -25,6 +25,7 @@
 #include "libcli/cldap/cldap.h"
 #include "libcli/ldap/ldap_client.h"
 #include "libcli/ldap/ldap_ndr.h"
+#include "libcli/resolve/resolve.h"
 #include "librpc/gen_ndr/netlogon.h"
 #include "param/param.h"
 #include "../lib/tsocket/tsocket.h"
@@ -579,14 +580,24 @@ static NTSTATUS udp_ldap_netlogon(void *data,
 bool torture_netlogon_udp(struct torture_context *tctx)
 {
 	const char *host = torture_setting_string(tctx, "host", NULL);
+	const char *ip;
+	struct nbt_name nbt_name;
 	bool ret = true;
 	int r;
 	struct cldap_socket *cldap;
 	NTSTATUS status;
 	struct tsocket_address *dest_addr;
 
+	make_nbt_name_server(&nbt_name, host);
+
+	status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+				 0, 0, &nbt_name, tctx, &ip, tctx->ev);
+	torture_assert_ntstatus_ok(tctx, status,
+			talloc_asprintf(tctx,"Failed to resolve %s: %s",
+					nbt_name.name, nt_errstr(status)));
+
 	r = tsocket_address_inet_from_strings(tctx, "ip",
-					      host,
+					      ip,
 					      lpcfg_cldap_port(tctx->lp_ctx),
 					      &dest_addr);
 	CHECK_VAL(r, 0);
diff --git a/source4/torture/ldb/ldb.c b/source4/torture/ldb/ldb.c
index fbf82d8..6210419 100644
--- a/source4/torture/ldb/ldb.c
+++ b/source4/torture/ldb/ldb.c
@@ -22,7 +22,9 @@
 #include "includes.h"
 #include "lib/events/events.h"
 #include <ldb.h>
+#include <ldb-samba/ldb_wrap.h>
 #include <ldb_errors.h>
+#include <ldb_module.h>
 #include "lib/ldb-samba/ldif_handlers.h"
 #include "ldb_wrap.h"
 #include "dsdb/samdb/samdb.h"
@@ -39,6 +41,226 @@ static const char *hex_guid = "fac55a97d9351d43b86a845bcd34fff9";
 static const char *prefix_map_newline = "2:1.2.840.113556.1.2\n5:2.16.840.1.101.2.2.3";
 static const char *prefix_map_semi = "2:1.2.840.113556.1.2;5:2.16.840.1.101.2.2.3";
 
+/**
+ * This is the hex code derived from the tdbdump for
+ * "st/ad_dc/private/sam.ldb.d/DC=ADDC,DC=SAMBA,DC=EXAMPLE,DC=COM.ldb"
+ * key "DN=CN=DDA1D01D-4BD7-4C49-A184-46F9241B560E,CN=OPERATIONS,CN=DOMAINUPDATES,CN=SYSTEM,DC=ADDC,DC=SAMBA,DC=EXAMPLE,DC=COM\00"
+ *   -- adrianc
+ */
+
+static const uint8_t dda1d01d_bin[] = {
+	0x67, 0x19, 0x01, 0x26, 0x0d, 0x00, 0x00, 0x00, 0x43, 0x4e, 0x3d, 0x64, 0x64, 0x61, 0x31, 0x64,
+	0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64, 0x37, 0x2d, 0x34, 0x63, 0x34, 0x39, 0x2d, 0x61, 0x31,
+	0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39, 0x32, 0x34, 0x31, 0x62, 0x35, 0x36, 0x30, 0x65, 0x2c,
+	0x43, 0x4e, 0x3d, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x43, 0x4e,
+	0x3d, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2c, 0x43,
+	0x4e, 0x3d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2c, 0x44, 0x43, 0x3d, 0x61, 0x64, 0x64, 0x63,
+	0x2c, 0x44, 0x43, 0x3d, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x2c, 0x44, 0x43, 0x3d, 0x65, 0x78, 0x61,
+	0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x44, 0x43, 0x3d, 0x63, 0x6f, 0x6d, 0x00, 0x6f, 0x62, 0x6a, 0x65,
+	0x63, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+	0x74, 0x6f, 0x70, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+	0x72, 0x00, 0x63, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x64, 0x64, 0x61,
+	0x31, 0x64, 0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64, 0x37, 0x2d, 0x34, 0x63, 0x34, 0x39, 0x2d,
+	0x61, 0x31, 0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39, 0x32, 0x34, 0x31, 0x62, 0x35, 0x36, 0x30,
+	0x65, 0x00, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x00, 0x01,
+	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x77, 0x68, 0x65, 0x6e, 0x43, 0x72, 0x65,
+	0x61, 0x74, 0x65, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x32, 0x30, 0x31,
+	0x35, 0x30, 0x37, 0x30, 0x38, 0x32, 0x32, 0x34, 0x33, 0x31, 0x30, 0x2e, 0x30, 0x5a, 0x00, 0x77,
+	0x68, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11,
+	0x00, 0x00, 0x00, 0x32, 0x30, 0x31, 0x35, 0x30, 0x37, 0x30, 0x38, 0x32, 0x32, 0x34, 0x33, 0x31,
+	0x30, 0x2e, 0x30, 0x5a, 0x00, 0x75, 0x53, 0x4e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x00,
+	0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x33, 0x34, 0x36, 0x37, 0x00, 0x75, 0x53, 0x4e,
+	0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0x33, 0x34, 0x36, 0x37, 0x00, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x41, 0x64, 0x76, 0x61, 0x6e,
+	0x63, 0x65, 0x64, 0x56, 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x6c, 0x79, 0x00, 0x01, 0x00, 0x00, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x54, 0x52, 0x55, 0x45, 0x00, 0x6e, 0x54, 0x53, 0x65, 0x63, 0x75, 0x72,
+	0x69, 0x74, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x00, 0x01, 0x00,
+	0x00, 0x00, 0x18, 0x05, 0x00, 0x00, 0x01, 0x00, 0x17, 0x8c, 0x14, 0x00, 0x00, 0x00, 0x30, 0x00,
+	0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e, 0x5e,
+	0x1a, 0x4b, 0x00, 0x02, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00,
+	0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e, 0x5e, 0x1a, 0x4b, 0x00, 0x02,
+	0x00, 0x00, 0x04, 0x00, 0x78, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x5a, 0x38, 0x00, 0x20, 0x00,
+	0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xbe, 0x3b, 0x0e, 0xf3, 0xf0, 0x9f, 0xd1, 0x11, 0xb6, 0x03,
+	0x00, 0x00, 0xf8, 0x03, 0x67, 0xc1, 0xa5, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+	0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x07, 0x5a, 0x38, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xbf, 0x3b,
+	0x0e, 0xf3, 0xf0, 0x9f, 0xd1, 0x11, 0xb6, 0x03, 0x00, 0x00, 0xf8, 0x03, 0x67, 0xc1, 0xa5, 0x7a,
+	0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x01,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x54, 0x04, 0x17, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0xff, 0x01, 0x0f, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e, 0x5e,
+	0x1a, 0x4b, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0xff, 0x01, 0x0f, 0x00, 0x01, 0x01,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x94, 0x00,
+	0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x1a,
+	0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x42, 0x16, 0x4c, 0xc0, 0x20,
+	0xd0, 0x11, 0xa7, 0x68, 0x00, 0xaa, 0x00, 0x6e, 0x05, 0x29, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14,
+	0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00,
+	0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x42, 0x16, 0x4c, 0xc0, 0x20, 0xd0, 0x11, 0xa7, 0x68,
+	0x00, 0xaa, 0x00, 0x6e, 0x05, 0x29, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+	0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+	0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00,
+	0x00, 0x00, 0x10, 0x20, 0x20, 0x5f, 0xa5, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2,
+	0xd4, 0xcf, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e,
+	0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02,
+	0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x20,
+	0x20, 0x5f, 0xa5, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd4, 0xcf, 0xba, 0x7a,
+	0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a,
+	0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0xc2, 0x0a, 0xbc, 0xa9, 0x79,
+	0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd4, 0xcf, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14,
+	0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00,
+	0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0xc2, 0x0a, 0xbc, 0xa9, 0x79, 0xd0, 0x11, 0x90, 0x20,
+	0x00, 0xc0, 0x4f, 0xc2, 0xd4, 0xcf, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+	0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+	0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00,
+	0x00, 0x00, 0x42, 0x2f, 0xba, 0x59, 0xa2, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2,
+	0xd3, 0xcf, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e,
+	0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02,
+	0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x42, 0x2f,
+	0xba, 0x59, 0xa2, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd3, 0xcf, 0xba, 0x7a,
+	0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a,
+	0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x88, 0x70, 0x03, 0xe1, 0x0a,
+	0xd2, 0x11, 0xb4, 0x22, 0x00, 0xa0, 0xc9, 0x68, 0xf9, 0x39, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14,
+	0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00,
+	0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x88, 0x70, 0x03, 0xe1, 0x0a, 0xd2, 0x11, 0xb4, 0x22,
+	0x00, 0xa0, 0xc9, 0x68, 0xf9, 0x39, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+	0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+	0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00,
+	0x00, 0x00, 0x6d, 0x9e, 0xc6, 0xb7, 0xc7, 0x2c, 0xd2, 0x11, 0x85, 0x4e, 0x00, 0xa0, 0xc9, 0x83,
+	0xf6, 0x08, 0x86, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30,
+	0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x05, 0x1a,
+	0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6d, 0x9e, 0xc6, 0xb7, 0xc7, 0x2c,
+	0xd2, 0x11, 0x85, 0x4e, 0x00, 0xa0, 0xc9, 0x83, 0xf6, 0x08, 0x9c, 0x7a, 0x96, 0xbf, 0xe6, 0x0d,
+	0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x05, 0x1a, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00,
+	0x00, 0x00, 0x6d, 0x9e, 0xc6, 0xb7, 0xc7, 0x2c, 0xd2, 0x11, 0x85, 0x4e, 0x00, 0xa0, 0xc9, 0x83,
+	0xf6, 0x08, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30,
+	0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x05, 0x1a,
+	0x2c, 0x00, 0x94, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14,
+	0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x2c, 0x00, 0x94, 0x00,
+	0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9c, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+	0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+	0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x2c, 0x00, 0x94, 0x00, 0x02, 0x00, 0x02, 0x00,
+	0x00, 0x00, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30,
+	0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02,
+	0x00, 0x00, 0x05, 0x12, 0x28, 0x00, 0x30, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xde, 0x47,
+	0xe6, 0x91, 0x6f, 0xd9, 0x70, 0x4b, 0x95, 0x57, 0xd6, 0x3f, 0xf4, 0xf3, 0xcc, 0xd8, 0x01, 0x01,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x12, 0x24, 0x00, 0xff, 0x01,
+	0x0f, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9a, 0xbd,
+	0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e, 0x5e, 0x1a, 0x4b, 0x07, 0x02, 0x00, 0x00, 0x00, 0x12,
+	0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+	0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x12, 0x18, 0x00, 0xbd, 0x01, 0x0f, 0x00, 0x01, 0x02,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x6e,
+	0x61, 0x6d, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x64, 0x64, 0x61, 0x31,
+	0x64, 0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64, 0x37, 0x2d, 0x34, 0x63, 0x34, 0x39, 0x2d, 0x61,
+	0x31, 0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39, 0x32, 0x34, 0x31, 0x62, 0x35, 0x36, 0x30, 0x65,
+	0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x47, 0x55, 0x49, 0x44, 0x00, 0x01, 0x00, 0x00, 0x00,
+	0x10, 0x00, 0x00, 0x00, 0x57, 0x93, 0x1e, 0x29, 0x25, 0x49, 0xe5, 0x40, 0x9d, 0x98, 0x36, 0x07,
+	0x11, 0x9e, 0xbd, 0xe5, 0x00, 0x72, 0x65, 0x70, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74,
+	0x79, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x90, 0x01,
+	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+	0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+	0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+	0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+	0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+	0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+	0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0xa9, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+	0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+	0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x19, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+	0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+	0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+	0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+	0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x0e, 0x03, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+	0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+	0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+	0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+	0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72,
+	0x79, 0x00, 0x01, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x55, 0x49, 0x44, 0x3d,
+	0x35, 0x32, 0x34, 0x32, 0x39, 0x30, 0x33, 0x38, 0x2d, 0x65, 0x34, 0x33, 0x35, 0x2d, 0x34, 0x66,
+	0x65, 0x33, 0x2d, 0x39, 0x36, 0x34, 0x65, 0x2d, 0x38, 0x30, 0x64, 0x61, 0x31, 0x35, 0x34, 0x39,
+	0x39, 0x63, 0x39, 0x63, 0x3e, 0x3b, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+	0x65, 0x72, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2c, 0x43, 0x4e, 0x3d,
+	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x44, 0x43,
+	0x3d, 0x61, 0x64, 0x64, 0x63, 0x2c, 0x44, 0x43, 0x3d, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x2c, 0x44,
+	0x43, 0x3d, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x44, 0x43, 0x3d, 0x63, 0x6f, 0x6d,
+	0x00
+};
+
+static const char dda1d01d_ldif[] = ""
+"dn: CN=dda1d01d-4bd7-4c49-a184-46f9241b560e,CN=Operations,CN=DomainUpdates,CN=System,DC=addc,DC=samba,DC=example,DC=com\n"
+"objectClass: top\n"
+"objectClass: container\n"
+"cn: dda1d01d-4bd7-4c49-a184-46f9241b560e\n"
+"instanceType: 4\n"
+"whenCreated: 20150708224310.0Z\n"
+"whenChanged: 20150708224310.0Z\n"
+"uSNCreated: 3467\n"
+"uSNChanged: 3467\n"
+"showInAdvancedViewOnly: TRUE\n"
+"nTSecurityDescriptor: O:S-1-5-21-2106703258-1007804629-1260019310-512G:S-1-5-2\n"
+" 1-2106703258-1007804629-1260019310-512D:AI(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;S-\n"
+" 1-5-21-2106703258-1007804629-1260019310-512)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;\n"
+" SY)(A;;RPLCLORC;;;AU)(OA;CIIOID;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828c\n"
+" c14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;4c164200-20c0-11d0-a768-00aa\n"
+" 006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;5f202010-79a5-\n"
+" 11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;\n"
+" 5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)\n"
+" (OA;CIIOID;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad\n"
+" 6f015e5f28;RU)(OA;CIIOID;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de\n"
+" 6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3c\n"
+" f;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;59ba2f42-79a2-11d0-90\n"
+" 20-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;037088f\n"
+" 8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CII\n"
+" OID;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa00304\n"
+" 9e2;RU)(OA;CIIOID;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-\n"
+" a285-00aa003049e2;ED)(OA;CIIOID;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967\n"
+" a9c-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIOID;RP;b7c69e6d-2cc7-11d2-854e-00a0\n"
+" c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIOID;RPLCLORC;;4828cc1\n"
+" 4-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RPLCLORC;;bf967a9c-0de6-11d0-a285\n"
+" -00aa003049e2;RU)(OA;CIIOID;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU\n"
+" )(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)(A;CIID;RPWPCRCCDCL\n"
+" CLORCWOWDSDDTSW;;;S-1-5-21-2106703258-1007804629-1260019310-519)(A;CIID;LC;;;\n"
+" RU)(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)S:AI(OU;CIIOIDSA;WP;f30e3bbe-9ff0-11d1\n"
+" -b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CIIOIDSA;WP;f3\n"
+" 0e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)\n"
+"name: dda1d01d-4bd7-4c49-a184-46f9241b560e\n"
+"objectGUID: 291e9357-4925-40e5-9d98-3607119ebde5\n"
+"replPropertyMetaData:: AQAAAAAAAAAIAAAAAAAAAAAAAAABAAAAfjiuCwMAAACdzc1X7lhuTpa\n"
+" ZzH3hlvEFiw0AAAAAAACLDQAAAAAAAAEAAgABAAAAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0A\n"
+" AAAAAACLDQAAAAAAAAIAAgABAAAAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0AAAAAAACLDQAAA\n"
+" AAAAKkAAgABAAAAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0AAAAAAACLDQAAAAAAABkBAgABAA\n"
+" AAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0AAAAAAACLDQAAAAAAAAEACQABAAAAfjiuCwMAAAC\n"
+" dzc1X7lhuTpaZzH3hlvEFiw0AAAAAAACLDQAAAAAAAA4DCQABAAAAfjiuCwMAAACdzc1X7lhuTpaZ\n"
+" zH3hlvEFiw0AAAAAAACLDQAAAAAAAAMAAAABAAAAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0AA\n"
+" AAAAACLDQAAAAAAAA==\n"
+"objectCategory: <GUID=52429038-e435-4fe3-964e-80da15499c9c>;CN=Container,CN=Sc\n"
+" hema,CN=Configuration,DC=addc,DC=samba,DC=example,DC=com\n\n";
+
+static const char *dda1d01d_ldif_reduced = ""
+"dn: CN=dda1d01d-4bd7-4c49-a184-46f9241b560e,CN=Operations,CN=DomainUpdates,CN=System,DC=addc,DC=samba,DC=example,DC=com\n"
+"objectClass: top\n"
+"objectClass: container\n"
+"instanceType: 4\n"
+"whenChanged: 20150708224310.0Z\n"
+"uSNCreated: 3467\n"
+"showInAdvancedViewOnly: TRUE\n"
+"name: dda1d01d-4bd7-4c49-a184-46f9241b560e\n\n";
+
 static bool torture_ldb_attrs(struct torture_context *torture)
 {
 	TALLOC_CTX *mem_ctx = talloc_new(torture);
@@ -793,6 +1015,235 @@ static bool torture_ldb_dn_invalid_extended(struct torture_context *torture)
 	return true;
 }
 
+static bool helper_ldb_message_compare(struct torture_context *torture,
+				       struct ldb_message *a,
+				       struct ldb_message *b)
+{
+	int i;
+
+	if (a->num_elements != b->num_elements) {
+		return false;
+	}
+
+	for (i = 0; i < a->num_elements; i++) {
+		int j;
+		struct ldb_message_element x = a->elements[i];
+		struct ldb_message_element y = b->elements[i];
+
+		torture_comment(torture, "#%s\n", x.name);
+		torture_assert_int_equal(torture, x.flags, y.flags,
+					 "Flags do not match");
+		torture_assert_str_equal(torture, x.name, y.name,
+					 "Names do not match in field");
+		torture_assert_int_equal(torture, x.num_values, y.num_values,
+					 "Number of values do not match");
+
+		/*
+		 * Records cannot round trip via the SDDL string with a
+		 * nTSecurityDescriptor field.
+		 *
+		 * Parsing from SDDL and diffing the NDR dump output gives the
+		 * following:
+		 *
+		 *          in: struct decode_security_descriptor
+		 *             sd: struct security_descriptor
+		 *                 revision                 : SECURITY_DESCRIPTOR_REVISION_1 (1)
+		 *-                type                     : 0x8c14 (35860)
+		 *-                       0: SEC_DESC_OWNER_DEFAULTED
+		 *-                       0: SEC_DESC_GROUP_DEFAULTED
+		 *+                type                     : 0x8c17 (35863)
+		 *+                       1: SEC_DESC_OWNER_DEFAULTED
+		 *+                       1: SEC_DESC_GROUP_DEFAULTED
+		 *                        1: SEC_DESC_DACL_PRESENT
+		 *                        0: SEC_DESC_DACL_DEFAULTED
+		 *                        1: SEC_DESC_SACL_PRESENT
+		 */
+		if (strcmp(x.name, "nTSecurityDescriptor") == 0) {
+			continue;
+		}
+		for (j = 0; j < x.num_values; j++) {
+			torture_assert_int_equal(torture, x.values[j].length,
+						 y.values[j].length,
+						 "Does not match in length");
+			torture_assert_mem_equal(torture,
+						 x.values[j].data,
+						 y.values[j].data,
+						 x.values[j].length,
+						 "Does not match in data");
+		}
+	}
+	return true;
+}
+
+static bool torture_ldb_unpack(struct torture_context *torture)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(torture);
+	struct ldb_context *ldb;
+	struct ldb_val data = data_blob_const(dda1d01d_bin, sizeof(dda1d01d_bin));
+	struct ldb_message *msg = ldb_msg_new(mem_ctx);
+	const char *ldif_text = dda1d01d_ldif;
+	struct ldb_ldif ldif;
+
+	torture_assert(torture,
+		       ldb = samba_ldb_init(mem_ctx, torture->ev, NULL, NULL, NULL),
+		       "Failed to init ldb");
+
+	torture_assert_int_equal(torture, ldb_unpack_data(ldb, &data, msg), 0,
+				 "ldb_unpack_data failed");
+
+	ldif.changetype = LDB_CHANGETYPE_NONE;
+	ldif.msg = msg;
+	ldif_text = ldb_ldif_write_string(ldb, mem_ctx, &ldif);
+
+	torture_assert_int_equal(torture,
+				 strcmp(ldif_text, dda1d01d_ldif), 0,
+				 "ldif form differs from binary form");
+	return true;
+}
+
+static bool torture_ldb_parse_ldif(struct torture_context *torture)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(torture);
+	const char *ldif_text = dda1d01d_ldif;
+	struct ldb_context *ldb;
+	struct ldb_ldif *ldif;
+	struct ldb_val binary;
+	struct ldb_val data = data_blob_const(dda1d01d_bin, sizeof(dda1d01d_bin));
+	struct ldb_message *msg = ldb_msg_new(mem_ctx);
+
+	torture_assert(torture,
+		       ldb=samba_ldb_init(mem_ctx, torture->ev, NULL,NULL,NULL),
+		       "Failed to init ldb");
+
+	torture_assert(torture,
+		       ldif = ldb_ldif_read_string(ldb, &ldif_text),
+		       "ldb_ldif_read_string failed");
+	torture_assert_int_equal(torture, ldif->changetype, LDB_CHANGETYPE_NONE,
+				 "changetype is incorrect");
+	torture_assert_int_equal(torture,
+				 ldb_pack_data(ldb, ldif->msg, &binary), 0,
+				 "ldb_pack_data failed");
+
+	torture_assert_int_equal(torture, ldb_unpack_data(ldb, &data, msg), 0,
+				 "ldb_unpack_data failed");
+
+	torture_assert(torture,
+		       helper_ldb_message_compare(torture, ldif->msg, msg),
+		       "Forms differ in memory");
+
+	return true;
+}
+
+static bool torture_ldb_unpack_only_attr_list(struct torture_context *torture)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(torture);
+	struct ldb_context *ldb;
+	struct ldb_val data = data_blob_const(dda1d01d_bin, sizeof(dda1d01d_bin));
+	struct ldb_message *msg = ldb_msg_new(mem_ctx);
+	const char *lookup_names[] = {"instanceType", "nonexistant", "whenChanged",
+				      "objectClass", "uSNCreated",
+				      "showInAdvancedViewOnly", "name", "cnNotHere"};
+	unsigned int nb_elements_in_db;
+	const char *ldif_text;
+	struct ldb_ldif ldif;
+
+	torture_assert(torture,
+		       ldb=samba_ldb_init(mem_ctx, torture->ev, NULL, NULL, NULL),
+		       "Failed to init samba");
+
+	torture_assert_int_equal(torture,
+				 ldb_unpack_data_only_attr_list(ldb, &data, msg,
+							  lookup_names, ARRAY_SIZE(lookup_names),
+							  &nb_elements_in_db), 0,
+				 "ldb_unpack_data_only_attr_list failed");
+	torture_assert_int_equal(torture, nb_elements_in_db, 13,
+				 "Got wrong count of elements");
+
+	/* Compare data in binary form */
+	torture_assert_int_equal(torture, msg->num_elements, 6,
+				 "Got wrong number of parsed elements");
+
+	torture_assert_str_equal(torture, msg->elements[0].name, "objectClass",
+				 "First element has wrong name");
+	torture_assert_int_equal(torture, msg->elements[0].num_values, 2,
+				 "First element has wrong count of values");
+	torture_assert_int_equal(torture,
+				 msg->elements[0].values[0].length, 3,
+				 "First element's first value is of wrong length");
+	torture_assert_mem_equal(torture,
+				 msg->elements[0].values[0].data, "top", 3,
+				 "First element's first value is incorrect");
+	torture_assert_int_equal(torture,
+				 msg->elements[0].values[1].length, strlen("container"),
+				 "First element's second value is of wrong length");
+	torture_assert_mem_equal(torture, msg->elements[0].values[1].data,
+				 "container", strlen("container"),
+				 "First element's second value is incorrect");
+
+	torture_assert_str_equal(torture, msg->elements[1].name, "instanceType",
+				 "Second element has wrong name");
+	torture_assert_int_equal(torture, msg->elements[1].num_values, 1,
+				 "Second element has too many values");
+	torture_assert_int_equal(torture, msg->elements[1].values[0].length, 1,
+				 "Second element's value is of wrong length");
+	torture_assert_mem_equal(torture, msg->elements[1].values[0].data,
+				 "4", 1,
+				 "Second element's value is incorrect");
+
+	torture_assert_str_equal(torture, msg->elements[2].name, "whenChanged",
+				 "Third element has wrong name");
+	torture_assert_int_equal(torture, msg->elements[2].num_values, 1,
+				 "Third element has too many values");
+	torture_assert_int_equal(torture, msg->elements[2].values[0].length,
+				 strlen("20150708224310.0Z"),
+				 "Third element's value is of wrong length");
+	torture_assert_mem_equal(torture, msg->elements[2].values[0].data,
+				 "20150708224310.0Z", strlen("20150708224310.0Z"),
+				 "Third element's value is incorrect");
+
+	torture_assert_str_equal(torture, msg->elements[3].name, "uSNCreated",
+				 "Fourth element has wrong name");
+	torture_assert_int_equal(torture, msg->elements[3].num_values, 1,
+				 "Fourth element has too many values");
+	torture_assert_int_equal(torture, msg->elements[3].values[0].length, 4,
+				 "Fourth element's value is of wrong length");
+	torture_assert_mem_equal(torture, msg->elements[3].values[0].data,
+				 "3467", 4,
+				 "Fourth element's value is incorrect");
+
+	torture_assert_str_equal(torture, msg->elements[4].name, "showInAdvancedViewOnly",
+				 "Fifth element has wrong name");
+	torture_assert_int_equal(torture, msg->elements[4].num_values, 1,
+				 "Fifth element has too many values");
+	torture_assert_int_equal(torture, msg->elements[4].values[0].length, 4,
+				 "Fifth element's value is of wrong length");
+	torture_assert_mem_equal(torture, msg->elements[4].values[0].data,
+				 "TRUE", 4,
+				 "Fourth element's value is incorrect");
+
+	torture_assert_str_equal(torture, msg->elements[5].name, "name",
+				 "Sixth element has wrong name");
+	torture_assert_int_equal(torture, msg->elements[5].num_values, 1,
+				 "Sixth element has too many values");
+	torture_assert_int_equal(torture, msg->elements[5].values[0].length,
+				 strlen("dda1d01d-4bd7-4c49-a184-46f9241b560e"),
+				 "Sixth element's value is of wrong length");
+	torture_assert_mem_equal(torture, msg->elements[5].values[0].data,
+				 "dda1d01d-4bd7-4c49-a184-46f9241b560e",
+				 strlen("dda1d01d-4bd7-4c49-a184-46f9241b560e"),
+				 "Sixth element's value is incorrect");
+
+	/* Compare data in ldif form */
+	ldif.changetype = LDB_CHANGETYPE_NONE;
+	ldif.msg = msg;
+	ldif_text = ldb_ldif_write_string(ldb, mem_ctx, &ldif);
+
+	torture_assert_str_equal(torture, ldif_text, dda1d01d_ldif_reduced,
+				 "Expected fields did not match");
+
+	return true;
+}
+
 struct torture_suite *torture_ldb(TALLOC_CTX *mem_ctx)
 {
 	struct torture_suite *suite = torture_suite_create(mem_ctx, "ldb");
@@ -803,9 +1254,17 @@ struct torture_suite *torture_ldb(TALLOC_CTX *mem_ctx)
 
 	torture_suite_add_simple_test(suite, "attrs", torture_ldb_attrs);
 	torture_suite_add_simple_test(suite, "dn-attrs", torture_ldb_dn_attrs);
-	torture_suite_add_simple_test(suite, "dn-extended", torture_ldb_dn_extended);
-	torture_suite_add_simple_test(suite, "dn-invalid-extended", torture_ldb_dn_invalid_extended);
+	torture_suite_add_simple_test(suite, "dn-extended",
+				      torture_ldb_dn_extended);
+	torture_suite_add_simple_test(suite, "dn-invalid-extended",
+				      torture_ldb_dn_invalid_extended);
 	torture_suite_add_simple_test(suite, "dn", torture_ldb_dn);
+	torture_suite_add_simple_test(suite, "unpack-data",
+				      torture_ldb_unpack);
+	torture_suite_add_simple_test(suite, "parse-ldif",
+				      torture_ldb_parse_ldif);
+	torture_suite_add_simple_test(suite, "unpack-data-only-attr-list",
+				      torture_ldb_unpack_only_attr_list);
 
 	suite->description = talloc_strdup(suite, "LDB (samba-specific behaviour) tests");
 
diff --git a/source4/torture/local/fsrvp_state.c b/source4/torture/local/fsrvp_state.c
index 3a08543..a806e64 100644
--- a/source4/torture/local/fsrvp_state.c
+++ b/source4/torture/local/fsrvp_state.c
@@ -298,12 +298,12 @@ static bool test_fsrvp_state_single(struct torture_context *tctx)
 	ok = test_fsrvp_state_smap(tctx, sc, "base_share", "sc_share", &smap);
 	torture_assert(tctx, ok, "failed to create smap");
 
-	DLIST_ADD_END(fss_gs.sc_sets, sc_set, struct fss_sc_set *);
+	DLIST_ADD_END(fss_gs.sc_sets, sc_set);
 	fss_gs.sc_sets_count++;
-	DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
+	DLIST_ADD_END(sc_set->scs, sc);
 	sc_set->scs_count++;
 	sc->sc_set = sc_set;
-	DLIST_ADD_END(sc->smaps, smap, struct fss_sc_smap *);
+	DLIST_ADD_END(sc->smaps, smap);
 	sc->smaps_count++;
 
 	status = fss_state_store(fss_gs.mem_ctx, fss_gs.sc_sets,
@@ -392,23 +392,23 @@ static bool test_fsrvp_state_multi(struct torture_context *tctx)
 				   &smap_abb);
 	torture_assert(tctx, ok, "failed to create smap");
 
-	DLIST_ADD_END(fss_gs.sc_sets, sc_set_a, struct fss_sc_set *);
+	DLIST_ADD_END(fss_gs.sc_sets, sc_set_a);
 	fss_gs.sc_sets_count++;
-	DLIST_ADD_END(fss_gs.sc_sets, sc_set_b, struct fss_sc_set *);
+	DLIST_ADD_END(fss_gs.sc_sets, sc_set_b);
 	fss_gs.sc_sets_count++;
 
-	DLIST_ADD_END(sc_set_a->scs, sc_aa, struct fss_sc *);
+	DLIST_ADD_END(sc_set_a->scs, sc_aa);
 	sc_set_a->scs_count++;
 	sc_aa->sc_set = sc_set_a;
-	DLIST_ADD_END(sc_set_a->scs, sc_ab, struct fss_sc *);
+	DLIST_ADD_END(sc_set_a->scs, sc_ab);
 	sc_set_a->scs_count++;
 	sc_ab->sc_set = sc_set_a;
 
-	DLIST_ADD_END(sc_aa->smaps, smap_aaa, struct fss_sc_smap *);
+	DLIST_ADD_END(sc_aa->smaps, smap_aaa);
 	sc_aa->smaps_count++;
-	DLIST_ADD_END(sc_ab->smaps, smap_aba, struct fss_sc_smap *);
+	DLIST_ADD_END(sc_ab->smaps, smap_aba);
 	sc_ab->smaps_count++;
-	DLIST_ADD_END(sc_ab->smaps, smap_abb, struct fss_sc_smap *);
+	DLIST_ADD_END(sc_ab->smaps, smap_abb);
 	sc_ab->smaps_count++;
 
 	status = fss_state_store(fss_gs.mem_ctx, fss_gs.sc_sets,
diff --git a/source4/torture/local/local.c b/source4/torture/local/local.c
index bad7b65..3988988 100644
--- a/source4/torture/local/local.c
+++ b/source4/torture/local/local.c
@@ -35,7 +35,6 @@
 	torture_local_messaging, 
 	torture_local_irpc, 
 	torture_local_util_strlist, 
-	torture_local_util_parmlist, 
 	torture_local_util_file, 
 	torture_local_util_str, 
 	torture_local_util_time, 
diff --git a/source4/torture/local/wscript_build b/source4/torture/local/wscript_build
index 570222e..eb45df8 100644
--- a/source4/torture/local/wscript_build
+++ b/source4/torture/local/wscript_build
@@ -5,7 +5,7 @@ TORTURE_LOCAL_SOURCE = '''../../../lib/util/charset/tests/iconv.c
 	../../lib/messaging/tests/irpc.c ../../librpc/tests/binding_string.c
 	../../../lib/util/tests/idtree.c ../../../lib/util/tests/dlinklist.c
 	../../lib/socket/testsuite.c ../../libcli/resolve/testsuite.c
-	../../../lib/util/tests/strlist.c ../../../lib/util/tests/parmlist.c
+	../../../lib/util/tests/strlist.c
 	../../../lib/util/tests/str.c ../../../lib/util/tests/time.c
 	../../../lib/util/tests/asn1_tests.c ../../../lib/util/tests/data_blob.c
 	../../../lib/util/tests/file.c ../../../lib/util/tests/genrand.c
diff --git a/source4/torture/nbench/nbio.c b/source4/torture/nbench/nbio.c
index c9b369e..1de988e 100644
--- a/source4/torture/nbench/nbio.c
+++ b/source4/torture/nbench/nbio.c
@@ -521,7 +521,7 @@ static bool nb_do_createx(struct ftable *f,
 		f = talloc (NULL, struct ftable);
 		f->locks = NULL;
 		nb_set_createx_params(f, fname, create_options, create_disposition, handle);
-		DLIST_ADD_END(ftable, f, struct ftable *);
+		DLIST_ADD_END(ftable, f);
 	}
 
 	f->handle = handle;
@@ -653,7 +653,7 @@ static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATU
 		linfo = talloc (f, struct lock_info);
 		linfo->offset = offset;
 		linfo->size = size;
-		DLIST_ADD_END(f->locks, linfo, struct lock_info *);
+		DLIST_ADD_END(f->locks, linfo);
 	}
 
 	return true;
diff --git a/source4/torture/nbt/wins.c b/source4/torture/nbt/wins.c
index d0ae9cd..8c847b5 100644
--- a/source4/torture/nbt/wins.c
+++ b/source4/torture/nbt/wins.c
@@ -169,8 +169,7 @@ static bool nbt_test_wins_name(struct torture_context *tctx, const char *address
 				 * and not handle it as new request
 				 */
 				req->state = NBT_REQUEST_SEND;
-				DLIST_ADD_END(nbtsock->send_queue, req,
-					      struct nbt_name_request *);
+				DLIST_ADD_END(nbtsock->send_queue, req);
 				TEVENT_FD_WRITEABLE(nbtsock->fde);
 				break;
 			}
diff --git a/source4/torture/ndr/backupkey.c b/source4/torture/ndr/backupkey.c
index bc9aa79..972d676 100644
--- a/source4/torture/ndr/backupkey.c
+++ b/source4/torture/ndr/backupkey.c
@@ -154,7 +154,11 @@ struct torture_suite *ndr_backupkey_suite(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite = torture_suite_create(ctx, "backupkey");
 
-	torture_suite_add_ndr_pull_fn_test(suite, bkrp_exported_RSA_key_pair, exported_rsa_ndr, NDR_BUFFERS|NDR_SCALARS, NULL);
+	torture_suite_add_ndr_pullpush_test(suite,
+					    bkrp_exported_RSA_key_pair,
+					    data_blob_const(exported_rsa_ndr,
+							    sizeof(exported_rsa_ndr)),
+					    NULL);
 
 	return suite;
 }
diff --git a/source4/torture/ndr/clusapi.c b/source4/torture/ndr/clusapi.c
new file mode 100644
index 0000000..f1156d0
--- /dev/null
+++ b/source4/torture/ndr/clusapi.c
@@ -0,0 +1,383 @@
+/*
+   Unix SMB/CIFS implementation.
+   test suite for clusapi ndr operations
+
+   Copyright (C) Guenther Deschner 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_clusapi.h"
+#include "torture/ndr/proto.h"
+#include "param/param.h"
+#include "libcli/registry/util_reg.h"
+
+static const uint8_t clusapi_PROPERTY_LIST_data[] = {
+	0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
+	0x46, 0x00, 0x69, 0x00, 0x78, 0x00, 0x51, 0x00, 0x75, 0x00, 0x6f, 0x00,
+	0x72, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x50, 0x00, 0x72, 0x00,
+	0x65, 0x00, 0x76, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x51, 0x00,
+	0x75, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x3e, 0x00, 0x00, 0x00,
+	0x49, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00,
+	0x50, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x73, 0x00,
+	0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x53, 0x00, 0x74, 0x00,
+	0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x53, 0x00,
+	0x74, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x75, 0x00, 0x70, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+	0x24, 0x00, 0x00, 0x00, 0x53, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00,
+	0x65, 0x00, 0x64, 0x00, 0x56, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x75, 0x00,
+	0x6d, 0x00, 0x65, 0x00, 0x73, 0x00, 0x52, 0x00, 0x6f, 0x00, 0x6f, 0x00,
+	0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00,
+	0x43, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x6c, 0x00, 0x75, 0x00,
+	0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x53, 0x00, 0x74, 0x00,
+	0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00,
+	0x57, 0x00, 0x69, 0x00, 0x74, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x73, 0x00,
+	0x73, 0x00, 0x44, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00,
+	0x69, 0x00, 0x63, 0x00, 0x57, 0x00, 0x65, 0x00, 0x69, 0x00, 0x67, 0x00,
+	0x68, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x41, 0x00, 0x64, 0x00,
+	0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x41, 0x00, 0x63, 0x00, 0x63, 0x00,
+	0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x50, 0x00, 0x6f, 0x00, 0x69, 0x00,
+	0x6e, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00
+};
+
+static bool clusapi_PROPERTY_LIST_check(struct torture_context *tctx,
+					struct clusapi_PROPERTY_LIST *r)
+{
+	DATA_BLOB blob_dword_null = data_blob_talloc_zero(tctx, 4);
+	DATA_BLOB blob_dword_one = data_blob(NULL, 4);
+	const char *str;
+
+	SIVAL(blob_dword_one.data, 0, 1);
+
+	torture_assert_int_equal(tctx, r->propertyCount, 6, "propertyCount");
+
+	torture_assert_int_equal(tctx, r->propertyValues[0].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[0].size, 20, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[0].buffer, "FixQuorum", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[0].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	torture_assert_data_blob_equal(tctx, r->propertyValues[0].PropertyValues.Buffer, blob_dword_null, "Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[0].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[1].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[1].size, 28, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[1].buffer, "PreventQuorum", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[1].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	torture_assert_data_blob_equal(tctx, r->propertyValues[1].PropertyValues.Buffer, blob_dword_null, "Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[1].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[2].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[2].size, 62, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[2].buffer, "IgnorePersistentStateOnStartup", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[2].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	torture_assert_data_blob_equal(tctx, r->propertyValues[2].PropertyValues.Buffer, blob_dword_null, "Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[2].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[3].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[3].size, 36, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[3].buffer, "SharedVolumesRoot", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[3].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_SZ, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Size, 36, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Buffer.length, 36, "PropertyValues.Buffer.length");
+	pull_reg_sz(tctx, &r->propertyValues[3].PropertyValues.Buffer, &str);
+	torture_assert_str_equal(tctx, str, "C:\\ClusterStorage", "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[3].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[4].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[4].size, 42, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[4].buffer, "WitnessDynamicWeight", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[4].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	torture_assert_data_blob_equal(tctx, r->propertyValues[4].PropertyValues.Buffer, blob_dword_one, "Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[4].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[5].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[5].size, 34, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[5].buffer, "AdminAccessPoint", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[5].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	torture_assert_data_blob_equal(tctx, r->propertyValues[5].PropertyValues.Buffer, blob_dword_one, "Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[5].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	return true;
+}
+
+static const uint8_t clusapi_PROPERTY_LIST_data2[] = {
+	0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00,
+	0x4e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x61, 0x00,
+	0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00,
+	0x0c, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00,
+	0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+	0x26, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00,
+	0x48, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68, 0x00, 0x65, 0x00, 0x73, 0x00,
+	0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00,
+	0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x80, 0x25, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x6f, 0x00,
+	0x64, 0x00, 0x65, 0x00, 0x4c, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x65, 0x00,
+	0x73, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00,
+	0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x80, 0x25, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x61, 0x00,
+	0x6a, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00,
+	0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00,
+	0x4d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x56, 0x00,
+	0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+	0x18, 0x00, 0x00, 0x00, 0x42, 0x00, 0x75, 0x00, 0x69, 0x00, 0x6c, 0x00,
+	0x64, 0x00, 0x4e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00,
+	0x72, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+	0x16, 0x00, 0x00, 0x00, 0x43, 0x00, 0x53, 0x00, 0x44, 0x00, 0x56, 0x00,
+	0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+	0x1e, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00,
+	0x49, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00,
+	0x63, 0x00, 0x65, 0x00, 0x49, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x01, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00,
+	0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
+	0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2d, 0x00,
+	0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x30, 0x00,
+	0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00,
+	0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
+	0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
+	0x4e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x44, 0x00, 0x72, 0x00,
+	0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00,
+	0x74, 0x00, 0x75, 0x00, 0x73, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x6f, 0x00,
+	0x64, 0x00, 0x65, 0x00, 0x44, 0x00, 0x72, 0x00, 0x61, 0x00, 0x69, 0x00,
+	0x6e, 0x00, 0x54, 0x00, 0x61, 0x00, 0x72, 0x00, 0x67, 0x00, 0x65, 0x00,
+	0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+	0x1c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x61, 0x00,
+	0x6d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x57, 0x00, 0x65, 0x00, 0x69, 0x00,
+	0x67, 0x00, 0x68, 0x00, 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x65, 0x00,
+	0x65, 0x00, 0x64, 0x00, 0x73, 0x00, 0x50, 0x00, 0x72, 0x00, 0x65, 0x00,
+	0x76, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x51, 0x00, 0x75, 0x00,
+	0x6f, 0x00, 0x72, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool clusapi_PROPERTY_LIST_check2(struct torture_context *tctx,
+					 struct clusapi_PROPERTY_LIST *r)
+{
+	DATA_BLOB blob_dword_null = data_blob_talloc_zero(tctx, 4);
+	DATA_BLOB blob_dword_one = data_blob(NULL, 4);
+	DATA_BLOB blob_dword = data_blob(NULL, 4);
+	const char *str;
+
+	SIVAL(blob_dword_one.data, 0, 1);
+
+	torture_assert_int_equal(tctx, r->propertyCount, 12, "propertyCount");
+
+	torture_assert_int_equal(tctx, r->propertyValues[0].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[0].size, 18, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[0].buffer, "NodeName", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[0].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_SZ, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Size, 12, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Buffer.length, 12, "PropertyValues.Buffer.length");
+	pull_reg_sz(tctx, &r->propertyValues[0].PropertyValues.Buffer, &str);
+	torture_assert_str_equal(tctx, str, "node1", "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[0].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[1].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[1].size, 38, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[1].buffer, "NodeHighestVersion", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[1].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	SIVAL(blob_dword.data, 0, 0x00082580);
+	torture_assert_data_blob_equal(tctx, r->propertyValues[1].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[1].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[2].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[2].size, 36, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[2].buffer, "NodeLowestVersion", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[2].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	SIVAL(blob_dword.data, 0, 0x00082580);
+	torture_assert_data_blob_equal(tctx, r->propertyValues[2].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[2].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[3].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[3].size, 26, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[3].buffer, "MajorVersion", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[3].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	SIVAL(blob_dword.data, 0, 0x06);
+	torture_assert_data_blob_equal(tctx, r->propertyValues[3].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[3].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[4].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[4].size, 26, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[4].buffer, "MinorVersion", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[4].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	SIVAL(blob_dword.data, 0, 0x03);
+	torture_assert_data_blob_equal(tctx, r->propertyValues[4].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[4].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[5].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[5].size, 24, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[5].buffer, "BuildNumber", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[5].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	SIVAL(blob_dword.data, 0, 0x00002580);
+	torture_assert_data_blob_equal(tctx, r->propertyValues[5].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[5].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[6].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[6].size, 22, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[6].buffer, "CSDVersion", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[6].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[6].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_SZ, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[6].PropertyValues.Size, 2, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[6].PropertyValues.Buffer.length, 2, "PropertyValues.Buffer.length");
+	pull_reg_sz(tctx, &r->propertyValues[6].PropertyValues.Buffer, &str);
+	torture_assert_str_equal(tctx, str, "", "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[6].PropertyValues.Padding.length, 2, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[6].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[7].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[7].size, 30, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[7].buffer, "NodeInstanceID", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[7].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[7].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_SZ, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[7].PropertyValues.Size, 74, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[7].PropertyValues.Buffer.length, 74, "PropertyValues.Buffer.length");
+	pull_reg_sz(tctx, &r->propertyValues[7].PropertyValues.Buffer, &str);
+	torture_assert_str_equal(tctx, str, "00000000-0000-0000-0000-000000000002", "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[7].PropertyValues.Padding.length, 2, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[7].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[8].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[8].size, 32, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[8].buffer, "NodeDrainStatus", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[8].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[8].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[8].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[8].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	torture_assert_data_blob_equal(tctx, r->propertyValues[8].PropertyValues.Buffer, blob_dword_null, "Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[8].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[8].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[9].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[9].size, 32, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[9].buffer, "NodeDrainTarget", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[9].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[9].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[9].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[9].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	SIVAL(blob_dword.data, 0, 0xffffffff);
+	torture_assert_data_blob_equal(tctx, r->propertyValues[9].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[9].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[9].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[10].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[10].size, 28, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[10].buffer, "DynamicWeight", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[10].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[10].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[10].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[10].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	torture_assert_data_blob_equal(tctx, r->propertyValues[10].PropertyValues.Buffer, blob_dword_one, "Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[10].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[10].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	torture_assert_int_equal(tctx, r->propertyValues[11].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+	torture_assert_int_equal(tctx, r->propertyValues[11].size, 38, "size");
+	torture_assert_str_equal(tctx, r->propertyValues[11].buffer, "NeedsPreventQuorum", "buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[11].padding.length, 0, "padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[11].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+	torture_assert_int_equal(tctx, r->propertyValues[11].PropertyValues.Size, 4, "PropertyValues.Size");
+	torture_assert_int_equal(tctx, r->propertyValues[11].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+	torture_assert_data_blob_equal(tctx, r->propertyValues[11].PropertyValues.Buffer, blob_dword_null, "Buffer");
+	torture_assert_int_equal(tctx, r->propertyValues[11].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+	torture_assert_int_equal(tctx, r->propertyValues[11].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+	return true;
+}
+
+struct torture_suite *ndr_clusapi_suite(TALLOC_CTX *ctx)
+{
+	struct torture_suite *suite = torture_suite_create(ctx, "clusapi");
+
+	torture_suite_add_ndr_pullpush_test(suite,
+					    clusapi_PROPERTY_LIST,
+					    data_blob_const(clusapi_PROPERTY_LIST_data,sizeof(clusapi_PROPERTY_LIST_data)),
+					    clusapi_PROPERTY_LIST_check);
+
+	torture_suite_add_ndr_pullpush_test(suite,
+					    clusapi_PROPERTY_LIST,
+					    data_blob_const(clusapi_PROPERTY_LIST_data2,sizeof(clusapi_PROPERTY_LIST_data2)),
+					    clusapi_PROPERTY_LIST_check2);
+
+	return suite;
+}
diff --git a/source4/torture/ndr/ndr.c b/source4/torture/ndr/ndr.c
index fe30705..dac550e 100644
--- a/source4/torture/ndr/ndr.c
+++ b/source4/torture/ndr/ndr.c
@@ -130,7 +130,7 @@ _PUBLIC_ struct torture_test *_torture_suite_add_ndr_pullpush_test(
 	test->fn = check_fn;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 }
@@ -226,7 +226,7 @@ _PUBLIC_ struct torture_test *_torture_suite_add_ndr_pull_inout_test(
 	test->fn = check_fn;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 }
@@ -417,6 +417,8 @@ struct torture_suite *torture_local_ndr(TALLOC_CTX *mem_ctx)
 	torture_suite_add_suite(suite, ndr_ntlmssp_suite(suite));
 	torture_suite_add_suite(suite, ndr_backupkey_suite(suite));
 	torture_suite_add_suite(suite, ndr_witness_suite(suite));
+	torture_suite_add_suite(suite, ndr_clusapi_suite(suite));
+	torture_suite_add_suite(suite, ndr_negoex_suite(suite));
 	torture_suite_add_suite(suite, ndr_string_suite(suite));
 
 	torture_suite_add_simple_test(suite, "string terminator",
diff --git a/source4/torture/ndr/negoex.c b/source4/torture/ndr/negoex.c
new file mode 100644
index 0000000..db94cb3
--- /dev/null
+++ b/source4/torture/ndr/negoex.c
@@ -0,0 +1,100 @@
+/*
+   Unix SMB/CIFS implementation.
+   test suite for negoex ndr operations
+
+   Copyright (C) Guenther Deschner 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_negoex.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t negoex_MESSAGE_ARRAY_data[] = {
+	0x4e, 0x45, 0x47, 0x4f, 0x45, 0x58, 0x54, 0x53, 0x01, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
+	0x06, 0xcb, 0x30, 0x71, 0x62, 0x20, 0x1b, 0x6a, 0x40, 0x9e, 0x35, 0x14,
+	0xc2, 0x6b, 0x17, 0x73, 0xba, 0x25, 0xdd, 0x80, 0x91, 0xfb, 0xae, 0x2c,
+	0x68, 0x4b, 0x99, 0x28, 0xf0, 0x3c, 0x3e, 0xf3, 0xe2, 0xcf, 0x60, 0xa3,
+	0x29, 0xee, 0xa0, 0xf9, 0xb1, 0x10, 0x4b, 0x56, 0xc3, 0x83, 0xc7, 0x32,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x5c, 0x33, 0x53, 0x0d, 0xea, 0xf9, 0x0d, 0x4d, 0xb2, 0xec, 0x4a, 0xe3,
+	0x78, 0x6e, 0xc3, 0x08, 0x4e, 0x45, 0x47, 0x4f, 0x45, 0x58, 0x54, 0x53,
+	0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+	0x98, 0x00, 0x00, 0x00, 0x06, 0xcb, 0x30, 0x71, 0x62, 0x20, 0x1b, 0x6a,
+	0x40, 0x9e, 0x35, 0x14, 0xc2, 0x6b, 0x17, 0x73, 0x5c, 0x33, 0x53, 0x0d,
+	0xea, 0xf9, 0x0d, 0x4d, 0xb2, 0xec, 0x4a, 0xe3, 0x78, 0x6e, 0xc3, 0x08,
+	0x40, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x30, 0x56, 0xa0, 0x54,
+	0x30, 0x52, 0x30, 0x27, 0x80, 0x25, 0x30, 0x23, 0x31, 0x21, 0x30, 0x1f,
+	0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
+	0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x50, 0x75, 0x62,
+	0x6c, 0x69, 0x63, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x27, 0x80, 0x25, 0x30,
+	0x23, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18,
+	0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e,
+	0x67, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4b, 0x65, 0x79
+};
+
+static bool negoex_MESSAGE_ARRAY_check(struct torture_context *tctx,
+				       struct negoex_MESSAGE_ARRAY *r)
+{
+	struct GUID guid;
+	struct negoex_MESSAGE m;
+
+	torture_assert_int_equal(tctx, r->count, 2, "count");
+
+	m = r->messages[0];
+
+	torture_assert_str_equal(tctx, m.signature, "NEGOEXTS", "signature");
+	torture_assert_int_equal(tctx, m.type, NEGOEX_MESSAGE_TYPE_ACCEPTOR_NEGO, "type");
+	torture_assert_int_equal(tctx, m.sequence_number, 0, "sequence_number");
+	torture_assert_int_equal(tctx, m.header_length, 96, "header_length");
+	torture_assert_int_equal(tctx, m.message_length, 112, "message_length");
+	GUID_from_string("7130cb06-2062-6a1b-409e-3514c26b1773", &guid);
+	torture_assert_guid_equal(tctx, m.conversation_id, guid, "conversation_id");
+	/* torture_assert_int_equal(tctx, m.p.nego.random, ba25dd8091fbae2c684b9928f03c3ef3e2cf60a329eea0f9b1104b56c383c732, "p.nego.random"); */
+	torture_assert_int_equal(tctx, m.p.nego.protocol_version, 0, "p.nego.protocol_version");
+	torture_assert_int_equal(tctx, m.p.nego.auth_schemes.count, 1, "p.nego.auth_schemes.count");
+	GUID_from_string("0d53335c-f9ea-4d0d-b2ec-4ae3786ec308", &guid);
+	torture_assert_guid_equal(tctx, m.p.nego.auth_schemes.array[0].guid, guid, "p.nego.auth_schemes.array[0].guid");
+	torture_assert_int_equal(tctx, m.p.nego.extensions.count, 0, "p.nego.extensions.count");
+
+	m = r->messages[1];
+
+	torture_assert_str_equal(tctx, m.signature, "NEGOEXTS", "signature");
+	torture_assert_int_equal(tctx, m.type, NEGOEX_MESSAGE_TYPE_ACCEPTOR_META_DATA, "type");
+	torture_assert_int_equal(tctx, m.sequence_number, 1, "sequence_number");
+	torture_assert_int_equal(tctx, m.header_length, 64, "header_length");
+	torture_assert_int_equal(tctx, m.message_length, 152, "message_length");
+	GUID_from_string("7130cb06-2062-6a1b-409e-3514c26b1773", &guid);
+	torture_assert_guid_equal(tctx, m.conversation_id, guid, "conversation_id");
+	GUID_from_string("0d53335c-f9ea-4d0d-b2ec-4ae3786ec308", &guid);
+	torture_assert_guid_equal(tctx, m.p.exchange.auth_scheme.guid, guid, "auth_scheme.guid");
+	torture_assert_int_equal(tctx, m.p.exchange.exchange.blob.length, 88, "exchange.blob.length");
+
+	return true;
+}
+
+struct torture_suite *ndr_negoex_suite(TALLOC_CTX *ctx)
+{
+	struct torture_suite *suite = torture_suite_create(ctx, "negoex");
+
+	torture_suite_add_ndr_pullpush_test(suite, negoex_MESSAGE_ARRAY,
+					    data_blob_const(negoex_MESSAGE_ARRAY_data, sizeof(negoex_MESSAGE_ARRAY_data)),
+					    negoex_MESSAGE_ARRAY_check);
+
+	return suite;
+}
diff --git a/source4/torture/ndr/witness.c b/source4/torture/ndr/witness.c
index e837eab..9ba97d3 100644
--- a/source4/torture/ndr/witness.c
+++ b/source4/torture/ndr/witness.c
@@ -268,6 +268,42 @@ static bool witness_AsyncNotify_check_OUT(struct torture_context *tctx,
 	return true;
 }
 
+static const uint8_t witness_AsyncNotify_data_move_OUT[] = {
+	0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00,
+	0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x03, 0x2d, 0x00, 0x00, 0x00, 0x00,
+	0x38, 0xe8, 0xeb, 0x26, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x60, 0x26,
+	0x00, 0x00, 0x00, 0x00
+};
+
+static bool witness_AsyncNotify_check_move_OUT(struct torture_context *tctx,
+					       struct witness_AsyncNotify *r)
+{
+	struct witness_notifyResponse *n;
+	struct witness_IPaddrInfoList *i;
+
+	torture_assert(tctx, r->out.response, "r->out.response");
+
+	n = *(r->out.response);
+
+	torture_assert_int_equal(tctx, n->type, WITNESS_NOTIFY_CLIENT_MOVE, "type");
+	torture_assert_int_equal(tctx, n->length, 36, "length");
+	torture_assert_int_equal(tctx, n->num, 1, "num");
+
+	i = &n->messages[0].client_move;
+
+	torture_assert_int_equal(tctx, i->length, 36, "i->length");
+	torture_assert_int_equal(tctx, i->reserved, 0, "i->reserved");
+	torture_assert_int_equal(tctx, i->num, 1, "i->num");
+
+	torture_assert_int_equal(tctx, i->addr[0].flags, WITNESS_IPADDR_V4, "i->addr[0].flags");
+	torture_assert_str_equal(tctx, i->addr[0].ipv4, "192.168.3.45", "i->addr[0].ipv4");
+	torture_assert_str_equal(tctx, i->addr[0].ipv6, "0000:0000:38e8:eb26:8e00:0000:009e:6026", "i->addr[0].ipv6");
+
+	return true;
+}
+
 struct torture_suite *ndr_witness_suite(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite = torture_suite_create(ctx, "witness");
@@ -320,5 +356,13 @@ struct torture_suite *ndr_witness_suite(TALLOC_CTX *ctx)
 					    NDR_OUT,
 					    0,
 					    witness_AsyncNotify_check_OUT);
+
+	torture_suite_add_ndr_pullpush_fn_test_flags(suite,
+					    witness_AsyncNotify,
+					    witness_AsyncNotify_data_move_OUT,
+					    NDR_OUT,
+					    0,
+					    witness_AsyncNotify_check_move_OUT);
+
 	return suite;
 }
diff --git a/source4/torture/raw/pingpong.c b/source4/torture/raw/pingpong.c
index 2cb3187..61f1d6b 100644
--- a/source4/torture/raw/pingpong.c
+++ b/source4/torture/raw/pingpong.c
@@ -72,7 +72,7 @@ try_again:
 
 	status = smb_raw_lock(cli->tree, &io);
 
-	/* If we dont use timeouts and we got file lock conflict
+	/* If we don't use timeouts and we got file lock conflict
 	   just try the lock again.
 	*/
 	if (lock_timeout==0) {
diff --git a/source4/torture/raw/session.c b/source4/torture/raw/session.c
index 1937ef7..6938c88 100644
--- a/source4/torture/raw/session.c
+++ b/source4/torture/raw/session.c
@@ -19,7 +19,7 @@
 
 #include "includes.h"
 #include "torture.h"
-#include "smb_cli.h"
+#include "libcli/libcli.h"
 #include "torture/raw/proto.h"
 #include "smb_composite/smb_composite.h"
 #include "lib/cmdline/popt_common.h"
diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c
index a3b8aaa..aaff59f 100644
--- a/source4/torture/rpc/backupkey.c
+++ b/source4/torture/rpc/backupkey.c
@@ -3,6 +3,7 @@
    test suite for backupkey remote protocol rpc operations
 
    Copyright (C) Matthieu Patou 2010-2011
+   Copyright (C) Andreas Schneider <asn at samba.org> 2015
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -24,23 +25,18 @@
 #include "torture/rpc/torture_rpc.h"
 #include "torture/ndr/ndr.h"
 
-#ifdef SAMBA4_USES_HEIMDAL
 #include "librpc/gen_ndr/ndr_backupkey_c.h"
 #include "librpc/gen_ndr/ndr_backupkey.h"
 #include "librpc/gen_ndr/ndr_lsa_c.h"
 #include "librpc/gen_ndr/ndr_security.h"
 #include "lib/cmdline/popt_common.h"
 #include "libcli/auth/proto.h"
-#include "lib/crypto/arcfour.h"
-#include <com_err.h>
-#include <hcrypto/sha.h>
 #include <system/network.h>
-#include <hx509.h>
-#include <der.h>
-#include <hcrypto/rsa.h>
-#include <hcrypto/hmac.h>
-#include <hcrypto/sha.h>
-#include <hcrypto/evp.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <gnutls/x509.h>
+#include <gnutls/abstract.h>
 
 enum test_wrong {
 	WRONG_MAGIC,
@@ -255,7 +251,7 @@ static DATA_BLOB *create_unencryptedsecret(TALLOC_CTX *mem_ctx,
 
 /*
  * Create an access check structure, the format depends on the version parameter.
- * If broken is specified then we create a stucture that isn't conform to the 
+ * If broken is specified then we create a stucture that isn't conform to the
  * specification.
  *
  * If the structure can't be created then NULL is returned.
@@ -278,7 +274,7 @@ static DATA_BLOB *create_access_check(struct torture_context *tctx,
 
 	if (version == 2) {
 		struct bkrp_access_check_v2 access_struct;
-		struct sha sctx;
+		gnutls_hash_hd_t dig_ctx;
 		uint8_t nonce[32];
 
 		ZERO_STRUCT(access_struct);
@@ -299,11 +295,12 @@ static DATA_BLOB *create_access_check(struct torture_context *tctx,
 		 * so we reduce the size of what has to be calculated
 		 */
 
-		SHA1_Init(&sctx);
-		SHA1_Update(&sctx, blob->data,
+		gnutls_hash_init(&dig_ctx, GNUTLS_DIG_SHA1);
+		gnutls_hash(dig_ctx,
+			    blob->data,
 			    blob->length - sizeof(access_struct.hash));
-		SHA1_Final(blob->data + blob->length - sizeof(access_struct.hash),
-			   &sctx);
+		gnutls_hash_deinit(dig_ctx,
+				   blob->data + blob->length - sizeof(access_struct.hash));
 
 		/* Altering the SHA */
 		if (broken) {
@@ -313,7 +310,7 @@ static DATA_BLOB *create_access_check(struct torture_context *tctx,
 
 	if (version == 3) {
 		struct bkrp_access_check_v3 access_struct;
-		struct hc_sha512state sctx;
+		gnutls_hash_hd_t dig_ctx;
 		uint8_t nonce[32];
 
 		ZERO_STRUCT(access_struct);
@@ -333,11 +330,12 @@ static DATA_BLOB *create_access_check(struct torture_context *tctx,
 		* so we reduce the size of what has to be calculated
 		*/
 
-		SHA512_Init(&sctx);
-		SHA512_Update(&sctx, blob->data,
-			      blob->length - sizeof(access_struct.hash));
-		SHA512_Final(blob->data + blob->length - sizeof(access_struct.hash),
-			     &sctx);
+		gnutls_hash_init(&dig_ctx, GNUTLS_DIG_SHA512);
+		gnutls_hash(dig_ctx,
+			    blob->data,
+			    blob->length - sizeof(access_struct.hash));
+		gnutls_hash_deinit(dig_ctx,
+				   blob->data + blob->length - sizeof(access_struct.hash));
 
 		/* Altering the SHA */
 		if (broken) {
@@ -354,53 +352,56 @@ static DATA_BLOB *encrypt_blob(struct torture_context *tctx,
 				    DATA_BLOB *key,
 				    DATA_BLOB *iv,
 				    DATA_BLOB *to_encrypt,
-				    const AlgorithmIdentifier *alg)
+				    gnutls_cipher_algorithm_t cipher_algo)
 {
-	hx509_crypto crypto;
-	hx509_context hctx;
-	heim_octet_string ivos;
-	heim_octet_string *encrypted;
-	DATA_BLOB *blob = talloc_zero(mem_ctx, DATA_BLOB);
-	int res;
+	gnutls_cipher_hd_t cipher_handle = { 0 };
+	gnutls_datum_t gkey = {
+		.data = key->data,
+		.size = key->length,
+	};
+	gnutls_datum_t giv = {
+		.data = iv->data,
+		.size = iv->length,
+	};
+	DATA_BLOB *blob;
+	int rc;
 
-	ivos.data = talloc_array(mem_ctx, uint8_t, iv->length);
-	ivos.length = iv->length;
-	memcpy(ivos.data, iv->data, iv->length);
+	blob = talloc(mem_ctx, DATA_BLOB);
+	if (blob == NULL) {
+		return NULL;
+	}
 
-	hx509_context_init(&hctx);
-	res = hx509_crypto_init(hctx, NULL, &alg->algorithm, &crypto);
-	if (res) {
-		torture_comment(tctx,
-				"error while doing the init of the crypto object\n");
-		hx509_context_free(&hctx);
+	*blob = data_blob_talloc_zero(mem_ctx, to_encrypt->length);
+	if (blob->data == NULL) {
+		talloc_free(blob);
 		return NULL;
 	}
-	res = hx509_crypto_set_key_data(crypto, key->data, key->length);
-	if (res) {
+
+	rc = gnutls_cipher_init(&cipher_handle,
+				cipher_algo,
+				&gkey,
+				&giv);
+	if (rc != GNUTLS_E_SUCCESS) {
 		torture_comment(tctx,
-				"error while setting the key of the crypto object\n");
-		hx509_context_free(&hctx);
+				"gnutls_cipher_init failed: %s\n",
+				gnutls_strerror(rc));
+		talloc_free(blob);
 		return NULL;
 	}
 
-	hx509_crypto_set_padding(crypto, HX509_CRYPTO_PADDING_NONE);
-	res = hx509_crypto_encrypt(crypto,
-				   to_encrypt->data,
-				   to_encrypt->length,
-				   &ivos,
-				   &encrypted);
-	if (res) {
-		torture_comment(tctx, "error while encrypting\n");
-		hx509_crypto_destroy(crypto);
-		hx509_context_free(&hctx);
+	rc = gnutls_cipher_encrypt2(cipher_handle,
+				    to_encrypt->data,
+				    to_encrypt->length,
+				    blob->data,
+				    blob->length);
+	gnutls_cipher_deinit(cipher_handle);
+	if (rc != GNUTLS_E_SUCCESS) {
+		torture_comment(tctx,
+				"gnutls_cipher_decrypt2 failed: %s\n",
+				gnutls_strerror(rc));
 		return NULL;
 	}
 
-	*blob = data_blob_talloc(blob, encrypted->data, encrypted->length);
-	der_free_octet_string(encrypted);
-	free(encrypted);
-	hx509_crypto_destroy(crypto);
-	hx509_context_free(&hctx);
 	return blob;
 }
 
@@ -413,42 +414,68 @@ static struct GUID *get_cert_guid(struct torture_context *tctx,
 				  uint8_t *cert_data,
 				  uint32_t cert_len)
 {
-	hx509_context hctx;
-	hx509_cert cert;
-	heim_bit_string subjectuniqid;
-	DATA_BLOB data;
-	int hret;
-	uint32_t size;
+	gnutls_x509_crt_t x509_cert = NULL;
+	gnutls_datum_t x509_crt_data = {
+		.data = cert_data,
+		.size = cert_len,
+	};
+	uint8_t dummy[1] = {0};
+	DATA_BLOB issuer_unique_id = {
+		.data = dummy,
+		.length = 0,
+	};
 	struct GUID *guid = talloc_zero(mem_ctx, struct GUID);
 	NTSTATUS status;
+	int rc;
 
-	hx509_context_init(&hctx);
+	rc = gnutls_x509_crt_init(&x509_cert);
+	if (rc != GNUTLS_E_SUCCESS) {
+		torture_comment(tctx,
+				"gnutls_x509_crt_init failed - %s",
+				gnutls_strerror(rc));
+		return NULL;
+	}
 
-	hret = hx509_cert_init_data(hctx, cert_data, cert_len, &cert);
-	if (hret) {
-		torture_comment(tctx, "error while loading the cert\n");
-		hx509_context_free(&hctx);
+	rc = gnutls_x509_crt_import(x509_cert,
+				    &x509_crt_data,
+				    GNUTLS_X509_FMT_DER);
+	if (rc != GNUTLS_E_SUCCESS) {
+		torture_comment(tctx,
+				"gnutls_x509_crt_import failed - %s",
+				gnutls_strerror(rc));
+		gnutls_x509_crt_deinit(x509_cert);
 		return NULL;
 	}
-	hret = hx509_cert_get_issuer_unique_id(hctx, cert, &subjectuniqid);
-	if (hret) {
-		torture_comment(tctx, "error while getting the issuer_uniq_id\n");
-		hx509_cert_free(cert);
-		hx509_context_free(&hctx);
+
+	/* Get the buffer size */
+	rc = gnutls_x509_crt_get_issuer_unique_id(x509_cert,
+						  (char *)issuer_unique_id.data,
+						  &issuer_unique_id.length);
+	if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER ||
+	    issuer_unique_id.length == 0) {
+		gnutls_x509_crt_deinit(x509_cert);
 		return NULL;
 	}
 
-	/* The subjectuniqid is a bit string,
-	 * which means that the real size has to be divided by 8
-	 * to have the number of bytes
-	 */
-	hx509_cert_free(cert);
-	hx509_context_free(&hctx);
-	size = subjectuniqid.length / 8;
-	data = data_blob_const(subjectuniqid.data, size);
+	issuer_unique_id = data_blob_talloc_zero(mem_ctx,
+						 issuer_unique_id.length);
+	if (issuer_unique_id.data == NULL) {
+		gnutls_x509_crt_deinit(x509_cert);
+		return NULL;
+	}
 
-	status = GUID_from_data_blob(&data, guid);
-	der_free_bit_string(&subjectuniqid);
+	rc = gnutls_x509_crt_get_issuer_unique_id(x509_cert,
+						  (char *)issuer_unique_id.data,
+						  &issuer_unique_id.length);
+	gnutls_x509_crt_deinit(x509_cert);
+	if (rc != GNUTLS_E_SUCCESS) {
+		torture_comment(tctx,
+				"gnutls_x509_crt_get_issuer_unique_id failed - %s",
+				gnutls_strerror(rc));
+		return NULL;
+	}
+
+	status = GUID_from_data_blob(&issuer_unique_id, guid);
 	if (!NT_STATUS_IS_OK(status)) {
 		return NULL;
 	}
@@ -466,54 +493,76 @@ static DATA_BLOB *encrypt_blob_pk(struct torture_context *tctx,
 				  uint32_t cert_len,
 				  DATA_BLOB *to_encrypt)
 {
-	hx509_context hctx;
-	hx509_cert cert;
-	heim_octet_string secretdata;
-	heim_octet_string encrypted;
-	heim_oid encryption_oid;
+	gnutls_x509_crt_t x509_cert;
+	gnutls_datum_t x509_crt_data = {
+		.data = cert_data,
+		.size = cert_len,
+	};
+	gnutls_pubkey_t pubkey;
+	gnutls_datum_t plaintext = {
+		.data = to_encrypt->data,
+		.size = to_encrypt->length,
+	};
+	gnutls_datum_t ciphertext = {
+		.data = NULL,
+	};
 	DATA_BLOB *blob;
-	int hret;
+	int rc;
+
+	rc = gnutls_x509_crt_init(&x509_cert);
+	if (rc != GNUTLS_E_SUCCESS) {
+		return NULL;
+	}
+
+	rc = gnutls_x509_crt_import(x509_cert,
+				    &x509_crt_data,
+				    GNUTLS_X509_FMT_DER);
+	if (rc != GNUTLS_E_SUCCESS) {
+		gnutls_x509_crt_deinit(x509_cert);
+		return NULL;
+	}
 
-	hx509_context_init(&hctx);
+	rc = gnutls_pubkey_init(&pubkey);
+	if (rc != GNUTLS_E_SUCCESS) {
+		gnutls_x509_crt_deinit(x509_cert);
+		return NULL;
+	}
 
-	hret = hx509_cert_init_data(hctx, cert_data, cert_len, &cert);
-	if (hret) {
-		torture_comment(tctx, "error while loading the cert\n");
-		hx509_context_free(&hctx);
+	rc = gnutls_pubkey_import_x509(pubkey,
+				       x509_cert,
+				       0);
+	gnutls_x509_crt_deinit(x509_cert);
+	if (rc != GNUTLS_E_SUCCESS) {
+		gnutls_pubkey_deinit(pubkey);
 		return NULL;
 	}
 
-	secretdata.data = to_encrypt->data;
-	secretdata.length = to_encrypt->length;
-	hret = hx509_cert_public_encrypt(hctx, &secretdata,
-					  cert, &encryption_oid,
-					  &encrypted);
-	hx509_cert_free(cert);
-	hx509_context_free(&hctx);
-	if (hret) {
-		torture_comment(tctx, "error while encrypting\n");
+	rc = gnutls_pubkey_encrypt_data(pubkey,
+					0,
+					&plaintext,
+					&ciphertext);
+	gnutls_pubkey_deinit(pubkey);
+	if (rc != GNUTLS_E_SUCCESS) {
 		return NULL;
 	}
 
 	blob = talloc_zero(mem_ctx, DATA_BLOB);
 	if (blob == NULL) {
-		der_free_oid(&encryption_oid);
-		der_free_octet_string(&encrypted);
+		gnutls_pubkey_deinit(pubkey);
 		return NULL;
 	}
 
-	*blob = data_blob_talloc(blob, encrypted.data, encrypted.length);
-	der_free_octet_string(&encrypted);
-	der_free_oid(&encryption_oid);
+	*blob = data_blob_talloc(blob, ciphertext.data, ciphertext.size);
+	gnutls_free(ciphertext.data);
 	if (blob->data == NULL) {
+		gnutls_pubkey_deinit(pubkey);
 		return NULL;
 	}
 
 	return blob;
 }
 
-
-static struct bkrp_BackupKey *createRetreiveBackupKeyGUIDStruct(struct torture_context *tctx,
+static struct bkrp_BackupKey *createRetrieveBackupKeyGUIDStruct(struct torture_context *tctx,
 				struct dcerpc_pipe *p, int version, DATA_BLOB *out)
 {
 	struct dcerpc_binding *binding;
@@ -576,8 +625,7 @@ static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tc
 	DATA_BLOB *enc_xs = NULL;
 	DATA_BLOB *blob2;
 	DATA_BLOB enc_sec_reverted;
-	DATA_BLOB des3_key;
-	DATA_BLOB aes_key;
+	DATA_BLOB key;
 	DATA_BLOB iv;
 	DATA_BLOB out_blob;
 	struct GUID *guid, *g;
@@ -586,7 +634,8 @@ static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tc
 	enum ndr_err_code ndr_err;
 	NTSTATUS status;
 	const char *user;
-	struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, version, &out_blob);
+	gnutls_cipher_algorithm_t cipher_algo;
+	struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, version, &out_blob);
 	if (r == NULL) {
 		return NULL;
 	}
@@ -605,7 +654,7 @@ static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tc
 			       "Get GUID");
 
 	/*
-	 * We have to set it outside of the function createRetreiveBackupKeyGUIDStruct
+	 * We have to set it outside of the function createRetrieveBackupKeyGUIDStruct
 	 * the len of the blob, this is due to the fact that they don't have the
 	 * same size (one is 32bits the other 64bits)
 	 */
@@ -622,7 +671,7 @@ static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tc
 	}
 
 	if (broken_magic_access){
-		/* The start of the access_check structure contains the 
+		/* The start of the access_check structure contains the
 		 * GUID of the certificate
 		 */
 		xs->data[0]++;
@@ -653,27 +702,23 @@ static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tc
 	}
 
 	size = sec->length;
-	if (version ==2) {
-		const AlgorithmIdentifier *alg = hx509_crypto_des_rsdi_ede3_cbc();
-		iv.data = sec->data+(size - 8);
-		iv.length = 8;
-
-		des3_key.data = sec->data+(size - 32);
-		des3_key.length = 24;
-
-		enc_xs = encrypt_blob(tctx, tctx, &des3_key, &iv, xs, alg);
+	switch (version) {
+	case 2:
+		cipher_algo = GNUTLS_CIPHER_3DES_CBC;
+		break;
+	case 3:
+		cipher_algo = GNUTLS_CIPHER_AES_256_CBC;
+		break;
+	default:
+		return NULL;
 	}
-	if (version == 3) {
-		const AlgorithmIdentifier *alg = hx509_crypto_aes256_cbc();
-		iv.data = sec->data+(size-16);
-		iv.length = 16;
-
-		aes_key.data = sec->data+(size-48);
-		aes_key.length = 32;
+	iv.length = gnutls_cipher_get_iv_size(cipher_algo);
+	iv.data = sec->data + (size - iv.length);
 
-		enc_xs = encrypt_blob(tctx, tctx, &aes_key, &iv, xs, alg);
-	}
+	key.length = gnutls_cipher_get_key_size(cipher_algo);
+	key.data = sec->data + (size - (key.length + iv.length));
 
+	enc_xs = encrypt_blob(tctx, tctx, &key, &iv, xs, cipher_algo);
 	if (!enc_xs) {
 		return NULL;
 	}
@@ -740,12 +785,12 @@ static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tc
 /* Check that we are able to receive the certificate of the DCs
  * used for client wrap version of the backup key protocol
  */
-static bool test_RetreiveBackupKeyGUID(struct torture_context *tctx,
+static bool test_RetrieveBackupKeyGUID(struct torture_context *tctx,
 					struct dcerpc_pipe *p)
 {
 	struct dcerpc_binding_handle *b = p->binding_handle;
 	DATA_BLOB out_blob;
-	struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+	struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
@@ -774,7 +819,7 @@ static bool test_RetreiveBackupKeyGUID(struct torture_context *tctx,
 	return true;
 }
 
-/* Test to check the failure to recover a secret because the 
+/* Test to check the failure to recover a secret because the
  * secret blob is not reversed
  */
 static bool test_RestoreGUID_ko(struct torture_context *tctx,
@@ -787,6 +832,8 @@ static bool test_RestoreGUID_ko(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -799,10 +846,13 @@ static bool test_RestoreGUID_ko(struct torture_context *tctx,
 		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
 		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAM, "Wrong error code");
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -816,6 +866,8 @@ static bool test_RestoreGUID_wrongversion(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -828,10 +880,13 @@ static bool test_RestoreGUID_wrongversion(struct torture_context *tctx,
 		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
 		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAM, "Wrong error code on wrong version");
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -845,6 +900,8 @@ static bool test_RestoreGUID_wronguser(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -857,10 +914,13 @@ static bool test_RestoreGUID_wronguser(struct torture_context *tctx,
 		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
 		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_ACCESS, "Restore GUID");
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -874,6 +934,8 @@ static bool test_RestoreGUID_v3(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -887,10 +949,13 @@ static bool test_RestoreGUID_v3(struct torture_context *tctx,
 		torture_assert_werr_equal(tctx, r->out.result, WERR_OK, "Restore GUID");
 		torture_assert_str_equal(tctx, (char*)resp.secret.data, secret, "Wrong secret");
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -903,6 +968,8 @@ static bool test_RestoreGUID(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -919,10 +986,13 @@ static bool test_RestoreGUID(struct torture_context *tctx,
 					     "Unable to unmarshall bkrp_client_side_unwrapped");
 		torture_assert_str_equal(tctx, (char*)resp.secret.data, secret, "Wrong secret");
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -936,6 +1006,8 @@ static bool test_RestoreGUID_badmagiconsecret(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -948,10 +1020,13 @@ static bool test_RestoreGUID_badmagiconsecret(struct torture_context *tctx,
 		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
 		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Wrong error code while providing bad magic in secret");
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -963,6 +1038,8 @@ static bool test_RestoreGUID_emptyrequest(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -977,10 +1054,13 @@ static bool test_RestoreGUID_emptyrequest(struct torture_context *tctx,
 		out_blob.length = *r->out.data_out_len;
 		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAM, "Bad error code on wrong has in access check");
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -994,6 +1074,8 @@ static bool test_RestoreGUID_badcertguid(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -1005,18 +1087,21 @@ static bool test_RestoreGUID_badcertguid(struct torture_context *tctx,
 		ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
 		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
 
-		/* 
+		/*
 		 * Windows 2012R2 has, presumably, a programming error
-		 * returning an NTSTATUS code on this interface 
+		 * returning an NTSTATUS code on this interface
 		 */
 		if (W_ERROR_V(r->out.result) != NT_STATUS_V(NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
 			torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check");
 		}
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -1030,6 +1115,8 @@ static bool test_RestoreGUID_badmagicaccesscheck(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -1042,10 +1129,13 @@ static bool test_RestoreGUID_badmagicaccesscheck(struct torture_context *tctx,
 		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
 		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check");
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -1059,6 +1149,8 @@ static bool test_RestoreGUID_badhashaccesscheck(struct torture_context *tctx,
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
@@ -1071,35 +1163,31 @@ static bool test_RestoreGUID_badhashaccesscheck(struct torture_context *tctx,
 		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
 		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check");
 	} else {
-		struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
 			NT_STATUS_ACCESS_DENIED, "Get GUID");
 	}
+
+	gnutls_global_init();
+
 	return true;
 }
 
-/* 
+/*
  * Check that the RSA modulus in the certificate of the DCs has 2048 bits.
  */
-static bool test_RetreiveBackupKeyGUID_2048bits(struct torture_context *tctx,
-					struct dcerpc_pipe *p)
+static bool test_RetrieveBackupKeyGUID_validate(struct torture_context *tctx,
+						struct dcerpc_pipe *p)
 {
 	struct dcerpc_binding_handle *b = p->binding_handle;
 	DATA_BLOB out_blob;
-	struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+	struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
 
-	hx509_context hctx;
-	int hret;
-	hx509_cert cert;
-	SubjectPublicKeyInfo spki;
-	RSA *rsa;
-	int RSA_returned_bits;
+	gnutls_global_init();
 
-	torture_assert(tctx, r != NULL, "createRetreiveBackupKeyGUIDStruct failed");
-	
-	hx509_context_init(&hctx);
+	torture_assert(tctx, r != NULL, "test_RetrieveBackupKeyGUID_validate failed");
 
 	if (r == NULL) {
 		return false;
@@ -1108,7 +1196,30 @@ static bool test_RetreiveBackupKeyGUID_2048bits(struct torture_context *tctx,
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
-		const unsigned char *spki_spk_data;
+		gnutls_x509_crt_t x509_cert = NULL;
+		gnutls_pubkey_t pubkey = NULL;
+		gnutls_datum_t x509_crt_data;
+		gnutls_pk_algorithm_t pubkey_algo;
+		uint8_t dummy[1] = {0};
+		DATA_BLOB subject_unique_id = {
+			.data = dummy,
+			.length = 0,
+		};
+		DATA_BLOB issuer_unique_id = {
+			.data = dummy,
+			.length = 0,
+		};
+		DATA_BLOB reversed = {
+			.data = dummy,
+			.length = 0,
+		};
+		DATA_BLOB serial_number;
+		unsigned int RSA_returned_bits = 0;
+		int version;
+		size_t i;
+		int cmp;
+		int rc;
+
 		torture_assert_ntstatus_ok(tctx,
 				dcerpc_bkrp_BackupKey_r(b, tctx, r),
 				"Get GUID");
@@ -1118,39 +1229,153 @@ static bool test_RetreiveBackupKeyGUID_2048bits(struct torture_context *tctx,
 
 		out_blob.length = *r->out.data_out_len;
 
-		hret = hx509_cert_init_data(hctx, out_blob.data, out_blob.length, &cert);
-		torture_assert_int_equal(tctx, hret, 0, "hx509_cert_init_data failed");
+		x509_crt_data.data = out_blob.data;
+		x509_crt_data.size = out_blob.length;
+
+		rc = gnutls_x509_crt_init(&x509_cert);
+		if (rc != GNUTLS_E_SUCCESS) {
+			return NULL;
+		}
+
+		rc = gnutls_x509_crt_import(x509_cert,
+					    &x509_crt_data,
+					    GNUTLS_X509_FMT_DER);
+		torture_assert_int_equal(tctx,
+					 rc,
+					 GNUTLS_E_SUCCESS,
+					 "gnutls_x509_crt_import failed");
+
+		/* Compare unique ids */
 
-		hret = hx509_cert_get_SPKI(hctx, cert , &spki);
-		torture_assert_int_equal(tctx, hret, 0, "hx509_cert_get_SPKI failed");
+		/* Get buffer size */
+		rc = gnutls_x509_crt_get_subject_unique_id(x509_cert,
+							   (char *)subject_unique_id.data,
+							   &subject_unique_id.length);
+		torture_assert_int_equal(tctx,
+					 rc,
+					 GNUTLS_E_SHORT_MEMORY_BUFFER,
+					 "gnutls_x509_crt_get_subject_unique_id "
+					 "get buffer size failed");
 
-		/* We must take a copy, as d2i_RSAPublicKey *changes* the input parameter */
-		spki_spk_data = spki.subjectPublicKey.data;
-		rsa = d2i_RSAPublicKey(NULL, &spki_spk_data, spki.subjectPublicKey.length / 8);
-		torture_assert_int_equal(tctx, rsa != NULL, 1, "d2i_RSAPublicKey failed");
+		subject_unique_id = data_blob_talloc_zero(tctx,
+							  subject_unique_id.length);
 
-		RSA_returned_bits = BN_num_bits(rsa->n);
+		rc = gnutls_x509_crt_get_subject_unique_id(x509_cert,
+							   (char *)subject_unique_id.data,
+							   &subject_unique_id.length);
 		torture_assert_int_equal(tctx,
-						RSA_returned_bits,
-						2048,
-						"RSA Key doesn't have 2048 bits");
+					 rc,
+					 GNUTLS_E_SUCCESS,
+					 "gnutls_x509_crt_get_subject_unique_id failed");
+
+		rc = gnutls_x509_crt_get_issuer_unique_id(x509_cert,
+							  (char *)issuer_unique_id.data,
+							  &issuer_unique_id.length);
+		torture_assert_int_equal(tctx,
+					 rc,
+					 GNUTLS_E_SHORT_MEMORY_BUFFER,
+					 "gnutls_x509_crt_get_issuer_unique_id "
+					 "get buffer size failed");
+
+		issuer_unique_id = data_blob_talloc_zero(tctx,
+							 issuer_unique_id.length);
+
+		rc = gnutls_x509_crt_get_issuer_unique_id(x509_cert,
+							  (char *)issuer_unique_id.data,
+							  &issuer_unique_id.length);
+		torture_assert_int_equal(tctx,
+					 rc,
+					 GNUTLS_E_SUCCESS,
+					 "gnutls_x509_crt_get_issuer_unique_id failed");
+
+		cmp = data_blob_cmp(&subject_unique_id, &issuer_unique_id);
+		torture_assert(tctx,
+			       cmp == 0,
+			       "The GUID to identify the public key is not "
+			       "identical");
+
+		rc = gnutls_x509_crt_get_serial(x509_cert,
+						reversed.data,
+						&reversed.length);
+		torture_assert_int_equal(tctx,
+					 rc,
+					 GNUTLS_E_SHORT_MEMORY_BUFFER,
+					 "gnutls_x509_crt_get_serial "
+					 "get buffer size failed");
 
-		RSA_free(rsa);
+		reversed = data_blob_talloc_zero(tctx,
+						 reversed.length);
 
-		/* 
-		 * Because we prevented spki from being changed above,
-		 * we can now safely call this to free it 
+		rc = gnutls_x509_crt_get_serial(x509_cert,
+						reversed.data,
+						&reversed.length);
+		torture_assert_int_equal(tctx,
+					 rc,
+					 GNUTLS_E_SUCCESS,
+					 "gnutls_x509_crt_get_serial failed");
+
+		/*
+		 * Heimdal sometimes adds a leading byte to the data buffer of
+		 * the serial number. So lets uses the subject_unique_id size
+		 * and ignore the leading byte.
 		 */
-		free_SubjectPublicKeyInfo(&spki);
-		hx509_cert_free(cert);
-		hx509_context_free(&hctx);
+		serial_number = data_blob_talloc_zero(tctx,
+						      subject_unique_id.length);
+
+		for (i = 0; i < serial_number.length; i++) {
+			serial_number.data[i] = reversed.data[reversed.length - i - 1];
+		}
 
+		cmp = data_blob_cmp(&subject_unique_id, &serial_number);
+		torture_assert(tctx,
+			       cmp == 0,
+			       "The GUID to identify the public key is not "
+			       "identical");
+
+		/* Check certificate version */
+		version = gnutls_x509_crt_get_version(x509_cert);
+		torture_assert_int_equal(tctx,
+					 version,
+					 3,
+					 "Invalid certificate version");
+
+		/* Get the public key */
+		rc = gnutls_pubkey_init(&pubkey);
+		torture_assert_int_equal(tctx,
+					 rc,
+					 GNUTLS_E_SUCCESS,
+					 "gnutls_pubkey_init failed");
+
+		rc = gnutls_pubkey_import_x509(pubkey,
+					       x509_cert,
+					       0);
+		gnutls_x509_crt_deinit(x509_cert);
+		torture_assert_int_equal(tctx,
+					 rc,
+					 GNUTLS_E_SUCCESS,
+					 "gnutls_pubkey_import_x509 failed");
+
+		pubkey_algo = gnutls_pubkey_get_pk_algorithm(pubkey,
+							     &RSA_returned_bits);
+		gnutls_pubkey_deinit(pubkey);
+		torture_assert_int_equal(tctx,
+					 pubkey_algo,
+					 GNUTLS_PK_RSA,
+					 "gnutls_pubkey_get_pk_algorithm did "
+					 "not return a RSA key");
+		torture_assert_int_equal(tctx,
+						RSA_returned_bits,
+						2048,
+						"RSA Key doesn't have 2048 bits");
 	} else {
 		torture_assert_ntstatus_equal(tctx,
 						dcerpc_bkrp_BackupKey_r(b, tctx, r),
 						NT_STATUS_ACCESS_DENIED,
 						"Get GUID");
 	}
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -1197,7 +1422,7 @@ static bool test_ServerWrap_encrypt_decrypt(struct torture_context *tctx,
 			       r.out.result,
 			       "encrypt");
 	encrypted.length = *r.out.data_out_len;
-	
+
 	/* Decrypt */
 	torture_assert_ntstatus_ok(tctx,
 				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
@@ -1300,7 +1525,7 @@ static bool test_ServerWrap_decrypt_wrong_keyGUID(struct torture_context *tctx,
 	ndr_err = ndr_push_struct_blob(&encrypted, tctx, &server_side_wrapped,
 				       (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped);
 	torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "push of server_side_wrapped");
-	
+
 	/* Decrypt */
 	torture_assert_ntstatus_ok(tctx,
 				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
@@ -1554,7 +1779,7 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 	struct GUID preferred_key_guid;
 	DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret));
 	DATA_BLOB preferred_key, preferred_key_clear, session_key,
-		decrypt_key, decrypt_key_clear, encrypted_blob, symkey_blob,
+		decrypt_key, decrypt_key_clear, encrypted_blob,
 		sid_blob;
 	struct bkrp_dc_serverwrap_key server_key;
 	struct lsa_DATA_BUF_PTR bufp1;
@@ -1564,14 +1789,17 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 	uint8_t symkey[20]; /* SHA-1 hash len */
 	uint8_t mackey[20]; /* SHA-1 hash len */
 	uint8_t mac[20]; /* SHA-1 hash len */
-	unsigned int hash_len;
-	HMAC_CTX ctx;
+	gnutls_hmac_hd_t hmac_hnd;
+	gnutls_cipher_hd_t cipher_hnd;
+	gnutls_datum_t cipher_key;
+	int rc;
+
 	ZERO_STRUCT(r);
 	ZERO_STRUCT(r_secret);
 	ZERO_STRUCT(r_query_secret);
 
 	/* Now read BCKUPKEY_P and prove we can do a matching decrypt and encrypt */
-	
+
 	torture_assert_ntstatus_ok(tctx,
 				   torture_rpc_connection(tctx, &lsa_p, &ndr_table_lsarpc),
 				   "Opening LSA pipe");
@@ -1579,18 +1807,18 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 
 	torture_assert(tctx, test_lsa_OpenPolicy2(lsa_b, tctx, &handle), "OpenPolicy failed");
 	r_secret.in.name.string = "G$BCKUPKEY_P";
-	
+
 	r_secret.in.handle = handle;
 	r_secret.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
 	r_secret.out.sec_handle = &sec_handle;
-	
+
 	torture_comment(tctx, "Testing OpenSecret\n");
-	
+
 	torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(lsa_b, tctx, &r_secret),
 				   "OpenSecret failed");
 	torture_assert_ntstatus_ok(tctx, r_secret.out.result,
 				   "OpenSecret failed");
-	
+
 	r_query_secret.in.sec_handle = &sec_handle;
 	r_query_secret.in.new_val = &bufp1;
 	bufp1.buf = NULL;
@@ -1599,41 +1827,41 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 		"QuerySecret failed");
 	torture_assert_ntstatus_ok(tctx, r_query_secret.out.result,
 				   "QuerySecret failed");
-	
-	
+
+
 	preferred_key.data = r_query_secret.out.new_val->buf->data;
 	preferred_key.length = r_query_secret.out.new_val->buf->size;
 	torture_assert_ntstatus_ok(tctx, dcerpc_fetch_session_key(lsa_p, &session_key),
 				   "dcerpc_fetch_session_key failed");
-	
+
 	torture_assert_ntstatus_ok(tctx,
 				   sess_decrypt_blob(tctx,
 						     &preferred_key, &session_key, &preferred_key_clear),
 				   "sess_decrypt_blob failed");
-	
+
 	torture_assert_ntstatus_ok(tctx, GUID_from_ndr_blob(&preferred_key_clear, &preferred_key_guid),
 				   "GUID parse failed");
-	
+
 	torture_assert_guid_equal(tctx, server_side_wrapped->guid,
 				  preferred_key_guid,
 				  "GUID didn't match value pointed at by G$BCKUPKEY_P");
 
 	/* And read BCKUPKEY_<guid> and get the actual key */
-	
+
 	key_guid_string = GUID_string(tctx, &server_side_wrapped->guid);
 	r_secret.in.name.string = talloc_asprintf(tctx, "G$BCKUPKEY_%s", key_guid_string);
-	
+
 	r_secret.in.handle = handle;
 	r_secret.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
 	r_secret.out.sec_handle = &sec_handle;
-	
+
 	torture_comment(tctx, "Testing OpenSecret\n");
-	
+
 	torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(lsa_b, tctx, &r_secret),
 				   "OpenSecret failed");
 	torture_assert_ntstatus_ok(tctx, r_secret.out.result,
 				   "OpenSecret failed");
-	
+
 	r_query_secret.in.sec_handle = &sec_handle;
 	r_query_secret.in.new_val = &bufp1;
 
@@ -1641,16 +1869,16 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 				   "QuerySecret failed");
 	torture_assert_ntstatus_ok(tctx, r_query_secret.out.result,
 				   "QuerySecret failed");
-	
-	
+
+
 	decrypt_key.data = r_query_secret.out.new_val->buf->data;
 	decrypt_key.length = r_query_secret.out.new_val->buf->size;
-	
+
 	torture_assert_ntstatus_ok(tctx,
 				   sess_decrypt_blob(tctx,
 						     &decrypt_key, &session_key, &decrypt_key_clear),
 				   "sess_decrypt_blob failed");
-	
+
 	torture_assert_ndr_err_equal(tctx, ndr_pull_struct_blob(&decrypt_key_clear, tctx, &server_key,
 								(ndr_pull_flags_fn_t)ndr_pull_bkrp_dc_serverwrap_key),
 				     NDR_ERR_SUCCESS, "Failed to parse server_key");
@@ -1659,19 +1887,42 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 
 	/*
 	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
-	 * BACKUPKEY_BACKUP_GUID, it really is the whole key 
+	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
 	 */
-	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
-	     server_side_wrapped->r2, sizeof(server_side_wrapped->r2),
-	     symkey, &hash_len);
-	
+	gnutls_hmac_init(&hmac_hnd,
+			 GNUTLS_MAC_SHA1,
+			 server_key.key,
+			 sizeof(server_key.key));
+	gnutls_hmac(hmac_hnd,
+		    server_side_wrapped->r2,
+		    sizeof(server_side_wrapped->r2));
+	gnutls_hmac_output(hmac_hnd, symkey);
+
 	/* rc4 decrypt sid and secret using sym key */
-	symkey_blob = data_blob_const(symkey, sizeof(symkey));
-	
+	cipher_key.data = symkey;
+	cipher_key.size = sizeof(symkey);
+
 	encrypted_blob = data_blob_talloc(tctx, server_side_wrapped->rc4encryptedpayload,
 					  server_side_wrapped->ciphertext_length);
-	
-	arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob);
+
+	rc = gnutls_cipher_init(&cipher_hnd,
+				GNUTLS_CIPHER_ARCFOUR_128,
+				&cipher_key,
+				NULL);
+	torture_assert_int_equal(tctx,
+				 rc,
+				 GNUTLS_E_SUCCESS,
+				 "gnutls_cipher_init failed");
+	rc = gnutls_cipher_encrypt2(cipher_hnd,
+				    encrypted_blob.data,
+				    encrypted_blob.length,
+				    encrypted_blob.data,
+				    encrypted_blob.length);
+	torture_assert_int_equal(tctx,
+				 rc,
+				 GNUTLS_E_SUCCESS,
+				 "gnutls_cipher_encrypt failed");
+	gnutls_cipher_deinit(cipher_hnd);
 
 	torture_assert_ndr_err_equal(tctx, ndr_pull_struct_blob(&encrypted_blob, tctx, &rc4payload,
 				       (ndr_pull_flags_fn_t)ndr_pull_bkrp_rc4encryptedpayload),
@@ -1683,24 +1934,30 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 
 	/*
 	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
-	 * BACKUPKEY_BACKUP_GUID, it really is the whole key 
+	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
 	 */
-	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
-	     rc4payload.r3, sizeof(rc4payload.r3),
-	     mackey, &hash_len);
-	
+	gnutls_hmac(hmac_hnd,
+		    rc4payload.r3,
+		    sizeof(rc4payload.r3));
+	gnutls_hmac_deinit(hmac_hnd, mackey);
+
 	torture_assert_ndr_err_equal(tctx, ndr_push_struct_blob(&sid_blob, tctx, &rc4payload.sid,
 								(ndr_push_flags_fn_t)ndr_push_dom_sid),
 				     NDR_ERR_SUCCESS, "unable to push SID");
 
-	HMAC_CTX_init(&ctx);
-	HMAC_Init_ex(&ctx, mackey, hash_len, EVP_sha1(), NULL);
+	gnutls_hmac_init(&hmac_hnd,
+			 GNUTLS_MAC_SHA1,
+			 mackey,
+			 sizeof(mackey));
 	/* SID field */
-	HMAC_Update(&ctx, sid_blob.data, sid_blob.length);
+	gnutls_hmac(hmac_hnd,
+		    sid_blob.data,
+		    sid_blob.length);
 	/* Secret field */
-	HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length);
-	HMAC_Final(&ctx, mac, &hash_len);
-	HMAC_CTX_cleanup(&ctx);
+	gnutls_hmac(hmac_hnd,
+		    rc4payload.secret_data.data,
+		    rc4payload.secret_data.length);
+	gnutls_hmac_output(hmac_hnd, mac);
 
 	torture_assert_mem_equal(tctx, mac, rc4payload.mac, sizeof(mac), "mac not correct");
 	torture_assert_int_equal(tctx, rc4payload.secret_data.length,
@@ -1714,7 +1971,7 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 
 	torture_assert_sid_equal(tctx, &rc4payload.sid, caller_sid, "Secret saved with wrong SID");
 
-	
+
 	/* RE-encrypt */
 
 	if (wrong == WRONG_SID) {
@@ -1729,17 +1986,18 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 				     NDR_ERR_SUCCESS,
 				     "push of sid failed");
 
-	HMAC_CTX_init(&ctx);
-	HMAC_Init_ex(&ctx, mackey, 20, EVP_sha1(), NULL);
 	/* SID field */
-	HMAC_Update(&ctx, sid_blob.data, sid_blob.length);
+	gnutls_hmac(hmac_hnd,
+		    sid_blob.data,
+		    sid_blob.length);
 	/* Secret field */
-	HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length);
-	HMAC_Final(&ctx, rc4payload.mac, &hash_len);
-	HMAC_CTX_cleanup(&ctx);
+	gnutls_hmac(hmac_hnd,
+		    rc4payload.secret_data.data,
+		    rc4payload.secret_data.length);
+	gnutls_hmac_deinit(hmac_hnd, rc4payload.mac);
 
 	dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac));
-	
+
 	torture_assert_ndr_err_equal(tctx,
 				     ndr_push_struct_blob(&encrypted_blob, tctx, &rc4payload,
 							  (ndr_push_flags_fn_t)ndr_push_bkrp_rc4encryptedpayload),
@@ -1747,13 +2005,34 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 				     "push of rc4payload failed");
 
 	if (wrong == WRONG_KEY) {
-		symkey_blob.data[0] = 78;
-		symkey_blob.data[1] = 78;
-		symkey_blob.data[2] = 78;
+		symkey[0] = 78;
+		symkey[1] = 78;
+		symkey[2] = 78;
 	}
-	
+
 	/* rc4 encrypt sid and secret using sym key */
-	arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob);
+	cipher_key.data = symkey;
+	cipher_key.size = sizeof(symkey);
+
+	rc = gnutls_cipher_init(&cipher_hnd,
+				GNUTLS_CIPHER_ARCFOUR_128,
+				&cipher_key,
+				NULL);
+	torture_assert_int_equal(tctx,
+				 rc,
+				 GNUTLS_E_SUCCESS,
+				 "gnutls_cipher_init failed");
+	rc = gnutls_cipher_encrypt2(cipher_hnd,
+				    encrypted_blob.data,
+				    encrypted_blob.length,
+				    encrypted_blob.data,
+				    encrypted_blob.length);
+	torture_assert_int_equal(tctx,
+				 rc,
+				 GNUTLS_E_SUCCESS,
+				 "gnutls_cipher_encrypt failed");
+	gnutls_cipher_deinit(cipher_hnd);
+
 
 	/* re-create server wrap structure */
 
@@ -1766,7 +2045,7 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
 					 encrypted_blob.length,
 					 "expected encrypted data not to change");
 	}
-						 
+
 	server_side_wrapped->payload_length = rc4payload.secret_data.length;
 	server_side_wrapped->ciphertext_length = encrypted_blob.length;
 	server_side_wrapped->rc4encryptedpayload = encrypted_blob.data;
@@ -1794,6 +2073,8 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx,
 	enum dcerpc_AuthLevel auth_level;
 	ZERO_STRUCT(r);
 
+	gnutls_global_init();
+
 	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
 
 	/* Encrypt */
@@ -1846,7 +2127,7 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx,
 		repush = true;
 		break;
 	case WRONG_CIPHERTEXT_LENGTH:
-		/* 
+		/*
 		 * Change the ciphertext len.  We can't push this if
 		 * we have it wrong, so do it raw
 		 */
@@ -1857,7 +2138,7 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx,
 		repush = true;
 		break;
 	case SHORT_CIPHERTEXT_LENGTH:
-		/* 
+		/*
 		 * Change the ciphertext len.  We can't push this if
 		 * we have it wrong, so do it raw
 		 */
@@ -1868,7 +2149,7 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx,
 		repush = true;
 		break;
 	case ZERO_CIPHERTEXT_LENGTH:
-		/* 
+		/*
 		 * Change the ciphertext len.  We can't push this if
 		 * we have it wrong, so do it raw
 		 */
@@ -1890,7 +2171,7 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx,
 					       (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped);
 		torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "push of server_side_wrapped");
 	}
-	
+
 	/* Decrypt */
 	torture_assert_ntstatus_ok(tctx,
 				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
@@ -1928,7 +2209,7 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx,
 					  WERR_INVALID_PARAM,
 					  "decrypt should fail with WERR_INVALID_PARAM");
 	}
-	
+
 	/* Decrypt */
 	torture_assert_ntstatus_ok(tctx,
 				   GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
@@ -1966,7 +2247,9 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx,
 					  WERR_INVALID_PARAM,
 					  "decrypt should fail with WERR_INVALID_PARAM");
 	}
-	
+
+	gnutls_global_deinit();
+
 	return true;
 }
 
@@ -2035,28 +2318,18 @@ static bool test_ServerWrap_encrypt_decrypt_wrong_sid(struct torture_context *tc
 {
 	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_SID);
 }
-#else
-static bool test_skip(struct torture_context *tctx,
-		      void *data)
-{
-	torture_skip(tctx, "Skip backupkey test with MIT Kerberos");
-
-	return true;
-}
-#endif
 
 struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx)
 {
 	struct torture_suite *suite = torture_suite_create(mem_ctx, "backupkey");
 
-#ifdef SAMBA4_USES_HEIMDAL
 	struct torture_rpc_tcase *tcase;
 
 	tcase = torture_suite_add_rpc_iface_tcase(suite, "backupkey",
 						  &ndr_table_backupkey);
 
 	torture_rpc_tcase_add_test(tcase, "retreive_backup_key_guid",
-				   test_RetreiveBackupKeyGUID);
+				   test_RetrieveBackupKeyGUID);
 
 	torture_rpc_tcase_add_test(tcase, "restore_guid",
 				   test_RestoreGUID);
@@ -2093,8 +2366,8 @@ struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx)
 	torture_rpc_tcase_add_test(tcase, "empty_request_restore_guid",
 				   test_RestoreGUID_emptyrequest);
 
-	torture_rpc_tcase_add_test(tcase, "retreive_backup_key_guid_2048_bits",
-				   test_RetreiveBackupKeyGUID_2048bits);
+	torture_rpc_tcase_add_test(tcase, "retreive_backup_key_guid_validate",
+				   test_RetrieveBackupKeyGUID_validate);
 
 	torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt",
 				   test_ServerWrap_encrypt_decrypt);
@@ -2132,22 +2405,14 @@ struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx)
 	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_zero_ciphertext_length",
 				   test_ServerWrap_decrypt_zero_ciphertext_length);
 
-	torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_remote_key", 
+	torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_remote_key",
 				   test_ServerWrap_encrypt_decrypt_remote_key);
-	
+
 	torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_wrong_key",
 				   test_ServerWrap_encrypt_decrypt_wrong_key);
 
 	torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_wrong_sid",
 				   test_ServerWrap_encrypt_decrypt_wrong_sid);
-#else
-	struct torture_tcase *tcase;
-
-	tcase = torture_suite_add_tcase(suite, "backupkey");
-
-	torture_tcase_add_simple_test(tcase, "skip",
-				      test_skip);
-#endif
 
 	return suite;
 }
diff --git a/source4/torture/rpc/backupkey_heimdal.c b/source4/torture/rpc/backupkey_heimdal.c
new file mode 100644
index 0000000..9c388c0
--- /dev/null
+++ b/source4/torture/rpc/backupkey_heimdal.c
@@ -0,0 +1,2134 @@
+/*
+   Unix SMB/CIFS implementation.
+   test suite for backupkey remote protocol rpc operations
+
+   Copyright (C) Matthieu Patou 2010-2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../libcli/security/security.h"
+
+#include "torture/rpc/torture_rpc.h"
+#include "torture/ndr/ndr.h"
+
+#include "librpc/gen_ndr/ndr_backupkey_c.h"
+#include "librpc/gen_ndr/ndr_backupkey.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/cmdline/popt_common.h"
+#include "libcli/auth/proto.h"
+#include "lib/crypto/arcfour.h"
+#include <com_err.h>
+#include <hcrypto/sha.h>
+#include <system/network.h>
+#include <hx509.h>
+#include <der.h>
+#include <hcrypto/rsa.h>
+#include <hcrypto/hmac.h>
+#include <hcrypto/sha.h>
+#include <hcrypto/evp.h>
+
+enum test_wrong {
+	WRONG_MAGIC,
+	WRONG_R2,
+	WRONG_PAYLOAD_LENGTH,
+	WRONG_CIPHERTEXT_LENGTH,
+	SHORT_PAYLOAD_LENGTH,
+	SHORT_CIPHERTEXT_LENGTH,
+	ZERO_PAYLOAD_LENGTH,
+	ZERO_CIPHERTEXT_LENGTH,
+	RIGHT_KEY,
+	WRONG_KEY,
+	WRONG_SID,
+};
+
+/* Our very special and valued secret */
+/* No need to put const as we cast the array in uint8_t
+ * we will get a warning about the discared const
+ */
+static const char secret[] = "tata yoyo mais qu'est ce qu'il y a sous ton grand chapeau ?";
+
+/* Get the SID from a user */
+static struct dom_sid *get_user_sid(struct torture_context *tctx,
+				    TALLOC_CTX *mem_ctx,
+				    const char *user)
+{
+	struct lsa_ObjectAttribute attr;
+	struct lsa_QosInfo qos;
+	struct lsa_OpenPolicy2 r;
+	struct lsa_Close c;
+	NTSTATUS status;
+	struct policy_handle handle;
+	struct lsa_LookupNames l;
+	struct lsa_TransSidArray sids;
+	struct lsa_RefDomainList *domains = NULL;
+	struct lsa_String lsa_name;
+	uint32_t count = 0;
+	struct dom_sid *result;
+	TALLOC_CTX *tmp_ctx;
+	struct dcerpc_pipe *p2;
+	struct dcerpc_binding_handle *b;
+
+	const char *domain = cli_credentials_get_domain(cmdline_credentials);
+
+	torture_assert_ntstatus_ok(tctx,
+				torture_rpc_connection(tctx, &p2, &ndr_table_lsarpc),
+				"could not open lsarpc pipe");
+	b = p2->binding_handle;
+
+	if (!(tmp_ctx = talloc_new(mem_ctx))) {
+		return NULL;
+	}
+	qos.len = 0;
+	qos.impersonation_level = 2;
+	qos.context_mode = 1;
+	qos.effective_only = 0;
+
+	attr.len = 0;
+	attr.root_dir = NULL;
+	attr.object_name = NULL;
+	attr.attributes = 0;
+	attr.sec_desc = NULL;
+	attr.sec_qos = &qos;
+
+	r.in.system_name = "\\";
+	r.in.attr = &attr;
+	r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+	r.out.handle = &handle;
+
+	status = dcerpc_lsa_OpenPolicy2_r(b, tmp_ctx, &r);
+	if (!NT_STATUS_IS_OK(status)) {
+		torture_comment(tctx,
+				"OpenPolicy2 failed - %s\n",
+				nt_errstr(status));
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+	if (!NT_STATUS_IS_OK(r.out.result)) {
+		torture_comment(tctx,
+				"OpenPolicy2_ failed - %s\n",
+				nt_errstr(r.out.result));
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+
+	sids.count = 0;
+	sids.sids = NULL;
+
+	lsa_name.string = talloc_asprintf(tmp_ctx, "%s\\%s", domain, user);
+
+	l.in.handle = &handle;
+	l.in.num_names = 1;
+	l.in.names = &lsa_name;
+	l.in.sids = &sids;
+	l.in.level = 1;
+	l.in.count = &count;
+	l.out.count = &count;
+	l.out.sids = &sids;
+	l.out.domains = &domains;
+
+	status = dcerpc_lsa_LookupNames_r(b, tmp_ctx, &l);
+	if (!NT_STATUS_IS_OK(status)) {
+		torture_comment(tctx,
+				"LookupNames of %s failed - %s\n",
+				lsa_name.string,
+				nt_errstr(status));
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+
+	if (domains->count == 0) {
+		return NULL;
+	}
+
+	result = dom_sid_add_rid(mem_ctx,
+				 domains->domains[0].sid,
+				 l.out.sids->sids[0].rid);
+	c.in.handle = &handle;
+	c.out.handle = &handle;
+
+	status = dcerpc_lsa_Close_r(b, tmp_ctx, &c);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		torture_comment(tctx,
+				"dcerpc_lsa_Close failed - %s\n",
+				nt_errstr(status));
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+
+	if (!NT_STATUS_IS_OK(c.out.result)) {
+		torture_comment(tctx,
+				"dcerpc_lsa_Close failed - %s\n",
+				nt_errstr(c.out.result));
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+
+	talloc_free(tmp_ctx);
+	talloc_free(p2);
+
+	torture_comment(tctx, "Get_user_sid finished\n");
+	return result;
+}
+
+/*
+ * Create a bkrp_encrypted_secret_vX structure
+ * the version depends on the version parameter
+ * the structure is returned as a blob.
+ * The broken flag is to indicate if we want
+ * to create a non conform to specification structre
+ */
+static DATA_BLOB *create_unencryptedsecret(TALLOC_CTX *mem_ctx,
+					   bool broken,
+					   int version)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+	DATA_BLOB *blob = talloc_zero(mem_ctx, DATA_BLOB);
+	enum ndr_err_code ndr_err;
+
+	if (version == 2) {
+		struct bkrp_encrypted_secret_v2 unenc_sec;
+
+		ZERO_STRUCT(unenc_sec);
+		unenc_sec.secret_len = sizeof(secret);
+		unenc_sec.secret = discard_const_p(uint8_t, secret);
+		generate_random_buffer(unenc_sec.payload_key,
+				       sizeof(unenc_sec.payload_key));
+
+		ndr_err = ndr_push_struct_blob(blob, blob, &unenc_sec,
+				(ndr_push_flags_fn_t)ndr_push_bkrp_encrypted_secret_v2);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			return NULL;
+		}
+
+		if (broken) {
+			/* The magic value is correctly set by the NDR push
+			 * but we want to test the behavior of the server
+			 * if a differrent value is provided
+			 */
+			((uint8_t*)blob->data)[4] = 79; /* A great year !!! */
+		}
+	}
+
+	if (version == 3) {
+		struct bkrp_encrypted_secret_v3 unenc_sec;
+
+		ZERO_STRUCT(unenc_sec);
+		unenc_sec.secret_len = sizeof(secret);
+		unenc_sec.secret = discard_const_p(uint8_t, secret);
+		generate_random_buffer(unenc_sec.payload_key,
+				       sizeof(unenc_sec.payload_key));
+
+		ndr_err = ndr_push_struct_blob(blob, blob, &unenc_sec,
+					(ndr_push_flags_fn_t)ndr_push_bkrp_encrypted_secret_v3);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			return NULL;
+		}
+
+		if (broken) {
+			/*
+			 * The magic value is correctly set by the NDR push
+			 * but we want to test the behavior of the server
+			 * if a differrent value is provided
+			 */
+			((uint8_t*)blob->data)[4] = 79; /* A great year !!! */
+		}
+	}
+	talloc_free(tmp_ctx);
+	return blob;
+}
+
+/*
+ * Create an access check structure, the format depends on the version parameter.
+ * If broken is specified then we create a stucture that isn't conform to the
+ * specification.
+ *
+ * If the structure can't be created then NULL is returned.
+ */
+static DATA_BLOB *create_access_check(struct torture_context *tctx,
+				      struct dcerpc_pipe *p,
+				      TALLOC_CTX *mem_ctx,
+				      const char *user,
+				      bool broken,
+				      uint32_t version)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+	DATA_BLOB *blob = talloc_zero(mem_ctx, DATA_BLOB);
+	enum ndr_err_code ndr_err;
+	const struct dom_sid *sid = get_user_sid(tctx, tmp_ctx, user);
+
+	if (sid == NULL) {
+		return NULL;
+	}
+
+	if (version == 2) {
+		struct bkrp_access_check_v2 access_struct;
+		struct sha sctx;
+		uint8_t nonce[32];
+
+		ZERO_STRUCT(access_struct);
+		generate_random_buffer(nonce, sizeof(nonce));
+		access_struct.nonce_len = sizeof(nonce);
+		access_struct.nonce = nonce;
+		access_struct.sid = *sid;
+
+		ndr_err = ndr_push_struct_blob(blob, blob, &access_struct,
+				(ndr_push_flags_fn_t)ndr_push_bkrp_access_check_v2);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			return NULL;
+		}
+
+		/*
+		 * We pushed the whole structure including a null hash
+		 * but the hash need to be calculated only up to the hash field
+		 * so we reduce the size of what has to be calculated
+		 */
+
+		SHA1_Init(&sctx);
+		SHA1_Update(&sctx, blob->data,
+			    blob->length - sizeof(access_struct.hash));
+		SHA1_Final(blob->data + blob->length - sizeof(access_struct.hash),
+			   &sctx);
+
+		/* Altering the SHA */
+		if (broken) {
+			blob->data[blob->length - 1]++;
+		}
+	}
+
+	if (version == 3) {
+		struct bkrp_access_check_v3 access_struct;
+		struct hc_sha512state sctx;
+		uint8_t nonce[32];
+
+		ZERO_STRUCT(access_struct);
+		generate_random_buffer(nonce, sizeof(nonce));
+		access_struct.nonce_len = sizeof(nonce);
+		access_struct.nonce = nonce;
+		access_struct.sid = *sid;
+
+		ndr_err = ndr_push_struct_blob(blob, blob, &access_struct,
+				(ndr_push_flags_fn_t)ndr_push_bkrp_access_check_v3);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			return NULL;
+		}
+
+		/*We pushed the whole structure including a null hash
+		* but the hash need to be calculated only up to the hash field
+		* so we reduce the size of what has to be calculated
+		*/
+
+		SHA512_Init(&sctx);
+		SHA512_Update(&sctx, blob->data,
+			      blob->length - sizeof(access_struct.hash));
+		SHA512_Final(blob->data + blob->length - sizeof(access_struct.hash),
+			     &sctx);
+
+		/* Altering the SHA */
+		if (broken) {
+			blob->data[blob->length -1]++;
+		}
+	}
+	talloc_free(tmp_ctx);
+	return blob;
+}
+
+
+static DATA_BLOB *encrypt_blob(struct torture_context *tctx,
+				    TALLOC_CTX *mem_ctx,
+				    DATA_BLOB *key,
+				    DATA_BLOB *iv,
+				    DATA_BLOB *to_encrypt,
+				    const AlgorithmIdentifier *alg)
+{
+	hx509_crypto crypto;
+	hx509_context hctx;
+	heim_octet_string ivos;
+	heim_octet_string *encrypted;
+	DATA_BLOB *blob = talloc_zero(mem_ctx, DATA_BLOB);
+	int res;
+
+	ivos.data = talloc_array(mem_ctx, uint8_t, iv->length);
+	ivos.length = iv->length;
+	memcpy(ivos.data, iv->data, iv->length);
+
+	hx509_context_init(&hctx);
+	res = hx509_crypto_init(hctx, NULL, &alg->algorithm, &crypto);
+	if (res) {
+		torture_comment(tctx,
+				"error while doing the init of the crypto object\n");
+		hx509_context_free(&hctx);
+		return NULL;
+	}
+	res = hx509_crypto_set_key_data(crypto, key->data, key->length);
+	if (res) {
+		torture_comment(tctx,
+				"error while setting the key of the crypto object\n");
+		hx509_context_free(&hctx);
+		return NULL;
+	}
+
+	hx509_crypto_set_padding(crypto, HX509_CRYPTO_PADDING_NONE);
+	res = hx509_crypto_encrypt(crypto,
+				   to_encrypt->data,
+				   to_encrypt->length,
+				   &ivos,
+				   &encrypted);
+	if (res) {
+		torture_comment(tctx, "error while encrypting\n");
+		hx509_crypto_destroy(crypto);
+		hx509_context_free(&hctx);
+		return NULL;
+	}
+
+	*blob = data_blob_talloc(blob, encrypted->data, encrypted->length);
+	der_free_octet_string(encrypted);
+	free(encrypted);
+	hx509_crypto_destroy(crypto);
+	hx509_context_free(&hctx);
+	return blob;
+}
+
+/*
+ * Certs used for this protocol have a GUID in the issuer_uniq_id field.
+ * This function fetch it.
+ */
+static struct GUID *get_cert_guid(struct torture_context *tctx,
+				  TALLOC_CTX *mem_ctx,
+				  uint8_t *cert_data,
+				  uint32_t cert_len)
+{
+	hx509_context hctx;
+	hx509_cert cert;
+	heim_bit_string issuer_unique_id;
+	DATA_BLOB data;
+	int hret;
+	uint32_t size;
+	struct GUID *guid = talloc_zero(mem_ctx, struct GUID);
+	NTSTATUS status;
+
+	hx509_context_init(&hctx);
+
+	hret = hx509_cert_init_data(hctx, cert_data, cert_len, &cert);
+	if (hret) {
+		torture_comment(tctx, "error while loading the cert\n");
+		hx509_context_free(&hctx);
+		return NULL;
+	}
+	hret = hx509_cert_get_issuer_unique_id(hctx, cert, &issuer_unique_id);
+	if (hret) {
+		torture_comment(tctx, "error while getting the issuer_uniq_id\n");
+		hx509_cert_free(cert);
+		hx509_context_free(&hctx);
+		return NULL;
+	}
+
+	/* The issuer_unique_id is a bit string,
+	 * which means that the real size has to be divided by 8
+	 * to have the number of bytes
+	 */
+	hx509_cert_free(cert);
+	hx509_context_free(&hctx);
+	size = issuer_unique_id.length / 8;
+	data = data_blob_const(issuer_unique_id.data, size);
+
+	status = GUID_from_data_blob(&data, guid);
+	der_free_bit_string(&issuer_unique_id);
+	if (!NT_STATUS_IS_OK(status)) {
+		return NULL;
+	}
+
+	return guid;
+}
+
+/*
+ * Encrypt a blob with the private key of the certificate
+ * passed as a parameter.
+ */
+static DATA_BLOB *encrypt_blob_pk(struct torture_context *tctx,
+				  TALLOC_CTX *mem_ctx,
+				  uint8_t *cert_data,
+				  uint32_t cert_len,
+				  DATA_BLOB *to_encrypt)
+{
+	hx509_context hctx;
+	hx509_cert cert;
+	heim_octet_string secretdata;
+	heim_octet_string encrypted;
+	heim_oid encryption_oid;
+	DATA_BLOB *blob;
+	int hret;
+
+	hx509_context_init(&hctx);
+
+	hret = hx509_cert_init_data(hctx, cert_data, cert_len, &cert);
+	if (hret) {
+		torture_comment(tctx, "error while loading the cert\n");
+		hx509_context_free(&hctx);
+		return NULL;
+	}
+
+	secretdata.data = to_encrypt->data;
+	secretdata.length = to_encrypt->length;
+	hret = hx509_cert_public_encrypt(hctx, &secretdata,
+					  cert, &encryption_oid,
+					  &encrypted);
+	hx509_cert_free(cert);
+	hx509_context_free(&hctx);
+	if (hret) {
+		torture_comment(tctx, "error while encrypting\n");
+		return NULL;
+	}
+
+	blob = talloc_zero(mem_ctx, DATA_BLOB);
+	if (blob == NULL) {
+		der_free_oid(&encryption_oid);
+		der_free_octet_string(&encrypted);
+		return NULL;
+	}
+
+	*blob = data_blob_talloc(blob, encrypted.data, encrypted.length);
+	der_free_octet_string(&encrypted);
+	der_free_oid(&encryption_oid);
+	if (blob->data == NULL) {
+		return NULL;
+	}
+
+	return blob;
+}
+
+
+static struct bkrp_BackupKey *createRetrieveBackupKeyGUIDStruct(struct torture_context *tctx,
+				struct dcerpc_pipe *p, int version, DATA_BLOB *out)
+{
+	struct dcerpc_binding *binding;
+	struct bkrp_client_side_wrapped data;
+	struct GUID *g = talloc(tctx, struct GUID);
+	struct bkrp_BackupKey *r = talloc_zero(tctx, struct bkrp_BackupKey);
+	enum ndr_err_code ndr_err;
+	DATA_BLOB blob;
+	NTSTATUS status;
+
+	if (r == NULL) {
+		return NULL;
+	}
+
+	binding = dcerpc_binding_dup(tctx, p->binding);
+	if (binding == NULL) {
+		return NULL;
+	}
+
+	status = dcerpc_binding_set_flags(binding, DCERPC_SEAL|DCERPC_AUTH_SPNEGO, 0);
+	if (!NT_STATUS_IS_OK(status)) {
+		return NULL;
+	}
+
+	ZERO_STRUCT(data);
+	status = GUID_from_string(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID, g);
+	if (!NT_STATUS_IS_OK(status)) {
+		return NULL;
+	}
+
+	r->in.guidActionAgent = g;
+	data.version = version;
+	ndr_err = ndr_push_struct_blob(&blob, tctx, &data,
+			(ndr_push_flags_fn_t)ndr_push_bkrp_client_side_wrapped);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return NULL;
+	}
+	r->in.data_in = blob.data;
+	r->in.data_in_len = blob.length;
+	r->out.data_out = &out->data;
+	r->out.data_out_len = talloc(r, uint32_t);
+	return r;
+}
+
+static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tctx,
+				struct dcerpc_pipe *p, int version, DATA_BLOB *out,
+				bool norevert,
+				bool broken_version,
+				bool broken_user,
+				bool broken_magic_secret,
+				bool broken_magic_access,
+				bool broken_hash_access,
+				bool broken_cert_guid)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct bkrp_client_side_wrapped data;
+	DATA_BLOB *xs;
+	DATA_BLOB *sec;
+	DATA_BLOB *enc_sec = NULL;
+	DATA_BLOB *enc_xs = NULL;
+	DATA_BLOB *blob2;
+	DATA_BLOB enc_sec_reverted;
+	DATA_BLOB des3_key;
+	DATA_BLOB aes_key;
+	DATA_BLOB iv;
+	DATA_BLOB out_blob;
+	struct GUID *guid, *g;
+	int t;
+	uint32_t size;
+	enum ndr_err_code ndr_err;
+	NTSTATUS status;
+	const char *user;
+	struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, version, &out_blob);
+	if (r == NULL) {
+		return NULL;
+	}
+
+	if (broken_user) {
+		/* we take a fake user*/
+		user = "guest";
+	} else {
+		user = cli_credentials_get_username(cmdline_credentials);
+	}
+
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+					"Get GUID");
+	torture_assert_werr_ok(tctx, r->out.result,
+			       "Get GUID");
+
+	/*
+	 * We have to set it outside of the function createRetrieveBackupKeyGUIDStruct
+	 * the len of the blob, this is due to the fact that they don't have the
+	 * same size (one is 32bits the other 64bits)
+	 */
+	out_blob.length = *r->out.data_out_len;
+
+	sec = create_unencryptedsecret(tctx, broken_magic_secret, version);
+	if (sec == NULL) {
+		return NULL;
+	}
+
+	xs = create_access_check(tctx, p, tctx, user, broken_hash_access, version);
+	if (xs == NULL) {
+		return NULL;
+	}
+
+	if (broken_magic_access){
+		/* The start of the access_check structure contains the
+		 * GUID of the certificate
+		 */
+		xs->data[0]++;
+	}
+
+	enc_sec = encrypt_blob_pk(tctx, tctx, out_blob.data, out_blob.length, sec);
+	if (!enc_sec) {
+		return NULL;
+	}
+	enc_sec_reverted.data = talloc_array(tctx, uint8_t, enc_sec->length);
+	if (enc_sec_reverted.data == NULL) {
+		return NULL;
+	}
+	enc_sec_reverted.length = enc_sec->length;
+
+	/*
+	* We DO NOT revert the array on purpose it's in order to check that
+	* when the server is not able to decrypt then it answer the correct error
+	*/
+	if (norevert) {
+		for(t=0; t< enc_sec->length; t++) {
+			enc_sec_reverted.data[t] = ((uint8_t*)enc_sec->data)[t];
+		}
+	} else {
+		for(t=0; t< enc_sec->length; t++) {
+			enc_sec_reverted.data[t] = ((uint8_t*)enc_sec->data)[enc_sec->length - t -1];
+		}
+	}
+
+	size = sec->length;
+	if (version ==2) {
+		const AlgorithmIdentifier *alg = hx509_crypto_des_rsdi_ede3_cbc();
+		iv.data = sec->data+(size - 8);
+		iv.length = 8;
+
+		des3_key.data = sec->data+(size - 32);
+		des3_key.length = 24;
+
+		enc_xs = encrypt_blob(tctx, tctx, &des3_key, &iv, xs, alg);
+	}
+	if (version == 3) {
+		const AlgorithmIdentifier *alg = hx509_crypto_aes256_cbc();
+		iv.data = sec->data+(size-16);
+		iv.length = 16;
+
+		aes_key.data = sec->data+(size-48);
+		aes_key.length = 32;
+
+		enc_xs = encrypt_blob(tctx, tctx, &aes_key, &iv, xs, alg);
+	}
+
+	if (!enc_xs) {
+		return NULL;
+	}
+
+	/* To cope with the fact that heimdal do padding at the end for the moment */
+	enc_xs->length = xs->length;
+
+	guid = get_cert_guid(tctx, tctx, out_blob.data, out_blob.length);
+	if (guid == NULL) {
+		return NULL;
+	}
+
+	if (broken_version) {
+		data.version = 1;
+	} else {
+		data.version = version;
+	}
+
+	data.guid = *guid;
+	data.encrypted_secret = enc_sec_reverted.data;
+	data.access_check = enc_xs->data;
+	data.encrypted_secret_len = enc_sec->length;
+	data.access_check_len = enc_xs->length;
+
+	/* We want the blob to persist after this function so we don't
+	 * allocate it in the stack
+	 */
+	blob2 = talloc(tctx, DATA_BLOB);
+	if (blob2 == NULL) {
+		return NULL;
+	}
+
+	ndr_err = ndr_push_struct_blob(blob2, tctx, &data,
+			(ndr_push_flags_fn_t)ndr_push_bkrp_client_side_wrapped);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return NULL;
+	}
+
+	if (broken_cert_guid) {
+		blob2->data[12]++;
+	}
+
+	ZERO_STRUCT(*r);
+
+	g = talloc(tctx, struct GUID);
+	if (g == NULL) {
+		return NULL;
+	}
+
+	status = GUID_from_string(BACKUPKEY_RESTORE_GUID, g);
+	if (!NT_STATUS_IS_OK(status)) {
+		return NULL;
+	}
+
+	r->in.guidActionAgent = g;
+	r->in.data_in = blob2->data;
+	r->in.data_in_len = blob2->length;
+	r->in.param = 0;
+	r->out.data_out = &(out->data);
+	r->out.data_out_len = talloc(r, uint32_t);
+	return r;
+}
+
+/* Check that we are able to receive the certificate of the DCs
+ * used for client wrap version of the backup key protocol
+ */
+static bool test_RetrieveBackupKeyGUID(struct torture_context *tctx,
+					struct dcerpc_pipe *p)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	if (r == NULL) {
+		return false;
+	}
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		torture_assert_ntstatus_ok(tctx,
+				dcerpc_bkrp_BackupKey_r(b, tctx, r),
+				"Get GUID");
+
+		out_blob.length = *r->out.data_out_len;
+		torture_assert_werr_equal(tctx,
+						r->out.result,
+						WERR_OK,
+						"Wrong dce/rpc error code");
+	} else {
+		torture_assert_ntstatus_equal(tctx,
+						dcerpc_bkrp_BackupKey_r(b, tctx, r),
+						NT_STATUS_ACCESS_DENIED,
+						"Get GUID");
+	}
+	return true;
+}
+
+/* Test to check the failure to recover a secret because the
+ * secret blob is not reversed
+ */
+static bool test_RestoreGUID_ko(struct torture_context *tctx,
+				struct dcerpc_pipe *p)
+{
+	enum ndr_err_code ndr_err;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_client_side_unwrapped resp;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+					true, false, false, false, false, false, false);
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAM, "Wrong error code");
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+static bool test_RestoreGUID_wrongversion(struct torture_context *tctx,
+					  struct dcerpc_pipe *p)
+{
+	enum ndr_err_code ndr_err;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_client_side_unwrapped resp;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+					false, true, false, false, false, false, false);
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAM, "Wrong error code on wrong version");
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+static bool test_RestoreGUID_wronguser(struct torture_context *tctx,
+				       struct dcerpc_pipe *p)
+{
+	enum ndr_err_code ndr_err;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_client_side_unwrapped resp;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+					false, false, true, false, false, false, false);
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_ACCESS, "Restore GUID");
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+static bool test_RestoreGUID_v3(struct torture_context *tctx,
+				struct dcerpc_pipe *p)
+{
+	enum ndr_err_code ndr_err;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_client_side_unwrapped resp;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob,
+					false, false, false, false, false, false, false);
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 1, "Unable to unmarshall bkrp_client_side_unwrapped");
+		torture_assert_werr_equal(tctx, r->out.result, WERR_OK, "Restore GUID");
+		torture_assert_str_equal(tctx, (char*)resp.secret.data, secret, "Wrong secret");
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+static bool test_RestoreGUID(struct torture_context *tctx,
+			     struct dcerpc_pipe *p)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_client_side_unwrapped resp;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+					false, false, false, false, false, false, false);
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		torture_assert_werr_equal(tctx, r->out.result, WERR_OK, "Restore GUID");
+		torture_assert_ndr_err_equal(tctx,
+					     ndr_pull_struct_blob(&out_blob, tctx, &resp,
+								(ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped),
+					     NDR_ERR_SUCCESS,
+					     "Unable to unmarshall bkrp_client_side_unwrapped");
+		torture_assert_str_equal(tctx, (char*)resp.secret.data, secret, "Wrong secret");
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+static bool test_RestoreGUID_badmagiconsecret(struct torture_context *tctx,
+					      struct dcerpc_pipe *p)
+{
+	enum ndr_err_code ndr_err;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_client_side_unwrapped resp;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob,
+					false, false, false, true, false, false, false);
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Wrong error code while providing bad magic in secret");
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+static bool test_RestoreGUID_emptyrequest(struct torture_context *tctx,
+					  struct dcerpc_pipe *p)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob,
+					false, false, false, true, false, false, true);
+
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+		r->in.data_in = talloc(tctx, uint8_t);
+		r->in.data_in_len = 0;
+		r->in.param = 0;
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAM, "Bad error code on wrong has in access check");
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+static bool test_RestoreGUID_badcertguid(struct torture_context *tctx,
+					 struct dcerpc_pipe *p)
+{
+	enum ndr_err_code ndr_err;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_client_side_unwrapped resp;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob,
+					false, false, false, false, false, false, true);
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct() failed");
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+
+		/*
+		 * Windows 2012R2 has, presumably, a programming error
+		 * returning an NTSTATUS code on this interface
+		 */
+		if (W_ERROR_V(r->out.result) != NT_STATUS_V(NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+			torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check");
+		}
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+static bool test_RestoreGUID_badmagicaccesscheck(struct torture_context *tctx,
+						 struct dcerpc_pipe *p)
+{
+	enum ndr_err_code ndr_err;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_client_side_unwrapped resp;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+					false, false, false, false, true, false, false);
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check");
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+static bool test_RestoreGUID_badhashaccesscheck(struct torture_context *tctx,
+						struct dcerpc_pipe *p)
+{
+	enum ndr_err_code ndr_err;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_client_side_unwrapped resp;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+					false, false, false, false, false, true, false);
+		torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+		torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+		out_blob.length = *r->out.data_out_len;
+		ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+		torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+		torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check");
+	} else {
+		struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+		torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+			NT_STATUS_ACCESS_DENIED, "Get GUID");
+	}
+	return true;
+}
+
+/*
+ * Check that the RSA modulus in the certificate of the DCs has 2048 bits.
+ */
+static bool test_RetrieveBackupKeyGUID_2048bits(struct torture_context *tctx,
+					struct dcerpc_pipe *p)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	DATA_BLOB out_blob;
+	struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+
+	hx509_context hctx;
+	int hret;
+	hx509_cert cert;
+	SubjectPublicKeyInfo spki;
+	RSA *rsa;
+	int RSA_returned_bits;
+
+	torture_assert(tctx, r != NULL, "createRetrieveBackupKeyGUIDStruct failed");
+
+	hx509_context_init(&hctx);
+
+	if (r == NULL) {
+		return false;
+	}
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		const unsigned char *spki_spk_data;
+		torture_assert_ntstatus_ok(tctx,
+				dcerpc_bkrp_BackupKey_r(b, tctx, r),
+				"Get GUID");
+
+		torture_assert_werr_ok(tctx, r->out.result,
+				       "Get GUID");
+
+		out_blob.length = *r->out.data_out_len;
+
+		hret = hx509_cert_init_data(hctx, out_blob.data, out_blob.length, &cert);
+		torture_assert_int_equal(tctx, hret, 0, "hx509_cert_init_data failed");
+
+		hret = hx509_cert_get_SPKI(hctx, cert , &spki);
+		torture_assert_int_equal(tctx, hret, 0, "hx509_cert_get_SPKI failed");
+
+		/* We must take a copy, as d2i_RSAPublicKey *changes* the input parameter */
+		spki_spk_data = spki.subjectPublicKey.data;
+		rsa = d2i_RSAPublicKey(NULL, &spki_spk_data, spki.subjectPublicKey.length / 8);
+		torture_assert_int_equal(tctx, rsa != NULL, 1, "d2i_RSAPublicKey failed");
+
+		RSA_returned_bits = BN_num_bits(rsa->n);
+		torture_assert_int_equal(tctx,
+						RSA_returned_bits,
+						2048,
+						"RSA Key doesn't have 2048 bits");
+
+		RSA_free(rsa);
+
+		/*
+		 * Because we prevented spki from being changed above,
+		 * we can now safely call this to free it
+		 */
+		free_SubjectPublicKeyInfo(&spki);
+		hx509_cert_free(cert);
+		hx509_context_free(&hctx);
+
+	} else {
+		torture_assert_ntstatus_equal(tctx,
+						dcerpc_bkrp_BackupKey_r(b, tctx, r),
+						NT_STATUS_ACCESS_DENIED,
+						"Get GUID");
+	}
+	return true;
+}
+
+static bool test_ServerWrap_encrypt_decrypt(struct torture_context *tctx,
+					    struct dcerpc_pipe *p)
+{
+	struct bkrp_BackupKey r;
+	struct GUID guid;
+	DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret));
+	DATA_BLOB encrypted;
+	uint32_t enclen;
+	DATA_BLOB decrypted;
+	uint32_t declen;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+	ZERO_STRUCT(r);
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	/* Encrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_BACKUP_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = plaintext.data;
+	r.in.data_in_len = plaintext.length;
+	r.in.param = 0;
+	r.out.data_out = &encrypted.data;
+	r.out.data_out_len = &enclen;
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		torture_assert_ntstatus_ok(tctx,
+					   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					   "encrypt");
+	} else {
+		torture_assert_ntstatus_equal(tctx,
+					      dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					      NT_STATUS_ACCESS_DENIED,
+					      "encrypt");
+		return true;
+	}
+	torture_assert_werr_ok(tctx,
+			       r.out.result,
+			       "encrypt");
+	encrypted.length = *r.out.data_out_len;
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = encrypted.data;
+	r.in.data_in_len = encrypted.length;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+	torture_assert_werr_ok(tctx,
+			       r.out.result,
+			       "decrypt");
+	decrypted.length = *r.out.data_out_len;
+
+	/* Compare */
+	torture_assert_data_blob_equal(tctx, plaintext, decrypted, "Decrypt failed");
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = encrypted.data;
+	r.in.data_in_len = encrypted.length;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+	torture_assert_werr_ok(tctx,
+			       r.out.result,
+			       "decrypt");
+	decrypted.length = *r.out.data_out_len;
+
+	/* Compare */
+	torture_assert_data_blob_equal(tctx, plaintext, decrypted, "Decrypt failed");
+	return true;
+}
+
+static bool test_ServerWrap_decrypt_wrong_keyGUID(struct torture_context *tctx,
+						  struct dcerpc_pipe *p)
+{
+	struct bkrp_BackupKey r;
+	struct GUID guid;
+	DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret));
+	DATA_BLOB encrypted;
+	uint32_t enclen;
+	DATA_BLOB decrypted;
+	uint32_t declen;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	enum ndr_err_code ndr_err;
+	struct bkrp_server_side_wrapped server_side_wrapped;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+	ZERO_STRUCT(r);
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	/* Encrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_BACKUP_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = plaintext.data;
+	r.in.data_in_len = plaintext.length;
+	r.in.param = 0;
+	r.out.data_out = &encrypted.data;
+	r.out.data_out_len = &enclen;
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		torture_assert_ntstatus_ok(tctx,
+					   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					   "encrypt");
+	} else {
+		torture_assert_ntstatus_equal(tctx,
+					      dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					      NT_STATUS_ACCESS_DENIED,
+					      "encrypt");
+		return true;
+	}
+	torture_assert_werr_ok(tctx,
+			       r.out.result,
+			       "encrypt");
+	encrypted.length = *r.out.data_out_len;
+
+	ndr_err = ndr_pull_struct_blob(&encrypted, tctx, &server_side_wrapped,
+				       (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped);
+	torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "pull of server_side_wrapped");
+
+	/* Change the GUID */
+	server_side_wrapped.guid = GUID_random();
+
+	ndr_err = ndr_push_struct_blob(&encrypted, tctx, &server_side_wrapped,
+				       (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped);
+	torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "push of server_side_wrapped");
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = encrypted.data;
+	r.in.data_in_len = encrypted.length;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+	torture_assert_werr_equal(tctx,
+				  r.out.result,
+				  WERR_INVALID_DATA,
+				  "decrypt should fail with WERR_INVALID_DATA");
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = encrypted.data;
+	r.in.data_in_len = encrypted.length;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+	torture_assert_werr_equal(tctx,
+				  r.out.result,
+				  WERR_INVALID_DATA,
+				  "decrypt should fail with WERR_INVALID_DATA");
+
+	return true;
+}
+
+static bool test_ServerWrap_decrypt_empty_request(struct torture_context *tctx,
+						 struct dcerpc_pipe *p)
+{
+	struct bkrp_BackupKey r;
+	struct GUID guid;
+	DATA_BLOB decrypted;
+	uint32_t declen;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	uint8_t short_request[4] = { 1, 0, 0, 0 };
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+	ZERO_STRUCT(r);
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = short_request;
+	r.in.data_in_len = 0;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		torture_assert_ntstatus_ok(tctx,
+					   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					   "encrypt");
+	} else {
+		torture_assert_ntstatus_equal(tctx,
+					      dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					      NT_STATUS_ACCESS_DENIED,
+					      "encrypt");
+		return true;
+	}
+	torture_assert_werr_equal(tctx,
+				  r.out.result,
+				  WERR_INVALID_PARAM,
+				  "decrypt should fail with WERR_INVALID_PARAM");
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = short_request;
+	r.in.data_in_len = 0;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+	torture_assert_werr_equal(tctx,
+				  r.out.result,
+				  WERR_INVALID_PARAM,
+				  "decrypt should fail with WERR_INVALID_PARAM");
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = NULL;
+	r.in.data_in_len = 0;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_equal(tctx,
+				      dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				      NT_STATUS_INVALID_PARAMETER_MIX,
+				      "decrypt");
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = NULL;
+	r.in.data_in_len = 0;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_equal(tctx,
+				      dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				      NT_STATUS_INVALID_PARAMETER_MIX,
+				      "decrypt");
+
+	return true;
+}
+
+
+static bool test_ServerWrap_decrypt_short_request(struct torture_context *tctx,
+						 struct dcerpc_pipe *p)
+{
+	struct bkrp_BackupKey r;
+	struct GUID guid;
+	DATA_BLOB decrypted;
+	uint32_t declen;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	uint8_t short_request[4] = { 1, 0, 0, 0 };
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+	ZERO_STRUCT(r);
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = short_request;
+	r.in.data_in_len = 4;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		torture_assert_ntstatus_ok(tctx,
+					   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					   "encrypt");
+	} else {
+		torture_assert_ntstatus_equal(tctx,
+					      dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					      NT_STATUS_ACCESS_DENIED,
+					      "encrypt");
+		return true;
+	}
+	torture_assert_werr_equal(tctx,
+				  r.out.result,
+				  WERR_INVALID_PARAM,
+				  "decrypt should fail with WERR_INVALID_PARM");
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = short_request;
+	r.in.data_in_len = 4;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+	torture_assert_werr_equal(tctx,
+				  r.out.result,
+				  WERR_INVALID_PARAM,
+				  "decrypt should fail with WERR_INVALID_PARAM");
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = short_request;
+	r.in.data_in_len = 1;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+	torture_assert_werr_equal(tctx,
+				  r.out.result,
+				  WERR_INVALID_PARAM,
+				  "decrypt should fail with WERR_INVALID_PARAM");
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = short_request;
+	r.in.data_in_len = 1;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+	torture_assert_werr_equal(tctx,
+				  r.out.result,
+				  WERR_INVALID_PARAM,
+				  "decrypt should fail with WERR_INVALID_PARAM");
+
+	return true;
+}
+
+static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
+						   struct bkrp_server_side_wrapped *server_side_wrapped,
+						   enum test_wrong wrong)
+{
+        struct dcerpc_pipe *lsa_p;
+	struct dcerpc_binding_handle *lsa_b;
+	struct lsa_OpenSecret r_secret;
+	struct lsa_QuerySecret r_query_secret;
+	struct policy_handle *handle, sec_handle;
+	struct bkrp_BackupKey r;
+	struct GUID preferred_key_guid;
+	DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret));
+	DATA_BLOB preferred_key, preferred_key_clear, session_key,
+		decrypt_key, decrypt_key_clear, encrypted_blob, symkey_blob,
+		sid_blob;
+	struct bkrp_dc_serverwrap_key server_key;
+	struct lsa_DATA_BUF_PTR bufp1;
+	char *key_guid_string;
+	struct bkrp_rc4encryptedpayload rc4payload;
+	struct dom_sid *caller_sid;
+	uint8_t symkey[20]; /* SHA-1 hash len */
+	uint8_t mackey[20]; /* SHA-1 hash len */
+	uint8_t mac[20]; /* SHA-1 hash len */
+	unsigned int hash_len;
+	HMAC_CTX ctx;
+	ZERO_STRUCT(r);
+	ZERO_STRUCT(r_secret);
+	ZERO_STRUCT(r_query_secret);
+
+	/* Now read BCKUPKEY_P and prove we can do a matching decrypt and encrypt */
+
+	torture_assert_ntstatus_ok(tctx,
+				   torture_rpc_connection(tctx, &lsa_p, &ndr_table_lsarpc),
+				   "Opening LSA pipe");
+	lsa_b = lsa_p->binding_handle;
+
+	torture_assert(tctx, test_lsa_OpenPolicy2(lsa_b, tctx, &handle), "OpenPolicy failed");
+	r_secret.in.name.string = "G$BCKUPKEY_P";
+
+	r_secret.in.handle = handle;
+	r_secret.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+	r_secret.out.sec_handle = &sec_handle;
+
+	torture_comment(tctx, "Testing OpenSecret\n");
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(lsa_b, tctx, &r_secret),
+				   "OpenSecret failed");
+	torture_assert_ntstatus_ok(tctx, r_secret.out.result,
+				   "OpenSecret failed");
+
+	r_query_secret.in.sec_handle = &sec_handle;
+	r_query_secret.in.new_val = &bufp1;
+	bufp1.buf = NULL;
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(lsa_b, tctx, &r_query_secret),
+		"QuerySecret failed");
+	torture_assert_ntstatus_ok(tctx, r_query_secret.out.result,
+				   "QuerySecret failed");
+
+
+	preferred_key.data = r_query_secret.out.new_val->buf->data;
+	preferred_key.length = r_query_secret.out.new_val->buf->size;
+	torture_assert_ntstatus_ok(tctx, dcerpc_fetch_session_key(lsa_p, &session_key),
+				   "dcerpc_fetch_session_key failed");
+
+	torture_assert_ntstatus_ok(tctx,
+				   sess_decrypt_blob(tctx,
+						     &preferred_key, &session_key, &preferred_key_clear),
+				   "sess_decrypt_blob failed");
+
+	torture_assert_ntstatus_ok(tctx, GUID_from_ndr_blob(&preferred_key_clear, &preferred_key_guid),
+				   "GUID parse failed");
+
+	torture_assert_guid_equal(tctx, server_side_wrapped->guid,
+				  preferred_key_guid,
+				  "GUID didn't match value pointed at by G$BCKUPKEY_P");
+
+	/* And read BCKUPKEY_<guid> and get the actual key */
+
+	key_guid_string = GUID_string(tctx, &server_side_wrapped->guid);
+	r_secret.in.name.string = talloc_asprintf(tctx, "G$BCKUPKEY_%s", key_guid_string);
+
+	r_secret.in.handle = handle;
+	r_secret.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+	r_secret.out.sec_handle = &sec_handle;
+
+	torture_comment(tctx, "Testing OpenSecret\n");
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(lsa_b, tctx, &r_secret),
+				   "OpenSecret failed");
+	torture_assert_ntstatus_ok(tctx, r_secret.out.result,
+				   "OpenSecret failed");
+
+	r_query_secret.in.sec_handle = &sec_handle;
+	r_query_secret.in.new_val = &bufp1;
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(lsa_b, tctx, &r_query_secret),
+				   "QuerySecret failed");
+	torture_assert_ntstatus_ok(tctx, r_query_secret.out.result,
+				   "QuerySecret failed");
+
+
+	decrypt_key.data = r_query_secret.out.new_val->buf->data;
+	decrypt_key.length = r_query_secret.out.new_val->buf->size;
+
+	torture_assert_ntstatus_ok(tctx,
+				   sess_decrypt_blob(tctx,
+						     &decrypt_key, &session_key, &decrypt_key_clear),
+				   "sess_decrypt_blob failed");
+
+	torture_assert_ndr_err_equal(tctx, ndr_pull_struct_blob(&decrypt_key_clear, tctx, &server_key,
+								(ndr_pull_flags_fn_t)ndr_pull_bkrp_dc_serverwrap_key),
+				     NDR_ERR_SUCCESS, "Failed to parse server_key");
+
+	torture_assert_int_equal(tctx, server_key.magic, 1, "Failed to correctly decrypt server key");
+
+	/*
+	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
+	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
+	 */
+	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
+	     server_side_wrapped->r2, sizeof(server_side_wrapped->r2),
+	     symkey, &hash_len);
+
+	/* rc4 decrypt sid and secret using sym key */
+	symkey_blob = data_blob_const(symkey, sizeof(symkey));
+
+	encrypted_blob = data_blob_talloc(tctx, server_side_wrapped->rc4encryptedpayload,
+					  server_side_wrapped->ciphertext_length);
+
+	arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob);
+
+	torture_assert_ndr_err_equal(tctx, ndr_pull_struct_blob(&encrypted_blob, tctx, &rc4payload,
+				       (ndr_pull_flags_fn_t)ndr_pull_bkrp_rc4encryptedpayload),
+				     NDR_ERR_SUCCESS, "Failed to parse rc4encryptedpayload");
+
+	torture_assert_int_equal(tctx, rc4payload.secret_data.length,
+				 server_side_wrapped->payload_length,
+				 "length of decrypted payload not the length declared in surrounding structure");
+
+	/*
+	 * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
+	 * BACKUPKEY_BACKUP_GUID, it really is the whole key
+	 */
+	HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key),
+	     rc4payload.r3, sizeof(rc4payload.r3),
+	     mackey, &hash_len);
+
+	torture_assert_ndr_err_equal(tctx, ndr_push_struct_blob(&sid_blob, tctx, &rc4payload.sid,
+								(ndr_push_flags_fn_t)ndr_push_dom_sid),
+				     NDR_ERR_SUCCESS, "unable to push SID");
+
+	HMAC_CTX_init(&ctx);
+	HMAC_Init_ex(&ctx, mackey, hash_len, EVP_sha1(), NULL);
+	/* SID field */
+	HMAC_Update(&ctx, sid_blob.data, sid_blob.length);
+	/* Secret field */
+	HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length);
+	HMAC_Final(&ctx, mac, &hash_len);
+	HMAC_CTX_cleanup(&ctx);
+
+	torture_assert_mem_equal(tctx, mac, rc4payload.mac, sizeof(mac), "mac not correct");
+	torture_assert_int_equal(tctx, rc4payload.secret_data.length,
+				 plaintext.length, "decrypted data is not correct length");
+	torture_assert_mem_equal(tctx, rc4payload.secret_data.data,
+				 plaintext.data, plaintext.length,
+				 "decrypted data is not correct");
+
+	/* Not strictly correct all the time, but good enough for this test */
+	caller_sid = get_user_sid(tctx, tctx, cli_credentials_get_username(cmdline_credentials));
+
+	torture_assert_sid_equal(tctx, &rc4payload.sid, caller_sid, "Secret saved with wrong SID");
+
+
+	/* RE-encrypt */
+
+	if (wrong == WRONG_SID) {
+		rc4payload.sid.sub_auths[rc4payload.sid.num_auths - 1] = DOMAIN_RID_KRBTGT;
+	}
+
+	dump_data_pw("mackey: \n", mackey, sizeof(mackey));
+
+	torture_assert_ndr_err_equal(tctx,
+				     ndr_push_struct_blob(&sid_blob, tctx, &rc4payload.sid,
+							  (ndr_push_flags_fn_t)ndr_push_dom_sid),
+				     NDR_ERR_SUCCESS,
+				     "push of sid failed");
+
+	HMAC_CTX_init(&ctx);
+	HMAC_Init_ex(&ctx, mackey, 20, EVP_sha1(), NULL);
+	/* SID field */
+	HMAC_Update(&ctx, sid_blob.data, sid_blob.length);
+	/* Secret field */
+	HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length);
+	HMAC_Final(&ctx, rc4payload.mac, &hash_len);
+	HMAC_CTX_cleanup(&ctx);
+
+	dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac));
+
+	torture_assert_ndr_err_equal(tctx,
+				     ndr_push_struct_blob(&encrypted_blob, tctx, &rc4payload,
+							  (ndr_push_flags_fn_t)ndr_push_bkrp_rc4encryptedpayload),
+				     NDR_ERR_SUCCESS,
+				     "push of rc4payload failed");
+
+	if (wrong == WRONG_KEY) {
+		symkey_blob.data[0] = 78;
+		symkey_blob.data[1] = 78;
+		symkey_blob.data[2] = 78;
+	}
+
+	/* rc4 encrypt sid and secret using sym key */
+	arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob);
+
+	/* re-create server wrap structure */
+
+	torture_assert_int_equal(tctx, encrypted_blob.length,
+				 server_side_wrapped->ciphertext_length,
+				 "expected encrypted length not to change");
+	if (wrong == RIGHT_KEY) {
+		torture_assert_mem_equal(tctx, server_side_wrapped->rc4encryptedpayload,
+					 encrypted_blob.data,
+					 encrypted_blob.length,
+					 "expected encrypted data not to change");
+	}
+
+	server_side_wrapped->payload_length = rc4payload.secret_data.length;
+	server_side_wrapped->ciphertext_length = encrypted_blob.length;
+	server_side_wrapped->rc4encryptedpayload = encrypted_blob.data;
+
+	return true;
+}
+
+
+static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx,
+						struct dcerpc_pipe *p,
+						enum test_wrong wrong)
+{
+	struct bkrp_BackupKey r;
+	struct GUID guid;
+	DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret));
+	DATA_BLOB encrypted;
+	uint32_t enclen;
+	DATA_BLOB decrypted;
+	uint32_t declen;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	enum ndr_err_code ndr_err;
+	struct bkrp_server_side_wrapped server_side_wrapped;
+	bool repush = false;
+	enum dcerpc_AuthType auth_type;
+	enum dcerpc_AuthLevel auth_level;
+	ZERO_STRUCT(r);
+
+	dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+	/* Encrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_BACKUP_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = plaintext.data;
+	r.in.data_in_len = plaintext.length;
+	r.in.param = 0;
+	r.out.data_out = &encrypted.data;
+	r.out.data_out_len = &enclen;
+	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		torture_assert_ntstatus_ok(tctx,
+					   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					   "encrypt");
+	} else {
+		torture_assert_ntstatus_equal(tctx,
+					      dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+					      NT_STATUS_ACCESS_DENIED,
+					      "encrypt");
+		return true;
+	}
+	torture_assert_werr_ok(tctx,
+			       r.out.result,
+			       "encrypt");
+	encrypted.length = *r.out.data_out_len;
+
+	ndr_err = ndr_pull_struct_blob(&encrypted, tctx, &server_side_wrapped,
+				       (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped);
+	torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "pull of server_side_wrapped");
+
+	torture_assert_int_equal(tctx, server_side_wrapped.payload_length, plaintext.length,
+				 "wrong payload length");
+
+	switch (wrong) {
+	case WRONG_MAGIC:
+		/* Change the magic.  Forced by our NDR layer, so do it raw */
+		SIVAL(encrypted.data, 0, 78);  /* valid values are 1-3 */
+		break;
+	case WRONG_R2:
+		server_side_wrapped.r2[0] = 78;
+		server_side_wrapped.r2[1] = 78;
+		server_side_wrapped.r2[3] = 78;
+		repush = true;
+		break;
+	case WRONG_PAYLOAD_LENGTH:
+		server_side_wrapped.payload_length = UINT32_MAX - 8;
+		repush = true;
+		break;
+	case WRONG_CIPHERTEXT_LENGTH:
+		/*
+		 * Change the ciphertext len.  We can't push this if
+		 * we have it wrong, so do it raw
+		 */
+		SIVAL(encrypted.data, 8, UINT32_MAX - 8);  /* valid values are 1-3 */
+		break;
+	case SHORT_PAYLOAD_LENGTH:
+		server_side_wrapped.payload_length = server_side_wrapped.payload_length - 8;
+		repush = true;
+		break;
+	case SHORT_CIPHERTEXT_LENGTH:
+		/*
+		 * Change the ciphertext len.  We can't push this if
+		 * we have it wrong, so do it raw
+		 */
+		SIVAL(encrypted.data, 8, server_side_wrapped.ciphertext_length - 8);  /* valid values are 1-3 */
+		break;
+	case ZERO_PAYLOAD_LENGTH:
+		server_side_wrapped.payload_length = 0;
+		repush = true;
+		break;
+	case ZERO_CIPHERTEXT_LENGTH:
+		/*
+		 * Change the ciphertext len.  We can't push this if
+		 * we have it wrong, so do it raw
+		 */
+		SIVAL(encrypted.data, 8, 0);  /* valid values are 1-3 */
+		break;
+
+	case RIGHT_KEY:
+	case WRONG_KEY:
+	case WRONG_SID:
+		torture_assert(tctx,
+			       test_ServerWrap_encrypt_decrypt_manual(tctx, &server_side_wrapped, wrong),
+			       "test_ServerWrap_encrypt_decrypt_manual failed");
+		repush = true;
+		break;
+	}
+
+	if (repush) {
+		ndr_err = ndr_push_struct_blob(&encrypted, tctx, &server_side_wrapped,
+					       (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped);
+		torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "push of server_side_wrapped");
+	}
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = encrypted.data;
+	r.in.data_in_len = encrypted.length;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+
+	if ((wrong == WRONG_R2 || wrong == WRONG_KEY)
+	    && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) {
+		torture_assert_werr_equal(tctx,
+					  r.out.result,
+					  WERR_INVALID_SID,
+					  "decrypt should fail with WERR_INVALID_SID or WERR_INVALID_PARAM");
+	} else if (wrong == RIGHT_KEY) {
+		torture_assert_werr_equal(tctx,
+					  r.out.result,
+					  WERR_OK,
+					  "decrypt should succeed!");
+	} else if (wrong == WRONG_SID) {
+		torture_assert_werr_equal(tctx,
+					  r.out.result,
+					  WERR_INVALID_ACCESS,
+					  "decrypt should fail with WERR_INVALID_ACCESS");
+	} else {
+		torture_assert_werr_equal(tctx,
+					  r.out.result,
+					  WERR_INVALID_PARAM,
+					  "decrypt should fail with WERR_INVALID_PARAM");
+	}
+
+	/* Decrypt */
+	torture_assert_ntstatus_ok(tctx,
+				   GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+				   "obtain GUID");
+
+	r.in.guidActionAgent = &guid;
+	r.in.data_in = encrypted.data;
+	r.in.data_in_len = encrypted.length;
+	r.in.param = 0;
+	r.out.data_out = &(decrypted.data);
+	r.out.data_out_len = &declen;
+	torture_assert_ntstatus_ok(tctx,
+				   dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+				   "decrypt");
+
+	if ((wrong == WRONG_R2 || wrong == WRONG_KEY)
+	    && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) {
+		torture_assert_werr_equal(tctx,
+					  r.out.result,
+					  WERR_INVALID_SID,
+					  "decrypt should fail with WERR_INVALID_SID or WERR_INVALID_PARAM");
+	} else if (wrong == RIGHT_KEY) {
+		torture_assert_werr_equal(tctx,
+					  r.out.result,
+					  WERR_OK,
+					  "decrypt should succeed!");
+	} else if (wrong == WRONG_SID) {
+		torture_assert_werr_equal(tctx,
+					  r.out.result,
+					  WERR_INVALID_ACCESS,
+					  "decrypt should fail with WERR_INVALID_ACCESS");
+	} else {
+		torture_assert_werr_equal(tctx,
+					  r.out.result,
+					  WERR_INVALID_PARAM,
+					  "decrypt should fail with WERR_INVALID_PARAM");
+	}
+
+	return true;
+}
+
+static bool test_ServerWrap_decrypt_wrong_magic(struct torture_context *tctx,
+						struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_MAGIC);
+}
+
+static bool test_ServerWrap_decrypt_wrong_r2(struct torture_context *tctx,
+						struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_R2);
+}
+
+static bool test_ServerWrap_decrypt_wrong_payload_length(struct torture_context *tctx,
+							 struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_PAYLOAD_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_short_payload_length(struct torture_context *tctx,
+							 struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, SHORT_PAYLOAD_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_zero_payload_length(struct torture_context *tctx,
+							 struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, ZERO_PAYLOAD_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_wrong_ciphertext_length(struct torture_context *tctx,
+							 struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_CIPHERTEXT_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_short_ciphertext_length(struct torture_context *tctx,
+							 struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, SHORT_CIPHERTEXT_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_zero_ciphertext_length(struct torture_context *tctx,
+							   struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, ZERO_CIPHERTEXT_LENGTH);
+}
+
+static bool test_ServerWrap_encrypt_decrypt_remote_key(struct torture_context *tctx,
+						       struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, RIGHT_KEY);
+}
+
+static bool test_ServerWrap_encrypt_decrypt_wrong_key(struct torture_context *tctx,
+						       struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_KEY);
+}
+
+static bool test_ServerWrap_encrypt_decrypt_wrong_sid(struct torture_context *tctx,
+						      struct dcerpc_pipe *p)
+{
+	return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_SID);
+}
+
+struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx)
+{
+	struct torture_suite *suite = torture_suite_create(mem_ctx, "backupkey");
+
+	struct torture_rpc_tcase *tcase;
+
+	tcase = torture_suite_add_rpc_iface_tcase(suite, "backupkey",
+						  &ndr_table_backupkey);
+
+	torture_rpc_tcase_add_test(tcase, "retreive_backup_key_guid",
+				   test_RetrieveBackupKeyGUID);
+
+	torture_rpc_tcase_add_test(tcase, "restore_guid",
+				   test_RestoreGUID);
+
+	torture_rpc_tcase_add_test(tcase, "restore_guid version 3",
+				   test_RestoreGUID_v3);
+
+/* We double the test in order to be sure that we don't mess stuff (ie. freeing static stuff) */
+
+	torture_rpc_tcase_add_test(tcase, "restore_guid_2nd",
+				   test_RestoreGUID);
+
+	torture_rpc_tcase_add_test(tcase, "unable_to_decrypt_secret",
+				   test_RestoreGUID_ko);
+
+	torture_rpc_tcase_add_test(tcase, "wrong_user_restore_guid",
+				   test_RestoreGUID_wronguser);
+
+	torture_rpc_tcase_add_test(tcase, "wrong_version_restore_guid",
+				   test_RestoreGUID_wrongversion);
+
+	torture_rpc_tcase_add_test(tcase, "bad_magic_on_secret_restore_guid",
+				   test_RestoreGUID_badmagiconsecret);
+
+	torture_rpc_tcase_add_test(tcase, "bad_hash_on_secret_restore_guid",
+				   test_RestoreGUID_badhashaccesscheck);
+
+	torture_rpc_tcase_add_test(tcase, "bad_magic_on_accesscheck_restore_guid",
+				   test_RestoreGUID_badmagicaccesscheck);
+
+	torture_rpc_tcase_add_test(tcase, "bad_cert_guid_restore_guid",
+				   test_RestoreGUID_badcertguid);
+
+	torture_rpc_tcase_add_test(tcase, "empty_request_restore_guid",
+				   test_RestoreGUID_emptyrequest);
+
+	torture_rpc_tcase_add_test(tcase, "retreive_backup_key_guid_2048_bits",
+				   test_RetrieveBackupKeyGUID_2048bits);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt",
+				   test_ServerWrap_encrypt_decrypt);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_keyGUID",
+				   test_ServerWrap_decrypt_wrong_keyGUID);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_empty_request",
+				   test_ServerWrap_decrypt_empty_request);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_short_request",
+				   test_ServerWrap_decrypt_short_request);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_magic",
+				   test_ServerWrap_decrypt_wrong_magic);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_r2",
+				   test_ServerWrap_decrypt_wrong_r2);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_payload_length",
+				   test_ServerWrap_decrypt_wrong_payload_length);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_short_payload_length",
+				   test_ServerWrap_decrypt_short_payload_length);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_zero_payload_length",
+				   test_ServerWrap_decrypt_zero_payload_length);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_ciphertext_length",
+				   test_ServerWrap_decrypt_wrong_ciphertext_length);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_short_ciphertext_length",
+				   test_ServerWrap_decrypt_short_ciphertext_length);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_zero_ciphertext_length",
+				   test_ServerWrap_decrypt_zero_ciphertext_length);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_remote_key",
+				   test_ServerWrap_encrypt_decrypt_remote_key);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_wrong_key",
+				   test_ServerWrap_encrypt_decrypt_wrong_key);
+
+	torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_wrong_sid",
+				   test_ServerWrap_encrypt_decrypt_wrong_sid);
+
+	return suite;
+}
diff --git a/source4/torture/rpc/clusapi.c b/source4/torture/rpc/clusapi.c
index f6f3ff5..d59f24f 100644
--- a/source4/torture/rpc/clusapi.c
+++ b/source4/torture/rpc/clusapi.c
@@ -325,6 +325,90 @@ static bool test_CreateEnum(struct torture_context *tctx,
 	return true;
 }
 
+static bool test_CreateEnumEx_int(struct torture_context *tctx,
+				  struct dcerpc_pipe *p,
+				  struct policy_handle *Cluster)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct clusapi_CreateEnumEx r;
+	uint32_t dwType[] = {
+		CLUSTER_ENUM_NODE,
+		CLUSTER_ENUM_RESTYPE,
+		CLUSTER_ENUM_RESOURCE,
+		CLUSTER_ENUM_GROUP,
+		CLUSTER_ENUM_NETWORK,
+		CLUSTER_ENUM_NETINTERFACE,
+		CLUSTER_ENUM_INTERNAL_NETWORK,
+		CLUSTER_ENUM_SHARED_VOLUME_RESOURCE
+	};
+	uint32_t dwType_invalid[] = {
+		0x00000040,
+		0x00000080,
+		0x00000100 /* and many more ... */
+	};
+	struct ENUM_LIST *ReturnIdEnum;
+	struct ENUM_LIST *ReturnNameEnum;
+	WERROR rpc_status;
+	int i;
+
+	for (i=0; i < ARRAY_SIZE(dwType); i++) {
+
+		r.in.hCluster = *Cluster;
+		r.in.dwType = dwType[i];
+		r.in.dwOptions = 0;
+		r.out.ReturnIdEnum = &ReturnIdEnum;
+		r.out.ReturnNameEnum = &ReturnNameEnum;
+		r.out.rpc_status = &rpc_status;
+
+		torture_assert_ntstatus_ok(tctx,
+			dcerpc_clusapi_CreateEnumEx_r(b, tctx, &r),
+			"CreateEnumEx failed");
+		torture_assert_werr_ok(tctx,
+			r.out.result,
+			"CreateEnumEx failed");
+	}
+
+	for (i=0; i < ARRAY_SIZE(dwType_invalid); i++) {
+
+		r.in.hCluster = *Cluster;
+		r.in.dwType = dwType_invalid[i];
+		r.in.dwOptions = 0;
+		r.out.ReturnIdEnum = &ReturnIdEnum;
+		r.out.ReturnNameEnum = &ReturnNameEnum;
+		r.out.rpc_status = &rpc_status;
+
+		torture_assert_ntstatus_ok(tctx,
+			dcerpc_clusapi_CreateEnumEx_r(b, tctx, &r),
+			"CreateEnumEx failed");
+		torture_assert_werr_equal(tctx,
+			r.out.result,
+			WERR_INVALID_PARAMETER,
+			"CreateEnumEx failed");
+	}
+
+	return true;
+}
+
+static bool test_CreateEnumEx(struct torture_context *tctx,
+			      void *data)
+{
+	struct torture_clusapi_context *t =
+		talloc_get_type_abort(data, struct torture_clusapi_context);
+	struct policy_handle Cluster;
+	bool ret;
+
+	if (!test_OpenCluster_int(tctx, t->p, &Cluster)) {
+		return false;
+	}
+
+	ret = test_CreateEnumEx_int(tctx, t->p, &Cluster);
+
+	test_CloseCluster_int(tctx, t->p, &Cluster);
+
+	return ret;
+}
+
+
 static bool test_GetQuorumResource(struct torture_context *tctx,
 				   void *data)
 {
@@ -387,10 +471,12 @@ static bool test_SetQuorumResource(struct torture_context *tctx,
 	return true;
 }
 
-bool test_OpenResource_int(struct torture_context *tctx,
-			   struct dcerpc_pipe *p,
-			   const char *lpszResourceName,
-			   struct policy_handle *hResource)
+static bool test_OpenResource_int_exp(struct torture_context *tctx,
+				      struct dcerpc_pipe *p,
+				      const char *lpszResourceName,
+				      struct policy_handle *hResource,
+				      WERROR expected_Status,
+				      WERROR expected_rpc_status)
 {
 	struct dcerpc_binding_handle *b = p->binding_handle;
 	struct clusapi_OpenResource r;
@@ -405,13 +491,27 @@ bool test_OpenResource_int(struct torture_context *tctx,
 	torture_assert_ntstatus_ok(tctx,
 		dcerpc_clusapi_OpenResource_r(b, tctx, &r),
 		"OpenResource failed");
-	torture_assert_werr_ok(tctx,
-		*r.out.Status,
+	torture_assert_werr_equal(tctx,
+		*r.out.Status, expected_Status,
+		"OpenResource failed");
+	torture_assert_werr_equal(tctx,
+		*r.out.rpc_status, expected_rpc_status,
 		"OpenResource failed");
 
 	return true;
 }
 
+bool test_OpenResource_int(struct torture_context *tctx,
+			   struct dcerpc_pipe *p,
+			   const char *lpszResourceName,
+			   struct policy_handle *hResource)
+{
+	return test_OpenResource_int_exp(tctx, p,
+					 lpszResourceName,
+					 hResource,
+					 WERR_OK, WERR_OK);
+}
+
 static bool test_OpenResourceEx_int(struct torture_context *tctx,
 				    struct dcerpc_pipe *p,
 				    const char *lpszResourceName,
@@ -476,6 +576,22 @@ static bool test_OpenResource(struct torture_context *tctx,
 
 	test_CloseResource_int(tctx, t->p, &hResource);
 
+	if (!test_OpenResource_int_exp(tctx, t->p, "", &hResource, WERR_RESOURCE_NOT_FOUND, WERR_OK)) {
+		return false;
+	}
+
+	torture_assert(tctx,
+		ndr_policy_handle_empty(&hResource),
+		"expected empty policy handle");
+
+	if (!test_OpenResource_int_exp(tctx, t->p, "jfUF38fjSNcfn", &hResource, WERR_RESOURCE_NOT_FOUND, WERR_OK)) {
+		return false;
+	}
+
+	torture_assert(tctx,
+		ndr_policy_handle_empty(&hResource),
+		"expected empty policy handle");
+
 	return true;
 }
 
@@ -830,9 +946,13 @@ bool test_OnlineResource_int(struct torture_context *tctx,
 	torture_assert_ntstatus_ok(tctx,
 		dcerpc_clusapi_OnlineResource_r(b, tctx, &r),
 		"OnlineResource failed");
-	torture_assert_werr_ok(tctx,
-		r.out.result,
-		"OnlineResource failed");
+	if (!W_ERROR_IS_OK(r.out.result) &&
+	    !W_ERROR_EQUAL(r.out.result, WERR_IO_PENDING)) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "OnlineResource failed with %s",
+			        win_errstr(r.out.result));
+		return false;
+	}
 
 	return true;
 }
@@ -870,9 +990,13 @@ bool test_OfflineResource_int(struct torture_context *tctx,
 	torture_assert_ntstatus_ok(tctx,
 		dcerpc_clusapi_OfflineResource_r(b, tctx, &r),
 		"OfflineResource failed");
-	torture_assert_werr_ok(tctx,
-		r.out.result,
-		"OfflineResource failed");
+	if (!W_ERROR_IS_OK(r.out.result) &&
+	    !W_ERROR_EQUAL(r.out.result, WERR_IO_PENDING)) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "OfflineResource failed with %s",
+			       win_errstr(r.out.result));
+		return false;
+	}
 
 	return true;
 }
@@ -940,6 +1064,90 @@ static bool test_CreateResEnum(struct torture_context *tctx,
 	return ret;
 }
 
+static bool test_GetResourceDependencyExpression_int(struct torture_context *tctx,
+						     struct dcerpc_pipe *p,
+						     struct policy_handle *hResource)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct clusapi_GetResourceDependencyExpression r;
+	const char *lpszDependencyExpression;
+	WERROR rpc_status;
+
+	r.in.hResource = *hResource;
+	r.out.lpszDependencyExpression = &lpszDependencyExpression;
+	r.out.rpc_status = &rpc_status;
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_clusapi_GetResourceDependencyExpression_r(b, tctx, &r),
+		"GetResourceDependencyExpression failed");
+	torture_assert_werr_ok(tctx,
+		r.out.result,
+		"GetResourceDependencyExpression failed");
+
+	return true;
+}
+
+static bool test_GetResourceDependencyExpression(struct torture_context *tctx,
+						 void *data)
+{
+	struct torture_clusapi_context *t =
+		talloc_get_type_abort(data, struct torture_clusapi_context);
+	struct policy_handle hResource;
+	bool ret = true;
+
+	if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+		return false;
+	}
+
+	ret = test_GetResourceDependencyExpression_int(tctx, t->p, &hResource);
+
+	test_CloseResource_int(tctx, t->p, &hResource);
+
+	return ret;
+}
+
+static bool test_GetResourceNetworkName_int(struct torture_context *tctx,
+					    struct dcerpc_pipe *p,
+					    struct policy_handle *hResource)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct clusapi_GetResourceNetworkName r;
+	const char *lpszName;
+	WERROR rpc_status;
+
+	r.in.hResource = *hResource;
+	r.out.lpszName = &lpszName;
+	r.out.rpc_status = &rpc_status;
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_clusapi_GetResourceNetworkName_r(b, tctx, &r),
+		"GetResourceNetworkName failed");
+	torture_assert_werr_ok(tctx,
+		r.out.result,
+		"GetResourceNetworkName failed");
+
+	return true;
+}
+
+static bool test_GetResourceNetworkName(struct torture_context *tctx,
+					void *data)
+{
+	struct torture_clusapi_context *t =
+		talloc_get_type_abort(data, struct torture_clusapi_context);
+	struct policy_handle hResource;
+	bool ret = true;
+
+	if (!test_OpenResource_int(tctx, t->p, "Network Name", &hResource)) {
+		return false;
+	}
+
+	ret = test_GetResourceNetworkName_int(tctx, t->p, &hResource);
+
+	test_CloseResource_int(tctx, t->p, &hResource);
+
+	return ret;
+}
+
 static bool test_one_resource(struct torture_context *tctx,
 			      struct dcerpc_pipe *p,
 			      const char *resource_name)
@@ -967,6 +1175,12 @@ static bool test_one_resource(struct torture_context *tctx,
 	torture_assert(tctx,
 		test_CreateResEnum_int(tctx, p, &hResource),
 		"failed to query resource enum");
+	torture_assert(tctx,
+		test_GetResourceDependencyExpression_int(tctx, p, &hResource),
+		"failed to query resource dependency expression");
+	torture_assert(tctx,
+		test_GetResourceNetworkName_int(tctx, p, &hResource),
+		"failed to query resource network name");
 
 	test_CloseResource_int(tctx, p, &hResource);
 
@@ -1217,6 +1431,111 @@ static bool test_GetNodeId(struct torture_context *tctx,
 	return ret;
 }
 
+static bool test_NodeControl_int(struct torture_context *tctx,
+				 struct dcerpc_pipe *p,
+				 struct policy_handle *hNode,
+				 enum clusapi_NodeControlCode dwControlCode)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct clusapi_NodeControl r;
+	uint32_t lpBytesReturned;
+	uint32_t lpcbRequired;
+	WERROR rpc_status;
+
+	r.in.hNode = *hNode;
+	r.in.dwControlCode = 0;
+	r.in.lpInBuffer = NULL;
+	r.in.nInBufferSize = 0;
+	r.in.nOutBufferSize = 0;
+	r.out.lpOutBuffer = NULL;
+	r.out.lpBytesReturned = &lpBytesReturned;
+	r.out.lpcbRequired = &lpcbRequired;
+	r.out.rpc_status = &rpc_status;
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_clusapi_NodeControl_r(b, tctx, &r),
+		"NodeControl failed");
+	torture_assert_werr_equal(tctx,
+		r.out.result,
+		WERR_INVALID_FUNCTION,
+		"NodeControl failed");
+
+	r.in.dwControlCode = dwControlCode;
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_clusapi_NodeControl_r(b, tctx, &r),
+		"NodeControl failed");
+
+	if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+		r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, *r.out.lpcbRequired);
+		r.in.nOutBufferSize = *r.out.lpcbRequired;
+		torture_assert_ntstatus_ok(tctx,
+			dcerpc_clusapi_NodeControl_r(b, tctx, &r),
+			"NodeControl failed");
+	}
+	torture_assert_werr_ok(tctx,
+		r.out.result,
+		"NodeControl failed");
+
+	/* now try what happens when we query with a buffer large enough to hold
+	 * the entire packet */
+
+	r.in.nOutBufferSize = 0x400;
+	r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, r.in.nOutBufferSize);
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_clusapi_NodeControl_r(b, tctx, &r),
+		"NodeControl failed");
+	torture_assert_werr_ok(tctx,
+		r.out.result,
+		"NodeControl failed");
+	torture_assert(tctx, *r.out.lpBytesReturned < r.in.nOutBufferSize,
+		"lpBytesReturned expected to be smaller than input size nOutBufferSize");
+
+	if (dwControlCode == CLUSCTL_NODE_GET_ID) {
+		const char *str;
+		DATA_BLOB blob = data_blob_const(r.out.lpOutBuffer, *r.out.lpBytesReturned);
+
+		torture_assert(tctx, *r.out.lpBytesReturned < 4, "unexpected size");
+		torture_assert(tctx, *r.out.lpBytesReturned % 2, "must be a multiple of 2");
+
+		torture_assert(tctx,
+			pull_reg_sz(tctx, &blob, &str),
+			"failed to pull unicode string");
+
+		torture_comment(tctx, "got this node id: '%s'", str);
+	}
+
+	return true;
+}
+
+static bool test_NodeControl(struct torture_context *tctx,
+			     void *data)
+{
+	struct torture_clusapi_context *t =
+		talloc_get_type_abort(data, struct torture_clusapi_context);
+	struct policy_handle hNode;
+	bool ret = true;
+
+	if (!test_OpenNode_int(tctx, t->p, t->NodeName, &hNode)) {
+		return false;
+	}
+
+	ret = test_NodeControl_int(tctx, t->p, &hNode, CLUSCTL_NODE_GET_RO_COMMON_PROPERTIES);
+	if (ret) {
+		return false;
+	}
+
+	ret = test_NodeControl_int(tctx, t->p, &hNode, CLUSCTL_NODE_GET_ID);
+	if (ret) {
+		return false;
+	}
+
+	test_CloseNode_int(tctx, t->p, &hNode);
+
+	return ret;
+}
+
 static bool test_PauseNode_int(struct torture_context *tctx,
 			       struct dcerpc_pipe *p,
 			       struct policy_handle *hNode)
@@ -1610,6 +1929,97 @@ static bool test_GetGroupId(struct torture_context *tctx,
 	return ret;
 }
 
+static bool test_GroupControl_int(struct torture_context *tctx,
+				  struct dcerpc_pipe *p,
+				  struct policy_handle *hGroup,
+				  enum clusapi_GroupControlCode dwControlCode)
+{
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct clusapi_GroupControl r;
+	uint32_t lpBytesReturned;
+	uint32_t lpcbRequired;
+	WERROR rpc_status;
+
+	r.in.hGroup = *hGroup;
+	r.in.dwControlCode = 0;
+	r.in.lpInBuffer = NULL;
+	r.in.nInBufferSize = 0;
+	r.in.nOutBufferSize = 0;
+	r.out.lpOutBuffer = NULL;
+	r.out.lpBytesReturned = &lpBytesReturned;
+	r.out.lpcbRequired = &lpcbRequired;
+	r.out.rpc_status = &rpc_status;
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_clusapi_GroupControl_r(b, tctx, &r),
+		"GroupControl failed");
+	torture_assert_werr_equal(tctx,
+		r.out.result,
+		WERR_INVALID_FUNCTION,
+		"GroupControl failed");
+
+	r.in.dwControlCode = dwControlCode;
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_clusapi_GroupControl_r(b, tctx, &r),
+		"GroupControl failed");
+
+	if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+		r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, *r.out.lpcbRequired);
+		r.in.nOutBufferSize = *r.out.lpcbRequired;
+		torture_assert_ntstatus_ok(tctx,
+			dcerpc_clusapi_GroupControl_r(b, tctx, &r),
+			"GroupControl failed");
+	}
+	torture_assert_werr_ok(tctx,
+		r.out.result,
+		"GroupControl failed");
+
+	/* now try what happens when we query with a buffer large enough to hold
+	 * the entire packet */
+
+	r.in.nOutBufferSize = 0x400;
+	r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, r.in.nOutBufferSize);
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_clusapi_GroupControl_r(b, tctx, &r),
+		"GroupControl failed");
+	torture_assert_werr_ok(tctx,
+		r.out.result,
+		"GroupControl failed");
+	torture_assert(tctx, *r.out.lpBytesReturned < r.in.nOutBufferSize,
+		"lpBytesReturned expected to be smaller than input size nOutBufferSize");
+
+	return true;
+}
+
+static bool test_GroupControl(struct torture_context *tctx,
+			      void *data)
+{
+	struct torture_clusapi_context *t =
+		talloc_get_type_abort(data, struct torture_clusapi_context);
+	struct policy_handle hGroup;
+	bool ret = true;
+
+	if (!test_OpenGroup_int(tctx, t->p, "Cluster Group", &hGroup)) {
+		return false;
+	}
+
+	ret = test_GroupControl_int(tctx, t->p, &hGroup, CLUSCTL_GROUP_GET_CHARACTERISTICS);
+	if (ret) {
+		return false;
+	}
+
+	ret = test_GroupControl_int(tctx, t->p, &hGroup, CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES);
+	if (ret) {
+		return false;
+	}
+
+	test_CloseGroup_int(tctx, t->p, &hGroup);
+
+	return ret;
+}
+
 static bool test_OnlineGroup_int(struct torture_context *tctx,
 				 struct dcerpc_pipe *p,
 				 struct policy_handle *hGroup)
@@ -1850,6 +2260,21 @@ static bool test_ClusterControl_int(struct torture_context *tctx,
 		r.out.result,
 		"ClusterControl failed");
 
+	/* now try what happens when we query with a buffer large enough to hold
+	 * the entire packet */
+
+	r.in.nOutBufferSize = 0x400;
+	r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, r.in.nOutBufferSize);
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_clusapi_ClusterControl_r(b, tctx, &r),
+		"ClusterControl failed");
+	torture_assert_werr_ok(tctx,
+		r.out.result,
+		"ClusterControl failed");
+	torture_assert(tctx, *r.out.lpBytesReturned < r.in.nOutBufferSize,
+		"lpBytesReturned expected to be smaller than input size nOutBufferSize");
+
 	return true;
 }
 
@@ -2878,6 +3303,8 @@ void torture_tcase_cluster(struct torture_tcase *tcase)
 				      test_GetClusterVersion);
 	torture_tcase_add_simple_test(tcase, "CreateEnum",
 				      test_CreateEnum);
+	torture_tcase_add_simple_test(tcase, "CreateEnumEx",
+				      test_CreateEnumEx);
 	torture_tcase_add_simple_test(tcase, "GetClusterVersion2",
 				      test_GetClusterVersion2);
 	torture_tcase_add_simple_test(tcase, "BackupClusterDatabase",
@@ -2925,6 +3352,10 @@ void torture_tcase_resource(struct torture_tcase *tcase)
 	test = torture_tcase_add_simple_test(tcase, "OfflineResource",
 				      test_OfflineResource);
 	test->dangerous = true;
+	torture_tcase_add_simple_test(tcase, "GetResourceDependencyExpression",
+				      test_GetResourceDependencyExpression);
+	torture_tcase_add_simple_test(tcase, "GetResourceNetworkName",
+				      test_GetResourceNetworkName);
 	torture_tcase_add_simple_test(tcase, "all_resources",
 				      test_all_resources);
 }
@@ -2943,6 +3374,8 @@ void torture_tcase_node(struct torture_tcase *tcase)
 				      test_GetNodeState);
 	torture_tcase_add_simple_test(tcase, "GetNodeId",
 				      test_GetNodeId);
+	torture_tcase_add_simple_test(tcase, "NodeControl",
+				      test_NodeControl);
 	test = torture_tcase_add_simple_test(tcase, "PauseNode",
 					     test_PauseNode);
 	test->dangerous = true;
@@ -2969,6 +3402,8 @@ void torture_tcase_group(struct torture_tcase *tcase)
 				      test_GetGroupState);
 	torture_tcase_add_simple_test(tcase, "GetGroupId",
 				      test_GetGroupId);
+	torture_tcase_add_simple_test(tcase, "GroupControl",
+				      test_GroupControl);
 	torture_tcase_add_simple_test(tcase, "OnlineGroup",
 				      test_OnlineGroup);
 	test = torture_tcase_add_simple_test(tcase, "OfflineGroup",
diff --git a/source4/torture/rpc/fsrvp.c b/source4/torture/rpc/fsrvp.c
index d6859dc..4a4e0d4 100644
--- a/source4/torture/rpc/fsrvp.c
+++ b/source4/torture/rpc/fsrvp.c
@@ -41,7 +41,7 @@
 #include "torture/torture.h"
 #include "torture/smb2/proto.h"
 #include "torture/rpc/torture_rpc.h"
-#include "librpc/gen_ndr/ndr_security.c"
+#include "librpc/gen_ndr/ndr_security.h"
 #include "librpc/gen_ndr/ndr_srvsvc_c.h"
 #include "librpc/gen_ndr/ndr_fsrvp_c.h"
 
diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c
index 44cdbdc..d2180db 100644
--- a/source4/torture/rpc/lsa.c
+++ b/source4/torture/rpc/lsa.c
@@ -36,6 +36,7 @@
 #include "source4/auth/kerberos/kerberos_util.h"
 #include "lib/util/util_net.h"
 #include "../lib/crypto/crypto.h"
+#include "libcli/resolve/resolve.h"
 #define TEST_MACHINENAME "lsatestmach"
 #define TRUSTPW "12345678"
 
@@ -3216,7 +3217,7 @@ static bool check_pw_with_krb5(struct torture_context *tctx,
 	k5ret = smb_krb5_init_context(ctx, tctx->lp_ctx, &ctx->smb_krb5_context);
 	torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
 
-	ok = interpret_string_addr_internal(&ctx->server, host, AI_NUMERICHOST);
+	ok = interpret_string_addr_internal(&ctx->server, host, 0);
 	torture_assert(tctx, ok, "Failed to parse target server");
 	talloc_set_destructor(ctx, check_pw_with_krb5_ctx_destructor);
 
@@ -4127,6 +4128,8 @@ static bool check_dom_trust_pw(struct dcerpc_pipe *p,
 	char *workstation = NULL;
 	const char *binding = torture_setting_string(tctx, "binding", NULL);
 	const char *host = torture_setting_string(tctx, "host", NULL);
+	const char *ip;
+	struct nbt_name nbt_name;
 	struct dcerpc_binding *b2;
 	struct netlogon_creds_CredentialState *creds;
 	struct samr_CryptPassword samr_crypt_password;
@@ -4182,11 +4185,22 @@ static bool check_dom_trust_pw(struct dcerpc_pipe *p,
 	cli_credentials_set_workstation(incoming_creds, workstation, CRED_SPECIFIED);
 	cli_credentials_set_secure_channel_type(incoming_creds, secure_channel_type);
 
+	make_nbt_name_server(&nbt_name, host);
+
+	status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+				 0, 0, &nbt_name, tctx, &ip, tctx->ev);
+	torture_assert_ntstatus_ok(tctx, status,
+			talloc_asprintf(tctx,"Failed to resolve %s: %s",
+					nbt_name.name, nt_errstr(status)));
+
 	rc = tsocket_address_inet_from_strings(tctx, "ip",
-					       host,
+					       ip,
 					       lpcfg_cldap_port(tctx->lp_ctx),
 					       &dest_addr);
-	torture_assert_int_equal(tctx, rc, 0, "tsocket_address_inet_from_strings");
+	torture_assert_int_equal(tctx, rc, 0,
+				 talloc_asprintf(tctx,
+						 "tsocket_address_inet_from_strings failed parsing %s:%d",
+						 host, lpcfg_cldap_port(tctx->lp_ctx)));
 
 	/* cldap_socket_init should now know about the dest. address */
 	status = cldap_socket_init(tctx, NULL, dest_addr, &cldap);
diff --git a/source4/torture/rpc/oxidresolve.c b/source4/torture/rpc/oxidresolve.c
index 33865d7..11cd8fe 100644
--- a/source4/torture/rpc/oxidresolve.c
+++ b/source4/torture/rpc/oxidresolve.c
@@ -1,19 +1,19 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    test suite for oxidresolve operations
 
    Copyright (C) Jelmer Vernooij 2004
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
@@ -30,7 +30,7 @@ const struct GUID IUnknown_uuid = {
 	0x00000000,0x0000,0x0000,{0xc0,0x00},{0x00,0x00,0x00,0x00,0x00,0x46}
 };
 
-static bool test_RemoteActivation(struct torture_context *tctx, 
+static bool test_RemoteActivation(struct torture_context *tctx,
 				 uint64_t *oxid, struct GUID *oid)
 {
 	struct RemoteActivation r;
@@ -39,16 +39,23 @@ static bool test_RemoteActivation(struct torture_context *tctx,
 	uint16_t protseq[3] = { EPM_PROTOCOL_TCP, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID };
 	struct dcerpc_pipe *p;
 	struct dcerpc_binding_handle *b;
-
-	status = torture_rpc_connection(tctx, &p, 
+	struct ORPCTHAT that;
+	struct DUALSTRINGARRAY *pdsaOxidBindings;
+	uint32_t AuthnHint;
+	struct COMVERSION ServerVersion;
+	HRESULT hr;
+	struct MInterfacePointer *ifaces;
+
+	status = torture_rpc_connection(tctx, &p,
 					&ndr_table_IRemoteActivation);
-			
+
 	if (!NT_STATUS_IS_OK(status)) {
 		return false;
 	}
 	b = p->binding_handle;
 
-	ZERO_STRUCT(r.in);
+	ZERO_STRUCT(r);
+
 	r.in.this_object.version.MajorVersion = 5;
 	r.in.this_object.version.MinorVersion = 1;
 	r.in.this_object.cid = GUID_random();
@@ -59,34 +66,26 @@ static bool test_RemoteActivation(struct torture_context *tctx,
 	r.in.Interfaces = 1;
 	iids[0] = IUnknown_uuid;
 	r.in.pIIDs = iids;
+
+	r.out.that = &that;
 	r.out.pOxid = oxid;
+	r.out.pdsaOxidBindings = &pdsaOxidBindings;
 	r.out.ipidRemUnknown = oid;
+	r.out.AuthnHint = &AuthnHint;
+	r.out.ServerVersion = &ServerVersion;
+	r.out.hr = &hr;
+	r.out.ifaces = &ifaces;
 
 	status = dcerpc_RemoteActivation_r(b, tctx, &r);
-	if(NT_STATUS_IS_ERR(status)) {
-		fprintf(stderr, "RemoteActivation: %s\n", nt_errstr(status));
-		return false;
-	}
-
-	if(!W_ERROR_IS_OK(r.out.result)) {
-		fprintf(stderr, "RemoteActivation: %s\n", win_errstr(r.out.result));
-		return false;
-	}
-
-	if(!W_ERROR_IS_OK(*r.out.hr)) {
-		fprintf(stderr, "RemoteActivation: %s\n", win_errstr(*r.out.hr));
-		return false;
-	}
-
-	if(!W_ERROR_IS_OK(r.out.results[0])) {
-		fprintf(stderr, "RemoteActivation: %s\n", win_errstr(r.out.results[0]));
-		return false;
-	}
+	torture_assert_ntstatus_ok(tctx, status, "RemoteActivation failed");
+	torture_assert_werr_ok(tctx, r.out.result, "RemoteActivation failed");
+	torture_assert_hresult_ok(tctx, *r.out.hr, "RemoteActivation failed");
+	torture_assert_hresult_ok(tctx, r.out.results[0], "RemoteActivation failed");
 
 	return true;
 }
 
-static bool test_SimplePing(struct torture_context *tctx, 
+static bool test_SimplePing(struct torture_context *tctx,
 			   struct dcerpc_pipe *p)
 {
 	struct SimplePing r;
@@ -103,7 +102,7 @@ static bool test_SimplePing(struct torture_context *tctx,
 	return true;
 }
 
-static bool test_ComplexPing(struct torture_context *tctx, 
+static bool test_ComplexPing(struct torture_context *tctx,
 			     struct dcerpc_pipe *p)
 {
 	struct ComplexPing r;
@@ -135,12 +134,12 @@ static bool test_ComplexPing(struct torture_context *tctx,
 		return 0;
 	}
 
-	
+
 
 	return 1;
 }
 
-static bool test_ServerAlive(struct torture_context *tctx, 
+static bool test_ServerAlive(struct torture_context *tctx,
 			    struct dcerpc_pipe *p)
 {
 	struct ServerAlive r;
@@ -154,15 +153,18 @@ static bool test_ServerAlive(struct torture_context *tctx,
 	return true;
 }
 
-static bool test_ResolveOxid(struct torture_context *tctx, 
+static bool test_ResolveOxid(struct torture_context *tctx,
 			     struct dcerpc_pipe *p)
 {
 	struct ResolveOxid r;
 	NTSTATUS status;
-	uint16_t protseq[2] = { EPM_PROTOCOL_TCP, EPM_PROTOCOL_SMB };	
+	uint16_t protseq[2] = { EPM_PROTOCOL_TCP, EPM_PROTOCOL_SMB };
 	uint64_t oxid;
 	struct GUID oid;
 	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct DUALSTRINGARRAY *ppdsaOxidBindings;
+	struct GUID pipidRemUnknown;
+	uint32_t pAuthnHint;
 
 	if (!test_RemoteActivation(tctx, &oxid, &oid))
 		return false;
@@ -170,6 +172,9 @@ static bool test_ResolveOxid(struct torture_context *tctx,
 	r.in.pOxid = oxid;
 	r.in.cRequestedProtseqs = 2;
 	r.in.arRequestedProtseqs = protseq;
+	r.out.ppdsaOxidBindings = &ppdsaOxidBindings;
+	r.out.pipidRemUnknown = &pipidRemUnknown;
+	r.out.pAuthnHint = &pAuthnHint;
 
 	status = dcerpc_ResolveOxid_r(b, tctx, &r);
 	torture_assert_ntstatus_ok(tctx, status, "ResolveOxid");
@@ -178,15 +183,19 @@ static bool test_ResolveOxid(struct torture_context *tctx,
 	return true;
 }
 
-static bool test_ResolveOxid2(struct torture_context *tctx, 
+static bool test_ResolveOxid2(struct torture_context *tctx,
 			      struct dcerpc_pipe *p)
 {
 	struct ResolveOxid2 r;
 	NTSTATUS status;
-	uint16_t protseq[2] = { EPM_PROTOCOL_TCP, EPM_PROTOCOL_SMB };	
+	uint16_t protseq[2] = { EPM_PROTOCOL_TCP, EPM_PROTOCOL_SMB };
 	uint64_t oxid;
 	struct GUID oid;
 	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct DUALSTRINGARRAY *pdsaOxidBindings;
+	struct GUID ipidRemUnknown;
+	uint32_t AuthnHint;
+	struct COMVERSION ComVersion;
 
 	if (!test_RemoteActivation(tctx, &oxid, &oid))
 		return false;
@@ -194,23 +203,34 @@ static bool test_ResolveOxid2(struct torture_context *tctx,
 	r.in.pOxid = oxid;
 	r.in.cRequestedProtseqs = 2;
 	r.in.arRequestedProtseqs = protseq;
+	r.out.pdsaOxidBindings = &pdsaOxidBindings;
+	r.out.ipidRemUnknown = &ipidRemUnknown;
+	r.out.AuthnHint = &AuthnHint;
+	r.out.ComVersion = &ComVersion;
 
 	status = dcerpc_ResolveOxid2_r(b, tctx, &r);
 	torture_assert_ntstatus_ok(tctx, status, "ResolveOxid2");
 
 	torture_assert_werr_ok(tctx, r.out.result, "ResolveOxid2");
-	
+
 	torture_comment(tctx, "Remote server versions: %d, %d\n", r.out.ComVersion->MajorVersion, r.out.ComVersion->MinorVersion);
 
 	return true;
 }
 
-static bool test_ServerAlive2(struct torture_context *tctx, 
+static bool test_ServerAlive2(struct torture_context *tctx,
 			     struct dcerpc_pipe *p)
 {
 	struct ServerAlive2 r;
 	NTSTATUS status;
 	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct COMINFO info;
+	struct DUALSTRINGARRAY *dualstring;
+	uint8_t pReserved;
+
+	r.out.info = &info;
+	r.out.dualstring = &dualstring;
+	r.out.pReserved = &pReserved;
 
 	status = dcerpc_ServerAlive2_r(b, tctx, &r);
 	torture_assert_ntstatus_ok(tctx, status, "ServerAlive2");
@@ -224,7 +244,7 @@ struct torture_suite *torture_rpc_oxidresolve(TALLOC_CTX *mem_ctx)
 	struct torture_suite *suite = torture_suite_create(mem_ctx, "oxidresolve");
 	struct torture_rpc_tcase *tcase;
 
-	tcase = torture_suite_add_rpc_iface_tcase(suite, "oxidresolver", 
+	tcase = torture_suite_add_rpc_iface_tcase(suite, "oxidresolver",
 					  &ndr_table_IOXIDResolver);
 
 	torture_rpc_tcase_add_test(tcase, "ServerAlive", test_ServerAlive);
@@ -234,7 +254,7 @@ struct torture_suite *torture_rpc_oxidresolve(TALLOC_CTX *mem_ctx)
 	torture_rpc_tcase_add_test(tcase, "ComplexPing", test_ComplexPing);
 
 	torture_rpc_tcase_add_test(tcase, "SimplePing", test_SimplePing);
-	
+
 	torture_rpc_tcase_add_test(tcase, "ResolveOxid", test_ResolveOxid);
 
 	torture_rpc_tcase_add_test(tcase, "ResolveOxid2", test_ResolveOxid2);
diff --git a/source4/torture/rpc/remact.c b/source4/torture/rpc/remact.c
index c14adb8..9e9642e 100644
--- a/source4/torture/rpc/remact.c
+++ b/source4/torture/rpc/remact.c
@@ -1,19 +1,19 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    test suite for remoteactivation operations
 
    Copyright (C) Jelmer Vernooij 2004
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
@@ -27,16 +27,25 @@
 #define DCERPC_IUNKNOWN_UUID "00000000-0000-0000-c000-000000000046"
 #define DCERPC_ICLASSFACTORY_UUID "00000001-0000-0000-c000-000000000046"
 
-static bool test_RemoteActivation(struct torture_context *tctx, 
-								 struct dcerpc_pipe *p)
+static bool test_RemoteActivation(struct torture_context *tctx,
+				  struct dcerpc_pipe *p)
 {
 	struct RemoteActivation r;
 	NTSTATUS status;
 	struct GUID iids[1];
 	uint16_t protseq[3] = { EPM_PROTOCOL_TCP, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID };
 	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct ORPCTHAT that;
+	uint64_t pOxid;
+	struct DUALSTRINGARRAY *pdsaOxidBindings;
+	struct GUID ipidRemUnknown;
+	uint32_t AuthnHint;
+	struct COMVERSION ServerVersion;
+	HRESULT hr;
+	struct MInterfacePointer *ifaces;
+
+	ZERO_STRUCT(r);
 
-	ZERO_STRUCT(r.in);
 	r.in.this_object.version.MajorVersion = 5;
 	r.in.this_object.version.MinorVersion = 1;
 	r.in.this_object.cid = GUID_random();
@@ -48,30 +57,36 @@ static bool test_RemoteActivation(struct torture_context *tctx,
 	GUID_from_string(DCERPC_IUNKNOWN_UUID, &iids[0]);
 	r.in.pIIDs = iids;
 
+	r.out.that = &that;
+	r.out.pOxid = &pOxid;
+	r.out.pdsaOxidBindings = &pdsaOxidBindings;
+	r.out.ipidRemUnknown = &ipidRemUnknown;
+	r.out.AuthnHint = &AuthnHint;
+	r.out.ServerVersion = &ServerVersion;
+	r.out.hr = &hr;
+	r.out.ifaces = &ifaces;
+
 	status = dcerpc_RemoteActivation_r(b, tctx, &r);
 	torture_assert_ntstatus_ok(tctx, status, "RemoteActivation");
 
 	torture_assert_werr_ok(tctx, r.out.result, "RemoteActivation");
 
-	torture_assert_werr_ok(tctx, *r.out.hr, "RemoteActivation");
+	torture_assert_hresult_ok(tctx, *r.out.hr, "RemoteActivation");
 
-	torture_assert_werr_ok(tctx, r.out.results[0], "RemoteActivation");
+	torture_assert_hresult_ok(tctx, r.out.results[0], "RemoteActivation");
 
 	GUID_from_string(DCERPC_ICLASSFACTORY_UUID, &iids[0]);
 	r.in.Interfaces = 1;
 	r.in.Mode = MODE_GET_CLASS_OBJECT;
 
 	status = dcerpc_RemoteActivation_r(b, tctx, &r);
-	torture_assert_ntstatus_ok(tctx, status, 
-							   "RemoteActivation(GetClassObject)");
+	torture_assert_ntstatus_ok(tctx, status, "RemoteActivation(GetClassObject)");
 
-	torture_assert_werr_ok(tctx, r.out.result, 
-						   "RemoteActivation(GetClassObject)");
+	torture_assert_werr_ok(tctx, r.out.result, "RemoteActivation(GetClassObject)");
 
-	torture_assert_werr_ok(tctx, *r.out.hr, "RemoteActivation(GetClassObject)");
+	torture_assert_hresult_ok(tctx, *r.out.hr, "RemoteActivation(GetClassObject)");
 
-	torture_assert_werr_ok(tctx, r.out.results[0], 
-						   "RemoteActivation(GetClassObject)");
+	torture_assert_hresult_ok(tctx, r.out.results[0], "RemoteActivation(GetClassObject)");
 
 	return true;
 }
diff --git a/source4/torture/rpc/rpc.c b/source4/torture/rpc/rpc.c
index e70fac52..46a9e56 100644
--- a/source4/torture/rpc/rpc.c
+++ b/source4/torture/rpc/rpc.c
@@ -489,7 +489,7 @@ NTSTATUS torture_rpc_init(void)
 	torture_suite_add_suite(suite, torture_rpc_object_uuid(suite));
 	torture_suite_add_suite(suite, torture_rpc_winreg(suite));
 	torture_suite_add_suite(suite, torture_rpc_spoolss(suite));
-#ifdef AD_DC_BUILD_IS_ENABLED
+#ifdef WITH_NTVFS_FILESERVER
 	torture_suite_add_suite(suite, torture_rpc_spoolss_notify(suite));
 #endif
 	torture_suite_add_suite(suite, torture_rpc_spoolss_win(suite));
@@ -540,7 +540,9 @@ NTSTATUS torture_rpc_init(void)
 	torture_suite_add_simple_test(suite, "asyncbind", torture_async_bind);
 	torture_suite_add_suite(suite, torture_rpc_ntsvcs(suite));
 	torture_suite_add_suite(suite, torture_rpc_bind(suite));
+#ifdef AD_DC_BUILD_IS_ENABLED
 	torture_suite_add_suite(suite, torture_rpc_backupkey(suite));
+#endif
 	torture_suite_add_suite(suite, torture_rpc_fsrvp(suite));
 	torture_suite_add_suite(suite, torture_rpc_clusapi(suite));
 	torture_suite_add_suite(suite, torture_rpc_witness(suite));
diff --git a/source4/torture/rpc/spoolss.c b/source4/torture/rpc/spoolss.c
index 5950673..4bc99f2 100644
--- a/source4/torture/rpc/spoolss.c
+++ b/source4/torture/rpc/spoolss.c
@@ -7475,7 +7475,7 @@ static bool test_AddPrinter_normal(struct torture_context *tctx,
 		"failed to add printer");
 	result = ex ? rex.out.result : r.out.result;
 
-	/* w2k8r2 allows to add printer w/o defining printprocessor */
+	/* w2k8r2 allows one to add printer w/o defining printprocessor */
 
 	if (!W_ERROR_IS_OK(result)) {
 		torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
diff --git a/source4/torture/rpc/spoolss_notify.c b/source4/torture/rpc/spoolss_notify.c
index 930a599..945e653 100644
--- a/source4/torture/rpc/spoolss_notify.c
+++ b/source4/torture/rpc/spoolss_notify.c
@@ -140,7 +140,7 @@ static NTSTATUS spoolss__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_
 	rp->opnum = opnum;
 	rp->r = talloc_reference(rp, r);
 
-	DLIST_ADD_END(received_packets, rp, struct received_packet *);
+	DLIST_ADD_END(received_packets, rp);
 
 	switch (opnum) {
 	case 58: {
diff --git a/source4/torture/smb2/connect.c b/source4/torture/smb2/connect.c
index 0067de0..6340430 100644
--- a/source4/torture/smb2/connect.c
+++ b/source4/torture/smb2/connect.c
@@ -90,7 +90,7 @@ static NTSTATUS torture_smb2_write(struct torture_context *tctx, struct smb2_tre
 
 	status = smb2_write(tree, &w);
 	if (!NT_STATUS_IS_OK(status)) {
-		printf("write failed - %s\n", nt_errstr(status));
+		printf("write 1 failed - %s\n", nt_errstr(status));
 		return status;
 	}
 
@@ -98,7 +98,7 @@ static NTSTATUS torture_smb2_write(struct torture_context *tctx, struct smb2_tre
 
 	status = smb2_write(tree, &w);
 	if (!NT_STATUS_IS_OK(status)) {
-		printf("write failed - %s\n", nt_errstr(status));
+		printf("write 2 failed - %s\n", nt_errstr(status));
 		return status;
 	}
 
@@ -137,8 +137,9 @@ static NTSTATUS torture_smb2_write(struct torture_context *tctx, struct smb2_tre
 /*
   send a create
 */
-static struct smb2_handle torture_smb2_createfile(struct smb2_tree *tree, 
-					      const char *fname)
+static NTSTATUS torture_smb2_createfile(struct smb2_tree *tree,
+					const char *fname,
+					struct smb2_handle *handle)
 {
 	struct smb2_create io;
 	NTSTATUS status;
@@ -158,8 +159,8 @@ static struct smb2_handle torture_smb2_createfile(struct smb2_tree *tree,
 
 	status = smb2_create(tree, tmp_ctx, &io);
 	if (!NT_STATUS_IS_OK(status)) {
-		printf("create1 failed - %s\n", nt_errstr(status));
-		return io.out.file.handle;
+		TALLOC_FREE(tmp_ctx);
+		return status;
 	}
 
 	if (DEBUGLVL(1)) {
@@ -179,8 +180,10 @@ static struct smb2_handle torture_smb2_createfile(struct smb2_tree *tree,
 	}
 
 	talloc_free(tmp_ctx);
-	
-	return io.out.file.handle;
+
+	*handle = io.out.file.handle;
+
+	return NT_STATUS_OK;
 }
 
 
@@ -194,74 +197,54 @@ bool torture_smb2_connect(struct torture_context *torture)
 	struct smb2_request *req;
 	struct smb2_handle h1, h2;
 	NTSTATUS status;
+	bool ok;
 
-	if (!torture_smb2_connection(torture, &tree)) {
-		return false;
-	}
+	ok = torture_smb2_connection(torture, &tree);
+	torture_assert(torture, ok, "torture_smb2_connection failed");
 
 	smb2_util_unlink(tree, "test9.dat");
 
-	h1 = torture_smb2_createfile(tree, "test9.dat");
-	h2 = torture_smb2_createfile(tree, "test9.dat");
+	status = torture_smb2_createfile(tree, "test9.dat", &h1);
+	torture_assert_ntstatus_ok(torture, status, "create failed");
+
+	status = torture_smb2_createfile(tree, "test9.dat", &h2);
+	torture_assert_ntstatus_ok(torture, status, "create failed");
+
 	status = torture_smb2_write(torture, tree, h1);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("Write failed - %s\n", nt_errstr(status));
-		return false;
-	}
+	torture_assert_ntstatus_ok(torture, status, "write failed");
+
 	status = torture_smb2_close(tree, h1);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("Close failed - %s\n", nt_errstr(status));
-		return false;
-	}
+	torture_assert_ntstatus_ok(torture, status, "close failed");
+
 	status = torture_smb2_close(tree, h2);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("Close failed - %s\n", nt_errstr(status));
-		return false;
-	}
+	torture_assert_ntstatus_ok(torture, status, "close failed");
 
 	status = smb2_util_close(tree, h1);
-	if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) {
-		printf("close should have closed the handle - %s\n", nt_errstr(status));
-		return false;
-	}
+	torture_assert_ntstatus_equal(torture, status, NT_STATUS_FILE_CLOSED,
+				      "close should have closed the handle");
 
 	status = smb2_tdis(tree);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("tdis failed - %s\n", nt_errstr(status));
-		return false;
-	}
+	torture_assert_ntstatus_ok(torture, status, "tdis failed");
 
 	status = smb2_tdis(tree);
-	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) {
-		printf("tdis should have disabled session - %s\n", nt_errstr(status));
-		return false;
-	}
+	torture_assert_ntstatus_equal(torture, status,
+				      NT_STATUS_NETWORK_NAME_DELETED,
+				      "tdis should have closed the tcon");
 
  	status = smb2_logoff(tree->session);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("Logoff failed - %s\n", nt_errstr(status));
-		return false;
-	}
+	torture_assert_ntstatus_ok(torture, status, "logoff failed");
 
 	req = smb2_logoff_send(tree->session);
-	if (!req) {
-		printf("smb2_logoff_send() failed\n");
-		return false;
-	}
+	torture_assert_not_null(torture, req, "smb2_logoff_send failed");
 
 	req->session = NULL;
 
 	status = smb2_logoff_recv(req);
-	if (!NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
-		printf("Logoff should have disabled session - %s\n", nt_errstr(status));
-		return false;
-	}
+	torture_assert_ntstatus_equal(torture, status, NT_STATUS_USER_SESSION_DELETED,
+				      "logoff should have disabled session");
 
 	status = smb2_keepalive(tree->session->transport);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("keepalive failed? - %s\n", nt_errstr(status));
-		return false;
-	}
+	torture_assert_ntstatus_ok(torture, status, "keepalive failed");
 
 	talloc_free(mem_ctx);
 
diff --git a/source4/torture/smb2/dir.c b/source4/torture/smb2/dir.c
index c57ce75..98844b4 100644
--- a/source4/torture/smb2/dir.c
+++ b/source4/torture/smb2/dir.c
@@ -710,6 +710,10 @@ static NTSTATUS multiple_smb2_search(struct smb2_tree *tree,
 			return NT_STATUS_UNSUCCESSFUL;
 		}
 
+		if (count == 0 || result == NULL || result->count == 0) {
+			return NT_STATUS_UNSUCCESSFUL;
+		}
+
 		/*
 		 * After the first iteration is complete set the CONTINUE
 		 * FLAGS appropriately
@@ -717,6 +721,30 @@ static NTSTATUS multiple_smb2_search(struct smb2_tree *tree,
 		switch (cont_type) {
 			case CONT_INDEX:
 				f.in.continue_flags = SMB2_CONTINUE_FLAG_INDEX;
+				switch (data_level) {
+					case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
+						f.in.file_index =
+							result->list[result->count-1].both_directory_info.file_index;
+						break;
+					case RAW_SEARCH_DATA_DIRECTORY_INFO:
+						f.in.file_index =
+							result->list[result->count-1].directory_info.file_index;
+						break;
+					case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
+						f.in.file_index =
+							result->list[result->count-1].full_directory_info.file_index;
+						break;
+					case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
+						f.in.file_index =
+							result->list[result->count-1].id_full_directory_info.file_index;
+						break;
+					case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
+						f.in.file_index =
+							result->list[result->count-1].id_both_directory_info.file_index;
+						break;
+					default:
+						return NT_STATUS_INVALID_PARAMETER;
+				}
 				break;
 			case CONT_SINGLE:
 				f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
diff --git a/source4/torture/smb2/durable_open.c b/source4/torture/smb2/durable_open.c
index bb32f96..fe0a326 100644
--- a/source4/torture/smb2/durable_open.c
+++ b/source4/torture/smb2/durable_open.c
@@ -2112,7 +2112,7 @@ static bool test_durable_open_open2_lease(struct torture_context *tctx,
 	status = smb2_create(tree2, mem_ctx, &io2);
 	CHECK_STATUS(status, NT_STATUS_OK);
 	h2 = io2.out.file.handle;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
 
 	/* Reconnect */
 	if (!torture_smb2_connection_ext(tctx, 0, &options, &tree1)) {
diff --git a/source4/torture/smb2/rename.c b/source4/torture/smb2/rename.c
old mode 100644
new mode 100755
index 07bdabd..23fe4f9
--- a/source4/torture/smb2/rename.c
+++ b/source4/torture/smb2/rename.c
@@ -1403,7 +1403,7 @@ struct torture_suite *torture_smb2_rename_init(void)
 	torture_suite_add_1smb2_test(suite, "simple",
 		torture_smb2_rename_simple);
 
-	torture_suite_add_1smb2_test(suite, "simple_nodelete)",
+	torture_suite_add_1smb2_test(suite, "simple_nodelete",
 		torture_smb2_rename_simple2);
 
 	torture_suite_add_1smb2_test(suite, "no_sharing",
diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c
index e4f5b01..c32533b 100644
--- a/source4/torture/smb2/replay.c
+++ b/source4/torture/smb2/replay.c
@@ -85,6 +85,11 @@
 		__IO_OUT_VAL(__io1, __io2, persistent_open);	\
 		__IO_OUT_VAL(__io1, __io2, timeout);		\
 		__IO_OUT_VAL(__io1, __io2, blobs.num_blobs);	\
+		if ((__io1)->out.oplock_level == SMB2_OPLOCK_LEVEL_LEASE) { \
+			__IO_OUT_VAL(__io1, __io2, lease_response.lease_state);\
+			__IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[0]);\
+			__IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[1]);\
+		} \
 	} while(0)
 
 #define BASEDIR "replaytestdir"
@@ -161,7 +166,7 @@ static bool torture_oplock_ack_handler(struct smb2_transport *transport,
  * Test what happens when SMB2_FLAGS_REPLAY_OPERATION is enabled for various
  * commands. We want to verify if the server returns an error code or not.
  */
-static bool test_replay1(struct torture_context *tctx, struct smb2_tree *tree)
+static bool test_replay_commands(struct torture_context *tctx, struct smb2_tree *tree)
 {
 	bool ret = true;
 	NTSTATUS status;
@@ -175,7 +180,7 @@ static bool test_replay1(struct torture_context *tctx, struct smb2_tree *tree)
 	struct smb2_lock_element el[2];
 	struct smb2_flush f;
 	TALLOC_CTX *tmp_ctx = talloc_new(tree);
-	const char *fname = BASEDIR "\\replay1.dat";
+	const char *fname = BASEDIR "\\replay_commands.dat";
 	struct smb2_transport *transport = tree->session->transport;
 
 	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
@@ -287,10 +292,218 @@ done:
 }
 
 /**
- * Test Durablity V2 Create Replay Detection on Single Channel. Also verify that
- * regular creates can not be replayed.
+ * Test replay detection without create GUID on single channel.
+ * Regular creates can not be replayed.
+ * The return code is unaffected of the REPLAY_OPERATION flag.
  */
-static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree)
+static bool test_replay_regular(struct torture_context *tctx,
+				struct smb2_tree *tree)
+{
+	NTSTATUS status;
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_handle _h;
+	struct smb2_handle *h = NULL;
+	struct smb2_create io;
+	uint32_t perms = 0;
+	bool ret = true;
+	const char *fname = BASEDIR "\\replay_regular.dat";
+	struct smb2_transport *transport = tree->session->transport;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				   "replay tests\n");
+	}
+
+	ZERO_STRUCT(break_info);
+	break_info.tctx = tctx;
+	tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+	tree->session->transport->oplock.private_data = tree;
+
+	smb2_util_unlink(tree, fname);
+	status = torture_smb2_testdir(tree, BASEDIR, &_h);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree, _h);
+	CHECK_VAL(break_info.count, 0);
+
+	torture_comment(tctx, "No replay detection for regular create\n");
+
+	perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
+		SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+		SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
+		SEC_FILE_WRITE_DATA;
+
+	io = (struct smb2_create) {
+		.in.desired_access  = perms,
+		.in.file_attributes = 0,
+		.in.create_disposition = NTCREATEX_DISP_CREATE,
+		.in.share_access    = NTCREATEX_SHARE_ACCESS_DELETE,
+		.in.create_options  = 0x0,
+		.in.fname   = fname
+	};
+
+	status = smb2_create(tree, tctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_VAL(break_info.count, 0);
+	_h = io.out.file.handle;
+	h = &_h;
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	status = smb2_create(tree, tctx, &io);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+	CHECK_VAL(break_info.count, 0);
+
+	smb2_util_close(tree, *h);
+	h = NULL;
+	smb2_util_unlink(tree, fname);
+
+	/*
+	 * Same experiment with different create disposition.
+	 */
+	io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+	status = smb2_create(tree, tctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_VAL(break_info.count, 0);
+	_h = io.out.file.handle;
+	h = &_h;
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	status = smb2_create(tree, tctx, &io);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+	CHECK_VAL(break_info.count, 0);
+
+	smb2_util_close(tree, *h);
+	h = NULL;
+	smb2_util_unlink(tree, fname);
+
+	/*
+	 * Now with more generous share mode.
+	 */
+	io.in.share_access = smb2_util_share_access("RWD");
+	status = smb2_create(tree, tctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_VAL(break_info.count, 0);
+	_h = io.out.file.handle;
+	h = &_h;
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	status = smb2_create(tree, tctx, &io);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_VAL(break_info.count, 0);
+
+done:
+	if (h != NULL) {
+		smb2_util_close(tree, *h);
+	}
+	smb2_deltree(tree, BASEDIR);
+
+	talloc_free(tree);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+/**
+ * Test Durablity V2 Create Replay Detection on Single Channel.
+ */
+static bool test_replay_dhv2_oplock1(struct torture_context *tctx,
+				     struct smb2_tree *tree)
+{
+	NTSTATUS status;
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_handle _h;
+	struct smb2_handle *h = NULL;
+	struct smb2_create io, ref1;
+	struct GUID create_guid = GUID_random();
+	bool ret = true;
+	const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
+	struct smb2_transport *transport = tree->session->transport;
+	uint32_t share_capabilities;
+	bool share_is_so;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				   "replay tests\n");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+	ZERO_STRUCT(break_info);
+	break_info.tctx = tctx;
+	tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+	tree->session->transport->oplock.private_data = tree;
+
+	torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
+			      "Channel\n");
+	smb2_util_unlink(tree, fname);
+	status = torture_smb2_testdir(tree, BASEDIR, &_h);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree, _h);
+	CHECK_VAL(break_info.count, 0);
+
+	smb2_oplock_create_share(&io, fname,
+			smb2_util_share_access(""),
+			smb2_util_oplock_level("b"));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = false;
+	io.in.create_guid = create_guid;
+	io.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	ref1 = io;
+	_h = io.out.file.handle;
+	h = &_h;
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io.out.durable_open, false);
+	if (share_is_so) {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+		CHECK_VAL(io.out.durable_open_v2, false);
+		CHECK_VAL(io.out.timeout, 0);
+	} else {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+		CHECK_VAL(io.out.durable_open_v2, true);
+		CHECK_VAL(io.out.timeout, io.in.timeout);
+	}
+
+	/*
+	 * Replay Durable V2 Create on single channel
+	 */
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	status = smb2_create(tree, mem_ctx, &io);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_CREATE_OUT(&io, &ref1);
+	CHECK_VAL(break_info.count, 0);
+
+done:
+	if (h != NULL) {
+		smb2_util_close(tree, *h);
+	}
+	smb2_deltree(tree, BASEDIR);
+
+	talloc_free(tree);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+/**
+ * Test Durablity V2 Create Replay Detection on Single Channel.
+ * Hand in a different oplock level in the replay.
+ * Server responds with the handed in oplock level and
+ * corresponding durable status, but does not change the
+ * oplock level or durable status of the opened file.
+ */
+static bool test_replay_dhv2_oplock2(struct torture_context *tctx,
+				      struct smb2_tree *tree)
 {
 	NTSTATUS status;
 	TALLOC_CTX *mem_ctx = talloc_new(tctx);
@@ -298,149 +511,914 @@ static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree)
 	struct smb2_handle *h = NULL;
 	struct smb2_create io, ref1, ref2;
 	struct GUID create_guid = GUID_random();
-	uint32_t perms = 0;
 	bool ret = true;
-	const char *fname = BASEDIR "\\replay2.dat";
+	const char *fname = BASEDIR "\\replay_dhv2_oplock2.dat";
+	struct smb2_transport *transport = tree->session->transport;
+	uint32_t share_capabilities;
+	bool share_is_so;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				   "replay tests\n");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+	ZERO_STRUCT(break_info);
+	break_info.tctx = tctx;
+	tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+	tree->session->transport->oplock.private_data = tree;
+
+	torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
+			      "Channel\n");
+	smb2_util_unlink(tree, fname);
+	status = torture_smb2_testdir(tree, BASEDIR, &_h);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree, _h);
+	CHECK_VAL(break_info.count, 0);
+
+	smb2_oplock_create_share(&io, fname,
+			smb2_util_share_access(""),
+			smb2_util_oplock_level("b"));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = false;
+	io.in.create_guid = create_guid;
+	io.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	ref1 = io;
+	_h = io.out.file.handle;
+	h = &_h;
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io.out.durable_open, false);
+	if (share_is_so) {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+		CHECK_VAL(io.out.durable_open_v2, false);
+		CHECK_VAL(io.out.timeout, 0);
+	} else {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+		CHECK_VAL(io.out.durable_open_v2, true);
+		CHECK_VAL(io.out.timeout, io.in.timeout);
+	}
+
+	/*
+	 * Replay durable v2 create on single channel:
+	 *
+	 * Replay the create with a different oplock (none).
+	 * The server replies with the requested oplock level
+	 * and also only replies with durable handle based
+	 * on whether it could have been granted based on
+	 * the requested oplock type.
+	 */
+	smb2_oplock_create_share(&io, fname,
+			smb2_util_share_access(""),
+			smb2_util_oplock_level(""));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = false;
+	io.in.create_guid = create_guid;
+	io.in.timeout = UINT32_MAX;
+
+	/*
+	 * Adapt the response to the exepected values
+	 */
+	ref2 = ref1;
+	ref2.out.oplock_level = smb2_util_oplock_level("");
+	ref2.out.durable_open_v2 = false;
+	ref2.out.timeout = 0;
+	ref2.out.blobs.num_blobs = 0;
+
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	status = smb2_create(tree, mem_ctx, &io);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_CREATE_OUT(&io, &ref2);
+	CHECK_VAL(break_info.count, 0);
+
+	/*
+	 * Prove that the open file still has a batch oplock
+	 * by breaking it with another open.
+	 */
+	smb2_oplock_create_share(&io, fname,
+			smb2_util_share_access(""),
+			smb2_util_oplock_level("b"));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = false;
+	io.in.create_guid = GUID_random();
+	io.in.timeout = UINT32_MAX;
+	status = smb2_create(tree, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+	if (!share_is_so) {
+		CHECK_VAL(break_info.count, 1);
+		CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle);
+		CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
+		ZERO_STRUCT(break_info);
+	}
+
+done:
+	if (h != NULL) {
+		smb2_util_close(tree, *h);
+	}
+	smb2_deltree(tree, BASEDIR);
+
+	talloc_free(tree);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+/**
+ * Test Durablity V2 Create Replay Detection on Single Channel.
+ * Replay with a different share mode. The share mode of
+ * the opened file is not changed by this.
+ */
+static bool test_replay_dhv2_oplock3(struct torture_context *tctx,
+				     struct smb2_tree *tree)
+{
+	NTSTATUS status;
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_handle _h;
+	struct smb2_handle *h = NULL;
+	struct smb2_create io, ref1;
+	struct GUID create_guid = GUID_random();
+	bool ret = true;
+	const char *fname = BASEDIR "\\replay_dhv2_oplock3.dat";
+	struct smb2_transport *transport = tree->session->transport;
+	uint32_t share_capabilities;
+	bool share_is_so;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				   "replay tests\n");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+	ZERO_STRUCT(break_info);
+	break_info.tctx = tctx;
+	tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+	tree->session->transport->oplock.private_data = tree;
+
+	torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
+			      "Channel\n");
+	smb2_util_unlink(tree, fname);
+	status = torture_smb2_testdir(tree, BASEDIR, &_h);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree, _h);
+	CHECK_VAL(break_info.count, 0);
+
+	smb2_oplock_create_share(&io, fname,
+			smb2_util_share_access(""),
+			smb2_util_oplock_level("b"));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = false;
+	io.in.create_guid = create_guid;
+	io.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	ref1 = io;
+	_h = io.out.file.handle;
+	h = &_h;
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io.out.durable_open, false);
+	if (share_is_so) {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+		CHECK_VAL(io.out.durable_open_v2, false);
+		CHECK_VAL(io.out.timeout, 0);
+	} else {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+		CHECK_VAL(io.out.durable_open_v2, true);
+		CHECK_VAL(io.out.timeout, io.in.timeout);
+	}
+
+	/*
+	 * Replay durable v2 create on single channel:
+	 *
+	 * Replay the create with a different share mode.
+	 * The server replies with the requested share
+	 * mode instead of that which is associated to
+	 * the handle.
+	 */
+	smb2_oplock_create_share(&io, fname,
+			smb2_util_share_access("RWD"),
+			smb2_util_oplock_level("b"));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = false;
+	io.in.create_guid = create_guid;
+	io.in.timeout = UINT32_MAX;
+
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	status = smb2_create(tree, mem_ctx, &io);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_CREATE_OUT(&io, &ref1);
+	CHECK_VAL(break_info.count, 0);
+
+	/*
+	 * In order to prove that the different share mode in the
+	 * replayed create had no effect on the open file handle,
+	 * show that a new create yields NT_STATUS_SHARING_VIOLATION.
+	 */
+	smb2_oplock_create_share(&io, fname,
+			smb2_util_share_access(""),
+			smb2_util_oplock_level("b"));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = false;
+	io.in.create_guid = GUID_random();
+	io.in.timeout = UINT32_MAX;
+	status = smb2_create(tree, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+	if (!share_is_so) {
+		CHECK_VAL(break_info.count, 1);
+		CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle);
+		CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
+		ZERO_STRUCT(break_info);
+	}
+
+done:
+	if (h != NULL) {
+		smb2_util_close(tree, *h);
+	}
+	smb2_deltree(tree, BASEDIR);
+
+	talloc_free(tree);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+/**
+ * Test Durablity V2 Create Replay Detection on Single Channel.
+ * Create with an oplock, and replay with a lease.
+ */
+static bool test_replay_dhv2_oplock_lease(struct torture_context *tctx,
+					  struct smb2_tree *tree)
+{
+	NTSTATUS status;
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_handle _h;
+	struct smb2_handle *h = NULL;
+	struct smb2_create io;
+	struct GUID create_guid = GUID_random();
+	bool ret = true;
+	const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
+	struct smb2_transport *transport = tree->session->transport;
+	uint32_t share_capabilities;
+	bool share_is_so;
+	uint32_t server_capabilities;
+	struct smb2_lease ls;
+	uint64_t lease_key;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				   "replay tests\n");
+	}
+
+	server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+	if (!(server_capabilities & SMB2_CAP_LEASING)) {
+		torture_skip(tctx, "leases are not supported");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+	ZERO_STRUCT(break_info);
+	break_info.tctx = tctx;
+	tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+	tree->session->transport->oplock.private_data = tree;
+
+	torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
+			      "Channel\n");
+	smb2_util_unlink(tree, fname);
+	status = torture_smb2_testdir(tree, BASEDIR, &_h);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree, _h);
+	CHECK_VAL(break_info.count, 0);
+
+	smb2_oplock_create_share(&io, fname,
+			smb2_util_share_access(""),
+			smb2_util_oplock_level("b"));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = false;
+	io.in.create_guid = create_guid;
+	io.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	_h = io.out.file.handle;
+	h = &_h;
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io.out.durable_open, false);
+	if (share_is_so) {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+		CHECK_VAL(io.out.durable_open_v2, false);
+		CHECK_VAL(io.out.timeout, 0);
+	} else {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+		CHECK_VAL(io.out.durable_open_v2, true);
+		CHECK_VAL(io.out.timeout, io.in.timeout);
+	}
+
+	/*
+	 * Replay Durable V2 Create on single channel
+	 * but replay it with a lease instead of an oplock.
+	 */
+	lease_key = random();
+	smb2_lease_create(&io, &ls, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("RH"));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = false;
+	io.in.create_guid = create_guid;
+	io.in.timeout = UINT32_MAX;
+
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	status = smb2_create(tree, mem_ctx, &io);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+done:
+	if (h != NULL) {
+		smb2_util_close(tree, *h);
+	}
+	smb2_deltree(tree, BASEDIR);
+
+	talloc_free(tree);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+
+/**
+ * Test durablity v2 create replay detection on single channel.
+ * Variant with leases instead of oplocks:
+ * - open a file with a rh lease
+ * - upgrade to a rwh lease with a second create
+ * - replay the first create.
+ *   ==> it gets back the upgraded lease level
+ */
+static bool test_replay_dhv2_lease1(struct torture_context *tctx,
+				    struct smb2_tree *tree)
+{
+	NTSTATUS status;
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_handle _h1;
+	struct smb2_handle *h1 = NULL;
+	struct smb2_handle _h2;
+	struct smb2_handle *h2 = NULL;
+	struct smb2_create io1, io2, ref1;
+	struct GUID create_guid = GUID_random();
+	bool ret = true;
+	const char *fname = BASEDIR "\\replay2_lease1.dat";
+	struct smb2_transport *transport = tree->session->transport;
+	uint32_t share_capabilities;
+	bool share_is_so;
+	uint32_t server_capabilities;
+	struct smb2_lease ls1, ls2;
+	uint64_t lease_key;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				   "replay tests\n");
+	}
+
+	server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+	if (!(server_capabilities & SMB2_CAP_LEASING)) {
+		torture_skip(tctx, "leases are not supported");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+	ZERO_STRUCT(break_info);
+	break_info.tctx = tctx;
+	tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+	tree->session->transport->oplock.private_data = tree;
+
+	torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
+			      "on Single Channel\n");
+	smb2_util_unlink(tree, fname);
+	status = torture_smb2_testdir(tree, BASEDIR, &_h1);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree, _h1);
+	CHECK_VAL(break_info.count, 0);
+
+	lease_key = random();
+
+	smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("RH"));
+	io1.in.durable_open = false;
+	io1.in.durable_open_v2 = true;
+	io1.in.persistent_open = false;
+	io1.in.create_guid = create_guid;
+	io1.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io1);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	ref1 = io1;
+	_h1 = io1.out.file.handle;
+	h1 = &_h1;
+	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io1.out.durable_open, false);
+	CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+	CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
+	CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
+	if (share_is_so) {
+		CHECK_VAL(io1.out.lease_response.lease_state,
+			  smb2_util_lease_state("R"));
+		CHECK_VAL(io1.out.durable_open_v2, false);
+		CHECK_VAL(io1.out.timeout, 0);
+	} else {
+		CHECK_VAL(io1.out.lease_response.lease_state,
+			  smb2_util_lease_state("RH"));
+		CHECK_VAL(io1.out.durable_open_v2, true);
+		CHECK_VAL(io1.out.timeout, io1.in.timeout);
+	}
+
+	/*
+	 * Upgrade the lease to RWH
+	 */
+	smb2_lease_create(&io2, &ls2, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("RHW"));
+	io2.in.durable_open = false;
+	io2.in.durable_open_v2 = true;
+	io2.in.persistent_open = false;
+	io2.in.create_guid = GUID_random(); /* new guid... */
+	io2.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	_h2 = io2.out.file.handle;
+	h2 = &_h2;
+
+	/*
+	 * Replay Durable V2 Create on single channel.
+	 * We get the io from open #1 but with the
+	 * upgraded lease.
+	 */
+
+	/* adapt expected lease in response */
+	if (!share_is_so) {
+		ref1.out.lease_response.lease_state =
+			smb2_util_lease_state("RHW");
+	}
+
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	status = smb2_create(tree, mem_ctx, &io1);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_CREATE_OUT(&io1, &ref1);
+	CHECK_VAL(break_info.count, 0);
+
+done:
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+
+	if (h1 != NULL) {
+		smb2_util_close(tree, *h1);
+	}
+	if (h2 != NULL) {
+		smb2_util_close(tree, *h2);
+	}
+	smb2_deltree(tree, BASEDIR);
+
+	talloc_free(tree);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+/**
+ * Test durablity v2 create replay detection on single channel.
+ * Variant with leases instead of oplocks, where the
+ * replay does not specify the original lease level but
+ * just a "R" lease. This still gives the upgraded lease
+ * level in the reply.
+ * - open a file with a rh lease
+ * - upgrade to a rwh lease with a second create
+ * - replay the first create.
+ *   ==> it gets back the upgraded lease level
+ */
+static bool test_replay_dhv2_lease2(struct torture_context *tctx,
+				    struct smb2_tree *tree)
+{
+	NTSTATUS status;
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_handle _h1;
+	struct smb2_handle *h1 = NULL;
+	struct smb2_handle _h2;
+	struct smb2_handle *h2 = NULL;
+	struct smb2_create io1, io2, ref1;
+	struct GUID create_guid = GUID_random();
+	bool ret = true;
+	const char *fname = BASEDIR "\\replay2_lease2.dat";
+	struct smb2_transport *transport = tree->session->transport;
+	uint32_t share_capabilities;
+	bool share_is_so;
+	uint32_t server_capabilities;
+	struct smb2_lease ls1, ls2;
+	uint64_t lease_key;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				   "replay tests\n");
+	}
+
+	server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+	if (!(server_capabilities & SMB2_CAP_LEASING)) {
+		torture_skip(tctx, "leases are not supported");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+	ZERO_STRUCT(break_info);
+	break_info.tctx = tctx;
+	tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+	tree->session->transport->oplock.private_data = tree;
+
+	torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
+			      "on Single Channel\n");
+	smb2_util_unlink(tree, fname);
+	status = torture_smb2_testdir(tree, BASEDIR, &_h1);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree, _h1);
+	CHECK_VAL(break_info.count, 0);
+
+	lease_key = random();
+
+	smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("RH"));
+	io1.in.durable_open = false;
+	io1.in.durable_open_v2 = true;
+	io1.in.persistent_open = false;
+	io1.in.create_guid = create_guid;
+	io1.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io1);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io1.out.durable_open, false);
+	CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+	CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
+	CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
+	if (share_is_so) {
+		CHECK_VAL(io1.out.lease_response.lease_state,
+			  smb2_util_lease_state("R"));
+		CHECK_VAL(io1.out.durable_open_v2, false);
+		CHECK_VAL(io1.out.timeout, 0);
+	} else {
+		CHECK_VAL(io1.out.lease_response.lease_state,
+			  smb2_util_lease_state("RH"));
+		CHECK_VAL(io1.out.durable_open_v2, true);
+		CHECK_VAL(io1.out.timeout, io1.in.timeout);
+	}
+	ref1 = io1;
+	_h1 = io1.out.file.handle;
+	h1 = &_h1;
+
+	/*
+	 * Upgrade the lease to RWH
+	 */
+	smb2_lease_create(&io2, &ls2, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("RHW"));
+	io2.in.durable_open = false;
+	io2.in.durable_open_v2 = true;
+	io2.in.persistent_open = false;
+	io2.in.create_guid = GUID_random(); /* new guid... */
+	io2.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	_h2 = io2.out.file.handle;
+	h2 = &_h2;
+
+	/*
+	 * Replay Durable V2 Create on single channel.
+	 * Changing the requested lease level to "R"
+	 * does not change the response:
+	 * We get the reply from open #1 but with the
+	 * upgraded lease.
+	 */
+
+	/* adapt the expected response */
+	if (!share_is_so) {
+		ref1.out.lease_response.lease_state =
+					smb2_util_lease_state("RHW");
+	}
+
+	smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("R"));
+	io1.in.durable_open = false;
+	io1.in.durable_open_v2 = true;
+	io1.in.persistent_open = false;
+	io1.in.create_guid = create_guid;
+	io1.in.timeout = UINT32_MAX;
+
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	status = smb2_create(tree, mem_ctx, &io1);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_CREATE_OUT(&io1, &ref1);
+	CHECK_VAL(break_info.count, 0);
+
+done:
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+
+	if (h1 != NULL) {
+		smb2_util_close(tree, *h1);
+	}
+	if (h2 != NULL) {
+		smb2_util_close(tree, *h2);
+	}
+	smb2_deltree(tree, BASEDIR);
+
+	talloc_free(tree);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+/**
+ * Test durablity v2 create replay detection on single channel.
+ * create with a lease, and replay with a different lease key
+ */
+static bool test_replay_dhv2_lease3(struct torture_context *tctx,
+				    struct smb2_tree *tree)
+{
+	NTSTATUS status;
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_handle _h1;
+	struct smb2_handle *h1 = NULL;
+	struct smb2_handle _h2;
+	struct smb2_handle *h2 = NULL;
+	struct smb2_create io1, io2;
+	struct GUID create_guid = GUID_random();
+	bool ret = true;
+	const char *fname = BASEDIR "\\replay2_lease2.dat";
 	struct smb2_transport *transport = tree->session->transport;
+	uint32_t share_capabilities;
+	bool share_is_so;
+	uint32_t server_capabilities;
+	struct smb2_lease ls1, ls2;
+	uint64_t lease_key;
 
 	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
 		torture_skip(tctx, "SMB 3.X Dialect family required for "
 				   "replay tests\n");
 	}
 
+	server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+	if (!(server_capabilities & SMB2_CAP_LEASING)) {
+		torture_skip(tctx, "leases are not supported");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
 	ZERO_STRUCT(break_info);
 	break_info.tctx = tctx;
 	tree->session->transport->oplock.handler = torture_oplock_ack_handler;
 	tree->session->transport->oplock.private_data = tree;
 
-	torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
-			      "Channel\n");
+	torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
+			      "on Single Channel\n");
 	smb2_util_unlink(tree, fname);
-	status = torture_smb2_testdir(tree, BASEDIR, &_h);
+	status = torture_smb2_testdir(tree, BASEDIR, &_h1);
 	CHECK_STATUS(status, NT_STATUS_OK);
-	smb2_util_close(tree, _h);
+	smb2_util_close(tree, _h1);
 	CHECK_VAL(break_info.count, 0);
 
-	smb2_oplock_create_share(&io, fname,
-			smb2_util_share_access(""),
-			smb2_util_oplock_level("b"));
-	io.in.durable_open = false;
-	io.in.durable_open_v2 = true;
-	io.in.persistent_open = false;
-	io.in.create_guid = create_guid;
-	io.in.timeout = UINT32_MAX;
+	lease_key = random();
 
-	status = smb2_create(tree, mem_ctx, &io);
+	smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("RH"));
+	io1.in.durable_open = false;
+	io1.in.durable_open_v2 = true;
+	io1.in.persistent_open = false;
+	io1.in.create_guid = create_guid;
+	io1.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io1);
 	CHECK_STATUS(status, NT_STATUS_OK);
-	ref1 = io;
-	_h = io.out.file.handle;
-	h = &_h;
-	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
-	CHECK_VAL(io.out.durable_open, false);
-	CHECK_VAL(io.out.durable_open_v2, true);
-	CHECK_VAL(io.out.timeout, io.in.timeout);
+	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io1.out.durable_open, false);
+	CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+	CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
+	CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
+	if (share_is_so) {
+		CHECK_VAL(io1.out.lease_response.lease_state,
+			  smb2_util_lease_state("R"));
+		CHECK_VAL(io1.out.durable_open_v2, false);
+		CHECK_VAL(io1.out.timeout, 0);
+	} else {
+		CHECK_VAL(io1.out.lease_response.lease_state,
+			  smb2_util_lease_state("RH"));
+		CHECK_VAL(io1.out.durable_open_v2, true);
+		CHECK_VAL(io1.out.timeout, io1.in.timeout);
+	}
+	_h1 = io1.out.file.handle;
+	h1 = &_h1;
 
 	/*
-	 * Replay Durable V2 Create on single channel
+	 * Upgrade the lease to RWH
 	 */
-	smb2cli_session_start_replay(tree->session->smbXcli);
-	status = smb2_create(tree, mem_ctx, &io);
-	smb2cli_session_stop_replay(tree->session->smbXcli);
+	smb2_lease_create(&io2, &ls2, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("RHW"));
+	io2.in.durable_open = false;
+	io2.in.durable_open_v2 = true;
+	io2.in.persistent_open = false;
+	io2.in.create_guid = GUID_random(); /* new guid... */
+	io2.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io2);
 	CHECK_STATUS(status, NT_STATUS_OK);
-	CHECK_CREATE_OUT(&io, &ref1);
-	CHECK_VAL(break_info.count, 0);
+	_h2 = io2.out.file.handle;
+	h2 = &_h2;
 
 	/*
-	 * See how server behaves if we change some of the Create params while
-	 * Replaying. Change Share Access and Oplock Level. It seems the server
-	 * does not care for change in these parameters. The server seems to
-	 * only care for the File Name and GUID
+	 * Replay Durable V2 Create on single channel.
+	 * use a different lease key.
 	 */
-	smb2_oplock_create_share(&io, fname,
-			smb2_util_share_access("RWD"),
-			smb2_util_oplock_level(""));
-	io.in.durable_open = false;
-	io.in.durable_open_v2 = true;
-	io.in.persistent_open = false;
-	io.in.create_guid = create_guid;
-	io.in.timeout = UINT32_MAX;
 
-	/*
-	 * The output will just react on the
-	 * input, but it doesn't change the oplock
-	 * or share access values on the existing open
-	 */
-	ref2 = ref1;
-	ref2.out.oplock_level = smb2_util_oplock_level("");
-	ref2.out.durable_open_v2 = false;
-	ref2.out.timeout = 0;
-	ref2.out.blobs.num_blobs = 0;
+	smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+			random() /* lease key */,
+			smb2_util_lease_state("RH"));
+	io1.in.durable_open = false;
+	io1.in.durable_open_v2 = true;
+	io1.in.persistent_open = false;
+	io1.in.create_guid = create_guid;
+	io1.in.timeout = UINT32_MAX;
 
 	smb2cli_session_start_replay(tree->session->smbXcli);
-	status = smb2_create(tree, mem_ctx, &io);
+	status = smb2_create(tree, mem_ctx, &io1);
 	smb2cli_session_stop_replay(tree->session->smbXcli);
-	CHECK_STATUS(status, NT_STATUS_OK);
-	CHECK_CREATE_OUT(&io, &ref2);
-	CHECK_VAL(break_info.count, 0);
+	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+done:
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+
+	if (h1 != NULL) {
+		smb2_util_close(tree, *h1);
+	}
+	if (h2 != NULL) {
+		smb2_util_close(tree, *h2);
+	}
+	smb2_deltree(tree, BASEDIR);
+
+	talloc_free(tree);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+/**
+ * Test durablity v2 create replay detection on single channel.
+ * Do the original create with a lease, and do the replay
+ * with an oplock.
+ */
+static bool test_replay_dhv2_lease_oplock(struct torture_context *tctx,
+					  struct smb2_tree *tree)
+{
+	NTSTATUS status;
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_handle _h1;
+	struct smb2_handle *h1 = NULL;
+	struct smb2_handle _h2;
+	struct smb2_handle *h2 = NULL;
+	struct smb2_create io1, io2, ref1;
+	struct GUID create_guid = GUID_random();
+	bool ret = true;
+	const char *fname = BASEDIR "\\replay2_lease1.dat";
+	struct smb2_transport *transport = tree->session->transport;
+	uint32_t share_capabilities;
+	bool share_is_so;
+	uint32_t server_capabilities;
+	struct smb2_lease ls1, ls2;
+	uint64_t lease_key;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				   "replay tests\n");
+	}
+
+	server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+	if (!(server_capabilities & SMB2_CAP_LEASING)) {
+		torture_skip(tctx, "leases are not supported");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
 
-	/*
-	 * This is a normal open, which triggers an oplock
-	 * break and still gets NT_STATUS_SHARING_VIOLATION
-	 */
-	io = ref1;
-	io.in.durable_open_v2 = false;
-	status = smb2_create(tree, mem_ctx, &io);
-	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
-	CHECK_VAL(break_info.count, 1);
-	CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle);
-	CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
 	ZERO_STRUCT(break_info);
+	break_info.tctx = tctx;
+	tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+	tree->session->transport->oplock.private_data = tree;
 
-	smb2_util_close(tree, *h);
-	h = NULL;
-	status = smb2_util_unlink(tree, fname);
+	torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
+			      "on Single Channel\n");
+	smb2_util_unlink(tree, fname);
+	status = torture_smb2_testdir(tree, BASEDIR, &_h1);
 	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree, _h1);
 	CHECK_VAL(break_info.count, 0);
 
-	/*
-	 * No Replay detection for regular Creates
-	 */
-	perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
-		SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
-		SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
-		SEC_FILE_WRITE_DATA;
+	lease_key = random();
 
-	io = (struct smb2_create) {
-		.in.desired_access  = perms,
-		.in.file_attributes = 0,
-		.in.create_disposition = NTCREATEX_DISP_CREATE,
-		.in.share_access    = NTCREATEX_SHARE_ACCESS_DELETE,
-		.in.create_options  = 0x0,
-		.in.fname   = fname
-	};
+	smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("RH"));
+	io1.in.durable_open = false;
+	io1.in.durable_open_v2 = true;
+	io1.in.persistent_open = false;
+	io1.in.create_guid = create_guid;
+	io1.in.timeout = UINT32_MAX;
 
-	status = smb2_create(tree, tctx, &io);
+	status = smb2_create(tree, mem_ctx, &io1);
 	CHECK_STATUS(status, NT_STATUS_OK);
-	CHECK_VAL(break_info.count, 0);
-	_h = io.out.file.handle;
-	h = &_h;
-	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	ref1 = io1;
+	_h1 = io1.out.file.handle;
+	h1 = &_h1;
+	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io1.out.durable_open, false);
+	CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+	CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
+	CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
+	if (share_is_so) {
+		CHECK_VAL(io1.out.lease_response.lease_state,
+			  smb2_util_lease_state("R"));
+		CHECK_VAL(io1.out.durable_open_v2, false);
+		CHECK_VAL(io1.out.timeout, 0);
+	} else {
+		CHECK_VAL(io1.out.lease_response.lease_state,
+			  smb2_util_lease_state("RH"));
+		CHECK_VAL(io1.out.durable_open_v2, true);
+		CHECK_VAL(io1.out.timeout, io1.in.timeout);
+	}
+
+	/*
+	 * Upgrade the lease to RWH
+	 */
+	smb2_lease_create(&io2, &ls2, false /* dir */, fname,
+			lease_key, smb2_util_lease_state("RHW"));
+	io2.in.durable_open = false;
+	io2.in.durable_open_v2 = true;
+	io2.in.persistent_open = false;
+	io2.in.create_guid = GUID_random(); /* new guid... */
+	io2.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	_h2 = io2.out.file.handle;
+	h2 = &_h2;
 
-	torture_comment(tctx, "No Replay Detection for regular Create\n");
 	/*
-	 * Now replay the same create
+	 * Replay Durable V2 Create on single channel.
+	 * We get the io from open #1 but with the
+	 * upgraded lease.
 	 */
+
+	smb2_oplock_create_share(&io2, fname,
+			smb2_util_share_access(""),
+			smb2_util_oplock_level("b"));
+	io2.in.durable_open = false;
+	io2.in.durable_open_v2 = true;
+	io2.in.persistent_open = false;
+	io2.in.create_guid = create_guid;
+	io2.in.timeout = UINT32_MAX;
+
+	/* adapt expected lease in response */
+	if (!share_is_so) {
+		ref1.out.lease_response.lease_state =
+			smb2_util_lease_state("RHW");
+	}
+
 	smb2cli_session_start_replay(tree->session->smbXcli);
-	status = smb2_create(tree, tctx, &io);
-	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+	status = smb2_create(tree, mem_ctx, &io1);
+	smb2cli_session_stop_replay(tree->session->smbXcli);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_CREATE_OUT(&io1, &ref1);
 	CHECK_VAL(break_info.count, 0);
 
 done:
 	smb2cli_session_stop_replay(tree->session->smbXcli);
 
-	if (h != NULL) {
-		smb2_util_close(tree, *h);
+	if (h1 != NULL) {
+		smb2_util_close(tree, *h1);
+	}
+	if (h2 != NULL) {
+		smb2_util_close(tree, *h2);
 	}
 	smb2_deltree(tree, BASEDIR);
 
@@ -471,12 +1449,25 @@ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1)
 	struct smb2_transport *transport2 = NULL;
 	struct smb2_session *session1_1 = tree1->session;
 	struct smb2_session *session1_2 = NULL;
+	uint32_t share_capabilities;
+	bool share_is_so;
+	uint32_t server_capabilities;
 
 	if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
 		torture_skip(tctx, "SMB 3.X Dialect family required for "
 				   "Replay tests\n");
 	}
 
+	server_capabilities = smb2cli_conn_server_capabilities(
+					tree1->session->transport->conn);
+	if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+		torture_skip(tctx,
+			     "Server does not support multi-channel.");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
 	ZERO_STRUCT(break_info);
 	break_info.tctx = tctx;
 	transport1->oplock.handler = torture_oplock_ack_handler;
@@ -508,10 +1499,16 @@ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1)
 	_h = io.out.file.handle;
 	h = &_h;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+	if (share_is_so) {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+		CHECK_VAL(io.out.durable_open_v2, false);
+		CHECK_VAL(io.out.timeout, 0);
+	} else {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+		CHECK_VAL(io.out.durable_open_v2, true);
+		CHECK_VAL(io.out.timeout, io.in.timeout);
+	}
 	CHECK_VAL(io.out.durable_open, false);
-	CHECK_VAL(io.out.durable_open_v2, true);
-	CHECK_VAL(io.out.timeout, io.in.timeout);
 	CHECK_VAL(break_info.count, 0);
 
 	status = smb2_connect(tctx,
@@ -557,10 +1554,16 @@ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1)
 	_h = io.out.file.handle;
 	h = &_h;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+	if (share_is_so) {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+		CHECK_VAL(io.out.durable_open_v2, false);
+		CHECK_VAL(io.out.timeout, 0);
+	} else {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+		CHECK_VAL(io.out.durable_open_v2, true);
+		CHECK_VAL(io.out.timeout, io.in.timeout);
+	}
 	CHECK_VAL(io.out.durable_open, false);
-	CHECK_VAL(io.out.durable_open_v2, true);
-	CHECK_VAL(io.out.timeout, io.in.timeout);
 	CHECK_VAL(break_info.count, 0);
 
 	tree1->session = session1_1;
@@ -609,12 +1612,25 @@ static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1)
 	struct smb2_session *session1_1 = tree1->session;
 	struct smb2_session *session1_2 = NULL;
 	uint16_t curr_cs;
+	uint32_t share_capabilities;
+	bool share_is_so;
+	uint32_t server_capabilities;
 
 	if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
 		torture_skip(tctx, "SMB 3.X Dialect family required for "
 				   "Replay tests\n");
 	}
 
+	server_capabilities = smb2cli_conn_server_capabilities(
+					tree1->session->transport->conn);
+	if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+		torture_skip(tctx,
+			     "Server does not support multi-channel.");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
 	ZERO_STRUCT(break_info);
 	break_info.tctx = tctx;
 	transport1->oplock.handler = torture_oplock_ack_handler;
@@ -646,10 +1662,16 @@ static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1)
 	_h1 = io.out.file.handle;
 	h1 = &_h1;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+	if (share_is_so) {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+		CHECK_VAL(io.out.durable_open_v2, false);
+		CHECK_VAL(io.out.timeout, 0);
+	} else {
+		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+		CHECK_VAL(io.out.durable_open_v2, true);
+		CHECK_VAL(io.out.timeout, io.in.timeout);
+	}
 	CHECK_VAL(io.out.durable_open, false);
-	CHECK_VAL(io.out.durable_open_v2, true);
-	CHECK_VAL(io.out.timeout, io.in.timeout);
 	CHECK_VAL(break_info.count, 0);
 
 	status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
@@ -790,7 +1812,11 @@ static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1)
 	smb2_util_close(tree1, *h1);
 	h1 = NULL;
 
-	CHECK_VAL(break_info.count, 0);
+	if (share_is_so) {
+		CHECK_VAL(break_info.count, 1);
+	} else {
+		CHECK_VAL(break_info.count, 0);
+	}
 done:
 	talloc_free(tree2);
 	tree1->session = session1_1;
@@ -808,15 +1834,146 @@ done:
 	return ret;
 }
 
+/**
+ * Test Durablity V2 Persistent Create Replay on a Single Channel
+ */
+static bool test_replay5(struct torture_context *tctx, struct smb2_tree *tree)
+{
+	NTSTATUS status;
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_handle _h;
+	struct smb2_handle *h = NULL;
+	struct smb2_create io;
+	struct GUID create_guid = GUID_random();
+	bool ret = true;
+	uint32_t share_capabilities;
+	bool share_is_ca;
+	bool share_is_so;
+	uint32_t server_capabilities;
+	const char *fname = BASEDIR "\\replay5.dat";
+	struct smb2_transport *transport = tree->session->transport;
+	struct smbcli_options options = tree->session->transport->options;
+	uint8_t expect_oplock = smb2_util_oplock_level("b");
+	NTSTATUS expect_status = NT_STATUS_DUPLICATE_OBJECTID;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				"Replay tests\n");
+	}
+
+	server_capabilities = smb2cli_conn_server_capabilities(
+					tree->session->transport->conn);
+	if (!(server_capabilities & SMB2_CAP_PERSISTENT_HANDLES)) {
+		torture_skip(tctx,
+			     "Server does not support persistent handles.");
+	}
+
+	share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+
+	share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
+	if (!share_is_ca) {
+		torture_skip(tctx, "Share is not continuously available.");
+	}
+
+	share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+	if (share_is_so) {
+		expect_oplock = smb2_util_oplock_level("s");
+		expect_status = NT_STATUS_FILE_NOT_AVAILABLE;
+	}
+
+	ZERO_STRUCT(break_info);
+	break_info.tctx = tctx;
+	transport->oplock.handler = torture_oplock_ack_handler;
+	transport->oplock.private_data = tree;
+
+	torture_comment(tctx, "Replay of Persistent DurableHandleReqV2 on Single "
+			"Channel\n");
+	status = torture_smb2_testdir(tree, BASEDIR, &_h);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree, _h);
+	smb2_util_unlink(tree, fname);
+	CHECK_VAL(break_info.count, 0);
+
+	smb2_oplock_create_share(&io, fname,
+			smb2_util_share_access("RWD"),
+			smb2_util_oplock_level("b"));
+	io.in.durable_open = false;
+	io.in.durable_open_v2 = true;
+	io.in.persistent_open = true;
+	io.in.create_guid = create_guid;
+	io.in.timeout = UINT32_MAX;
+
+	status = smb2_create(tree, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	_h = io.out.file.handle;
+	h = &_h;
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io.out.oplock_level, expect_oplock);
+	CHECK_VAL(io.out.durable_open, false);
+	CHECK_VAL(io.out.durable_open_v2, true);
+	CHECK_VAL(io.out.persistent_open, true);
+	CHECK_VAL(io.out.timeout, io.in.timeout);
+	CHECK_VAL(break_info.count, 0);
+
+	/* disconnect, leaving the durable open */
+	TALLOC_FREE(tree);
+
+	if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+		torture_warning(tctx, "couldn't reconnect, bailing\n");
+		ret = false;
+		goto done;
+	}
+
+	/* a re-open of a persistent handle causes an error */
+	status = smb2_create(tree, mem_ctx, &io);
+	CHECK_STATUS(status, expect_status);
+
+	/* SMB2_FLAGS_REPLAY_OPERATION must be set to open the Persistent Handle */
+	smb2cli_session_start_replay(tree->session->smbXcli);
+	smb2cli_session_increment_channel_sequence(tree->session->smbXcli);
+	status = smb2_create(tree, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_VAL(io.out.durable_open, false);
+	CHECK_VAL(io.out.persistent_open, true);
+	CHECK_VAL(io.out.oplock_level, expect_oplock);
+	_h = io.out.file.handle;
+	h = &_h;
+
+	smb2_util_close(tree, *h);
+	h = NULL;
+done:
+	if (h != NULL) {
+		smb2_util_close(tree, *h);
+	}
+
+	smb2_util_unlink(tree, fname);
+	smb2_deltree(tree, BASEDIR);
+
+	talloc_free(tree);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
 struct torture_suite *torture_smb2_replay_init(void)
 {
 	struct torture_suite *suite =
 		torture_suite_create(talloc_autofree_context(), "replay");
 
-	torture_suite_add_1smb2_test(suite, "replay1", test_replay1);
-	torture_suite_add_1smb2_test(suite, "replay2", test_replay2);
+	torture_suite_add_1smb2_test(suite, "replay-commands", test_replay_commands);
+	torture_suite_add_1smb2_test(suite, "replay-regular", test_replay_regular);
+	torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock1", test_replay_dhv2_oplock1);
+	torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock2", test_replay_dhv2_oplock2);
+	torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3);
+	torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock-lease", test_replay_dhv2_oplock_lease);
+	torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1",  test_replay_dhv2_lease1);
+	torture_suite_add_1smb2_test(suite, "replay-dhv2-lease2",  test_replay_dhv2_lease2);
+	torture_suite_add_1smb2_test(suite, "replay-dhv2-lease3",  test_replay_dhv2_lease3);
+	torture_suite_add_1smb2_test(suite, "replay-dhv2-lease-oplock",  test_replay_dhv2_lease_oplock);
 	torture_suite_add_1smb2_test(suite, "replay3", test_replay3);
 	torture_suite_add_1smb2_test(suite, "replay4", test_replay4);
+	torture_suite_add_1smb2_test(suite, "replay5", test_replay5);
 
 	suite->description = talloc_strdup(suite, "SMB2 REPLAY tests");
 
diff --git a/source4/torture/smb2/session.c b/source4/torture/smb2/session.c
index 798230b..9d7cc4b 100644
--- a/source4/torture/smb2/session.c
+++ b/source4/torture/smb2/session.c
@@ -31,31 +31,22 @@
 #include "libcli/resolve/resolve.h"
 #include "lib/param/param.h"
 
-#define CHECK_VAL(v, correct) do { \
-	if ((v) != (correct)) { \
-		torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
-				__location__, #v, (int)v, (int)correct); \
-		ret = false; \
-	}} while (0)
-
-#define CHECK_STATUS(status, correct) do { \
-	if (!NT_STATUS_EQUAL(status, correct)) { \
-		torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
-		       nt_errstr(status), nt_errstr(correct)); \
-		ret = false; \
-		goto done; \
-	}} while (0)
-
-#define CHECK_CREATED(__io, __created, __attribute)			\
-	do {								\
-		CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
-		CHECK_VAL((__io)->out.alloc_size, 0);			\
-		CHECK_VAL((__io)->out.size, 0);				\
-		CHECK_VAL((__io)->out.file_attr, (__attribute));	\
-		CHECK_VAL((__io)->out.reserved2, 0);			\
+#define CHECK_CREATED(tctx, __io, __created, __attribute)			\
+	do {									\
+		torture_assert_int_equal(tctx, (__io)->out.create_action,	\
+						NTCREATEX_ACTION_ ## __created,	\
+						"out.create_action incorrect");	\
+		torture_assert_int_equal(tctx, (__io)->out.alloc_size, 0,	\
+						"out.alloc_size incorrect");	\
+		torture_assert_int_equal(tctx, (__io)->out.size, 0,		\
+						"out.size incorrect");		\
+		torture_assert_int_equal(tctx, (__io)->out.file_attr,		\
+						(__attribute),			\
+						"out.file_attr incorrect");	\
+		torture_assert_int_equal(tctx, (__io)->out.reserved2, 0,	\
+				"out.reserverd2 incorrect");			\
 	} while(0)
 
-
 /**
  * basic test for doing a session reconnect
  */
@@ -85,11 +76,14 @@ bool test_session_reconnect1(struct torture_context *tctx, struct smb2_tree *tre
 				 smb2_util_oplock_level("b"));
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	/* disconnect, reconnect and then do durable reopen */
 	previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
@@ -105,7 +99,10 @@ bool test_session_reconnect1(struct torture_context *tctx, struct smb2_tree *tre
 	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
 	qfinfo.generic.in.file.handle = _h1;
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+	torture_assert_ntstatus_equal_goto(tctx, status,
+					   NT_STATUS_USER_SESSION_DELETED,
+					   ret, done, "smb2_getinfo_file "
+					   "returned unexpected status");
 	h1 = NULL;
 
 	smb2_oplock_create_share(&io2, fname,
@@ -113,9 +110,13 @@ bool test_session_reconnect1(struct torture_context *tctx, struct smb2_tree *tre
 				 smb2_util_oplock_level("b"));
 
 	status = smb2_create(tree2, mem_ctx, &io2);
-	CHECK_STATUS(status, NT_STATUS_OK);
-	CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
+
+	CHECK_CREATED(tctx, &io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 	_h2 = io2.out.file.handle;
 	h2 = &_h2;
 
@@ -168,11 +169,14 @@ bool test_session_reconnect2(struct torture_context *tctx, struct smb2_tree *tre
 	io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	/* disconnect, reconnect and then do durable reopen */
 	previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
@@ -187,7 +191,10 @@ bool test_session_reconnect2(struct torture_context *tctx, struct smb2_tree *tre
 	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
 	qfinfo.generic.in.file.handle = _h1;
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+	torture_assert_ntstatus_equal_goto(tctx, status,
+					   NT_STATUS_USER_SESSION_DELETED,
+					   ret, done, "smb2_getinfo_file "
+					   "returned unexpected status");
 	h1 = NULL;
 
 done:
@@ -225,16 +232,20 @@ bool test_session_reauth1(struct torture_context *tctx, struct smb2_tree *tree)
 				 smb2_util_oplock_level("b"));
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	status = smb2_session_setup_spnego(tree->session,
 					   cmdline_credentials,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* try to access the file via the old handle */
 
@@ -242,12 +253,14 @@ bool test_session_reauth1(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
 	qfinfo.generic.in.file.handle = _h1;
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	status = smb2_session_setup_spnego(tree->session,
 					   cmdline_credentials,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* try to access the file via the old handle */
 
@@ -255,7 +268,8 @@ bool test_session_reauth1(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
 	qfinfo.generic.in.file.handle = _h1;
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 done:
 	if (h1 != NULL) {
@@ -294,11 +308,14 @@ bool test_session_reauth2(struct torture_context *tctx, struct smb2_tree *tree)
 				 smb2_util_oplock_level("b"));
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	/* re-authenticate as anonymous */
 
@@ -308,7 +325,8 @@ bool test_session_reauth2(struct torture_context *tctx, struct smb2_tree *tree)
 	status = smb2_session_setup_spnego(tree->session,
 					   anon_creds,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* try to access the file via the old handle */
 
@@ -316,14 +334,16 @@ bool test_session_reauth2(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
 	qfinfo.generic.in.file.handle = _h1;
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	/* re-authenticate as original user again */
 
 	status = smb2_session_setup_spnego(tree->session,
 					   cmdline_credentials,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* try to access the file via the old handle */
 
@@ -331,7 +351,8 @@ bool test_session_reauth2(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
 	qfinfo.generic.in.file.handle = _h1;
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 done:
 	if (h1 != NULL) {
@@ -378,11 +399,14 @@ bool test_session_reauth3(struct torture_context *tctx, struct smb2_tree *tree)
 				 smb2_util_oplock_level("b"));
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	/* get the security descriptor */
 
@@ -393,7 +417,9 @@ bool test_session_reauth3(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
+
 	/* re-authenticate as anonymous */
 
 	anon_creds = cli_credentials_init_anon(mem_ctx);
@@ -402,7 +428,8 @@ bool test_session_reauth3(struct torture_context *tctx, struct smb2_tree *tree)
 	status = smb2_session_setup_spnego(tree->session,
 					   anon_creds,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* try to access the file via the old handle */
 
@@ -413,14 +440,16 @@ bool test_session_reauth3(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	/* re-authenticate as original user again */
 
 	status = smb2_session_setup_spnego(tree->session,
 					   cmdline_credentials,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* try to access the file via the old handle */
 
@@ -431,7 +460,8 @@ bool test_session_reauth3(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 done:
 	if (h1 != NULL) {
@@ -482,11 +512,14 @@ bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree)
 				 smb2_util_oplock_level("b"));
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	/* get the security descriptor */
 
@@ -497,7 +530,8 @@ bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	sd1 = qfinfo.query_secdesc.out.sd;
 
@@ -509,7 +543,8 @@ bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree)
 	status = smb2_session_setup_spnego(tree->session,
 					   anon_creds,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* give full access on the file to anonymous */
 
@@ -522,7 +557,8 @@ bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree)
 	ace.trustee = *extra_sid;
 
 	status = security_descriptor_dacl_add(sd1, &ace);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"security_descriptor_dacl_add failed");
 
 	ZERO_STRUCT(sfinfo);
 	sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
@@ -531,14 +567,16 @@ bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree)
 	sfinfo.set_secdesc.in.sd = sd1;
 
 	status = smb2_setinfo_file(tree, &sfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_setinfo_file failed");
 
 	/* re-authenticate as original user again */
 
 	status = smb2_session_setup_spnego(tree->session,
 					   cmdline_credentials,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* re-get the security descriptor */
 
@@ -549,7 +587,8 @@ bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	ret = true;
 
@@ -604,10 +643,11 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	snprintf(fname, sizeof(fname), "%s\\file.dat", dname);
 
 	ok = smb2_util_setup_dir(tctx, tree, dname);
-	CHECK_VAL(ok, true);
+	torture_assert(tctx, ok, "smb2_util_setup_dir not ok");
 
 	status = torture_smb2_testdir(tree, dname, &_dh1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"torture_smb2_testdir failed");
 	dh1 = &_dh1;
 
 	smb2_oplock_create_share(&io1, fname,
@@ -615,11 +655,14 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 				 smb2_util_oplock_level("b"));
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	/* get the security descriptor */
 
@@ -630,7 +673,8 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	f_sd1 = qfinfo.query_secdesc.out.sd;
 
@@ -642,13 +686,17 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	status = smb2_session_setup_spnego(tree->session,
 					   anon_creds,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* try to rename the file: fails */
 
 	snprintf(fname2, sizeof(fname2), "%s\\file2.dat", dname);
 
-	smb2_util_unlink(tree, fname2);
+	status = smb2_util_unlink(tree, fname2);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_unlink failed");
+
 
 	ZERO_STRUCT(sfinfo);
 	sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
@@ -657,14 +705,18 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	sfinfo.rename_information.in.new_name = fname2;
 
 	status = smb2_setinfo_file(tree, &sfinfo);
-	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+	torture_assert_ntstatus_equal_goto(tctx, status,
+					   NT_STATUS_ACCESS_DENIED,
+					   ret, done, "smb2_setinfo_file "
+					   "returned unexpected status");
 
 	/* re-authenticate as original user again */
 
 	status = smb2_session_setup_spnego(tree->session,
 					   cmdline_credentials,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* give full access on the file to anonymous */
 
@@ -677,7 +729,8 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	ace.trustee = *extra_sid;
 
 	status = security_descriptor_dacl_add(f_sd1, &ace);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"security_descriptor_dacl_add failed");
 
 	ZERO_STRUCT(sfinfo);
 	sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
@@ -686,7 +739,8 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	sfinfo.set_secdesc.in.sd = f_sd1;
 
 	status = smb2_setinfo_file(tree, &sfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_setinfo_file failed");
 
 	/* re-get the security descriptor */
 
@@ -697,7 +751,8 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	/* re-authenticate as anonymous - again */
 
@@ -707,7 +762,8 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	status = smb2_session_setup_spnego(tree->session,
 					   anon_creds,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* try to rename the file: fails */
 
@@ -718,7 +774,10 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	sfinfo.rename_information.in.new_name = fname2;
 
 	status = smb2_setinfo_file(tree, &sfinfo);
-	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+	torture_assert_ntstatus_equal_goto(tctx, status,
+					   NT_STATUS_ACCESS_DENIED,
+					   ret, done, "smb2_setinfo_file "
+					   "returned unexpected status");
 
 	/* give full access on the parent dir to anonymous */
 
@@ -729,7 +788,8 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	d_sd1 = qfinfo.query_secdesc.out.sd;
 
@@ -740,7 +800,8 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	ace.trustee = *extra_sid;
 
 	status = security_descriptor_dacl_add(d_sd1, &ace);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"security_descriptor_dacl_add failed");
 
 	ZERO_STRUCT(sfinfo);
 	sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
@@ -750,7 +811,8 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	sfinfo.set_secdesc.in.sd = d_sd1;
 
 	status = smb2_setinfo_file(tree, &sfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_setinfo_file failed");
 
 	ZERO_STRUCT(qfinfo);
 
@@ -759,9 +821,12 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
-	smb2_util_close(tree, _dh1);
+	status = smb2_util_close(tree, _dh1);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_close failed");
 	dh1 = NULL;
 
 	/* try to rename the file: still fails */
@@ -773,14 +838,18 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	sfinfo.rename_information.in.new_name = fname2;
 
 	status = smb2_setinfo_file(tree, &sfinfo);
-	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+	torture_assert_ntstatus_equal_goto(tctx, status,
+					NT_STATUS_ACCESS_DENIED,
+					ret, done, "smb2_setinfo_file "
+					"returned unexpected status");
 
 	/* re-authenticate as original user - again */
 
 	status = smb2_session_setup_spnego(tree->session,
 					   cmdline_credentials,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* rename the file - for verification that it works */
 
@@ -791,12 +860,14 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	sfinfo.rename_information.in.new_name = fname2;
 
 	status = smb2_setinfo_file(tree, &sfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_setinfo_file failed");
 
 	/* closs the file, check it is gone and reopen under the new name */
 
-	smb2_util_close(tree, _h1);
-
+	status = smb2_util_close(tree, _h1);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_close failed");
 	ZERO_STRUCT(io1);
 
 	smb2_generic_create_share(&io1,
@@ -808,7 +879,10 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 				  0 /* leasekey */, 0 /* leasestate */);
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+	torture_assert_ntstatus_equal_goto(tctx, status,
+					NT_STATUS_OBJECT_NAME_NOT_FOUND,
+					ret, done, "smb2_create "
+					"returned unexpected status");
 
 	ZERO_STRUCT(io1);
 
@@ -821,11 +895,14 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 				  0 /* leasekey */, 0 /* leasestate */);
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	/* try to access the file via the old handle */
 
@@ -836,7 +913,8 @@ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
 	qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
 
 	status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 done:
 	if (dh1 != NULL) {
@@ -896,11 +974,14 @@ bool test_session_reauth6(struct torture_context *tctx, struct smb2_tree *tree)
 	io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	/*
 	 * reauthentication with invalid credentials:
@@ -917,12 +998,15 @@ bool test_session_reauth6(struct torture_context *tctx, struct smb2_tree *tree)
 
 	ok = cli_credentials_set_password(broken_creds, corrupted_password,
 					  CRED_SPECIFIED);
-	CHECK_VAL(ok, true);
+	torture_assert(tctx, ok, "cli_credentials_set_password not ok");
 
 	status = smb2_session_setup_spnego(tree->session,
 					   broken_creds,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
+	torture_assert_ntstatus_equal_goto(tctx, status,
+					NT_STATUS_LOGON_FAILURE, ret, done,
+					"smb2_session_setup_spnego "
+					"returned unexpected status");
 
 	torture_comment(tctx, "did failed reauth\n");
 	/*
@@ -940,7 +1024,9 @@ bool test_session_reauth6(struct torture_context *tctx, struct smb2_tree *tree)
 				 smb2_util_oplock_level("b"));
 
 	status = smb2_create(tree, mem_ctx, &io1);
-	CHECK_STATUS(status, expected);
+	torture_assert_ntstatus_equal_goto(tctx, status, expected,
+					ret, done, "smb2_create "
+					"returned unexpected status");
 
 done:
 	if (h1 != NULL) {
@@ -1014,11 +1100,14 @@ static bool test_session_expire1(struct torture_context *tctx)
 	io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
 
 	status = smb2_create(tree, tctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	/* get the security descriptor */
 
@@ -1032,7 +1121,8 @@ static bool test_session_expire1(struct torture_context *tctx)
 
 		ZERO_STRUCT(qfinfo.access_information.out);
 		status = smb2_getinfo_file(tree, tctx, &qfinfo);
-		CHECK_STATUS(status, NT_STATUS_OK);
+		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+						"smb2_getinfo_file failed");
 
 		torture_comment(tctx, "sleep 5 seconds\n");
 		smb_msleep(5*1000);
@@ -1040,7 +1130,10 @@ static bool test_session_expire1(struct torture_context *tctx)
 		torture_comment(tctx, "query info => EXPIRED\n");
 		ZERO_STRUCT(qfinfo.access_information.out);
 		status = smb2_getinfo_file(tree, tctx, &qfinfo);
-		CHECK_STATUS(status, NT_STATUS_NETWORK_SESSION_EXPIRED);
+		torture_assert_ntstatus_equal_goto(tctx, status,
+					NT_STATUS_NETWORK_SESSION_EXPIRED,
+					ret, done, "smb2_getinfo_file "
+					"returned unexpected status");
 
 		/*
 		 * the krb5 library may not handle expired creds
@@ -1052,12 +1145,14 @@ static bool test_session_expire1(struct torture_context *tctx)
 		status = smb2_session_setup_spnego(tree->session,
 						   credentials,
 						   0 /* previous_session_id */);
-		CHECK_STATUS(status, NT_STATUS_OK);
+		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_seutup_spnego failed");
 	}
 
 	ZERO_STRUCT(qfinfo.access_information.out);
 	status = smb2_getinfo_file(tree, tctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	ret = true;
 done:
@@ -1108,11 +1203,14 @@ bool test_session_bind1(struct torture_context *tctx, struct smb2_tree *tree1)
 				 smb2_util_oplock_level("b"));
 
 	status = smb2_create(tree1, mem_ctx, &io1);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create failed");
 	_h1 = io1.out.file.handle;
 	h1 = &_h1;
-	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+	CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	torture_assert_int_equal(tctx, io1.out.oplock_level,
+					smb2_util_oplock_level("b"),
+					"oplock_level incorrect");
 
 	status = smb2_connect(tctx,
 			      host,
@@ -1143,7 +1241,8 @@ bool test_session_bind1(struct torture_context *tctx, struct smb2_tree *tree1)
 	status = smb2_session_setup_spnego(session1_2,
 					   cmdline_credentials,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	/* use the 1st connection, 1st session */
 	ZERO_STRUCT(qfinfo);
@@ -1151,7 +1250,8 @@ bool test_session_bind1(struct torture_context *tctx, struct smb2_tree *tree1)
 	qfinfo.generic.in.file.handle = _h1;
 	tree1->session = session1_1;
 	status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	/* use the 2nd connection, 1st session */
 	ZERO_STRUCT(qfinfo);
@@ -1159,10 +1259,13 @@ bool test_session_bind1(struct torture_context *tctx, struct smb2_tree *tree1)
 	qfinfo.generic.in.file.handle = _h1;
 	tree1->session = session1_2;
 	status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_getinfo_file failed");
 
 	tree1->session = session1_1;
-	smb2_util_close(tree1, *h1);
+	status = smb2_util_close(tree1, *h1);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_close failed");
 	h1 = NULL;
 
 	/*
@@ -1177,12 +1280,13 @@ bool test_session_bind1(struct torture_context *tctx, struct smb2_tree *tree1)
 	status = smb2_session_setup_spnego(session2_1,
 					   cmdline_credentials,
 					   0 /* previous_session_id */);
-	CHECK_STATUS(status, NT_STATUS_OK);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_session_setup_spnego failed");
 
 	tree2->session = session2_1;
 	status = smb2_util_unlink(tree2, fname);
-	CHECK_STATUS(status, NT_STATUS_OK);
-
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_unlink failed");
 	ret = true;
 done:
 	talloc_free(tree2);
diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c
index 0124cf1..90029c7 100644
--- a/source4/torture/smb2/smb2.c
+++ b/source4/torture/smb2/smb2.c
@@ -74,7 +74,7 @@ struct torture_test *torture_suite_add_1smb2_test(struct torture_suite *suite,
 	test->fn = run;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 }
@@ -138,7 +138,7 @@ struct torture_test *torture_suite_add_2smb2_test(struct torture_suite *suite,
 	test->fn = run;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 }
diff --git a/source4/torture/smb2/streams.c b/source4/torture/smb2/streams.c
index 2db893c..d9098af 100644
--- a/source4/torture/smb2/streams.c
+++ b/source4/torture/smb2/streams.c
@@ -484,6 +484,79 @@ done:
 	return ret;
 }
 
+static bool test_zero_byte_stream(struct torture_context *tctx,
+				  struct smb2_tree *tree)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	NTSTATUS status;
+	union smb_open io;
+	const char *fname = DNAME "\\stream.txt";
+	const char *sname;
+	bool ret = true;
+	struct smb2_handle h, bh;
+	const char *streams[] = { "::$DATA", ":foo:$DATA" };
+
+	sname = talloc_asprintf(mem_ctx, "%s:%s", fname, "foo");
+
+	smb2_util_unlink(tree, fname);
+	smb2_deltree(tree, DNAME);
+
+	status = torture_smb2_testdir(tree, DNAME, &h);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "testdir");
+	smb2_util_close(tree, h);
+
+	torture_comment(tctx, "(%s) Check 0 byte named stream\n",
+	    __location__);
+
+	/* Create basefile */
+	ZERO_STRUCT(io);
+	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+	io.smb2.in.fname = fname;
+	io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+		SEC_FILE_WRITE_ATTRIBUTE |
+		SEC_FILE_READ_DATA |
+		SEC_FILE_WRITE_DATA;
+	status = smb2_create(tree, mem_ctx, &(io.smb2));
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
+	smb2_util_close(tree, io.smb2.out.file.handle);
+
+	/* Create named stream and close it */
+	ZERO_STRUCT(io);
+	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+	io.smb2.in.fname = sname;
+	io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+		SEC_FILE_WRITE_ATTRIBUTE |
+		SEC_FILE_READ_DATA |
+		SEC_FILE_WRITE_DATA;
+	status = smb2_create(tree, mem_ctx, &(io.smb2));
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
+	smb2_util_close(tree, io.smb2.out.file.handle);
+
+	/*
+	 * Check stream list, the 0 byte stream MUST be returned by
+	 * the server.
+	 */
+	ZERO_STRUCT(io);
+	io.smb2.in.fname = fname;
+	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+	io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+		SEC_FILE_WRITE_ATTRIBUTE |
+		SEC_FILE_READ_DATA |
+		SEC_FILE_WRITE_DATA;
+	status = smb2_create(tree, mem_ctx, &(io.smb2));
+	bh = io.smb2.out.file.handle;
+
+	ret = check_stream_list(tree,tctx, fname, 2, streams, bh);
+	torture_assert_goto(tctx, ret == true, ret, done, "smb2_create");
+	smb2_util_close(tree, bh);
+
+done:
+	smb2_deltree(tree, DNAME);
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
 /*
   test stream sharemodes
 */
@@ -1754,6 +1827,7 @@ struct torture_suite *torture_smb2_streams_init(void)
 	torture_suite_add_1smb2_test(suite, "create-disposition", test_stream_create_disposition);
 	torture_suite_add_1smb2_test(suite, "attributes", test_stream_attributes);
 	torture_suite_add_1smb2_test(suite, "delete", test_stream_delete);
+	torture_suite_add_1smb2_test(suite, "zero-byte", test_zero_byte_stream);
 
 	suite->description = talloc_strdup(suite, "SMB2-STREAM tests");
 
diff --git a/source4/torture/unix/whoami.c b/source4/torture/unix/whoami.c
index 00109eb..53921d4 100644
--- a/source4/torture/unix/whoami.c
+++ b/source4/torture/unix/whoami.c
@@ -300,7 +300,10 @@ static bool test_against_ldap(struct torture_context *torture, struct ldb_contex
 			struct dom_sid *sid = talloc(torture, struct dom_sid);
 			torture_assert(torture, sid != NULL, "talloc failed");
 			
-			torture_assert(torture, sid_blob_parse(el->values[i], sid), "sid parse failed");
+			torture_assert(torture,
+				       sid_parse(el->values[i].data,
+						 el->values[i].length, sid),
+				       "sid parse failed");
 			torture_assert_str_equal(torture, dom_sid_string(sid, sid), dom_sid_string(sid, whoami->sid_list[i]), "SID from LDAP and SID from CIFS does not match!");
 			talloc_free(sid);
 		}
@@ -311,13 +314,20 @@ static bool test_against_ldap(struct torture_context *torture, struct ldb_contex
 		struct dom_sid *dc_sids = talloc_array(torture, struct dom_sid, el->num_values);
 		struct dom_sid *member_sids = talloc_array(torture, struct dom_sid, whoami->num_sids);
 		torture_assert(torture, user_sid != NULL, "talloc failed");
-		torture_assert(torture, sid_blob_parse(el->values[0], user_sid), "sid parse failed");
+		torture_assert(torture, sid_parse(el->values[0].data,
+						  el->values[0].length,
+						  user_sid),
+			       "sid parse failed");
 		torture_assert_ntstatus_equal(torture, dom_sid_split_rid(torture, user_sid, &dom_sid, NULL), NT_STATUS_OK, "failed to split domain SID from user SID");
 		for (i = 0; i < el->num_values; i++) {
 			struct dom_sid *sid = talloc(dc_sids, struct dom_sid);
 			torture_assert(torture, sid != NULL, "talloc failed");
 			
-			torture_assert(torture, sid_blob_parse(el->values[i], sid), "sid parse failed");
+			torture_assert(torture,
+				       sid_parse(el->values[i].data,
+						 el->values[i].length,
+						 sid),
+				       "sid parse failed");
 			if (dom_sid_in_domain(dom_sid, sid)) {
 				dc_sids[num_domain_sids_dc] = *sid;
 				num_domain_sids_dc++;
diff --git a/source4/torture/util_smb.c b/source4/torture/util_smb.c
index 0520f27..32de753 100644
--- a/source4/torture/util_smb.c
+++ b/source4/torture/util_smb.c
@@ -783,7 +783,7 @@ _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
 	test->fn = run;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 
@@ -834,7 +834,7 @@ _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
 	test->fn = run;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 
@@ -878,7 +878,7 @@ _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
 	test->fn = run;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 }
diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c
index d74eb65..ae978c2 100644
--- a/source4/torture/vfs/fruit.c
+++ b/source4/torture/vfs/fruit.c
@@ -1931,7 +1931,7 @@ static bool test_aapl(struct torture_context *tctx,
 	/*
 	 * Now check returned AAPL context
 	 */
-	torture_comment(tctx, "Comparing returned AAPL capabilites\n");
+	torture_comment(tctx, "Comparing returned AAPL capabilities\n");
 
 	aapl = smb2_create_blob_find(&io.out.blobs,
 				     SMB2_CREATE_TAG_AAPL);
diff --git a/source4/torture/vfs/vfs.c b/source4/torture/vfs/vfs.c
index 9b82387..f3ce447 100644
--- a/source4/torture/vfs/vfs.c
+++ b/source4/torture/vfs/vfs.c
@@ -94,7 +94,7 @@ struct torture_test *torture_suite_add_2ns_smb2_test(struct torture_suite *suite
 	test->fn = run;
 	test->dangerous = false;
 
-	DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+	DLIST_ADD_END(tcase->tests, test);
 
 	return test;
 }
diff --git a/source4/torture/winbind/struct_based.c b/source4/torture/winbind/struct_based.c
index a7b6bfd..1a84a7a 100644
--- a/source4/torture/winbind/struct_based.c
+++ b/source4/torture/winbind/struct_based.c
@@ -417,6 +417,14 @@ static bool torture_winbind_struct_domain_info(struct torture_context *torture)
 	torture_assert(torture, ok, "failed to get trust list");
 
 	for (i=0; listd && listd[i].netbios_name; i++) {
+		torture_comment(torture, "LIST[%u] '%s' => '%s' [%s]\n",
+				(unsigned)i,
+				listd[i].netbios_name,
+				listd[i].dns_name,
+				dom_sid_string(torture, listd[i].sid));
+	}
+
+	for (i=0; listd && listd[i].netbios_name; i++) {
 		struct winbindd_request req;
 		struct winbindd_response rep;
 		struct dom_sid *sid;
@@ -447,7 +455,8 @@ static bool torture_winbind_struct_domain_info(struct torture_context *torture)
 			flagstr = talloc_strdup_append(flagstr, "NA ");
 		}
 
-		torture_comment(torture, "DOMAIN '%s' => '%s' [%s] [%s]\n",
+		torture_comment(torture, "DOMAIN[%u] '%s' => '%s' [%s] [%s]\n",
+				(unsigned)i,
 				rep.data.domain_info.name,
 				rep.data.domain_info.alt_name,
 				flagstr,
@@ -457,7 +466,9 @@ static bool torture_winbind_struct_domain_info(struct torture_context *torture)
 		torture_assert(torture, sid, "Failed to parse SID");
 
 		ok = dom_sid_equal(listd[i].sid, sid);
-		torture_assert(torture, ok, "SID's doesn't match");
+		torture_assert(torture, ok, talloc_asprintf(torture, "SID's doesn't match [%s] != [%s]",
+			       dom_sid_string(torture, listd[i].sid),
+			       dom_sid_string(torture, sid)));
 
 		torture_assert_str_equal(torture,
 					 rep.data.domain_info.name,
diff --git a/source4/torture/wscript_build b/source4/torture/wscript_build
index 9231bba..8966026 100755
--- a/source4/torture/wscript_build
+++ b/source4/torture/wscript_build
@@ -32,18 +32,46 @@ bld.RECURSE('winbind')
 bld.RECURSE('libnetapi')
 bld.RECURSE('libsmbclient')
 
-heimdal_specific = dict(source='', deps='')
+ntvfs_specific = dict(source='', deps='')
 
-if bld.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'):
-	heimdal_specific['source'] += ' rpc/spoolss_notify.c'
-	heimdal_specific['deps'] += ' SMB_SERVER dcerpc_server ntvfs'
+# Yes, the spoolss_notify test uses the NTVFS file server to run the SMB server expected
+# to handle the RPC callback!
+if bld.CONFIG_SET('WITH_NTVFS_FILESERVER'):
+	ntvfs_specific['source'] += ' rpc/spoolss_notify.c'
+	ntvfs_specific['deps'] += ' SMB_SERVER dcerpc_server ntvfs'
 
 bld.SAMBA_SUBSYSTEM('TORTURE_NDR',
-	source='ndr/ndr.c ndr/winreg.c ndr/atsvc.c ndr/lsa.c ndr/epmap.c ndr/dfs.c ndr/netlogon.c ndr/drsuapi.c ndr/spoolss.c ndr/ntprinting.c ndr/samr.c ndr/dfsblob.c ndr/drsblobs.c ndr/nbt.c ndr/ntlmssp.c ndr/string.c ndr/backupkey.c ndr/witness.c',
+        source='''ndr/ndr.c
+                  ndr/winreg.c
+                  ndr/atsvc.c
+                  ndr/lsa.c
+                  ndr/epmap.c
+                  ndr/dfs.c
+                  ndr/netlogon.c
+                  ndr/drsuapi.c
+                  ndr/spoolss.c
+                  ndr/ntprinting.c
+                  ndr/samr.c
+                  ndr/dfsblob.c
+                  ndr/drsblobs.c
+                  ndr/nbt.c
+                  ndr/ntlmssp.c
+                  ndr/string.c
+                  ndr/backupkey.c
+                  ndr/witness.c
+                  ndr/clusapi.c
+                  ndr/negoex.c
+		  ''',
 	autoproto='ndr/proto.h',
 	deps='torture'
 	)
 
+torture_rpc_backupkey = ''
+if bld.AD_DC_BUILD_IS_ENABLED():
+    if bld.CONFIG_SET('HAVE_GNUTLS_3_4_7'):
+        torture_rpc_backupkey = 'rpc/backupkey.c'
+    else:
+        torture_rpc_backupkey = 'rpc/backupkey_heimdal.c'
 
 bld.SAMBA_MODULE('torture_rpc',
                  source='''
@@ -99,8 +127,7 @@ bld.SAMBA_MODULE('torture_rpc',
                         rpc/fsrvp.c
                         rpc/clusapi.c
                         rpc/witness.c
-                        rpc/backupkey.c
-                        ''' + heimdal_specific['source'],
+                        ''' + torture_rpc_backupkey + ntvfs_specific['source'],
                  autoproto='rpc/proto.h',
                  subsystem='smbtorture',
                  init_function='torture_rpc_init',
@@ -115,7 +142,7 @@ bld.SAMBA_MODULE('torture_rpc',
                       RPC_NDR_ECHO
                       RPC_NDR_SVCCTL
                       RPC_NDR_NETLOGON
-                      dcerpc-atsvc
+                      RPC_NDR_ATSVC
                       RPC_NDR_DRSUAPI
                       RPC_NDR_LSA
                       RPC_NDR_EPMAPPER
@@ -146,7 +173,7 @@ bld.SAMBA_MODULE('torture_rpc',
                       RPC_NDR_CLUSAPI
                       RPC_NDR_WITNESS
                       RPC_NDR_BACKUPKEY
-                      ''' + heimdal_specific['deps'],
+                      ''' + ntvfs_specific['deps'],
                  internal_module=True)
 
 bld.RECURSE('drs')
@@ -261,7 +288,7 @@ bld.SAMBA_SUBSYSTEM('torturemain',
 bld.SAMBA_BINARY('smbtorture',
                  source=[],
                  manpages='man/smbtorture.1',
-                 public_headers='smbtorture.h',
+                 private_headers='smbtorture.h',
                  deps='torturemain torture popt POPT_SAMBA POPT_CREDENTIALS dcerpc LIBCLI_SMB SMBREADLINE ' + TORTURE_MODULES,
                  pyembed=True
                  )
diff --git a/source4/utils/man/ntlm_auth4.1.xml b/source4/utils/man/ntlm_auth4.1.xml
index 3e26e37..fe6ce6d 100644
--- a/source4/utils/man/ntlm_auth4.1.xml
+++ b/source4/utils/man/ntlm_auth4.1.xml
@@ -183,7 +183,7 @@
 
 	<varlistentry>
 	<term>--request-lm-key</term>
-	<listitem><para>Retreive LM session key</para></listitem>
+	<listitem><para>Retrieve LM session key</para></listitem>
 	</varlistentry>
 
 	<varlistentry>
diff --git a/source4/web_server/web_server.c b/source4/web_server/web_server.c
index 0339b55..d83b35a 100644
--- a/source4/web_server/web_server.c
+++ b/source4/web_server/web_server.c
@@ -49,7 +49,7 @@ static void websrv_timeout(struct tevent_context *event_context,
 			   struct tevent_timer *te, 
 			   struct timeval t, void *private_data)
 {
-	struct websrv_context *web = talloc_get_type(private_data, struct websrv_context);
+	struct websrv_context *web = talloc_get_type_abort(private_data, struct websrv_context);
 	struct stream_connection *conn = web->conn;
 	web->conn = NULL;
 	/* TODO: send a message to any running esp context on this connection
@@ -142,8 +142,8 @@ NTSTATUS http_parse_header(struct websrv_context *web, const char *line)
 static void websrv_recv(struct stream_connection *conn, uint16_t flags)
 {
 	struct web_server_data *wdata;
-	struct websrv_context *web = talloc_get_type(conn->private_data,
-						     struct websrv_context);
+	struct websrv_context *web = talloc_get_type_abort(conn->private_data,
+							   struct websrv_context);
 	NTSTATUS status;
 	uint8_t buf[1024];
 	size_t nread;
@@ -199,7 +199,7 @@ static void websrv_recv(struct stream_connection *conn, uint16_t flags)
 		 destroy the stack variables being used by that
 		 rendering process when we handle the timeout. */
 		if (!talloc_reference(web->task, web)) goto failed;
-		wdata = talloc_get_type(web->task->private_data, struct web_server_data);
+		wdata = talloc_get_type_abort(web->task->private_data, struct web_server_data);
 		if (wdata == NULL) goto failed;
 		wdata->http_process_input(wdata, web);
 		talloc_unlink(web->task, web);
@@ -217,8 +217,8 @@ failed:
 */
 static void websrv_send(struct stream_connection *conn, uint16_t flags)
 {
-	struct websrv_context *web = talloc_get_type(conn->private_data,
-						     struct websrv_context);
+	struct websrv_context *web = talloc_get_type_abort(conn->private_data,
+							   struct websrv_context);
 	NTSTATUS status;
 	size_t nsent;
 	DATA_BLOB b;
@@ -248,7 +248,8 @@ static void websrv_send(struct stream_connection *conn, uint16_t flags)
 */
 static void websrv_accept(struct stream_connection *conn)
 {
-	struct web_server_data *wdata = talloc_get_type(conn->private_data, struct web_server_data);
+	struct task_server *task = talloc_get_type_abort(conn->private_data, struct task_server);
+	struct web_server_data *wdata = talloc_get_type_abort(task->private_data, struct web_server_data);
 	struct websrv_context *web;
 	struct socket_context *tls_socket;
 
diff --git a/source4/web_server/wsgi.c b/source4/web_server/wsgi.c
index f0e7bd5..0b1c5d2 100644
--- a/source4/web_server/wsgi.c
+++ b/source4/web_server/wsgi.c
@@ -28,13 +28,6 @@
 #include "lib/tsocket/tsocket.h"
 #include "python/modules.h"
 
-/* There's no Py_ssize_t in 2.4, apparently */
-#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
-typedef int Py_ssize_t;
-typedef inquiry lenfunc;
-typedef intargfunc ssizeargfunc;
-#endif
-
 typedef struct {
 	PyObject_HEAD
 	struct websrv_context *web;
diff --git a/source4/wrepl_server/wrepl_server.c b/source4/wrepl_server/wrepl_server.c
index e28afc6..75a927a 100644
--- a/source4/wrepl_server/wrepl_server.c
+++ b/source4/wrepl_server/wrepl_server.c
@@ -192,7 +192,7 @@ NTSTATUS wreplsrv_load_partners(struct wreplsrv_service *service)
 			partner->address = address;
 			talloc_steal(partner, partner->address);
 
-			DLIST_ADD_END(service->partners, partner, struct wreplsrv_partner *);
+			DLIST_ADD_END(service->partners, partner);
 		}
 
 		partner->name			= ldb_msg_find_attr_as_string(res->msgs[i], "name", partner->address);
@@ -328,7 +328,7 @@ NTSTATUS wreplsrv_add_table(struct wreplsrv_service *service,
 
 		cur->partner		= wreplsrv_find_partner(service, wins_owner);
 
-		DLIST_ADD_END(table, cur, struct wreplsrv_owner *);
+		DLIST_ADD_END(table, cur);
 		*_table = table;
 	}
 
diff --git a/testprogs/blackbox/dbcheck-oldrelease.sh b/testprogs/blackbox/dbcheck-oldrelease.sh
index 22942dd..89c0c0f 100755
--- a/testprogs/blackbox/dbcheck-oldrelease.sh
+++ b/testprogs/blackbox/dbcheck-oldrelease.sh
@@ -141,14 +141,41 @@ reindex() {
        $PYTHON $BINDIR/samba-tool dbcheck --reindex -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $@
 }
 
+do_current_version_mod() {
+    if [ x$RELEASE = x"release-4-1-0rc3" ]; then
+	# Confirm (in combination with the ldbsearch below) that
+	# changing the attribute with current Samba fixes it, and that
+	# a fixed attriute isn't unfixed by dbcheck.
+	tmpldif=$release_dir/sudoers2-mod.ldif
+	$ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $tmpldif
+    fi
+    return 0
+}
+
 check_expected_before_values() {
     if [ x$RELEASE = x"release-4-1-0rc3" ]; then
 	tmpldif=$PREFIX_ABS/$RELEASE/expected-replpropertymetadata-before-dbcheck.ldif.tmp
-	TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb -s base -b CN=ops_run_anything,OU=SUDOers,DC=release-4-1-0rc3,DC=samba,DC=corp \* replpropertymetadata --show-binary > $tmpldif
+	TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb cn=ops_run_anything -s one -b OU=SUDOers,DC=release-4-1-0rc3,DC=samba,DC=corp \* replpropertymetadata --sorted --show-binary > $tmpldif
 	diff $tmpldif $release_dir/expected-replpropertymetadata-before-dbcheck.ldif
 	if [ "$?" != "0" ]; then
 	    return 1
 	fi
+
+	TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb cn=ops_run_anything2 -s one -b OU=SUDOers,DC=release-4-1-0rc3,DC=samba,DC=corp \* replpropertymetadata --sorted --show-binary | grep -v originating_change_time| grep -v whenChanged > $tmpldif
+
+	# Here we remove originating_change_time and whenChanged as
+	# these are time-dependent, caused by the ldbmodify above.
+
+	diff $tmpldif $release_dir/expected-replpropertymetadata-before-dbcheck2.ldif
+	if [ "$?" != "0" ]; then
+	    return 1
+	fi
+
+	TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb cn=ops_run_anything3 -s one -b OU=SUDOers,DC=release-4-1-0rc3,DC=samba,DC=corp \* replpropertymetadata --sorted --show-binary > $tmpldif
+	diff $tmpldif $release_dir/expected-replpropertymetadata-before-dbcheck3.ldif
+	if [ "$?" != "0" ]; then
+	    return 1
+	fi
     fi
     return 0
 }
@@ -160,9 +187,52 @@ dbcheck() {
 
 check_expected_after_values() {
     if [ x$RELEASE = x"release-4-1-0rc3" ]; then
-	tmpldif=$PREFIX_ABS/$RELEASE/expected-replpropertymetadata-after-dbcheck.ldif.tmp
-	TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb -s base -b CN=ops_run_anything,OU=SUDOers,DC=release-4-1-0rc3,DC=samba,DC=corp \* replpropertymetadata --show-binary > $tmpldif
-	diff -u $tmpldif $release_dir/expected-replpropertymetadata-after-dbcheck.ldif
+	tmpldif=$PREFIX_ABS/$RELEASE/expected-replpropertymetadata-before-dbcheck.ldif.tmp
+	TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb cn=ops_run_anything -s one -b OU=SUDOers,DC=release-4-1-0rc3,DC=samba,DC=corp \* replpropertymetadata --sorted --show-binary > $tmpldif
+	diff $tmpldif $release_dir/expected-replpropertymetadata-after-dbcheck.ldif
+	if [ "$?" != "0" ]; then
+	    return 1
+	fi
+	TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb cn=ops_run_anything2 -s one -b OU=SUDOers,DC=release-4-1-0rc3,DC=samba,DC=corp \* replpropertymetadata --sorted --show-binary | grep -v originating_change_time| grep -v whenChanged > $tmpldif
+	diff $tmpldif $release_dir/expected-replpropertymetadata-after-dbcheck2.ldif
+	if [ "$?" != "0" ]; then
+	    return 1
+	fi
+	TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb cn=ops_run_anything3 -s one -b OU=SUDOers,DC=release-4-1-0rc3,DC=samba,DC=corp \* replpropertymetadata --sorted --show-binary > $tmpldif
+	diff $tmpldif $release_dir/expected-replpropertymetadata-after-dbcheck3.ldif
+	if [ "$?" != "0" ]; then
+	    return 1
+	fi
+    fi
+    return 0
+}
+
+check_forced_duplicate_values() {
+    if [ x$RELEASE = x"release-4-1-0rc3" ]; then
+	ldif=$release_dir/forced-duplicate-value-for-dbcheck.ldif
+	TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-1-0RC3,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+	if [ "$?" != "0" ]; then
+	    return 1
+	fi
+    else
+	return 0
+    fi
+}
+
+# This should 'fail', because it returns the number of modified records
+dbcheck_after_dup() {
+    if [ x$RELEASE = x"release-4-1-0rc3" ]; then
+	$PYTHON $BINDIR/samba-tool dbcheck --cross-ncs --fix --yes -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $@
+    else
+	return 1
+    fi
+}
+
+check_expected_after_dup_values() {
+    if [ x$RELEASE = x"release-4-1-0rc3" ]; then
+	tmpldif=$PREFIX_ABS/$RELEASE/expected-otherphone-after-dbcheck.ldif.tmp
+	TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb cn=administrator -s base -b cn=administrator,cn=users,DC=release-4-1-0rc3,DC=samba,DC=corp otherHomePhone --sorted --show-binary | grep -v \# | sort > $tmpldif
+	diff $tmpldif $release_dir/expected-otherphone-after-dbcheck.ldif
 	if [ "$?" != "0" ]; then
 	    return 1
 	fi
@@ -228,9 +298,13 @@ ldapcmp_sd() {
 if [ -d $release_dir ]; then
     testit $RELEASE undump
     testit "reindex" reindex
+    testit "current_version_mod" do_current_version_mod
     testit "check_expected_before_values" check_expected_before_values
     testit_expect_failure "dbcheck" dbcheck
     testit "check_expected_after_values" check_expected_after_values
+    testit "check_forced_duplicate_values" check_forced_duplicate_values
+    testit_expect_failure "dbcheck_after_dup" dbcheck_after_dup
+    testit "check_expected_after_dup_values" check_expected_after_dup_values
     testit "dbcheck_clean" dbcheck_clean
     testit_expect_failure "dbcheck_acl_reset" dbcheck_acl_reset
     testit "dbcheck_acl_reset_clean" dbcheck_acl_reset_clean
diff --git a/testprogs/blackbox/demote-saveddb.sh b/testprogs/blackbox/demote-saveddb.sh
new file mode 100755
index 0000000..3d5fabd
--- /dev/null
+++ b/testprogs/blackbox/demote-saveddb.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+if [ $# -lt 1 ]; then
+cat <<EOF
+Usage: demote.sh PREFIX RELEASE
+EOF
+exit 1;
+fi
+
+PREFIX_ABS="$1"
+shift 1
+
+. `dirname $0`/subunit.sh
+
+tree_dir=`dirname $0`/../../source4/selftest/provisions/multi-dc-samba-master-c596ac6
+
+undump() {
+       if test -x $BINDIR/tdbrestore;
+       then
+	`dirname $0`/../../source4/selftest/provisions/undump.sh $tree_dir $PREFIX_ABS $BINDIR/tdbrestore
+       else
+	`dirname $0`/../../source4/selftest/provisions/undump.sh $tree_dir $PREFIX_ABS
+       fi
+}
+
+demote() {
+       $PYTHON $BINDIR/samba-tool domain demote -H tdb://$PREFIX_ABS/private/sam.ldb --remove-other-dead-server=$1
+}
+
+
+if [ -d $tree_dir ]; then
+    testit "undump" undump
+    testit "demote-q-0-0" demote "q-0-0"
+    # The database was copied of q-0-1 so this will fail
+    # as we can't remove our own name
+    testit_expect_failure "demote-q-0-1" demote "q-0-1"
+    testit "demote-q-1-0" demote "q-1-0"
+    testit "demote-q-1-1" demote "q-1-1"
+else
+    subunit_start_test "undump"
+    subunit_skip_test "undump" <<EOF
+no test provision
+EOF
+
+    subunit_start_test "demote-q-0-0"
+    subunit_skip_test "demote-q-0-0" <<EOF
+no test provision
+EOF
+    subunit_start_test "demote-q-0-1"
+    subunit_skip_test "demote-q-0-1" <<EOF
+no test provision
+EOF
+    subunit_start_test "demote-q-1-1"
+    subunit_skip_test "demote-q-0-1" <<EOF
+no test provision
+EOF
+    subunit_start_test "demote-q-1-1"
+    subunit_skip_test "demote-q-1-1" <<EOF
+no test provision
+EOF
+fi
+
+if [ -d $PREFIX_ABS ]; then
+    rm -fr $PREFIX_ABS
+fi
+
+exit $failed
diff --git a/testprogs/blackbox/test_kinit.sh b/testprogs/blackbox/test_kinit.sh
deleted file mode 100755
index 9df13a7..0000000
--- a/testprogs/blackbox/test_kinit.sh
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/bin/sh
-# Blackbox tests for kinit and kerberos integration with smbclient etc
-# Copyright (C) 2006-2007 Jelmer Vernooij <jelmer at samba.org>
-# Copyright (C) 2006-2008 Andrew Bartlett <abartlet at samba.org>
-
-if [ $# -lt 5 ]; then
-cat <<EOF
-Usage: test_kinit.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX ENCTYPE SMBCLIENT
-EOF
-exit 1;
-fi
-
-SERVER=$1
-USERNAME=$2
-PASSWORD=$3
-REALM=$4
-DOMAIN=$5
-PREFIX=$6
-ENCTYPE=$7
-smbclient=$8
-shift 8
-failed=0
-
-samba4bindir="$BINDIR"
-samba4srcdir="$SRCDIR/source4"
-samba4kinit=kinit
-if test -x $BINDIR/samba4kinit; then
-	samba4kinit=$BINDIR/samba4kinit
-fi
-
-samba_tool="$samba4bindir/samba-tool"
-texpect="$samba4bindir/texpect"
-samba4kpasswd=kpasswd
-if test -x $BINDIR/samba4kpasswd; then
-	samba4kpasswd=$BINDIR/samba4kpasswd
-fi
-
-enableaccount="$samba_tool user enable"
-machineaccountccache="$samba4srcdir/scripting/bin/machineaccountccache"
-
-ldbmodify="ldbmodify"
-if [ -x "$samba4bindir/ldbmodify" ]; then
-	ldbmodify="$samba4bindir/ldbmodify"
-fi
-
-ldbsearch="ldbsearch"
-if [ -x "$samba4bindir/ldbsearch" ]; then
-	ldbsearch="$samba4bindir/ldbsearch"
-fi
-
-. `dirname $0`/subunit.sh
-
-test_smbclient() {
-	name="$1"
-	cmd="$2"
-	shift
-	shift
-	echo "test: $name"
-	$VALGRIND $smbclient $CONFIGURATION //$SERVER/tmp -c "$cmd" $@
-	status=$?
-	if [ x$status = x0 ]; then
-		echo "success: $name"
-	else
-		echo "failure: $name"
-	fi
-	return $status
-}
-
-enctype="-e $ENCTYPE"
-
-ADMIN_LDBMODIFY_CONFIG="-H ldap://$SERVER -U$USERNAME%$PASSWORD"
-export ADMIN_LDBMODIFY_CONFIG
-
-KRB5CCNAME_PATH="$PREFIX/tmpccache"
-KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
-ADMIN_KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
-export KRB5CCNAME
-rm -rf $KRB5CCNAME_PATH
-
-testit "reset password policies beside of minimum password age of 0 days" $VALGRIND $samba_tool domain passwordsettings $ADMIN_LDBMODIFY_CONFIG set --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=0 --max-pwd-age=default || failed=`expr $failed + 1`
-
-echo $PASSWORD > $PREFIX/tmppassfile
-testit "kinit with password" $samba4kinit $enctype --password-file=$PREFIX/tmppassfile --request-pac $USERNAME@$REALM   || failed=`expr $failed + 1`
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-testit "kinit with password (enterprise style)" $samba4kinit $enctype --enterprise --password-file=$PREFIX/tmppassfile --request-pac $USERNAME@$REALM   || failed=`expr $failed + 1`
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-testit "kinit with password (windows style)" $samba4kinit $enctype  --renewable --windows --password-file=$PREFIX/tmppassfile --request-pac $USERNAME@$REALM   || failed=`expr $failed + 1`
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-testit "kinit renew ticket" $samba4kinit $enctype --request-pac -R
-
-test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-testit "check time with kerberos ccache" $VALGRIND $samba_tool time $SERVER $CONFIGURATION -k yes $@ || failed=`expr $failed + 1`
-
-USERPASS=testPass at 12%
-echo $USERPASS > $PREFIX/tmpuserpassfile
-testit "add user with kerberos ccache" $VALGRIND $samba_tool user create nettestuser $USERPASS $CONFIGURATION  -k yes $@ || failed=`expr $failed + 1`
-
-echo "Getting defaultNamingContext"
-BASEDN=`$ldbsearch $options --basedn='' -H ldap://$SERVER -s base DUMMY=x defaultNamingContext | grep defaultNamingContext | awk '{print $2}'`
-
-cat > $PREFIX/tmpldbmodify <<EOF
-dn: cn=nettestuser,cn=users,$BASEDN
-changetype: modify
-add: servicePrincipalName
-servicePrincipalName: host/nettestuser
-replace: userPrincipalName
-userPrincipalName: nettest@$REALM
-EOF
-
-testit "modify servicePrincipalName and userPrincpalName" $VALGRIND $ldbmodify -H ldap://$SERVER $PREFIX/tmpldbmodify -k yes $@ || failed=`expr $failed + 1`
-
-testit "set user password with kerberos ccache" $VALGRIND $samba_tool user setpassword nettestuser --newpassword=$USERPASS $CONFIGURATION  -k yes $@ || failed=`expr $failed + 1`
-
-testit "enable user with kerberos cache" $VALGRIND $enableaccount nettestuser -H ldap://$SERVER -k yes $@ || failed=`expr $failed + 1`
-
-KRB5CCNAME_PATH="$PREFIX/tmpuserccache"
-KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
-export KRB5CCNAME
-
-rm -f $KRB5CCNAME_PATH
-testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
-
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-NEWUSERPASS=testPaSS at 34%
-testit "change user password with 'samba-tool user password' (rpc)" $VALGRIND $samba_tool user password -W$DOMAIN -Unettestuser%$USERPASS $CONFIGURATION -k no --newpassword=$NEWUSERPASS $@ || failed=`expr $failed + 1`
-
-echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
-rm -f $KRB5CCNAME_PATH
-testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
-
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-
-rm -f $KRB5CCNAME_PATH
-testit "kinit with password (NT-Principal style) using UPN" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettest@$REALM   || failed=`expr $failed + 1`
-test_smbclient "Test login with user kerberos ccache from enterprise UPN" 'ls' -k yes || failed=`expr $failed + 1`
-
-rm -f $KRB5CCNAME_PATH
-testit "kinit with password (enterprise style) using UPN" $samba4kinit $enctype --enterprise --password-file=$PREFIX/tmpuserpassfile --request-pac nettest@$REALM   || failed=`expr $failed + 1`
-test_smbclient "Test login with user kerberos ccache from enterprise UPN" 'ls' -k yes || failed=`expr $failed + 1`
-
-rm -f $KRB5CCNAME_PATH
-testit "kinit with password (windows style) using UPN" $samba4kinit $enctype  --renewable --windows --password-file=$PREFIX/tmpuserpassfile --request-pac nettest@$REALM   || failed=`expr $failed + 1`
-test_smbclient "Test login with user kerberos ccache from windows UPN" 'ls' -k yes || failed=`expr $failed + 1`
-
-cat > $PREFIX/tmpldbmodify <<EOF
-dn: cn=nettestuser,cn=users,$BASEDN
-changetype: modify
-replace: userPrincipalName
-userPrincipalName: nettest@$REALM.org
-EOF
-
-testit "modify userPrincipalName to be a different domain" $VALGRIND $ldbmodify $ADMIN_LDBMODIFY_CONFIG $PREFIX/tmpldbmodify $PREFIX/tmpldbmodify -k yes $@ || failed=`expr $failed + 1`
-
-rm -f $KRB5CCNAME_PATH
-testit "kinit with password (enterprise style) using UPN" $samba4kinit $enctype --enterprise --password-file=$PREFIX/tmpuserpassfile --request-pac nettest@$REALM.org   || failed=`expr $failed + 1`
-test_smbclient "Test login with user kerberos ccache from enterprise UPN, different domain" 'ls' -k yes || failed=`expr $failed + 1`
-
-
-USERPASS=$NEWUSERPASS
-NEWUSERPASS=testPaSS at 56%
-echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
-
-cat > $PREFIX/tmpkpasswdscript <<EOF
-expect Password
-password ${USERPASS}\n
-expect New password
-send ${NEWUSERPASS}\n
-expect Verify password
-send ${NEWUSERPASS}\n
-expect Success
-EOF
-
-testit "change user password with kpasswd" $texpect $PREFIX/tmpkpasswdscript $samba4kpasswd nettestuser@$REALM || failed=`expr $failed + 1`
-
-rm -f $KRB5CCNAME_PATH
-testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
-
-NEWUSERPASS=testPaSS at 78%
-echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
-
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-cat > $PREFIX/tmpkpasswdscript <<EOF
-expect New password
-send ${NEWUSERPASS}\n
-expect Verify password
-send ${NEWUSERPASS}\n
-expect Success
-EOF
-
-testit "set user password with kpasswd" $texpect $PREFIX/tmpkpasswdscript $samba4kpasswd --cache=$ADMIN_KRB5CCNAME nettestuser@$REALM || failed=`expr $failed + 1`
-
-rm -f $KRB5CCNAME_PATH
-testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
-
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-NEWUSERPASS=testPaSS at 910%
-echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
-
-cat > $PREFIX/tmpkpasswdscript <<EOF
-expect New password
-send ${NEWUSERPASS}\n
-expect Verify password
-send ${NEWUSERPASS}\n
-expect Success
-EOF
-
-testit "set user password with kpasswd and servicePrincipalName" $texpect $PREFIX/tmpkpasswdscript $samba4kpasswd --cache=$PREFIX/tmpccache host/nettestuser@$REALM || failed=`expr $failed + 1`
-
-testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
-
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-cat > $PREFIX/tmpldbmodify <<EOF
-dn: cn=nettestuser,cn=users,$BASEDN
-changetype: modify
-replace: pwdLastSet
-pwdLastSet: 0
-EOF
-
-USERPASS=$NEWUSERPASS
-NEWUSERPASS=testPaSS at 911%
-
-testit "modify pwdLastSet" $VALGRIND $ldbmodify $ADMIN_LDBMODIFY_CONFIG $PREFIX/tmpldbmodify $PREFIX/tmpldbmodify -k yes $@ || failed=`expr $failed + 1`
-
-cat > $PREFIX/tmppasswordchange <<EOF
-expect nettestuser@${REALM}'s Password: 
-send ${USERPASS}\n
-expect Your password will expire at
-expect Changing password
-expect New password:
-send ${NEWUSERPASS}\n
-expect Repeat new password:
-send ${NEWUSERPASS}\n
-expect Success: Password changed
-EOF
-
-testit "kinit with user password for expired password" $texpect $PREFIX/tmppasswordchange $samba4kinit $enctype --request-pac nettestuser@$REALM && failed=`expr $failed + 1`
-
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
-testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
-
-test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-KRB5CCNAME_PATH="$PREFIX/tmpccache"
-KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
-export KRB5CCNAME
-
-rm -rf $KRB5CCNAME_PATH
-
-lowerrealm=$(echo $REALM | tr '[A-Z]' '[a-z]')
-test_smbclient "Test login with user kerberos lowercase realm" 'ls' -k yes -Unettestuser@$lowerrealm%$NEWUSERPASS || failed=`expr $failed + 1`
-test_smbclient "Test login with user kerberos lowercase realm 2" 'ls' -k yes -Unettestuser@$REALM%$NEWUSERPASS --realm=$lowerrealm || failed=`expr $failed + 1`
-
-testit "del user with kerberos ccache" $VALGRIND $samba_tool user delete nettestuser $CONFIGURATION -k yes $@ || failed=`expr $failed + 1`
-
-rm -f $KRB5CCNAME_PATH
-testit "kinit with machineaccountccache script" $machineaccountccache $CONFIGURATION $KRB5CCNAME || failed=`expr $failed + 1`
-test_smbclient "Test machine account login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
-
-testit "reset password policies" $VALGRIND $samba_tool domain passwordsettings $ADMIN_LDBMODIFY_CONFIG set --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default || failed=`expr $failed + 1`
-
-rm -f $PREFIX/tmpccache tmpccfile tmppassfile tmpuserpassfile tmpuserccache tmpkpasswdscript
-exit $failed
diff --git a/testprogs/blackbox/test_kinit_heimdal.sh b/testprogs/blackbox/test_kinit_heimdal.sh
new file mode 100755
index 0000000..ab16123
--- /dev/null
+++ b/testprogs/blackbox/test_kinit_heimdal.sh
@@ -0,0 +1,273 @@
+#!/bin/sh
+# Blackbox tests for kinit and kerberos integration with smbclient etc
+# Copyright (C) 2006-2007 Jelmer Vernooij <jelmer at samba.org>
+# Copyright (C) 2006-2008 Andrew Bartlett <abartlet at samba.org>
+
+if [ $# -lt 5 ]; then
+cat <<EOF
+Usage: test_kinit.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX ENCTYPE SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+REALM=$4
+DOMAIN=$5
+PREFIX=$6
+ENCTYPE=$7
+smbclient=$8
+shift 8
+failed=0
+
+samba4bindir="$BINDIR"
+samba4srcdir="$SRCDIR/source4"
+samba4kinit=kinit
+if test -x $BINDIR/samba4kinit; then
+	samba4kinit=$BINDIR/samba4kinit
+fi
+
+samba_tool="$samba4bindir/samba-tool"
+texpect="$samba4bindir/texpect"
+samba4kpasswd=kpasswd
+if test -x $BINDIR/samba4kpasswd; then
+	samba4kpasswd=$BINDIR/samba4kpasswd
+fi
+
+enableaccount="$samba_tool user enable"
+machineaccountccache="$samba4srcdir/scripting/bin/machineaccountccache"
+
+ldbmodify="ldbmodify"
+if [ -x "$samba4bindir/ldbmodify" ]; then
+	ldbmodify="$samba4bindir/ldbmodify"
+fi
+
+ldbsearch="ldbsearch"
+if [ -x "$samba4bindir/ldbsearch" ]; then
+	ldbsearch="$samba4bindir/ldbsearch"
+fi
+
+. `dirname $0`/subunit.sh
+
+test_smbclient() {
+	name="$1"
+	cmd="$2"
+	shift
+	shift
+	echo "test: $name"
+	$VALGRIND $smbclient $CONFIGURATION //$SERVER/tmp -c "$cmd" $@
+	status=$?
+	if [ x$status = x0 ]; then
+		echo "success: $name"
+	else
+		echo "failure: $name"
+	fi
+	return $status
+}
+
+enctype="-e $ENCTYPE"
+
+ADMIN_LDBMODIFY_CONFIG="-H ldap://$SERVER -U$USERNAME%$PASSWORD"
+export ADMIN_LDBMODIFY_CONFIG
+
+KRB5CCNAME_PATH="$PREFIX/tmpccache"
+KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+ADMIN_KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+export KRB5CCNAME
+rm -rf $KRB5CCNAME_PATH
+
+testit "reset password policies beside of minimum password age of 0 days" $VALGRIND $samba_tool domain passwordsettings $ADMIN_LDBMODIFY_CONFIG set --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=0 --max-pwd-age=default || failed=`expr $failed + 1`
+
+echo $PASSWORD > $PREFIX/tmppassfile
+testit "kinit with password" $samba4kinit $enctype --password-file=$PREFIX/tmppassfile --request-pac $USERNAME@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+testit "kinit with password (enterprise style)" $samba4kinit $enctype --enterprise --password-file=$PREFIX/tmppassfile --request-pac $USERNAME@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+testit "kinit with password (windows style)" $samba4kinit $enctype  --renewable --windows --password-file=$PREFIX/tmppassfile --request-pac $USERNAME@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+testit "kinit renew ticket" $samba4kinit $enctype --request-pac -R
+
+test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+testit "check time with kerberos ccache" $VALGRIND $samba_tool time $SERVER $CONFIGURATION -k yes $@ || failed=`expr $failed + 1`
+
+USERPASS=testPass at 12%
+echo $USERPASS > $PREFIX/tmpuserpassfile
+testit "add user with kerberos ccache" $VALGRIND $samba_tool user create nettestuser $USERPASS $CONFIGURATION  -k yes $@ || failed=`expr $failed + 1`
+
+echo "Getting defaultNamingContext"
+BASEDN=`$ldbsearch $options --basedn='' -H ldap://$SERVER -s base DUMMY=x defaultNamingContext | grep defaultNamingContext | awk '{print $2}'`
+
+cat > $PREFIX/tmpldbmodify <<EOF
+dn: cn=nettestuser,cn=users,$BASEDN
+changetype: modify
+add: servicePrincipalName
+servicePrincipalName: host/nettestuser
+replace: userPrincipalName
+userPrincipalName: nettest@$REALM
+EOF
+
+testit "modify servicePrincipalName and userPrincpalName" $VALGRIND $ldbmodify -H ldap://$SERVER $PREFIX/tmpldbmodify -k yes $@ || failed=`expr $failed + 1`
+
+testit "set user password with kerberos ccache" $VALGRIND $samba_tool user setpassword nettestuser --newpassword=$USERPASS $CONFIGURATION  -k yes $@ || failed=`expr $failed + 1`
+
+testit "enable user with kerberos cache" $VALGRIND $enableaccount nettestuser -H ldap://$SERVER -k yes $@ || failed=`expr $failed + 1`
+
+KRB5CCNAME_PATH="$PREFIX/tmpuserccache"
+KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+export KRB5CCNAME
+
+rm -f $KRB5CCNAME_PATH
+testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
+
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+NEWUSERPASS=testPaSS at 34%
+testit "change user password with 'samba-tool user password' (rpc)" $VALGRIND $samba_tool user password -W$DOMAIN -Unettestuser%$USERPASS $CONFIGURATION -k no --newpassword=$NEWUSERPASS $@ || failed=`expr $failed + 1`
+
+echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
+rm -f $KRB5CCNAME_PATH
+testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
+
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+
+rm -f $KRB5CCNAME_PATH
+testit "kinit with password (NT-Principal style) using UPN" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettest@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache from enterprise UPN" 'ls' -k yes || failed=`expr $failed + 1`
+
+rm -f $KRB5CCNAME_PATH
+testit "kinit with password (enterprise style) using UPN" $samba4kinit $enctype --enterprise --password-file=$PREFIX/tmpuserpassfile --request-pac nettest@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache from enterprise UPN" 'ls' -k yes || failed=`expr $failed + 1`
+
+rm -f $KRB5CCNAME_PATH
+testit "kinit with password (windows style) using UPN" $samba4kinit $enctype  --renewable --windows --password-file=$PREFIX/tmpuserpassfile --request-pac nettest@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache from windows UPN" 'ls' -k yes || failed=`expr $failed + 1`
+
+cat > $PREFIX/tmpldbmodify <<EOF
+dn: cn=nettestuser,cn=users,$BASEDN
+changetype: modify
+replace: userPrincipalName
+userPrincipalName: nettest@$REALM.org
+EOF
+
+testit "modify userPrincipalName to be a different domain" $VALGRIND $ldbmodify $ADMIN_LDBMODIFY_CONFIG $PREFIX/tmpldbmodify $PREFIX/tmpldbmodify -k yes $@ || failed=`expr $failed + 1`
+
+rm -f $KRB5CCNAME_PATH
+testit "kinit with password (enterprise style) using UPN" $samba4kinit $enctype --enterprise --password-file=$PREFIX/tmpuserpassfile --request-pac nettest@$REALM.org   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache from enterprise UPN, different domain" 'ls' -k yes || failed=`expr $failed + 1`
+
+
+USERPASS=$NEWUSERPASS
+NEWUSERPASS=testPaSS at 56%
+echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
+
+cat > $PREFIX/tmpkpasswdscript <<EOF
+expect Password
+password ${USERPASS}\n
+expect New password
+send ${NEWUSERPASS}\n
+expect Verify password
+send ${NEWUSERPASS}\n
+expect Success
+EOF
+
+testit "change user password with kpasswd" $texpect $PREFIX/tmpkpasswdscript $samba4kpasswd nettestuser@$REALM || failed=`expr $failed + 1`
+
+rm -f $KRB5CCNAME_PATH
+testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
+
+NEWUSERPASS=testPaSS at 78%
+echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
+
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+cat > $PREFIX/tmpkpasswdscript <<EOF
+expect New password
+send ${NEWUSERPASS}\n
+expect Verify password
+send ${NEWUSERPASS}\n
+expect Success
+EOF
+
+testit "set user password with kpasswd" $texpect $PREFIX/tmpkpasswdscript $samba4kpasswd --cache=$ADMIN_KRB5CCNAME nettestuser@$REALM || failed=`expr $failed + 1`
+
+rm -f $KRB5CCNAME_PATH
+testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
+
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+NEWUSERPASS=testPaSS at 910%
+echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
+
+cat > $PREFIX/tmpkpasswdscript <<EOF
+expect New password
+send ${NEWUSERPASS}\n
+expect Verify password
+send ${NEWUSERPASS}\n
+expect Success
+EOF
+
+testit "set user password with kpasswd and servicePrincipalName" $texpect $PREFIX/tmpkpasswdscript $samba4kpasswd --cache=$PREFIX/tmpccache host/nettestuser@$REALM || failed=`expr $failed + 1`
+
+testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
+
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+cat > $PREFIX/tmpldbmodify <<EOF
+dn: cn=nettestuser,cn=users,$BASEDN
+changetype: modify
+replace: pwdLastSet
+pwdLastSet: 0
+EOF
+
+USERPASS=$NEWUSERPASS
+NEWUSERPASS=testPaSS at 911%
+
+testit "modify pwdLastSet" $VALGRIND $ldbmodify $ADMIN_LDBMODIFY_CONFIG $PREFIX/tmpldbmodify $PREFIX/tmpldbmodify -k yes $@ || failed=`expr $failed + 1`
+
+cat > $PREFIX/tmppasswordchange <<EOF
+expect nettestuser@${REALM}'s Password:
+send ${USERPASS}\n
+expect Your password will expire at
+expect Changing password
+expect New password:
+send ${NEWUSERPASS}\n
+expect Repeat new password:
+send ${NEWUSERPASS}\n
+expect Success: Password changed
+EOF
+
+testit "kinit with user password for expired password" $texpect $PREFIX/tmppasswordchange $samba4kinit $enctype --request-pac nettestuser@$REALM && failed=`expr $failed + 1`
+
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+echo $NEWUSERPASS > $PREFIX/tmpuserpassfile
+testit "kinit with user password" $samba4kinit $enctype --password-file=$PREFIX/tmpuserpassfile --request-pac nettestuser@$REALM   || failed=`expr $failed + 1`
+
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+KRB5CCNAME_PATH="$PREFIX/tmpccache"
+KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+export KRB5CCNAME
+
+rm -rf $KRB5CCNAME_PATH
+
+lowerrealm=$(echo $REALM | tr '[A-Z]' '[a-z]')
+test_smbclient "Test login with user kerberos lowercase realm" 'ls' -k yes -Unettestuser@$lowerrealm%$NEWUSERPASS || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos lowercase realm 2" 'ls' -k yes -Unettestuser@$REALM%$NEWUSERPASS --realm=$lowerrealm || failed=`expr $failed + 1`
+
+testit "del user with kerberos ccache" $VALGRIND $samba_tool user delete nettestuser $CONFIGURATION -k yes $@ || failed=`expr $failed + 1`
+
+rm -f $KRB5CCNAME_PATH
+testit "kinit with machineaccountccache script" $machineaccountccache $CONFIGURATION $KRB5CCNAME || failed=`expr $failed + 1`
+test_smbclient "Test machine account login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+testit "reset password policies" $VALGRIND $samba_tool domain passwordsettings $ADMIN_LDBMODIFY_CONFIG set --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default || failed=`expr $failed + 1`
+
+rm -f $PREFIX/tmpccache tmpccfile tmppassfile tmpuserpassfile tmpuserccache tmpkpasswdscript
+exit $failed
diff --git a/testprogs/blackbox/test_kinit_trusts.sh b/testprogs/blackbox/test_kinit_trusts_heimdal.sh
similarity index 100%
rename from testprogs/blackbox/test_kinit_trusts.sh
rename to testprogs/blackbox/test_kinit_trusts_heimdal.sh
diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh
new file mode 100755
index 0000000..487014d
--- /dev/null
+++ b/testprogs/blackbox/test_net_ads.sh
@@ -0,0 +1,35 @@
+if [ $# -lt 3 ]; then
+cat <<EOF
+Usage: test_net.sh SERVER USERNAME PASSWORD
+EOF
+exit 1;
+fi
+
+DC_SERVER=$1
+DC_USERNAME=$2
+DC_PASSWORD=$3
+
+failed=0
+
+net_tool="$BINDIR/net"
+
+# Load test functions
+. `dirname $0`/subunit.sh
+
+testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
+
+testit "join+server" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD -S$DC_SERVER || failed=`expr $failed + 1`
+
+testit "leave+server" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD -S$DC_SERVER || failed=`expr $failed + 1`
+
+testit_expect_failure "join+invalid_server" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD -SINVALID && failed=`expr $failed + 1`
+
+testit "join+server" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
+
+testit_expect_failure "leave+invalid_server" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD -SINVALID && failed=`expr $failed + 1`
+
+testit "testjoin" $VALGRIND $net_tool ads testjoin -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
+
+testit "testjoin_machine_account" $VALGRIND $net_tool ads testjoin -kP || failed=`expr $failed + 1`
+
+exit $failed
diff --git a/testprogs/blackbox/test_pdbtest.sh b/testprogs/blackbox/test_pdbtest.sh
index 017116c..e29df75 100755
--- a/testprogs/blackbox/test_pdbtest.sh
+++ b/testprogs/blackbox/test_pdbtest.sh
@@ -98,6 +98,13 @@ testit "modify user - disable password expiry"  $VALGRIND $net sam set pwnoexp $
 
 test_smbclient "Test login with no expiry (ntlm)" 'ls' -k no -U$USER%$NEWUSERPASS || failed=`expr $failed + 1`
 
+NEWUSERPASS=testPaSS at 03%
+NEWUSERHASH=062519096c45739c1938800f80906731
+
+testit "Set user password with password hash" $VALGRIND $pdbedit -u $USER --set-nt-hash $NEWUSERHASH $@ || failed=`expr $failed + 1`
+
+test_smbclient "Test login with new password (from hash)" 'ls' -k no -U$USER%$NEWUSERPASS || failed=`expr $failed + 1`
+
 testit "del user"  $VALGRIND $pdbedit -x $USER $@ || failed=`expr $failed + 1`
 
 rm ./tmpsmbpasswdscript
diff --git a/testprogs/blackbox/test_pkinit.sh b/testprogs/blackbox/test_pkinit_heimdal.sh
similarity index 100%
rename from testprogs/blackbox/test_pkinit.sh
rename to testprogs/blackbox/test_pkinit_heimdal.sh
diff --git a/testprogs/win32/spoolss/README.win32 b/testprogs/win32/spoolss/README.win32
index 1e7bacc..0c10f60 100644
--- a/testprogs/win32/spoolss/README.win32
+++ b/testprogs/win32/spoolss/README.win32
@@ -35,7 +35,7 @@ usage: testspoolss.exe <name> [print] [samba3] [architecture=ARCHITECTURE]
                          from the printserver
         [samba3]         will skip some tests samba servers are known
                          not to have implemented
-        [architecture=X] allows to define a specific
+        [architecture=X] allows one to define a specific
                          architecture to test with. choose between:
                          "Windows NT x86" or "Windows x64"
 ..............................................................................
diff --git a/testprogs/win32/spoolss/testspoolss.c b/testprogs/win32/spoolss/testspoolss.c
index 422cca4..794e545 100644
--- a/testprogs/win32/spoolss/testspoolss.c
+++ b/testprogs/win32/spoolss/testspoolss.c
@@ -1055,7 +1055,7 @@ static BOOL test_OnePrinter(struct torture_context *tctx,
 	ret &= test_EnumPrinterDataEx(tctx, printername, "PrinterDriverData", handle, NULL, NULL);
 	ret &= test_DeviceModes(tctx, printername, handle);
 #if 0
-	/* dont run these at the moment, behaviour is PrinterData API calls (not
+	/* don't run these at the moment, behaviour is PrinterData API calls (not
 	 * dcerpc calls) is almost unpredictable - gd */
 	ret &= test_PrinterData(tctx, printername, handle);
 	ret &= test_PrinterDataW(tctx, printername, handle);
@@ -1765,7 +1765,7 @@ int main(int argc, char *argv[])
 		fprintf(stderr, "\t                 from the printserver\n");
 		fprintf(stderr, "\t[samba3]         will skip some tests samba servers are known\n");
 		fprintf(stderr, "\t                 not to have implemented\n");
-		fprintf(stderr, "\t[architecture=X] allows to define a specific\n");
+		fprintf(stderr, "\t[architecture=X] allows one to define a specific\n");
 		fprintf(stderr, "\t                 architecture to test with. choose between:\n");
 		fprintf(stderr, "\t                 \"Windows NT x86\" or \"Windows x64\"\n");
 		exit(-1);
diff --git a/tests/oldquotas.c b/tests/oldquotas.c
new file mode 100644
index 0000000..bdb2beb
--- /dev/null
+++ b/tests/oldquotas.c
@@ -0,0 +1,174 @@
+/* this test should find out whether legacy quota code in disk_quotas.c
+ * compiles. It is a stripped-down version of disk_quotas.c, with samba
+ * stuff removed and only system calls, header files, and constants left.
+ */
+
+#ifndef HAVE_SYS_QUOTAS
+
+/* just a quick hack because sysquotas.h is included before linux/quota.h */
+#ifdef QUOTABLOCK_SIZE
+#undef QUOTABLOCK_SIZE
+#endif
+
+#ifdef WITH_QUOTAS
+
+#if defined(VXFS_QUOTA)
+
+bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize,
+		      uint64_t *dfree, uint64_t *dsize);
+
+#endif /* VXFS_QUOTA */
+
+#if defined(SUNOS5) || defined(SUNOS4)
+
+#include <fcntl.h>
+#include <sys/param.h>
+#if defined(SUNOS5)
+#include <sys/fs/ufs_quota.h>
+#include <sys/mnttab.h>
+#include <sys/mntent.h>
+#else /* defined(SUNOS4) */
+#include <ufs/quota.h>
+#include <mntent.h>
+#endif
+
+#if defined(SUNOS5)
+
+/****************************************************************************
+ Allows querying of remote hosts for quotas on NFS mounted shares.
+ Supports normal NFS and AMD mounts.
+ Alan Romeril <a.romeril at ic.ac.uk> July 2K.
+****************************************************************************/
+
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpcsvc/rquota.h>
+#include <rpc/nettype.h>
+#include <rpc/xdr.h>
+
+static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize,
+		       uint64_t *dfree, uint64_t *dsize)
+{
+	CLIENT *clnt;
+	clnt = clnt_create("host", RQUOTAPROG, RQUOTAVERS, "udp");
+	return true;
+}
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas (SunOS & Solaris2 version)
+Quota code by Peter Urbanec (amiga at cse.unsw.edu.au).
+****************************************************************************/
+
+bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree,
+		 uint64_t *dsize)
+{
+	int ret;
+#if defined(SUNOS5)
+	struct quotctl command;
+#else /* SunOS4 */
+	struct mntent *mnt;
+#endif
+#if defined(SUNOS5)
+	nfs_quotas("", 0, bsize, dfree, dsize);
+
+	command.op = Q_GETQUOTA;
+	command.uid = 0;
+	command.addr = NULL;
+	ret = ioctl(1, Q_QUOTACTL, &command);
+#else
+	ret = quotactl(Q_GETQUOTA, "", 0, NULL);
+#endif
+
+#if defined(SUNOS5) && defined(VXFS_QUOTA)
+	disk_quotas_vxfs("", path, bsize, dfree, dsize);
+#endif
+	return true;
+}
+
+#else
+
+#if AIX
+/* AIX quota patch from Ole Holm Nielsen <ohnielse at fysik.dtu.dk> */
+#include <jfs/quota.h>
+/* AIX 4.X: Rename members of the dqblk structure (ohnielse at fysik.dtu.dk) */
+#define dqb_curfiles dqb_curinodes
+#define dqb_fhardlimit dqb_ihardlimit
+#define dqb_fsoftlimit dqb_isoftlimit
+#ifdef _AIXVERSION_530
+#include <sys/statfs.h>
+#include <sys/vmount.h>
+#endif /* AIX 5.3 */
+#else  /* !AIX */
+#include <sys/quota.h>
+#include <devnm.h>
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas - default version
+****************************************************************************/
+
+bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree,
+		 uint64_t *dsize)
+{
+	struct dqblk D;
+#if defined(AIX)
+#ifdef _AIXVERSION_530
+	quota64_t user_quota;
+	quotactl(path, QCMD(Q_J2GETQUOTA, USRQUOTA), 0, (char *)&user_quota);
+#endif /* AIX 5.3 */
+	quotactl(path, QCMD(Q_GETQUOTA, USRQUOTA), 0, (char *)&D);
+#else  /* !AIX */
+	quotactl(Q_GETQUOTA, "", 0, &D);
+#endif /* !AIX */
+	return (true);
+}
+
+#endif
+
+#if defined(VXFS_QUOTA)
+
+#if defined(SUNOS5)
+
+#include <sys/fs/vx_solaris.h>
+#include <sys/fs/vx_machdep.h>
+#include <sys/fs/vx_layout.h>
+#include <sys/fs/vx_quota.h>
+#include <sys/fs/vx_aioctl.h>
+#include <sys/fs/vx_ioctl.h>
+
+bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize,
+		      uint64_t *dfree, uint64_t *dsize)
+{
+	struct vx_dqblk D;
+	struct vx_quotctl quotabuf;
+	struct vx_genioctl genbuf;
+
+	genbuf.ioc_cmd = VX_QUOTACTL;
+	genbuf.ioc_up = (void *)"abuf;
+
+	quotabuf.cmd = VX_GETQUOTA;
+	quotabuf.uid = 0;
+	quotabuf.addr = (caddr_t)&D;
+	ret = ioctl(1, VX_ADMIN_IOCTL, &genbuf);
+
+	return true;
+}
+
+#endif /* SUNOS5 || ... */
+
+#endif /* VXFS_QUOTA */
+
+#else /* WITH_QUOTAS */
+
+#error "This test should be called with WITH_QUOTAS defined"
+
+#endif /* WITH_QUOTAS */
+
+#else /* HAVE_SYS_QUOTAS */
+
+#error "This test should not be called for systems with new quota interface"
+
+#endif /* HAVE_SYS_QUOTAS */
+
+int main() { return disk_quotas(NULL, NULL, NULL, NULL); }
diff --git a/testsuite/headers/wscript_build b/testsuite/headers/wscript_build
index d0625a0..64b10ba 100644
--- a/testsuite/headers/wscript_build
+++ b/testsuite/headers/wscript_build
@@ -24,22 +24,13 @@ bld.SAMBA_GENERATOR('test_headers.h',
                     source=public_headers,
                     target='test_headers.h')
 
-cflags=''
-for lib in ['talloc', 'tevent', 'tdb', 'ldb', 'popt' ]:
-    ename = 'CPPPATH_%s' % lib.upper()
-    for p in bld.env[ename]:
-        cflags += bld.env.CPPPATH_ST % p + ' '
-
-if not bld.env.USING_SYSTEM_POPT:
-    cflags += bld.env.CPPPATH_ST % '../third_party/popt'
-
 if bld.env.DEVELOPER_MODE:
     bld.SAMBA_BINARY('test_headers',
                      source='test_headers.c',
                      includes="#include/public",
                      pyembed=True,
-                     cflags=cflags,
                      local_include=True,
                      global_include=False,
                      use_global_deps=False,
-                     install=False)
+                     install=False,
+                     deps='talloc tdb ldb tevent popt')
diff --git a/third_party/waf/wafadmin/3rdparty/gccdeps.py b/third_party/waf/wafadmin/3rdparty/gccdeps.py
index 28a889d..55cd515 100644
--- a/third_party/waf/wafadmin/3rdparty/gccdeps.py
+++ b/third_party/waf/wafadmin/3rdparty/gccdeps.py
@@ -15,7 +15,7 @@ lock = threading.Lock()
 
 preprocessor_flag = '-MD'
 
- at feature('cc')
+ at feature('cc', 'c')
 @before('apply_core')
 def add_mmd_cc(self):
 	if self.env.get_flat('CCFLAGS').find(preprocessor_flag) < 0:
diff --git a/third_party/waf/wafadmin/3rdparty/print_commands.py b/third_party/waf/wafadmin/3rdparty/print_commands.py
new file mode 100644
index 0000000..3b12aa3
--- /dev/null
+++ b/third_party/waf/wafadmin/3rdparty/print_commands.py
@@ -0,0 +1,25 @@
+#! /usr/bin/env python
+
+"""
+In this case, print the commands being executed as strings
+(the commands are usually lists, so this can be misleading)
+"""
+
+import Build, Utils, Logs
+
+def exec_command(self, cmd, **kw):
+	txt = cmd
+	if isinstance(cmd, list):
+		txt = ' '.join(cmd)
+	Logs.debug('runner: %s' % txt)
+	if self.log:
+		self.log.write('%s\n' % cmd)
+		kw['log'] = self.log
+	try:
+		if not kw.get('cwd', None):
+			kw['cwd'] = self.cwd
+	except AttributeError:
+		self.cwd = kw['cwd'] = self.bldnode.abspath()
+	return Utils.exec_command(cmd, **kw)
+Build.BuildContext.exec_command = exec_command
+
diff --git a/third_party/waf/wafadmin/Build.py b/third_party/waf/wafadmin/Build.py
index 50f4d7f..d36d3df 100644
--- a/third_party/waf/wafadmin/Build.py
+++ b/third_party/waf/wafadmin/Build.py
@@ -645,6 +645,10 @@ class BuildContext(Utils.Context):
 						cache[v] = x
 		return cache.get(env.variant() + '_' + name, None)
 
+	def get_tgen_by_name(self, name):
+		"""waf 1.8 api"""
+		return self.name_to_obj(name, self.env)
+
 	def flush(self, all=1):
 		"""tell the task generators to create the tasks"""
 
diff --git a/third_party/waf/wafadmin/Node.py b/third_party/waf/wafadmin/Node.py
index 158a4a4..6b03726 100644
--- a/third_party/waf/wafadmin/Node.py
+++ b/third_party/waf/wafadmin/Node.py
@@ -689,6 +689,13 @@ class Node(object):
 					child = self.ensure_dir_node_from_path(k)
 				child.update_build_dir(env)
 
+	def read(self, flags='r', encoding='ISO8859-1'):
+		"""backported from waf 1.8"""
+		return Utils.readf(self.abspath(), flags, encoding)
+
+	def write(self, data, flags='w', encoding='ISO8859-1'):
+		"""backported from waf 1.8"""
+		Utils.writef(self.abspath(self.bld.env), data, flags, encoding)
 
 class Nodu(Node):
 	pass
diff --git a/third_party/waf/wafadmin/TaskGen.py b/third_party/waf/wafadmin/TaskGen.py
index 5900809..386798f 100644
--- a/third_party/waf/wafadmin/TaskGen.py
+++ b/third_party/waf/wafadmin/TaskGen.py
@@ -242,6 +242,9 @@ class task_gen(object):
 	def name_to_obj(self, name):
 		return self.bld.name_to_obj(name, self.env)
 
+	def get_tgen_by_name(self, name):
+		return self.bld.get_tgen_by_name(name)
+
 	def find_sources_in_dirs(self, dirnames, excludes=[], exts=[]):
 		"""
 		The attributes "excludes" and "exts" must be lists to avoid the confusion
diff --git a/third_party/waf/wafadmin/Tools/cc.py b/third_party/waf/wafadmin/Tools/cc.py
index e54df47..7eb5272 100644
--- a/third_party/waf/wafadmin/Tools/cc.py
+++ b/third_party/waf/wafadmin/Tools/cc.py
@@ -23,7 +23,7 @@ g_cc_type_vars = ['CCFLAGS', 'LINKFLAGS']
 class cc_taskgen(ccroot.ccroot_abstract):
 	pass
 
- at feature('cc')
+ at feature('c', 'cc')
 @before('apply_type_vars')
 @after('default_cc')
 def init_cc(self):
@@ -33,7 +33,7 @@ def init_cc(self):
 	if not self.env['CC_NAME']:
 		raise Utils.WafError("At least one compiler (gcc, ..) must be selected")
 
- at feature('cc')
+ at feature('c', 'cc')
 @after('apply_incpaths')
 def apply_obj_vars_cc(self):
 	"""after apply_incpaths for INC_PATHS"""
@@ -51,7 +51,7 @@ def apply_obj_vars_cc(self):
 	for i in env['CPPPATH']:
 		app('_CCINCFLAGS', cpppath_st % i)
 
- at feature('cc')
+ at feature('c', 'cc')
 @after('apply_lib_vars')
 def apply_defines_cc(self):
 	"""after uselib is set for CCDEFINES"""
diff --git a/third_party/waf/wafadmin/Tools/ccroot.py b/third_party/waf/wafadmin/Tools/ccroot.py
index c130b40..2240b2f 100644
--- a/third_party/waf/wafadmin/Tools/ccroot.py
+++ b/third_party/waf/wafadmin/Tools/ccroot.py
@@ -190,7 +190,7 @@ def get_target_name(self):
 
 	return os.path.join(dir, pattern % name)
 
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 @before('apply_core')
 def default_cc(self):
 	"""compiled_tasks attribute must be set before the '.c->.o' tasks can be created"""
@@ -253,7 +253,7 @@ def default_link_install(self):
 	if self.install_path:
 		self.bld.install_files(self.install_path, self.link_task.outputs[0], env=self.env, chmod=self.chmod)
 
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 @after('apply_type_vars', 'apply_lib_vars', 'apply_core')
 def apply_incpaths(self):
 	"""used by the scanner
@@ -297,7 +297,7 @@ def apply_incpaths(self):
 	if USE_TOP_LEVEL:
 		self.env.append_value('INC_PATHS', self.bld.srcnode)
 
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 @after('init_cc', 'init_cxx')
 @before('apply_lib_vars')
 def apply_type_vars(self):
@@ -339,7 +339,7 @@ def apply_link(self):
 
 	self.link_task = tsk
 
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 @after('apply_link', 'init_cc', 'init_cxx', 'apply_core')
 def apply_lib_vars(self):
 	"""after apply_link because of 'link_task'
@@ -523,7 +523,7 @@ c_attrs = {
 'frameworkpath' : 'FRAMEWORKPATH'
 }
 
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 @before('init_cxx', 'init_cc')
 @before('apply_lib_vars', 'apply_obj_vars', 'apply_incpaths', 'init_cc')
 def add_extra_flags(self):
diff --git a/third_party/waf/wafadmin/Tools/config_c.py b/third_party/waf/wafadmin/Tools/config_c.py
index 9f1103c..3ab447c 100644
--- a/third_party/waf/wafadmin/Tools/config_c.py
+++ b/third_party/waf/wafadmin/Tools/config_c.py
@@ -82,6 +82,10 @@ def parse_flags(line, uselib, env):
 		# RPATH later, and hence can potentially lead to linking
 		# in too old versions of our internal libs.
 		#
+		elif x == '-Wl,-rpath' or x == '-Wl,-R':
+			app('RPATH_' + uselib, lst.pop(0).lstrip('-Wl,'))
+		elif x.startswith('-Wl,-R,'):
+			app('RPATH_' + uselib, x[7:])
 		elif x.startswith('-Wl,-R'):
 			app('RPATH_' + uselib, x[6:])
 		elif x.startswith('-Wl,-rpath,'):
diff --git a/third_party/waf/wafadmin/Tools/msvc.py b/third_party/waf/wafadmin/Tools/msvc.py
index 2a97d19..72e7376 100644
--- a/third_party/waf/wafadmin/Tools/msvc.py
+++ b/third_party/waf/wafadmin/Tools/msvc.py
@@ -638,7 +638,7 @@ def msvc_common_flags(conf):
 ##### conf above, build below
 
 @after('apply_link')
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 def apply_flags_msvc(self):
 	if self.env.CC_NAME != 'msvc' or not self.link_task:
 		return
diff --git a/third_party/waf/wafadmin/Tools/osx.py b/third_party/waf/wafadmin/Tools/osx.py
index 88ca0d9..95184ee 100644
--- a/third_party/waf/wafadmin/Tools/osx.py
+++ b/third_party/waf/wafadmin/Tools/osx.py
@@ -38,7 +38,7 @@ app_info = '''
 
 # see WAF issue 285
 # and also http://trac.macports.org/ticket/17059
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 @before('apply_lib_vars')
 def set_macosx_deployment_target(self):
 	if self.env['MACOSX_DEPLOYMENT_TARGET']:
@@ -47,7 +47,7 @@ def set_macosx_deployment_target(self):
 		if sys.platform == 'darwin':
 			os.environ['MACOSX_DEPLOYMENT_TARGET'] = '.'.join(platform.mac_ver()[0].split('.')[:2])
 
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 @after('apply_lib_vars')
 def apply_framework(self):
 	for x in self.to_list(self.env['FRAMEWORKPATH']):
@@ -145,7 +145,7 @@ def apply_link_osx(self):
 		self.env.append_value('LINKFLAGS', path)
 
 @before('apply_link', 'apply_lib_vars')
- at feature('cc', 'cxx')
+ at feature('c', 'cc', 'cxx')
 def apply_bundle(self):
 	"""use env['MACBUNDLE'] to force all shlibs into mac bundles
 	or use obj.mac_bundle = True for specific targets only"""
diff --git a/third_party/waf/wafadmin/Utils.py b/third_party/waf/wafadmin/Utils.py
index 5a59a4c..abb46a7 100644
--- a/third_party/waf/wafadmin/Utils.py
+++ b/third_party/waf/wafadmin/Utils.py
@@ -147,6 +147,38 @@ except ImportError:
 		# portability fixes may be added elsewhere (although, md5 should be everywhere by now)
 		md5 = None
 
+def readf(fname, m='r', encoding='ISO8859-1'):
+	"""backported from waf 1.8"""
+	if sys.hexversion > 0x3000000 and not 'b' in m:
+		m += 'b'
+		f = open(fname, m)
+		try:
+			txt = f.read()
+		finally:
+			f.close()
+		if encoding:
+			txt = txt.decode(encoding)
+		else:
+			txt = txt.decode()
+	else:
+		f = open(fname, m)
+		try:
+			txt = f.read()
+		finally:
+			f.close()
+	return txt
+
+def writef(fname, data, m='w', encoding='ISO8859-1'):
+	"""backported from waf 1.8"""
+	if sys.hexversion > 0x3000000 and not 'b' in m:
+		data = data.encode(encoding)
+		m += 'b'
+	f = open(fname, m)
+	try:
+		f.write(data)
+	finally:
+		f.close()
+
 class ordered_dict(UserDict):
 	def __init__(self, dict = None):
 		self.allkeys = []
@@ -423,8 +455,7 @@ def check_dir(path):
 			os.makedirs(path)
 		except OSError, e:
 			if not os.path.isdir(path):
-				raise Errors.WafError('Cannot create the folder %r' % path, ex=e)
-
+				raise WafError("Cannot create the folder '%s' (error: %s)" % (path, e))
 
 def cmd_output(cmd, **kw):
 
@@ -557,15 +588,6 @@ def load_tool(tool, tooldir=None):
 		for dt in tooldir:
 			sys.path.remove(dt)
 
-def readf(fname, m='r'):
-	"get the contents of a file, it is not used anywhere for the moment"
-	f = open(fname, m)
-	try:
-		txt = f.read()
-	finally:
-		f.close()
-	return txt
-
 def nada(*k, **kw):
 	"""A function that does nothing"""
 	pass
diff --git a/wscript b/wscript
index 9431e11..41ed5da 100644
--- a/wscript
+++ b/wscript
@@ -15,7 +15,7 @@ samba_dist.DIST_DIRS('.')
 samba_dist.DIST_BLACKLIST('.gitignore .bzrignore source4/selftest/provisions')
 
 # install in /usr/local/samba by default
-Options.default_prefix = '/usr/local/samba'
+default_prefix = Options.default_prefix = '/usr/local/samba'
 
 # This callback optionally takes a list of paths as arguments:
 # --with-system_mitkrb5 /path/to/krb5 /another/path
@@ -53,6 +53,14 @@ def set_options(opt):
                    help='disable AD DC functionality (enables Samba 4 client and Samba 3 code base).',
                    action='store_true', dest='without_ad_dc', default=False)
 
+    opt.add_option('--with-ntvfs-fileserver',
+                   help='enable the depricated NTVFS file server from the original Samba4 branch (default if --enable-selftest specicifed).  Conflicts with --with-system-mitkrb5 and --without-ad-dc',
+                   action='store_true', dest='with_ntvfs_fileserver')
+
+    opt.add_option('--without-ntvfs-fileserver',
+                   help='disable the depricated NTVFS file server from the original Samba4 branch',
+                   action='store_false', dest='with_ntvfs_fileserver')
+
     opt.add_option('--with-pie',
                   help=("Build Position Independent Executables " +
                         "(default if supported by compiler)"),
@@ -132,6 +140,7 @@ def configure(conf):
         conf.PROCESS_SEPARATE_RULE('system_mitkrb5')
     if not (Options.options.without_ad_dc or Options.options.with_system_mitkrb5):
         conf.DEFINE('AD_DC_BUILD_IS_ENABLED', 1)
+
     # Only process heimdal_build for non-MIT KRB5 builds
     # When MIT KRB5 checks are done as above, conf.env.KRB5_VENDOR will be set
     # to the lowcased output of 'krb5-config --vendor'.
@@ -154,10 +163,24 @@ def configure(conf):
         conf.RECURSE('lib/resolv_wrapper')
         conf.RECURSE('lib/socket_wrapper')
         conf.RECURSE('lib/uid_wrapper')
+        if Options.options.with_ntvfs_fileserver != False:
+            if not (Options.options.without_ad_dc or Options.options.with_system_mitkrb5):
+                conf.DEFINE('WITH_NTVFS_FILESERVER', 1)
+        if Options.options.with_ntvfs_fileserver == False:
+            if not (Options.options.without_ad_dc or Options.options.with_system_mitkrb5):
+                raise Utils.WafError('--without-ntvfs-fileserver conflicts with --enable-selftest while building the AD DC')
+
+    if Options.options.with_ntvfs_fileserver == True:
+        if Options.options.without_ad_dc:
+            raise Utils.WafError('--with-ntvfs-fileserver conflicts with --without-ad-dc')
+        if Options.options.with_system_mitkrb5:
+            raise Utils.WafError('--with-ntvfs-fileserver conflicts with --with-system-mitkrb5')
+        conf.DEFINE('WITH_NTVFS_FILESERVER', 1)
     conf.RECURSE('source3')
     conf.RECURSE('lib/texpect')
     if conf.env.with_ctdb:
         conf.RECURSE('ctdb')
+    conf.RECURSE('lib/socket')
 
     conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-samba/samba.git




More information about the Pkg-samba-maint mailing list