libcli/util Rename common map_nt_error_from_unix to avoid duplicate symbol
[sfrench/samba-autobuild/.git] / source4 / libnet / libnet_unbecome_dc.c
index 0c781b66eca9b79a60a4fe540d486cd74c7de599..85d47a91f926edcbf7f5c78bb22fcb8d25edb58b 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
@@ -193,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 {
@@ -203,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;
@@ -250,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;
+
+       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;
+       }
 
-       s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
-       if (composite_nomem(s->cldap.sock, c)) return;
+       c->status = cldap_socket_init(s, s->libnet->event_ctx,
+                                     NULL, dest_address, &s->cldap.sock);
+       if (!composite_is_ok(c)) return;
 
-       req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
+       req = cldap_netlogon_send(s, 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);
 }
@@ -308,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;
@@ -334,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);
@@ -343,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;
@@ -368,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",
@@ -378,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);
@@ -392,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;
@@ -407,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) {
@@ -420,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;
        }
@@ -459,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);
@@ -538,8 +550,13 @@ static void unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s)
        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) {
+               s->drsuapi.binding->flags |= DCERPC_DEBUG_PRINT_BOTH;
+       }
+
+       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);
 }
 
@@ -554,23 +571,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;
@@ -580,19 +599,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)) {
@@ -608,10 +631,19 @@ 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 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 28:
                        s->drsuapi.remote_info28 = s->drsuapi.bind_r.out.bind_info->info.info28;
                        break;
@@ -621,32 +653,40 @@ static void unbecomeDC_drsuapi_bind_recv(struct rpc_request *req)
        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)) {
@@ -654,15 +694,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);
 }
@@ -699,7 +734,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;