s4-drs: Implementation of GetNCChanges extended op 6 - fsmo role transfer
authorNadezhda Ivanova <nivanova@samba.org>
Tue, 24 Aug 2010 21:22:16 +0000 (00:22 +0300)
committerKamen Mazdrashki <kamenim@samba.org>
Fri, 10 Sep 2010 10:08:17 +0000 (13:08 +0300)
Basically the candidate owner makes a getncchanges call with extended op 6 when they want to
become the new owner. The current owner then updates the corresponding fSMORoleOwner attribute
in its database with the new owner, and replicates the change to the candidate, who then becomes the
owner.
The patch was made in cooperation with Anatoliy Atanasov <anatoliy.atanasov@postpath.com> who
kindly helped to debug it.

source4/dsdb/config.mk
source4/dsdb/repl/drepl_fsmo.c [new file with mode: 0644]
source4/dsdb/wscript_build
source4/librpc/idl/irpc.idl

index 1ab0cb2102f1c95faf58ef8786b911f51953a80d..e12193d52471c9bc654ae3691a44c7e7e1158512 100644 (file)
@@ -68,7 +68,8 @@ DREPL_SRV_OBJ_FILES = $(addprefix $(dsdbsrcdir)/repl/, \
                drepl_out_pull.o \
                drepl_out_helpers.o \
                drepl_notify.o \
-               drepl_ridalloc.o)
+               drepl_ridalloc.o \
+               drepl_fsmo.o)
 
 $(eval $(call proto_header_template,$(dsdbsrcdir)/repl/drepl_service_proto.h,$(DREPL_SRV_OBJ_FILES:.o=.c)))
 
diff --git a/source4/dsdb/repl/drepl_fsmo.c b/source4/dsdb/repl/drepl_fsmo.c
new file mode 100644 (file)
index 0000000..8719967
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+   Unix SMB/CIFS mplementation.
+
+   DSDB replication service - FSMO role change
+
+   Copyright (C) Nadezhda Ivanova 2010
+   Copyright (C) Andrew Tridgell 2010
+   Copyright (C) Andrew Bartlett 2010
+
+   based on drepl_ridalloc.c
+
+   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 "dsdb/samdb/samdb.h"
+#include "smbd/service.h"
+#include "dsdb/repl/drepl_service.h"
+#include "param/param.h"
+#include "lib/messaging/irpc.h"
+#include "librpc/gen_ndr/ndr_irpc.h"
+
+static void drepl_role_callback(struct dreplsrv_service *service,
+                               WERROR werr,
+                               enum drsuapi_DsExtendedError ext_err)
+{
+       if (!W_ERROR_IS_OK(werr)) {
+               DEBUG(0,(__location__ ": Failed role transfer - %s - extended_ret[0x%X]\n",
+                        win_errstr(werr), ext_err));
+       } else {
+               DEBUG(0,(__location__ ": Successful role transfer\n"));
+       }
+       talloc_free(service->ncchanges_extended.role_owner_source_dsa);
+       service->ncchanges_extended.role_owner_source_dsa = NULL;
+       service->ncchanges_extended.in_progress = false;
+}
+
+static bool fsmo_master_cmp(struct ldb_dn *ntds_dn, struct ldb_dn *fsmo_role_dn)
+{
+       if (ldb_dn_compare(ntds_dn, fsmo_role_dn) == 0) {
+               DEBUG(0,("\nWe are the FSMO master.\n"));
+               return true;
+       }
+       return false;
+}
+
+/*
+  see which role is we are asked to assume, initialize data and send request
+ */
+WERROR dreplsrv_fsmo_role_check(struct dreplsrv_service *service,
+                               uint32_t role)
+{
+       struct ldb_dn *role_owner_dn, *fsmo_role_dn, *ntds_dn;
+       TALLOC_CTX *tmp_ctx = talloc_new(service);
+       struct ldb_context *ldb = service->samdb;
+       int ret;
+       uint64_t alloc_pool = 0;
+
+       if (service->ncchanges_extended.in_progress) {
+               talloc_free(tmp_ctx);
+               return WERR_OK;
+       }
+
+       ntds_dn = samdb_ntds_settings_dn(ldb);
+       if (!ntds_dn) {
+               return WERR_DS_DRA_INTERNAL_ERROR;
+       }
+       /* work out who is the current owner */
+       switch (role) {
+       case DREPL_NAMING_MASTER:
+               role_owner_dn = samdb_partitions_dn(ldb, tmp_ctx),
+               ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
+               if (ret != LDB_SUCCESS) {
+                       DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
+                                ldb_errstring(ldb)));
+                       talloc_free(tmp_ctx);
+                       return WERR_DS_DRA_INTERNAL_ERROR;
+               }
+               break;
+       case DREPL_INFRASTRUCTURE_MASTER:
+               role_owner_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
+               ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
+               if (ret != LDB_SUCCESS) {
+                       DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
+                                ldb_errstring(ldb)));
+                       talloc_free(tmp_ctx);
+                       return WERR_DS_DRA_INTERNAL_ERROR;
+               }
+               break;
+       case DREPL_RID_MASTER:
+               ret = samdb_rid_manager_dn(ldb, tmp_ctx, &role_owner_dn);
+               if (ret != LDB_SUCCESS) {
+                       DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
+                       talloc_free(tmp_ctx);
+                       return WERR_DS_DRA_INTERNAL_ERROR;
+               }
+
+               /* find the DN of the RID Manager */
+               ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
+               if (ret != LDB_SUCCESS) {
+                       DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
+                                ldb_errstring(ldb)));
+                       talloc_free(tmp_ctx);
+                       return WERR_DS_DRA_INTERNAL_ERROR;
+               }
+               break;
+       case DREPL_SCHEMA_MASTER:
+               role_owner_dn = ldb_get_schema_basedn(ldb);
+               ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
+               if (ret != LDB_SUCCESS) {
+                       DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
+                                ldb_errstring(ldb)));
+                       talloc_free(tmp_ctx);
+                       return WERR_DS_DRA_INTERNAL_ERROR;
+               }
+               if (!fsmo_master_cmp(ntds_dn, fsmo_role_dn)) {
+                       return drepl_request_extended_op(service,
+                                                        role_owner_dn,
+                                                        fsmo_role_dn,
+                                                        DRSUAPI_EXOP_FSMO_REQ_ROLE,
+                                                        alloc_pool,
+                                                        drepl_role_callback);
+               }
+               break;
+       case DREPL_PDC_MASTER:
+               role_owner_dn = ldb_get_default_basedn(ldb);
+               ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
+               if (ret != LDB_SUCCESS) {
+                       DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
+                                ldb_errstring(ldb)));
+                       talloc_free(tmp_ctx);
+                       return WERR_DS_DRA_INTERNAL_ERROR;
+               }
+               break;
+       default:
+               return WERR_DS_DRA_INTERNAL_ERROR;
+       }
+       return WERR_OK;
+}
index d3961f52d57a8f3022af84b689d5e56b2f21add8..426b12dc7f1965d617f0677d7375dda3b9ef9960 100644 (file)
@@ -25,7 +25,7 @@ bld.SAMBA_SUBSYSTEM('SAMDB_SCHEMA',
 
 
 bld.SAMBA_MODULE('DREPL_SRV',
-       source='repl/drepl_service.c repl/drepl_periodic.c repl/drepl_partitions.c repl/drepl_out_pull.c repl/drepl_out_helpers.c repl/drepl_notify.c repl/drepl_ridalloc.c',
+       source='repl/drepl_service.c repl/drepl_periodic.c repl/drepl_partitions.c repl/drepl_out_pull.c repl/drepl_out_helpers.c repl/drepl_notify.c repl/drepl_ridalloc.c repl/drepl_fsmo.c',
        autoproto='repl/drepl_service_proto.h',
        subsystem='service',
        init_function='server_service_drepl_init',
index 35204dbedc6ec9689bdb694c91e36940f9aea4e3..2b88dc749b432ebc1c9ab95ee788a1d2b4d07e64 100644 (file)
@@ -157,4 +157,20 @@ import "misc.idl", "security.idl", "nbt.idl";
         *                     If empy/NULL, refresh all partitions.
         */
        WERROR dreplsrv_refresh();
+
+       /*
+         called when role transfer is requested via LDAP
+       */
+       typedef [v1_enum] enum {
+               DREPL_SCHEMA_MASTER,
+               DREPL_RID_MASTER,
+               DREPL_INFRASTRUCTURE_MASTER,
+               DREPL_NAMING_MASTER,
+               DREPL_PDC_MASTER
+       } drepl_role_master;
+
+       NTSTATUS drepl_takeFSMORole(
+               [in] uint32 role
+               );
+
 }