• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/libnet/
1/*
2   Unix SMB/CIFS implementation.
3
4   Copyright (C) Stefan (metze) Metzmacher 2005
5   Copyright (C) Guenther Deschner 2008
6   Copyright (C) Michael Adam 2008
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*/
21
22
23#include "includes.h"
24#include "libnet/libnet.h"
25#include "../libcli/drsuapi/drsuapi.h"
26#include "../librpc/gen_ndr/cli_drsuapi.h"
27
28/****************************************************************
29****************************************************************/
30
31static int libnet_dssync_free_context(struct dssync_context *ctx)
32{
33	if (!ctx) {
34		return 0;
35	}
36
37	if (is_valid_policy_hnd(&ctx->bind_handle) && ctx->cli) {
38		rpccli_drsuapi_DsUnbind(ctx->cli, ctx, &ctx->bind_handle, NULL);
39	}
40
41	return 0;
42}
43
44/****************************************************************
45****************************************************************/
46
47NTSTATUS libnet_dssync_init_context(TALLOC_CTX *mem_ctx,
48				    struct dssync_context **ctx_p)
49{
50	struct dssync_context *ctx;
51
52	ctx = TALLOC_ZERO_P(mem_ctx, struct dssync_context);
53	NT_STATUS_HAVE_NO_MEMORY(ctx);
54
55	talloc_set_destructor(ctx, libnet_dssync_free_context);
56	ctx->clean_old_entries = false;
57
58	*ctx_p = ctx;
59
60	return NT_STATUS_OK;
61}
62
63/****************************************************************
64****************************************************************/
65
66static void parse_obj_identifier(struct drsuapi_DsReplicaObjectIdentifier *id,
67				 uint32_t *rid)
68{
69	if (!id || !rid) {
70		return;
71	}
72
73	*rid = 0;
74
75	if (id->sid.num_auths > 0) {
76		*rid = id->sid.sub_auths[id->sid.num_auths - 1];
77	}
78}
79
80/****************************************************************
81****************************************************************/
82
83static void libnet_dssync_decrypt_attributes(TALLOC_CTX *mem_ctx,
84					     DATA_BLOB *session_key,
85					     struct drsuapi_DsReplicaObjectListItemEx *cur)
86{
87	for (; cur; cur = cur->next_object) {
88
89		uint32_t i;
90		uint32_t rid = 0;
91
92		parse_obj_identifier(cur->object.identifier, &rid);
93
94		for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
95
96			struct drsuapi_DsReplicaAttribute *attr;
97
98			attr = &cur->object.attribute_ctr.attributes[i];
99
100			if (attr->value_ctr.num_values < 1) {
101				continue;
102			}
103
104			if (!attr->value_ctr.values[0].blob) {
105				continue;
106			}
107
108			drsuapi_decrypt_attribute(mem_ctx,
109						  session_key,
110						  rid,
111						  attr);
112		}
113	}
114}
115/****************************************************************
116****************************************************************/
117
118static NTSTATUS libnet_dssync_bind(TALLOC_CTX *mem_ctx,
119				   struct dssync_context *ctx)
120{
121	NTSTATUS status;
122	WERROR werr;
123
124	struct GUID bind_guid;
125	struct drsuapi_DsBindInfoCtr bind_info;
126	struct drsuapi_DsBindInfo28 info28;
127
128	ZERO_STRUCT(info28);
129
130	GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
131
132	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_BASE;
133	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
134	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
135	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
136	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
137	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
138	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
139	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
140	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
141	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
142	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
143	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
144	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
145	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
146	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
147	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
148	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
149	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
150	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
151	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
152	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
153	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
154	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
155	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
156	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
157	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
158	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
159	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
160	info28.site_guid		= GUID_zero();
161	info28.pid			= 508;
162	info28.repl_epoch		= 0;
163
164	bind_info.length = 28;
165	bind_info.info.info28 = info28;
166
167	status = rpccli_drsuapi_DsBind(ctx->cli, mem_ctx,
168				       &bind_guid,
169				       &bind_info,
170				       &ctx->bind_handle,
171				       &werr);
172
173	if (!NT_STATUS_IS_OK(status)) {
174		return status;
175	}
176
177	if (!W_ERROR_IS_OK(werr)) {
178		return werror_to_ntstatus(werr);
179	}
180
181	ZERO_STRUCT(ctx->remote_info28);
182	switch (bind_info.length) {
183	case 24: {
184		struct drsuapi_DsBindInfo24 *info24;
185		info24 = &bind_info.info.info24;
186		ctx->remote_info28.site_guid		= info24->site_guid;
187		ctx->remote_info28.supported_extensions	= info24->supported_extensions;
188		ctx->remote_info28.pid			= info24->pid;
189		ctx->remote_info28.repl_epoch		= 0;
190		break;
191	}
192	case 28:
193		ctx->remote_info28 = bind_info.info.info28;
194		break;
195	case 48: {
196		struct drsuapi_DsBindInfo48 *info48;
197		info48 = &bind_info.info.info48;
198		ctx->remote_info28.site_guid		= info48->site_guid;
199		ctx->remote_info28.supported_extensions	= info48->supported_extensions;
200		ctx->remote_info28.pid			= info48->pid;
201		ctx->remote_info28.repl_epoch		= info48->repl_epoch;
202		break;
203	}
204	default:
205		DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
206			  bind_info.length));
207		break;
208	}
209
210	return status;
211}
212
213/****************************************************************
214****************************************************************/
215
216static NTSTATUS libnet_dssync_lookup_nc(TALLOC_CTX *mem_ctx,
217					struct dssync_context *ctx)
218{
219	NTSTATUS status;
220	WERROR werr;
221	int32_t level = 1;
222	union drsuapi_DsNameRequest req;
223	int32_t level_out;
224	struct drsuapi_DsNameString names[1];
225	union drsuapi_DsNameCtr ctr;
226
227	names[0].str = talloc_asprintf(mem_ctx, "%s\\", ctx->domain_name);
228	NT_STATUS_HAVE_NO_MEMORY(names[0].str);
229
230	req.req1.codepage	= 1252; /* german */
231	req.req1.language	= 0x00000407; /* german */
232	req.req1.count		= 1;
233	req.req1.names		= names;
234	req.req1.format_flags	= DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
235	req.req1.format_offered	= DRSUAPI_DS_NAME_FORMAT_UNKNOWN;
236	req.req1.format_desired	= DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
237
238	status = rpccli_drsuapi_DsCrackNames(ctx->cli, mem_ctx,
239					     &ctx->bind_handle,
240					     level,
241					     &req,
242					     &level_out,
243					     &ctr,
244					     &werr);
245	if (!NT_STATUS_IS_OK(status)) {
246		ctx->error_message = talloc_asprintf(ctx,
247			"Failed to lookup DN for domain name: %s",
248			get_friendly_werror_msg(werr));
249		return status;
250	}
251
252	if (!W_ERROR_IS_OK(werr)) {
253		return werror_to_ntstatus(werr);
254	}
255
256	if (ctr.ctr1->count != 1) {
257		return NT_STATUS_UNSUCCESSFUL;
258	}
259
260	if (ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
261		return NT_STATUS_UNSUCCESSFUL;
262	}
263
264	ctx->nc_dn = talloc_strdup(mem_ctx, ctr.ctr1->array[0].result_name);
265	NT_STATUS_HAVE_NO_MEMORY(ctx->nc_dn);
266
267	if (!ctx->dns_domain_name) {
268		ctx->dns_domain_name = talloc_strdup_upper(mem_ctx,
269			ctr.ctr1->array[0].dns_domain_name);
270		NT_STATUS_HAVE_NO_MEMORY(ctx->dns_domain_name);
271	}
272
273	return NT_STATUS_OK;
274}
275
276/****************************************************************
277****************************************************************/
278
279static NTSTATUS libnet_dssync_init(TALLOC_CTX *mem_ctx,
280				   struct dssync_context *ctx)
281{
282	NTSTATUS status;
283
284	status = libnet_dssync_bind(mem_ctx, ctx);
285	if (!NT_STATUS_IS_OK(status)) {
286		return status;
287	}
288
289	if (!ctx->nc_dn) {
290		status = libnet_dssync_lookup_nc(mem_ctx, ctx);
291	}
292
293	return status;
294}
295
296/****************************************************************
297****************************************************************/
298
299static NTSTATUS libnet_dssync_build_request(TALLOC_CTX *mem_ctx,
300					    struct dssync_context *ctx,
301					    const char *dn,
302					    struct replUpToDateVectorBlob *utdv,
303					    int32_t *plevel,
304					    union drsuapi_DsGetNCChangesRequest *preq)
305{
306	NTSTATUS status;
307	uint32_t count;
308	int32_t level;
309	union drsuapi_DsGetNCChangesRequest req;
310	struct dom_sid null_sid;
311	enum drsuapi_DsExtendedOperation extended_op;
312	struct drsuapi_DsReplicaObjectIdentifier *nc = NULL;
313	struct drsuapi_DsReplicaCursorCtrEx *cursors = NULL;
314
315	uint32_t replica_flags	= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE |
316				  DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP |
317				  DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS |
318				  DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS |
319				  DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED;
320
321	ZERO_STRUCT(null_sid);
322	ZERO_STRUCT(req);
323
324	if (ctx->remote_info28.supported_extensions
325	    & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8)
326	{
327		level = 8;
328	} else {
329		level = 5;
330	}
331
332	nc = TALLOC_ZERO_P(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier);
333	if (!nc) {
334		status = NT_STATUS_NO_MEMORY;
335		goto fail;
336	}
337	nc->dn = dn;
338	nc->guid = GUID_zero();
339	nc->sid = null_sid;
340
341	if (!ctx->single_object_replication &&
342	    !ctx->force_full_replication && utdv)
343	{
344		cursors = TALLOC_ZERO_P(mem_ctx,
345					 struct drsuapi_DsReplicaCursorCtrEx);
346		if (!cursors) {
347			status = NT_STATUS_NO_MEMORY;
348			goto fail;
349		}
350
351		switch (utdv->version) {
352		case 1:
353			cursors->count = utdv->ctr.ctr1.count;
354			cursors->cursors = utdv->ctr.ctr1.cursors;
355			break;
356		case 2:
357			cursors->count = utdv->ctr.ctr2.count;
358			cursors->cursors = talloc_array(cursors,
359						struct drsuapi_DsReplicaCursor,
360						cursors->count);
361			if (!cursors->cursors) {
362				status = NT_STATUS_NO_MEMORY;
363				goto fail;
364			}
365			for (count = 0; count < cursors->count; count++) {
366				cursors->cursors[count].source_dsa_invocation_id =
367					utdv->ctr.ctr2.cursors[count].source_dsa_invocation_id;
368				cursors->cursors[count].highest_usn =
369					utdv->ctr.ctr2.cursors[count].highest_usn;
370			}
371			break;
372		}
373	}
374
375	if (ctx->single_object_replication) {
376		extended_op = DRSUAPI_EXOP_REPL_OBJ;
377	} else {
378		extended_op = DRSUAPI_EXOP_NONE;
379	}
380
381	if (level == 8) {
382		req.req8.naming_context		= nc;
383		req.req8.replica_flags		= replica_flags;
384		req.req8.max_object_count	= 402;
385		req.req8.max_ndr_size		= 402116;
386		req.req8.uptodateness_vector	= cursors;
387		req.req8.extended_op		= extended_op;
388	} else if (level == 5) {
389		req.req5.naming_context		= nc;
390		req.req5.replica_flags		= replica_flags;
391		req.req5.max_object_count	= 402;
392		req.req5.max_ndr_size		= 402116;
393		req.req5.uptodateness_vector	= cursors;
394		req.req5.extended_op		= extended_op;
395	} else {
396		status = NT_STATUS_INVALID_PARAMETER;
397		goto fail;
398	}
399
400	if (plevel) {
401		*plevel = level;
402	}
403
404	if (preq) {
405		*preq = req;
406	}
407
408	return NT_STATUS_OK;
409
410fail:
411	TALLOC_FREE(nc);
412	TALLOC_FREE(cursors);
413	return status;
414}
415
416static NTSTATUS libnet_dssync_getncchanges(TALLOC_CTX *mem_ctx,
417					   struct dssync_context *ctx,
418					   int32_t level,
419					   union drsuapi_DsGetNCChangesRequest *req,
420					   struct replUpToDateVectorBlob **pnew_utdv)
421{
422	NTSTATUS status;
423	WERROR werr;
424	union drsuapi_DsGetNCChangesCtr ctr;
425	struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
426	struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
427	struct replUpToDateVectorBlob *new_utdv = NULL;
428	int32_t level_out = 0;
429	int32_t out_level = 0;
430	int y;
431	bool last_query;
432
433	if (!ctx->single_object_replication) {
434		new_utdv = TALLOC_ZERO_P(mem_ctx, struct replUpToDateVectorBlob);
435		if (!new_utdv) {
436			status = NT_STATUS_NO_MEMORY;
437			goto out;
438		}
439	}
440
441	for (y=0, last_query = false; !last_query; y++) {
442		struct drsuapi_DsReplicaObjectListItemEx *first_object = NULL;
443		struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr = NULL;
444
445		if (level == 8) {
446			DEBUG(1,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
447				(long long)req->req8.highwatermark.tmp_highest_usn,
448				(long long)req->req8.highwatermark.highest_usn));
449		} else if (level == 5) {
450			DEBUG(1,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
451				(long long)req->req5.highwatermark.tmp_highest_usn,
452				(long long)req->req5.highwatermark.highest_usn));
453		}
454
455		status = rpccli_drsuapi_DsGetNCChanges(ctx->cli, mem_ctx,
456						       &ctx->bind_handle,
457						       level,
458						       req,
459						       &level_out,
460						       &ctr,
461						       &werr);
462		if (!NT_STATUS_IS_OK(status)) {
463			ctx->error_message = talloc_asprintf(ctx,
464				"Failed to get NC Changes: %s",
465				get_friendly_werror_msg(werr));
466			goto out;
467		}
468
469		if (!W_ERROR_IS_OK(werr)) {
470			status = werror_to_ntstatus(werr);
471			goto out;
472		}
473
474		if (level_out == 1) {
475			out_level = 1;
476			ctr1 = &ctr.ctr1;
477		} else if (level_out == 2 && ctr.ctr2.mszip1.ts) {
478			out_level = 1;
479			ctr1 = &ctr.ctr2.mszip1.ts->ctr1;
480		} else if (level_out == 6) {
481			out_level = 6;
482			ctr6 = &ctr.ctr6;
483		} else if (level_out == 7
484			   && ctr.ctr7.level == 6
485			   && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP
486			   && ctr.ctr7.ctr.mszip6.ts) {
487			out_level = 6;
488			ctr6 = &ctr.ctr7.ctr.mszip6.ts->ctr6;
489		} else if (level_out == 7
490			   && ctr.ctr7.level == 6
491			   && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS
492			   && ctr.ctr7.ctr.xpress6.ts) {
493			out_level = 6;
494			ctr6 = &ctr.ctr7.ctr.xpress6.ts->ctr6;
495		}
496
497		if (out_level == 1) {
498			DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
499				(long long)ctr1->new_highwatermark.tmp_highest_usn,
500				(long long)ctr1->new_highwatermark.highest_usn));
501
502			first_object = ctr1->first_object;
503			mapping_ctr = &ctr1->mapping_ctr;
504
505			if (ctr1->more_data) {
506				req->req5.highwatermark = ctr1->new_highwatermark;
507			} else {
508				last_query = true;
509				if (ctr1->uptodateness_vector &&
510				    !ctx->single_object_replication)
511				{
512					new_utdv->version = 1;
513					new_utdv->ctr.ctr1.count =
514						ctr1->uptodateness_vector->count;
515					new_utdv->ctr.ctr1.cursors =
516						ctr1->uptodateness_vector->cursors;
517				}
518			}
519		} else if (out_level == 6) {
520			DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
521				(long long)ctr6->new_highwatermark.tmp_highest_usn,
522				(long long)ctr6->new_highwatermark.highest_usn));
523
524			first_object = ctr6->first_object;
525			mapping_ctr = &ctr6->mapping_ctr;
526
527			if (ctr6->more_data) {
528				req->req8.highwatermark = ctr6->new_highwatermark;
529			} else {
530				last_query = true;
531				if (ctr6->uptodateness_vector &&
532				    !ctx->single_object_replication)
533				{
534					new_utdv->version = 2;
535					new_utdv->ctr.ctr2.count =
536						ctr6->uptodateness_vector->count;
537					new_utdv->ctr.ctr2.cursors =
538						ctr6->uptodateness_vector->cursors;
539				}
540			}
541		}
542
543		status = cli_get_session_key(mem_ctx, ctx->cli, &ctx->session_key);
544		if (!NT_STATUS_IS_OK(status)) {
545			ctx->error_message = talloc_asprintf(ctx,
546				"Failed to get Session Key: %s",
547				nt_errstr(status));
548			goto out;
549		}
550
551		libnet_dssync_decrypt_attributes(mem_ctx,
552						 &ctx->session_key,
553						 first_object);
554
555		if (ctx->ops->process_objects) {
556			status = ctx->ops->process_objects(ctx, mem_ctx,
557							   first_object,
558							   mapping_ctr);
559			if (!NT_STATUS_IS_OK(status)) {
560				ctx->error_message = talloc_asprintf(ctx,
561					"Failed to call processing function: %s",
562					nt_errstr(status));
563				goto out;
564			}
565		}
566	}
567
568	*pnew_utdv = new_utdv;
569
570out:
571	return status;
572}
573
574static NTSTATUS libnet_dssync_process(TALLOC_CTX *mem_ctx,
575				      struct dssync_context *ctx)
576{
577	NTSTATUS status;
578
579	int32_t level = 0;
580	union drsuapi_DsGetNCChangesRequest req;
581	struct replUpToDateVectorBlob *old_utdv = NULL;
582	struct replUpToDateVectorBlob *pnew_utdv = NULL;
583	const char **dns;
584	uint32_t dn_count;
585	uint32_t count;
586
587	if (ctx->ops->startup) {
588		status = ctx->ops->startup(ctx, mem_ctx, &old_utdv);
589		if (!NT_STATUS_IS_OK(status)) {
590			ctx->error_message = talloc_asprintf(ctx,
591				"Failed to call startup operation: %s",
592				nt_errstr(status));
593			goto out;
594		}
595	}
596
597	if (ctx->single_object_replication && ctx->object_dns) {
598		dns = ctx->object_dns;
599		dn_count = ctx->object_count;
600	} else {
601		dns = &ctx->nc_dn;
602		dn_count = 1;
603	}
604
605	status = NT_STATUS_OK;
606
607	for (count=0; count < dn_count; count++) {
608		status = libnet_dssync_build_request(mem_ctx, ctx,
609						     dns[count],
610						     old_utdv, &level,
611						     &req);
612		if (!NT_STATUS_IS_OK(status)) {
613			goto out;
614		}
615
616		status = libnet_dssync_getncchanges(mem_ctx, ctx, level, &req,
617						    &pnew_utdv);
618		if (!NT_STATUS_IS_OK(status)) {
619			ctx->error_message = talloc_asprintf(ctx,
620				"Failed to call DsGetNCCHanges: %s",
621				nt_errstr(status));
622			goto out;
623		}
624	}
625
626	if (ctx->ops->finish) {
627		status = ctx->ops->finish(ctx, mem_ctx, pnew_utdv);
628		if (!NT_STATUS_IS_OK(status)) {
629			ctx->error_message = talloc_asprintf(ctx,
630				"Failed to call finishing operation: %s",
631				nt_errstr(status));
632			goto out;
633		}
634	}
635
636 out:
637	return status;
638}
639
640/****************************************************************
641****************************************************************/
642
643NTSTATUS libnet_dssync(TALLOC_CTX *mem_ctx,
644		       struct dssync_context *ctx)
645{
646	NTSTATUS status;
647	TALLOC_CTX *tmp_ctx;
648
649	tmp_ctx = talloc_new(mem_ctx);
650	if (!tmp_ctx) {
651		return NT_STATUS_NO_MEMORY;
652	}
653
654	status = libnet_dssync_init(tmp_ctx, ctx);
655	if (!NT_STATUS_IS_OK(status)) {
656		goto out;
657	}
658
659	status = libnet_dssync_process(tmp_ctx, ctx);
660	if (!NT_STATUS_IS_OK(status)) {
661		goto out;
662	}
663
664 out:
665	TALLOC_FREE(tmp_ctx);
666	return status;
667}
668
669