s4-dsdb:large_ldap: Fix typos in variable names
[Samba.git] / source4 / torture / rpc / drsuapi.c
blobd3e18ca246bb7f5ed1602d9a6b226aa2eec2eaf7
1 /*
2 Unix SMB/CIFS implementation.
4 DRSUapi tests
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Stefan (metze) Metzmacher 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "lib/cmdline/cmdline.h"
26 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
27 #include "torture/rpc/torture_rpc.h"
28 #include "libcli/security/dom_sid.h"
29 #include "param/param.h"
31 #define TEST_MACHINE_NAME "torturetest"
33 static bool test_DsBind(struct dcerpc_pipe *p,
34 struct torture_context *tctx,
35 struct policy_handle *bind_handle,
36 struct drsuapi_DsBindInfo28 *srv_info28)
38 NTSTATUS status;
39 struct drsuapi_DsBind r;
40 struct GUID bind_guid;
41 struct drsuapi_DsBindInfo28 *bind_info28;
42 struct drsuapi_DsBindInfoCtr bind_info_ctr;
44 ZERO_STRUCT(bind_info_ctr);
45 bind_info_ctr.length = 28;
47 bind_info28 = &bind_info_ctr.info.info28;
48 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
49 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
50 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
51 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
52 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
53 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
54 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
55 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
56 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
57 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
58 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
59 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
60 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
61 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
62 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
63 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
64 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
65 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
66 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
67 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
68 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
69 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
70 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
71 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
72 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
73 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
74 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
75 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
77 GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
79 r.in.bind_guid = &bind_guid;
80 r.in.bind_info = &bind_info_ctr;
81 r.out.bind_handle = bind_handle;
83 torture_comment(tctx, "Testing DsBind\n");
85 status = dcerpc_drsuapi_DsBind_r(p->binding_handle, tctx, &r);
86 torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsBind");
88 if (srv_info28 != NULL) {
89 *srv_info28 = r.out.bind_info->info.info28;
92 return true;
95 static bool test_DsGetDomainControllerInfo(struct torture_context *tctx,
96 struct DsPrivate *priv)
98 NTSTATUS status;
99 struct dcerpc_pipe *p = priv->drs_pipe;
100 struct drsuapi_DsGetDomainControllerInfo r;
101 union drsuapi_DsGetDCInfoCtr ctr;
102 union drsuapi_DsGetDCInfoRequest req;
103 int32_t level_out = 0;
104 bool found = false;
105 int i, j, k;
107 struct {
108 const char *name;
109 WERROR expected;
110 } names[] = {
112 .name = torture_join_dom_netbios_name(priv->join),
113 .expected = WERR_OK
116 .name = torture_join_dom_dns_name(priv->join),
117 .expected = WERR_OK
120 .name = "__UNKNOWN_DOMAIN__",
121 .expected = WERR_DS_OBJ_NOT_FOUND
124 .name = "unknown.domain.samba.example.com",
125 .expected = WERR_DS_OBJ_NOT_FOUND
128 int levels[] = {1, 2};
129 int level;
131 for (i=0; i < ARRAY_SIZE(levels); i++) {
132 for (j=0; j < ARRAY_SIZE(names); j++) {
133 level = levels[i];
134 r.in.bind_handle = &priv->bind_handle;
135 r.in.level = 1;
136 r.in.req = &req;
138 r.in.req->req1.domain_name = names[j].name;
139 r.in.req->req1.level = level;
141 r.out.ctr = &ctr;
142 r.out.level_out = &level_out;
144 torture_comment(tctx,
145 "Testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
146 r.in.req->req1.level, r.in.req->req1.domain_name);
148 status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(p->binding_handle, tctx, &r);
149 torture_assert_ntstatus_ok(tctx, status,
150 "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
151 torture_assert_werr_equal(tctx,
152 r.out.result, names[j].expected,
153 "DsGetDomainControllerInfo level with dns domain failed");
155 if (!W_ERROR_IS_OK(r.out.result)) {
156 /* If this was an error, we can't read the result structure */
157 continue;
160 torture_assert_int_equal(tctx,
161 r.in.req->req1.level, *r.out.level_out,
162 "dcerpc_drsuapi_DsGetDomainControllerInfo in/out level differs");
164 switch (level) {
165 case 1:
166 for (k=0; k < r.out.ctr->ctr1.count; k++) {
167 if (strcasecmp_m(r.out.ctr->ctr1.array[k].netbios_name,
168 torture_join_netbios_name(priv->join)) == 0) {
169 found = true;
170 break;
173 break;
174 case 2:
175 for (k=0; k < r.out.ctr->ctr2.count; k++) {
176 if (strcasecmp_m(r.out.ctr->ctr2.array[k].netbios_name,
177 torture_join_netbios_name(priv->join)) == 0) {
178 found = true;
179 priv->dcinfo = r.out.ctr->ctr2.array[k];
180 break;
183 break;
185 torture_assert(tctx, found,
186 "dcerpc_drsuapi_DsGetDomainControllerInfo: Failed to find the domain controller we just created during the join");
190 r.in.bind_handle = &priv->bind_handle;
191 r.in.level = 1;
193 r.out.ctr = &ctr;
194 r.out.level_out = &level_out;
196 r.in.req->req1.domain_name = "__UNKNOWN_DOMAIN__"; /* This is clearly ignored for this level */
197 r.in.req->req1.level = -1;
199 torture_comment(tctx, "Testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
200 r.in.req->req1.level, r.in.req->req1.domain_name);
202 status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(p->binding_handle, tctx, &r);
204 torture_assert_ntstatus_ok(tctx, status,
205 "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
206 torture_assert_werr_ok(tctx, r.out.result,
207 "DsGetDomainControllerInfo with dns domain failed");
210 const char *dc_account = talloc_asprintf(tctx, "%s\\%s$",
211 torture_join_dom_netbios_name(priv->join),
212 priv->dcinfo.netbios_name);
213 torture_comment(tctx, "%s: Enum active LDAP sessions searching for %s\n", __func__, dc_account);
214 for (k=0; k < r.out.ctr->ctr01.count; k++) {
215 if (strcasecmp_m(r.out.ctr->ctr01.array[k].client_account,
216 dc_account)) {
217 found = true;
218 break;
221 torture_assert(tctx, found,
222 "dcerpc_drsuapi_DsGetDomainControllerInfo level: Failed to find the domain controller in last logon records");
226 return true;
229 static bool test_DsWriteAccountSpn(struct torture_context *tctx,
230 struct DsPrivate *priv)
232 NTSTATUS status;
233 struct dcerpc_pipe *p = priv->drs_pipe;
234 struct drsuapi_DsWriteAccountSpn r;
235 union drsuapi_DsWriteAccountSpnRequest req;
236 struct drsuapi_DsNameString names[2];
237 union drsuapi_DsWriteAccountSpnResult res;
238 uint32_t level_out;
240 r.in.bind_handle = &priv->bind_handle;
241 r.in.level = 1;
242 r.in.req = &req;
244 torture_comment(tctx, "Testing DsWriteAccountSpn\n");
246 r.in.req->req1.operation = DRSUAPI_DS_SPN_OPERATION_ADD;
247 r.in.req->req1.unknown1 = 0;
248 r.in.req->req1.object_dn = priv->dcinfo.computer_dn;
249 r.in.req->req1.count = 2;
250 r.in.req->req1.spn_names = names;
251 names[0].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.netbios_name);
252 names[1].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.dns_name);
254 r.out.res = &res;
255 r.out.level_out = &level_out;
257 status = dcerpc_drsuapi_DsWriteAccountSpn_r(p->binding_handle, tctx, &r);
258 torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsWriteAccountSpn");
260 r.in.req->req1.operation = DRSUAPI_DS_SPN_OPERATION_DELETE;
261 r.in.req->req1.unknown1 = 0;
263 status = dcerpc_drsuapi_DsWriteAccountSpn_r(p->binding_handle, tctx, &r);
264 torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsWriteAccountSpn");
266 return true;
269 static bool test_DsReplicaGetInfo(struct torture_context *tctx,
270 struct DsPrivate *priv)
272 NTSTATUS status;
273 struct dcerpc_pipe *p = priv->drs_pipe;
274 struct drsuapi_DsReplicaGetInfo r;
275 union drsuapi_DsReplicaGetInfoRequest req;
276 union drsuapi_DsReplicaInfo info;
277 enum drsuapi_DsReplicaInfoType info_type;
278 int i;
279 struct {
280 int32_t level;
281 int32_t infotype;
282 const char *obj_dn;
283 } array[] = {
285 DRSUAPI_DS_REPLICA_GET_INFO,
286 DRSUAPI_DS_REPLICA_INFO_NEIGHBORS,
287 NULL
289 DRSUAPI_DS_REPLICA_GET_INFO,
290 DRSUAPI_DS_REPLICA_INFO_CURSORS,
291 NULL
293 DRSUAPI_DS_REPLICA_GET_INFO,
294 DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA,
295 NULL
297 DRSUAPI_DS_REPLICA_GET_INFO,
298 DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES,
299 NULL
301 DRSUAPI_DS_REPLICA_GET_INFO,
302 DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES,
303 NULL
305 DRSUAPI_DS_REPLICA_GET_INFO,
306 DRSUAPI_DS_REPLICA_INFO_PENDING_OPS,
307 NULL
309 DRSUAPI_DS_REPLICA_GET_INFO2,
310 DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA,
311 NULL
313 DRSUAPI_DS_REPLICA_GET_INFO2,
314 DRSUAPI_DS_REPLICA_INFO_CURSORS2,
315 NULL
317 DRSUAPI_DS_REPLICA_GET_INFO2,
318 DRSUAPI_DS_REPLICA_INFO_CURSORS3,
319 NULL
321 DRSUAPI_DS_REPLICA_GET_INFO2,
322 DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2,
323 NULL
325 DRSUAPI_DS_REPLICA_GET_INFO2,
326 DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2,
327 NULL
329 DRSUAPI_DS_REPLICA_GET_INFO2,
330 DRSUAPI_DS_REPLICA_INFO_REPSTO,
331 NULL
333 DRSUAPI_DS_REPLICA_GET_INFO2,
334 DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS,
335 "__IGNORED__"
337 DRSUAPI_DS_REPLICA_GET_INFO2,
338 DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1,
339 NULL
341 DRSUAPI_DS_REPLICA_GET_INFO2,
342 DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS,
343 NULL
347 if (torture_setting_bool(tctx, "samba4", false)) {
348 torture_comment(tctx, "skipping DsReplicaGetInfo test against Samba4\n");
349 return true;
352 r.in.bind_handle = &priv->bind_handle;
353 r.in.req = &req;
355 for (i=0; i < ARRAY_SIZE(array); i++) {
356 const char *object_dn;
358 torture_comment(tctx, "Testing DsReplicaGetInfo level %d infotype %d\n",
359 array[i].level, array[i].infotype);
361 object_dn = (array[i].obj_dn ? array[i].obj_dn : priv->domain_obj_dn);
363 r.in.level = array[i].level;
364 switch(r.in.level) {
365 case DRSUAPI_DS_REPLICA_GET_INFO:
366 r.in.req->req1.info_type = array[i].infotype;
367 r.in.req->req1.object_dn = object_dn;
368 ZERO_STRUCT(r.in.req->req1.source_dsa_guid);
369 break;
370 case DRSUAPI_DS_REPLICA_GET_INFO2:
371 r.in.req->req2.info_type = array[i].infotype;
372 r.in.req->req2.object_dn = object_dn;
373 ZERO_STRUCT(r.in.req->req2.source_dsa_guid);
374 r.in.req->req2.flags = 0;
375 r.in.req->req2.attribute_name = NULL;
376 r.in.req->req2.value_dn_str = NULL;
377 r.in.req->req2.enumeration_context = 0;
378 break;
381 r.out.info = &info;
382 r.out.info_type = &info_type;
384 status = dcerpc_drsuapi_DsReplicaGetInfo_r(p->binding_handle, tctx, &r);
385 torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaGetInfo");
386 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
387 torture_comment(tctx,
388 "DsReplicaGetInfo level %d and/or infotype %d not supported by server\n",
389 array[i].level, array[i].infotype);
390 } else {
391 torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaGetInfo");
395 return true;
398 static bool test_DsReplicaSync(struct torture_context *tctx,
399 struct DsPrivate *priv)
401 NTSTATUS status;
402 struct dcerpc_pipe *p = priv->drs_pipe;
403 int i;
404 struct drsuapi_DsReplicaSync r;
405 union drsuapi_DsReplicaSyncRequest sync_req;
406 struct drsuapi_DsReplicaObjectIdentifier nc;
407 struct dom_sid null_sid;
408 struct {
409 int32_t level;
410 } array[] = {
416 if (!torture_setting_bool(tctx, "dangerous", false)) {
417 torture_comment(tctx, "DsReplicaSync disabled - enable dangerous tests to use\n");
418 return true;
421 if (torture_setting_bool(tctx, "samba4", false)) {
422 torture_comment(tctx, "skipping DsReplicaSync test against Samba4\n");
423 return true;
426 ZERO_STRUCT(null_sid);
428 r.in.bind_handle = &priv->bind_handle;
430 for (i=0; i < ARRAY_SIZE(array); i++) {
431 torture_comment(tctx, "Testing DsReplicaSync level %d\n",
432 array[i].level);
434 r.in.level = array[i].level;
435 switch(r.in.level) {
436 case 1:
437 nc.guid = GUID_zero();
438 nc.sid = null_sid;
439 nc.dn = priv->domain_obj_dn?priv->domain_obj_dn:"";
441 sync_req.req1.naming_context = &nc;
442 sync_req.req1.source_dsa_guid = priv->dcinfo.ntds_guid;
443 sync_req.req1.source_dsa_dns = NULL;
444 sync_req.req1.options = 16;
446 r.in.req = &sync_req;
447 break;
450 status = dcerpc_drsuapi_DsReplicaSync_r(p->binding_handle, tctx, &r);
451 torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaSync");
454 return true;
457 static bool test_DsReplicaUpdateRefs(struct torture_context *tctx,
458 struct DsPrivate *priv)
460 NTSTATUS status;
461 struct dcerpc_pipe *p = priv->drs_pipe;
462 struct drsuapi_DsReplicaUpdateRefs r;
463 struct drsuapi_DsReplicaObjectIdentifier nc;
464 struct GUID dest_dsa_guid;
465 const char *dest_dsa_guid_str;
466 struct dom_sid null_sid;
468 ZERO_STRUCT(null_sid);
469 dest_dsa_guid = GUID_random();
470 dest_dsa_guid_str = GUID_string(tctx, &dest_dsa_guid);
472 r.in.bind_handle = &priv->bind_handle;
473 r.in.level = 1; /* Only version 1 is defined presently */
475 /* setup NC */
476 nc.guid = priv->domain_obj_dn ? GUID_zero():priv->domain_guid;
477 nc.sid = null_sid;
478 nc.dn = priv->domain_obj_dn ? priv->domain_obj_dn : "";
480 /* default setup for request */
481 r.in.req.req1.naming_context = &nc;
482 r.in.req.req1.dest_dsa_dns_name = talloc_asprintf(tctx, "%s._msdn.%s",
483 dest_dsa_guid_str,
484 priv->domain_dns_name);
485 r.in.req.req1.dest_dsa_guid = dest_dsa_guid;
487 /* 1. deleting replica dest should fail */
488 torture_comment(tctx, "delete: %s\n", r.in.req.req1.dest_dsa_dns_name);
489 r.in.req.req1.options = DRSUAPI_DRS_DEL_REF;
490 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
491 torture_drsuapi_assert_call_werr(tctx, p,
492 status, WERR_DS_DRA_REF_NOT_FOUND, &r,
493 "dcerpc_drsuapi_DsReplicaUpdateRefs");
495 /* 2. hopefully adding random replica dest should succeed */
496 torture_comment(tctx, "add : %s\n", r.in.req.req1.dest_dsa_dns_name);
497 r.in.req.req1.options = DRSUAPI_DRS_ADD_REF;
498 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
499 torture_drsuapi_assert_call_werr(tctx, p,
500 status, WERR_OK, &r,
501 "dcerpc_drsuapi_DsReplicaUpdateRefs");
503 /* 3. try adding same replica dest - should fail */
504 torture_comment(tctx, "add : %s\n", r.in.req.req1.dest_dsa_dns_name);
505 r.in.req.req1.options = DRSUAPI_DRS_ADD_REF;
506 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
507 torture_drsuapi_assert_call_werr(tctx, p,
508 status, WERR_DS_DRA_REF_ALREADY_EXISTS, &r,
509 "dcerpc_drsuapi_DsReplicaUpdateRefs");
511 /* 4. try resetting same replica dest - should succeed */
512 torture_comment(tctx, "reset : %s\n", r.in.req.req1.dest_dsa_dns_name);
513 r.in.req.req1.options = DRSUAPI_DRS_DEL_REF | DRSUAPI_DRS_ADD_REF;
514 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
515 torture_drsuapi_assert_call_werr(tctx, p,
516 status, WERR_OK, &r,
517 "dcerpc_drsuapi_DsReplicaUpdateRefs");
519 /* 5. delete random replicate added at step 2. */
520 torture_comment(tctx, "delete : %s\n", r.in.req.req1.dest_dsa_dns_name);
521 r.in.req.req1.options = DRSUAPI_DRS_DEL_REF;
522 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
523 torture_drsuapi_assert_call_werr(tctx, p,
524 status, WERR_OK, &r,
525 "dcerpc_drsuapi_DsReplicaUpdateRefs");
527 /* 6. try replace on non-existing replica dest - should succeed */
528 torture_comment(tctx, "replace: %s\n", r.in.req.req1.dest_dsa_dns_name);
529 r.in.req.req1.options = DRSUAPI_DRS_DEL_REF | DRSUAPI_DRS_ADD_REF;
530 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
531 torture_drsuapi_assert_call_werr(tctx, p,
532 status, WERR_OK, &r,
533 "dcerpc_drsuapi_DsReplicaUpdateRefs");
535 /* 7. delete random replicate added at step 6. */
536 torture_comment(tctx, "delete : %s\n", r.in.req.req1.dest_dsa_dns_name);
537 r.in.req.req1.options = DRSUAPI_DRS_DEL_REF;
538 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
539 torture_drsuapi_assert_call_werr(tctx, p,
540 status, WERR_OK, &r,
541 "dcerpc_drsuapi_DsReplicaUpdateRefs");
543 return true;
546 static bool test_DsGetNCChanges(struct torture_context *tctx,
547 struct DsPrivate *priv)
549 NTSTATUS status;
550 struct dcerpc_pipe *p = priv->drs_pipe;
551 int i;
552 struct drsuapi_DsGetNCChanges r;
553 union drsuapi_DsGetNCChangesRequest req;
554 union drsuapi_DsGetNCChangesCtr ctr;
555 struct drsuapi_DsReplicaObjectIdentifier nc;
556 struct dom_sid null_sid;
557 uint32_t level_out;
558 struct {
559 uint32_t level;
560 } array[] = {
569 if (torture_setting_bool(tctx, "samba4", false)) {
570 torture_comment(tctx, "skipping DsGetNCChanges test against Samba4\n");
571 return true;
574 ZERO_STRUCT(null_sid);
576 for (i=0; i < ARRAY_SIZE(array); i++) {
577 torture_comment(tctx,
578 "Testing DsGetNCChanges level %d\n",
579 array[i].level);
581 r.in.bind_handle = &priv->bind_handle;
582 r.in.level = array[i].level;
583 r.out.level_out = &level_out;
584 r.out.ctr = &ctr;
586 switch (r.in.level) {
587 case 5:
588 nc.guid = GUID_zero();
589 nc.sid = null_sid;
590 nc.dn = priv->domain_obj_dn ? priv->domain_obj_dn : "";
592 r.in.req = &req;
593 r.in.req->req5.destination_dsa_guid = GUID_random();
594 r.in.req->req5.source_dsa_invocation_id = GUID_zero();
595 r.in.req->req5.naming_context = &nc;
596 r.in.req->req5.highwatermark.tmp_highest_usn = 0;
597 r.in.req->req5.highwatermark.reserved_usn = 0;
598 r.in.req->req5.highwatermark.highest_usn = 0;
599 r.in.req->req5.uptodateness_vector = NULL;
600 r.in.req->req5.replica_flags = 0;
601 if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "compression", false)) {
602 r.in.req->req5.replica_flags |= DRSUAPI_DRS_USE_COMPRESSION;
604 r.in.req->req5.max_object_count = 0;
605 r.in.req->req5.max_ndr_size = 0;
606 r.in.req->req5.extended_op = DRSUAPI_EXOP_NONE;
607 r.in.req->req5.fsmo_info = 0;
609 break;
610 case 8:
611 nc.guid = GUID_zero();
612 nc.sid = null_sid;
613 nc.dn = priv->domain_obj_dn ? priv->domain_obj_dn : "";
615 r.in.req = &req;
616 r.in.req->req8.destination_dsa_guid = GUID_random();
617 r.in.req->req8.source_dsa_invocation_id = GUID_zero();
618 r.in.req->req8.naming_context = &nc;
619 r.in.req->req8.highwatermark.tmp_highest_usn = 0;
620 r.in.req->req8.highwatermark.reserved_usn = 0;
621 r.in.req->req8.highwatermark.highest_usn = 0;
622 r.in.req->req8.uptodateness_vector = NULL;
623 r.in.req->req8.replica_flags = 0;
624 if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "compression", false)) {
625 r.in.req->req8.replica_flags |= DRSUAPI_DRS_USE_COMPRESSION;
627 if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "neighbour_writeable", true)) {
628 r.in.req->req8.replica_flags |= DRSUAPI_DRS_WRIT_REP;
630 r.in.req->req8.replica_flags |= DRSUAPI_DRS_INIT_SYNC
631 | DRSUAPI_DRS_PER_SYNC
632 | DRSUAPI_DRS_GET_ANC
633 | DRSUAPI_DRS_NEVER_SYNCED
635 r.in.req->req8.max_object_count = 402;
636 r.in.req->req8.max_ndr_size = 402116;
637 r.in.req->req8.extended_op = DRSUAPI_EXOP_NONE;
638 r.in.req->req8.fsmo_info = 0;
639 r.in.req->req8.partial_attribute_set = NULL;
640 r.in.req->req8.partial_attribute_set_ex = NULL;
641 r.in.req->req8.mapping_ctr.num_mappings = 0;
642 r.in.req->req8.mapping_ctr.mappings = NULL;
644 break;
647 status = dcerpc_drsuapi_DsGetNCChanges_r(p->binding_handle, tctx, &r);
648 torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsGetNCChanges");
651 return true;
654 bool test_QuerySitesByCost(struct torture_context *tctx,
655 struct DsPrivate *priv)
657 NTSTATUS status;
658 struct dcerpc_pipe *p = priv->drs_pipe;
659 struct drsuapi_QuerySitesByCost r;
660 union drsuapi_QuerySitesByCostRequest req;
662 const char *my_site = "Default-First-Site-Name";
663 const char *remote_site1 = "smbtorture-nonexisting-site1";
664 const char *remote_site2 = "smbtorture-nonexisting-site2";
666 req.req1.site_from = talloc_strdup(tctx, my_site);
667 req.req1.num_req = 2;
668 req.req1.site_to = talloc_zero_array(tctx, const char *, 2);
669 req.req1.site_to[0] = talloc_strdup(tctx, remote_site1);
670 req.req1.site_to[1] = talloc_strdup(tctx, remote_site2);
671 req.req1.flags = 0;
673 r.in.bind_handle = &priv->bind_handle;
674 r.in.level = 1;
675 r.in.req = &req;
677 status = dcerpc_drsuapi_QuerySitesByCost_r(p->binding_handle, tctx, &r);
678 torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_QuerySitesByCost");
680 if (W_ERROR_IS_OK(r.out.result)) {
681 torture_assert_werr_equal(tctx,
682 r.out.ctr->ctr1.info[0].error_code, WERR_DS_OBJ_NOT_FOUND,
683 "dcerpc_drsuapi_QuerySitesByCost");
684 torture_assert_werr_equal(tctx,
685 r.out.ctr->ctr1.info[1].error_code, WERR_DS_OBJ_NOT_FOUND,
686 "dcerpc_drsuapi_QuerySitesByCost expected error_code WERR_DS_OBJ_NOT_FOUND");
688 torture_assert_int_equal(tctx,
689 r.out.ctr->ctr1.info[0].site_cost, -1,
690 "dcerpc_drsuapi_QuerySitesByCost");
691 torture_assert_int_equal(tctx,
692 r.out.ctr->ctr1.info[1].site_cost, -1,
693 "dcerpc_drsuapi_QuerySitesByCost exptected site cost");
696 return true;
701 bool test_DsUnbind(struct dcerpc_pipe *p,
702 struct torture_context *tctx,
703 struct DsPrivate *priv)
705 NTSTATUS status;
706 struct drsuapi_DsUnbind r;
708 r.in.bind_handle = &priv->bind_handle;
709 r.out.bind_handle = &priv->bind_handle;
711 torture_comment(tctx, "Testing DsUnbind\n");
713 status = dcerpc_drsuapi_DsUnbind_r(p->binding_handle, tctx, &r);
714 torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsUnbind");
716 return true;
721 * Helper func to collect DC information for testing purposes.
722 * This function is almost identical to test_DsGetDomainControllerInfo
724 bool torture_rpc_drsuapi_get_dcinfo(struct torture_context *torture,
725 struct DsPrivate *priv)
727 NTSTATUS status;
728 int32_t level_out = 0;
729 struct drsuapi_DsGetDomainControllerInfo r;
730 union drsuapi_DsGetDCInfoCtr ctr;
731 int j, k;
732 const char *names[] = {
733 torture_join_dom_netbios_name(priv->join),
734 torture_join_dom_dns_name(priv->join)};
736 for (j=0; j < ARRAY_SIZE(names); j++) {
737 union drsuapi_DsGetDCInfoRequest req;
738 struct dcerpc_binding_handle *b = priv->drs_pipe->binding_handle;
739 r.in.bind_handle = &priv->bind_handle;
740 r.in.level = 1;
741 r.in.req = &req;
743 r.in.req->req1.domain_name = names[j];
744 r.in.req->req1.level = 2;
746 r.out.ctr = &ctr;
747 r.out.level_out = &level_out;
749 status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(b, torture, &r);
750 if (!NT_STATUS_IS_OK(status)) {
751 continue;
753 if (!W_ERROR_IS_OK(r.out.result)) {
754 /* If this was an error, we can't read the result structure */
755 continue;
758 for (k=0; k < r.out.ctr->ctr2.count; k++) {
759 if (strcasecmp_m(r.out.ctr->ctr2.array[k].netbios_name,
760 torture_join_netbios_name(priv->join)) == 0) {
761 priv->dcinfo = r.out.ctr->ctr2.array[k];
762 return true;
767 return false;
771 * Common test case setup function to be used
772 * in DRS suit of test when appropriate
774 bool torture_drsuapi_tcase_setup_common(struct torture_context *tctx, struct DsPrivate *priv)
776 NTSTATUS status;
777 int rnd = rand() % 1000;
778 char *name = talloc_asprintf(tctx, "%s%d", TEST_MACHINE_NAME, rnd);
780 torture_assert(tctx, priv, "Invalid argument");
782 priv->admin_credentials = samba_cmdline_get_creds();
784 torture_comment(tctx, "Create DRSUAPI pipe\n");
785 status = torture_rpc_connection(tctx,
786 &priv->drs_pipe,
787 &ndr_table_drsuapi);
788 torture_assert(tctx, NT_STATUS_IS_OK(status), "Unable to connect to DRSUAPI pipe");
790 torture_comment(tctx, "About to join domain with name %s\n", name);
791 priv->join = torture_join_domain(tctx, name, ACB_SVRTRUST,
792 &priv->dc_credentials);
793 torture_assert(tctx, priv->join, "Failed to join as BDC");
795 if (!test_DsBind(priv->drs_pipe, tctx,
796 &priv->bind_handle,
797 &priv->srv_bind_info))
799 /* clean up */
800 torture_drsuapi_tcase_teardown_common(tctx, priv);
801 torture_fail(tctx, "Failed execute test_DsBind()");
804 /* try collect some information for testing */
805 torture_rpc_drsuapi_get_dcinfo(tctx, priv);
807 return true;
811 * Common test case teardown function to be used
812 * in DRS suit of test when appropriate
814 bool torture_drsuapi_tcase_teardown_common(struct torture_context *tctx, struct DsPrivate *priv)
816 if (priv->join) {
817 torture_leave_domain(tctx, priv->join);
820 return true;
824 * Test case setup for DRSUAPI test case
826 static bool torture_drsuapi_tcase_setup(struct torture_context *tctx, void **data)
828 struct DsPrivate *priv;
830 *data = priv = talloc_zero(tctx, struct DsPrivate);
832 return torture_drsuapi_tcase_setup_common(tctx, priv);
836 * Test case tear-down for DRSUAPI test case
838 static bool torture_drsuapi_tcase_teardown(struct torture_context *tctx, void *data)
840 bool ret;
841 struct DsPrivate *priv = talloc_get_type(data, struct DsPrivate);
843 ret = torture_drsuapi_tcase_teardown_common(tctx, priv);
845 talloc_free(priv);
846 return ret;
849 static bool __test_DsBind_assoc_group(struct torture_context *tctx,
850 const char *testname,
851 struct DsPrivate *priv,
852 struct cli_credentials *creds)
854 NTSTATUS status;
855 const char *err_msg;
856 struct drsuapi_DsCrackNames r;
857 union drsuapi_DsNameRequest req;
858 uint32_t level_out;
859 union drsuapi_DsNameCtr ctr;
860 struct drsuapi_DsNameString names[1];
861 const char *dom_sid = NULL;
862 struct dcerpc_pipe *p1 = NULL;
863 struct dcerpc_pipe *p2 = NULL;
864 TALLOC_CTX *mem_ctx = priv;
865 struct dcerpc_binding *binding = NULL;
866 struct policy_handle ds_bind_handle = { .handle_type = 0, };
868 torture_comment(tctx, "%s: starting...\n", testname);
870 torture_assert_ntstatus_ok(tctx,
871 torture_rpc_binding(tctx, &binding),
872 "torture_rpc_binding");
874 torture_assert_ntstatus_ok(tctx,
875 dcerpc_pipe_connect_b(tctx,
876 &p1,
877 binding,
878 &ndr_table_drsuapi,
879 creds,
880 tctx->ev,
881 tctx->lp_ctx),
882 "connect p1");
884 torture_assert_ntstatus_ok(tctx,
885 dcerpc_pipe_connect_b(tctx,
886 &p2,
887 p1->binding,
888 &ndr_table_drsuapi,
889 creds,
890 tctx->ev,
891 tctx->lp_ctx),
892 "connect p2");
894 torture_assert(tctx, test_DsBind(p1, tctx, &ds_bind_handle, NULL), "DsBind");
896 ZERO_STRUCT(r);
897 r.in.bind_handle = &ds_bind_handle;
898 r.in.level = 1;
899 r.in.req = &req;
900 r.in.req->req1.codepage = 1252; /* german */
901 r.in.req->req1.language = 0x00000407; /* german */
902 r.in.req->req1.count = 1;
903 r.in.req->req1.names = names;
904 r.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
906 r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
907 r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
909 r.out.level_out = &level_out;
910 r.out.ctr = &ctr;
912 dom_sid = dom_sid_string(mem_ctx, torture_join_sid(priv->join));
914 names[0].str = dom_sid;
916 torture_comment(tctx, "Testing DsCrackNames on p1 with name '%s'"
917 " offered format: %d desired format:%d\n",
918 names[0].str,
919 r.in.req->req1.format_offered,
920 r.in.req->req1.format_desired);
921 status = dcerpc_drsuapi_DsCrackNames_r(p1->binding_handle, mem_ctx, &r);
922 if (!NT_STATUS_IS_OK(status)) {
923 const char *errstr = nt_errstr(status);
924 err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
925 torture_fail(tctx, err_msg);
926 } else if (!W_ERROR_IS_OK(r.out.result)) {
927 err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
928 torture_fail(tctx, err_msg);
929 } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
930 err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
931 r.out.ctr->ctr1->array[0].status);
932 torture_fail(tctx, err_msg);
935 torture_comment(tctx, "Testing DsCrackNames on p2 with name '%s'"
936 " offered format: %d desired format:%d\n",
937 names[0].str,
938 r.in.req->req1.format_offered,
939 r.in.req->req1.format_desired);
940 status = dcerpc_drsuapi_DsCrackNames_r(p2->binding_handle, mem_ctx, &r);
941 if (!NT_STATUS_IS_OK(status)) {
942 const char *errstr = nt_errstr(status);
943 err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
944 torture_fail(tctx, err_msg);
945 } else if (!W_ERROR_IS_OK(r.out.result)) {
946 err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
947 torture_fail(tctx, err_msg);
948 } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
949 err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
950 r.out.ctr->ctr1->array[0].status);
951 torture_fail(tctx, err_msg);
954 TALLOC_FREE(p1);
956 torture_comment(tctx, "Testing DsCrackNames on p2 (with p1 closed) with name '%s'"
957 " offered format: %d desired format:%d\n",
958 names[0].str,
959 r.in.req->req1.format_offered,
960 r.in.req->req1.format_desired);
961 status = dcerpc_drsuapi_DsCrackNames_r(p2->binding_handle, mem_ctx, &r);
962 if (!NT_STATUS_IS_OK(status)) {
963 const char *errstr = nt_errstr(status);
964 err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
965 torture_fail(tctx, err_msg);
966 } else if (!W_ERROR_IS_OK(r.out.result)) {
967 err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
968 torture_fail(tctx, err_msg);
969 } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
970 err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
971 r.out.ctr->ctr1->array[0].status);
972 torture_fail(tctx, err_msg);
975 torture_comment(tctx, "%s: ... finished\n", testname);
976 return true;
979 static bool test_DsBindAssocGroupAdmin(struct torture_context *tctx,
980 struct DsPrivate *priv,
981 struct cli_credentials *creds)
983 return __test_DsBind_assoc_group(tctx, __func__, priv,
984 priv->admin_credentials);
987 static bool test_DsBindAssocGroupDC(struct torture_context *tctx,
988 struct DsPrivate *priv,
989 struct cli_credentials *creds)
991 return __test_DsBind_assoc_group(tctx, __func__, priv,
992 priv->dc_credentials);
995 static bool test_DsBindAssocGroupWS(struct torture_context *tctx,
996 struct DsPrivate *priv,
997 struct cli_credentials *creds)
999 struct test_join *wks_join = NULL;
1000 struct cli_credentials *wks_credentials = NULL;
1001 int rnd = rand() % 1000;
1002 char *wks_name = talloc_asprintf(tctx, "WKS%s%d", TEST_MACHINE_NAME, rnd);
1003 bool ret;
1005 torture_comment(tctx, "%s: About to join workstation with name %s\n",
1006 __func__, wks_name);
1007 wks_join = torture_join_domain(tctx, wks_name, ACB_WSTRUST,
1008 &wks_credentials);
1009 torture_assert(tctx, wks_join, "Failed to join as WORKSTATION");
1010 ret = __test_DsBind_assoc_group(tctx, __func__, priv,
1011 wks_credentials);
1012 torture_leave_domain(tctx, wks_join);
1013 return ret;
1017 * DRSUAPI test case implementation
1019 void torture_rpc_drsuapi_tcase(struct torture_suite *suite)
1021 typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
1023 struct torture_tcase *tcase = torture_suite_add_tcase(suite, "drsuapi");
1025 torture_tcase_set_fixture(tcase, torture_drsuapi_tcase_setup,
1026 torture_drsuapi_tcase_teardown);
1028 #if 0
1029 test = torture_tcase_add_simple_test(tcase, "QuerySitesByCost", (run_func)test_QuerySitesByCost);
1030 #endif
1032 torture_tcase_add_simple_test(tcase, "DsGetDomainControllerInfo", (run_func)test_DsGetDomainControllerInfo);
1034 torture_tcase_add_simple_test(tcase, "DsCrackNames", (run_func)test_DsCrackNames);
1036 torture_tcase_add_simple_test(tcase, "DsWriteAccountSpn", (run_func)test_DsWriteAccountSpn);
1038 torture_tcase_add_simple_test(tcase, "DsReplicaGetInfo", (run_func)test_DsReplicaGetInfo);
1040 torture_tcase_add_simple_test(tcase, "DsReplicaSync", (run_func)test_DsReplicaSync);
1042 torture_tcase_add_simple_test(tcase, "DsReplicaUpdateRefs", (run_func)test_DsReplicaUpdateRefs);
1044 torture_tcase_add_simple_test(tcase, "DsGetNCChanges", (run_func)test_DsGetNCChanges);
1046 torture_tcase_add_simple_test(tcase, "DsBindAssocGroupAdmin", (run_func)test_DsBindAssocGroupAdmin);
1047 torture_tcase_add_simple_test(tcase, "DsBindAssocGroupDC", (run_func)test_DsBindAssocGroupDC);
1048 torture_tcase_add_simple_test(tcase, "DsBindAssocGroupWS", (run_func)test_DsBindAssocGroupWS);