1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-08 04:58:40 +03:00

s4/drs_util: 'net drs replicate' command implementation

This commit is contained in:
Kamen Mazdrashki 2010-02-13 03:27:27 +02:00 committed by Anatoliy Atanasov
parent ff94094dfa
commit 3f5e9e9974
3 changed files with 254 additions and 4 deletions

View File

@ -15,7 +15,8 @@ PRIVATE_DEPENDENCIES = \
net_drs_OBJ_FILES = $(addprefix $(utilssrcdir)/net/drs/, \
net_drs.o \
net_drs_bind.o \
net_drs_kcc.o)
net_drs_kcc.o \
net_drs_replicate.o)
$(eval $(call proto_header_template,$(utilssrcdir)/net/drs/net_drs_proto.h,$(net_drs_OBJ_FILES:.o=.c)))

View File

@ -34,7 +34,9 @@
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 },
net_drs_kcc_cmd, net_drs_kcc_usage },
{ "replicate", "Triggers replication event for the specified naming context between the source and destination domain controllers.\n",
net_drs_replicate_cmd, net_drs_replicate_usage },
{ NULL, NULL }
};
@ -54,8 +56,9 @@ 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\n");
d_printf(" kcc - Forces the KCC to recalculate replication topology for a specified domain controller\n");
d_printf(" bind - Display DC replication features\n");
d_printf(" kcc - Forces the KCC to recalculate replication topology for a specified domain controller\n");
d_printf(" replicate - Triggers replication event for the specified naming context between the source and destination domain controllers.\n");
return 0;
}

View File

@ -0,0 +1,246 @@
/*
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"
#include "dsdb/samdb/samdb.h"
/**
* Figure out what is the NDTS Settings objectGUID
* when DC_NAME is given
*/
static struct ldb_dn *
net_drs_server_dn_from_dc_name(struct net_drs_context *drs_ctx,
const char *dc_name)
{
int ldb_err;
struct ldb_dn *dn;
struct ldb_dn *server_dn = NULL;
struct ldb_result *ldb_res;
const char *filter;
static const char *attrs[] = {
"objectGUID",
"name",
"dNSHostName",
NULL
};
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_new(drs_ctx);
/* Make DN for Sites container */
dn = ldb_msg_find_attr_as_dn(drs_ctx->ldap.ldb, mem_ctx, drs_ctx->ldap.rootdse, "dsServiceName");
NET_DRS_CHECK_GOTO(dn != NULL, failed, "RootDSE doesn't have dsServiceName!?\n");
if (!ldb_dn_remove_child_components(dn, 4)) {
d_printf("Failed to make DN for Sites container.\n");
goto failed;
}
/* search for Server in Sites container */
ldb_err = ldb_search(drs_ctx->ldap.ldb, mem_ctx, &ldb_res,
dn, LDB_SCOPE_SUBTREE, attrs,
"(&(objectCategory=server)(|(name=%1$s)(dNSHostName=%1$s)))",
dc_name);
if (ldb_err != LDB_SUCCESS) {
d_printf("ldb_seach() failed with err: %d (%s); filter: (%s)",
ldb_err, ldb_errstring(drs_ctx->ldap.ldb), filter);
goto failed;
}
if (ldb_res->count != 1) {
d_printf("ldb_search() should return exactly one record!");
goto failed;
}
server_dn = talloc_steal(drs_ctx, ldb_res->msgs[0]->dn);
failed:
talloc_free(mem_ctx);
return server_dn;
}
/**
* Figure out what is the NDTS Settings objectGUID
* when DC_NAME is given
*/
static bool net_drs_ntds_guid_from_dc_name(struct net_drs_context *drs_ctx,
const char *dc_name,
struct GUID *_ntds_guid)
{
int ldb_err;
struct ldb_dn *server_dn;
struct ldb_result *ldb_res;
const char *filter;
static const char *attrs[] = {
"objectGUID",
"msDS-portLDAP",
"name",
"objectCategory",
NULL
};
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_new(drs_ctx);
/* resolve Server_DN for dc_name */
server_dn = net_drs_server_dn_from_dc_name(drs_ctx, dc_name);
if (!server_dn) {
d_printf("DSA object for %s could not be found.\n", dc_name);
goto failed;
}
/* move server_dn mem to local context */
server_dn = talloc_steal(mem_ctx, server_dn);
/* search ntdsDsa object under Server container */
ldb_err = ldb_search(drs_ctx->ldap.ldb, mem_ctx, &ldb_res,
server_dn, LDB_SCOPE_ONELEVEL, attrs,
"%s", "(|(objectCategory=nTDSDSA)(objectCategory=nTDSDSARO))");
if (ldb_err != LDB_SUCCESS) {
d_printf("ldb_seach() failed with err: %d (%s); filter: (%s)",
ldb_err, ldb_errstring(drs_ctx->ldap.ldb), filter);
goto failed;
}
if (ldb_res->count != 1) {
d_printf("ldb_search() should return exactly one record!");
goto failed;
}
*_ntds_guid = samdb_result_guid(ldb_res->msgs[0], "objectGUID");
talloc_free(mem_ctx);
return true;
failed:
talloc_free(mem_ctx);
return false;
}
/**
* Sends DsReplicaSync to dc_name_dest to
* replicate naming context nc_dn_str from
* server with ntds_guid_src GUID
*/
static bool net_drs_replicate_sync_nc(struct net_drs_context *drs_ctx,
struct GUID ntds_guid_src,
const char *nc_dn_str,
uint32_t options)
{
NTSTATUS status;
struct net_drs_connection *drs_conn;
struct drsuapi_DsReplicaSync req;
union drsuapi_DsReplicaSyncRequest sync_req;
struct drsuapi_DsReplicaObjectIdentifier nc;
/* use already opened connection */
drs_conn = drs_ctx->drs_conn;
/* construct naming context object */
ZERO_STRUCT(nc);
nc.dn = nc_dn_str;
/* construct request object for DsReplicaSync */
req.in.bind_handle = &drs_conn->bind_handle;
req.in.level = 1;
req.in.req = &sync_req;
req.in.req->req1.naming_context = &nc;
req.in.req->req1.options = options;
req.in.req->req1.source_dsa_dns = NULL;
req.in.req->req1.source_dsa_guid = ntds_guid_src;
/* send DsReplicaSync request */
status = dcerpc_drsuapi_DsReplicaSync(drs_conn->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_conn->drs_pipe->last_fault_code);
}
d_printf("DsReplicaSync failed - %s.\n", errstr);
return false;
} else if (!W_ERROR_IS_OK(req.out.result)) {
d_printf("DsReplicaSync failed - %s.\n", win_errstr(req.out.result));
return false;
}
return true;
}
/**
* 'net drs replicate' command entry point
*/
int net_drs_replicate_cmd(struct net_context *ctx, int argc, const char **argv)
{
bool bret;
struct net_drs_context *drs_ctx;
struct GUID ntds_guid_src;
const char *dc_name_dest;
const char *dc_name_src;
const char *nc_dn_str;
/* only one arg expected */
if (argc != 3) {
return net_drs_replicate_usage(ctx, argc, argv);
}
dc_name_dest = argv[0];
dc_name_src = argv[1];
nc_dn_str = argv[2];
if (!net_drs_create_context(ctx, dc_name_dest, &drs_ctx)) {
return -1;
}
/* Resolve source DC_NAME to its NDTS Settings GUID */
if (!net_drs_ntds_guid_from_dc_name(drs_ctx, dc_name_src, &ntds_guid_src)) {
d_printf("Error: DSA object for %s could not be found.\n", dc_name_src);
goto failed;
}
/* Synchronize given Naming Context */
bret = net_drs_replicate_sync_nc(drs_ctx,
ntds_guid_src, nc_dn_str,
DRSUAPI_DRS_WRIT_REP);
if (!bret) {
goto failed;
}
d_printf("Replicate from %s to %s was successful.\n", dc_name_src, drs_ctx->dc_name);
talloc_free(drs_ctx);
return 0;
failed:
d_printf("Replicate terminated with errors.\n");
talloc_free(drs_ctx);
return -1;
}
/**
* 'net drs replicate' usage
*/
int net_drs_replicate_usage(struct net_context *ctx, int argc, const char **argv)
{
d_printf("net drs replicate <Dest_DC_NAME> <Src_DC_NAME> <Naming Context>\n");
return 0;
}