s4/net_drs: 'net drs kcc' command implementation
authorKamen Mazdrashki <kamen.mazdrashki@postpath.com>
Sat, 6 Feb 2010 01:13:33 +0000 (03:13 +0200)
committerAndrew Tridgell <tridge@samba.org>
Thu, 11 Feb 2010 10:59:39 +0000 (21:59 +1100)
Signed-off-by: Andrew Tridgell <tridge@samba.org>
source4/utils/net/config.mk
source4/utils/net/drs/net_drs.c
source4/utils/net/drs/net_drs_kcc.c [new file with mode: 0644]

index 70c6bafd0a8f4da2578effb62bdbb4f89ad215ce..e3dfb35ce0aba51bba8045d06d40bfae607340dd 100644 (file)
@@ -14,7 +14,8 @@ PRIVATE_DEPENDENCIES = \
 
 net_drs_OBJ_FILES = $(addprefix $(utilssrcdir)/net/drs/,  \
                net_drs.o \
-               net_drs_bind.o)
+               net_drs_bind.o \
+               net_drs_kcc.o)
 
 $(eval $(call proto_header_template,$(utilssrcdir)/net/drs/net_drs_proto.h,$(net_drs_OBJ_FILES:.o=.c)))
 
index 547d642bfbe5ce3eddff2cdbf28cde8b57aab936..7772d83aceea9c818c792242e700a642c7eca820 100644 (file)
@@ -34,6 +34,8 @@
  */
 static const struct net_functable net_drs_functable[] = {
        { "bind", "Display replication features for a domain controller\n", net_drs_bind_cmd, net_drs_bind_usage },
+       { "kcc", "Forces the KCC to recalculate replication topology for a specified domain controller\n",
+                 net_drs_kcc_cmd, net_drs_kcc_usage },
        { NULL, NULL }
 };
 
@@ -53,7 +55,8 @@ int net_drs_usage(struct net_context *ctx, int argc, const char **argv)
        d_printf("net drs <command> [options]\n");
        d_printf("\n");
        d_printf("Currently implemented commands:\n");
-       d_printf("  bind - Display DC replication features");
+       d_printf("  bind - Display DC replication features\n");
+       d_printf("  kcc - Forces the KCC to recalculate replication topology for a specified domain controller\n");
        return 0;
 }
 
diff --git a/source4/utils/net/drs/net_drs_kcc.c b/source4/utils/net/drs/net_drs_kcc.c
new file mode 100644 (file)
index 0000000..fb2c661
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Implements functions offered by repadmin.exe tool under Windows
+
+   Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2010
+
+   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 "utils/net/net.h"
+#include "net_drs.h"
+#include "lib/ldb/include/ldb.h"
+
+
+static bool net_drs_kcc_site_info(struct net_drs_context *drs_ctx,
+                                 const char **site_name,
+                                 uint32_t *site_options)
+{
+       struct ldb_dn *dn;
+       const struct ldb_val *ldb_val;
+       TALLOC_CTX *mem_ctx;
+       int ret;
+       struct ldb_result *ldb_res;
+       static const char *attrs[] = {
+               "options",
+               "whenChanged",
+               NULL
+       };
+
+       mem_ctx = talloc_new(drs_ctx);
+
+       /* get dsServiceName, which is NTDS Settings
+        * object for the server
+        * e.g.: CN=NTDS Settings,CN=<DC_NAME>,CN=Servers,CN=<SITE_NAME>,CN=Sites,<CONFIG> */
+       dn = ldb_msg_find_attr_as_dn(drs_ctx->ldap.ldb, mem_ctx, drs_ctx->ldap.rootdse, "dsServiceName");
+       if (!dn) {
+               d_printf("No dsServiceName value in RootDSE!\n");
+               goto failed;
+       }
+
+       /* work out site name */
+       if (!ldb_dn_remove_child_components(dn, 3)) {
+               d_printf("Failed to find Site DN.\n");
+               goto failed;
+       }
+
+       ldb_val = ldb_dn_get_rdn_val(dn);
+       if (!ldb_val) {
+               d_printf("Failed to get site name.\n");
+               goto failed;
+       }
+       *site_name = talloc_strndup(drs_ctx, (const char*)ldb_val->data, ldb_val->length);
+
+       /* get 'NTDS Site Settings' */
+       if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Site Settings")) {
+               d_printf("Failed to create NTDS Site Settings DN.\n");
+               goto failed;
+       }
+
+       ret = ldb_search(drs_ctx->ldap.ldb, mem_ctx, &ldb_res,
+                            dn, LDB_SCOPE_BASE,  attrs, "(objectClass=*)");
+       if (ret != LDB_SUCCESS) {
+               d_printf("Failed to get Site object\n");
+               goto failed;
+       }
+       if (ldb_res->count != 1) {
+               d_printf("Error: returned %d messages for Site object.\n", ldb_res->count);
+               goto failed;
+       }
+       *site_options = ldb_msg_find_attr_as_uint(ldb_res->msgs[0], "options", 0);
+
+       talloc_free(mem_ctx);
+       return true;
+
+failed:
+       talloc_free(mem_ctx);
+       return false;
+}
+
+/**
+ * 'net drs kcc' command entry point
+ */
+int net_drs_kcc_cmd(struct net_context *ctx, int argc, const char **argv)
+{
+       NTSTATUS status;
+       struct net_drs_context *drs_ctx;
+       struct drsuapi_DsBindInfo48 *info48;
+       struct drsuapi_DsExecuteKCC req;
+       union drsuapi_DsExecuteKCCRequest kcc_req;
+       const char *site_name;
+       uint32_t site_options;
+
+       /* only one arg expected */
+       if (argc != 1) {
+               return net_drs_kcc_usage(ctx, argc, argv);
+       }
+
+       if (!net_drs_create_context(ctx, argv[0], &drs_ctx)) {
+               return -1;
+       }
+       info48 = &drs_ctx->info48;
+
+       /* check if target DC supports ExecuteKCC */
+       if (!(info48->supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE)) {
+               d_printf("%s does not support EXECUTE_KCC extension.\n", drs_ctx->dc_name);
+               goto failed;
+       }
+
+       /* gather some Site info */
+       if (!net_drs_kcc_site_info(drs_ctx, &site_name, &site_options)) {
+               goto failed;
+       }
+
+       d_printf("%s\n", site_name);
+       if (site_options) {
+               // TODO: print meaningfull site options here
+               d_printf("Current Site Options: 0x%X\n", site_options);
+       } else {
+               d_printf("Current Site Options: (none)\n");
+       }
+
+       /* execute KCC */
+       ZERO_STRUCT(req);
+       ZERO_STRUCT(kcc_req);
+       req.in.bind_handle = &drs_ctx->bind_handle;
+       req.in.level = 1;
+       req.in.req = &kcc_req;
+       status = dcerpc_drsuapi_DsExecuteKCC(drs_ctx->drs_pipe, drs_ctx, &req);
+       if (!NT_STATUS_IS_OK(status)) {
+               const char *errstr = nt_errstr(status);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
+                       errstr = dcerpc_errstr(drs_ctx, drs_ctx->drs_pipe->last_fault_code);
+               }
+               d_printf("dcerpc_drsuapi_DsExecuteKCC failed - %s.\n", errstr);
+               goto failed;
+       } else if (!W_ERROR_IS_OK(req.out.result)) {
+               d_printf("DsExecuteKCC failed - %s.\n", win_errstr(req.out.result));
+               goto failed;
+       }
+
+       d_printf("Consistency check on %s successful.\n", drs_ctx->dc_name);
+
+       talloc_free(drs_ctx);
+       return 0;
+
+failed:
+       talloc_free(drs_ctx);
+       return -1;
+}
+
+/**
+ * 'net drs kcc' usage
+ */
+int net_drs_kcc_usage(struct net_context *ctx, int argc, const char **argv)
+{
+       d_printf("net drs kcc <DC_NAME>\n");
+       return 0;
+}