dfsr: add the dfsr service
authorMatthieu Patou <mat@matws.net>
Mon, 23 Sep 2013 22:49:41 +0000 (15:49 -0700)
committerMatthieu Patou <mat@matws.net>
Fri, 3 Oct 2014 19:23:01 +0000 (12:23 -0700)
Signed-off-by: Matthieu Patou <mat@matws.net>
lib/param/loadparm.c
source4/dfsr/dfsr_service.c [new file with mode: 0644]
source4/dfsr/dfsr_service.h [new file with mode: 0644]
source4/dfsr/wscript_build [new file with mode: 0644]
wscript_build

index 4b42bb7816e6baac05e13d1581f478dcdc3dc6bf..0b863c22613096de100f0b2026c347042f3669e3 100644 (file)
@@ -2437,7 +2437,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "max connections", "0");
 
        lpcfg_do_global_parameter(lp_ctx, "dcerpc endpoint servers", "epmapper wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver frstrans");
-       lpcfg_do_global_parameter(lp_ctx, "server services", "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns");
+       lpcfg_do_global_parameter(lp_ctx, "server services", "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns dfsr");
        lpcfg_do_global_parameter(lp_ctx, "kccsrv:samba_kcc", "false");
        /* the winbind method for domain controllers is for both RODC
           auth forwarding and for trusted domains */
diff --git a/source4/dfsr/dfsr_service.c b/source4/dfsr/dfsr_service.c
new file mode 100644 (file)
index 0000000..5b66259
--- /dev/null
@@ -0,0 +1,1733 @@
+/*
+   Unix SMB/CIFS mplementation.
+   DFSR replication service
+
+   Copyright (C) Matthieu Patou <mat@matws.net> 2013-2014
+
+   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 "auth/auth.h"
+#include "smbd/service.h"
+#include "lib/events/events.h"
+#include <ldb_errors.h>
+#include <ldb_module.h>
+#include "lib/messaging/irpc.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_frstrans.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_frstrans_c.h"
+#include "param/param.h"
+#include "dfsr/dfsr_service.h"
+#include "util/tevent_ntstatus.h"
+#include "util/dlinklist.h"
+#include "ldb_wrap.h"
+#include "libcli/composite/composite.h"
+
+#define ALLYOUCANEATLOG 11
+#define INFOLOG 1
+#define ERRORLOG 0
+#define WARNLOG 1
+#define DEBUGLOG 1
+
+const char NULLSHA1[20] = {0};
+static WERROR dfsrsrv_init_creds(struct dfsrsrv_service *service)
+{
+       service->system_session_info = system_session(service->task->lp_ctx);
+       if (service->system_session_info == NULL) {
+               return WERR_NOMEM;
+       }
+
+       return WERR_OK;
+}
+
+static WERROR dfsrsrv_connect_dbs(struct dfsrsrv_service *service, struct loadparm_context *lp_ctx)
+{
+       service->samdb = samdb_connect(service, service->task->event_ctx, lp_ctx,
+                                       service->system_session_info, 0);
+       if (!service->samdb) {
+               return WERR_DS_UNAVAILABLE;
+       }
+
+       service->dfsrdb = ldb_wrap_connect(service, NULL, lp_ctx, "dfsr.ldb",
+                                       NULL, NULL, 0);
+       if (!service->dfsrdb) {
+               return WERR_DS_UNAVAILABLE;
+       }
+
+       return WERR_OK;
+}
+
+static void dorun(struct dfsrsrv_service *service);
+
+WERROR dfsrsrv_periodic_schedule(struct dfsrsrv_service *service, uint32_t next_interval);
+
+/* Callback called when the timer expire for the DFSR service
+ * it will call dorun and then rearm a new time
+ */
+static void dfsrsrv_periodic_handler_te(struct tevent_context *ev, struct tevent_timer *te,
+                                        struct timeval t, void *ptr)
+{
+       struct dfsrsrv_service *service = talloc_get_type(ptr, struct dfsrsrv_service);
+       WERROR status;
+
+       service->periodic.te = NULL;
+
+       service->tevent_ctx = ev;
+
+       dorun(service);
+
+       status = dfsrsrv_periodic_schedule(service, service->periodic.interval);
+       if (!W_ERROR_IS_OK(status)) {
+               task_server_terminate(service->task, win_errstr(status), false);
+               return;
+       }
+}
+
+/* Schedule the DFSR service for a run in @next_interval delay */
+WERROR dfsrsrv_periodic_schedule(struct dfsrsrv_service *service, uint32_t next_interval)
+{
+       struct tevent_timer *new_te;
+       struct timeval next_time;
+
+       /* prevent looping */
+       if (next_interval == 0) next_interval = 1;
+
+       next_time = timeval_current_ofs(next_interval, 50);
+
+       if (service->periodic.te) {
+               /*
+                * if the timestamp of the new event is higher,
+                * as current next we don't need to reschedule.
+                * This can happen if the next event is scheduled in 5 seconds,
+                * but we ask to schedule in 10 seconds.
+                */
+               if (timeval_compare(&next_time, &service->periodic.next_event) > 0) {
+                       return WERR_OK;
+               }
+       }
+
+       /* reset the next scheduled timestamp */
+       service->periodic.next_event = next_time;
+
+       new_te = tevent_add_timer(service->task->event_ctx, service,
+                                 service->periodic.next_event,
+                                 dfsrsrv_periodic_handler_te, service);
+       W_ERROR_HAVE_NO_MEMORY(new_te);
+
+       talloc_free(service->periodic.te);
+       service->periodic.te = new_te;
+
+       return WERR_OK;
+}
+
+/* For a given replicagroup specified by it's DN (@rep_group_dn)
+ * search for DFSR sets in it.
+ */
+static WERROR get_dfsr_sets_ingroup(struct dfsrsrv_service *service,
+                                       struct ldb_dn *rep_group_dn,
+                                       bool issysvol)
+{
+       int ret, i;
+       const char *attrs[] = { "name", "objectGUID", NULL };
+       struct ldb_result *res, *res2;
+       struct dfsrsrv_replica_group *group;
+
+       if (service->sysvol) {
+               /* Already exists */
+               return WERR_OK;
+       }
+       if (!issysvol) {
+               /*
+                * FIXME do also the other replica group one day
+                */
+               return WERR_NOT_SUPPORTED;
+       }
+       /*
+        * FIXME
+        * Check the DL > 2008
+        */
+
+       /* Search the specified msDFSR-ReplicationGroup in order to validate it*/
+       ret = ldb_search(service->samdb, service, &res, rep_group_dn,
+                        LDB_SCOPE_BASE, attrs, "(objectClass=*)");
+       if (ret != LDB_SUCCESS || res->count == 0) {
+               /*
+                * No entry or a problem ?
+                * Hum we might have this group
+                * TODO if we are alone, that's normal we just need to create
+                * the structure if it's sysvol.
+                */
+               DEBUG(ERRORLOG, ("Unable to find DFSR replica group for DN %s",
+                               ldb_dn_get_linearized(rep_group_dn)));
+               return WERR_NOT_SUPPORTED;
+       }
+
+       group = talloc_zero(service, struct dfsrsrv_replica_group);
+       if (issysvol) {
+               service->sysvol = group;
+       } else {
+               /* FIXME add the service to the list of replica */
+               return WERR_NOT_SUPPORTED;
+       }
+       /*
+        * Ok we've found the replica group, so now look for the replica sets
+        * in this group
+        */
+       group->is_sysvol = issysvol;
+       group->dn = talloc_steal(group, res->msgs[0]->dn);
+       group->name = talloc_strdup(group, ldb_msg_find_attr_as_string(res->msgs[0],
+                                                               "name", NULL));
+       group->guid = samdb_result_guid(res->msgs[0], "objectGUID");
+
+       ret = ldb_search(service->samdb, service, &res2, rep_group_dn,
+                        LDB_SCOPE_SUBTREE, attrs,
+                        "(objectClass=msDFSR-ContentSet)");
+       if (ret != LDB_SUCCESS || res2->count == 0) {
+               /*
+                * No entry or a problem ?
+                * Hum we might have this replica
+                * TODO if we are alone, that's normal we just need to create
+                * the structure if it's sysvol.
+                */
+               DEBUG(ERRORLOG, ("Unable to find DFSR contentSet for group %s",
+                               ldb_dn_get_linearized(rep_group_dn)));
+               return WERR_NOT_SUPPORTED;
+       }
+
+       group->set_names = talloc_array(group, char *, res2->count);
+       W_ERROR_HAVE_NO_MEMORY(group->set_names);
+
+       group->numsets = res2->count;
+
+       group->set_guids = talloc_array(group, struct GUID, res2->count);
+       W_ERROR_HAVE_NO_MEMORY(group->set_guids);
+
+       for (i = 0; i < res2->count; i++) {
+               group->dn = talloc_steal(group, res->msgs[0]->dn);
+               group->set_names[i] = talloc_strdup(group->set_names,
+                                               ldb_msg_find_attr_as_string(res->msgs[i],
+                                                                           "name", NULL));
+               group->set_guids[i] = samdb_result_guid(res2->msgs[i], "objectGUID");
+       }
+
+       service->groups = talloc_realloc(service, service->groups,
+                                        struct dfsrsrv_replica_group*,
+                                        service->numgroups + 1);
+       service->groups[service->numgroups] = group;
+       service->numgroups++;
+
+       group->me = talloc_zero(group, struct dfsrsrv_replica_member);
+
+       talloc_free(res);
+       talloc_free(res2);
+       return WERR_OK;
+}
+
+/* Subscribe current DC to the sysvol contentset, creating needed entries in the DB,
+ * the @me object is also populated so that it can be used for replication
+ */
+static int subscribe_sysvol_contentset(TALLOC_CTX *mem_ctx, struct dfsrsrv_service *service, struct dfsrsrv_replica_member *me)
+{
+       /*
+        * Ok we do not have registered ourself as
+        * a member of this dfsr replica, let's do it !
+        */
+       struct ldb_message *msg, *msg2;
+       struct ldb_dn *dn, *dn2;
+       struct ldb_result *res;
+       const char *attrs2[] = { "objectGUID", NULL };
+       const char *string_ntds_dn = ldb_dn_get_linearized(samdb_ntds_settings_dn(service->samdb, mem_ctx));
+       int ret = ldb_transaction_start(service->samdb);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /* CN=DFSR-LocalSettings,CN=<NETBIOS>,OU=Domain Controllers,<DOMAIN> */
+       msg = ldb_msg_new(mem_ctx);
+
+       if (msg == NULL) {
+               return ldb_operr(service->samdb);
+       }
+       dn = ldb_dn_new_fmt(msg, service->samdb, "CN=DFSR-LocalSettings,%s",
+                               ldb_dn_get_linearized(service->my_account_dn));
+       DEBUG(0, ("DN = %s\n", ldb_dn_get_linearized(dn)));
+
+       if (dn == NULL) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       msg->dn = dn;
+       ret = ldb_msg_add_string(msg, "objectClass", "msDFSR-LocalSettings");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_msg_add_string(msg, "msDFSR-Version", "1.0.0.0");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_msg_add_string(msg, "msDFSR-Flags", "48");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_add(service->samdb, msg);
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               return ret;
+       }
+       /*
+        * End
+        * CN=DFSR-LocalSettings,CN=<NETBIOS>,OU=Domain Controllers,<DOMAIN>
+        */
+
+       /* CN=<NETBIOS>,CN=Topology,CN=Domain System Volume,CN=DFSR-GlobalSettings,<DOMAIN>*/
+       msg2 = ldb_msg_new(mem_ctx);
+
+       if (msg2 == NULL) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       dn2 = ldb_dn_new_fmt(msg2, service->samdb,
+                       "CN=%s, CN=Topology, %s",
+                       lpcfg_netbios_name(service->task->lp_ctx),
+                       ldb_dn_get_linearized(service->sysvol->dn));
+
+       if (dn2 == NULL) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+       msg2->dn = talloc_steal(msg2, dn2);
+
+       ret = ldb_msg_add_string(msg2, "objectClass", "msDFSR-Member");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_msg_add_string(msg2, "serverReference", string_ntds_dn);
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_msg_add_string(msg2, "msDFSR-ComputerReference",
+                                       ldb_dn_get_linearized(service->my_account_dn));
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_add(service->samdb, msg2);
+       /*
+        * END
+        * CN=<NETBIOS>,CN=Topology,CN=Domain System Volume,CN=DFSR-GlobalSettings,<DOMAIN>
+        */
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ret;
+       }
+       me->memberdn = talloc_steal(me, msg2->dn);
+
+       /* We will need this for the memberReference */
+       dn2 = msg2->dn;
+       talloc_free(msg2);
+
+       /* CN=Domain System Volume,CN=DFSR-LocalSettings,CN=<NETBIOS>,OU=Domain Controllers,<DOMAIN> */
+       msg2 = ldb_msg_new(mem_ctx);
+
+       if (msg2 == NULL) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_error(service->samdb, LDB_ERR_OPERATIONS_ERROR,
+                               "Unable to allocate a ldb_msg object");
+       }
+
+       ldb_dn_add_child_fmt(dn, "CN=Domain System Volume");
+       msg2->dn = talloc_steal(msg2, dn);
+       if (msg2->dn == NULL) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_error(service->samdb, LDB_ERR_OPERATIONS_ERROR,
+                               "Unable to allocate dn for DFSR");
+       }
+       /* dn is on the msg context */
+       talloc_free(msg);
+
+       ret = ldb_msg_add_string(msg2, "objectClass", "msDFSR-Subscriber");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = dsdb_msg_add_guid(msg2,
+                               &service->sysvol->guid,
+                               "msDFSR-ReplicationGroupGuid");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_msg_add_string(msg2, "msDFSR-MemberReference",
+                                       ldb_dn_get_linearized(dn2));
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_add(service->samdb, msg2);
+       talloc_free(dn2);
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ret;
+       }
+       /*
+        * END
+        * CN=Domain System Volume,CN=DFSR-LocalSettings,CN=<NETBIOS>,OU=Domain Controllers,<DOMAIN>
+        */
+
+       /* CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=<NETBIOS>,OU=Domain Controllers,<DOMAIN>*/
+       msg = ldb_msg_new(mem_ctx);
+
+       if (msg == NULL) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_error(service->samdb, LDB_ERR_OPERATIONS_ERROR,
+                               "Unable to allocate a ldb_msg object");
+       }
+
+       ldb_dn_add_child_fmt(dn, "CN=SYSVOL Subscription");
+       msg->dn = talloc_steal(msg, dn);
+       if (!msg->dn) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_error(service->samdb, LDB_ERR_OPERATIONS_ERROR,
+                               "Unable to add NTdfsr Subscriptions object for sysvol");
+       }
+       /* dn is on the msg2 context */
+       talloc_free(msg2);
+
+       ret = ldb_msg_add_string(msg, "objectClass", "msDFSR-Subscription");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_msg_add_string(msg, "msDFSR-RootPath", me->path);
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_msg_add_string(msg, "msDFSR-Enabled", "TRUE");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_msg_add_string(msg, "msDFSR-Options", "0");
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = dsdb_msg_add_guid(msg,
+                               &service->sysvol->set_guids[0],
+                               "msDFSR-ContentSetGuid");
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = dsdb_msg_add_guid(msg,
+                               &service->sysvol->guid,
+                               "msDFSR-ReplicationGroupGuid");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_msg_add_string(msg, "msDFSR-ReadOnly", "FALSE");
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ldb_operr(service->samdb);
+       }
+
+       ret = ldb_add(service->samdb, msg);
+
+       if (ret != LDB_SUCCESS) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               return ret;
+       }
+       /*
+        * END
+        * CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=<NETBIOS>,OU=Domain Controllers,<DOMAIN>
+        */
+       ret = ldb_search(service->samdb, mem_ctx, &res, msg->dn,
+                       LDB_SCOPE_BASE, attrs2,
+                       "(objectClass=msDFSR-Subscription)");
+
+       DEBUG(0, ("DN = %s count = %d\n", ldb_dn_get_linearized(service->sysvol->dn), res->count));
+       if (ret != LDB_SUCCESS || res->count == 0) {
+               ldb_transaction_cancel(service->samdb);
+               talloc_free(mem_ctx);
+               TALLOC_FREE(service->sysvol->me);
+               return ret;
+       }
+       DEBUG(0, ("Finished initializing our DFSR settings\n"));
+
+       me->guid = samdb_result_guid(res->msgs[0], "objectGUID");
+       me->dn = talloc_steal(me, res->msgs[0]->dn);
+       me->name = talloc_strdup(me, ldb_msg_find_attr_as_string(res->msgs[0], "cn", NULL));
+       talloc_free(mem_ctx);
+
+       service->sysvol->initizialized = true;
+       return ldb_transaction_commit(service->samdb);
+}
+
+static int register_or_get_sysvol_subscription(struct dfsrsrv_service *service)
+{
+       int ret;
+       TALLOC_CTX *mem_ctx = talloc_new(service);
+       struct ldb_result *res, *res2;
+       struct dfsrsrv_replica_member *me;
+       const char* sysvol_path;
+       const char *string_ntds_dn = ldb_dn_get_linearized(samdb_ntds_settings_dn(service->samdb, mem_ctx));
+       const char *attrs[] = { "objectGUID",
+                               "msDFSR-MemberReferenceBL", NULL };
+       const char *attrs2[] = { "objectGUID", NULL };
+       struct loadparm_service *lp_sysvol;
+
+       ret = ldb_search(service->samdb, service, &res, service->sysvol->dn,
+                        LDB_SCOPE_SUBTREE, attrs,
+                        "(objectClass=msDFSR-Member)");
+
+       DEBUG(ALLYOUCANEATLOG, (__FILE__": start\n"));
+       if (ret != LDB_SUCCESS || res->count == 0) {
+               /* TODO if we are alone in the domain just take the job */
+               DEBUG(ERRORLOG, ("Unable to find any the dfsr member for group %s",
+                               ldb_dn_get_linearized(service->sysvol->dn)));
+               return LDB_ERR_NO_SUCH_OBJECT;
+       }
+       lp_sysvol = lpcfg_service(service->task->lp_ctx , "sysvol");
+       sysvol_path = lpcfg_path(lp_sysvol, lpcfg_default_service(service->task->lp_ctx), mem_ctx);
+       if (sysvol_path == NULL) {
+               DEBUG(0, ("sysvol path is null\n"));
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = samdb_server_reference_dn(service->samdb, service, &service->my_account_dn);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       talloc_free(res);
+
+       /* Check if we have already subscribed to the SYSVOL DFSR ContentSet */
+       ret = ldb_search(service->samdb, service, &res, service->sysvol->dn,
+                        LDB_SCOPE_SUBTREE, attrs,
+                        "(&(objectClass=msDFSR-Member)(serverReference=%s))",
+                        string_ntds_dn);
+
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       me = service->sysvol->me;
+       me->path = talloc_strdup(me, sysvol_path);
+
+       if (res->count == 1) {
+               /* We did */
+               struct ldb_dn *refbl = ldb_msg_find_attr_as_dn(service->samdb, mem_ctx,
+                                       res->msgs[0], "msDFSR-MemberReferenceBL");
+               if (refbl == NULL) {
+                       talloc_free(mem_ctx);
+                       TALLOC_FREE(service->sysvol->me);
+                       return LDB_ERR_NO_SUCH_OBJECT;
+               }
+
+               ret = ldb_search(service->samdb, mem_ctx, &res2, refbl,
+                               LDB_SCOPE_ONELEVEL, attrs2,
+                               "(objectClass=msDFSR-Subscription)");
+
+               if (ret != LDB_SUCCESS || res2->count == 0) {
+                       talloc_free(mem_ctx);
+                       TALLOC_FREE(service->sysvol->me);
+                       return ret;
+               }
+
+               me->guid = samdb_result_guid(res2->msgs[0], "objectGUID");
+               me->dn = talloc_steal(me, res2->msgs[0]->dn);
+               me->name = talloc_strdup(me, ldb_msg_find_attr_as_string(res2->msgs[0], "cn", NULL));
+               /* to be checked */
+               me->memberdn = talloc_steal(me, res->msgs[0]->dn);
+
+               return LDB_SUCCESS;
+       } else if (res->count == 0) {
+               return subscribe_sysvol_contentset(mem_ctx, service, me);
+       } else {
+               char *txt = talloc_asprintf(service->samdb,
+                                           "There is more than 1 object with serverReference"
+                                           " ,bellow %s,pointing to our NTDS value"
+                                           " database is corrupted",
+                                           ldb_dn_get_linearized(service->sysvol->dn));
+               ldb_error(service->samdb, LDB_ERR_OPERATIONS_ERROR, txt);
+       }
+       /* Never reached */
+       return LDB_SUCCESS;
+}
+
+static bool init_sysvol_replicaset(struct dfsrsrv_service *service);
+
+
+static int populate_sysvol_cnxs(struct dfsrsrv_replica_member *member,
+                               struct ldb_context *samdb)
+{
+       uint32_t old_num = member->num_cnx;
+       struct ldb_result *res;
+       TALLOC_CTX *mem_ctx = talloc_new(member);
+       const char* attrs[] = {"objectGUID", "fromServer", NULL};
+       const char* attrs2[] = {"dNSHostName", NULL};
+       struct ldb_dn *settings_dn = samdb_ntds_settings_dn(samdb, mem_ctx);
+       int i, j;
+       struct dfsrsrv_connection **cnxs;
+       int ret = ldb_search(samdb, mem_ctx, &res, settings_dn,
+                               LDB_SCOPE_ONELEVEL, attrs,
+                               "(objectclass=nTDSConnection)");
+
+       DEBUG(ALLYOUCANEATLOG, ("%s called, # cnx = %d\n", __func__, member->num_cnx));
+       if (old_num != 0) {
+               /* FIXME we need to adapt to the change of number of replica in the group*/
+               return LDB_SUCCESS;
+       }
+       member->num_cnx = 0;
+
+       if (ret != LDB_SUCCESS || res->count == 0) {
+               DEBUG(0, ("No NTDS connection for our server (%s)\n",
+                     ldb_dn_get_linearized(settings_dn)));
+               talloc_free(mem_ctx);
+               return LDB_SUCCESS;
+       }
+
+       cnxs = talloc_zero_array(member, struct dfsrsrv_connection *, res->count);
+       for (i = 0; i < res->count; i++) {
+               struct GUID guid = samdb_result_guid(res->msgs[i], "objectGUID");
+               struct ldb_dn *from_server, *from_server_ntds;
+
+               for (j = 0; j < old_num; j++) {
+                       if (GUID_equal(&member->cnxs[j]->guid, &guid)) {
+                               cnxs[i] = talloc_move(cnxs, &member->cnxs[j]);
+                       }
+               }
+               if (cnxs[i] != NULL) {
+                       continue;
+               }
+
+               from_server_ntds = ldb_msg_find_attr_as_dn(samdb, member,
+                                                     res->msgs[i],
+                                                     "fromServer");
+               if (!from_server_ntds) {
+                       DEBUG(0, ("Unable to find fromServer from %s\n",
+                             ldb_dn_get_linearized(res->msgs[i]->dn)));
+                       talloc_free(mem_ctx);
+                       return LDB_ERR_NO_SUCH_ATTRIBUTE;
+               }
+               from_server = ldb_dn_get_parent(mem_ctx, from_server_ntds);
+               talloc_free(res);
+               ret = ldb_search(samdb, mem_ctx, &res, from_server,
+                                LDB_SCOPE_BASE, attrs2,
+                                "(&(objectclass=server)(dnsHostName=*))");
+               if (ret != LDB_SUCCESS || res->count == 0) {
+                       DEBUG(0, ("Unable to get the dnsHostname from %s\n",
+                             ldb_dn_get_linearized(from_server)));
+                       talloc_free(mem_ctx);
+                       return LDB_ERR_NO_SUCH_ATTRIBUTE;
+               }
+               cnxs[i] = talloc_zero(member, struct dfsrsrv_connection);
+               cnxs[i]->guid = guid;
+               cnxs[i]->hostname = ldb_msg_find_attr_as_string(res->msgs[0],
+                                                               "dNSHostName",
+                                                               NULL);
+               talloc_steal(cnxs[i], cnxs[i]->hostname);
+               cnxs[i]->established = false;
+       }
+       if (member->cnxs) {
+               talloc_free(member->cnxs);
+       }
+       member->cnxs = cnxs;
+       member->num_cnx = res->count;
+       talloc_free(mem_ctx);
+       return LDB_SUCCESS;
+}
+static int populate_connections(struct dfsrsrv_replica_member *member,
+                               struct ldb_context *samdb,
+                               bool is_sysvol)
+{
+       if (is_sysvol) {
+               return populate_sysvol_cnxs(member, samdb);
+       }
+       return LDB_SUCCESS;
+}
+
+static void dfsrsrv_session_loop_start(struct dfsrsrv_service *service,
+                                      struct dfsrsrv_replica_group *group,
+                                      struct dfsrsrv_replica_member *member,
+                                      struct dfsrsrv_connection *conn);
+
+static void establish_connection(struct dfsrsrv_service *service,
+                                struct dfsrsrv_replica_group *group,
+                                struct dfsrsrv_replica_member *member,
+                                struct dfsrsrv_connection *conn)
+{
+       enum frstrans_ProtocolVersion version;
+       uint32_t flags;
+       NTSTATUS status;
+       WERROR result;
+       struct dcerpc_pipe *p;
+       struct GUID_txt_buf tmp_buf;
+
+       DEBUG(INFOLOG, ("Trying to connect to %s (connection guid %s)\n",
+             conn->hostname,
+             GUID_string(conn, &conn->guid)));
+
+       /* Use print to print the NDR */
+       conn->binding_string = talloc_asprintf(conn,
+                                       "%s@ncacn_ip_tcp:%s[krb5,seal]",
+                                       "5bc1ed07-f5f5-485f-9dfd-6fd0acf9a23c",
+                                       conn->hostname);
+
+       status = dcerpc_parse_binding(conn, conn->binding_string,
+                                     &conn->binding);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Unable to parse the binding string %s\n",
+                         conn->binding_string));
+               return;
+       }
+       dcerpc_binding_set_flags(conn->binding, DCERPC_CONCURRENT_MULTIPLEX, 0);
+
+       status = dcerpc_pipe_connect_b(conn, &p, conn->binding,
+                                       &ndr_table_frstrans,
+                                       service->system_session_info->credentials,
+                                       service->tevent_ctx,
+                                       service->task->lp_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Failed to connect to %s - %s\n",
+                        conn->binding_string, nt_errstr(status)));
+               return;
+       }
+       conn->dcerpc_pipe = p;
+       if (conn->dcerpc_pipe == NULL) {
+               return;
+       }
+       DEBUG(INFOLOG, ("Creating a DFSR connection to %s\n",
+               GUID_buf_string(&conn->guid, &tmp_buf)));
+       status = dcerpc_frstrans_EstablishConnection(p->binding_handle,
+                                                    conn,
+                                                    group->guid,
+                                                    conn->guid,
+                                                    FRSTRANS_PROTOCOL_VERSION_LONGHORN_SERVER,
+                                                    FRSTRANS_TRANSPORT_SUPPORTS_RDC_SIMILARITY,
+                                                    &version,
+                                                    &flags,
+                                                    &result);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(ERRORLOG, ("Unable to established a connection"));
+               return;
+       }
+       if (!W_ERROR_IS_OK(result)) {
+               DEBUG(ERRORLOG, ("Unable to established a connection"));
+               return;
+       }
+
+       status = dcerpc_frstrans_EstablishSession(p->binding_handle,
+                                                 conn,
+                                                 conn->guid,
+                                                 group->set_guids[0],
+                                                 &result);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Unable to establishe a session"));
+               return;
+       }
+       if (!W_ERROR_IS_OK(result)) {
+               DEBUG(0, ("Unable to establishe a session"));
+               return;
+       }
+       conn->established = true;
+
+       dfsrsrv_session_loop_start(service, group, member, conn);
+       return;
+}
+
+struct dfsrsrv_session_loop_state {
+       struct dfsrsrv_service *service;
+       struct dfsrsrv_replica_group *group;
+       struct dfsrsrv_replica_member *member;
+       struct dfsrsrv_connection *conn;
+
+       struct frstrans_AsyncResponseContext poll_response;
+       struct tevent_req *subreq;
+
+       enum frstrans_VersionChangeType change_type;
+       uint32_t sequence;
+       uint64_t generation;
+       uint64_t known_generation;
+       bool use_new_generation;
+
+       /* Version Vectors that we want to have */
+       uint32_t vector_diff_count;
+       struct frstrans_VersionVector *vector_diff;
+
+       uint32_t max_updates;
+       uint32_t num_updates;
+       uint32_t remaining_downloads;
+       uint32_t downloaded_updates;
+       uint32_t skipped_updates;
+       struct frstrans_Update *updates;
+       enum frstrans_UpdateStatus update_status;
+       struct GUID gvsn_db_guid;
+       uint64_t gvsn_version;
+};
+
+static void dfsrsrv_session_loop_next(struct dfsrsrv_session_loop_state *state);
+static void dfsrsrv_session_loop_poll_done(struct tevent_req *subreq);
+static void dfsrsrv_session_loop_vector_done(struct tevent_req *subreq);
+static void dfsrsrv_session_loop_update_done(struct tevent_req *subreq);
+
+static void dfsrsrv_download_loop_start(struct dfsrsrv_session_loop_state *session,
+                                       uint32_t update_idx);
+
+/* Will start looping for DFSR events on a connection related to our membership in a
+ * given replicaset for a given partner
+ */
+static void dfsrsrv_session_loop_start(struct dfsrsrv_service *service,
+                                      struct dfsrsrv_replica_group *group,
+                                      struct dfsrsrv_replica_member *member,
+                                      struct dfsrsrv_connection *conn)
+{
+       struct dfsrsrv_session_loop_state *state;
+       struct GUID_txt_buf tmp_buf;
+
+       DEBUG(DEBUGLOG, ("Starting looping for DFSR member group '%s' with %s (our set = %s)\n",
+               group->name,
+               conn->hostname,
+               GUID_buf_string(&member->guid, &tmp_buf)));
+       state = talloc_zero(conn, struct dfsrsrv_session_loop_state);
+       if (state == NULL) {
+               //???
+               return;
+       }
+       state->service = service;
+       state->group = group;
+       state->member = member;
+       state->conn = conn;
+       state->generation = 0;
+       state->known_generation = 0;
+       state->change_type = FRSTRANS_VERSION_CHANGE_NOTIFY;
+
+       dfsrsrv_session_loop_next(state);
+}
+
+static void dfsrsrv_session_loop_next(struct dfsrsrv_session_loop_state *state)
+{
+       struct tevent_req *subreq;
+       uint32_t old_timeout;
+       uint32_t hash_requested = 0;
+       struct GUID_txt_buf tmp_buf;
+
+       if (state->subreq != NULL) {
+               goto request_updates;
+       }
+
+       old_timeout = dcerpc_binding_handle_set_timeout(state->conn->dcerpc_pipe->binding_handle, UINT32_MAX);
+       state->subreq = dcerpc_frstrans_AsyncPoll_send(state,
+                                                       state->service->task->event_ctx,
+                                                       state->conn->dcerpc_pipe->binding_handle,
+                                                       state->conn->guid,
+                                                       &state->poll_response);
+       dcerpc_binding_handle_set_timeout(state->conn->dcerpc_pipe->binding_handle, old_timeout);
+       if (state->subreq == NULL) {
+               return;
+       }
+       tevent_req_set_callback(state->subreq, dfsrsrv_session_loop_poll_done, state);
+       DEBUG(DEBUGLOG, ("Sending Request Version Vector with flag %s and generation %ld to %s\n",
+             state->change_type == FRSTRANS_VERSION_CHANGE_NOTIFY?"CHANGE_NOTIFY":"CHANGE_ALL",
+             state->known_generation,
+             GUID_buf_string(&state->conn->guid, &tmp_buf)));
+       state->sequence += 1;
+       subreq = dcerpc_frstrans_RequestVersionVector_send(state,
+                                                       state->service->task->event_ctx,
+                                                       state->conn->dcerpc_pipe->binding_handle,
+                                                       state->sequence,
+                                                       state->conn->guid,
+                                                       state->group->set_guids[0],
+                                                       FRSTRANS_VERSION_REQUEST_NORNAL_SYNC,
+                                                       state->change_type,
+                                                       state->known_generation);
+       if (subreq == NULL) {
+               return;
+       }
+       tevent_req_set_callback(subreq, dfsrsrv_session_loop_vector_done, state);
+
+       if (state->vector_diff_count != 0) {
+               goto request_updates;
+       }
+       state->change_type = FRSTRANS_VERSION_CHANGE_NOTIFY;
+       return;
+
+request_updates:
+       /*
+        * We have at this moment calculated a delta between what we know
+        * and what the partner told us as new stuff
+        */
+       state->num_updates = 0;
+       state->max_updates = 32;
+       state->updates = talloc_zero_array(state, struct frstrans_Update, state->max_updates);
+       if (state->updates == NULL) {
+               return;
+       }
+       subreq = dcerpc_frstrans_RequestUpdates_send(state,
+                                               state->service->task->event_ctx,
+                                               state->conn->dcerpc_pipe->binding_handle,
+                                               state->conn->guid,
+                                               state->group->set_guids[0],
+                                               state->max_updates,
+                                               hash_requested,
+                                               FRSTRANS_UPDATE_REQUEST_ALL,
+                                               state->vector_diff_count,
+                                               state->vector_diff,
+                                               state->updates,
+                                               &state->num_updates,
+                                               &state->update_status,
+                                               &state->gvsn_db_guid,
+                                               &state->gvsn_version);
+       if (subreq == NULL) {
+               return;
+       }
+       tevent_req_set_callback(subreq, dfsrsrv_session_loop_update_done, state);
+}
+
+/*
+ * Calculate the delta between what we know and what was sent by the partner
+ * Result is stored in state->vector_diff, previous vector is freed is non NULL
+ */
+static void calculate_delta_vectors(struct dfsrsrv_session_loop_state *state,
+                                   uint32_t vector_diff_count,
+                                   struct frstrans_VersionVector *vector_diff)
+{
+       uint32_t i, j;
+       if (state->vector_diff) {
+               TALLOC_FREE(state->vector_diff);
+               state->vector_diff_count = 0;
+       }
+
+       for (i = 0; i < vector_diff_count; i++) {
+               bool found = false;
+               for (j = 0; j < state->group->known_vector_diff_count; j++) {
+                       if (!GUID_compare(&vector_diff[i].db_guid,
+                                        &state->group->known_vector_diff[j].db_guid) == 0)
+                       {
+                               continue;
+                       }
+                       /* Same guid */
+                       found = true;
+                       if (state->group->known_vector_diff[j].high >= vector_diff[i].high) {
+                               /* We know already every thing */
+                               break;
+                       } else {
+                               state->vector_diff = talloc_realloc(state, state->vector_diff, struct frstrans_VersionVector, state->vector_diff_count + 1);
+                               state->vector_diff[state->vector_diff_count] = vector_diff[i];
+                               state->vector_diff[state->vector_diff_count].low = state->group->known_vector_diff[i].high;
+                               state->vector_diff_count++;
+                               break;
+                       }
+               }
+               if (!found) {
+                       state->vector_diff = talloc_realloc(state, state->vector_diff, struct frstrans_VersionVector, state->vector_diff_count + 1);
+                       state->vector_diff[state->vector_diff_count] = vector_diff[i];
+                       state->vector_diff_count++;
+               }
+       }
+       DEBUG(DEBUGLOG, ("%s %d newer vectors\n", __FILE__, state->vector_diff_count));
+}
+
+static void dfsrsrv_session_loop_poll_done(struct tevent_req *subreq)
+{
+       struct dfsrsrv_session_loop_state *state =
+               tevent_req_callback_data(subreq,
+               struct dfsrsrv_session_loop_state);
+       NTSTATUS error;
+       WERROR result;
+
+       if (state->change_type == FRSTRANS_VERSION_CHANGE_NOTIFY) {
+               state->change_type = FRSTRANS_VERSION_CHANGE_ALL ;
+       }
+       error = dcerpc_frstrans_AsyncPoll_recv(subreq, state, &result);
+       if (!NT_STATUS_IS_OK(error)) {
+               return;
+       }
+       if (!W_ERROR_IS_OK(result)) {
+               return;
+       }
+
+       if (!W_ERROR_IS_OK(state->poll_response.status)) {
+               return;
+       }
+       if (state->poll_response.sequence_number != state->sequence) {
+               return;
+       }
+       state->generation = state->poll_response.response.vv_generation;
+       if (state->poll_response.response.version_vector_count == 0) {
+               /* So that we restart a request version_vector */
+               state->subreq = NULL;
+       } else {
+               calculate_delta_vectors(state,
+                                       state->poll_response.response.version_vector_count,
+                                       state->poll_response.response.version_vector);
+       }
+
+       dfsrsrv_session_loop_next(state);
+}
+
+static void dfsrsrv_session_loop_vector_done(struct tevent_req *subreq)
+{
+       struct dfsrsrv_session_loop_state *state =
+               tevent_req_callback_data(subreq,
+               struct dfsrsrv_session_loop_state);
+       NTSTATUS error;
+       WERROR result;
+
+       error = dcerpc_frstrans_RequestVersionVector_recv(subreq, state,
+                                                         &result);
+       if (!NT_STATUS_IS_OK(error)) {
+               return;
+       }
+       if (!W_ERROR_IS_OK(result)) {
+               return;
+       }
+}
+
+static void lexicofilter_vector(struct GUID dbguid, uint64_t version,
+                               struct dfsrsrv_session_loop_state *state)
+{
+       unsigned i;
+       struct frstrans_VersionVector *vector_diff = NULL;
+       uint32_t vector_diff_count = 0;
+
+       for (i = 0; i < state->vector_diff_count; i++) {
+               int compare_res = GUID_compare(&state->vector_diff[i].db_guid, &dbguid);
+               switch (compare_res) {
+                       case -1:
+                               /* Lexically less so we ignore it */
+                               break;
+                       case 1:
+                               /* More so we keep it */
+                               vector_diff = talloc_realloc(state, vector_diff,
+                                                            struct frstrans_VersionVector,
+                                                            vector_diff_count + 1);
+                               vector_diff[vector_diff_count] = state->vector_diff[i];
+                               vector_diff_count++;
+                               break;
+                       case 0:
+                               /* Equal, let's see if the high is > version */
+                               if (state->vector_diff[i].high > version) {
+                                       vector_diff = talloc_realloc(state, vector_diff,
+                                                                    struct frstrans_VersionVector,
+                                                                    vector_diff_count + 1);
+                                       vector_diff[vector_diff_count] = state->vector_diff[i];
+                                       vector_diff[vector_diff_count].low = version;
+                                       vector_diff_count++;
+                               }
+                               break;
+                       default:
+                               break;
+               }
+       }
+       talloc_free(state->vector_diff);
+       state->vector_diff = vector_diff;
+       state->vector_diff_count = vector_diff_count;
+       return;
+}
+
+static void xor_guid(struct GUID *tgt, const struct GUID *guid1, const struct GUID *guid2)
+{
+       tgt->time_low = guid1->time_low ^ guid2->time_low;
+       tgt->time_mid = guid1->time_mid ^ guid2->time_mid;
+       tgt->time_hi_and_version = guid1->time_hi_and_version ^ guid2->time_hi_and_version;
+       tgt->clock_seq[0] = guid1->clock_seq[0] ^ guid2->clock_seq[0];
+       tgt->clock_seq[1] = guid1->clock_seq[1] ^ guid2->clock_seq[1];
+       tgt->node[0] = guid1->node[0] ^ guid2->node[0];
+       tgt->node[1] = guid1->node[1] ^ guid2->node[1];
+       tgt->node[2] = guid1->node[2] ^ guid2->node[2];
+       tgt->node[3] = guid1->node[3] ^ guid2->node[3];
+       tgt->node[4] = guid1->node[4] ^ guid2->node[4];
+       tgt->node[5] = guid1->node[5] ^ guid2->node[5];
+}
+
+/* Called once we have requested all the updates (but not got them necessarly */
+static void dfsrsrv_session_loop_update_done(struct tevent_req *subreq)
+{
+       struct dfsrsrv_session_loop_state *state =
+               tevent_req_callback_data(subreq,
+               struct dfsrsrv_session_loop_state);
+       NTSTATUS error;
+       WERROR result;
+       uint32_t i;
+       struct GUID_txt_buf tmp_buf;
+
+       error = dcerpc_frstrans_RequestUpdates_recv(subreq, state,
+                                                   &result);
+       if (!NT_STATUS_IS_OK(error)) {
+               TALLOC_FREE(subreq);
+               return;
+       }
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(subreq);
+               return;
+       }
+
+       TALLOC_FREE(subreq);
+       state->remaining_downloads += state->num_updates;
+       if (state->update_status != FRSTRANS_UPDATE_STATUS_MORE) {
+               /*
+                * state->vector_diff will be freed next time we do the calculation
+                * of the delta
+                */
+               state->vector_diff_count = 0;
+               state->known_generation = state->generation;
+               state->known_vector_diff = talloc_steal(state, state->poll_response.response.version_vector);
+               state->known_vector_diff_count = state->poll_response.response.version_vector_count;
+               state->change_type = FRSTRANS_VERSION_CHANGE_NOTIFY;
+               ZERO_STRUCT(state->poll_response);
+               TALLOC_FREE(state->subreq);
+       } else {
+               /* MS-FRS2 3.3.4.6.1: Requesting Updates (State Transitions)
+                * If thet status is not FRSTRANS_UPDATE_STATUS_DONE
+                * We need to compare the guid and not blindly assume that it's always the first elment*/
+               lexicofilter_vector(state->gvsn_db_guid, state->gvsn_version, state);
+               if (state->vector_diff == NULL) {
+                       DEBUG(ERRORLOG, ("FRSTRANS_UPDATE_STATUS_MORE but 0 delta\n"));
+                       state->vector_diff_count = 0;
+                       state->known_generation = state->generation;
+                       state->known_vector_diff = talloc_steal(state, state->poll_response.response.version_vector);
+                       state->known_vector_diff_count = state->poll_response.response.version_vector_count;
+                       state->change_type = FRSTRANS_VERSION_CHANGE_NOTIFY;
+                       ZERO_STRUCT(state->poll_response);
+                       TALLOC_FREE(state->subreq);
+               }
+               /* We don't do the free of the subreq if the lexicofilter thiny
+                * retruns a non empty vector so that session_loop_next
+                * goes back to requesting more updates
+                */
+       }
+       for (i = 0; i < state->num_updates; i++) {
+               struct GUID xored;
+               if (!state->member->isinitialized && !state->updates[i].present) {
+                       state->downloaded_updates += 1;
+                       DEBUG(0, ("Skipping update %d as we are not initialized and the file is not present\n",
+                             i));
+                       continue;
+               }
+               if (state->updates[i].uid_version == 2) {
+                       xor_guid(&xored, &state->updates[i].uid_db_guid,
+                               &state->updates[i].content_set_guid);
+                       state->skipped_updates += 1;
+                       DEBUG(0, ("VersionVector Tombstone at %d for GUID %s\n",
+                             i,
+                             GUID_buf_string(&xored, &tmp_buf)));
+                       continue;
+               }
+               dfsrsrv_download_loop_start(state, i);
+       }
+       dfsrsrv_session_loop_next(state);
+}
+
+struct dfsrsrv_download_loop_state {
+       struct dfsrsrv_session_loop_state *session;
+       uint32_t update_idx;
+       struct frstrans_Update *update;
+
+       enum frstrans_RequestedStagingPolicy staging_policy;
+       struct policy_handle server_context;
+       struct frstrans_RdcFileInfo *rdc_file_info;
+       uint8_t *data_buffer;
+       uint32_t buffer_size;
+       uint32_t size_read;
+       uint32_t is_end_of_file;
+       uint64_t offset;
+
+       struct dcerpc_pipe *p;
+       struct frstrans_BytePipe *byte_pipe;
+};
+
+static void dfsrsrv_download_loop_open_done(struct tevent_req *subreq);
+
+static void dfsrsrv_download_loop_start(struct dfsrsrv_session_loop_state *session,
+                                       uint32_t update_idx)
+{
+       struct frstrans_Update *update = &session->updates[update_idx];
+       struct dfsrsrv_download_loop_state *state;
+       struct tevent_req *subreq;
+
+       state = talloc_zero(session->updates, struct dfsrsrv_download_loop_state);
+       if (state == NULL) {
+               //???
+               return;
+       }
+       state->session = session;
+       state->update_idx = update_idx;
+       state->update = update;
+
+       state->staging_policy = FRSTRANS_STAGING_POLICY_SERVER_DEFAULTY;
+       state->buffer_size = 262144;
+       state->data_buffer = talloc_zero_array(state, uint8_t, state->buffer_size);
+       if (state->data_buffer == NULL) {
+               return;
+       }
+       state->size_read = 0;
+       state->is_end_of_file = 0;
+
+       DEBUG(0, ("Requesting file %s\n",state->update->name));
+       subreq = dcerpc_frstrans_InitializeFileTransferAsync_send(state,
+                                                       session->service->task->event_ctx,
+                                                       session->conn->dcerpc_pipe->binding_handle,
+                                                       session->conn->guid,
+                                                       state->update,
+                                                       1, /* rdc_desired */
+                                                       &state->staging_policy,
+                                                       &state->server_context,
+                                                       &state->rdc_file_info,
+                                                       state->data_buffer,
+                                                       state->buffer_size,
+                                                       &state->size_read,
+                                                       &state->is_end_of_file);
+       if (subreq == NULL) {
+               return;
+       }
+       tevent_req_set_callback(subreq, dfsrsrv_download_loop_open_done, state);
+}
+
+static void dfsrsrv_download_loop_connect_done(struct composite_context *c_req);
+
+/* Will write in the database the information that we had from the download */
+static void checkpoint_download(struct dfsrsrv_session_loop_state *session)
+{
+       DEBUG(INFOLOG, ("Downloaded %d files, skipped %d files\n",
+               session->downloaded_updates,
+               session->skipped_updates));
+       session->max_updates = 0;
+       session->num_updates = 0;
+       session->downloaded_updates = 0;
+       session->skipped_updates = 0;
+       session->remaining_downloads = 0;
+       if (!session->member->isinitialized) {
+               DEBUG(0, ("Finish initializing !\n"));
+               session->member->isinitialized = true;
+               /*
+                * FIXME check with ASAN if we need this or not
+                * session->conn->established = false;
+                * TALLOC_FREE(state->p);
+                * TALLOC_FREE(state);
+                * TALLOC_FREE(session);
+                */
+       }
+       TALLOC_FREE(session->updates);
+       return;
+}
+
+static void dfsrsrv_download_loop_open_done(struct tevent_req *subreq)
+{
+       struct dfsrsrv_download_loop_state *state =
+               tevent_req_callback_data(subreq,
+               struct dfsrsrv_download_loop_state);
+       struct dfsrsrv_session_loop_state *session = state->session;
+       struct composite_context *c_req;
+       NTSTATUS error;
+       WERROR result;
+
+       error = dcerpc_frstrans_InitializeFileTransferAsync_recv(subreq, state, &result);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(error)) {
+               DEBUG(ERRORLOG, ("dcerpc_frstrans_InitializeFileTransferAsync_recv returned error: %s",
+                               nt_errstr(error)));
+               return;
+       }
+       if (!W_ERROR_IS_OK(result)) {
+               DEBUG(ERRORLOG, ("RPC call InitializeFileTranferAsync return an error: %s",
+                       get_friendly_werror_msg(result)));
+               return;
+       }
+
+       if (state->is_end_of_file != 0) {
+               session->downloaded_updates += 1;
+               DEBUG(INFOLOG, ("Finished downloading file %s (%d out of %d)\n",
+                     state->update->name,
+                     session->downloaded_updates,
+                     (session->remaining_downloads - session->skipped_updates)));
+               TALLOC_FREE(state);
+               if (session->downloaded_updates < (session->remaining_downloads - session->skipped_updates)) {
+                       return;
+               }
+               /*
+                * TODO we want to checkpoint when 1 batch is finished not when
+                * everything is downloaded otherwise if there is a lot of updates
+                * and the download speed is low we can takes minutes/hours/days...
+                * to store our state
+                */
+               checkpoint_download(session);
+               return;
+       }
+
+       /*
+        * If the file couldn't be downloaded in just one rpc call then
+        * we have to go async with the byte pipe stuff
+        */
+       c_req = dcerpc_pipe_connect_b_send(state, session->conn->binding,
+                               &ndr_table_frstrans,
+                               session->service->system_session_info->credentials,
+                               session->service->tevent_ctx,
+                               session->service->task->lp_ctx);
+       if (c_req == NULL) {
+               return;
+       }
+       c_req->async.fn = dfsrsrv_download_loop_connect_done;
+       c_req->async.private_data = state;
+}
+
+static void dfsrsrv_download_loop_read_done(struct tevent_req *subreq);
+static void dfsrsrv_download_loop_chunk_done(struct tevent_req *subreq2);
+
+static void dfsrsrv_download_loop_connect_done(struct composite_context *c_req)
+{
+       struct dfsrsrv_download_loop_state *state =
+               talloc_get_type_abort(c_req->async.private_data,
+               struct dfsrsrv_download_loop_state);
+       struct dfsrsrv_session_loop_state *session = state->session;
+       struct tevent_req *subreq;
+       struct tevent_req *subreq2;
+       NTSTATUS error;
+
+       error = dcerpc_pipe_connect_b_recv(c_req, state, &state->p);
+       if (!NT_STATUS_IS_OK(error)) {
+               DEBUG(ERRORLOG, ("dcerpc_pipe_connect_b_recv returned error: %s",
+                               nt_errstr(error)));
+               return;
+       }
+
+       state->byte_pipe = dcerpc_frstrans_BytePipe_create(state);
+       if (state->byte_pipe == NULL) {
+               DEBUG(ERRORLOG, ("dcerpc_frstrans_BytePipe_create returned NULL"));
+               return;
+       }
+
+       subreq = dcerpc_frstrans_RawGetFileDataAsync_send(state,
+                                                       session->service->task->event_ctx,
+                                                       session->conn->dcerpc_pipe->binding_handle,
+                                                       &state->server_context,
+                                                       state->byte_pipe);
+       if (subreq == NULL) {
+               return;
+       }
+       tevent_req_set_callback(subreq, dfsrsrv_download_loop_read_done, state);
+
+       subreq2 = dcerpc_frstrans_BytePipe_chunk_pull_send(state,
+                                                       session->service->task->event_ctx,
+                                                       state->byte_pipe);
+       if (subreq2 == NULL) {
+               return;
+       }
+       tevent_req_set_callback(subreq2, dfsrsrv_download_loop_chunk_done, state);
+}
+
+static void dfsrsrv_download_loop_chunk_done(struct tevent_req *subreq2)
+{
+       struct dfsrsrv_download_loop_state *state =
+               tevent_req_callback_data(subreq2,
+               struct dfsrsrv_download_loop_state);
+       struct dfsrsrv_session_loop_state *session = state->session;
+       NTSTATUS error;
+       struct frstrans_BytePipe_chunk *chunk;
+
+       error = dcerpc_frstrans_BytePipe_chunk_pull_recv(subreq2, state, &chunk);
+       TALLOC_FREE(subreq2);
+       if (!NT_STATUS_IS_OK(error)) {
+               DEBUG(ERRORLOG, ("dcerpc_frstrans_InitializeFileTransferAsync_recv returned error: %s",
+                               nt_errstr(error)));
+               return;
+       }
+
+       if (DEBUGLVL(10)) {
+               NDR_PRINT_DEBUG(frstrans_BytePipe_chunk, chunk);
+       } else {
+               if (chunk->count > 0) {
+                       DEBUG(DEBUGLOG,("file %s frstrans_BytePipe_chunk count[%u]\n",
+                               state->update->name,
+                               chunk->count));
+               }
+       }
+
+       if (chunk->count == 0) {
+               session->downloaded_updates += 1;
+               DEBUG(INFOLOG, ("Finished downloading file %s (%d out of %d) (using async)\n",
+                     state->update->name,
+                     session->downloaded_updates,
+                     (session->remaining_downloads - session->skipped_updates)));
+               TALLOC_FREE(chunk);
+               return;
+       }
+       TALLOC_FREE(chunk);
+
+       subreq2 = dcerpc_frstrans_BytePipe_chunk_pull_send(state,
+                                                       session->service->task->event_ctx,
+                                                       state->byte_pipe);
+       if (subreq2 == NULL) {
+               return;
+       }
+       tevent_req_set_callback(subreq2, dfsrsrv_download_loop_chunk_done, state);
+}
+
+static void dfsrsrv_download_loop_close_done(struct tevent_req *subreq);
+
+static void dfsrsrv_download_loop_read_done(struct tevent_req *subreq)
+{
+       struct dfsrsrv_download_loop_state *state =
+               tevent_req_callback_data(subreq,
+               struct dfsrsrv_download_loop_state);
+       struct dfsrsrv_session_loop_state *session = state->session;
+       NTSTATUS error;
+       WERROR result;
+
+       error = dcerpc_frstrans_RawGetFileDataAsync_recv(subreq, state, &result);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(error)) {
+               DEBUG(ERRORLOG, ("dcerpc_frstrans_RawGetFileDataAsync_recv returned error: %s",
+                               nt_errstr(error)));
+               return;
+       }
+       if (!W_ERROR_IS_OK(result)) {
+               DEBUG(ERRORLOG, ("RPC call RawGetFileDataAsync return an error: %s",
+                       get_friendly_werror_msg(result)));
+               return;
+       }
+
+       subreq = dcerpc_frstrans_RdcClose_send(state,
+                                               session->service->task->event_ctx,
+                                               session->conn->dcerpc_pipe->binding_handle,
+                                               &state->server_context);
+       if (subreq == NULL) {
+               return;
+       }
+       tevent_req_set_callback(subreq, dfsrsrv_download_loop_close_done, state);
+}
+
+/* End of async download */
+static void dfsrsrv_download_loop_close_done(struct tevent_req *subreq)
+{
+       struct dfsrsrv_download_loop_state *state =
+               tevent_req_callback_data(subreq,
+               struct dfsrsrv_download_loop_state);
+       struct dfsrsrv_session_loop_state *session = state->session;
+       NTSTATUS error;
+       WERROR result;
+
+       error = dcerpc_frstrans_RdcClose_recv(subreq, state, &result);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(error)) {
+               return;
+       }
+       if (!W_ERROR_IS_OK(result)) {
+               return;
+       }
+
+       TALLOC_FREE(state);
+       if (session->downloaded_updates < (session->remaining_downloads - session->skipped_updates)) {
+               return;
+       }
+
+       checkpoint_download(session);
+}
+
+static void dorun(struct dfsrsrv_service *service)
+{
+       struct ldb_dn *dn_sysvol;
+       TALLOC_CTX *mem_ctx = talloc_new(service);
+       const struct GUID *ntds_guid;
+       unsigned int i;
+       static bool just_booted = true;
+
+       /*
+        * Every time we run if we don't know the sysvol dfsr
+        * replication group has already been created
+        *
+        * Normaly the dfsr sysvol is now created at provision time, but
+        * in order to cope with existing provsion that do not have it
+        * we wait for one to pop !
+        */
+       if (!init_sysvol_replicaset(service)) {
+               DEBUG(0, ("init_sysvol_replicaset returned %s",
+                         service->error));
+               talloc_free(service->error);
+               return;
+       }
+
+       ntds_guid = samdb_ntds_objectGUID(service->samdb);
+       dn_sysvol = ldb_dn_new_fmt(mem_ctx, service->dfsrdb, "CN=%s, CN=%s",
+                                       GUID_string(mem_ctx, &service->sysvol->guid),
+                                       GUID_string(mem_ctx, ntds_guid));
+       if (dn_sysvol == NULL || service->sysvol->me == NULL) {
+               talloc_free(mem_ctx);
+               return;
+       }
+       if (just_booted) {
+               DEBUG(INFOLOG, ("DFSR SYSVOL subscription for this server is %s\n",
+                       ldb_dn_get_linearized(service->sysvol->me->dn)));
+       }
+
+       /* TODO
+        * We need to scan the groups from time to time in order to find new groups
+        * and also new member
+        */
+
+       for (i = 0; i < service->numgroups; i++) {
+               /* Most probably FIXME because we make the assumption that there
+                * is one replicaset in a given group
+                * It's the case for sysvol but not for the rest I think
+                * Matthieu Patou Sep 2014
+                */
+               struct dfsrsrv_replica_member *me = service->groups[i]->me;
+               if (me) {
+                       int j, loglevel;
+                       populate_connections(me, service->samdb,
+                                            service->groups[i]->is_sysvol);
+
+                       if (!just_booted) {
+                               loglevel = ALLYOUCANEATLOG;
+                       } else {
+                               loglevel = 1;
+                       }
+                       DEBUG(loglevel, ("There is %d connection for the subscription %s\n",
+                             me->num_cnx, ldb_dn_get_linearized(me->dn)));
+
+                       for (j=0; j < me->num_cnx; j++) {
+                               if (!me->cnxs[j]->established) {
+                                       establish_connection(service,
+                                                            service->groups[i],
+                                                            me,
+                                                            me->cnxs[j]);
+                               } else {
+                                       continue;
+                               }
+                               //send_asyncpoll();
+                       }
+               }
+       }
+       just_booted = false;
+}
+
+static bool init_sysvol_replicaset(struct dfsrsrv_service *service)
+{
+       struct ldb_dn *sysvol_replicagrp_dn;
+       WERROR status;
+       if (service->sysvol != NULL && service->sysvol->initizialized) {
+               return true;
+       }
+       sysvol_replicagrp_dn = ldb_dn_new_fmt(service, service->samdb,
+                                       "CN=Domain System Volume, %s",
+                                       ldb_dn_get_linearized(service->dfsr_basedn));
+       status = get_dfsr_sets_ingroup(service, sysvol_replicagrp_dn, true);
+       if (!W_ERROR_IS_OK(status)) {
+               service->error = talloc_asprintf(service,
+                                               "dfssrv: Failed to get sysvol replica infos %s",
+                                               win_errstr(status));
+               return false;
+       }
+       talloc_free(sysvol_replicagrp_dn);
+       /*
+        * There is a dfsr group for sysvol, let's see if we should
+        * register ourselves
+        */
+       if (service->sysvol) {
+               int ret = register_or_get_sysvol_subscription(service);
+               if ( ret != LDB_SUCCESS) {
+                       DEBUG(ERRORLOG, ("register_or_get_sysvol_subscription "
+                               "failed with the following ldb error: %s\n",
+                               ldb_errstring(service->samdb)));
+                       service->error = talloc_asprintf(service,
+                                                       "dfsrsrv: Failed to register_or_get_sysvol_subscription: %d\n",
+                                                       ret);
+                       return false;
+               }
+       }
+       return true;
+}
+
+/*
+  startup the dfsr service.
+*/
+static void dfsrsrv_task_init(struct task_server *task)
+{
+       WERROR status;
+       struct dfsrsrv_service *service;
+       uint32_t periodic_startup_interval;
+
+       switch (lpcfg_server_role(task->lp_ctx)) {
+       case ROLE_STANDALONE:
+               task_server_terminate(task, "dfsrsrv: no dfsr required in standalone configuration",
+                                     false);
+               return;
+       case ROLE_DOMAIN_MEMBER:
+               /*
+                * FIXME
+                * Needs to be fixed in the future
+                */
+               task_server_terminate(task, "dfsrsrv: no dfsr required in domain member configuration",
+                                     false);
+               return;
+       case ROLE_ACTIVE_DIRECTORY_DC:
+               break;
+       }
+
+       task_server_set_title(task, "task[dfsrsrv]");
+
+       service = talloc_zero(task, struct dfsrsrv_service);
+       if (!service) {
+               task_server_terminate(task, "dfsrsrv_task_init: out of memory", true);
+               return;
+       }
+       service->task           = task;
+       service->startup_time   = timeval_current();
+       status = init_service_paths(service);
+
+       if (!W_ERROR_IS_OK(status)) {
+               task_server_terminate(task, talloc_asprintf(task,
+                                     "dfsrsrv: Failed to init files path: %s\n",
+                                                           win_errstr(status)), true);
+               return;
+       }
+
+       task->private_data      = service;
+
+       status = dfsrsrv_init_creds(service);
+       if (!W_ERROR_IS_OK(status)) {
+               task_server_terminate(task, talloc_asprintf(task,
+                                     "dfsrsrv: Failed to obtain server credentials: %s\n",
+                                                           win_errstr(status)), true);
+               return;
+       }
+       status = dfsrsrv_connect_dbs(service, task->lp_ctx);
+       if (!W_ERROR_IS_OK(status)) {
+               task_server_terminate(task, talloc_asprintf(task,
+                                     "dfsrsrv: Failed to connect to databases: %s\n",
+                                                           win_errstr(status)), true);
+               return;
+       }
+
+       service->dfsr_basedn = ldb_dn_new_fmt(service, service->samdb,
+                                             "CN=DFSR-GlobalSettings,CN=System,%s",
+                                             ldb_dn_get_linearized(ldb_get_root_basedn(service->samdb)));
+       /*
+        * FIXME do all the DFSR Replication groups one day
+        * For the moment do only sysvol
+        */
+       if (!init_sysvol_replicaset(service)) {
+               task_server_terminate(task, service->error, true);
+               return;
+       }
+       periodic_startup_interval = lpcfg_parm_int(task->lp_ctx, NULL,
+                                                  "dfsrsrv",
+                                                  "periodic_startup_interval",
+                                                  1); /* in seconds */
+       service->periodic.interval = lpcfg_parm_int(task->lp_ctx, NULL,
+                                                   "dfsrsrv",
+                                                   "periodic_interval",
+                                                   10); /* in seconds */
+
+       status = dfsrsrv_periodic_schedule(service, periodic_startup_interval);
+       if (!W_ERROR_IS_OK(status)) {
+               task_server_terminate(task,
+                                     talloc_asprintf(task,
+                                       "dfsrsrv: Failed to periodic schedule: %s\n",
+                                       win_errstr(status)),
+                                     true);
+               return;
+       }
+
+#if 0
+       irpc_add_name(task->msg_ctx, "dfsrsrv");
+
+       IRPC_REGISTER(task->msg_ctx, irpc, dfsrSRV_CHECK_VALID_VOLATILE,
+                       dfsrsrv_is_valid_temporary_cnx, service);
+
+       IRPC_REGISTER(task->msg_ctx, irpc, dfsrSRV_PROCESS_COMMAND,
+                       dfsrsrv_process_command, service);
+
+       IRPC_REGISTER(task->msg_ctx, irpc, dfsrSRV_PROCESS_START_PROMOTION,
+                       dfsrsrv_process_start_promotion, service);
+#endif
+}
+
+/*
+  register ourselves as a available server
+*/
+NTSTATUS server_service_dfsr_init(void)
+{
+       return register_server_service("dfsr", dfsrsrv_task_init);
+}
diff --git a/source4/dfsr/dfsr_service.h b/source4/dfsr/dfsr_service.h
new file mode 100644 (file)
index 0000000..3708b74
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+   Unix SMB/CIFS mplementation.
+   DFSR Replication service, it's the server part of it.
+
+   Copyright (C) Matthieu Patou <mat@matws.net> 2013
+
+   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/>.
+
+*/
+
+#ifndef _dfsr_SERVICE_H_
+#define _dfsr_SERVICE_H_
+
+#include "librpc/gen_ndr/ndr_irpc.h"
+
+enum dfsrsrv_state_type
+#ifndef USE_UINT_ENUMS
+{
+       INIT_FILE=(int)(0),
+       GET_FILE=(int)(1),
+       RENAME_FILE=(int)(2),
+       INIT_FOLDER=(int)(3),
+       GET_FOLDER=(int)(4),
+       RENAME_FOLDER=(int)(5),
+       DELETE_OBJECT=(int)(6)
+}
+#else
+ { __donnot_use_enum_cnx_dir=0x7FFFFFFF}
+#define INIT_FILE (0)
+#define GET_FILE (1)
+#define RENAME_FILE (2)
+#define INIT_FOLDER (3)
+#define GET_FOLDER (4)
+#define RENAME_FOLDER (5)
+#define DELETE_OBJECT (6)
+#endif
+;
+
+enum cnx_dir
+#ifndef USE_UINT_ENUMS
+{
+       CNX_INBOUND=(int)(0),
+       CNX_OUTBOUND=(int)(1),
+}
+#else
+ { __donnot_use_enum_cnx_dir=0x7FFFFFFF}
+#define CNX_INBOUND ( 0 )
+#define CNX_OUTBOUND ( 1 )
+#endif
+;
+
+enum dfsrsrv_change_state
+#ifndef USE_UINT_ENUMS
+{
+       CHANGE_NEW=(int)(0),
+       CHANGE_REQUESTED=(int)(1),
+       CHANGE_STAGED=(int)(2),
+}
+#else
+ { __donnot_use_enum_cnx_dir=0x7FFFFFFF}
+#define CHANGE_NEW ( 0 )
+#define CHANGE_REQUESTED ( 1 )
+#define CHANGE_STAGED ( 2 )
+#endif
+;
+
+struct dfsrsrv_connection;
+
+struct dfsrsrv_change_order {
+       struct GUID guid;
+       struct dfsrsrv_connection *cnx;
+       const char *entry_name;
+       uint64_t sequence;
+       uint64_t offset;
+       uint64_t size;
+       uint64_t type;
+       enum dfsrsrv_change_state state;
+       struct dfsrrpc_CommPktChangeOrderCommand *command;
+};
+
+struct dfsrsrv_queued_co {
+       struct dfsrsrv_queued_co *next;
+       struct dfsrsrv_queued_co *prev;
+       struct dfsrsrv_change_order *co;
+};
+
+struct dfsrsrv_connection {
+       struct GUID guid;
+       const char *hostname;
+       const char *binding_string;
+       struct dcerpc_binding *binding;
+       struct dcerpc_pipe *dcerpc_pipe;
+       bool established;
+};
+
+struct dfsrsrv_replica_member {
+       /* dn of the subscription */
+       struct ldb_dn *dn;
+       /* dn of the dfrsmember */
+       struct ldb_dn *memberdn;
+       const char *path;
+       const char *name;
+       struct GUID guid;
+       uint32_t num_cnx;
+       bool isinitialized;
+       struct dfsrsrv_connection **cnxs;
+};
+
+struct dfsrsrv_replica_group {
+       struct GUID guid;
+       /*
+        * Will be something like
+        * CN=Domain System Volume,CN=DFSR-GlobalSettings,CN=System,<DOMAIN>
+        * or
+        * CN=<GroupName>,CN=DFSR-GlobalSettings,CN=System,<DOMAIN>
+        */
+       struct ldb_dn *dn;
+       const char *name;
+       struct dfsrsrv_replica_member *me;
+       bool is_sysvol;
+       uint32_t numsets;
+       char **set_names;
+       struct GUID *set_guids;
+       bool initizialized;
+
+       uint32_t known_vector_diff_count;
+       struct frstrans_VersionVector *known_vector_diff;
+
+       /* Future use */
+       uint64_t max_usn;
+};
+
+struct dfsrsrv_service {
+       /* the whole dfsr service is in one task */
+       struct task_server *task;
+
+       /* the time the service was started */
+       struct timeval startup_time;
+
+       /*
+        * system session info
+        * with machine account credentials
+        */
+       struct auth_session_info *system_session_info;
+
+       /*
+        * a connection to the local samdb
+        */
+       struct ldb_context *samdb;
+       /*
+        * a connection to the dfsr db
+        */
+       struct ldb_context *dfsrdb;
+
+       struct ldb_dn *my_account_dn;
+
+       struct dfsrsrv_replica_group *sysvol;
+       struct dfsrsrv_replica_group **groups;
+       uint32_t numgroups;
+
+       int sysvol_join;
+
+       struct ldb_dn *dfsr_basedn;
+
+       struct tevent_context *tevent_ctx;
+       /* some stuff for periodic processing */
+       struct {
+               /*
+                * the interval between to periodic runs
+                */
+               uint32_t interval;
+
+               /*
+                * the timestamp for the next event,
+                * this is the timstamp passed to event_add_timed()
+                */
+               struct timeval next_event;
+
+               /* here we have a reference to the timed event the schedules the periodic stuff */
+               struct tevent_timer *te;
+       } periodic;
+       char *error;
+};
+
+#include "dfsr/dfsr_service_proto.h"
+#endif /* _dfsr_SERVICE_H_ */
diff --git a/source4/dfsr/wscript_build b/source4/dfsr/wscript_build
new file mode 100644 (file)
index 0000000..35236e7
--- /dev/null
@@ -0,0 +1,9 @@
+
+bld.SAMBA_MODULE('service_dfsr',
+       source='dfsr_service.c',
+       autoproto='dfsr_service_proto.h',
+       subsystem='service',
+       init_function='server_service_dfsr_init',
+       deps='samdb process_model RPC_NDR_FRSTRANS',
+       internal_module=False
+       )
index 5b3a9449be46f995a844767575832058a48ffecc..efa455208af14cea6e08d7dda50d901468357623 100644 (file)
@@ -87,6 +87,7 @@ bld.RECURSE('lib/crypto')
 bld.RECURSE('lib/torture')
 bld.RECURSE('source4/lib/com')
 bld.RECURSE('source4/dns_server')
+bld.RECURSE('source4/dfsr')
 bld.RECURSE('source4/echo_server')
 bld.RECURSE('source4/smb_server')
 bld.RECURSE('source4/rpc_server')