Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : DRSUapi tests
5 :
6 : Copyright (C) Andrew Tridgell 2003
7 : Copyright (C) Stefan (metze) Metzmacher 2004
8 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
9 :
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.
14 :
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.
19 :
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/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "librpc/gen_ndr/ndr_drsuapi_c.h"
26 : #include "torture/rpc/torture_rpc.h"
27 : #include "param/param.h"
28 :
29 : #define TEST_MACHINE_NAME "torturetest"
30 :
31 4 : bool test_DsBind(struct dcerpc_pipe *p,
32 : struct torture_context *tctx,
33 : struct DsPrivate *priv)
34 : {
35 : NTSTATUS status;
36 : struct drsuapi_DsBind r;
37 : struct drsuapi_DsBindInfo28 *bind_info28;
38 : struct drsuapi_DsBindInfoCtr bind_info_ctr;
39 :
40 4 : ZERO_STRUCT(bind_info_ctr);
41 4 : bind_info_ctr.length = 28;
42 :
43 4 : bind_info28 = &bind_info_ctr.info.info28;
44 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
45 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
46 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
47 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
48 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
49 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
50 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
51 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
52 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
53 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
54 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
55 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
56 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
57 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
58 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
59 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
60 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
61 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
62 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
63 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
64 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
65 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
66 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
67 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
68 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
69 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
70 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
71 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
72 :
73 4 : GUID_from_string(DRSUAPI_DS_BIND_GUID, &priv->bind_guid);
74 :
75 4 : r.in.bind_guid = &priv->bind_guid;
76 4 : r.in.bind_info = &bind_info_ctr;
77 4 : r.out.bind_handle = &priv->bind_handle;
78 :
79 4 : torture_comment(tctx, "Testing DsBind\n");
80 :
81 4 : status = dcerpc_drsuapi_DsBind_r(p->binding_handle, tctx, &r);
82 6 : torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsBind");
83 :
84 : /* cache server supported extensions, i.e. bind_info */
85 2 : priv->srv_bind_info = r.out.bind_info->info.info28;
86 :
87 2 : return true;
88 : }
89 :
90 1 : static bool test_DsGetDomainControllerInfo(struct torture_context *tctx,
91 : struct DsPrivate *priv)
92 : {
93 : NTSTATUS status;
94 1 : struct dcerpc_pipe *p = priv->drs_pipe;
95 : struct drsuapi_DsGetDomainControllerInfo r;
96 : union drsuapi_DsGetDCInfoCtr ctr;
97 : union drsuapi_DsGetDCInfoRequest req;
98 1 : int32_t level_out = 0;
99 1 : bool found = false;
100 : int i, j, k;
101 :
102 : struct {
103 : const char *name;
104 : WERROR expected;
105 2 : } names[] = {
106 : {
107 1 : .name = torture_join_dom_netbios_name(priv->join),
108 : .expected = WERR_OK
109 : },
110 : {
111 1 : .name = torture_join_dom_dns_name(priv->join),
112 : .expected = WERR_OK
113 : },
114 : {
115 : .name = "__UNKNOWN_DOMAIN__",
116 : .expected = WERR_DS_OBJ_NOT_FOUND
117 : },
118 : {
119 : .name = "unknown.domain.samba.example.com",
120 : .expected = WERR_DS_OBJ_NOT_FOUND
121 : },
122 : };
123 1 : int levels[] = {1, 2};
124 : int level;
125 :
126 1 : for (i=0; i < ARRAY_SIZE(levels); i++) {
127 3 : for (j=0; j < ARRAY_SIZE(names); j++) {
128 3 : level = levels[i];
129 3 : r.in.bind_handle = &priv->bind_handle;
130 3 : r.in.level = 1;
131 3 : r.in.req = &req;
132 :
133 3 : r.in.req->req1.domain_name = names[j].name;
134 3 : r.in.req->req1.level = level;
135 :
136 3 : r.out.ctr = &ctr;
137 3 : r.out.level_out = &level_out;
138 :
139 6 : torture_comment(tctx,
140 : "Testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
141 6 : r.in.req->req1.level, r.in.req->req1.domain_name);
142 :
143 3 : status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(p->binding_handle, tctx, &r);
144 3 : torture_assert_ntstatus_ok(tctx, status,
145 : "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
146 3 : torture_assert_werr_equal(tctx,
147 : r.out.result, names[j].expected,
148 : "DsGetDomainControllerInfo level with dns domain failed");
149 :
150 2 : if (!W_ERROR_IS_OK(r.out.result)) {
151 : /* If this was an error, we can't read the result structure */
152 0 : continue;
153 : }
154 :
155 2 : torture_assert_int_equal(tctx,
156 : r.in.req->req1.level, *r.out.level_out,
157 : "dcerpc_drsuapi_DsGetDomainControllerInfo in/out level differs");
158 :
159 2 : switch (level) {
160 2 : case 1:
161 4 : for (k=0; k < r.out.ctr->ctr1.count; k++) {
162 4 : if (strcasecmp_m(r.out.ctr->ctr1.array[k].netbios_name,
163 : torture_join_netbios_name(priv->join)) == 0) {
164 2 : found = true;
165 2 : break;
166 : }
167 : }
168 2 : break;
169 0 : case 2:
170 0 : for (k=0; k < r.out.ctr->ctr2.count; k++) {
171 0 : if (strcasecmp_m(r.out.ctr->ctr2.array[k].netbios_name,
172 : torture_join_netbios_name(priv->join)) == 0) {
173 0 : found = true;
174 0 : priv->dcinfo = r.out.ctr->ctr2.array[k];
175 0 : break;
176 : }
177 : }
178 0 : break;
179 : }
180 2 : torture_assert(tctx, found,
181 : "dcerpc_drsuapi_DsGetDomainControllerInfo: Failed to find the domain controller we just created during the join");
182 : }
183 : }
184 :
185 0 : r.in.bind_handle = &priv->bind_handle;
186 0 : r.in.level = 1;
187 :
188 0 : r.out.ctr = &ctr;
189 0 : r.out.level_out = &level_out;
190 :
191 0 : r.in.req->req1.domain_name = "__UNKNOWN_DOMAIN__"; /* This is clearly ignored for this level */
192 0 : r.in.req->req1.level = -1;
193 :
194 0 : torture_comment(tctx, "Testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
195 0 : r.in.req->req1.level, r.in.req->req1.domain_name);
196 :
197 0 : status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(p->binding_handle, tctx, &r);
198 :
199 0 : torture_assert_ntstatus_ok(tctx, status,
200 : "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
201 0 : torture_assert_werr_ok(tctx, r.out.result,
202 : "DsGetDomainControllerInfo with dns domain failed");
203 :
204 : {
205 0 : const char *dc_account = talloc_asprintf(tctx, "%s\\%s$",
206 : torture_join_dom_netbios_name(priv->join),
207 : priv->dcinfo.netbios_name);
208 0 : torture_comment(tctx, "%s: Enum active LDAP sessions searching for %s\n", __func__, dc_account);
209 0 : for (k=0; k < r.out.ctr->ctr01.count; k++) {
210 0 : if (strcasecmp_m(r.out.ctr->ctr01.array[k].client_account,
211 : dc_account)) {
212 0 : found = true;
213 0 : break;
214 : }
215 : }
216 0 : torture_assert(tctx, found,
217 : "dcerpc_drsuapi_DsGetDomainControllerInfo level: Failed to find the domain controller in last logon records");
218 : }
219 :
220 :
221 0 : return true;
222 : }
223 :
224 1 : static bool test_DsWriteAccountSpn(struct torture_context *tctx,
225 : struct DsPrivate *priv)
226 : {
227 : NTSTATUS status;
228 1 : struct dcerpc_pipe *p = priv->drs_pipe;
229 : struct drsuapi_DsWriteAccountSpn r;
230 : union drsuapi_DsWriteAccountSpnRequest req;
231 : struct drsuapi_DsNameString names[2];
232 : union drsuapi_DsWriteAccountSpnResult res;
233 : uint32_t level_out;
234 :
235 1 : r.in.bind_handle = &priv->bind_handle;
236 1 : r.in.level = 1;
237 1 : r.in.req = &req;
238 :
239 1 : torture_comment(tctx, "Testing DsWriteAccountSpn\n");
240 :
241 1 : r.in.req->req1.operation = DRSUAPI_DS_SPN_OPERATION_ADD;
242 1 : r.in.req->req1.unknown1 = 0;
243 1 : r.in.req->req1.object_dn = priv->dcinfo.computer_dn;
244 1 : r.in.req->req1.count = 2;
245 1 : r.in.req->req1.spn_names = names;
246 1 : names[0].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.netbios_name);
247 1 : names[1].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.dns_name);
248 :
249 1 : r.out.res = &res;
250 1 : r.out.level_out = &level_out;
251 :
252 1 : status = dcerpc_drsuapi_DsWriteAccountSpn_r(p->binding_handle, tctx, &r);
253 1 : torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsWriteAccountSpn");
254 :
255 1 : r.in.req->req1.operation = DRSUAPI_DS_SPN_OPERATION_DELETE;
256 1 : r.in.req->req1.unknown1 = 0;
257 :
258 1 : status = dcerpc_drsuapi_DsWriteAccountSpn_r(p->binding_handle, tctx, &r);
259 1 : torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsWriteAccountSpn");
260 :
261 1 : return true;
262 : }
263 :
264 1 : static bool test_DsReplicaGetInfo(struct torture_context *tctx,
265 : struct DsPrivate *priv)
266 : {
267 : NTSTATUS status;
268 1 : struct dcerpc_pipe *p = priv->drs_pipe;
269 : struct drsuapi_DsReplicaGetInfo r;
270 : union drsuapi_DsReplicaGetInfoRequest req;
271 : union drsuapi_DsReplicaInfo info;
272 : enum drsuapi_DsReplicaInfoType info_type;
273 : int i;
274 : struct {
275 : int32_t level;
276 : int32_t infotype;
277 : const char *obj_dn;
278 1 : } array[] = {
279 : {
280 : DRSUAPI_DS_REPLICA_GET_INFO,
281 : DRSUAPI_DS_REPLICA_INFO_NEIGHBORS,
282 : NULL
283 : },{
284 : DRSUAPI_DS_REPLICA_GET_INFO,
285 : DRSUAPI_DS_REPLICA_INFO_CURSORS,
286 : NULL
287 : },{
288 : DRSUAPI_DS_REPLICA_GET_INFO,
289 : DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA,
290 : NULL
291 : },{
292 : DRSUAPI_DS_REPLICA_GET_INFO,
293 : DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES,
294 : NULL
295 : },{
296 : DRSUAPI_DS_REPLICA_GET_INFO,
297 : DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES,
298 : NULL
299 : },{
300 : DRSUAPI_DS_REPLICA_GET_INFO,
301 : DRSUAPI_DS_REPLICA_INFO_PENDING_OPS,
302 : NULL
303 : },{
304 : DRSUAPI_DS_REPLICA_GET_INFO2,
305 : DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA,
306 : NULL
307 : },{
308 : DRSUAPI_DS_REPLICA_GET_INFO2,
309 : DRSUAPI_DS_REPLICA_INFO_CURSORS2,
310 : NULL
311 : },{
312 : DRSUAPI_DS_REPLICA_GET_INFO2,
313 : DRSUAPI_DS_REPLICA_INFO_CURSORS3,
314 : NULL
315 : },{
316 : DRSUAPI_DS_REPLICA_GET_INFO2,
317 : DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2,
318 : NULL
319 : },{
320 : DRSUAPI_DS_REPLICA_GET_INFO2,
321 : DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2,
322 : NULL
323 : },{
324 : DRSUAPI_DS_REPLICA_GET_INFO2,
325 : DRSUAPI_DS_REPLICA_INFO_REPSTO,
326 : NULL
327 : },{
328 : DRSUAPI_DS_REPLICA_GET_INFO2,
329 : DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS,
330 : "__IGNORED__"
331 : },{
332 : DRSUAPI_DS_REPLICA_GET_INFO2,
333 : DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1,
334 : NULL
335 : },{
336 : DRSUAPI_DS_REPLICA_GET_INFO2,
337 : DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS,
338 : NULL
339 : }
340 : };
341 :
342 1 : if (torture_setting_bool(tctx, "samba4", false)) {
343 1 : torture_comment(tctx, "skipping DsReplicaGetInfo test against Samba4\n");
344 1 : return true;
345 : }
346 :
347 0 : r.in.bind_handle = &priv->bind_handle;
348 0 : r.in.req = &req;
349 :
350 0 : for (i=0; i < ARRAY_SIZE(array); i++) {
351 : const char *object_dn;
352 :
353 0 : torture_comment(tctx, "Testing DsReplicaGetInfo level %d infotype %d\n",
354 : array[i].level, array[i].infotype);
355 :
356 0 : object_dn = (array[i].obj_dn ? array[i].obj_dn : priv->domain_obj_dn);
357 :
358 0 : r.in.level = array[i].level;
359 0 : switch(r.in.level) {
360 0 : case DRSUAPI_DS_REPLICA_GET_INFO:
361 0 : r.in.req->req1.info_type = array[i].infotype;
362 0 : r.in.req->req1.object_dn = object_dn;
363 0 : ZERO_STRUCT(r.in.req->req1.source_dsa_guid);
364 0 : break;
365 0 : case DRSUAPI_DS_REPLICA_GET_INFO2:
366 0 : r.in.req->req2.info_type = array[i].infotype;
367 0 : r.in.req->req2.object_dn = object_dn;
368 0 : ZERO_STRUCT(r.in.req->req2.source_dsa_guid);
369 0 : r.in.req->req2.flags = 0;
370 0 : r.in.req->req2.attribute_name = NULL;
371 0 : r.in.req->req2.value_dn_str = NULL;
372 0 : r.in.req->req2.enumeration_context = 0;
373 0 : break;
374 : }
375 :
376 0 : r.out.info = &info;
377 0 : r.out.info_type = &info_type;
378 :
379 0 : status = dcerpc_drsuapi_DsReplicaGetInfo_r(p->binding_handle, tctx, &r);
380 0 : torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaGetInfo");
381 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
382 0 : torture_comment(tctx,
383 : "DsReplicaGetInfo level %d and/or infotype %d not supported by server\n",
384 : array[i].level, array[i].infotype);
385 : } else {
386 0 : torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaGetInfo");
387 : }
388 : }
389 :
390 0 : return true;
391 : }
392 :
393 1 : static bool test_DsReplicaSync(struct torture_context *tctx,
394 : struct DsPrivate *priv)
395 : {
396 : NTSTATUS status;
397 1 : struct dcerpc_pipe *p = priv->drs_pipe;
398 : int i;
399 : struct drsuapi_DsReplicaSync r;
400 : union drsuapi_DsReplicaSyncRequest sync_req;
401 : struct drsuapi_DsReplicaObjectIdentifier nc;
402 : struct dom_sid null_sid;
403 : struct {
404 : int32_t level;
405 1 : } array[] = {
406 : {
407 : 1
408 : }
409 : };
410 :
411 1 : if (!torture_setting_bool(tctx, "dangerous", false)) {
412 1 : torture_comment(tctx, "DsReplicaSync disabled - enable dangerous tests to use\n");
413 1 : return true;
414 : }
415 :
416 0 : if (torture_setting_bool(tctx, "samba4", false)) {
417 0 : torture_comment(tctx, "skipping DsReplicaSync test against Samba4\n");
418 0 : return true;
419 : }
420 :
421 0 : ZERO_STRUCT(null_sid);
422 :
423 0 : r.in.bind_handle = &priv->bind_handle;
424 :
425 0 : for (i=0; i < ARRAY_SIZE(array); i++) {
426 0 : torture_comment(tctx, "Testing DsReplicaSync level %d\n",
427 : array[i].level);
428 :
429 0 : r.in.level = array[i].level;
430 0 : switch(r.in.level) {
431 0 : case 1:
432 0 : nc.guid = GUID_zero();
433 0 : nc.sid = null_sid;
434 0 : nc.dn = priv->domain_obj_dn?priv->domain_obj_dn:"";
435 :
436 0 : sync_req.req1.naming_context = &nc;
437 0 : sync_req.req1.source_dsa_guid = priv->dcinfo.ntds_guid;
438 0 : sync_req.req1.source_dsa_dns = NULL;
439 0 : sync_req.req1.options = 16;
440 :
441 0 : r.in.req = &sync_req;
442 0 : break;
443 : }
444 :
445 0 : status = dcerpc_drsuapi_DsReplicaSync_r(p->binding_handle, tctx, &r);
446 0 : torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaSync");
447 : }
448 :
449 0 : return true;
450 : }
451 :
452 1 : static bool test_DsReplicaUpdateRefs(struct torture_context *tctx,
453 : struct DsPrivate *priv)
454 : {
455 : NTSTATUS status;
456 1 : struct dcerpc_pipe *p = priv->drs_pipe;
457 : struct drsuapi_DsReplicaUpdateRefs r;
458 : struct drsuapi_DsReplicaObjectIdentifier nc;
459 : struct GUID dest_dsa_guid;
460 : const char *dest_dsa_guid_str;
461 : struct dom_sid null_sid;
462 :
463 1 : ZERO_STRUCT(null_sid);
464 1 : dest_dsa_guid = GUID_random();
465 1 : dest_dsa_guid_str = GUID_string(tctx, &dest_dsa_guid);
466 :
467 1 : r.in.bind_handle = &priv->bind_handle;
468 1 : r.in.level = 1; /* Only version 1 is defined presently */
469 :
470 : /* setup NC */
471 1 : nc.guid = priv->domain_obj_dn ? GUID_zero():priv->domain_guid;
472 1 : nc.sid = null_sid;
473 1 : nc.dn = priv->domain_obj_dn ? priv->domain_obj_dn : "";
474 :
475 : /* default setup for request */
476 1 : r.in.req.req1.naming_context = &nc;
477 1 : r.in.req.req1.dest_dsa_dns_name = talloc_asprintf(tctx, "%s._msdn.%s",
478 : dest_dsa_guid_str,
479 : priv->domain_dns_name);
480 1 : r.in.req.req1.dest_dsa_guid = dest_dsa_guid;
481 :
482 : /* 1. deleting replica dest should fail */
483 1 : torture_comment(tctx, "delete: %s\n", r.in.req.req1.dest_dsa_dns_name);
484 1 : r.in.req.req1.options = DRSUAPI_DRS_DEL_REF;
485 1 : status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
486 1 : torture_drsuapi_assert_call_werr(tctx, p,
487 : status, WERR_DS_DRA_REF_NOT_FOUND, &r,
488 : "dcerpc_drsuapi_DsReplicaUpdateRefs");
489 :
490 : /* 2. hopefully adding random replica dest should succeed */
491 1 : torture_comment(tctx, "add : %s\n", r.in.req.req1.dest_dsa_dns_name);
492 1 : r.in.req.req1.options = DRSUAPI_DRS_ADD_REF;
493 1 : status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
494 1 : torture_drsuapi_assert_call_werr(tctx, p,
495 : status, WERR_OK, &r,
496 : "dcerpc_drsuapi_DsReplicaUpdateRefs");
497 :
498 : /* 3. try adding same replica dest - should fail */
499 1 : torture_comment(tctx, "add : %s\n", r.in.req.req1.dest_dsa_dns_name);
500 1 : r.in.req.req1.options = DRSUAPI_DRS_ADD_REF;
501 1 : status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
502 1 : torture_drsuapi_assert_call_werr(tctx, p,
503 : status, WERR_DS_DRA_REF_ALREADY_EXISTS, &r,
504 : "dcerpc_drsuapi_DsReplicaUpdateRefs");
505 :
506 : /* 4. try resetting same replica dest - should succeed */
507 1 : torture_comment(tctx, "reset : %s\n", r.in.req.req1.dest_dsa_dns_name);
508 1 : r.in.req.req1.options = DRSUAPI_DRS_DEL_REF | DRSUAPI_DRS_ADD_REF;
509 1 : status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
510 1 : torture_drsuapi_assert_call_werr(tctx, p,
511 : status, WERR_OK, &r,
512 : "dcerpc_drsuapi_DsReplicaUpdateRefs");
513 :
514 : /* 5. delete random replicate added at step 2. */
515 1 : torture_comment(tctx, "delete : %s\n", r.in.req.req1.dest_dsa_dns_name);
516 1 : r.in.req.req1.options = DRSUAPI_DRS_DEL_REF;
517 1 : status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
518 1 : torture_drsuapi_assert_call_werr(tctx, p,
519 : status, WERR_OK, &r,
520 : "dcerpc_drsuapi_DsReplicaUpdateRefs");
521 :
522 : /* 6. try replace on non-existing replica dest - should succeed */
523 1 : torture_comment(tctx, "replace: %s\n", r.in.req.req1.dest_dsa_dns_name);
524 1 : r.in.req.req1.options = DRSUAPI_DRS_DEL_REF | DRSUAPI_DRS_ADD_REF;
525 1 : status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
526 1 : torture_drsuapi_assert_call_werr(tctx, p,
527 : status, WERR_OK, &r,
528 : "dcerpc_drsuapi_DsReplicaUpdateRefs");
529 :
530 : /* 7. delete random replicate added at step 6. */
531 1 : torture_comment(tctx, "delete : %s\n", r.in.req.req1.dest_dsa_dns_name);
532 1 : r.in.req.req1.options = DRSUAPI_DRS_DEL_REF;
533 1 : status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
534 1 : torture_drsuapi_assert_call_werr(tctx, p,
535 : status, WERR_OK, &r,
536 : "dcerpc_drsuapi_DsReplicaUpdateRefs");
537 :
538 1 : return true;
539 : }
540 :
541 1 : static bool test_DsGetNCChanges(struct torture_context *tctx,
542 : struct DsPrivate *priv)
543 : {
544 : NTSTATUS status;
545 1 : struct dcerpc_pipe *p = priv->drs_pipe;
546 : int i;
547 : struct drsuapi_DsGetNCChanges r;
548 : union drsuapi_DsGetNCChangesRequest req;
549 : union drsuapi_DsGetNCChangesCtr ctr;
550 : struct drsuapi_DsReplicaObjectIdentifier nc;
551 : struct dom_sid null_sid;
552 : uint32_t level_out;
553 : struct {
554 : uint32_t level;
555 1 : } array[] = {
556 : {
557 : 5
558 : },
559 : {
560 : 8
561 : }
562 : };
563 :
564 1 : if (torture_setting_bool(tctx, "samba4", false)) {
565 1 : torture_comment(tctx, "skipping DsGetNCChanges test against Samba4\n");
566 1 : return true;
567 : }
568 :
569 0 : ZERO_STRUCT(null_sid);
570 :
571 0 : for (i=0; i < ARRAY_SIZE(array); i++) {
572 0 : torture_comment(tctx,
573 : "Testing DsGetNCChanges level %d\n",
574 : array[i].level);
575 :
576 0 : r.in.bind_handle = &priv->bind_handle;
577 0 : r.in.level = array[i].level;
578 0 : r.out.level_out = &level_out;
579 0 : r.out.ctr = &ctr;
580 :
581 0 : switch (r.in.level) {
582 0 : case 5:
583 0 : nc.guid = GUID_zero();
584 0 : nc.sid = null_sid;
585 0 : nc.dn = priv->domain_obj_dn ? priv->domain_obj_dn : "";
586 :
587 0 : r.in.req = &req;
588 0 : r.in.req->req5.destination_dsa_guid = GUID_random();
589 0 : r.in.req->req5.source_dsa_invocation_id = GUID_zero();
590 0 : r.in.req->req5.naming_context = &nc;
591 0 : r.in.req->req5.highwatermark.tmp_highest_usn = 0;
592 0 : r.in.req->req5.highwatermark.reserved_usn = 0;
593 0 : r.in.req->req5.highwatermark.highest_usn = 0;
594 0 : r.in.req->req5.uptodateness_vector = NULL;
595 0 : r.in.req->req5.replica_flags = 0;
596 0 : if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "compression", false)) {
597 0 : r.in.req->req5.replica_flags |= DRSUAPI_DRS_USE_COMPRESSION;
598 : }
599 0 : r.in.req->req5.max_object_count = 0;
600 0 : r.in.req->req5.max_ndr_size = 0;
601 0 : r.in.req->req5.extended_op = DRSUAPI_EXOP_NONE;
602 0 : r.in.req->req5.fsmo_info = 0;
603 :
604 0 : break;
605 0 : case 8:
606 0 : nc.guid = GUID_zero();
607 0 : nc.sid = null_sid;
608 0 : nc.dn = priv->domain_obj_dn ? priv->domain_obj_dn : "";
609 :
610 0 : r.in.req = &req;
611 0 : r.in.req->req8.destination_dsa_guid = GUID_random();
612 0 : r.in.req->req8.source_dsa_invocation_id = GUID_zero();
613 0 : r.in.req->req8.naming_context = &nc;
614 0 : r.in.req->req8.highwatermark.tmp_highest_usn = 0;
615 0 : r.in.req->req8.highwatermark.reserved_usn = 0;
616 0 : r.in.req->req8.highwatermark.highest_usn = 0;
617 0 : r.in.req->req8.uptodateness_vector = NULL;
618 0 : r.in.req->req8.replica_flags = 0;
619 0 : if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "compression", false)) {
620 0 : r.in.req->req8.replica_flags |= DRSUAPI_DRS_USE_COMPRESSION;
621 : }
622 0 : if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "neighbour_writeable", true)) {
623 0 : r.in.req->req8.replica_flags |= DRSUAPI_DRS_WRIT_REP;
624 : }
625 0 : r.in.req->req8.replica_flags |= DRSUAPI_DRS_INIT_SYNC
626 : | DRSUAPI_DRS_PER_SYNC
627 : | DRSUAPI_DRS_GET_ANC
628 : | DRSUAPI_DRS_NEVER_SYNCED
629 : ;
630 0 : r.in.req->req8.max_object_count = 402;
631 0 : r.in.req->req8.max_ndr_size = 402116;
632 0 : r.in.req->req8.extended_op = DRSUAPI_EXOP_NONE;
633 0 : r.in.req->req8.fsmo_info = 0;
634 0 : r.in.req->req8.partial_attribute_set = NULL;
635 0 : r.in.req->req8.partial_attribute_set_ex = NULL;
636 0 : r.in.req->req8.mapping_ctr.num_mappings = 0;
637 0 : r.in.req->req8.mapping_ctr.mappings = NULL;
638 :
639 0 : break;
640 : }
641 :
642 0 : status = dcerpc_drsuapi_DsGetNCChanges_r(p->binding_handle, tctx, &r);
643 0 : torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsGetNCChanges");
644 : }
645 :
646 0 : return true;
647 : }
648 :
649 0 : bool test_QuerySitesByCost(struct torture_context *tctx,
650 : struct DsPrivate *priv)
651 : {
652 : NTSTATUS status;
653 0 : struct dcerpc_pipe *p = priv->drs_pipe;
654 : struct drsuapi_QuerySitesByCost r;
655 : union drsuapi_QuerySitesByCostRequest req;
656 :
657 0 : const char *my_site = "Default-First-Site-Name";
658 0 : const char *remote_site1 = "smbtorture-nonexisting-site1";
659 0 : const char *remote_site2 = "smbtorture-nonexisting-site2";
660 :
661 0 : req.req1.site_from = talloc_strdup(tctx, my_site);
662 0 : req.req1.num_req = 2;
663 0 : req.req1.site_to = talloc_zero_array(tctx, const char *, 2);
664 0 : req.req1.site_to[0] = talloc_strdup(tctx, remote_site1);
665 0 : req.req1.site_to[1] = talloc_strdup(tctx, remote_site2);
666 0 : req.req1.flags = 0;
667 :
668 0 : r.in.bind_handle = &priv->bind_handle;
669 0 : r.in.level = 1;
670 0 : r.in.req = &req;
671 :
672 0 : status = dcerpc_drsuapi_QuerySitesByCost_r(p->binding_handle, tctx, &r);
673 0 : torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_QuerySitesByCost");
674 :
675 0 : if (W_ERROR_IS_OK(r.out.result)) {
676 0 : torture_assert_werr_equal(tctx,
677 : r.out.ctr->ctr1.info[0].error_code, WERR_DS_OBJ_NOT_FOUND,
678 : "dcerpc_drsuapi_QuerySitesByCost");
679 0 : torture_assert_werr_equal(tctx,
680 : r.out.ctr->ctr1.info[1].error_code, WERR_DS_OBJ_NOT_FOUND,
681 : "dcerpc_drsuapi_QuerySitesByCost expected error_code WERR_DS_OBJ_NOT_FOUND");
682 :
683 0 : torture_assert_int_equal(tctx,
684 : r.out.ctr->ctr1.info[0].site_cost, -1,
685 : "dcerpc_drsuapi_QuerySitesByCost");
686 0 : torture_assert_int_equal(tctx,
687 : r.out.ctr->ctr1.info[1].site_cost, -1,
688 : "dcerpc_drsuapi_QuerySitesByCost exptected site cost");
689 : }
690 :
691 0 : return true;
692 :
693 :
694 : }
695 :
696 0 : bool test_DsUnbind(struct dcerpc_pipe *p,
697 : struct torture_context *tctx,
698 : struct DsPrivate *priv)
699 : {
700 : NTSTATUS status;
701 : struct drsuapi_DsUnbind r;
702 :
703 0 : r.in.bind_handle = &priv->bind_handle;
704 0 : r.out.bind_handle = &priv->bind_handle;
705 :
706 0 : torture_comment(tctx, "Testing DsUnbind\n");
707 :
708 0 : status = dcerpc_drsuapi_DsUnbind_r(p->binding_handle, tctx, &r);
709 0 : torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsUnbind");
710 :
711 0 : return true;
712 : }
713 :
714 :
715 : /**
716 : * Helper func to collect DC information for testing purposes.
717 : * This function is almost identical to test_DsGetDomainControllerInfo
718 : */
719 2 : bool torture_rpc_drsuapi_get_dcinfo(struct torture_context *torture,
720 : struct DsPrivate *priv)
721 : {
722 : NTSTATUS status;
723 2 : int32_t level_out = 0;
724 : struct drsuapi_DsGetDomainControllerInfo r;
725 : union drsuapi_DsGetDCInfoCtr ctr;
726 : int j, k;
727 4 : const char *names[] = {
728 2 : torture_join_dom_netbios_name(priv->join),
729 2 : torture_join_dom_dns_name(priv->join)};
730 :
731 2 : for (j=0; j < ARRAY_SIZE(names); j++) {
732 : union drsuapi_DsGetDCInfoRequest req;
733 2 : struct dcerpc_binding_handle *b = priv->drs_pipe->binding_handle;
734 2 : r.in.bind_handle = &priv->bind_handle;
735 2 : r.in.level = 1;
736 2 : r.in.req = &req;
737 :
738 2 : r.in.req->req1.domain_name = names[j];
739 2 : r.in.req->req1.level = 2;
740 :
741 2 : r.out.ctr = &ctr;
742 2 : r.out.level_out = &level_out;
743 :
744 2 : status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(b, torture, &r);
745 2 : if (!NT_STATUS_IS_OK(status)) {
746 0 : continue;
747 : }
748 2 : if (!W_ERROR_IS_OK(r.out.result)) {
749 : /* If this was an error, we can't read the result structure */
750 0 : continue;
751 : }
752 :
753 3 : for (k=0; k < r.out.ctr->ctr2.count; k++) {
754 3 : if (strcasecmp_m(r.out.ctr->ctr2.array[k].netbios_name,
755 : torture_join_netbios_name(priv->join)) == 0) {
756 2 : priv->dcinfo = r.out.ctr->ctr2.array[k];
757 2 : return true;
758 : }
759 : }
760 : }
761 :
762 0 : return false;
763 : }
764 :
765 : /**
766 : * Common test case setup function to be used
767 : * in DRS suit of test when appropriate
768 : */
769 4 : bool torture_drsuapi_tcase_setup_common(struct torture_context *tctx, struct DsPrivate *priv)
770 : {
771 : NTSTATUS status;
772 4 : int rnd = rand() % 1000;
773 4 : char *name = talloc_asprintf(tctx, "%s%d", TEST_MACHINE_NAME, rnd);
774 : struct cli_credentials *machine_credentials;
775 :
776 4 : torture_assert(tctx, priv, "Invalid argument");
777 :
778 4 : torture_comment(tctx, "Create DRSUAPI pipe\n");
779 4 : status = torture_rpc_connection(tctx,
780 : &priv->drs_pipe,
781 : &ndr_table_drsuapi);
782 4 : torture_assert(tctx, NT_STATUS_IS_OK(status), "Unable to connect to DRSUAPI pipe");
783 :
784 4 : torture_comment(tctx, "About to join domain with name %s\n", name);
785 4 : priv->join = torture_join_domain(tctx, name, ACB_SVRTRUST,
786 : &machine_credentials);
787 4 : torture_assert(tctx, priv->join, "Failed to join as BDC");
788 :
789 4 : if (!test_DsBind(priv->drs_pipe, tctx, priv)) {
790 : /* clean up */
791 2 : torture_drsuapi_tcase_teardown_common(tctx, priv);
792 2 : torture_fail(tctx, "Failed execute test_DsBind()");
793 : }
794 :
795 : /* try collect some information for testing */
796 2 : torture_rpc_drsuapi_get_dcinfo(tctx, priv);
797 :
798 2 : return true;
799 : }
800 :
801 : /**
802 : * Common test case teardown function to be used
803 : * in DRS suit of test when appropriate
804 : */
805 4 : bool torture_drsuapi_tcase_teardown_common(struct torture_context *tctx, struct DsPrivate *priv)
806 : {
807 4 : if (priv->join) {
808 4 : torture_leave_domain(tctx, priv->join);
809 : }
810 :
811 4 : return true;
812 : }
813 :
814 : /**
815 : * Test case setup for DRSUAPI test case
816 : */
817 3 : static bool torture_drsuapi_tcase_setup(struct torture_context *tctx, void **data)
818 : {
819 : struct DsPrivate *priv;
820 :
821 3 : *data = priv = talloc_zero(tctx, struct DsPrivate);
822 :
823 3 : return torture_drsuapi_tcase_setup_common(tctx, priv);
824 : }
825 :
826 : /**
827 : * Test case tear-down for DRSUAPI test case
828 : */
829 1 : static bool torture_drsuapi_tcase_teardown(struct torture_context *tctx, void *data)
830 : {
831 : bool ret;
832 1 : struct DsPrivate *priv = talloc_get_type(data, struct DsPrivate);
833 :
834 1 : ret = torture_drsuapi_tcase_teardown_common(tctx, priv);
835 :
836 1 : talloc_free(priv);
837 1 : return ret;
838 : }
839 :
840 : /**
841 : * DRSUAPI test case implementation
842 : */
843 2355 : void torture_rpc_drsuapi_tcase(struct torture_suite *suite)
844 : {
845 : typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
846 :
847 2355 : struct torture_tcase *tcase = torture_suite_add_tcase(suite, "drsuapi");
848 :
849 2355 : torture_tcase_set_fixture(tcase, torture_drsuapi_tcase_setup,
850 : torture_drsuapi_tcase_teardown);
851 :
852 : #if 0
853 : test = torture_tcase_add_simple_test(tcase, "QuerySitesByCost", (run_func)test_QuerySitesByCost);
854 : #endif
855 :
856 2355 : torture_tcase_add_simple_test(tcase, "DsGetDomainControllerInfo", (run_func)test_DsGetDomainControllerInfo);
857 :
858 2355 : torture_tcase_add_simple_test(tcase, "DsCrackNames", (run_func)test_DsCrackNames);
859 :
860 2355 : torture_tcase_add_simple_test(tcase, "DsWriteAccountSpn", (run_func)test_DsWriteAccountSpn);
861 :
862 2355 : torture_tcase_add_simple_test(tcase, "DsReplicaGetInfo", (run_func)test_DsReplicaGetInfo);
863 :
864 2355 : torture_tcase_add_simple_test(tcase, "DsReplicaSync", (run_func)test_DsReplicaSync);
865 :
866 2355 : torture_tcase_add_simple_test(tcase, "DsReplicaUpdateRefs", (run_func)test_DsReplicaUpdateRefs);
867 :
868 2355 : torture_tcase_add_simple_test(tcase, "DsGetNCChanges", (run_func)test_DsGetNCChanges);
869 2355 : }
|