diff options
-rw-r--r-- | source3/Makefile.in | 1 | ||||
-rw-r--r-- | source3/libnet/libnet.h | 1 | ||||
-rw-r--r-- | source3/libnet/libnet_dssync.c | 353 | ||||
-rw-r--r-- | source3/libnet/libnet_dssync.h | 37 | ||||
-rw-r--r-- | source3/libnet/libnet_proto.h | 8 |
5 files changed, 400 insertions, 0 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 4f680cc56f..a45c67f860 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -897,6 +897,7 @@ LIBNET_OBJ = libnet/libnet_join.o \ libnet/libnet_samsync_passdb.o \ libnet/libnet_samsync_display.o \ libnet/libnet_samsync_keytab.o \ + libnet/libnet_dssync.o \ librpc/gen_ndr/ndr_libnet_join.o NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_help.o \ diff --git a/source3/libnet/libnet.h b/source3/libnet/libnet.h index 2b5e60bf14..ca393c4393 100644 --- a/source3/libnet/libnet.h +++ b/source3/libnet/libnet.h @@ -21,6 +21,7 @@ #define __LIBNET_H__ #include "libnet/libnet_samsync.h" +#include "libnet/libnet_dssync.h" #include "librpc/gen_ndr/libnet_join.h" #include "libnet/libnet_proto.h" diff --git a/source3/libnet/libnet_dssync.c b/source3/libnet/libnet_dssync.c new file mode 100644 index 0000000000..63a5c8bef1 --- /dev/null +++ b/source3/libnet/libnet_dssync.c @@ -0,0 +1,353 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Stefan (metze) Metzmacher 2005 + Copyright (C) Guenther Deschner 2008 + + 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 "libnet/libnet_dssync.h" + +/**************************************************************** +****************************************************************/ + +static int libnet_dssync_free_context(struct dssync_context *ctx) +{ + if (!ctx) { + return 0; + } + + if (is_valid_policy_hnd(&ctx->bind_handle) && ctx->cli) { + rpccli_drsuapi_DsUnbind(ctx->cli, ctx, &ctx->bind_handle, NULL); + } + + return 0; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS libnet_dssync_init_context(TALLOC_CTX *mem_ctx, + struct dssync_context **ctx_p) +{ + struct dssync_context *ctx; + + ctx = TALLOC_ZERO_P(mem_ctx, struct dssync_context); + NT_STATUS_HAVE_NO_MEMORY(ctx); + + talloc_set_destructor(ctx, libnet_dssync_free_context); + + *ctx_p = ctx; + + return NT_STATUS_OK; +} + +/**************************************************************** +****************************************************************/ + +static NTSTATUS libnet_dssync_bind(TALLOC_CTX *mem_ctx, + struct dssync_context *ctx) +{ + NTSTATUS status; + WERROR werr; + + struct GUID bind_guid; + struct drsuapi_DsBindInfoCtr bind_info; + struct drsuapi_DsBindInfo28 info28; + + ZERO_STRUCT(info28); + + GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid); + + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT; + info28.site_guid = GUID_zero(); + info28.u1 = 508; + info28.repl_epoch = 0; + + bind_info.length = 28; + bind_info.info.info28 = info28; + + status = rpccli_drsuapi_DsBind(ctx->cli, mem_ctx, + &bind_guid, + &bind_info, + &ctx->bind_handle, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!W_ERROR_IS_OK(werr)) { + return werror_to_ntstatus(werr); + } + + return status; +} + +/**************************************************************** +****************************************************************/ + +static NTSTATUS libnet_dssync_lookup_nc(TALLOC_CTX *mem_ctx, + struct dssync_context *ctx) +{ + NTSTATUS status; + WERROR werr; + int32_t level = 1; + union drsuapi_DsNameRequest req; + int32_t level_out; + struct drsuapi_DsNameString names[1]; + union drsuapi_DsNameCtr ctr; + + names[0].str = talloc_asprintf(mem_ctx, "%s\\", ctx->domain_name); + NT_STATUS_HAVE_NO_MEMORY(names[0].str); + + req.req1.codepage = 1252; /* german */ + req.req1.language = 0x00000407; /* german */ + req.req1.count = 1; + req.req1.names = names; + req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; + req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_UKNOWN; + req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; + + status = rpccli_drsuapi_DsCrackNames(ctx->cli, mem_ctx, + &ctx->bind_handle, + level, + &req, + &level_out, + &ctr, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!W_ERROR_IS_OK(werr)) { + return werror_to_ntstatus(werr); + } + + if (ctr.ctr1->count != 1) { + return NT_STATUS_UNSUCCESSFUL; + } + + if (ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { + return NT_STATUS_UNSUCCESSFUL; + } + + ctx->nc_dn = talloc_strdup(mem_ctx, ctr.ctr1->array[0].result_name); + NT_STATUS_HAVE_NO_MEMORY(ctx->nc_dn); + + return NT_STATUS_OK; +} + +/**************************************************************** +****************************************************************/ + +static NTSTATUS libnet_dssync_init(TALLOC_CTX *mem_ctx, + struct dssync_context *ctx) +{ + NTSTATUS status; + + status = libnet_dssync_bind(mem_ctx, ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!ctx->nc_dn) { + status = libnet_dssync_lookup_nc(mem_ctx, ctx); + } + + return status; +} + +/**************************************************************** +****************************************************************/ + +static NTSTATUS libnet_dssync_process(TALLOC_CTX *mem_ctx, + struct dssync_context *ctx) +{ + NTSTATUS status; + WERROR werr; + + int32_t level = 8; + int32_t level_out = 0; + union drsuapi_DsGetNCChangesRequest req; + union drsuapi_DsGetNCChangesCtr ctr; + struct drsuapi_DsReplicaObjectIdentifier nc; + struct dom_sid null_sid; + + struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL; + struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL; + int32_t out_level = 0; + int y; + + ZERO_STRUCT(null_sid); + ZERO_STRUCT(req); + + nc.dn = ctx->nc_dn; + nc.guid = GUID_zero(); + nc.sid = null_sid; + + req.req8.naming_context = &nc; + req.req8.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE | + DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP | + DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS | + DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS | + DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED; + req.req8.max_object_count = 402; + req.req8.max_ndr_size = 402116; + + for (y=0; ;y++) { + + if (level == 8) { + DEBUG(1,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y, + (long long)req.req8.highwatermark.tmp_highest_usn, + (long long)req.req8.highwatermark.highest_usn)); + } + + status = rpccli_drsuapi_DsGetNCChanges(ctx->cli, mem_ctx, + &ctx->bind_handle, + level, + &req, + &level_out, + &ctr, + &werr); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(status); + goto out; + } + + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + + if (level_out == 1) { + out_level = 1; + ctr1 = &ctr.ctr1; + } else if (level_out == 2) { + out_level = 1; + ctr1 = ctr.ctr2.ctr.mszip1.ctr1; + } + + status = cli_get_session_key(ctx->cli, &ctx->session_key); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (out_level == 1) { + DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y, + (long long)ctr1->new_highwatermark.tmp_highest_usn, + (long long)ctr1->new_highwatermark.highest_usn)); + + if (ctx->processing_fn) { + status = ctx->processing_fn(mem_ctx, + ctr1->first_object, + ctx); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + } + + if (ctr1->new_highwatermark.tmp_highest_usn > ctr1->new_highwatermark.highest_usn) { + req.req5.highwatermark = ctr1->new_highwatermark; + continue; + } + } + + if (level_out == 6) { + out_level = 6; + ctr6 = &ctr.ctr6; + } else if (level_out == 7 + && ctr.ctr7.level == 6 + && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) { + out_level = 6; + ctr6 = ctr.ctr7.ctr.mszip6.ctr6; + } + + if (out_level == 6) { + DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y, + (long long)ctr6->new_highwatermark.tmp_highest_usn, + (long long)ctr6->new_highwatermark.highest_usn)); + + if (ctx->processing_fn) { + status = ctx->processing_fn(mem_ctx, + ctr6->first_object, + ctx); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + } + + if (ctr6->new_highwatermark.tmp_highest_usn > ctr6->new_highwatermark.highest_usn) { + req.req8.highwatermark = ctr6->new_highwatermark; + continue; + } + } + + break; + } + + out: + return status; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS libnet_dssync(TALLOC_CTX *mem_ctx, + struct dssync_context *ctx) +{ + NTSTATUS status; + + status = libnet_dssync_init(mem_ctx, ctx); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + status = libnet_dssync_process(mem_ctx, ctx); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + out: + return status; +} diff --git a/source3/libnet/libnet_dssync.h b/source3/libnet/libnet_dssync.h new file mode 100644 index 0000000000..8c26562845 --- /dev/null +++ b/source3/libnet/libnet_dssync.h @@ -0,0 +1,37 @@ +/* + * Unix SMB/CIFS implementation. + * libnet Support + * Copyright (C) Guenther Deschner 2008 + * + * 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/>. + */ + +struct dssync_context; + +typedef NTSTATUS (*dssync_processing_fn_t)(TALLOC_CTX *, + struct drsuapi_DsReplicaObjectListItemEx *, + struct dssync_context *ctx); + +struct dssync_context { + const char *domain_name; + struct rpc_pipe_client *cli; + const char *nc_dn; + struct policy_handle bind_handle; + DATA_BLOB session_key; + + dssync_processing_fn_t processing_fn; + + char *result_message; + char *error_message; +}; diff --git a/source3/libnet/libnet_proto.h b/source3/libnet/libnet_proto.h index 2440cd3c7f..720b52bcc7 100644 --- a/source3/libnet/libnet_proto.h +++ b/source3/libnet/libnet_proto.h @@ -53,4 +53,12 @@ NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id, NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx, struct lsa_BinaryString *r, struct netr_AcctLockStr **str_p); + +/* The following definitions come from libnet/libnet_dssync.c */ + +NTSTATUS libnet_dssync_init_context(TALLOC_CTX *mem_ctx, + struct dssync_context **ctx_p); +NTSTATUS libnet_dssync(TALLOC_CTX *mem_ctx, + struct dssync_context *ctx); + #endif /* _LIBNET_PROTO_H_ */ |