s4-repl: Check if GC SPN exists before using it for replication
authorAmitay Isaacs <amitay@gmail.com>
Sun, 27 Nov 2011 23:33:53 +0000 (10:33 +1100)
committerAmitay Isaacs <amitay@gmail.com>
Tue, 29 Nov 2011 05:00:36 +0000 (16:00 +1100)
Sometimes windows DC will set up dNSHostname before setting up
GC SPN and that causes replication errors since samba tries to
use GC SPN, which does not yet exist locally.

Pair-Programmed-With: Andrew Tridgell <tridge@samba.org>

source4/dsdb/repl/drepl_partitions.c

index 70f9971a7cf27616a0d9da0f2e2cb4730fd6c952..927dc687663a9134b903d6429bafd29781b38e1b 100644 (file)
@@ -125,6 +125,47 @@ WERROR dreplsrv_load_partitions(struct dreplsrv_service *s)
        return WERR_OK;
 }
 
+/*
+  Check if particular SPN exists for an account
+ */
+static bool dreplsrv_spn_exists(struct ldb_context *samdb, struct ldb_dn *ntds_dn,
+                               const char *principal_name)
+{
+       TALLOC_CTX *tmp_ctx;
+       const char *attrs[] = { "serverReference", NULL };
+       const char *attrs_empty[] = { NULL };
+       int ret;
+       struct ldb_result *res;
+       struct ldb_dn *account_dn;
+
+       tmp_ctx = talloc_new(samdb);
+
+       ret = dsdb_search_dn(samdb, tmp_ctx, &res, ntds_dn, attrs, 0);
+       if (ret != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               return false;
+       }
+
+       account_dn = ldb_msg_find_attr_as_dn(samdb, tmp_ctx, res->msgs[0], "serverReference");
+       if (account_dn == NULL) {
+               talloc_free(tmp_ctx);
+               return false;
+       }
+
+       talloc_free(res);
+
+       ret = dsdb_search(samdb, tmp_ctx, &res, account_dn, LDB_SCOPE_BASE, attrs_empty,
+                       0, "servicePrincipalName=%s",
+                       ldb_binary_encode_string(tmp_ctx, principal_name));
+       if (ret != LDB_SUCCESS || res->count != 1) {
+               talloc_free(tmp_ctx);
+               return false;
+       }
+
+       talloc_free(tmp_ctx);
+       return true;
+}
+
 /*
   work out the principal to use for DRS replication connections
  */
@@ -181,15 +222,25 @@ NTSTATUS dreplsrv_get_target_principal(struct dreplsrv_service *s,
 
        hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
        if (hostname != NULL) {
+               char *local_principal;
+
                /*
                  if we have the dNSHostName attribute then we can use
                  the GC/hostname/realm SPN. All DCs should have this SPN
+
+                 Windows DC may set up it's dNSHostName before setting up
+                 GC/xx/xx SPN. So make sure it exists, before using it.
                 */
-               *target_principal = talloc_asprintf(mem_ctx, "GC/%s/%s",
+               local_principal = talloc_asprintf(mem_ctx, "GC/%s/%s",
                                                    hostname,
                                                    samdb_dn_to_dns_domain(tmp_ctx, forest_dn));
-               talloc_free(tmp_ctx);
-               return NT_STATUS_OK;
+               if (dreplsrv_spn_exists(s->samdb, ntds_dn, local_principal)) {
+                       *target_principal = local_principal;
+                       talloc_free(tmp_ctx);
+                       return NT_STATUS_OK;
+               }
+
+               talloc_free(local_principal);
        }
 
        /*