Avoid including libds/common/roles.h in public loadparm.h header.
[obnox/samba/samba-obnox.git] / source4 / dsdb / kcc / kcc_service.c
index b088d2ed896cd94105999eec29a4ba5438a6f96d..985692f4fb9bbebd686776d3c1043e9447efd695 100644 (file)
 #include "lib/events/events.h"
 #include "lib/messaging/irpc.h"
 #include "dsdb/kcc/kcc_service.h"
-#include "lib/ldb/include/ldb_errors.h"
+#include <ldb_errors.h>
 #include "../lib/util/dlinklist.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/gen_ndr/ndr_drsuapi.h"
 #include "librpc/gen_ndr/ndr_drsblobs.h"
 #include "param/param.h"
+#include "libds/common/roles.h"
 
 /*
   establish system creds
@@ -55,7 +56,7 @@ static WERROR kccsrv_connect_samdb(struct kccsrv_service *service, struct loadpa
 {
        const struct GUID *ntds_guid;
 
-       service->samdb = samdb_connect(service, service->task->event_ctx, lp_ctx, service->system_session_info);
+       service->samdb = samdb_connect(service, service->task->event_ctx, lp_ctx, service->system_session_info, 0);
        if (!service->samdb) {
                return WERR_DS_UNAVAILABLE;
        }
@@ -67,6 +68,11 @@ static WERROR kccsrv_connect_samdb(struct kccsrv_service *service, struct loadpa
 
        service->ntds_guid = *ntds_guid;
 
+       if (samdb_rodc(service->samdb, &service->am_rodc) != LDB_SUCCESS) {
+               DEBUG(0,(__location__ ": Failed to determine RODC status\n"));
+               return WERR_DS_UNAVAILABLE;
+       }
+
        return WERR_OK;
 }
 
@@ -80,7 +86,7 @@ static WERROR kccsrv_load_partitions(struct kccsrv_service *s)
        struct ldb_result *r;
        struct ldb_message_element *el;
        static const char *attrs[] = { "namingContexts", "configurationNamingContext", NULL };
-       uint32_t i;
+       unsigned int i;
        int ret;
 
        basedn = ldb_dn_new(s, s->samdb, NULL);
@@ -101,7 +107,7 @@ static WERROR kccsrv_load_partitions(struct kccsrv_service *s)
                return WERR_FOOBAR;
        }
 
-       for (i=0; el && i < el->num_values; i++) {
+       for (i=0; i < el->num_values; i++) {
                const char *v = (const char *)el->values[i].data;
                struct ldb_dn *pdn;
                struct kccsrv_partition *p;
@@ -137,6 +143,122 @@ static WERROR kccsrv_load_partitions(struct kccsrv_service *s)
 }
 
 
+struct kcc_manual_runcmd_state {
+       struct irpc_message *msg;
+       struct drsuapi_DsExecuteKCC *r;
+       struct kccsrv_service *service;
+};
+
+
+/*
+ * Called when samba_kcc script has finished
+ */
+static void manual_samba_kcc_done(struct tevent_req *subreq)
+{
+       struct kcc_manual_runcmd_state *st =
+               tevent_req_callback_data(subreq,
+               struct kcc_manual_runcmd_state);
+        int rc;
+        int sys_errno;
+       NTSTATUS status;
+
+        st->service->periodic.subreq = NULL;
+
+       rc = samba_runcmd_recv(subreq, &sys_errno);
+       TALLOC_FREE(subreq);
+
+       if (rc != 0) {
+               status = map_nt_error_from_unix_common(sys_errno);
+       } else {
+               status = NT_STATUS_OK;
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,(__location__ ": Failed manual run of samba_kcc - %s\n",
+                       nt_errstr(status)));
+       } else {
+               DEBUG(3,("Completed manual run of samba_kcc OK\n"));
+       }
+
+       if (!(st->r->in.req->ctr1.flags & DRSUAPI_DS_EXECUTE_KCC_ASYNCHRONOUS_OPERATION)) {
+               irpc_send_reply(st->msg, status);
+       }
+}
+
+static NTSTATUS kccsrv_execute_kcc(struct irpc_message *msg, struct drsuapi_DsExecuteKCC *r)
+{
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status = NT_STATUS_OK;
+       struct kccsrv_service *service = talloc_get_type(msg->private_data, struct kccsrv_service);
+
+       const char * const *samba_kcc_command;
+       struct kcc_manual_runcmd_state *st;
+
+       if (!service->samba_kcc_code) {
+               mem_ctx = talloc_new(service);
+
+               status = kccsrv_simple_update(service, mem_ctx);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,("kccsrv_execute_kcc failed - %s\n",
+                               nt_errstr(status)));
+               }
+               talloc_free(mem_ctx);
+
+               return NT_STATUS_OK;
+       }
+
+       /* Invocation of the samba_kcc python script for replication
+        * topology generation.
+        */
+
+       samba_kcc_command =
+               lpcfg_samba_kcc_command(service->task->lp_ctx);
+
+       st = talloc(msg, struct kcc_manual_runcmd_state);
+       if (st == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       st->msg = msg;
+       st->r = r;
+       st->service = service;
+
+       /* don't run at the same time as an existing child */
+       if (service->periodic.subreq) {
+               status = NT_STATUS_DS_BUSY;
+               return status;
+       }
+
+       DEBUG(2, ("Calling samba_kcc script\n"));
+       service->periodic.subreq = samba_runcmd_send(service,
+                                                    service->task->event_ctx,
+                                                    timeval_current_ofs(40, 0),
+                                                    2, 0, samba_kcc_command, NULL);
+
+       if (service->periodic.subreq == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               DEBUG(0,(__location__ ": failed - %s\n", nt_errstr(status)));
+               return status;
+       } else {
+               tevent_req_set_callback(service->periodic.subreq,
+                                       manual_samba_kcc_done, st);
+       }
+
+       if (r->in.req->ctr1.flags & DRSUAPI_DS_EXECUTE_KCC_ASYNCHRONOUS_OPERATION) {
+               /* This actually means reply right away, let it run in the background */
+       } else {
+               /* mark the request as replied async, the caller wants to know when this is finished */
+               msg->defer_reply = true;
+       }
+       return status;
+
+}
+
+static NTSTATUS kccsrv_replica_get_info(struct irpc_message *msg, struct drsuapi_DsReplicaGetInfo *r)
+{
+       return kccdrs_replica_get_info(msg, r);
+}
+
 /*
   startup the kcc service task
 */
@@ -146,14 +268,14 @@ static void kccsrv_task_init(struct task_server *task)
        struct kccsrv_service *service;
        uint32_t periodic_startup_interval;
 
-       switch (lp_server_role(task->lp_ctx)) {
+       switch (lpcfg_server_role(task->lp_ctx)) {
        case ROLE_STANDALONE:
                task_server_terminate(task, "kccsrv: no KCC required in standalone configuration", false);
                return;
        case ROLE_DOMAIN_MEMBER:
                task_server_terminate(task, "kccsrv: no KCC required in domain member configuration", false);
                return;
-       case ROLE_DOMAIN_CONTROLLER:
+       case ROLE_ACTIVE_DIRECTORY_DC:
                /* Yes, we want a KCC */
                break;
        }
@@ -194,10 +316,18 @@ static void kccsrv_task_init(struct task_server *task)
                return;
        }
 
-       periodic_startup_interval       = lp_parm_int(task->lp_ctx, NULL, "kccsrv", 
-                                                     "periodic_startup_interval", 15); /* in seconds */
-       service->periodic.interval      = lp_parm_int(task->lp_ctx, NULL, "kccsrv", 
-                                                     "periodic_interval", 300); /* in seconds */
+       periodic_startup_interval =
+               lpcfg_parm_int(task->lp_ctx, NULL, "kccsrv",
+                             "periodic_startup_interval", 15); /* in seconds */
+       service->periodic.interval =
+               lpcfg_parm_int(task->lp_ctx, NULL, "kccsrv",
+                             "periodic_interval", 300); /* in seconds */
+
+       /* (kccsrv:samba_kcc=true) will run newer samba_kcc replication
+        * topology generation code.
+        */
+       service->samba_kcc_code = lpcfg_parm_bool(task->lp_ctx, NULL,
+                                               "kccsrv", "samba_kcc", false);
 
        status = kccsrv_periodic_schedule(service, periodic_startup_interval);
        if (!W_ERROR_IS_OK(status)) {
@@ -208,6 +338,9 @@ static void kccsrv_task_init(struct task_server *task)
        }
 
        irpc_add_name(task->msg_ctx, "kccsrv");
+
+       IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSEXECUTEKCC, kccsrv_execute_kcc, service);
+       IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSREPLICAGETINFO, kccsrv_replica_get_info, service);
 }
 
 /*