s4-torture: switch to generic DRS options flags
[ira/wip.git] / source4 / libnet / libnet_become_dc.c
index 38357efffedaa326a6118a3f56379efdbcc51cf1..b971e43dd7d71066fcdeed8c582bdcc083e670a8 100644 (file)
  *             name:           <new_dc_site_name>
  *             objectGUID:     <object_guid>
  *             systemFlags:    1107296256 <0x42000000>
- *             objectCategory: CN=Site,C=Schema,CN=Configuration,<domain_partition>
+ *             objectCategory: CN=Site,CN=Schema,CN=Configuration,<domain_partition>
  */
 
 /***************************************************************
@@ -731,6 +731,20 @@ struct libnet_BecomeDC_state {
        struct libnet_BecomeDC_Callbacks callbacks;
 };
 
+static int32_t get_dc_function_level(struct loadparm_context *lp_ctx)
+{
+       /* per default we are (Windows) 2008 compatible */
+       return lp_parm_int(lp_ctx, NULL, "ads", "dc function level",
+               DS_DC_FUNCTION_2008);
+}
+
+static int32_t get_min_function_level(struct loadparm_context *lp_ctx)
+{
+       /* per default it is (Windows) 2003 Native compatible */
+       return lp_parm_int(lp_ctx, NULL, "ads", "min function level",
+               DS_DOMAIN_FUNCTION_2003);
+}
+
 static void becomeDC_recv_cldap(struct tevent_req *req);
 
 static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
@@ -770,8 +784,13 @@ static void becomeDC_recv_cldap(struct tevent_req *req)
                                        lp_iconv_convenience(s->libnet->lp_ctx),
                                        s, &s->cldap.io);
        talloc_free(req);
-       if (!composite_is_ok(c)) return;
-
+       if (!composite_is_ok(c)) {
+               DEBUG(0,("Failed to send, receive or parse CLDAP reply from server %s for our host %s: %s\n", 
+                        s->cldap.io.in.dest_address, 
+                        s->cldap.io.in.host, 
+                        nt_errstr(c->status)));
+               return;
+       }
        s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex;
 
        s->domain.dns_name              = s->cldap.netlogon.dns_domain;
@@ -800,7 +819,7 @@ static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *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 (ldap->ldb == NULL) {
                return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
@@ -876,6 +895,22 @@ static NTSTATUS becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_
        }
 
        s->forest.crossref_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
+       if (s->forest.crossref_behavior_version <
+                        get_min_function_level(s->libnet->lp_ctx)) {
+               talloc_free(r);
+               DEBUG(0,("The servers function level %u is below 'ads:min function level' of %u\n", 
+                        s->forest.crossref_behavior_version, 
+                        get_min_function_level(s->libnet->lp_ctx)));
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+       if (s->forest.crossref_behavior_version >
+                       get_dc_function_level(s->libnet->lp_ctx)) {
+               talloc_free(r);
+               DEBUG(0,("The servers function level %u is above 'ads:dc function level' of %u\n", 
+                        s->forest.crossref_behavior_version, 
+                        get_dc_function_level(s->libnet->lp_ctx)));
+               return NT_STATUS_NOT_SUPPORTED;
+       }
 
        talloc_free(r);
        return NT_STATUS_OK;
@@ -905,6 +940,22 @@ static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_st
        }
 
        s->domain.behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
+       if (s->domain.behavior_version <
+                       get_min_function_level(s->libnet->lp_ctx)) {
+               talloc_free(r);
+               DEBUG(0,("The servers function level %u is below 'ads:min function level' of %u\n", 
+                        s->forest.crossref_behavior_version, 
+                        get_min_function_level(s->libnet->lp_ctx)));
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+       if (s->domain.behavior_version >
+                       get_dc_function_level(s->libnet->lp_ctx)) {
+               talloc_free(r);
+               DEBUG(0,("The servers function level %u is above 'ads:dc function level' of %u\n", 
+                        s->forest.crossref_behavior_version, 
+                        get_dc_function_level(s->libnet->lp_ctx)));
+               return NT_STATUS_NOT_SUPPORTED;
+       }
 
        talloc_free(r);
        return NT_STATUS_OK;
@@ -980,14 +1031,6 @@ static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state
        struct ldb_dn *basedn;
        struct ldb_dn *ntds_dn;
        struct ldb_dn *server_dn;
-       static const char *_1_1_attrs[] = {
-               "1.1",
-               NULL
-       };
-       static const char *fsmo_attrs[] = {
-               "fSMORoleOwner",
-               NULL
-       };
        static const char *dns_attrs[] = {
                "dnsHostName",
                NULL
@@ -997,41 +1040,21 @@ static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state
                NULL
        };
 
-       basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "<WKGUID=2fbac1870ade11d297c400c04fd8d5cd,%s>",
-                               s->domain.dn_str);
-       NT_STATUS_HAVE_NO_MEMORY(basedn);
-
-       ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
-                        _1_1_attrs, "(objectClass=*)");
-       talloc_free(basedn);
+       ret = dsdb_wellknown_dn(s->ldap1.ldb, s, samdb_base_dn(s->ldap1.ldb),
+                               DS_GUID_INFRASTRUCTURE_CONTAINER,
+                               &basedn);
        if (ret != LDB_SUCCESS) {
                return NT_STATUS_LDAP(ret);
-       } else if (r->count != 1) {
-               talloc_free(r);
-               return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       basedn = talloc_steal(s, r->msgs[0]->dn);
-       talloc_free(r);
-
-       ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
-                        fsmo_attrs, "(objectClass=*)");
-       talloc_free(basedn);
+       ret = samdb_reference_dn(s->ldap1.ldb, s, basedn, "fSMORoleOwner", &ntds_dn);
        if (ret != LDB_SUCCESS) {
+               talloc_free(basedn);
                return NT_STATUS_LDAP(ret);
-       } else if (r->count != 1) {
-               talloc_free(r);
-               return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       s->infrastructure_fsmo.ntds_dn_str      = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
-       if (!s->infrastructure_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
-       talloc_steal(s, s->infrastructure_fsmo.ntds_dn_str);
-
-       talloc_free(r);
-
-       ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->infrastructure_fsmo.ntds_dn_str);
-       NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
+       s->infrastructure_fsmo.ntds_dn_str = ldb_dn_get_linearized(ntds_dn);
+       NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.ntds_dn_str);
 
        server_dn = ldb_dn_get_parent(s, ntds_dn);
        NT_STATUS_HAVE_NO_MEMORY(server_dn);
@@ -1282,8 +1305,8 @@ static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s)
                NT_STATUS_HAVE_NO_MEMORY(computer_dn);
 
                /*
-                * if the server object belongs to another DC in another domain in the forest,
-                * we should not touch this object!
+                * if the server object belongs to another DC in another domain
+                * in the forest, we should not touch this object!
                 */
                if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) {
                        talloc_free(r);
@@ -1519,9 +1542,10 @@ static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
                 * Note: Replication only works with Windows 2000 when 'krb5' is
                 *       passed as auth_type here. If NTLMSSP is used, Windows
                 *       2000 returns garbage in the DsGetNCChanges() response
-                *       if encrypted password attributes would be in the response.
-                *       That means the replication of the schema and configuration
-                *       partition works fine, but it fails for the domain partition.
+                *       if encrypted password attributes would be in the
+                *       response. That means the replication of the schema and
+                *       configuration partition works fine, but it fails for
+                *       the domain partition.
                 */
                if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc",
                                 "force krb5", true))
@@ -1589,7 +1613,7 @@ static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
-       if (s->domain.behavior_version == 2) {
+       if (s->domain.behavior_version >= DS_DOMAIN_FUNCTION_2003) {
                /* TODO: find out how this is really triggered! */
                bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
        }
@@ -1716,8 +1740,8 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
        s->dest_dsa.invocation_id = GUID_random();
 
        /*
-        * if the schema version indicates w2k3, then
-        * also send some w2k3 specific attributes
+        * if the schema version indicates w2k3, then also send some w2k3
+        * specific attributes.
         */
        if (s->forest.schema_object_version >= 30) {
                w2k3 = true;
@@ -1896,11 +1920,8 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
 
                v = &s->dest_dsa.invocation_id;
 
-               ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, v, (ndr_push_flags_fn_t)ndr_push_GUID);
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                       c->status = ndr_map_error2ntstatus(ndr_err);
-                       if (!composite_is_ok(c)) return;
-               }
+               c->status = GUID_to_ndr_blob(v, vd, &vd[0]);
+               if (!composite_is_ok(c)) return;
 
                vs[0].blob              = &vd[0];
 
@@ -2101,8 +2122,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
                vd[0] = data_blob_talloc(vd, NULL, 4);
                if (composite_nomem(vd[0].data, c)) return;
 
-               SIVAL(vd[0].data, 0, 
-                     lp_parm_int(s->libnet->lp_ctx, NULL, "ads", "functional level", DS_DC_FUNCTION_2008));
+               SIVAL(vd[0].data, 0, get_dc_function_level(s->libnet->lp_ctx));
 
                vs[0].blob              = &vd[0];
 
@@ -2767,12 +2787,11 @@ static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
        r->in.req.req1.naming_context   = &partition->nc;
        r->in.req.req1.dest_dsa_dns_name= ntds_dns_name;
        r->in.req.req1.dest_dsa_guid    = s->dest_dsa.ntds_guid;
-       r->in.req.req1.options          = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
-                                       | DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE;
+       r->in.req.req1.options          = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
 
        /* I think this is how we mark ourselves as a RODC */
        if (!lp_parm_bool(s->libnet->lp_ctx, NULL, "repl", "RODC", false)) {
-               r->in.req.req1.options |= DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE;
+               r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
        }
 
        req = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r);
@@ -2903,55 +2922,40 @@ static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s)
 static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s)
 {
        int ret;
-       struct ldb_result *r;
-       struct ldb_dn *basedn;
        struct ldb_dn *old_dn;
        struct ldb_dn *new_dn;
-       static const char *_1_1_attrs[] = {
-               "1.1",
-               NULL
-       };
 
-       basedn = ldb_dn_new_fmt(s, s->ldap2.ldb, "<WKGUID=a361b2ffffd211d1aa4b00c04fd7d83a,%s>",
-                               s->domain.dn_str);
-       NT_STATUS_HAVE_NO_MEMORY(basedn);
-
-       ret = ldb_search(s->ldap2.ldb, s, &r, basedn, LDB_SCOPE_BASE,
-                        _1_1_attrs, "(objectClass=*)");
-       talloc_free(basedn);
+       ret = dsdb_wellknown_dn(s->ldap2.ldb, s, samdb_base_dn(s->ldap2.ldb),
+                               DS_GUID_DOMAIN_CONTROLLERS_CONTAINER,
+                               &new_dn);
        if (ret != LDB_SUCCESS) {
                return NT_STATUS_LDAP(ret);
-       } else if (r->count != 1) {
-               talloc_free(r);
-               return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       old_dn = ldb_dn_new(r, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
-       NT_STATUS_HAVE_NO_MEMORY(old_dn);
-
-       new_dn = r->msgs[0]->dn;
-
        if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
-               talloc_free(r);
+               talloc_free(new_dn);
                return NT_STATUS_NO_MEMORY;
        }
 
+       old_dn = ldb_dn_new(new_dn, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
+       NT_STATUS_HAVE_NO_MEMORY(old_dn);
+
        if (ldb_dn_compare(old_dn, new_dn) == 0) {
                /* we don't need to rename if the old and new dn match */
-               talloc_free(r);
+               talloc_free(new_dn);
                return NT_STATUS_OK;
        }
 
        ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn);
        if (ret != LDB_SUCCESS) {
-               talloc_free(r);
+               talloc_free(new_dn);
                return NT_STATUS_LDAP(ret);
        }
 
        s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn);
        NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str);
 
-       talloc_free(r);
+       talloc_free(new_dn);
 
        return NT_STATUS_OK;
 }