1/* 2 Unix SMB/CIFS implementation. 3 test suite for rpc dfs operations 4 5 Copyright (C) Andrew Tridgell 2003 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*/ 21 22#include "includes.h" 23#include "torture/torture.h" 24#include "torture/rpc/rpc.h" 25#include "librpc/gen_ndr/ndr_dfs_c.h" 26#include "librpc/gen_ndr/ndr_srvsvc_c.h" 27#include "libnet/libnet.h" 28#include "libcli/raw/libcliraw.h" 29#include "torture/util.h" 30#include "libcli/libcli.h" 31#include "lib/cmdline/popt_common.h" 32 33#define SMBTORTURE_DFS_SHARENAME "smbtorture_dfs_share" 34#define SMBTORTURE_DFS_DIRNAME "\\smbtorture_dfs_dir" 35#define SMBTORTURE_DFS_PATHNAME "C:"SMBTORTURE_DFS_DIRNAME 36 37#define IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(x,y)\ 38 if (x == DFS_MANAGER_VERSION_W2K3) {\ 39 if (!W_ERROR_EQUAL(y,WERR_NOT_SUPPORTED)) {\ 40 printf("expected WERR_NOT_SUPPORTED\n");\ 41 return false;\ 42 }\ 43 return true;\ 44 }\ 45 46static bool test_NetShareAdd(TALLOC_CTX *mem_ctx, 47 struct torture_context *tctx, 48 const char *host, 49 const char *sharename, 50 const char *dir) 51{ 52 NTSTATUS status; 53 struct srvsvc_NetShareInfo2 i; 54 struct libnet_context* libnetctx; 55 struct libnet_AddShare r; 56 57 printf("Creating share %s\n", sharename); 58 59 if (!(libnetctx = libnet_context_init(tctx->ev, tctx->lp_ctx))) { 60 return false; 61 } 62 63 libnetctx->cred = cmdline_credentials; 64 65 i.name = sharename; 66 i.type = STYPE_DISKTREE; 67 i.path = dir; 68 i.max_users = (uint32_t) -1; 69 i.comment = "created by smbtorture"; 70 i.password = NULL; 71 i.permissions = 0x0; 72 i.current_users = 0x0; 73 74 r.level = 2; 75 r.in.server_name = host; 76 r.in.share = i; 77 78 status = libnet_AddShare(libnetctx, mem_ctx, &r); 79 if (!NT_STATUS_IS_OK(status)) { 80 d_printf("Failed to add new share: %s (%s)\n", 81 nt_errstr(status), r.out.error_string); 82 return false; 83 } 84 85 return true; 86} 87 88static bool test_NetShareDel(TALLOC_CTX *mem_ctx, 89 struct torture_context *tctx, 90 const char *host, 91 const char *sharename) 92{ 93 NTSTATUS status; 94 struct libnet_context* libnetctx; 95 struct libnet_DelShare r; 96 97 printf("Deleting share %s\n", sharename); 98 99 if (!(libnetctx = libnet_context_init(tctx->ev, tctx->lp_ctx))) { 100 return false; 101 } 102 103 libnetctx->cred = cmdline_credentials; 104 105 r.in.share_name = sharename; 106 r.in.server_name = host; 107 108 status = libnet_DelShare(libnetctx, mem_ctx, &r); 109 if (!NT_STATUS_IS_OK(status)) { 110 d_printf("Failed to delete share: %s (%s)\n", 111 nt_errstr(status), r.out.error_string); 112 return false; 113 } 114 115 return true; 116} 117 118static bool test_CreateDir(TALLOC_CTX *mem_ctx, 119 struct smbcli_state **cli, 120 struct torture_context *tctx, 121 const char *host, 122 const char *share, 123 const char *dir) 124{ 125 printf("Creating directory %s\n", dir); 126 127 if (!torture_open_connection_share(mem_ctx, cli, tctx, host, share, tctx->ev)) { 128 return false; 129 } 130 131 if (!torture_setup_dir(*cli, dir)) { 132 return false; 133 } 134 135 return true; 136} 137 138static bool test_DeleteDir(struct smbcli_state *cli, 139 const char *dir) 140{ 141 printf("Deleting directory %s\n", dir); 142 143 if (smbcli_deltree(cli->tree, dir) == -1) { 144 printf("Unable to delete dir %s - %s\n", dir, 145 smbcli_errstr(cli->tree)); 146 return false; 147 } 148 149 return true; 150} 151 152static bool test_GetManagerVersion(struct dcerpc_pipe *p, 153 TALLOC_CTX *mem_ctx, 154 enum dfs_ManagerVersion *version) 155{ 156 NTSTATUS status; 157 struct dfs_GetManagerVersion r; 158 159 r.out.version = version; 160 161 status = dcerpc_dfs_GetManagerVersion(p, mem_ctx, &r); 162 if (!NT_STATUS_IS_OK(status)) { 163 printf("GetManagerVersion failed - %s\n", nt_errstr(status)); 164 return false; 165 } 166 167 return true; 168} 169 170static bool test_ManagerInitialize(struct dcerpc_pipe *p, 171 TALLOC_CTX *mem_ctx, 172 const char *host) 173{ 174 NTSTATUS status; 175 enum dfs_ManagerVersion version; 176 struct dfs_ManagerInitialize r; 177 178 printf("Testing ManagerInitialize\n"); 179 180 if (!test_GetManagerVersion(p, mem_ctx, &version)) { 181 return false; 182 } 183 184 r.in.servername = host; 185 r.in.flags = 0; 186 187 status = dcerpc_dfs_ManagerInitialize(p, mem_ctx, &r); 188 if (!NT_STATUS_IS_OK(status)) { 189 printf("ManagerInitialize failed - %s\n", nt_errstr(status)); 190 return false; 191 } else if (!W_ERROR_IS_OK(r.out.result)) { 192 printf("dfs_ManagerInitialize failed - %s\n", 193 win_errstr(r.out.result)); 194 IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result); 195 return false; 196 } 197 198 return true; 199} 200 201static bool test_GetInfoLevel(struct dcerpc_pipe *p, 202 TALLOC_CTX *mem_ctx, 203 uint16_t level, 204 const char *root) 205{ 206 NTSTATUS status; 207 struct dfs_GetInfo r; 208 union dfs_Info info; 209 210 printf("Testing GetInfo level %u on '%s'\n", level, root); 211 212 r.in.dfs_entry_path = talloc_strdup(mem_ctx, root); 213 r.in.servername = NULL; 214 r.in.sharename = NULL; 215 r.in.level = level; 216 r.out.info = &info; 217 218 status = dcerpc_dfs_GetInfo(p, mem_ctx, &r); 219 if (!NT_STATUS_IS_OK(status)) { 220 printf("GetInfo failed - %s\n", nt_errstr(status)); 221 return false; 222 } else if (!W_ERROR_IS_OK(r.out.result) && 223 !W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, r.out.result)) { 224 printf("dfs_GetInfo failed - %s\n", win_errstr(r.out.result)); 225 return false; 226 } 227 228 return true; 229} 230 231static bool test_GetInfo(struct dcerpc_pipe *p, 232 TALLOC_CTX *mem_ctx, 233 const char *root) 234{ 235 bool ret = true; 236 /* 103, 104, 105, 106 is only available on Set */ 237 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 100, 101, 102, 103, 104, 105, 106}; 238 int i; 239 240 for (i=0;i<ARRAY_SIZE(levels);i++) { 241 if (!test_GetInfoLevel(p, mem_ctx, levels[i], root)) { 242 ret = false; 243 } 244 } 245 return ret; 246} 247 248static bool test_EnumLevelEx(struct dcerpc_pipe *p, 249 TALLOC_CTX *mem_ctx, 250 uint16_t level, 251 const char *dfs_name) 252{ 253 NTSTATUS status; 254 struct dfs_EnumEx rex; 255 uint32_t total=0; 256 struct dfs_EnumStruct e; 257 struct dfs_Info1 s; 258 struct dfs_EnumArray1 e1; 259 bool ret = true; 260 261 rex.in.level = level; 262 rex.in.bufsize = (uint32_t)-1; 263 rex.in.total = &total; 264 rex.in.info = &e; 265 rex.in.dfs_name = dfs_name; 266 267 e.level = rex.in.level; 268 e.e.info1 = &e1; 269 e.e.info1->count = 0; 270 e.e.info1->s = &s; 271 s.path = NULL; 272 273 printf("Testing EnumEx level %u on '%s'\n", level, dfs_name); 274 275 status = dcerpc_dfs_EnumEx(p, mem_ctx, &rex); 276 if (!NT_STATUS_IS_OK(status)) { 277 printf("EnumEx failed - %s\n", nt_errstr(status)); 278 return false; 279 } 280 281 if (level == 1 && rex.out.total) { 282 int i; 283 for (i=0;i<*rex.out.total;i++) { 284 const char *root = talloc_strdup(mem_ctx, 285 rex.out.info->e.info1->s[i].path); 286 if (!test_GetInfo(p, mem_ctx, root)) { 287 ret = false; 288 } 289 } 290 } 291 292 if (level == 300 && rex.out.total) { 293 int i,k; 294 for (i=0;i<*rex.out.total;i++) { 295 uint16_t levels[] = {1, 2, 3, 4, 200}; /* 300 */ 296 const char *root = talloc_strdup(mem_ctx, 297 rex.out.info->e.info300->s[i].dom_root); 298 for (k=0;k<ARRAY_SIZE(levels);k++) { 299 if (!test_EnumLevelEx(p, mem_ctx, 300 levels[k], root)) 301 { 302 ret = false; 303 } 304 } 305 if (!test_GetInfo(p, mem_ctx, root)) { 306 ret = false; 307 } 308 } 309 } 310 311 return ret; 312} 313 314 315static bool test_EnumLevel(struct dcerpc_pipe *p, 316 TALLOC_CTX *mem_ctx, 317 uint16_t level) 318{ 319 NTSTATUS status; 320 struct dfs_Enum r; 321 uint32_t total=0; 322 struct dfs_EnumStruct e; 323 struct dfs_Info1 s; 324 struct dfs_EnumArray1 e1; 325 bool ret = true; 326 327 r.in.level = level; 328 r.in.bufsize = (uint32_t)-1; 329 r.in.total = &total; 330 r.in.info = &e; 331 332 e.level = r.in.level; 333 e.e.info1 = &e1; 334 e.e.info1->count = 0; 335 e.e.info1->s = &s; 336 s.path = NULL; 337 338 printf("Testing Enum level %u\n", level); 339 340 status = dcerpc_dfs_Enum(p, mem_ctx, &r); 341 if (!NT_STATUS_IS_OK(status)) { 342 printf("Enum failed - %s\n", nt_errstr(status)); 343 return false; 344 } else if (!W_ERROR_IS_OK(r.out.result) && 345 !W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, r.out.result)) { 346 printf("dfs_Enum failed - %s\n", win_errstr(r.out.result)); 347 return false; 348 } 349 350 if (level == 1 && r.out.total) { 351 int i; 352 for (i=0;i<*r.out.total;i++) { 353 const char *root = r.out.info->e.info1->s[i].path; 354 if (!test_GetInfo(p, mem_ctx, root)) { 355 ret = false; 356 } 357 } 358 359 } 360 361 return ret; 362} 363 364 365static bool test_Enum(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) 366{ 367 bool ret = true; 368 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 200, 300}; 369 int i; 370 371 for (i=0;i<ARRAY_SIZE(levels);i++) { 372 if (!test_EnumLevel(p, mem_ctx, levels[i])) { 373 ret = false; 374 } 375 } 376 377 return ret; 378} 379 380static bool test_EnumEx(struct dcerpc_pipe *p, 381 TALLOC_CTX *mem_ctx, 382 const char *host) 383{ 384 bool ret = true; 385 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 200, 300}; 386 int i; 387 388 for (i=0;i<ARRAY_SIZE(levels);i++) { 389 if (!test_EnumLevelEx(p, mem_ctx, levels[i], host)) { 390 ret = false; 391 } 392 } 393 394 return ret; 395} 396 397static bool test_RemoveStdRoot(struct dcerpc_pipe *p, 398 TALLOC_CTX *mem_ctx, 399 const char *host, 400 const char *sharename) 401{ 402 struct dfs_RemoveStdRoot r; 403 NTSTATUS status; 404 405 printf("Testing RemoveStdRoot\n"); 406 407 r.in.servername = host; 408 r.in.rootshare = sharename; 409 r.in.flags = 0; 410 411 status = dcerpc_dfs_RemoveStdRoot(p, mem_ctx, &r); 412 if (!NT_STATUS_IS_OK(status)) { 413 printf("RemoveStdRoot failed - %s\n", nt_errstr(status)); 414 return false; 415 } else if (!W_ERROR_IS_OK(r.out.result)) { 416 printf("dfs_RemoveStdRoot failed - %s\n", 417 win_errstr(r.out.result)); 418 return false; 419 } 420 421 return true; 422} 423 424static bool test_AddStdRoot(struct dcerpc_pipe *p, 425 TALLOC_CTX *mem_ctx, 426 const char *host, 427 const char *sharename) 428{ 429 NTSTATUS status; 430 struct dfs_AddStdRoot r; 431 432 printf("Testing AddStdRoot\n"); 433 434 r.in.servername = host; 435 r.in.rootshare = sharename; 436 r.in.comment = "standard dfs standalone DFS root created by smbtorture (dfs_AddStdRoot)"; 437 r.in.flags = 0; 438 439 status = dcerpc_dfs_AddStdRoot(p, mem_ctx, &r); 440 if (!NT_STATUS_IS_OK(status)) { 441 printf("AddStdRoot failed - %s\n", nt_errstr(status)); 442 return false; 443 } else if (!W_ERROR_IS_OK(r.out.result)) { 444 printf("dfs_AddStdRoot failed - %s\n", 445 win_errstr(r.out.result)); 446 return false; 447 } 448 449 return true; 450} 451 452static bool test_AddStdRootForced(struct dcerpc_pipe *p, 453 TALLOC_CTX *mem_ctx, 454 const char *host, 455 const char *sharename) 456{ 457 NTSTATUS status; 458 struct dfs_AddStdRootForced r; 459 enum dfs_ManagerVersion version; 460 461 printf("Testing AddStdRootForced\n"); 462 463 if (!test_GetManagerVersion(p, mem_ctx, &version)) { 464 return false; 465 } 466 467 r.in.servername = host; 468 r.in.rootshare = sharename; 469 r.in.comment = "standard dfs forced standalone DFS root created by smbtorture (dfs_AddStdRootForced)"; 470 r.in.store = SMBTORTURE_DFS_PATHNAME; 471 472 status = dcerpc_dfs_AddStdRootForced(p, mem_ctx, &r); 473 if (!NT_STATUS_IS_OK(status)) { 474 printf("AddStdRootForced failed - %s\n", nt_errstr(status)); 475 return false; 476 } else if (!W_ERROR_IS_OK(r.out.result)) { 477 printf("dfs_AddStdRootForced failed - %s\n", 478 win_errstr(r.out.result)); 479 IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result); 480 return false; 481 } 482 483 return test_RemoveStdRoot(p, mem_ctx, host, sharename); 484} 485 486static void test_cleanup_stdroot(struct dcerpc_pipe *p, 487 TALLOC_CTX *mem_ctx, 488 struct torture_context *tctx, 489 const char *host, 490 const char *sharename, 491 const char *dir) 492{ 493 struct smbcli_state *cli; 494 495 printf("Cleaning up StdRoot\n"); 496 497 test_RemoveStdRoot(p, mem_ctx, host, sharename); 498 test_NetShareDel(mem_ctx, tctx, host, sharename); 499 torture_open_connection_share(mem_ctx, &cli, tctx, host, "C$", tctx->ev); 500 test_DeleteDir(cli, dir); 501 torture_close_connection(cli); 502} 503 504static bool test_StdRoot(struct dcerpc_pipe *p, 505 TALLOC_CTX *mem_ctx, 506 struct torture_context *tctx, 507 const char *host) 508{ 509 const char *sharename = SMBTORTURE_DFS_SHARENAME; 510 const char *dir = SMBTORTURE_DFS_DIRNAME; 511 const char *path = SMBTORTURE_DFS_PATHNAME; 512 struct smbcli_state *cli; 513 bool ret = true; 514 515 printf("Testing StdRoot\n"); 516 517 test_cleanup_stdroot(p, mem_ctx, tctx, host, sharename, dir); 518 519 ret &= test_CreateDir(mem_ctx, &cli, tctx, host, "C$", dir); 520 ret &= test_NetShareAdd(mem_ctx, tctx, host, sharename, path); 521 ret &= test_AddStdRoot(p, mem_ctx, host, sharename); 522 ret &= test_RemoveStdRoot(p, mem_ctx, host, sharename); 523 ret &= test_AddStdRootForced(p, mem_ctx, host, sharename); 524 ret &= test_NetShareDel(mem_ctx, tctx, host, sharename); 525 ret &= test_DeleteDir(cli, dir); 526 527 torture_close_connection(cli); 528 529 return ret; 530} 531 532static bool test_GetDcAddress(struct dcerpc_pipe *p, 533 TALLOC_CTX *mem_ctx, 534 const char *host) 535{ 536 NTSTATUS status; 537 struct dfs_GetDcAddress r; 538 uint8_t is_root = 0; 539 uint32_t ttl = 0; 540 const char *ptr; 541 542 printf("Testing GetDcAddress\n"); 543 544 ptr = host; 545 546 r.in.servername = host; 547 r.in.server_fullname = r.out.server_fullname = &ptr; 548 r.in.is_root = r.out.is_root = &is_root; 549 r.in.ttl = r.out.ttl = &ttl; 550 551 status = dcerpc_dfs_GetDcAddress(p, mem_ctx, &r); 552 if (!NT_STATUS_IS_OK(status)) { 553 printf("GetDcAddress failed - %s\n", nt_errstr(status)); 554 return false; 555 } else if (!W_ERROR_IS_OK(r.out.result)) { 556 printf("dfs_GetDcAddress failed - %s\n", 557 win_errstr(r.out.result)); 558 return false; 559 } 560 561 return true; 562} 563 564static bool test_SetDcAddress(struct dcerpc_pipe *p, 565 TALLOC_CTX *mem_ctx, 566 const char *host) 567{ 568 NTSTATUS status; 569 struct dfs_SetDcAddress r; 570 571 printf("Testing SetDcAddress\n"); 572 573 r.in.servername = host; 574 r.in.server_fullname = host; 575 r.in.flags = 0; 576 r.in.ttl = 1000; 577 578 status = dcerpc_dfs_SetDcAddress(p, mem_ctx, &r); 579 if (!NT_STATUS_IS_OK(status)) { 580 printf("SetDcAddress failed - %s\n", nt_errstr(status)); 581 return false; 582 } else if (!W_ERROR_IS_OK(r.out.result)) { 583 printf("dfs_SetDcAddress failed - %s\n", 584 win_errstr(r.out.result)); 585 return false; 586 } 587 588 return true; 589} 590 591static bool test_DcAddress(struct dcerpc_pipe *p, 592 TALLOC_CTX *mem_ctx, 593 const char *host) 594{ 595 if (!test_GetDcAddress(p, mem_ctx, host)) { 596 return false; 597 } 598 599 if (!test_SetDcAddress(p, mem_ctx, host)) { 600 return false; 601 } 602 603 return true; 604} 605 606static bool test_FlushFtTable(struct dcerpc_pipe *p, 607 TALLOC_CTX *mem_ctx, 608 const char *host, 609 const char *sharename) 610{ 611 NTSTATUS status; 612 struct dfs_FlushFtTable r; 613 enum dfs_ManagerVersion version; 614 615 printf("Testing FlushFtTable\n"); 616 617 if (!test_GetManagerVersion(p, mem_ctx, &version)) { 618 return false; 619 } 620 621 r.in.servername = host; 622 r.in.rootshare = sharename; 623 624 status = dcerpc_dfs_FlushFtTable(p, mem_ctx, &r); 625 if (!NT_STATUS_IS_OK(status)) { 626 printf("FlushFtTable failed - %s\n", nt_errstr(status)); 627 return false; 628 } else if (!W_ERROR_IS_OK(r.out.result)) { 629 printf("dfs_FlushFtTable failed - %s\n", 630 win_errstr(r.out.result)); 631 IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result); 632 return false; 633 } 634 635 return true; 636} 637 638static bool test_FtRoot(struct dcerpc_pipe *p, 639 TALLOC_CTX *mem_ctx, 640 const char *host) 641{ 642 const char *sharename = SMBTORTURE_DFS_SHARENAME; 643 644 return test_FlushFtTable(p, mem_ctx, host, sharename); 645} 646 647bool torture_rpc_dfs(struct torture_context *torture) 648{ 649 NTSTATUS status; 650 struct dcerpc_pipe *p; 651 bool ret = true; 652 enum dfs_ManagerVersion version; 653 const char *host = torture_setting_string(torture, "host", NULL); 654 655 status = torture_rpc_connection(torture, &p, &ndr_table_netdfs); 656 torture_assert_ntstatus_ok(torture, status, "Unable to connect"); 657 658 ret &= test_GetManagerVersion(p, torture, &version); 659 ret &= test_ManagerInitialize(p, torture, host); 660 ret &= test_Enum(p, torture); 661 ret &= test_EnumEx(p, torture, host); 662 ret &= test_StdRoot(p, torture, torture, host); 663 ret &= test_FtRoot(p, torture, host); 664 ret &= test_DcAddress(p, torture, host); 665 666 return ret; 667} 668