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"
38 struct DsSyncBindInfo
{
39 struct dcerpc_pipe
*pipe
;
40 struct drsuapi_DsBind req
;
41 struct GUID bind_guid
;
42 struct drsuapi_DsBindInfoCtr our_bind_info_ctr
;
43 struct drsuapi_DsBindInfo28 our_bind_info28
;
44 struct drsuapi_DsBindInfo28 peer_bind_info28
;
45 struct policy_handle bind_handle
;
48 struct DsSyncLDAPInfo
{
49 struct ldb_context
*ldb
;
53 struct dcerpc_binding
*drsuapi_binding
;
56 const char *site_name
;
58 const char *domain_dn
;
60 /* what we need to do as 'Administrator' */
62 struct cli_credentials
*credentials
;
63 struct DsSyncBindInfo drsuapi
;
64 struct DsSyncLDAPInfo ldap
;
67 /* what we need to do as the new dc machine account */
69 struct cli_credentials
*credentials
;
70 struct DsSyncBindInfo drsuapi
;
71 struct drsuapi_DsGetDCInfo2 dc_info2
;
72 struct GUID invocation_id
;
73 struct GUID object_guid
;
76 /* info about the old dc */
78 struct drsuapi_DsGetDomainControllerInfo dc_info
;
82 static bool _drs_util_verify_attids(struct torture_context
*tctx
,
83 struct DsSyncTest
*ctx
,
84 const struct drsuapi_DsReplicaOIDMapping_Ctr
*prefix_map
,
85 const struct drsuapi_DsReplicaObjectListItemEx
*cur
);
87 static struct DsSyncTest
*test_create_context(struct torture_context
*tctx
)
90 struct DsSyncTest
*ctx
;
91 struct drsuapi_DsBindInfo28
*our_bind_info28
;
92 struct drsuapi_DsBindInfoCtr
*our_bind_info_ctr
;
93 const char *binding
= torture_setting_string(tctx
, "binding", NULL
);
94 ctx
= talloc_zero(tctx
, struct DsSyncTest
);
95 if (!ctx
) return NULL
;
97 status
= dcerpc_parse_binding(ctx
, binding
, &ctx
->drsuapi_binding
);
98 if (!NT_STATUS_IS_OK(status
)) {
99 printf("Bad binding string %s\n", binding
);
102 ctx
->drsuapi_binding
->flags
|= DCERPC_SIGN
| DCERPC_SEAL
;
104 ctx
->ldap_url
= talloc_asprintf(ctx
, "ldap://%s", ctx
->drsuapi_binding
->host
);
107 ctx
->admin
.credentials
= cmdline_credentials
;
109 our_bind_info28
= &ctx
->admin
.drsuapi
.our_bind_info28
;
110 our_bind_info28
->supported_extensions
= 0xFFFFFFFF;
111 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
;
112 our_bind_info28
->site_guid
= GUID_zero();
113 our_bind_info28
->pid
= 0;
114 our_bind_info28
->repl_epoch
= 1;
116 our_bind_info_ctr
= &ctx
->admin
.drsuapi
.our_bind_info_ctr
;
117 our_bind_info_ctr
->length
= 28;
118 our_bind_info_ctr
->info
.info28
= *our_bind_info28
;
120 GUID_from_string(DRSUAPI_DS_BIND_GUID
, &ctx
->admin
.drsuapi
.bind_guid
);
122 ctx
->admin
.drsuapi
.req
.in
.bind_guid
= &ctx
->admin
.drsuapi
.bind_guid
;
123 ctx
->admin
.drsuapi
.req
.in
.bind_info
= our_bind_info_ctr
;
124 ctx
->admin
.drsuapi
.req
.out
.bind_handle
= &ctx
->admin
.drsuapi
.bind_handle
;
127 ctx
->new_dc
.credentials
= cmdline_credentials
;
129 our_bind_info28
= &ctx
->new_dc
.drsuapi
.our_bind_info28
;
130 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_BASE
;
131 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION
;
132 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI
;
133 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2
;
134 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS
;
135 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1
;
136 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION
;
137 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE
;
138 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2
;
139 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION
;
140 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2
;
141 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD
;
142 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND
;
143 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO
;
144 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION
;
145 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01
;
146 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP
;
147 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY
;
148 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3
;
149 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2
;
150 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6
;
151 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS
;
152 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
;
153 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5
;
154 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6
;
155 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
;
156 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7
;
157 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT
;
158 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "xpress", false)) {
159 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS
;
161 our_bind_info28
->site_guid
= GUID_zero();
162 our_bind_info28
->pid
= 0;
163 our_bind_info28
->repl_epoch
= 0;
165 our_bind_info_ctr
= &ctx
->new_dc
.drsuapi
.our_bind_info_ctr
;
166 our_bind_info_ctr
->length
= 28;
167 our_bind_info_ctr
->info
.info28
= *our_bind_info28
;
169 GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3
, &ctx
->new_dc
.drsuapi
.bind_guid
);
171 ctx
->new_dc
.drsuapi
.req
.in
.bind_guid
= &ctx
->new_dc
.drsuapi
.bind_guid
;
172 ctx
->new_dc
.drsuapi
.req
.in
.bind_info
= our_bind_info_ctr
;
173 ctx
->new_dc
.drsuapi
.req
.out
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
175 ctx
->new_dc
.invocation_id
= ctx
->new_dc
.drsuapi
.bind_guid
;
182 static bool _test_DsBind(struct torture_context
*tctx
,
183 struct DsSyncTest
*ctx
, struct cli_credentials
*credentials
, struct DsSyncBindInfo
*b
)
188 status
= dcerpc_pipe_connect_b(ctx
,
189 &b
->pipe
, ctx
->drsuapi_binding
,
191 credentials
, tctx
->ev
, tctx
->lp_ctx
);
193 if (!NT_STATUS_IS_OK(status
)) {
194 printf("Failed to connect to server as a BDC: %s\n", nt_errstr(status
));
198 status
= dcerpc_drsuapi_DsBind(b
->pipe
, ctx
, &b
->req
);
199 if (!NT_STATUS_IS_OK(status
)) {
200 const char *errstr
= nt_errstr(status
);
201 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
202 errstr
= dcerpc_errstr(ctx
, b
->pipe
->last_fault_code
);
204 printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr
);
206 } else if (!W_ERROR_IS_OK(b
->req
.out
.result
)) {
207 printf("DsBind failed - %s\n", win_errstr(b
->req
.out
.result
));
211 ZERO_STRUCT(b
->peer_bind_info28
);
212 if (b
->req
.out
.bind_info
) {
213 switch (b
->req
.out
.bind_info
->length
) {
215 struct drsuapi_DsBindInfo24
*info24
;
216 info24
= &b
->req
.out
.bind_info
->info
.info24
;
217 b
->peer_bind_info28
.supported_extensions
= info24
->supported_extensions
;
218 b
->peer_bind_info28
.site_guid
= info24
->site_guid
;
219 b
->peer_bind_info28
.pid
= info24
->pid
;
220 b
->peer_bind_info28
.repl_epoch
= 0;
224 struct drsuapi_DsBindInfo48
*info48
;
225 info48
= &b
->req
.out
.bind_info
->info
.info48
;
226 b
->peer_bind_info28
.supported_extensions
= info48
->supported_extensions
;
227 b
->peer_bind_info28
.site_guid
= info48
->site_guid
;
228 b
->peer_bind_info28
.pid
= info48
->pid
;
229 b
->peer_bind_info28
.repl_epoch
= info48
->repl_epoch
;
233 b
->peer_bind_info28
= b
->req
.out
.bind_info
->info
.info28
;
236 printf("DsBind - warning: unknown BindInfo length: %u\n",
237 b
->req
.out
.bind_info
->length
);
244 static bool test_LDAPBind(struct torture_context
*tctx
, struct DsSyncTest
*ctx
,
245 struct cli_credentials
*credentials
, struct DsSyncLDAPInfo
*l
)
249 struct ldb_context
*ldb
;
251 const char *modules_option
[] = { "modules:paged_searches", NULL
};
252 ctx
->admin
.ldap
.ldb
= ldb
= ldb_init(ctx
, tctx
->ev
);
257 /* Despite us loading the schema from the AD server, we need
258 * the samba handlers to get the extended DN syntax stuff */
259 ret
= ldb_register_samba_handlers(ldb
);
265 ldb_set_modules_dir(ldb
,
268 lp_modulesdir(tctx
->lp_ctx
)));
270 if (ldb_set_opaque(ldb
, "credentials", credentials
)) {
275 if (ldb_set_opaque(ldb
, "loadparm", tctx
->lp_ctx
)) {
280 ret
= ldb_connect(ldb
, ctx
->ldap_url
, 0, modules_option
);
281 if (ret
!= LDB_SUCCESS
) {
283 torture_assert_int_equal(tctx
, ret
, LDB_SUCCESS
, "Failed to make LDB connection to target");
286 printf("connected to LDAP: %s\n", ctx
->ldap_url
);
291 static bool test_GetInfo(struct torture_context
*tctx
, struct DsSyncTest
*ctx
)
294 struct drsuapi_DsCrackNames r
;
295 union drsuapi_DsNameRequest req
;
296 union drsuapi_DsNameCtr ctr
;
297 int32_t level_out
= 0;
298 struct drsuapi_DsNameString names
[1];
300 struct cldap_socket
*cldap
;
301 struct cldap_netlogon search
;
303 status
= cldap_socket_init(ctx
, NULL
, NULL
, NULL
, &cldap
);
304 if (!NT_STATUS_IS_OK(status
)) {
305 printf("failed to setup cldap socket - %s\n",
310 r
.in
.bind_handle
= &ctx
->admin
.drsuapi
.bind_handle
;
313 r
.in
.req
->req1
.codepage
= 1252; /* western european */
314 r
.in
.req
->req1
.language
= 0x00000407; /* german */
315 r
.in
.req
->req1
.count
= 1;
316 r
.in
.req
->req1
.names
= names
;
317 r
.in
.req
->req1
.format_flags
= DRSUAPI_DS_NAME_FLAG_NO_FLAGS
;
318 r
.in
.req
->req1
.format_offered
= DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT
;
319 r
.in
.req
->req1
.format_desired
= DRSUAPI_DS_NAME_FORMAT_FQDN_1779
;
320 names
[0].str
= talloc_asprintf(ctx
, "%s\\", lp_workgroup(tctx
->lp_ctx
));
322 r
.out
.level_out
= &level_out
;
325 status
= dcerpc_drsuapi_DsCrackNames(ctx
->admin
.drsuapi
.pipe
, ctx
, &r
);
326 if (!NT_STATUS_IS_OK(status
)) {
327 const char *errstr
= nt_errstr(status
);
328 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
329 errstr
= dcerpc_errstr(ctx
, ctx
->admin
.drsuapi
.pipe
->last_fault_code
);
331 printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr
);
333 } else if (!W_ERROR_IS_OK(r
.out
.result
)) {
334 printf("DsCrackNames failed - %s\n", win_errstr(r
.out
.result
));
338 ctx
->domain_dn
= r
.out
.ctr
->ctr1
->array
[0].result_name
;
341 search
.in
.dest_address
= ctx
->drsuapi_binding
->host
;
342 search
.in
.dest_port
= lp_cldap_port(tctx
->lp_ctx
);
343 search
.in
.acct_control
= -1;
344 search
.in
.version
= NETLOGON_NT_VERSION_5
| NETLOGON_NT_VERSION_5EX
;
345 search
.in
.map_response
= true;
346 status
= cldap_netlogon(cldap
, lp_iconv_convenience(tctx
->lp_ctx
), ctx
, &search
);
347 if (!NT_STATUS_IS_OK(status
)) {
348 const char *errstr
= nt_errstr(status
);
349 ctx
->site_name
= talloc_asprintf(ctx
, "%s", "Default-First-Site-Name");
350 printf("cldap_netlogon() returned %s. Defaulting to Site-Name: %s\n", errstr
, ctx
->site_name
);
352 ctx
->site_name
= talloc_steal(ctx
, search
.out
.netlogon
.data
.nt5_ex
.client_site
);
353 printf("cldap_netlogon() returned Client Site-Name: %s.\n",ctx
->site_name
);
354 printf("cldap_netlogon() returned Server Site-Name: %s.\n",search
.out
.netlogon
.data
.nt5_ex
.server_site
);
357 if (!ctx
->domain_dn
) {
358 struct ldb_context
*ldb
= ldb_init(ctx
, tctx
->ev
);
359 struct ldb_dn
*dn
= samdb_dns_domain_to_dn(ldb
, ctx
, search
.out
.netlogon
.data
.nt5_ex
.dns_domain
);
360 ctx
->domain_dn
= ldb_dn_alloc_linearized(ctx
, dn
);
368 static bool test_analyse_objects(struct torture_context
*tctx
,
369 struct DsSyncTest
*ctx
,
370 const char *partition
,
371 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
,
372 uint32_t object_count
,
373 const struct drsuapi_DsReplicaObjectListItemEx
*first_object
,
374 const DATA_BLOB
*gensec_skey
)
376 static uint32_t object_id
;
377 const char *save_values_dir
;
378 const struct drsuapi_DsReplicaObjectListItemEx
*cur
;
379 struct ldb_context
*ldb
= ctx
->admin
.ldap
.ldb
;
380 struct ldb_dn
*deleted_dn
;
383 struct dsdb_extended_replicated_objects
*objs
;
384 struct ldb_extended_dn_control
*extended_dn_ctrl
;
385 _drs_util_verify_attids(tctx
, ctx
, mapping_ctr
, first_object
);
387 if (!dsdb_get_schema(ldb
)) {
388 struct dsdb_schema
*ldap_schema
;
389 struct ldb_result
*a_res
;
390 struct ldb_result
*c_res
;
391 struct ldb_dn
*schema_dn
= ldb_get_schema_basedn(ldb
);
392 ldap_schema
= dsdb_new_schema(ctx
, lp_iconv_convenience(tctx
->lp_ctx
));
396 status
= dsdb_load_prefixmap_from_drsuapi(ldap_schema
, mapping_ctr
);
399 * load the attribute definitions
401 ret
= ldb_search(ldb
, ldap_schema
, &a_res
,
402 schema_dn
, LDB_SCOPE_ONELEVEL
, NULL
,
403 "(objectClass=attributeSchema)");
404 if (ret
!= LDB_SUCCESS
) {
405 DEBUG(0, ("load schema from LDAP for DSSYNC: failed to search attributeSchema objects: %s",
406 ldb_errstring(ldb
)));
411 * load the objectClass definitions
413 ret
= ldb_search(ldb
, ldap_schema
, &c_res
,
414 schema_dn
, LDB_SCOPE_ONELEVEL
, NULL
,
415 "(objectClass=classSchema)");
416 if (ret
!= LDB_SUCCESS
) {
417 DEBUG(0, ("load schema from LDAP for DSSYNC: failed to search classSchema objects: %s",
418 ldb_errstring(ldb
)));
423 for (i
=0; i
< a_res
->count
; i
++) {
424 status
= dsdb_attribute_from_ldb(ldb
, ldap_schema
, a_res
->msgs
[i
]);
425 if (!W_ERROR_IS_OK(status
)) {
426 DEBUG(0, ("load schema from LDAP for DSSYNC: failed to load attribute definition: %s:%s",
427 ldb_dn_get_linearized(a_res
->msgs
[i
]->dn
),
428 win_errstr(status
)));
433 for (i
=0; i
< c_res
->count
; i
++) {
434 status
= dsdb_class_from_ldb(ldap_schema
, c_res
->msgs
[i
]);
435 if (!W_ERROR_IS_OK(status
)) {
436 DEBUG(0, ("load scheam from LDAP for DSSYNC: failed to load class definition: %s:%s",
437 ldb_dn_get_linearized(c_res
->msgs
[i
]->dn
),
438 win_errstr(status
)));
444 ret
= dsdb_set_schema(ldb
, ldap_schema
);
445 if (ret
!= LDB_SUCCESS
) {
446 DEBUG(0, ("load schema from LDAP for DSSYNC: failed to set schema: %s\n", ldb_strerror(ret
)));
451 status
= dsdb_extended_replicated_objects_convert(ldb
,
460 if (!W_ERROR_IS_OK(status
)) {
461 DEBUG(0, ("load scheam from LDAP for DSSYNC: failed to parse objects: %s",
462 win_errstr(status
)));
466 extended_dn_ctrl
= talloc(objs
, struct ldb_extended_dn_control
);
467 extended_dn_ctrl
->type
= 1;
469 deleted_dn
= ldb_dn_new(objs
, ldb
, partition
);
470 ldb_dn_add_child_fmt(deleted_dn
, "CN=Deleted Objects");
472 for (i
=0; i
< object_count
; i
++) {
473 struct ldb_request
*search_req
;
474 struct ldb_result
*res
;
475 struct ldb_message
*new_msg
, *drs_msg
, *ldap_msg
;
476 const char **attrs
= talloc_array(objs
, const char *, objs
->objects
[i
].msg
->num_elements
+1);
477 for (j
=0; j
< objs
->objects
[i
].msg
->num_elements
; j
++) {
478 attrs
[j
] = objs
->objects
[i
].msg
->elements
[j
].name
;
481 res
= talloc_zero(objs
, struct ldb_result
);
483 return LDB_ERR_OPERATIONS_ERROR
;
485 ret
= ldb_build_search_req(&search_req
, ldb
, objs
,
486 objs
->objects
[i
].msg
->dn
,
492 ldb_search_default_callback
,
494 if (ret
!= LDB_SUCCESS
) {
497 talloc_steal(search_req
, res
);
498 ret
= ldb_request_add_control(search_req
, LDB_CONTROL_SHOW_DELETED_OID
, true, NULL
);
499 if (ret
!= LDB_SUCCESS
) {
503 ret
= ldb_request_add_control(search_req
, LDB_CONTROL_EXTENDED_DN_OID
, true, extended_dn_ctrl
);
504 if (ret
!= LDB_SUCCESS
) {
508 ret
= ldb_request(ldb
, search_req
);
509 if (ret
== LDB_SUCCESS
) {
510 ret
= ldb_wait(search_req
->handle
, LDB_WAIT_ALL
);
513 if (ret
!= LDB_SUCCESS
) {
514 DEBUG(0, ("Could not re-fetch object just delivered over DRS: %s", ldb_errstring(ldb
)));
517 if (res
->count
!= 1) {
518 DEBUG(0, ("Could not re-fetch object just delivered over DRS"));
521 ldap_msg
= res
->msgs
[0];
522 for (j
=0; j
< ldap_msg
->num_elements
; j
++) {
523 ldap_msg
->elements
[j
].flags
= LDB_FLAG_MOD_ADD
;
526 drs_msg
= ldb_msg_canonicalize(ldb
, objs
->objects
[i
].msg
);
527 for (j
=0; j
< drs_msg
->num_elements
; j
++) {
528 if (drs_msg
->elements
[j
].num_values
== 0) {
529 ldb_msg_remove_element(drs_msg
, &drs_msg
->elements
[j
]);
533 /* For unknown reasons, there is no nTSecurityDescriptor on cn=deleted objects over LDAP, but there is over DRS! */
534 } else if (ldb_attr_cmp(drs_msg
->elements
[j
].name
, "nTSecurityDescriptor") == 0 &&
535 ldb_dn_compare(drs_msg
->dn
, deleted_dn
) == 0) {
536 ldb_msg_remove_element(drs_msg
, &drs_msg
->elements
[j
]);
539 } else if (ldb_attr_cmp(drs_msg
->elements
[j
].name
, "unicodePwd") == 0 ||
540 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "dBCSPwd") == 0 ||
541 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "ntPwdHistory") == 0 ||
542 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "lmPwdHistory") == 0 ||
543 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "supplementalCredentials") == 0 ||
544 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "priorValue") == 0 ||
545 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "currentValue") == 0 ||
546 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "trustAuthOutgoing") == 0 ||
547 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "trustAuthIncoming") == 0 ||
548 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "initialAuthOutgoing") == 0 ||
549 ldb_attr_cmp(drs_msg
->elements
[j
].name
, "initialAuthIncoming") == 0) {
551 /* These are not shown over LDAP, so we need to skip them for the comparison */
552 ldb_msg_remove_element(drs_msg
, &drs_msg
->elements
[j
]);
556 drs_msg
->elements
[j
].flags
= LDB_FLAG_MOD_ADD
;
561 new_msg
= ldb_msg_diff(ldb
, drs_msg
, ldap_msg
);
562 talloc_steal(search_req
, new_msg
);
563 if (new_msg
->num_elements
!= 0) {
565 struct ldb_ldif ldif
;
566 fprintf(stdout
, "#\n");
567 ldif
.changetype
= LDB_CHANGETYPE_MODIFY
;
569 s
= ldb_ldif_write_string(ldb
, new_msg
, &ldif
);
570 DEBUG(0, ("Difference in between DRS and LDAP objects: %s\n", s
));
572 talloc_free(search_req
);
575 if (!lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "print_pwd_blobs", false)) {
579 save_values_dir
= lp_parm_string(tctx
->lp_ctx
, NULL
, "dssync", "save_pwd_blobs_dir");
581 for (cur
= first_object
; cur
; cur
= cur
->next_object
) {
583 struct dom_sid
*sid
= NULL
;
585 bool dn_printed
= false;
587 if (!cur
->object
.identifier
) continue;
589 dn
= cur
->object
.identifier
->dn
;
590 if (cur
->object
.identifier
->sid
.num_auths
> 0) {
591 sid
= &cur
->object
.identifier
->sid
;
592 rid
= sid
->sub_auths
[sid
->num_auths
- 1];
595 for (i
=0; i
< cur
->object
.attribute_ctr
.num_attributes
; i
++) {
597 const char *name
= NULL
;
599 DATA_BLOB
*enc_data
= NULL
;
600 DATA_BLOB plain_data
;
601 struct drsuapi_DsReplicaAttribute
*attr
;
602 ndr_pull_flags_fn_t pull_fn
= NULL
;
603 ndr_print_fn_t print_fn
= NULL
;
605 attr
= &cur
->object
.attribute_ctr
.attributes
[i
];
607 switch (attr
->attid
) {
608 case DRSUAPI_ATTRIBUTE_dBCSPwd
:
612 case DRSUAPI_ATTRIBUTE_unicodePwd
:
616 case DRSUAPI_ATTRIBUTE_ntPwdHistory
:
617 name
= "ntPwdHistory";
620 case DRSUAPI_ATTRIBUTE_lmPwdHistory
:
621 name
= "lmPwdHistory";
624 case DRSUAPI_ATTRIBUTE_supplementalCredentials
:
625 name
= "supplementalCredentials";
626 pull_fn
= (ndr_pull_flags_fn_t
)ndr_pull_supplementalCredentialsBlob
;
627 print_fn
= (ndr_print_fn_t
)ndr_print_supplementalCredentialsBlob
;
628 ptr
= talloc(ctx
, struct supplementalCredentialsBlob
);
630 case DRSUAPI_ATTRIBUTE_priorValue
:
633 case DRSUAPI_ATTRIBUTE_currentValue
:
634 name
= "currentValue";
636 case DRSUAPI_ATTRIBUTE_trustAuthOutgoing
:
637 name
= "trustAuthOutgoing";
638 pull_fn
= (ndr_pull_flags_fn_t
)ndr_pull_trustAuthInOutBlob
;
639 print_fn
= (ndr_print_fn_t
)ndr_print_trustAuthInOutBlob
;
640 ptr
= talloc(ctx
, struct trustAuthInOutBlob
);
642 case DRSUAPI_ATTRIBUTE_trustAuthIncoming
:
643 name
= "trustAuthIncoming";
644 pull_fn
= (ndr_pull_flags_fn_t
)ndr_pull_trustAuthInOutBlob
;
645 print_fn
= (ndr_print_fn_t
)ndr_print_trustAuthInOutBlob
;
646 ptr
= talloc(ctx
, struct trustAuthInOutBlob
);
648 case DRSUAPI_ATTRIBUTE_initialAuthOutgoing
:
649 name
= "initialAuthOutgoing";
651 case DRSUAPI_ATTRIBUTE_initialAuthIncoming
:
652 name
= "initialAuthIncoming";
658 if (attr
->value_ctr
.num_values
!= 1) continue;
660 if (!attr
->value_ctr
.values
[0].blob
) continue;
662 enc_data
= attr
->value_ctr
.values
[0].blob
;
663 ZERO_STRUCT(plain_data
);
665 werr
= drsuapi_decrypt_attribute_value(ctx
, gensec_skey
, rcrypt
,
667 enc_data
, &plain_data
);
668 if (!W_ERROR_IS_OK(werr
)) {
669 DEBUG(0, ("Failed to decrypt %s\n", name
));
674 DEBUG(0,("DN[%u] %s\n", object_id
, dn
));
677 DEBUGADD(0,("ATTR: %s enc.length=%lu plain.length=%lu\n",
678 name
, (long)enc_data
->length
, (long)plain_data
.length
));
679 if (plain_data
.length
) {
680 enum ndr_err_code ndr_err
;
681 dump_data(0, plain_data
.data
, plain_data
.length
);
682 if (save_values_dir
) {
684 fname
= talloc_asprintf(ctx
, "%s/%s%02d",
689 ok
= file_save(fname
, plain_data
.data
, plain_data
.length
);
691 DEBUGADD(0,("Failed to save '%s'\n", fname
));
698 /* Can't use '_all' because of PIDL bugs with relative pointers */
699 ndr_err
= ndr_pull_struct_blob(&plain_data
, ptr
,
700 lp_iconv_convenience(tctx
->lp_ctx
), ptr
,
702 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
703 ndr_print_debug(print_fn
, name
, ptr
);
705 DEBUG(0, ("Failed to decode %s\n", name
));
709 dump_data(0, enc_data
->data
, enc_data
->length
);
718 * Fetch LDAP attribute name and DN by supplied OID
720 static bool _drs_ldap_attr_by_oid(struct torture_context
*tctx
,
721 struct DsSyncTest
*ctx
,
725 struct ldb_dn
*config_dn
;
726 struct ldb_result
*res
;
727 TALLOC_CTX
*tmp_ctx
= NULL
;
728 const char *search_attrs
[] = {"lDAPDisplayName", NULL
};
731 tmp_ctx
= talloc_new(ctx
);
733 config_dn
= ldb_dn_new_fmt(tmp_ctx
, ctx
->admin
.ldap
.ldb
,
734 "CN=Schema,CN=Configuration,%s", ctx
->domain_dn
);
735 ret
= ldb_search(ctx
->admin
.ldap
.ldb
, tmp_ctx
, &res
, config_dn
,
736 LDB_SCOPE_ONELEVEL
, search_attrs
, "(attributeID=%s)", oid
);
738 torture_assert_int_equal(tctx
,
740 "Failed to search for attribute");
742 torture_assert_int_equal(tctx
,
743 res
->count
, 1, "Failed to find attribute for OID");
746 *attr_name
= talloc_strdup(ctx
, ldb_msg_find_attr_as_string(res
->msgs
[0], "lDAPDisplayName", NULL
));
749 talloc_free(tmp_ctx
);
755 * Make Attribute OID and verify such Attribute exists in schema
757 static bool _drs_util_verify_attids(struct torture_context
*tctx
,
758 struct DsSyncTest
*ctx
,
759 const struct drsuapi_DsReplicaOIDMapping_Ctr
*prefix_map
,
760 const struct drsuapi_DsReplicaObjectListItemEx
*cur
)
764 DEBUG(1,("drs_test_verify_attids:\n"));
766 for (; cur
; cur
= cur
->next_object
) {
767 char *attr_name
= NULL
;
768 const struct drsuapi_DsReplicaObject
*obj
= &cur
->object
;
770 DEBUG(1,("%3s %-10s: %s\n", "", "object_dn", obj
->identifier
->dn
));
772 for (i
= 0; i
< obj
->attribute_ctr
.num_attributes
; i
++) {
774 const char *oid
= NULL
;
775 struct drsuapi_DsReplicaAttribute
*attr
;
777 attr
= &obj
->attribute_ctr
.attributes
[i
];
778 if (!drs_util_oid_from_attid(tctx
, prefix_map
, attr
->attid
, &oid
, &map_idx
)) {
782 if (!_drs_ldap_attr_by_oid(tctx
, ctx
, oid
, &attr_name
)) {
786 DEBUG(10,("%7s attr[%2d]: %-22s {map_idx=%2d; attid=0x%06x; ldap_name=%-26s; idl_name=%s}\n", "",
787 i
, oid
, map_idx
, attr
->attid
, attr_name
,
788 drs_util_DsAttributeId_to_string(attr
->attid
)));
789 talloc_free(attr_name
);
797 static bool test_FetchData(struct torture_context
*tctx
, struct DsSyncTest
*ctx
)
802 uint64_t highest_usn
= 0;
803 const char *partition
= NULL
;
804 struct drsuapi_DsGetNCChanges r
;
805 union drsuapi_DsGetNCChangesRequest req
;
806 struct drsuapi_DsReplicaObjectIdentifier nc
;
807 struct drsuapi_DsGetNCChangesCtr1
*ctr1
= NULL
;
808 struct drsuapi_DsGetNCChangesCtr6
*ctr6
= NULL
;
809 int32_t out_level
= 0;
810 struct GUID null_guid
;
811 struct dom_sid null_sid
;
812 DATA_BLOB gensec_skey
;
824 ZERO_STRUCT(null_guid
);
825 ZERO_STRUCT(null_sid
);
827 partition
= lp_parm_string(tctx
->lp_ctx
, NULL
, "dssync", "partition");
828 if (partition
== NULL
) {
829 partition
= ctx
->domain_dn
;
830 printf("dssync:partition not specified, defaulting to %s.\n", ctx
->domain_dn
);
833 highest_usn
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "highest_usn", 0);
835 array
[0].level
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "get_nc_changes_level", array
[0].level
);
837 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "print_pwd_blobs", false)) {
838 const struct samr_Password
*nthash
;
839 nthash
= cli_credentials_get_nt_hash(ctx
->new_dc
.credentials
, ctx
);
841 dump_data_pw("CREDENTIALS nthash:", nthash
->hash
, sizeof(nthash
->hash
));
844 status
= gensec_session_key(ctx
->new_dc
.drsuapi
.pipe
->conn
->security_state
.generic_state
,
846 if (!NT_STATUS_IS_OK(status
)) {
847 printf("failed to get gensec session key: %s\n", nt_errstr(status
));
851 for (i
=0; i
< ARRAY_SIZE(array
); i
++) {
852 printf("testing DsGetNCChanges level %d\n",
855 r
.in
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
856 r
.in
.level
= array
[i
].level
;
858 switch (r
.in
.level
) {
865 r
.in
.req
->req5
.destination_dsa_guid
= ctx
->new_dc
.invocation_id
;
866 r
.in
.req
->req5
.source_dsa_invocation_id
= null_guid
;
867 r
.in
.req
->req5
.naming_context
= &nc
;
868 r
.in
.req
->req5
.highwatermark
.tmp_highest_usn
= highest_usn
;
869 r
.in
.req
->req5
.highwatermark
.reserved_usn
= 0;
870 r
.in
.req
->req5
.highwatermark
.highest_usn
= highest_usn
;
871 r
.in
.req
->req5
.uptodateness_vector
= NULL
;
872 r
.in
.req
->req5
.replica_flags
= 0;
873 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "compression", false)) {
874 r
.in
.req
->req5
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES
;
876 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "neighbour_writeable", true)) {
877 r
.in
.req
->req5
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
;
879 r
.in
.req
->req5
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
880 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
881 | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS
882 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
884 r
.in
.req
->req5
.max_object_count
= 133;
885 r
.in
.req
->req5
.max_ndr_size
= 1336770;
886 r
.in
.req
->req5
.extended_op
= DRSUAPI_EXOP_NONE
;
887 r
.in
.req
->req5
.fsmo_info
= 0;
894 /* nc.dn can be set to any other ad partition */
897 r
.in
.req
->req8
.destination_dsa_guid
= ctx
->new_dc
.invocation_id
;
898 r
.in
.req
->req8
.source_dsa_invocation_id
= null_guid
;
899 r
.in
.req
->req8
.naming_context
= &nc
;
900 r
.in
.req
->req8
.highwatermark
.tmp_highest_usn
= highest_usn
;
901 r
.in
.req
->req8
.highwatermark
.reserved_usn
= 0;
902 r
.in
.req
->req8
.highwatermark
.highest_usn
= highest_usn
;
903 r
.in
.req
->req8
.uptodateness_vector
= NULL
;
904 r
.in
.req
->req8
.replica_flags
= 0;
905 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "compression", false)) {
906 r
.in
.req
->req8
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES
;
908 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "neighbour_writeable", true)) {
909 r
.in
.req
->req8
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
;
911 r
.in
.req
->req8
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
912 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
913 | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS
914 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
916 r
.in
.req
->req8
.max_object_count
= 402;
917 r
.in
.req
->req8
.max_ndr_size
= 402116;
919 r
.in
.req
->req8
.extended_op
= DRSUAPI_EXOP_NONE
;
920 r
.in
.req
->req8
.fsmo_info
= 0;
921 r
.in
.req
->req8
.partial_attribute_set
= NULL
;
922 r
.in
.req
->req8
.partial_attribute_set_ex
= NULL
;
923 r
.in
.req
->req8
.mapping_ctr
.num_mappings
= 0;
924 r
.in
.req
->req8
.mapping_ctr
.mappings
= NULL
;
929 printf("Dumping AD partition: %s\n", nc
.dn
);
932 union drsuapi_DsGetNCChangesCtr ctr
;
936 r
.out
.level_out
= &_level
;
939 if (r
.in
.level
== 5) {
940 DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y
,
941 (long long)r
.in
.req
->req5
.highwatermark
.tmp_highest_usn
,
942 (long long)r
.in
.req
->req5
.highwatermark
.highest_usn
));
945 if (r
.in
.level
== 8) {
946 DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y
,
947 (long long)r
.in
.req
->req8
.highwatermark
.tmp_highest_usn
,
948 (long long)r
.in
.req
->req8
.highwatermark
.highest_usn
));
951 status
= dcerpc_drsuapi_DsGetNCChanges(ctx
->new_dc
.drsuapi
.pipe
, ctx
, &r
);
952 if (!NT_STATUS_IS_OK(status
)) {
953 const char *errstr
= nt_errstr(status
);
954 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
955 errstr
= dcerpc_errstr(ctx
, ctx
->new_dc
.drsuapi
.pipe
->last_fault_code
);
957 printf("dcerpc_drsuapi_DsGetNCChanges failed - %s\n", errstr
);
959 } else if (!W_ERROR_IS_OK(r
.out
.result
)) {
960 printf("DsGetNCChanges failed - %s\n", win_errstr(r
.out
.result
));
964 if (ret
== true && *r
.out
.level_out
== 1) {
966 ctr1
= &r
.out
.ctr
->ctr1
;
967 } else if (ret
== true && *r
.out
.level_out
== 2 &&
968 r
.out
.ctr
->ctr2
.mszip1
.ts
) {
970 ctr1
= &r
.out
.ctr
->ctr2
.mszip1
.ts
->ctr1
;
973 if (out_level
== 1) {
974 DEBUG(0,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y
,
975 (long long)ctr1
->new_highwatermark
.tmp_highest_usn
,
976 (long long)ctr1
->new_highwatermark
.highest_usn
));
978 if (!test_analyse_objects(tctx
, ctx
, partition
, &ctr1
->mapping_ctr
, ctr1
->object_count
,
979 ctr1
->first_object
, &gensec_skey
)) {
983 if (ctr1
->more_data
) {
984 r
.in
.req
->req5
.highwatermark
= ctr1
->new_highwatermark
;
989 if (ret
== true && *r
.out
.level_out
== 6) {
991 ctr6
= &r
.out
.ctr
->ctr6
;
992 } else if (ret
== true && *r
.out
.level_out
== 7
993 && r
.out
.ctr
->ctr7
.level
== 6
994 && r
.out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_MSZIP
995 && r
.out
.ctr
->ctr7
.ctr
.mszip6
.ts
) {
997 ctr6
= &r
.out
.ctr
->ctr7
.ctr
.mszip6
.ts
->ctr6
;
998 } else if (ret
== true && *r
.out
.level_out
== 7
999 && r
.out
.ctr
->ctr7
.level
== 6
1000 && r
.out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_XPRESS
1001 && r
.out
.ctr
->ctr7
.ctr
.xpress6
.ts
) {
1003 ctr6
= &r
.out
.ctr
->ctr7
.ctr
.xpress6
.ts
->ctr6
;
1006 if (out_level
== 6) {
1007 DEBUG(0,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y
,
1008 (long long)ctr6
->new_highwatermark
.tmp_highest_usn
,
1009 (long long)ctr6
->new_highwatermark
.highest_usn
));
1011 if (!test_analyse_objects(tctx
, ctx
, partition
, &ctr6
->mapping_ctr
, ctr6
->object_count
,
1012 ctr6
->first_object
, &gensec_skey
)) {
1016 if (ctr6
->more_data
) {
1017 r
.in
.req
->req8
.highwatermark
= ctr6
->new_highwatermark
;
1029 static bool test_FetchNT4Data(struct torture_context
*tctx
,
1030 struct DsSyncTest
*ctx
)
1034 struct drsuapi_DsGetNT4ChangeLog r
;
1035 union drsuapi_DsGetNT4ChangeLogRequest req
;
1036 union drsuapi_DsGetNT4ChangeLogInfo info
;
1037 uint32_t level_out
= 0;
1038 struct GUID null_guid
;
1039 struct dom_sid null_sid
;
1042 ZERO_STRUCT(null_guid
);
1043 ZERO_STRUCT(null_sid
);
1044 ZERO_STRUCT(cookie
);
1047 r
.in
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
1050 r
.out
.level_out
= &level_out
;
1052 req
.req1
.unknown1
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "nt4-1", 3);
1053 req
.req1
.unknown2
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "nt4-2", 0x00004000);
1056 req
.req1
.length
= cookie
.length
;
1057 req
.req1
.data
= cookie
.data
;
1061 status
= dcerpc_drsuapi_DsGetNT4ChangeLog(ctx
->new_dc
.drsuapi
.pipe
, ctx
, &r
);
1062 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_IMPLEMENTED
)) {
1063 printf("DsGetNT4ChangeLog not supported by target server\n");
1065 } else if (!NT_STATUS_IS_OK(status
)) {
1066 const char *errstr
= nt_errstr(status
);
1067 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
1068 errstr
= dcerpc_errstr(ctx
, ctx
->new_dc
.drsuapi
.pipe
->last_fault_code
);
1070 printf("dcerpc_drsuapi_DsGetNT4ChangeLog failed - %s\n", errstr
);
1072 } else if (W_ERROR_EQUAL(r
.out
.result
, WERR_INVALID_DOMAIN_ROLE
)) {
1073 printf("DsGetNT4ChangeLog not supported by target server\n");
1075 } else if (!W_ERROR_IS_OK(r
.out
.result
)) {
1076 printf("DsGetNT4ChangeLog failed - %s\n", win_errstr(r
.out
.result
));
1078 } else if (*r
.out
.level_out
!= 1) {
1079 printf("DsGetNT4ChangeLog unknown level - %u\n", *r
.out
.level_out
);
1081 } else if (NT_STATUS_IS_OK(r
.out
.info
->info1
.status
)) {
1082 } else if (NT_STATUS_EQUAL(r
.out
.info
->info1
.status
, STATUS_MORE_ENTRIES
)) {
1083 cookie
.length
= r
.out
.info
->info1
.length1
;
1084 cookie
.data
= r
.out
.info
->info1
.data1
;
1087 printf("DsGetNT4ChangeLog failed - %s\n", nt_errstr(r
.out
.info
->info1
.status
));
1097 bool torture_rpc_dssync(struct torture_context
*torture
)
1100 TALLOC_CTX
*mem_ctx
;
1101 struct DsSyncTest
*ctx
;
1103 mem_ctx
= talloc_init("torture_rpc_dssync");
1104 ctx
= test_create_context(torture
);
1106 ret
&= _test_DsBind(torture
, ctx
, ctx
->admin
.credentials
, &ctx
->admin
.drsuapi
);
1110 ret
&= test_LDAPBind(torture
, ctx
, ctx
->admin
.credentials
, &ctx
->admin
.ldap
);
1114 ret
&= test_GetInfo(torture
, ctx
);
1115 ret
&= _test_DsBind(torture
, ctx
, ctx
->new_dc
.credentials
, &ctx
->new_dc
.drsuapi
);
1119 ret
&= test_FetchData(torture
, ctx
);
1120 ret
&= test_FetchNT4Data(torture
, ctx
);