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 "libcli/cldap/cldap.h"
27 #include "libcli/ldap/ldap_client.h"
28 #include "torture/torture.h"
29 #include "torture/ldap/proto.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "lib/crypto/crypto.h"
32 #include "auth/credentials/credentials.h"
33 #include "libcli/auth/libcli_auth.h"
34 #include "auth/gensec/gensec.h"
35 #include "param/param.h"
37 struct DsSyncBindInfo
{
38 struct dcerpc_pipe
*pipe
;
39 struct drsuapi_DsBind req
;
40 struct GUID bind_guid
;
41 struct drsuapi_DsBindInfoCtr our_bind_info_ctr
;
42 struct drsuapi_DsBindInfo28 our_bind_info28
;
43 struct drsuapi_DsBindInfo28 peer_bind_info28
;
44 struct policy_handle bind_handle
;
47 struct DsSyncLDAPInfo
{
48 struct ldap_connection
*conn
;
52 struct dcerpc_binding
*drsuapi_binding
;
55 const char *site_name
;
57 const char *domain_dn
;
59 /* what we need to do as 'Administrator' */
61 struct cli_credentials
*credentials
;
62 struct DsSyncBindInfo drsuapi
;
63 struct DsSyncLDAPInfo ldap
;
66 /* what we need to do as the new dc machine account */
68 struct cli_credentials
*credentials
;
69 struct DsSyncBindInfo drsuapi
;
70 struct drsuapi_DsGetDCInfo2 dc_info2
;
71 struct GUID invocation_id
;
72 struct GUID object_guid
;
75 /* info about the old dc */
77 struct drsuapi_DsGetDomainControllerInfo dc_info
;
81 static struct DsSyncTest
*test_create_context(struct torture_context
*tctx
)
84 struct DsSyncTest
*ctx
;
85 struct drsuapi_DsBindInfo28
*our_bind_info28
;
86 struct drsuapi_DsBindInfoCtr
*our_bind_info_ctr
;
87 const char *binding
= torture_setting_string(tctx
, "binding", NULL
);
88 ctx
= talloc_zero(tctx
, struct DsSyncTest
);
89 if (!ctx
) return NULL
;
91 status
= dcerpc_parse_binding(ctx
, binding
, &ctx
->drsuapi_binding
);
92 if (!NT_STATUS_IS_OK(status
)) {
93 printf("Bad binding string %s\n", binding
);
96 ctx
->drsuapi_binding
->flags
|= DCERPC_SIGN
| DCERPC_SEAL
;
98 ctx
->ldap_url
= talloc_asprintf(ctx
, "ldap://%s/", ctx
->drsuapi_binding
->host
);
101 ctx
->admin
.credentials
= cmdline_credentials
;
103 our_bind_info28
= &ctx
->admin
.drsuapi
.our_bind_info28
;
104 our_bind_info28
->supported_extensions
= 0xFFFFFFFF;
105 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
;
106 our_bind_info28
->site_guid
= GUID_zero();
107 our_bind_info28
->u1
= 0;
108 our_bind_info28
->repl_epoch
= 1;
110 our_bind_info_ctr
= &ctx
->admin
.drsuapi
.our_bind_info_ctr
;
111 our_bind_info_ctr
->length
= 28;
112 our_bind_info_ctr
->info
.info28
= *our_bind_info28
;
114 GUID_from_string(DRSUAPI_DS_BIND_GUID
, &ctx
->admin
.drsuapi
.bind_guid
);
116 ctx
->admin
.drsuapi
.req
.in
.bind_guid
= &ctx
->admin
.drsuapi
.bind_guid
;
117 ctx
->admin
.drsuapi
.req
.in
.bind_info
= our_bind_info_ctr
;
118 ctx
->admin
.drsuapi
.req
.out
.bind_handle
= &ctx
->admin
.drsuapi
.bind_handle
;
121 ctx
->new_dc
.credentials
= cmdline_credentials
;
123 our_bind_info28
= &ctx
->new_dc
.drsuapi
.our_bind_info28
;
124 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_BASE
;
125 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION
;
126 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI
;
127 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2
;
128 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS
;
129 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1
;
130 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION
;
131 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE
;
132 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2
;
133 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION
;
134 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2
;
135 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD
;
136 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND
;
137 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO
;
138 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION
;
139 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01
;
140 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP
;
141 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY
;
142 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3
;
143 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2
;
144 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6
;
145 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS
;
146 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
;
147 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5
;
148 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6
;
149 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
;
150 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7
;
151 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT
;
152 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "xpress", false)) {
153 our_bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS
;
155 our_bind_info28
->site_guid
= GUID_zero();
156 our_bind_info28
->u1
= 508;
157 our_bind_info28
->repl_epoch
= 0;
159 our_bind_info_ctr
= &ctx
->new_dc
.drsuapi
.our_bind_info_ctr
;
160 our_bind_info_ctr
->length
= 28;
161 our_bind_info_ctr
->info
.info28
= *our_bind_info28
;
163 GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3
, &ctx
->new_dc
.drsuapi
.bind_guid
);
165 ctx
->new_dc
.drsuapi
.req
.in
.bind_guid
= &ctx
->new_dc
.drsuapi
.bind_guid
;
166 ctx
->new_dc
.drsuapi
.req
.in
.bind_info
= our_bind_info_ctr
;
167 ctx
->new_dc
.drsuapi
.req
.out
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
169 ctx
->new_dc
.invocation_id
= ctx
->new_dc
.drsuapi
.bind_guid
;
176 static bool _test_DsBind(struct torture_context
*tctx
,
177 struct DsSyncTest
*ctx
, struct cli_credentials
*credentials
, struct DsSyncBindInfo
*b
)
182 status
= dcerpc_pipe_connect_b(ctx
,
183 &b
->pipe
, ctx
->drsuapi_binding
,
185 credentials
, tctx
->ev
, tctx
->lp_ctx
);
187 if (!NT_STATUS_IS_OK(status
)) {
188 printf("Failed to connect to server as a BDC: %s\n", nt_errstr(status
));
192 status
= dcerpc_drsuapi_DsBind(b
->pipe
, ctx
, &b
->req
);
193 if (!NT_STATUS_IS_OK(status
)) {
194 const char *errstr
= nt_errstr(status
);
195 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
196 errstr
= dcerpc_errstr(ctx
, b
->pipe
->last_fault_code
);
198 printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr
);
200 } else if (!W_ERROR_IS_OK(b
->req
.out
.result
)) {
201 printf("DsBind failed - %s\n", win_errstr(b
->req
.out
.result
));
205 ZERO_STRUCT(b
->peer_bind_info28
);
206 if (b
->req
.out
.bind_info
) {
207 switch (b
->req
.out
.bind_info
->length
) {
209 struct drsuapi_DsBindInfo24
*info24
;
210 info24
= &b
->req
.out
.bind_info
->info
.info24
;
211 b
->peer_bind_info28
.supported_extensions
= info24
->supported_extensions
;
212 b
->peer_bind_info28
.site_guid
= info24
->site_guid
;
213 b
->peer_bind_info28
.u1
= info24
->u1
;
214 b
->peer_bind_info28
.repl_epoch
= 0;
218 b
->peer_bind_info28
= b
->req
.out
.bind_info
->info
.info28
;
226 static bool test_LDAPBind(struct torture_context
*tctx
, struct DsSyncTest
*ctx
,
227 struct cli_credentials
*credentials
, struct DsSyncLDAPInfo
*l
)
232 status
= torture_ldap_connection(tctx
, &l
->conn
, ctx
->ldap_url
);
233 if (!NT_STATUS_IS_OK(status
)) {
234 printf("failed to connect to LDAP: %s\n", ctx
->ldap_url
);
238 printf("connected to LDAP: %s\n", ctx
->ldap_url
);
240 status
= torture_ldap_bind_sasl(l
->conn
, credentials
, tctx
->lp_ctx
);
241 if (!NT_STATUS_IS_OK(status
)) {
242 printf("failed to bind to LDAP:\n");
245 printf("bound to LDAP.\n");
250 static bool test_GetInfo(struct torture_context
*tctx
, struct DsSyncTest
*ctx
)
253 struct drsuapi_DsCrackNames r
;
254 struct drsuapi_DsNameString names
[1];
256 struct cldap_socket
*cldap
;
257 struct cldap_netlogon search
;
259 cldap
= cldap_socket_init(ctx
, tctx
->ev
, lp_iconv_convenience(tctx
->lp_ctx
));
261 r
.in
.bind_handle
= &ctx
->admin
.drsuapi
.bind_handle
;
263 r
.in
.req
.req1
.codepage
= 1252; /* western european */
264 r
.in
.req
.req1
.language
= 0x00000407; /* german */
265 r
.in
.req
.req1
.count
= 1;
266 r
.in
.req
.req1
.names
= names
;
267 r
.in
.req
.req1
.format_flags
= DRSUAPI_DS_NAME_FLAG_NO_FLAGS
;
268 r
.in
.req
.req1
.format_offered
= DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT
;
269 r
.in
.req
.req1
.format_desired
= DRSUAPI_DS_NAME_FORMAT_FQDN_1779
;
270 names
[0].str
= talloc_asprintf(ctx
, "%s\\", lp_workgroup(tctx
->lp_ctx
));
272 status
= dcerpc_drsuapi_DsCrackNames(ctx
->admin
.drsuapi
.pipe
, ctx
, &r
);
273 if (!NT_STATUS_IS_OK(status
)) {
274 const char *errstr
= nt_errstr(status
);
275 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
276 errstr
= dcerpc_errstr(ctx
, ctx
->admin
.drsuapi
.pipe
->last_fault_code
);
278 printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr
);
280 } else if (!W_ERROR_IS_OK(r
.out
.result
)) {
281 printf("DsCrackNames failed - %s\n", win_errstr(r
.out
.result
));
285 ctx
->domain_dn
= r
.out
.ctr
.ctr1
->array
[0].result_name
;
288 search
.in
.dest_address
= ctx
->drsuapi_binding
->host
;
289 search
.in
.dest_port
= lp_cldap_port(tctx
->lp_ctx
);
290 search
.in
.acct_control
= -1;
291 search
.in
.version
= NETLOGON_NT_VERSION_5
| NETLOGON_NT_VERSION_5EX
;
292 search
.in
.map_response
= true;
293 status
= cldap_netlogon(cldap
, ctx
, &search
);
294 if (!NT_STATUS_IS_OK(status
)) {
295 const char *errstr
= nt_errstr(status
);
296 ctx
->site_name
= talloc_asprintf(ctx
, "%s", "Default-First-Site-Name");
297 printf("cldap_netlogon() returned %s. Defaulting to Site-Name: %s\n", errstr
, ctx
->site_name
);
299 ctx
->site_name
= talloc_steal(ctx
, search
.out
.netlogon
.nt5_ex
.client_site
);
300 printf("cldap_netlogon() returned Client Site-Name: %s.\n",ctx
->site_name
);
301 printf("cldap_netlogon() returned Server Site-Name: %s.\n",search
.out
.netlogon
.nt5_ex
.server_site
);
307 static DATA_BLOB
decrypt_blob(TALLOC_CTX
*mem_ctx
,
308 const DATA_BLOB
*gensec_skey
,
310 struct drsuapi_DsReplicaObjectIdentifier
*id
,
312 const DATA_BLOB
*buffer
)
314 DATA_BLOB confounder
;
315 DATA_BLOB enc_buffer
;
317 struct MD5Context md5
;
318 uint8_t _enc_key
[16];
321 DATA_BLOB dec_buffer
;
323 uint32_t crc32_given
;
325 DATA_BLOB checked_buffer
;
327 DATA_BLOB plain_buffer
;
330 * the combination "c[3] s[1] e[1] d[0]..."
331 * was successful!!!!!!!!!!!!!!!!!!!!!!!!!!
335 * the first 16 bytes at the beginning are the confounder
336 * followed by the 4 byte crc32 checksum
338 if (buffer
->length
< 20) {
339 return data_blob_const(NULL
, 0);
341 confounder
= data_blob_const(buffer
->data
, 16);
342 enc_buffer
= data_blob_const(buffer
->data
+ 16, buffer
->length
- 16);
345 * build the encryption key md5 over the session key followed
348 * here the gensec session key is used and
349 * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
351 enc_key
= data_blob_const(_enc_key
, sizeof(_enc_key
));
353 MD5Update(&md5
, gensec_skey
->data
, gensec_skey
->length
);
354 MD5Update(&md5
, confounder
.data
, confounder
.length
);
355 MD5Final(enc_key
.data
, &md5
);
358 * copy the encrypted buffer part and
359 * decrypt it using the created encryption key using arcfour
361 dec_buffer
= data_blob_talloc(mem_ctx
, enc_buffer
.data
, enc_buffer
.length
);
362 if (!dec_buffer
.data
) {
363 return data_blob_const(NULL
, 0);
365 arcfour_crypt_blob(dec_buffer
.data
, dec_buffer
.length
, &enc_key
);
368 * the first 4 byte are the crc32 checksum
369 * of the remaining bytes
371 crc32_given
= IVAL(dec_buffer
.data
, 0);
372 crc32_calc
= crc32_calc_buffer(dec_buffer
.data
+ 4 , dec_buffer
.length
- 4);
373 if (crc32_given
!= crc32_calc
) {
374 DEBUG(0,("CRC32: given[0x%08X] calc[0x%08X]\n",
375 crc32_given
, crc32_calc
));
376 return data_blob_const(NULL
, 0);
378 checked_buffer
= data_blob_talloc(mem_ctx
, dec_buffer
.data
+ 4, dec_buffer
.length
- 4);
379 if (!checked_buffer
.data
) {
380 return data_blob_const(NULL
, 0);
384 * some attributes seem to be in a usable form after this decryption
385 * (supplementalCredentials, priorValue, currentValue, trustAuthOutgoing,
386 * trustAuthIncoming, initialAuthOutgoing, initialAuthIncoming)
387 * At least supplementalCredentials contains plaintext
388 * like "Primary:Kerberos" (in unicode form)
390 * some attributes seem to have some additional encryption
391 * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
393 * it's the sam_rid_crypt() function, as the value is constant,
394 * so it doesn't depend on sessionkeys.
397 uint32_t i
, num_hashes
;
399 if ((checked_buffer
.length
% 16) != 0) {
400 return data_blob_const(NULL
, 0);
403 plain_buffer
= data_blob_talloc(mem_ctx
, checked_buffer
.data
, checked_buffer
.length
);
404 if (!plain_buffer
.data
) {
405 return data_blob_const(NULL
, 0);
408 num_hashes
= plain_buffer
.length
/ 16;
409 for (i
= 0; i
< num_hashes
; i
++) {
410 uint32_t offset
= i
* 16;
411 sam_rid_crypt(rid
, checked_buffer
.data
+ offset
, plain_buffer
.data
+ offset
, 0);
414 plain_buffer
= checked_buffer
;
420 static void test_analyse_objects(struct torture_context
*tctx
,
421 struct DsSyncTest
*ctx
,
422 const DATA_BLOB
*gensec_skey
,
423 struct drsuapi_DsReplicaObjectListItemEx
*cur
)
425 static uint32_t object_id
;
426 const char *save_values_dir
;
428 if (!lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "print_pwd_blobs", false)) {
432 save_values_dir
= lp_parm_string(tctx
->lp_ctx
, NULL
, "dssync", "save_pwd_blobs_dir");
434 for (; cur
; cur
= cur
->next_object
) {
436 struct dom_sid
*sid
= NULL
;
438 bool dn_printed
= false;
441 if (!cur
->object
.identifier
) continue;
443 dn
= cur
->object
.identifier
->dn
;
444 if (cur
->object
.identifier
->sid
.num_auths
> 0) {
445 sid
= &cur
->object
.identifier
->sid
;
446 rid
= sid
->sub_auths
[sid
->num_auths
- 1];
449 for (i
=0; i
< cur
->object
.attribute_ctr
.num_attributes
; i
++) {
450 const char *name
= NULL
;
452 DATA_BLOB
*enc_data
= NULL
;
453 DATA_BLOB plain_data
;
454 struct drsuapi_DsReplicaAttribute
*attr
;
455 attr
= &cur
->object
.attribute_ctr
.attributes
[i
];
457 switch (attr
->attid
) {
458 case DRSUAPI_ATTRIBUTE_dBCSPwd
:
462 case DRSUAPI_ATTRIBUTE_unicodePwd
:
466 case DRSUAPI_ATTRIBUTE_ntPwdHistory
:
467 name
= "ntPwdHistory";
470 case DRSUAPI_ATTRIBUTE_lmPwdHistory
:
471 name
= "lmPwdHistory";
474 case DRSUAPI_ATTRIBUTE_supplementalCredentials
:
475 name
= "supplementalCredentials";
477 case DRSUAPI_ATTRIBUTE_priorValue
:
480 case DRSUAPI_ATTRIBUTE_currentValue
:
481 name
= "currentValue";
483 case DRSUAPI_ATTRIBUTE_trustAuthOutgoing
:
484 name
= "trustAuthOutgoing";
486 case DRSUAPI_ATTRIBUTE_trustAuthIncoming
:
487 name
= "trustAuthIncoming";
489 case DRSUAPI_ATTRIBUTE_initialAuthOutgoing
:
490 name
= "initialAuthOutgoing";
492 case DRSUAPI_ATTRIBUTE_initialAuthIncoming
:
493 name
= "initialAuthIncoming";
499 if (attr
->value_ctr
.num_values
!= 1) continue;
501 if (!attr
->value_ctr
.values
[0].blob
) continue;
503 enc_data
= attr
->value_ctr
.values
[0].blob
;
504 ZERO_STRUCT(plain_data
);
506 plain_data
= decrypt_blob(ctx
, gensec_skey
, rcrypt
,
507 cur
->object
.identifier
, rid
,
511 DEBUG(0,("DN[%u] %s\n", object_id
, dn
));
514 DEBUGADD(0,("ATTR: %s enc.length=%lu plain.length=%lu\n",
515 name
, (long)enc_data
->length
, (long)plain_data
.length
));
516 if (plain_data
.length
) {
517 dump_data(0, plain_data
.data
, plain_data
.length
);
518 if (save_values_dir
) {
520 fname
= talloc_asprintf(ctx
, "%s/%s%02d",
525 ok
= file_save(fname
, plain_data
.data
, plain_data
.length
);
527 DEBUGADD(0,("Failed to save '%s'\n", fname
));
533 dump_data(0, enc_data
->data
, enc_data
->length
);
539 static bool test_FetchData(struct torture_context
*tctx
, struct DsSyncTest
*ctx
)
544 uint64_t highest_usn
= 0;
545 const char *partition
= NULL
;
546 struct drsuapi_DsGetNCChanges r
;
547 struct drsuapi_DsReplicaObjectIdentifier nc
;
548 struct drsuapi_DsGetNCChangesCtr1
*ctr1
= NULL
;
549 struct drsuapi_DsGetNCChangesCtr6
*ctr6
= NULL
;
550 int32_t out_level
= 0;
551 struct GUID null_guid
;
552 struct dom_sid null_sid
;
553 DATA_BLOB gensec_skey
;
565 ZERO_STRUCT(null_guid
);
566 ZERO_STRUCT(null_sid
);
568 partition
= lp_parm_string(tctx
->lp_ctx
, NULL
, "dssync", "partition");
569 if (partition
== NULL
) {
570 partition
= ctx
->domain_dn
;
571 printf("dssync:partition not specified, defaulting to %s.\n", ctx
->domain_dn
);
574 highest_usn
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "highest_usn", 0);
576 array
[0].level
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "get_nc_changes_level", array
[0].level
);
578 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "print_pwd_blobs", false)) {
579 const struct samr_Password
*nthash
;
580 nthash
= cli_credentials_get_nt_hash(ctx
->new_dc
.credentials
, ctx
);
582 dump_data_pw("CREDENTIALS nthash:", nthash
->hash
, sizeof(nthash
->hash
));
585 status
= gensec_session_key(ctx
->new_dc
.drsuapi
.pipe
->conn
->security_state
.generic_state
,
587 if (!NT_STATUS_IS_OK(status
)) {
588 printf("failed to get gensec session key: %s\n", nt_errstr(status
));
592 for (i
=0; i
< ARRAY_SIZE(array
); i
++) {
593 printf("testing DsGetNCChanges level %d\n",
596 r
.in
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
597 r
.in
.level
= &array
[i
].level
;
599 switch (*r
.in
.level
) {
605 r
.in
.req
.req5
.destination_dsa_guid
= ctx
->new_dc
.invocation_id
;
606 r
.in
.req
.req5
.source_dsa_invocation_id
= null_guid
;
607 r
.in
.req
.req5
.naming_context
= &nc
;
608 r
.in
.req
.req5
.highwatermark
.tmp_highest_usn
= highest_usn
;
609 r
.in
.req
.req5
.highwatermark
.reserved_usn
= 0;
610 r
.in
.req
.req5
.highwatermark
.highest_usn
= highest_usn
;
611 r
.in
.req
.req5
.uptodateness_vector
= NULL
;
612 r
.in
.req
.req5
.replica_flags
= 0;
613 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "compression", false)) {
614 r
.in
.req
.req5
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES
;
616 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "neighbour_writeable", true)) {
617 r
.in
.req
.req5
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
;
619 r
.in
.req
.req5
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
620 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
621 | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS
622 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
624 r
.in
.req
.req5
.max_object_count
= 133;
625 r
.in
.req
.req5
.max_ndr_size
= 1336770;
626 r
.in
.req
.req5
.extended_op
= DRSUAPI_EXOP_NONE
;
627 r
.in
.req
.req5
.fsmo_info
= 0;
634 /* nc.dn can be set to any other ad partition */
636 r
.in
.req
.req8
.destination_dsa_guid
= ctx
->new_dc
.invocation_id
;
637 r
.in
.req
.req8
.source_dsa_invocation_id
= null_guid
;
638 r
.in
.req
.req8
.naming_context
= &nc
;
639 r
.in
.req
.req8
.highwatermark
.tmp_highest_usn
= highest_usn
;
640 r
.in
.req
.req8
.highwatermark
.reserved_usn
= 0;
641 r
.in
.req
.req8
.highwatermark
.highest_usn
= highest_usn
;
642 r
.in
.req
.req8
.uptodateness_vector
= NULL
;
643 r
.in
.req
.req8
.replica_flags
= 0;
644 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "compression", false)) {
645 r
.in
.req
.req8
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES
;
647 if (lp_parm_bool(tctx
->lp_ctx
, NULL
, "dssync", "neighbour_writeable", true)) {
648 r
.in
.req
.req8
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
;
650 r
.in
.req
.req8
.replica_flags
|= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
651 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
652 | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS
653 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
655 r
.in
.req
.req8
.max_object_count
= 402;
656 r
.in
.req
.req8
.max_ndr_size
= 402116;
658 r
.in
.req
.req8
.extended_op
= DRSUAPI_EXOP_NONE
;
659 r
.in
.req
.req8
.fsmo_info
= 0;
660 r
.in
.req
.req8
.partial_attribute_set
= NULL
;
661 r
.in
.req
.req8
.partial_attribute_set_ex
= NULL
;
662 r
.in
.req
.req8
.mapping_ctr
.num_mappings
= 0;
663 r
.in
.req
.req8
.mapping_ctr
.mappings
= NULL
;
668 printf("Dumping AD partition: %s\n", nc
.dn
);
672 r
.out
.level
= &_level
;
674 if (*r
.in
.level
== 5) {
675 DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y
,
676 (long long)r
.in
.req
.req5
.highwatermark
.tmp_highest_usn
,
677 (long long)r
.in
.req
.req5
.highwatermark
.highest_usn
));
680 if (*r
.in
.level
== 8) {
681 DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y
,
682 (long long)r
.in
.req
.req8
.highwatermark
.tmp_highest_usn
,
683 (long long)r
.in
.req
.req8
.highwatermark
.highest_usn
));
686 status
= dcerpc_drsuapi_DsGetNCChanges(ctx
->new_dc
.drsuapi
.pipe
, ctx
, &r
);
687 if (!NT_STATUS_IS_OK(status
)) {
688 const char *errstr
= nt_errstr(status
);
689 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
690 errstr
= dcerpc_errstr(ctx
, ctx
->new_dc
.drsuapi
.pipe
->last_fault_code
);
692 printf("dcerpc_drsuapi_DsGetNCChanges failed - %s\n", errstr
);
694 } else if (!W_ERROR_IS_OK(r
.out
.result
)) {
695 printf("DsGetNCChanges failed - %s\n", win_errstr(r
.out
.result
));
699 if (ret
== true && *r
.out
.level
== 1) {
701 ctr1
= &r
.out
.ctr
.ctr1
;
702 } else if (ret
== true && *r
.out
.level
== 2) {
704 ctr1
= r
.out
.ctr
.ctr2
.ctr
.mszip1
.ctr1
;
707 if (out_level
== 1) {
708 DEBUG(0,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y
,
709 (long long)ctr1
->new_highwatermark
.tmp_highest_usn
,
710 (long long)ctr1
->new_highwatermark
.highest_usn
));
712 test_analyse_objects(tctx
, ctx
, &gensec_skey
, ctr1
->first_object
);
714 if (ctr1
->new_highwatermark
.tmp_highest_usn
> ctr1
->new_highwatermark
.highest_usn
) {
715 r
.in
.req
.req5
.highwatermark
= ctr1
->new_highwatermark
;
720 if (ret
== true && *r
.out
.level
== 6) {
722 ctr6
= &r
.out
.ctr
.ctr6
;
723 } else if (ret
== true && *r
.out
.level
== 7
724 && r
.out
.ctr
.ctr7
.level
== 6
725 && r
.out
.ctr
.ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_MSZIP
) {
727 ctr6
= r
.out
.ctr
.ctr7
.ctr
.mszip6
.ctr6
;
728 } else if (ret
== true && *r
.out
.level
== 7
729 && r
.out
.ctr
.ctr7
.level
== 6
730 && r
.out
.ctr
.ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_XPRESS
) {
732 ctr6
= r
.out
.ctr
.ctr7
.ctr
.xpress6
.ctr6
;
735 if (out_level
== 6) {
736 DEBUG(0,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y
,
737 (long long)ctr6
->new_highwatermark
.tmp_highest_usn
,
738 (long long)ctr6
->new_highwatermark
.highest_usn
));
740 test_analyse_objects(tctx
, ctx
, &gensec_skey
, ctr6
->first_object
);
742 if (ctr6
->new_highwatermark
.tmp_highest_usn
> ctr6
->new_highwatermark
.highest_usn
) {
743 r
.in
.req
.req8
.highwatermark
= ctr6
->new_highwatermark
;
755 static bool test_FetchNT4Data(struct torture_context
*tctx
,
756 struct DsSyncTest
*ctx
)
760 struct drsuapi_DsGetNT4ChangeLog r
;
761 struct GUID null_guid
;
762 struct dom_sid null_sid
;
765 ZERO_STRUCT(null_guid
);
766 ZERO_STRUCT(null_sid
);
770 r
.in
.bind_handle
= &ctx
->new_dc
.drsuapi
.bind_handle
;
773 r
.in
.req
.req1
.unknown1
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "nt4-1", 3);
774 r
.in
.req
.req1
.unknown2
= lp_parm_int(tctx
->lp_ctx
, NULL
, "dssync", "nt4-2", 0x00004000);
777 r
.in
.req
.req1
.length
= cookie
.length
;
778 r
.in
.req
.req1
.data
= cookie
.data
;
780 status
= dcerpc_drsuapi_DsGetNT4ChangeLog(ctx
->new_dc
.drsuapi
.pipe
, ctx
, &r
);
781 if (!NT_STATUS_IS_OK(status
)) {
782 const char *errstr
= nt_errstr(status
);
783 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
784 errstr
= dcerpc_errstr(ctx
, ctx
->new_dc
.drsuapi
.pipe
->last_fault_code
);
786 printf("dcerpc_drsuapi_DsGetNT4ChangeLog failed - %s\n", errstr
);
788 } else if (W_ERROR_EQUAL(r
.out
.result
, WERR_INVALID_DOMAIN_ROLE
)) {
789 printf("DsGetNT4ChangeLog not supported by target server\n");
791 } else if (!W_ERROR_IS_OK(r
.out
.result
)) {
792 printf("DsGetNT4ChangeLog failed - %s\n", win_errstr(r
.out
.result
));
794 } else if (r
.out
.level
!= 1) {
795 printf("DsGetNT4ChangeLog unknown level - %u\n", r
.out
.level
);
797 } else if (NT_STATUS_IS_OK(r
.out
.info
.info1
.status
)) {
798 } else if (NT_STATUS_EQUAL(r
.out
.info
.info1
.status
, STATUS_MORE_ENTRIES
)) {
799 cookie
.length
= r
.out
.info
.info1
.length1
;
800 cookie
.data
= r
.out
.info
.info1
.data1
;
803 printf("DsGetNT4ChangeLog failed - %s\n", nt_errstr(r
.out
.info
.info1
.status
));
813 bool torture_rpc_dssync(struct torture_context
*torture
)
817 struct DsSyncTest
*ctx
;
819 mem_ctx
= talloc_init("torture_rpc_dssync");
820 ctx
= test_create_context(torture
);
822 ret
&= _test_DsBind(torture
, ctx
, ctx
->admin
.credentials
, &ctx
->admin
.drsuapi
);
826 ret
&= test_LDAPBind(torture
, ctx
, ctx
->admin
.credentials
, &ctx
->admin
.ldap
);
830 ret
&= test_GetInfo(torture
, ctx
);
831 ret
&= _test_DsBind(torture
, ctx
, ctx
->new_dc
.credentials
, &ctx
->new_dc
.drsuapi
);
835 ret
&= test_FetchData(torture
, ctx
);
836 ret
&= test_FetchNT4Data(torture
, ctx
);