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)
committerNadezhda Ivanova <nivanova@samba.org>
Tue, 24 Aug 2010 21:22:16 +0000 (00:22 +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..dc90f58
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+   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 3b3dae9e661cf0b645add4d94efb6a5267020936..dfbe640965d2561233ede3a42ad8537d1fbe3422 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 03a931661eae7c2a5801527eb53c5d354b96cff1..4eb767165220904f699b003fc3a86ac6b7ff5075 100644 (file)
@@ -148,4 +148,19 @@ import "misc.idl", "security.idl", "nbt.idl";
                [in] astring reason
                );
 
+       /*
+         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
+               );
+
 }