2 Unix SMB/CIFS implementation.
4 DsGetNCChanges replication test
6 Copyright (C) Stefan (metze) Metzmacher 2005
7 Copyright (C) Brad Henry 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "lib/cmdline/popt_common.h"
25 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
26 #include "librpc/gen_ndr/ndr_drsblobs.h"
27 #include "libcli/cldap/cldap.h"
28 #include "torture/torture.h"
29 #include "../libcli/drsuapi/drsuapi.h"
30 #include "auth/gensec/gensec.h"
31 #include "param/param.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "lib/ldb_wrap.h"
34 #include "torture/rpc/rpc.h"
35 #include "torture/drs/proto.h"
36 #include "lib/tsocket/tsocket.h"
37 #include "libcli/resolve/resolve.h"
39 struct DsSyncBindInfo
{
40 struct dcerpc_pipe
*drs_pipe
;
41 struct dcerpc_binding_handle
*drs_handle
;
42 struct drsuapi_DsBind req
;
43 struct GUID bind_guid
;
44 struct drsuapi_DsBindInfoCtr our_bind_info_ctr
;
45 struct drsuapi_DsBindInfo28 our_bind_info28
;
46 struct drsuapi_DsBindInfo28 peer_bind_info28
;
47 struct policy_handle bind_handle
;
50 struct DsSyncLDAPInfo
{
51 struct ldb_context
*ldb
;
55 struct dcerpc_binding
*drsuapi_binding
;
58 const char *site_name
;
59 const char *dest_address
;
60 const char *domain_dn
;
62 /* what we need to do as 'Administrator' */
64 struct cli_credentials
*credentials
;
65 struct DsSyncBindInfo drsuapi
;
66 struct DsSyncLDAPInfo ldap
;
69 /* what we need to do as the new dc machine account */
71 struct cli_credentials
*credentials
;
72 struct DsSyncBindInfo drsuapi
;
73 struct drsuapi_DsGetDCInfo2 dc_info2
;
74 struct GUID invocation_id
;
75 struct GUID object_guid
;
78 /* info about the old dc */
80 struct drsuapi_DsGetDomainControllerInfo dc_info
;
84 static struct DsSyncTest
*test_create_context(struct torture_context
*tctx
)
87 struct DsSyncTest
*ctx
;
88 struct drsuapi_DsBindInfo28
*our_bind_info28
;
89 struct drsuapi_DsBindInfoCtr
*our_bind_info_ctr
;
90 const char *binding
= torture_setting_string(tctx
, "binding", NULL
);
93 ctx
= talloc_zero(tctx
, struct DsSyncTest
);
94 if (!ctx
) return NULL
;
96 status
= dcerpc_parse_binding(ctx
, binding
, &ctx
->drsuapi_binding
);
97 if (!NT_STATUS_IS_OK(status
)) {
98 printf("Bad binding string %s\n", binding
);
101 ctx
->drsuapi_binding
->flags
|= DCERPC_SIGN
| DCERPC_SEAL
;
103 ctx
->ldap_url
= talloc_asprintf(ctx
, "ldap://%s", ctx
->drsuapi_binding
->host
);
105 make_nbt_name_server(&name
, ctx
->drsuapi_binding
->host
);
107 /* do an initial name resolution to find its IP */
108 status
= resolve_name(lp_resolve_context(tctx
->lp_ctx
), &name
, tctx
,
109 &ctx
->dest_address
, tctx
->ev
);
110 if (!NT_STATUS_IS_OK(status
)) {
111 printf("Failed to resolve %s - %s\n",
112 name
.name
, nt_errstr(status
));
117 ctx
->admin
.credentials
= cmdline_credentials
;
119 our_bind_info28
= &ctx
->admin
.drsuapi
.our_bind_info28
;
120 our_bind_info28
->supported_extensions
= 0xFFFFFFFF;
121 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
;
122 our_bind_info28
->site_guid
= GUID_zero();
123 our_bind_info28
->pid
= 0;
124 our_bind_info28
->repl_epoch
= 1;
126 our_bind_info_ctr
= &ctx
->admin
.drsuapi
.our_bind_info_ctr
;
127 our_bind_info_ctr
->length
= 28;
128 our_bind_info_ctr
->info
.info28
= *our_bind_info28
;
130 GUID_from_string(DRSUAPI_DS_BIND_GUID
, &ctx
->admin
.drsuapi
.bind_guid
);
132 ctx
->admin
.drsuapi
.req
.in
.bind_guid
= &ctx
->admin
.drsuapi
.bind_guid
;
133 ctx
->admin
.drsuapi
.req
.in
.bind_info
= our_bind_info_ctr
;
134 ctx
->admin
.drsuapi
.req
.out
.bind_handle
= &ctx
->admin
.drsuapi
.bind_handle
;
137 ctx
->new_dc
.credentials
= cmdline_credentials
;
139 our_bind_info28
= &ctx
->new_dc
.drsuapi
.our_bind_info28
;
140 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_BASE
;
141 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION
;
142 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI
;
143 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2
;
144 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS
;
145 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1
;
146 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION
;
147 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE
;
148 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2
;
149 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION
;
150 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2
;
151 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD
;
152 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND
;
153 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO
;
154 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION
;
155 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01
;
156 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP
;
157 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY
;
158 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3
;
159 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2
;
160 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6
;
161 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS
;
162 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
;
163 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5
;
164 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6
;
165 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
;
166 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7
;
167 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT
;
168 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "xpress", false)) {
169 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS
;
171 our_bind_info28
->site_guid
= GUID_zero();
172 our_bind_info28
->pid
= 0;
173 our_bind_info28
->repl_epoch
= 0;
175 our_bind_info_ctr
= &ctx
->new_dc
.drsuapi
.our_bind_info_ctr
;
176 our_bind_info_ctr
->length
= 28;
177 our_bind_info_ctr
->info
.info28
= *our_bind_info28
;
179 GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3
, &ctx
->new_dc
.drsuapi
.bind_guid
);
181 ctx
->new_dc
.drsuapi
.req
.in
.bind_guid
= &ctx
->new_dc
.drsuapi
.bind_guid
;
182 ctx
->new_dc
.drsuapi
.req
.in
.bind_info
= our_bind_info_ctr
;
183 ctx
->new_dc
.drsuapi
.req
.out
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
185 ctx
->new_dc
.invocation_id
= ctx
->new_dc
.drsuapi
.bind_guid
;
192 static bool _test_DsBind(struct torture_context
*tctx
,
193 struct DsSyncTest
*ctx
, struct cli_credentials
*credentials
, struct DsSyncBindInfo
*b
)
198 status
= dcerpc_pipe_connect_b(ctx
,
199 &b
->drs_pipe
, ctx
->drsuapi_binding
,
201 credentials
, tctx
->ev
, tctx
->lp_ctx
);
203 if (!NT_STATUS_IS_OK(status
)) {
204 printf("Failed to connect to server as a BDC: %s\n", nt_errstr(status
));
207 b
->drs_handle
= b
->drs_pipe
->binding_handle
;
209 status
= dcerpc_drsuapi_DsBind_r(b
->drs_handle
, ctx
, &b
->req
);
210 if (!NT_STATUS_IS_OK(status
)) {
211 const char *errstr
= nt_errstr(status
);
212 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
213 errstr
= dcerpc_errstr(ctx
, b
->drs_pipe
->last_fault_code
);
215 printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr
);
217 } else if (!W_ERROR_IS_OK(b
->req
.out
.result
)) {
218 printf("DsBind failed - %s\n", win_errstr(b
->req
.out
.result
));
222 ZERO_STRUCT(b
->peer_bind_info28
);
223 if (b
->req
.out
.bind_info
) {
224 switch (b
->req
.out
.bind_info
->length
) {
226 struct drsuapi_DsBindInfo24
*info24
;
227 info24
= &b
->req
.out
.bind_info
->info
.info24
;
228 b
->peer_bind_info28
.supported_extensions
= info24
->supported_extensions
;
229 b
->peer_bind_info28
.site_guid
= info24
->site_guid
;
230 b
->peer_bind_info28
.pid
= info24
->pid
;
231 b
->peer_bind_info28
.repl_epoch
= 0;
235 struct drsuapi_DsBindInfo48
*info48
;
236 info48
= &b
->req
.out
.bind_info
->info
.info48
;
237 b
->peer_bind_info28
.supported_extensions
= info48
->supported_extensions
;
238 b
->peer_bind_info28
.site_guid
= info48
->site_guid
;
239 b
->peer_bind_info28
.pid
= info48
->pid
;
240 b
->peer_bind_info28
.repl_epoch
= info48
->repl_epoch
;
244 b
->peer_bind_info28
= b
->req
.out
.bind_info
->info
.info28
;
247 printf("DsBind - warning: unknown BindInfo length: %u\n",
248 b
->req
.out
.bind_info
->length
);
255 static bool test_LDAPBind(struct torture_context
*tctx
, struct DsSyncTest
*ctx
,
256 struct cli_credentials
*credentials
, struct DsSyncLDAPInfo
*l
)
260 struct ldb_context
*ldb
;
262 const char *modules_option
[] = { "modules:paged_searches", NULL
};
263 ctx
->admin
.ldap
.ldb
= ldb
= ldb_init(ctx
, tctx
->ev
);
268 /* Despite us loading the schema from the AD server, we need
269 * the samba handlers to get the extended DN syntax stuff */
270 ret
= ldb_register_samba_handlers(ldb
);
276 ldb_set_modules_dir(ldb
,
279 lp_modulesdir(tctx
->lp_ctx
)));
281 if (ldb_set_opaque(ldb
, "credentials", credentials
)) {
286 if (ldb_set_opaque(ldb
, "loadparm", tctx
->lp_ctx
)) {
291 ret
= ldb_connect(ldb
, ctx
->ldap_url
, 0, modules_option
);
292 if (ret
!= LDB_SUCCESS
) {
294 torture_assert_int_equal(tctx
, ret
, LDB_SUCCESS
, "Failed to make LDB connection to target");
297 printf("connected to LDAP: %s\n", ctx
->ldap_url
);
302 static bool test_GetInfo(struct torture_context
*tctx
, struct DsSyncTest
*ctx
)
305 struct drsuapi_DsCrackNames r
;
306 union drsuapi_DsNameRequest req
;
307 union drsuapi_DsNameCtr ctr
;
308 uint32_t level_out
= 0;
309 struct drsuapi_DsNameString names
[1];
311 struct cldap_socket
*cldap
;
312 struct cldap_netlogon search
;
313 struct tsocket_address
*dest_addr
;
316 ret2
= tsocket_address_inet_from_strings(tctx
, "ip",
318 lp_cldap_port(tctx
->lp_ctx
),
321 printf("failed to create tsocket_address for '%s' port %u - %s\n",
322 ctx
->drsuapi_binding
->host
, lp_cldap_port(tctx
->lp_ctx
),
327 status
= cldap_socket_init(ctx
, NULL
, NULL
, dest_addr
, &cldap
);
328 if (!NT_STATUS_IS_OK(status
)) {
329 printf("failed to setup cldap socket - %s\n",
334 r
.in
.bind_handle
= &ctx
->admin
.drsuapi
.bind_handle
;
337 r
.in
.req
->req1
.codepage
= 1252; /* western european */
338 r
.in
.req
->req1
.language
= 0x00000407; /* german */
339 r
.in
.req
->req1
.count
= 1;
340 r
.in
.req
->req1
.names
= names
;
341 r
.in
.req
->req1
.format_flags
= DRSUAPI_DS_NAME_FLAG_NO_FLAGS
;
342 r
.in
.req
->req1
.format_offered
= DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT
;
343 r
.in
.req
->req1
.format_desired
= DRSUAPI_DS_NAME_FORMAT_FQDN_1779
;
344 names
[0].str
= talloc_asprintf(ctx
, "%s\\", lp_workgroup(tctx
->lp_ctx
));
346 r
.out
.level_out
= &level_out
;
349 status
= dcerpc_drsuapi_DsCrackNames_r(ctx
->admin
.drsuapi
.drs_handle
, ctx
, &r
);
350 if (!NT_STATUS_IS_OK(status
)) {
351 const char *errstr
= nt_errstr(status
);
352 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
353 errstr
= dcerpc_errstr(ctx
, ctx
->admin
.drsuapi
.drs_pipe
->last_fault_code
);
355 printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr
);
357 } else if (!W_ERROR_IS_OK(r
.out
.result
)) {
358 printf("DsCrackNames failed - %s\n", win_errstr(r
.out
.result
));
362 ctx
->domain_dn
= r
.out
.ctr
->ctr1
->array
[0].result_name
;
365 search
.in
.dest_address
= NULL
;
366 search
.in
.dest_port
= 0;
367 search
.in
.acct_control
= -1;
368 search
.in
.version
= NETLOGON_NT_VERSION_5
| NETLOGON_NT_VERSION_5EX
;
369 search
.in
.map_response
= true;
370 status
= cldap_netlogon(cldap
, lp_iconv_convenience(tctx
->lp_ctx
), ctx
, &search
);
371 if (!NT_STATUS_IS_OK(status
)) {
372 const char *errstr
= nt_errstr(status
);
373 ctx
->site_name
= talloc_asprintf(ctx
, "%s", "Default-First-Site-Name");
374 printf("cldap_netlogon() returned %s. Defaulting to Site-Name: %s\n", errstr
, ctx
->site_name
);
376 ctx
->site_name
= talloc_steal(ctx
, search
.out
.netlogon
.data
.nt5_ex
.client_site
);
377 printf("cldap_netlogon() returned Client Site-Name: %s.\n",ctx
->site_name
);
378 printf("cldap_netlogon() returned Server Site-Name: %s.\n",search
.out
.netlogon
.data
.nt5_ex
.server_site
);
381 if (!ctx
->domain_dn
) {
382 struct ldb_context
*ldb
= ldb_init(ctx
, tctx
->ev
);
383 struct ldb_dn
*dn
= samdb_dns_domain_to_dn(ldb
, ctx
, search
.out
.netlogon
.data
.nt5_ex
.dns_domain
);
384 ctx
->domain_dn
= ldb_dn_alloc_linearized(ctx
, dn
);
392 static bool test_analyse_objects(struct torture_context
*tctx
,
393 struct DsSyncTest
*ctx
,
394 const char *partition
,
395 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
,
396 uint32_t object_count
,
397 const struct drsuapi_DsReplicaObjectListItemEx
*first_object
,
398 const DATA_BLOB
*gensec_skey
)
400 static uint32_t object_id
;
401 const char *save_values_dir
;
402 const struct drsuapi_DsReplicaObjectListItemEx
*cur
;
403 struct ldb_context
*ldb
= ctx
->admin
.ldap
.ldb
;
404 struct ldb_dn
*deleted_dn
;
407 struct dsdb_extended_replicated_objects
*objs
;
408 struct ldb_extended_dn_control
*extended_dn_ctrl
;
411 if (!dsdb_get_schema(ldb
, NULL
)) {
412 struct dsdb_schema
*ldap_schema
;
413 struct ldb_result
*a_res
;
414 struct ldb_result
*c_res
;
415 struct ldb_dn
*schema_dn
= ldb_get_schema_basedn(ldb
);
416 ldap_schema
= dsdb_new_schema(ctx
, lp_iconv_convenience(tctx
->lp_ctx
));
420 status
= dsdb_load_prefixmap_from_drsuapi(ldap_schema
, mapping_ctr
);
423 * load the attribute definitions
425 ret
= ldb_search(ldb
, ldap_schema
, &a_res
,
426 schema_dn
, LDB_SCOPE_ONELEVEL
, NULL
,
427 "(objectClass=attributeSchema)");
428 if (ret
!= LDB_SUCCESS
) {
429 err_msg
= talloc_asprintf(tctx
,
430 "failed to search attributeSchema objects: %s",
432 torture_fail(tctx
, err_msg
);
436 * load the objectClass definitions
438 ret
= ldb_search(ldb
, ldap_schema
, &c_res
,
439 schema_dn
, LDB_SCOPE_ONELEVEL
, NULL
,
440 "(objectClass=classSchema)");
441 if (ret
!= LDB_SUCCESS
) {
442 err_msg
= talloc_asprintf(tctx
,
443 "failed to search classSchema objects: %s",
445 torture_fail(tctx
, err_msg
);
449 for (i
=0; i
< a_res
->count
; i
++) {
450 status
= dsdb_attribute_from_ldb(ldb
, ldap_schema
, a_res
->msgs
[i
]);
451 torture_assert_werr_ok(tctx
, status
,
452 talloc_asprintf(tctx
,
453 "dsdb_attribute_from_ldb() failed for: %s",
454 ldb_dn_get_linearized(a_res
->msgs
[i
]->dn
)));
457 for (i
=0; i
< c_res
->count
; i
++) {
458 status
= dsdb_class_from_ldb(ldap_schema
, c_res
->msgs
[i
]);
459 torture_assert_werr_ok(tctx
, status
,
460 talloc_asprintf(tctx
,
461 "dsdb_class_from_ldb() failed for: %s",
462 ldb_dn_get_linearized(c_res
->msgs
[i
]->dn
)));
466 ret
= dsdb_set_schema(ldb
, ldap_schema
);
467 if (ret
!= LDB_SUCCESS
) {
469 talloc_asprintf(tctx
, "dsdb_set_schema() failed: %s", ldb_strerror(ret
)));
473 status
= dsdb_extended_replicated_objects_convert(ldb
,
482 torture_assert_werr_ok(tctx
, status
, "dsdb_extended_replicated_objects_convert() failed!");
484 extended_dn_ctrl
= talloc(objs
, struct ldb_extended_dn_control
);
485 extended_dn_ctrl
->type
= 1;
487 deleted_dn
= ldb_dn_new(objs
, ldb
, partition
);
488 ldb_dn_add_child_fmt(deleted_dn
, "CN=Deleted Objects");
490 for (i
=0; i
< object_count
; i
++) {
491 struct ldb_request
*search_req
;
492 struct ldb_result
*res
;
493 struct ldb_message
*new_msg
, *drs_msg
, *ldap_msg
;
494 const char **attrs
= talloc_array(objs
, const char *, objs
->objects
[i
].msg
->num_elements
+1);
495 for (j
=0; j
< objs
->objects
[i
].msg
->num_elements
; j
++) {
496 attrs
[j
] = objs
->objects
[i
].msg
->elements
[j
].name
;
499 res
= talloc_zero(objs
, struct ldb_result
);
501 return LDB_ERR_OPERATIONS_ERROR
;
503 ret
= ldb_build_search_req(&search_req
, ldb
, objs
,
504 objs
->objects
[i
].msg
->dn
,
510 ldb_search_default_callback
,
512 if (ret
!= LDB_SUCCESS
) {
515 talloc_steal(search_req
, res
);
516 ret
= ldb_request_add_control(search_req
, LDB_CONTROL_SHOW_DELETED_OID
, true, NULL
);
517 if (ret
!= LDB_SUCCESS
) {
521 ret
= ldb_request_add_control(search_req
, LDB_CONTROL_EXTENDED_DN_OID
, true, extended_dn_ctrl
);
522 if (ret
!= LDB_SUCCESS
) {
526 ret
= ldb_request(ldb
, search_req
);
527 if (ret
== LDB_SUCCESS
) {
528 ret
= ldb_wait(search_req
->handle
, LDB_WAIT_ALL
);
531 torture_assert_int_equal(tctx
, ret
, LDB_SUCCESS
,
532 talloc_asprintf(tctx
,
533 "Could not re-fetch object just delivered over DRS: %s",
534 ldb_errstring(ldb
)));
535 torture_assert_int_equal(tctx
, res
->count
, 1, "Could not re-fetch object just delivered over DRS");
536 ldap_msg
= res
->msgs
[0];
537 for (j
=0; j
< ldap_msg
->num_elements
; j
++) {
538 ldap_msg
->elements
[j
].flags
= LDB_FLAG_MOD_ADD
;
539 /* For unknown reasons, there is no nTSecurityDescriptor on cn=deleted objects over LDAP, but there is over DRS! Skip it on both transports for now here so */
540 if ((ldb_attr_cmp(ldap_msg
->elements
[j
].name
, "nTSecurityDescriptor") == 0) &&
541 (ldb_dn_compare(ldap_msg
->dn
, deleted_dn
) == 0)) {
542 ldb_msg_remove_element(ldap_msg
, &ldap_msg
->elements
[j
]);
548 drs_msg
= ldb_msg_canonicalize(ldb
, objs
->objects
[i
].msg
);
549 talloc_steal(search_req
, drs_msg
);
551 for (j
=0; j
< drs_msg
->num_elements
; j
++) {
552 if (drs_msg
->elements
[j
].num_values
== 0) {
553 ldb_msg_remove_element(drs_msg
, &drs_msg
->elements
[j
]);
557 /* For unknown reasons, there is no nTSecurityDescriptor on cn=deleted objects over LDAP, but there is over DRS! */
558 } else if ((ldb_attr_cmp(drs_msg
->elements
[j
].name
, "nTSecurityDescriptor") == 0) &&
559 (ldb_dn_compare(drs_msg
->dn
, deleted_dn
) == 0)) {
560 ldb_msg_remove_element(drs_msg
, &drs_msg
->elements
[j
]);
563 } else if (ldb_attr_cmp(drs_msg
->elements
[j
].name
, "unicodePwd") == 0 ||
564 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "dBCSPwd") == 0 ||
565 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "ntPwdHistory") == 0 ||
566 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "lmPwdHistory") == 0 ||
567 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "supplementalCredentials") == 0 ||
568 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "priorValue") == 0 ||
569 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "currentValue") == 0 ||
570 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "trustAuthOutgoing") == 0 ||
571 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "trustAuthIncoming") == 0 ||
572 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "initialAuthOutgoing") == 0 ||
573 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "initialAuthIncoming") == 0) {
575 /* These are not shown over LDAP, so we need to skip them for the comparison */
576 ldb_msg_remove_element(drs_msg
, &drs_msg
->elements
[j
]);
580 drs_msg
->elements
[j
].flags
= LDB_FLAG_MOD_ADD
;
585 new_msg
= ldb_msg_diff(ldb
, drs_msg
, ldap_msg
);
586 talloc_steal(search_req
, new_msg
);
587 if (new_msg
->num_elements
!= 0) {
589 struct ldb_ldif ldif
;
590 ldif
.changetype
= LDB_CHANGETYPE_MODIFY
;
592 s
= ldb_ldif_write_string(ldb
, new_msg
, &ldif
);
593 s
= talloc_asprintf(tctx
, "\n# Difference in between DRS and LDAP objects: \n%s\n", s
);
595 ldif
.msg
= ldb_msg_diff(ldb
, ldap_msg
, drs_msg
);
596 s
= talloc_asprintf_append(s
,
597 "\n# Difference in between LDAP and DRS objects: \n%s\n",
598 ldb_ldif_write_string(ldb
, new_msg
, &ldif
));
600 s
= talloc_asprintf_append(s
,
601 "# Should have no objects in 'difference' message. Diff elements: %d",
602 new_msg
->num_elements
);
603 torture_fail(tctx
, s
);
606 /* search_req is used as a tmp talloc context in the above */
607 talloc_free(search_req
);
610 if (!lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "print_pwd_blobs", false)) {
615 save_values_dir
= lp_parm_string(tctx
->lp_ctx
, NULL
, "dssync", "save_pwd_blobs_dir");
617 for (cur
= first_object
; cur
; cur
= cur
->next_object
) {
619 struct dom_sid
*sid
= NULL
;
621 bool dn_printed
= false;
623 if (!cur
->object
.identifier
) continue;
625 dn
= cur
->object
.identifier
->dn
;
626 if (cur
->object
.identifier
->sid
.num_auths
> 0) {
627 sid
= &cur
->object
.identifier
->sid
;
628 rid
= sid
->sub_auths
[sid
->num_auths
- 1];
631 for (i
=0; i
< cur
->object
.attribute_ctr
.num_attributes
; i
++) {
633 const char *name
= NULL
;
635 DATA_BLOB
*enc_data
= NULL
;
636 DATA_BLOB plain_data
;
637 struct drsuapi_DsReplicaAttribute
*attr
;
638 ndr_pull_flags_fn_t pull_fn
= NULL
;
639 ndr_print_fn_t print_fn
= NULL
;
641 attr
= &cur
->object
.attribute_ctr
.attributes
[i
];
643 switch (attr
->attid
) {
644 case DRSUAPI_ATTRIBUTE_dBCSPwd
:
648 case DRSUAPI_ATTRIBUTE_unicodePwd
:
652 case DRSUAPI_ATTRIBUTE_ntPwdHistory
:
653 name
= "ntPwdHistory";
656 case DRSUAPI_ATTRIBUTE_lmPwdHistory
:
657 name
= "lmPwdHistory";
660 case DRSUAPI_ATTRIBUTE_supplementalCredentials
:
661 name
= "supplementalCredentials";
662 pull_fn
= (ndr_pull_flags_fn_t
)ndr_pull_supplementalCredentialsBlob
;
663 print_fn
= (ndr_print_fn_t
)ndr_print_supplementalCredentialsBlob
;
664 ptr
= talloc(ctx
, struct supplementalCredentialsBlob
);
666 case DRSUAPI_ATTRIBUTE_priorValue
:
669 case DRSUAPI_ATTRIBUTE_currentValue
:
670 name
= "currentValue";
672 case DRSUAPI_ATTRIBUTE_trustAuthOutgoing
:
673 name
= "trustAuthOutgoing";
674 pull_fn
= (ndr_pull_flags_fn_t
)ndr_pull_trustAuthInOutBlob
;
675 print_fn
= (ndr_print_fn_t
)ndr_print_trustAuthInOutBlob
;
676 ptr
= talloc(ctx
, struct trustAuthInOutBlob
);
678 case DRSUAPI_ATTRIBUTE_trustAuthIncoming
:
679 name
= "trustAuthIncoming";
680 pull_fn
= (ndr_pull_flags_fn_t
)ndr_pull_trustAuthInOutBlob
;
681 print_fn
= (ndr_print_fn_t
)ndr_print_trustAuthInOutBlob
;
682 ptr
= talloc(ctx
, struct trustAuthInOutBlob
);
684 case DRSUAPI_ATTRIBUTE_initialAuthOutgoing
:
685 name
= "initialAuthOutgoing";
687 case DRSUAPI_ATTRIBUTE_initialAuthIncoming
:
688 name
= "initialAuthIncoming";
694 if (attr
->value_ctr
.num_values
!= 1) continue;
696 if (!attr
->value_ctr
.values
[0].blob
) continue;
698 enc_data
= attr
->value_ctr
.values
[0].blob
;
699 ZERO_STRUCT(plain_data
);
701 werr
= drsuapi_decrypt_attribute_value(ctx
, gensec_skey
, rcrypt
,
703 enc_data
, &plain_data
);
704 if (!W_ERROR_IS_OK(werr
)) {
705 DEBUG(0, ("Failed to decrypt %s\n", name
));
710 DEBUG(0,("DN[%u] %s\n", object_id
, dn
));
713 DEBUGADD(0,("ATTR: %s enc.length=%lu plain.length=%lu\n",
714 name
, (long)enc_data
->length
, (long)plain_data
.length
));
715 if (plain_data
.length
) {
716 enum ndr_err_code ndr_err
;
717 dump_data(0, plain_data
.data
, plain_data
.length
);
718 if (save_values_dir
) {
720 fname
= talloc_asprintf(ctx
, "%s/%s%02d",
725 ok
= file_save(fname
, plain_data
.data
, plain_data
.length
);
727 DEBUGADD(0,("Failed to save '%s'\n", fname
));
734 /* Can't use '_all' because of PIDL bugs with relative pointers */
735 ndr_err
= ndr_pull_struct_blob(&plain_data
, ptr
,
736 lp_iconv_convenience(tctx
->lp_ctx
), ptr
,
738 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
739 ndr_print_debug(print_fn
, name
, ptr
);
741 DEBUG(0, ("Failed to decode %s\n", name
));
745 dump_data(0, enc_data
->data
, enc_data
->length
);
754 static bool test_FetchData(struct torture_context
*tctx
, struct DsSyncTest
*ctx
)
759 uint64_t highest_usn
= 0;
760 const char *partition
= NULL
;
761 struct drsuapi_DsGetNCChanges r
;
762 union drsuapi_DsGetNCChangesRequest req
;
763 struct drsuapi_DsReplicaObjectIdentifier nc
;
764 struct drsuapi_DsGetNCChangesCtr1
*ctr1
= NULL
;
765 struct drsuapi_DsGetNCChangesCtr6
*ctr6
= NULL
;
766 uint32_t out_level
= 0;
767 struct GUID null_guid
;
768 struct dom_sid null_sid
;
769 DATA_BLOB gensec_skey
;
781 ZERO_STRUCT(null_guid
);
782 ZERO_STRUCT(null_sid
);
784 partition
= lp_parm_string(tctx
->lp_ctx
, NULL
, "dssync", "partition");
785 if (partition
== NULL
) {
786 partition
= ctx
->domain_dn
;
787 printf("dssync:partition not specified, defaulting to %s.\n", ctx
->domain_dn
);
790 highest_usn
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "highest_usn", 0);
792 array
[0].level
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "get_nc_changes_level", array
[0].level
);
794 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "print_pwd_blobs", false)) {
795 const struct samr_Password
*nthash
;
796 nthash
= cli_credentials_get_nt_hash(ctx
->new_dc
.credentials
, ctx
);
798 dump_data_pw("CREDENTIALS nthash:", nthash
->hash
, sizeof(nthash
->hash
));
801 status
= gensec_session_key(ctx
->new_dc
.drsuapi
.drs_pipe
->conn
->security_state
.generic_state
,
803 if (!NT_STATUS_IS_OK(status
)) {
804 printf("failed to get gensec session key: %s\n", nt_errstr(status
));
808 for (i
=0; i
< ARRAY_SIZE(array
); i
++) {
809 printf("Testing DsGetNCChanges level %d\n",
812 r
.in
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
813 r
.in
.level
= array
[i
].level
;
815 switch (r
.in
.level
) {
822 r
.in
.req
->req5
.destination_dsa_guid
= ctx
->new_dc
.invocation_id
;
823 r
.in
.req
->req5
.source_dsa_invocation_id
= null_guid
;
824 r
.in
.req
->req5
.naming_context
= &nc
;
825 r
.in
.req
->req5
.highwatermark
.tmp_highest_usn
= highest_usn
;
826 r
.in
.req
->req5
.highwatermark
.reserved_usn
= 0;
827 r
.in
.req
->req5
.highwatermark
.highest_usn
= highest_usn
;
828 r
.in
.req
->req5
.uptodateness_vector
= NULL
;
829 r
.in
.req
->req5
.replica_flags
= 0;
830 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "compression", false)) {
831 r
.in
.req
->req5
.replica_flags
|= DRSUAPI_DRS_USE_COMPRESSION
;
833 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "neighbour_writeable", true)) {
834 r
.in
.req
->req5
.replica_flags
|= DRSUAPI_DRS_WRIT_REP
;
836 r
.in
.req
->req5
.replica_flags
|= DRSUAPI_DRS_INIT_SYNC
837 | DRSUAPI_DRS_PER_SYNC
838 | DRSUAPI_DRS_GET_ANC
839 | DRSUAPI_DRS_NEVER_SYNCED
841 r
.in
.req
->req5
.max_object_count
= 133;
842 r
.in
.req
->req5
.max_ndr_size
= 1336770;
843 r
.in
.req
->req5
.extended_op
= DRSUAPI_EXOP_NONE
;
844 r
.in
.req
->req5
.fsmo_info
= 0;
851 /* nc.dn can be set to any other ad partition */
854 r
.in
.req
->req8
.destination_dsa_guid
= ctx
->new_dc
.invocation_id
;
855 r
.in
.req
->req8
.source_dsa_invocation_id
= null_guid
;
856 r
.in
.req
->req8
.naming_context
= &nc
;
857 r
.in
.req
->req8
.highwatermark
.tmp_highest_usn
= highest_usn
;
858 r
.in
.req
->req8
.highwatermark
.reserved_usn
= 0;
859 r
.in
.req
->req8
.highwatermark
.highest_usn
= highest_usn
;
860 r
.in
.req
->req8
.uptodateness_vector
= NULL
;
861 r
.in
.req
->req8
.replica_flags
= 0;
862 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "compression", false)) {
863 r
.in
.req
->req8
.replica_flags
|= DRSUAPI_DRS_USE_COMPRESSION
;
865 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "neighbour_writeable", true)) {
866 r
.in
.req
->req8
.replica_flags
|= DRSUAPI_DRS_WRIT_REP
;
868 r
.in
.req
->req8
.replica_flags
|= DRSUAPI_DRS_INIT_SYNC
869 | DRSUAPI_DRS_PER_SYNC
870 | DRSUAPI_DRS_GET_ANC
871 | DRSUAPI_DRS_NEVER_SYNCED
873 r
.in
.req
->req8
.max_object_count
= 402;
874 r
.in
.req
->req8
.max_ndr_size
= 402116;
876 r
.in
.req
->req8
.extended_op
= DRSUAPI_EXOP_NONE
;
877 r
.in
.req
->req8
.fsmo_info
= 0;
878 r
.in
.req
->req8
.partial_attribute_set
= NULL
;
879 r
.in
.req
->req8
.partial_attribute_set_ex
= NULL
;
880 r
.in
.req
->req8
.mapping_ctr
.num_mappings
= 0;
881 r
.in
.req
->req8
.mapping_ctr
.mappings
= NULL
;
886 printf("Dumping AD partition: %s\n", nc
.dn
);
889 union drsuapi_DsGetNCChangesCtr ctr
;
893 r
.out
.level_out
= &_level
;
896 if (r
.in
.level
== 5) {
897 torture_comment(tctx
,
898 "start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",
900 r
.in
.req
->req5
.highwatermark
.tmp_highest_usn
,
901 r
.in
.req
->req5
.highwatermark
.highest_usn
);
904 if (r
.in
.level
== 8) {
905 torture_comment(tctx
,
906 "start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",
908 r
.in
.req
->req8
.highwatermark
.tmp_highest_usn
,
909 r
.in
.req
->req8
.highwatermark
.highest_usn
);
912 status
= dcerpc_drsuapi_DsGetNCChanges_r(ctx
->new_dc
.drsuapi
.drs_handle
, ctx
, &r
);
913 torture_drsuapi_assert_call(tctx
, ctx
->new_dc
.drsuapi
.drs_pipe
, status
,
914 &r
, "dcerpc_drsuapi_DsGetNCChanges");
916 if (ret
== true && *r
.out
.level_out
== 1) {
918 ctr1
= &r
.out
.ctr
->ctr1
;
919 } else if (ret
== true && *r
.out
.level_out
== 2 &&
920 r
.out
.ctr
->ctr2
.mszip1
.ts
) {
922 ctr1
= &r
.out
.ctr
->ctr2
.mszip1
.ts
->ctr1
;
925 if (out_level
== 1) {
926 torture_comment(tctx
,
927 "end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",
929 ctr1
->new_highwatermark
.tmp_highest_usn
,
930 ctr1
->new_highwatermark
.highest_usn
);
932 if (!test_analyse_objects(tctx
, ctx
, partition
, &ctr1
->mapping_ctr
, ctr1
->object_count
,
933 ctr1
->first_object
, &gensec_skey
)) {
937 if (ctr1
->more_data
) {
938 r
.in
.req
->req5
.highwatermark
= ctr1
->new_highwatermark
;
943 if (ret
== true && *r
.out
.level_out
== 6) {
945 ctr6
= &r
.out
.ctr
->ctr6
;
946 } else if (ret
== true && *r
.out
.level_out
== 7
947 && r
.out
.ctr
->ctr7
.level
== 6
948 && r
.out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_MSZIP
949 && r
.out
.ctr
->ctr7
.ctr
.mszip6
.ts
) {
951 ctr6
= &r
.out
.ctr
->ctr7
.ctr
.mszip6
.ts
->ctr6
;
952 } else if (ret
== true && *r
.out
.level_out
== 7
953 && r
.out
.ctr
->ctr7
.level
== 6
954 && r
.out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_XPRESS
955 && r
.out
.ctr
->ctr7
.ctr
.xpress6
.ts
) {
957 ctr6
= &r
.out
.ctr
->ctr7
.ctr
.xpress6
.ts
->ctr6
;
960 if (out_level
== 6) {
961 torture_comment(tctx
,
962 "end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",
964 ctr6
->new_highwatermark
.tmp_highest_usn
,
965 ctr6
->new_highwatermark
.highest_usn
);
967 if (!test_analyse_objects(tctx
, ctx
, partition
, &ctr6
->mapping_ctr
, ctr6
->object_count
,
968 ctr6
->first_object
, &gensec_skey
)) {
972 if (ctr6
->more_data
) {
973 r
.in
.req
->req8
.highwatermark
= ctr6
->new_highwatermark
;
985 static bool test_FetchNT4Data(struct torture_context
*tctx
,
986 struct DsSyncTest
*ctx
)
989 struct drsuapi_DsGetNT4ChangeLog r
;
990 union drsuapi_DsGetNT4ChangeLogRequest req
;
991 union drsuapi_DsGetNT4ChangeLogInfo info
;
992 uint32_t level_out
= 0;
993 struct GUID null_guid
;
994 struct dom_sid null_sid
;
997 ZERO_STRUCT(null_guid
);
998 ZERO_STRUCT(null_sid
);
1002 r
.in
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
1005 r
.out
.level_out
= &level_out
;
1007 req
.req1
.flags
= lp_parm_int(tctx
->lp_ctx
, NULL
,
1008 "dssync", "nt4changelog_flags",
1009 DRSUAPI_NT4_CHANGELOG_GET_CHANGELOG
|
1010 DRSUAPI_NT4_CHANGELOG_GET_SERIAL_NUMBERS
);
1011 req
.req1
.preferred_maximum_length
= lp_parm_int(tctx
->lp_ctx
, NULL
,
1012 "dssync", "nt4changelog_preferred_len",
1016 req
.req1
.restart_length
= cookie
.length
;
1017 req
.req1
.restart_data
= cookie
.data
;
1021 status
= dcerpc_drsuapi_DsGetNT4ChangeLog_r(ctx
->new_dc
.drsuapi
.drs_handle
, ctx
, &r
);
1022 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_IMPLEMENTED
)) {
1023 torture_skip(tctx
, "DsGetNT4ChangeLog not supported by target server");
1024 } else if (!NT_STATUS_IS_OK(status
)) {
1025 const char *errstr
= nt_errstr(status
);
1026 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
1027 struct dcerpc_pipe
*p
= ctx
->new_dc
.drsuapi
.drs_pipe
;
1028 if (p
->last_fault_code
== DCERPC_FAULT_OP_RNG_ERROR
) {
1029 torture_skip(tctx
, "DsGetNT4ChangeLog not supported by target server");
1031 errstr
= dcerpc_errstr(ctx
, p
->last_fault_code
);
1034 talloc_asprintf(tctx
, "dcerpc_drsuapi_DsGetNT4ChangeLog failed - %s\n",
1036 } else if (W_ERROR_EQUAL(r
.out
.result
, WERR_INVALID_DOMAIN_ROLE
)) {
1037 torture_skip(tctx
, "DsGetNT4ChangeLog not supported by target server");
1038 } else if (!W_ERROR_IS_OK(r
.out
.result
)) {
1040 talloc_asprintf(tctx
, "DsGetNT4ChangeLog failed - %s\n",
1041 win_errstr(r
.out
.result
)));
1042 } else if (*r
.out
.level_out
!= 1) {
1044 talloc_asprintf(tctx
, "DsGetNT4ChangeLog unknown level - %u\n",
1046 } else if (NT_STATUS_IS_OK(r
.out
.info
->info1
.status
)) {
1047 } else if (NT_STATUS_EQUAL(r
.out
.info
->info1
.status
, STATUS_MORE_ENTRIES
)) {
1048 cookie
.length
= r
.out
.info
->info1
.restart_length
;
1049 cookie
.data
= r
.out
.info
->info1
.restart_data
;
1053 talloc_asprintf(tctx
, "DsGetNT4ChangeLog failed - %s\n",
1054 nt_errstr(r
.out
.info
->info1
.status
)));
1064 * DSSYNC test case setup
1066 static bool torture_dssync_tcase_setup(struct torture_context
*tctx
, void **data
)
1069 struct DsSyncTest
*ctx
;
1071 *data
= ctx
= test_create_context(tctx
);
1072 torture_assert(tctx
, ctx
, "test_create_context() failed");
1074 bret
= _test_DsBind(tctx
, ctx
, ctx
->admin
.credentials
, &ctx
->admin
.drsuapi
);
1075 torture_assert(tctx
, bret
, "_test_DsBind() failed");
1077 bret
= test_LDAPBind(tctx
, ctx
, ctx
->admin
.credentials
, &ctx
->admin
.ldap
);
1078 torture_assert(tctx
, bret
, "test_LDAPBind() failed");
1080 bret
= test_GetInfo(tctx
, ctx
);
1081 torture_assert(tctx
, bret
, "test_GetInfo() failed");
1083 bret
= _test_DsBind(tctx
, ctx
, ctx
->new_dc
.credentials
, &ctx
->new_dc
.drsuapi
);
1084 torture_assert(tctx
, bret
, "_test_DsBind() failed");
1090 * DSSYNC test case cleanup
1092 static bool torture_dssync_tcase_teardown(struct torture_context
*tctx
, void *data
)
1094 struct DsSyncTest
*ctx
;
1095 struct drsuapi_DsUnbind r
;
1096 struct policy_handle bind_handle
;
1098 ctx
= talloc_get_type(data
, struct DsSyncTest
);
1101 r
.out
.bind_handle
= &bind_handle
;
1103 /* Unbing admin handle */
1104 r
.in
.bind_handle
= &ctx
->admin
.drsuapi
.bind_handle
;
1105 dcerpc_drsuapi_DsUnbind_r(ctx
->admin
.drsuapi
.drs_handle
, ctx
, &r
);
1107 /* Unbing new_dc handle */
1108 r
.in
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
1109 dcerpc_drsuapi_DsUnbind_r(ctx
->new_dc
.drsuapi
.drs_handle
, ctx
, &r
);
1117 * DSSYNC test case implementation
1119 void torture_drs_rpc_dssync_tcase(struct torture_suite
*suite
)
1121 typedef bool (*run_func
) (struct torture_context
*test
, void *tcase_data
);
1123 struct torture_test
*test
;
1124 struct torture_tcase
*tcase
= torture_suite_add_tcase(suite
, "DSSYNC");
1126 torture_tcase_set_fixture(tcase
,
1127 torture_dssync_tcase_setup
,
1128 torture_dssync_tcase_teardown
);
1130 test
= torture_tcase_add_simple_test(tcase
, "DC_FetchData", (run_func
)test_FetchData
);
1131 test
= torture_tcase_add_simple_test(tcase
, "FetchNT4Data", (run_func
)test_FetchNT4Data
);