wafsamba/samba_autoconf: when setting undefined result, use empty tuple
[samba.git] / source4 / libnet / libnet_unbecome_dc.c
index c0dbfcc68d4000420d043340fc0cf18585acf4a9..38d6a94b23f1bd973d7c84af796ace2467c116b6 100644 (file)
@@ -1,11 +1,11 @@
 /*
    Unix SMB/CIFS implementation.
 
-   Copyright (C) Stefan Metzmacher     2006
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 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 2 of the License, or
+   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,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "libnet/libnet.h"
 #include "libcli/composite/composite.h"
 #include "libcli/cldap/cldap.h"
-#include "lib/ldb/include/ldb.h"
-#include "lib/ldb/include/ldb_errors.h"
-#include "lib/db_wrap.h"
+#include <ldb.h>
+#include <ldb_errors.h>
+#include "ldb_wrap.h"
 #include "dsdb/samdb/samdb.h"
-#include "dsdb/common/flags.h"
+#include "../libds/common/flags.h"
 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
+#include "param/param.h"
+#include "lib/tsocket/tsocket.h"
+
+/*****************************************************************************
+ * Windows 2003 (w2k3) does the following steps when changing the server role
+ * from domain controller back to domain member
+ *
+ * We mostly do the same.
+ *****************************************************************************/
+
+/*
+ * lookup DC:
+ * - using nbt name<1C> request and a samlogon mailslot request
+ * or
+ * - using a DNS SRV _ldap._tcp.dc._msdcs. request and a CLDAP netlogon request
+ *
+ * see: unbecomeDC_send_cldap() and unbecomeDC_recv_cldap()
+ */
+
+/*
+ * Open 1st LDAP connection to the DC using admin credentials
+ *
+ * see: unbecomeDC_ldap_connect()
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: unbecomeDC_ldap_rootdse()
+ *
+ * Request:
+ *     basedn: ""
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  defaultNamingContext
+ *             configurationNamingContext
+ * Result:
+ *      ""
+ *             defaultNamingContext:   <domain_partition>
+ *             configurationNamingContext:CN=Configuration,<domain_partition>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ * 
+ * see: unbecomeDC_ldap_computer_object()
+ *
+ * Request:
+ *     basedn: <domain_partition>
+ *     scope:  sub
+ *     filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
+ *     attrs:  distinguishedName
+ *             userAccountControl
+ * Result:
+ *      CN=<new_dc_netbios_name>,CN=Domain Controllers,<domain_partition>
+ *             distinguishedName:      CN=<new_dc_netbios_name>,CN=Domain Controllers,<domain_partition>
+ *             userAccoountControl:    532480 <0x82000>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ * 
+ * see: unbecomeDC_ldap_modify_computer()
+ *
+ * Request:
+ *     basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  userAccountControl
+ * Result:
+ *      CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *             userAccoountControl:    532480 <0x82000>
+ */
+
+/*
+ * LDAP modify 1st LDAP connection:
+ *
+ * see: unbecomeDC_ldap_modify_computer()
+ * 
+ * Request (replace):
+ *     CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *     userAccoountControl:    4096 <0x1000>
+ * Result:
+ *     <success>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ * 
+ * see: unbecomeDC_ldap_move_computer()
+ *
+ * Request:
+ *     basedn: <WKGUID=aa312825768811d1aded00c04fd8d5cd,<domain_partition>>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  1.1
+ * Result:
+ *     CN=Computers,<domain_partition>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * not implemented because it doesn't give any new information
+ *
+ * Request:
+ *     basedn: CN=Computers,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  distinguishedName
+ * Result:
+ *     CN=Computers,<domain_partition>
+ *             distinguishedName:      CN=Computers,<domain_partition>
+ */
+
+/*
+ * LDAP modifyRDN 1st LDAP connection:
+ * 
+ * see: unbecomeDC_ldap_move_computer()
+ *
+ * Request:
+ *      entry:         CN=<new_dc_netbios_name>,CN=Domain Controllers,<domain_partition>
+ *     newrdn:         CN=<new_dc_netbios_name>
+ *     deleteoldrdn:   TRUE
+ *     newparent:      CN=Computers,<domain_partition>
+ * Result:
+ *     <success>
+ */
+
+/*
+ * LDAP unbind on the 1st LDAP connection
+ *
+ * not implemented, because it's not needed...
+ */
+
+/*
+ * Open 1st DRSUAPI connection to the DC using admin credentials
+ * DsBind with DRSUAPI_DS_BIND_GUID ("e24d201a-4fd6-11d1-a3da-0000f875ae0d")
+ *
+ * see:        unbecomeDC_drsuapi_connect_send(), unbecomeDC_drsuapi_connect_recv(),
+ *     unbecomeDC_drsuapi_bind_send() and unbecomeDC_drsuapi_bind_recv()
+ */
+
+/*
+ * DsRemoveDsServer to remove the 
+ * CN=<machine_name>,CN=Servers,CN=<site_name>,CN=Configuration,<domain_partition>
+ * and CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=<site_name>,CN=Configuration,<domain_partition>
+ * on the 1st DRSUAPI connection
+ *
+ * see: unbecomeDC_drsuapi_remove_ds_server_send() and unbecomeDC_drsuapi_remove_ds_server_recv()
+ */
+
+/*
+ * DsUnbind on the 1st DRSUAPI connection
+ *
+ * not implemented, because it's not needed...
+ */
+
 
 struct libnet_UnbecomeDC_state {
        struct composite_context *creq;
@@ -37,7 +194,7 @@ struct libnet_UnbecomeDC_state {
        struct {
                struct cldap_socket *sock;
                struct cldap_netlogon io;
-               struct nbt_cldap_netlogon_5 netlogon5;
+               struct NETLOGON_SAM_LOGON_RESPONSE_EX netlogon;
        } cldap;
 
        struct {
@@ -47,6 +204,7 @@ struct libnet_UnbecomeDC_state {
        struct {
                struct dcerpc_binding *binding;
                struct dcerpc_pipe *pipe;
+               struct dcerpc_binding_handle *drsuapi_handle;
                struct drsuapi_DsBind bind_r;
                struct GUID bind_guid;
                struct drsuapi_DsBindInfoCtr bind_info_ctr;
@@ -94,53 +252,67 @@ struct libnet_UnbecomeDC_state {
        } dest_dsa;
 };
 
-static void unbecomeDC_recv_cldap(struct cldap_request *req);
+static void unbecomeDC_recv_cldap(struct tevent_req *req);
 
 static void unbecomeDC_send_cldap(struct libnet_UnbecomeDC_state *s)
 {
        struct composite_context *c = s->creq;
-       struct cldap_request *req;
+       struct tevent_req *req;
+       struct tsocket_address *dest_address;
+       int ret;
 
-       s->cldap.io.in.dest_address     = s->source_dsa.address;
+       s->cldap.io.in.dest_address     = NULL;
+       s->cldap.io.in.dest_port        = 0;
        s->cldap.io.in.realm            = s->domain.dns_name;
        s->cldap.io.in.host             = s->dest_dsa.netbios_name;
        s->cldap.io.in.user             = NULL;
        s->cldap.io.in.domain_guid      = NULL;
        s->cldap.io.in.domain_sid       = NULL;
        s->cldap.io.in.acct_control     = -1;
-       s->cldap.io.in.version          = 6;
+       s->cldap.io.in.version          = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
+       s->cldap.io.in.map_response     = true;
 
-       s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
-       if (composite_nomem(s->cldap.sock, c)) return;
+       ret = tsocket_address_inet_from_strings(s, "ip",
+                                               s->source_dsa.address,
+                                               lpcfg_cldap_port(s->libnet->lp_ctx),
+                                               &dest_address);
+       if (ret != 0) {
+               c->status = map_nt_error_from_unix_common(errno);
+               if (!composite_is_ok(c)) return;
+       }
 
-       req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
+       c->status = cldap_socket_init(s, NULL, dest_address, &s->cldap.sock);
+       if (!composite_is_ok(c)) return;
+
+       req = cldap_netlogon_send(s, s->libnet->event_ctx,
+                                 s->cldap.sock, &s->cldap.io);
        if (composite_nomem(req, c)) return;
-       req->async.fn           = unbecomeDC_recv_cldap;
-       req->async.private      = s;
+       tevent_req_set_callback(req, unbecomeDC_recv_cldap, s);
 }
 
 static void unbecomeDC_connect_ldap(struct libnet_UnbecomeDC_state *s);
 
-static void unbecomeDC_recv_cldap(struct cldap_request *req)
+static void unbecomeDC_recv_cldap(struct tevent_req *req)
 {
-       struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_UnbecomeDC_state *s = tevent_req_callback_data(req,
                                            struct libnet_UnbecomeDC_state);
        struct composite_context *c = s->creq;
 
        c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
+       talloc_free(req);
        if (!composite_is_ok(c)) return;
 
-       s->cldap.netlogon5 = s->cldap.io.out.netlogon.logon5;
+       s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex;
 
-       s->domain.dns_name              = s->cldap.netlogon5.dns_domain;
-       s->domain.netbios_name          = s->cldap.netlogon5.domain;
-       s->domain.guid                  = s->cldap.netlogon5.domain_uuid;
+       s->domain.dns_name              = s->cldap.netlogon.dns_domain;
+       s->domain.netbios_name          = s->cldap.netlogon.domain_name;
+       s->domain.guid                  = s->cldap.netlogon.domain_uuid;
 
-       s->source_dsa.dns_name          = s->cldap.netlogon5.pdc_dns_name;
-       s->source_dsa.netbios_name      = s->cldap.netlogon5.pdc_name;
-       s->source_dsa.site_name         = s->cldap.netlogon5.server_site;
+       s->source_dsa.dns_name          = s->cldap.netlogon.pdc_dns_name;
+       s->source_dsa.netbios_name      = s->cldap.netlogon.pdc_name;
+       s->source_dsa.site_name         = s->cldap.netlogon.server_site;
 
-       s->dest_dsa.site_name           = s->cldap.netlogon5.client_site;
+       s->dest_dsa.site_name           = s->cldap.netlogon.client_site;
 
        unbecomeDC_connect_ldap(s);
 }
@@ -152,10 +324,10 @@ static NTSTATUS unbecomeDC_ldap_connect(struct libnet_UnbecomeDC_state *s)
        url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
        NT_STATUS_HAVE_NO_MEMORY(url);
 
-       s->ldap.ldb = ldb_wrap_connect(s, url,
+       s->ldap.ldb = ldb_wrap_connect(s, s->libnet->event_ctx, s->libnet->lp_ctx, url,
                                       NULL,
                                       s->libnet->cred,
-                                      0, NULL);
+                                      0);
        talloc_free(url);
        if (s->ldap.ldb == NULL) {
                return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
@@ -178,8 +350,8 @@ static NTSTATUS unbecomeDC_ldap_rootdse(struct libnet_UnbecomeDC_state *s)
        basedn = ldb_dn_new(s, s->ldap.ldb, NULL);
        NT_STATUS_HAVE_NO_MEMORY(basedn);
 
-       ret = ldb_search(s->ldap.ldb, basedn, LDB_SCOPE_BASE, 
-                        "(objectClass=*)", attrs, &r);
+       ret = ldb_search(s->ldap.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
+                        "(objectClass=*)");
        talloc_free(basedn);
        if (ret != LDB_SUCCESS) {
                return NT_STATUS_LDAP(ret);
@@ -187,7 +359,6 @@ static NTSTATUS unbecomeDC_ldap_rootdse(struct libnet_UnbecomeDC_state *s)
                talloc_free(r);
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
-       talloc_steal(s, r);
 
        s->domain.dn_str        = ldb_msg_find_attr_as_string(r->msgs[0], "defaultNamingContext", NULL);
        if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
@@ -212,7 +383,6 @@ static NTSTATUS unbecomeDC_ldap_computer_object(struct libnet_UnbecomeDC_state *
        int ret;
        struct ldb_result *r;
        struct ldb_dn *basedn;
-       char *filter;
        static const char *attrs[] = {
                "distinguishedName",
                "userAccountControl",
@@ -222,12 +392,9 @@ static NTSTATUS unbecomeDC_ldap_computer_object(struct libnet_UnbecomeDC_state *
        basedn = ldb_dn_new(s, s->ldap.ldb, s->domain.dn_str);
        NT_STATUS_HAVE_NO_MEMORY(basedn);
 
-       filter = talloc_asprintf(basedn, "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
-                                s->dest_dsa.netbios_name);
-       NT_STATUS_HAVE_NO_MEMORY(filter);
-
-       ret = ldb_search(s->ldap.ldb, basedn, LDB_SCOPE_SUBTREE, 
-                        filter, attrs, &r);
+       ret = ldb_search(s->ldap.ldb, s, &r, basedn, LDB_SCOPE_SUBTREE, attrs,
+                        "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
+                        s->dest_dsa.netbios_name);
        talloc_free(basedn);
        if (ret != LDB_SUCCESS) {
                return NT_STATUS_LDAP(ret);
@@ -236,11 +403,11 @@ static NTSTATUS unbecomeDC_ldap_computer_object(struct libnet_UnbecomeDC_state *
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       s->dest_dsa.computer_dn_str     = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
+       s->dest_dsa.computer_dn_str     = ldb_msg_find_attr_as_string(r->msgs[0], "distinguishedName", NULL);
        if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
        talloc_steal(s, s->dest_dsa.computer_dn_str);
 
-       s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0);
+       s->dest_dsa.user_account_control = ldb_msg_find_attr_as_uint(r->msgs[0], "userAccountControl", 0);
 
        talloc_free(r);
        return NT_STATUS_OK;
@@ -251,7 +418,7 @@ static NTSTATUS unbecomeDC_ldap_modify_computer(struct libnet_UnbecomeDC_state *
        int ret;
        struct ldb_message *msg;
        uint32_t user_account_control = UF_WORKSTATION_TRUST_ACCOUNT;
-       uint32_t i;
+       unsigned int i;
 
        /* as the value is already as we want it to be, we're done */
        if (s->dest_dsa.user_account_control == user_account_control) {
@@ -264,8 +431,9 @@ static NTSTATUS unbecomeDC_ldap_modify_computer(struct libnet_UnbecomeDC_state *
        msg->dn = ldb_dn_new(msg, s->ldap.ldb, s->dest_dsa.computer_dn_str);
        NT_STATUS_HAVE_NO_MEMORY(msg->dn);
 
-       ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control);
-       if (ret != 0) {
+       ret = samdb_msg_add_uint(s->ldap.ldb, msg, msg, "userAccountControl",
+                                user_account_control);
+       if (ret != LDB_SUCCESS) {
                talloc_free(msg);
                return NT_STATUS_NO_MEMORY;
        }
@@ -303,8 +471,8 @@ static NTSTATUS unbecomeDC_ldap_move_computer(struct libnet_UnbecomeDC_state *s)
                                s->domain.dn_str);
        NT_STATUS_HAVE_NO_MEMORY(basedn);
 
-       ret = ldb_search(s->ldap.ldb, basedn, LDB_SCOPE_BASE,
-                        "(objectClass=*)", _1_1_attrs, &r);
+       ret = ldb_search(s->ldap.ldb, s, &r, basedn, LDB_SCOPE_BASE,
+                        _1_1_attrs, "(objectClass=*)");
        talloc_free(basedn);
        if (ret != LDB_SUCCESS) {
                return NT_STATUS_LDAP(ret);
@@ -375,15 +543,25 @@ static void unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s)
        struct composite_context *creq;
        char *binding_str;
 
-       binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal]", s->source_dsa.dns_name);
+       binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal,target_hostname=%s]",
+                                     s->source_dsa.address,
+                                     s->source_dsa.dns_name);
        if (composite_nomem(binding_str, c)) return;
 
        c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi.binding);
        talloc_free(binding_str);
        if (!composite_is_ok(c)) return;
 
-       creq = dcerpc_pipe_connect_b_send(s, s->drsuapi.binding, &dcerpc_table_drsuapi,
-                                         s->libnet->cred, s->libnet->event_ctx);
+       if (DEBUGLEVEL >= 10) {
+               c->status = dcerpc_binding_set_flags(s->drsuapi.binding,
+                                                    DCERPC_DEBUG_PRINT_BOTH,
+                                                    0);
+               if (!composite_is_ok(c)) return;
+       }
+
+       creq = dcerpc_pipe_connect_b_send(s, s->drsuapi.binding, &ndr_table_drsuapi,
+                                         s->libnet->cred, s->libnet->event_ctx,
+                                         s->libnet->lp_ctx);
        composite_continue(c, creq, unbecomeDC_drsuapi_connect_recv, s);
 }
 
@@ -398,23 +576,25 @@ static void unbecomeDC_drsuapi_connect_recv(struct composite_context *req)
        c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi.pipe);
        if (!composite_is_ok(c)) return;
 
+       s->drsuapi.drsuapi_handle = s->drsuapi.pipe->binding_handle;
+
        unbecomeDC_drsuapi_bind_send(s);
 }
 
-static void unbecomeDC_drsuapi_bind_recv(struct rpc_request *req);
+static void unbecomeDC_drsuapi_bind_recv(struct tevent_req *subreq);
 
 static void unbecomeDC_drsuapi_bind_send(struct libnet_UnbecomeDC_state *s)
 {
        struct composite_context *c = s->creq;
-       struct rpc_request *req;
        struct drsuapi_DsBindInfo28 *bind_info28;
+       struct tevent_req *subreq;
 
        GUID_from_string(DRSUAPI_DS_BIND_GUID, &s->drsuapi.bind_guid);
 
        bind_info28                             = &s->drsuapi.local_info28;
        bind_info28->supported_extensions       = 0;
        bind_info28->site_guid                  = GUID_zero();
-       bind_info28->u1                         = 508;
+       bind_info28->pid                        = 0;
        bind_info28->repl_epoch                 = 0;
 
        s->drsuapi.bind_info_ctr.length         = 28;
@@ -424,19 +604,23 @@ static void unbecomeDC_drsuapi_bind_send(struct libnet_UnbecomeDC_state *s)
        s->drsuapi.bind_r.in.bind_info = &s->drsuapi.bind_info_ctr;
        s->drsuapi.bind_r.out.bind_handle = &s->drsuapi.bind_handle;
 
-       req = dcerpc_drsuapi_DsBind_send(s->drsuapi.pipe, s, &s->drsuapi.bind_r);
-       composite_continue_rpc(c, req, unbecomeDC_drsuapi_bind_recv, s);
+       subreq = dcerpc_drsuapi_DsBind_r_send(s, c->event_ctx,
+                                             s->drsuapi.drsuapi_handle,
+                                             &s->drsuapi.bind_r);
+       if (composite_nomem(subreq, c)) return;
+       tevent_req_set_callback(subreq, unbecomeDC_drsuapi_bind_recv, s);
 }
 
 static void unbecomeDC_drsuapi_remove_ds_server_send(struct libnet_UnbecomeDC_state *s);
 
-static void unbecomeDC_drsuapi_bind_recv(struct rpc_request *req)
+static void unbecomeDC_drsuapi_bind_recv(struct tevent_req *subreq)
 {
-       struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_UnbecomeDC_state *s = tevent_req_callback_data(subreq,
                                            struct libnet_UnbecomeDC_state);
        struct composite_context *c = s->creq;
 
-       c->status = dcerpc_ndr_request_recv(req);
+       c->status = dcerpc_drsuapi_DsBind_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
        if (!composite_is_ok(c)) return;
 
        if (!W_ERROR_IS_OK(s->drsuapi.bind_r.out.result)) {
@@ -452,45 +636,85 @@ static void unbecomeDC_drsuapi_bind_recv(struct rpc_request *req)
                        info24 = &s->drsuapi.bind_r.out.bind_info->info.info24;
                        s->drsuapi.remote_info28.supported_extensions   = info24->supported_extensions;
                        s->drsuapi.remote_info28.site_guid              = info24->site_guid;
-                       s->drsuapi.remote_info28.u1                     = info24->u1;
+                       s->drsuapi.remote_info28.pid                    = info24->pid;
                        s->drsuapi.remote_info28.repl_epoch             = 0;
                        break;
                }
-               case 28:
+               case 28: {
                        s->drsuapi.remote_info28 = s->drsuapi.bind_r.out.bind_info->info.info28;
                        break;
                }
+               case 32: {
+                       struct drsuapi_DsBindInfo32 *info32;
+                       info32 = &s->drsuapi.bind_r.out.bind_info->info.info32;
+                       s->drsuapi.remote_info28.supported_extensions   = info32->supported_extensions;
+                       s->drsuapi.remote_info28.site_guid              = info32->site_guid;
+                       s->drsuapi.remote_info28.pid                    = info32->pid;
+                       s->drsuapi.remote_info28.repl_epoch             = info32->repl_epoch;
+                       break;
+               }
+               case 48: {
+                       struct drsuapi_DsBindInfo48 *info48;
+                       info48 = &s->drsuapi.bind_r.out.bind_info->info.info48;
+                       s->drsuapi.remote_info28.supported_extensions   = info48->supported_extensions;
+                       s->drsuapi.remote_info28.site_guid              = info48->site_guid;
+                       s->drsuapi.remote_info28.pid                    = info48->pid;
+                       s->drsuapi.remote_info28.repl_epoch             = info48->repl_epoch;
+                       break;
+               }
+               case 52: {
+                       struct drsuapi_DsBindInfo52 *info52;
+                       info52 = &s->drsuapi.bind_r.out.bind_info->info.info52;
+                       s->drsuapi.remote_info28.supported_extensions   = info52->supported_extensions;
+                       s->drsuapi.remote_info28.site_guid              = info52->site_guid;
+                       s->drsuapi.remote_info28.pid                    = info52->pid;
+                       s->drsuapi.remote_info28.repl_epoch             = info52->repl_epoch;
+                       break;
+               }
+               default:
+                       DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
+                               s->drsuapi.bind_r.out.bind_info->length));
+                       break;
+               }
        }
 
        unbecomeDC_drsuapi_remove_ds_server_send(s);
 }
 
-static void unbecomeDC_drsuapi_remove_ds_server_recv(struct rpc_request *req);
+static void unbecomeDC_drsuapi_remove_ds_server_recv(struct tevent_req *subreq);
 
 static void unbecomeDC_drsuapi_remove_ds_server_send(struct libnet_UnbecomeDC_state *s)
 {
        struct composite_context *c = s->creq;
-       struct rpc_request *req;
        struct drsuapi_DsRemoveDSServer *r = &s->drsuapi.rm_ds_srv_r;
+       struct tevent_req *subreq;
 
        r->in.bind_handle       = &s->drsuapi.bind_handle;
        r->in.level             = 1;
-       r->in.req.req1.server_dn= s->dest_dsa.server_dn_str;
-       r->in.req.req1.domain_dn= s->domain.dn_str;
-       r->in.req.req1.unknown  = 0x00000001;
-
-       req = dcerpc_drsuapi_DsRemoveDSServer_send(s->drsuapi.pipe, s, r);
-       composite_continue_rpc(c, req, unbecomeDC_drsuapi_remove_ds_server_recv, s);
+       r->in.req               = talloc(s, union drsuapi_DsRemoveDSServerRequest);
+       r->in.req->req1.server_dn = s->dest_dsa.server_dn_str;
+       r->in.req->req1.domain_dn = s->domain.dn_str;
+       r->in.req->req1.commit  = true;
+
+       r->out.level_out        = talloc(s, uint32_t);
+       r->out.res              = talloc(s, union drsuapi_DsRemoveDSServerResult);
+
+       subreq = dcerpc_drsuapi_DsRemoveDSServer_r_send(s, c->event_ctx,
+                                                       s->drsuapi.drsuapi_handle,
+                                                       r);
+       if (composite_nomem(subreq, c)) return;
+       tevent_req_set_callback(subreq, unbecomeDC_drsuapi_remove_ds_server_recv, s);
 }
 
-static void unbecomeDC_drsuapi_remove_ds_server_recv(struct rpc_request *req)
+static void unbecomeDC_drsuapi_remove_ds_server_recv(struct tevent_req *subreq)
 {
-       struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_UnbecomeDC_state *s = tevent_req_callback_data(subreq,
                                            struct libnet_UnbecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsRemoveDSServer *r = &s->drsuapi.rm_ds_srv_r;
 
-       c->status = dcerpc_ndr_request_recv(req);
+       c->status = dcerpc_drsuapi_DsRemoveDSServer_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
        if (!composite_is_ok(c)) return;
 
        if (!W_ERROR_IS_OK(r->out.result)) {
@@ -498,15 +722,10 @@ static void unbecomeDC_drsuapi_remove_ds_server_recv(struct rpc_request *req)
                return;
        }
 
-       if (r->out.level != 1) {
+       if (*r->out.level_out != 1) {
                composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
                return;
        }
-               
-       if (!W_ERROR_IS_OK(r->out.res.res1.status)) {
-               composite_error(c, werror_to_ntstatus(r->out.res.res1.status));
-               return;
-       }
 
        composite_done(c);
 }
@@ -543,7 +762,7 @@ struct composite_context *libnet_UnbecomeDC_send(struct libnet_context *ctx, TAL
        /* Destination DSA dns_name construction */
        tmp_name                = strlower_talloc(s, s->dest_dsa.netbios_name);
        if (composite_nomem(tmp_name, c)) return c;
-       s->dest_dsa.dns_name    = talloc_asprintf_append(tmp_name, ".%s",
+       s->dest_dsa.dns_name    = talloc_asprintf_append_buffer(tmp_name, ".%s",
                                                         s->domain.dns_name);
        if (composite_nomem(s->dest_dsa.dns_name, c)) return c;