1/* 2 Unix SMB/CIFS implementation. 3 test suite for various lock operations 4 Copyright (C) Andrew Tridgell 2003 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include "torture/torture.h" 22#include "libcli/raw/libcliraw.h" 23#include "libcli/raw/raw_proto.h" 24#include "system/time.h" 25#include "system/filesys.h" 26#include "libcli/libcli.h" 27#include "torture/util.h" 28#include "libcli/composite/composite.h" 29#include "libcli/smb_composite/smb_composite.h" 30#include "lib/cmdline/popt_common.h" 31#include "param/param.h" 32 33#define CHECK_STATUS(status, correct) do { \ 34 if (!NT_STATUS_EQUAL(status, correct)) { \ 35 torture_result(tctx, TORTURE_FAIL, \ 36 "(%s) Incorrect status %s - should be %s\n", \ 37 __location__, nt_errstr(status), nt_errstr(correct)); \ 38 ret = false; \ 39 goto done; \ 40 }} while (0) 41 42#define CHECK_STATUS_CONT(status, correct) do { \ 43 if (!NT_STATUS_EQUAL(status, correct)) { \ 44 torture_result(tctx, TORTURE_FAIL, \ 45 "(%s) Incorrect status %s - should be %s\n", \ 46 __location__, nt_errstr(status), nt_errstr(correct)); \ 47 ret = false; \ 48 }} while (0) 49 50#define CHECK_STATUS_OR(status, correct1, correct2) do { \ 51 if ((!NT_STATUS_EQUAL(status, correct1)) && \ 52 (!NT_STATUS_EQUAL(status, correct2))) { \ 53 torture_result(tctx, TORTURE_FAIL, \ 54 "(%s) Incorrect status %s - should be %s or %s\n", \ 55 __location__, nt_errstr(status), nt_errstr(correct1), \ 56 nt_errstr(correct2)); \ 57 ret = false; \ 58 goto done; \ 59 }} while (0) 60 61#define CHECK_STATUS_OR_CONT(status, correct1, correct2) do { \ 62 if ((!NT_STATUS_EQUAL(status, correct1)) && \ 63 (!NT_STATUS_EQUAL(status, correct2))) { \ 64 torture_result(tctx, TORTURE_FAIL, \ 65 "(%s) Incorrect status %s - should be %s or %s\n", \ 66 __location__, nt_errstr(status), nt_errstr(correct1), \ 67 nt_errstr(correct2)); \ 68 ret = false; \ 69 }} while (0) 70#define BASEDIR "\\testlock" 71 72#define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false)) 73#define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false)) 74#define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false)) 75 76/* 77 test SMBlock and SMBunlock ops 78*/ 79static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli) 80{ 81 union smb_lock io; 82 NTSTATUS status; 83 bool ret = true; 84 int fnum; 85 const char *fname = BASEDIR "\\test.txt"; 86 87 if (!torture_setup_dir(cli, BASEDIR)) { 88 return false; 89 } 90 91 torture_comment(tctx, "Testing RAW_LOCK_LOCK\n"); 92 io.generic.level = RAW_LOCK_LOCK; 93 94 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 95 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 96 "Failed to create %s - %s\n", 97 fname, smbcli_errstr(cli->tree))); 98 99 torture_comment(tctx, "Trying 0/0 lock\n"); 100 io.lock.level = RAW_LOCK_LOCK; 101 io.lock.in.file.fnum = fnum; 102 io.lock.in.count = 0; 103 io.lock.in.offset = 0; 104 status = smb_raw_lock(cli->tree, &io); 105 CHECK_STATUS(status, NT_STATUS_OK); 106 cli->session->pid++; 107 status = smb_raw_lock(cli->tree, &io); 108 CHECK_STATUS(status, NT_STATUS_OK); 109 cli->session->pid--; 110 io.lock.level = RAW_LOCK_UNLOCK; 111 status = smb_raw_lock(cli->tree, &io); 112 CHECK_STATUS(status, NT_STATUS_OK); 113 114 torture_comment(tctx, "Trying 0/1 lock\n"); 115 io.lock.level = RAW_LOCK_LOCK; 116 io.lock.in.file.fnum = fnum; 117 io.lock.in.count = 1; 118 io.lock.in.offset = 0; 119 status = smb_raw_lock(cli->tree, &io); 120 CHECK_STATUS(status, NT_STATUS_OK); 121 cli->session->pid++; 122 status = smb_raw_lock(cli->tree, &io); 123 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 124 cli->session->pid--; 125 io.lock.level = RAW_LOCK_UNLOCK; 126 status = smb_raw_lock(cli->tree, &io); 127 CHECK_STATUS(status, NT_STATUS_OK); 128 io.lock.level = RAW_LOCK_UNLOCK; 129 status = smb_raw_lock(cli->tree, &io); 130 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 131 132 torture_comment(tctx, "Trying 0xEEFFFFFF lock\n"); 133 io.lock.level = RAW_LOCK_LOCK; 134 io.lock.in.file.fnum = fnum; 135 io.lock.in.count = 4000; 136 io.lock.in.offset = 0xEEFFFFFF; 137 status = smb_raw_lock(cli->tree, &io); 138 CHECK_STATUS(status, NT_STATUS_OK); 139 cli->session->pid++; 140 status = smb_raw_lock(cli->tree, &io); 141 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 142 cli->session->pid--; 143 io.lock.level = RAW_LOCK_UNLOCK; 144 status = smb_raw_lock(cli->tree, &io); 145 CHECK_STATUS(status, NT_STATUS_OK); 146 io.lock.level = RAW_LOCK_UNLOCK; 147 status = smb_raw_lock(cli->tree, &io); 148 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 149 150 torture_comment(tctx, "Trying 0xEF000000 lock\n"); 151 io.lock.level = RAW_LOCK_LOCK; 152 io.lock.in.file.fnum = fnum; 153 io.lock.in.count = 4000; 154 io.lock.in.offset = 0xEEFFFFFF; 155 status = smb_raw_lock(cli->tree, &io); 156 CHECK_STATUS(status, NT_STATUS_OK); 157 cli->session->pid++; 158 status = smb_raw_lock(cli->tree, &io); 159 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 160 cli->session->pid--; 161 io.lock.level = RAW_LOCK_UNLOCK; 162 status = smb_raw_lock(cli->tree, &io); 163 CHECK_STATUS(status, NT_STATUS_OK); 164 io.lock.level = RAW_LOCK_UNLOCK; 165 status = smb_raw_lock(cli->tree, &io); 166 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 167 168 torture_comment(tctx, "Trying max lock\n"); 169 io.lock.level = RAW_LOCK_LOCK; 170 io.lock.in.file.fnum = fnum; 171 io.lock.in.count = 4000; 172 io.lock.in.offset = 0xEF000000; 173 status = smb_raw_lock(cli->tree, &io); 174 CHECK_STATUS(status, NT_STATUS_OK); 175 cli->session->pid++; 176 status = smb_raw_lock(cli->tree, &io); 177 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 178 cli->session->pid--; 179 io.lock.level = RAW_LOCK_UNLOCK; 180 status = smb_raw_lock(cli->tree, &io); 181 CHECK_STATUS(status, NT_STATUS_OK); 182 io.lock.level = RAW_LOCK_UNLOCK; 183 status = smb_raw_lock(cli->tree, &io); 184 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 185 186 torture_comment(tctx, "Trying wrong pid unlock\n"); 187 io.lock.level = RAW_LOCK_LOCK; 188 io.lock.in.file.fnum = fnum; 189 io.lock.in.count = 4002; 190 io.lock.in.offset = 10001; 191 status = smb_raw_lock(cli->tree, &io); 192 CHECK_STATUS(status, NT_STATUS_OK); 193 cli->session->pid++; 194 io.lock.level = RAW_LOCK_UNLOCK; 195 status = smb_raw_lock(cli->tree, &io); 196 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 197 cli->session->pid--; 198 status = smb_raw_lock(cli->tree, &io); 199 CHECK_STATUS(status, NT_STATUS_OK); 200 201done: 202 smbcli_close(cli->tree, fnum); 203 smb_raw_exit(cli->session); 204 smbcli_deltree(cli->tree, BASEDIR); 205 return ret; 206} 207 208 209/* 210 test locking&X ops 211*/ 212static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli) 213{ 214 union smb_lock io; 215 struct smb_lock_entry lock[1]; 216 NTSTATUS status; 217 bool ret = true; 218 int fnum; 219 const char *fname = BASEDIR "\\test.txt"; 220 221 if (!torture_setup_dir(cli, BASEDIR)) { 222 return false; 223 } 224 225 torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n"); 226 io.generic.level = RAW_LOCK_LOCKX; 227 228 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 229 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 230 "Failed to create %s - %s\n", 231 fname, smbcli_errstr(cli->tree))); 232 233 io.lockx.level = RAW_LOCK_LOCKX; 234 io.lockx.in.file.fnum = fnum; 235 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 236 io.lockx.in.timeout = 0; 237 io.lockx.in.ulock_cnt = 0; 238 io.lockx.in.lock_cnt = 1; 239 lock[0].pid = cli->session->pid; 240 lock[0].offset = 10; 241 lock[0].count = 1; 242 io.lockx.in.locks = &lock[0]; 243 status = smb_raw_lock(cli->tree, &io); 244 CHECK_STATUS(status, NT_STATUS_OK); 245 246 247 torture_comment(tctx, "Trying 0xEEFFFFFF lock\n"); 248 io.lockx.in.ulock_cnt = 0; 249 io.lockx.in.lock_cnt = 1; 250 lock[0].count = 4000; 251 lock[0].offset = 0xEEFFFFFF; 252 status = smb_raw_lock(cli->tree, &io); 253 CHECK_STATUS(status, NT_STATUS_OK); 254 lock[0].pid++; 255 status = smb_raw_lock(cli->tree, &io); 256 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 257 lock[0].pid--; 258 io.lockx.in.ulock_cnt = 1; 259 io.lockx.in.lock_cnt = 0; 260 status = smb_raw_lock(cli->tree, &io); 261 CHECK_STATUS(status, NT_STATUS_OK); 262 status = smb_raw_lock(cli->tree, &io); 263 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 264 265 torture_comment(tctx, "Trying 0xEF000000 lock\n"); 266 io.lockx.in.ulock_cnt = 0; 267 io.lockx.in.lock_cnt = 1; 268 lock[0].count = 4000; 269 lock[0].offset = 0xEF000000; 270 status = smb_raw_lock(cli->tree, &io); 271 CHECK_STATUS(status, NT_STATUS_OK); 272 lock[0].pid++; 273 status = smb_raw_lock(cli->tree, &io); 274 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 275 lock[0].pid--; 276 io.lockx.in.ulock_cnt = 1; 277 io.lockx.in.lock_cnt = 0; 278 status = smb_raw_lock(cli->tree, &io); 279 CHECK_STATUS(status, NT_STATUS_OK); 280 status = smb_raw_lock(cli->tree, &io); 281 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 282 283 torture_comment(tctx, "Trying zero lock\n"); 284 io.lockx.in.ulock_cnt = 0; 285 io.lockx.in.lock_cnt = 1; 286 lock[0].count = 0; 287 lock[0].offset = ~0; 288 status = smb_raw_lock(cli->tree, &io); 289 CHECK_STATUS(status, NT_STATUS_OK); 290 lock[0].pid++; 291 status = smb_raw_lock(cli->tree, &io); 292 CHECK_STATUS(status, NT_STATUS_OK); 293 lock[0].pid--; 294 io.lockx.in.ulock_cnt = 1; 295 io.lockx.in.lock_cnt = 0; 296 status = smb_raw_lock(cli->tree, &io); 297 CHECK_STATUS(status, NT_STATUS_OK); 298 status = smb_raw_lock(cli->tree, &io); 299 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 300 301 torture_comment(tctx, "Trying max lock\n"); 302 io.lockx.in.ulock_cnt = 0; 303 io.lockx.in.lock_cnt = 1; 304 lock[0].count = 0; 305 lock[0].offset = ~0; 306 status = smb_raw_lock(cli->tree, &io); 307 CHECK_STATUS(status, NT_STATUS_OK); 308 lock[0].pid++; 309 status = smb_raw_lock(cli->tree, &io); 310 CHECK_STATUS(status, NT_STATUS_OK); 311 lock[0].pid--; 312 io.lockx.in.ulock_cnt = 1; 313 io.lockx.in.lock_cnt = 0; 314 status = smb_raw_lock(cli->tree, &io); 315 CHECK_STATUS(status, NT_STATUS_OK); 316 status = smb_raw_lock(cli->tree, &io); 317 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 318 319 torture_comment(tctx, "Trying 2^63\n"); 320 io.lockx.in.ulock_cnt = 0; 321 io.lockx.in.lock_cnt = 1; 322 lock[0].count = 1; 323 lock[0].offset = 1; 324 lock[0].offset <<= 63; 325 status = smb_raw_lock(cli->tree, &io); 326 CHECK_STATUS(status, NT_STATUS_OK); 327 lock[0].pid++; 328 status = smb_raw_lock(cli->tree, &io); 329 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 330 lock[0].pid--; 331 io.lockx.in.ulock_cnt = 1; 332 io.lockx.in.lock_cnt = 0; 333 status = smb_raw_lock(cli->tree, &io); 334 CHECK_STATUS(status, NT_STATUS_OK); 335 status = smb_raw_lock(cli->tree, &io); 336 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 337 338 torture_comment(tctx, "Trying 2^63 - 1\n"); 339 io.lockx.in.ulock_cnt = 0; 340 io.lockx.in.lock_cnt = 1; 341 lock[0].count = 1; 342 lock[0].offset = 1; 343 lock[0].offset <<= 63; 344 lock[0].offset--; 345 status = smb_raw_lock(cli->tree, &io); 346 CHECK_STATUS(status, NT_STATUS_OK); 347 lock[0].pid++; 348 status = smb_raw_lock(cli->tree, &io); 349 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 350 lock[0].pid--; 351 io.lockx.in.ulock_cnt = 1; 352 io.lockx.in.lock_cnt = 0; 353 status = smb_raw_lock(cli->tree, &io); 354 CHECK_STATUS(status, NT_STATUS_OK); 355 status = smb_raw_lock(cli->tree, &io); 356 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 357 358 torture_comment(tctx, "Trying max lock 2\n"); 359 io.lockx.in.ulock_cnt = 0; 360 io.lockx.in.lock_cnt = 1; 361 lock[0].count = 1; 362 lock[0].offset = ~0; 363 status = smb_raw_lock(cli->tree, &io); 364 CHECK_STATUS(status, NT_STATUS_OK); 365 lock[0].pid++; 366 lock[0].count = 2; 367 status = smb_raw_lock(cli->tree, &io); 368 if (TARGET_IS_WIN7(tctx)) 369 CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE); 370 else 371 CHECK_STATUS(status, NT_STATUS_OK); 372 lock[0].pid--; 373 io.lockx.in.ulock_cnt = 1; 374 io.lockx.in.lock_cnt = 0; 375 lock[0].count = 1; 376 status = smb_raw_lock(cli->tree, &io); 377 378 CHECK_STATUS(status, NT_STATUS_OK); 379 status = smb_raw_lock(cli->tree, &io); 380 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 381 382done: 383 smbcli_close(cli->tree, fnum); 384 smb_raw_exit(cli->session); 385 smbcli_deltree(cli->tree, BASEDIR); 386 return ret; 387} 388 389/* 390 test high pid 391*/ 392static bool test_pidhigh(struct torture_context *tctx, 393 struct smbcli_state *cli) 394{ 395 union smb_lock io; 396 struct smb_lock_entry lock[1]; 397 NTSTATUS status; 398 bool ret = true; 399 int fnum; 400 const char *fname = BASEDIR "\\test.txt"; 401 uint8_t c = 1; 402 403 if (!torture_setup_dir(cli, BASEDIR)) { 404 return false; 405 } 406 407 torture_comment(tctx, "Testing high pid\n"); 408 io.generic.level = RAW_LOCK_LOCKX; 409 410 cli->session->pid = 1; 411 412 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 413 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 414 "Failed to create %s - %s\n", 415 fname, smbcli_errstr(cli->tree))); 416 417 if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) { 418 torture_result(tctx, TORTURE_FAIL, 419 "Failed to write 1 byte - %s\n", 420 smbcli_errstr(cli->tree)); 421 ret = false; 422 goto done; 423 } 424 425 io.lockx.level = RAW_LOCK_LOCKX; 426 io.lockx.in.file.fnum = fnum; 427 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 428 io.lockx.in.timeout = 0; 429 io.lockx.in.ulock_cnt = 0; 430 io.lockx.in.lock_cnt = 1; 431 lock[0].pid = cli->session->pid; 432 lock[0].offset = 0; 433 lock[0].count = 0xFFFFFFFF; 434 io.lockx.in.locks = &lock[0]; 435 status = smb_raw_lock(cli->tree, &io); 436 CHECK_STATUS(status, NT_STATUS_OK); 437 438 if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) { 439 torture_result(tctx, TORTURE_FAIL, 440 "Failed to read 1 byte - %s\n", 441 smbcli_errstr(cli->tree)); 442 ret = false; 443 goto done; 444 } 445 446 cli->session->pid = 2; 447 448 if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) { 449 torture_result(tctx, TORTURE_FAIL, 450 "pid is incorrect handled for read with lock!\n"); 451 ret = false; 452 goto done; 453 } 454 455 cli->session->pid = 0x10001; 456 457 if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) { 458 torture_result(tctx, TORTURE_FAIL, 459 "High pid is used on this server!\n"); 460 ret = false; 461 } else { 462 torture_warning(tctx, "High pid is not used on this server (correct)\n"); 463 } 464 465done: 466 smbcli_close(cli->tree, fnum); 467 smb_raw_exit(cli->session); 468 smbcli_deltree(cli->tree, BASEDIR); 469 return ret; 470} 471 472 473/* 474 test locking&X async operation 475*/ 476static bool test_async(struct torture_context *tctx, 477 struct smbcli_state *cli) 478{ 479 struct smbcli_session *session; 480 struct smb_composite_sesssetup setup; 481 struct smbcli_tree *tree; 482 union smb_tcon tcon; 483 const char *host, *share; 484 union smb_lock io; 485 struct smb_lock_entry lock[2]; 486 NTSTATUS status; 487 bool ret = true; 488 int fnum; 489 const char *fname = BASEDIR "\\test.txt"; 490 time_t t; 491 struct smbcli_request *req; 492 struct smbcli_session_options options; 493 494 if (!torture_setup_dir(cli, BASEDIR)) { 495 return false; 496 } 497 498 lp_smbcli_session_options(tctx->lp_ctx, &options); 499 500 torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n"); 501 io.generic.level = RAW_LOCK_LOCKX; 502 503 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 504 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 505 "Failed to create %s - %s\n", 506 fname, smbcli_errstr(cli->tree))); 507 508 io.lockx.level = RAW_LOCK_LOCKX; 509 io.lockx.in.file.fnum = fnum; 510 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 511 io.lockx.in.timeout = 0; 512 io.lockx.in.ulock_cnt = 0; 513 io.lockx.in.lock_cnt = 1; 514 lock[0].pid = cli->session->pid; 515 lock[0].offset = 100; 516 lock[0].count = 10; 517 io.lockx.in.locks = &lock[0]; 518 status = smb_raw_lock(cli->tree, &io); 519 CHECK_STATUS(status, NT_STATUS_OK); 520 521 t = time(NULL); 522 523 torture_comment(tctx, "testing cancel by CANCEL_LOCK\n"); 524 525 /* setup a timed lock */ 526 io.lockx.in.timeout = 10000; 527 req = smb_raw_lock_send(cli->tree, &io); 528 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, 529 "Failed to setup timed lock (%s)\n", __location__)); 530 531 /* cancel the wrong range */ 532 lock[0].offset = 0; 533 io.lockx.in.timeout = 0; 534 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK; 535 status = smb_raw_lock(cli->tree, &io); 536 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation)); 537 538 /* cancel with the wrong bits set */ 539 lock[0].offset = 100; 540 io.lockx.in.timeout = 0; 541 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK; 542 status = smb_raw_lock(cli->tree, &io); 543 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation)); 544 545 /* cancel the right range */ 546 lock[0].offset = 100; 547 io.lockx.in.timeout = 0; 548 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES; 549 status = smb_raw_lock(cli->tree, &io); 550 CHECK_STATUS(status, NT_STATUS_OK); 551 552 /* receive the failed lock request */ 553 status = smbcli_request_simple_recv(req); 554 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 555 556 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx, 557 "lock cancel was not immediate (%s)\n", __location__)); 558 559 torture_comment(tctx, "testing cancel by unlock\n"); 560 io.lockx.in.ulock_cnt = 0; 561 io.lockx.in.lock_cnt = 1; 562 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 563 io.lockx.in.timeout = 0; 564 status = smb_raw_lock(cli->tree, &io); 565 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 566 567 io.lockx.in.timeout = 5000; 568 req = smb_raw_lock_send(cli->tree, &io); 569 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, 570 "Failed to setup timed lock (%s)\n", __location__)); 571 572 io.lockx.in.ulock_cnt = 1; 573 io.lockx.in.lock_cnt = 0; 574 status = smb_raw_lock(cli->tree, &io); 575 CHECK_STATUS(status, NT_STATUS_OK); 576 577 t = time(NULL); 578 status = smbcli_request_simple_recv(req); 579 CHECK_STATUS(status, NT_STATUS_OK); 580 581 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx, 582 "lock cancel by unlock was not immediate (%s) - took %d secs\n", 583 __location__, (int)(time(NULL)-t))); 584 585 torture_comment(tctx, "testing cancel by close\n"); 586 io.lockx.in.ulock_cnt = 0; 587 io.lockx.in.lock_cnt = 1; 588 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 589 io.lockx.in.timeout = 0; 590 status = smb_raw_lock(cli->tree, &io); 591 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 592 593 t = time(NULL); 594 io.lockx.in.timeout = 10000; 595 req = smb_raw_lock_send(cli->tree, &io); 596 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, 597 "Failed to setup timed lock (%s)\n", __location__)); 598 599 status = smbcli_close(cli->tree, fnum); 600 CHECK_STATUS(status, NT_STATUS_OK); 601 602 status = smbcli_request_simple_recv(req); 603 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 604 605 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx, 606 "lock cancel by close was not immediate (%s)\n", __location__)); 607 608 torture_comment(tctx, "create a new sessions\n"); 609 session = smbcli_session_init(cli->transport, tctx, false, options); 610 setup.in.sesskey = cli->transport->negotiate.sesskey; 611 setup.in.capabilities = cli->transport->negotiate.capabilities; 612 setup.in.workgroup = lp_workgroup(tctx->lp_ctx); 613 setup.in.credentials = cmdline_credentials; 614 setup.in.gensec_settings = lp_gensec_settings(tctx, tctx->lp_ctx); 615 status = smb_composite_sesssetup(session, &setup); 616 CHECK_STATUS(status, NT_STATUS_OK); 617 session->vuid = setup.out.vuid; 618 619 torture_comment(tctx, "create new tree context\n"); 620 share = torture_setting_string(tctx, "share", NULL); 621 host = torture_setting_string(tctx, "host", NULL); 622 tree = smbcli_tree_init(session, tctx, false); 623 tcon.generic.level = RAW_TCON_TCONX; 624 tcon.tconx.in.flags = 0; 625 tcon.tconx.in.password = data_blob(NULL, 0); 626 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share); 627 tcon.tconx.in.device = "A:"; 628 status = smb_raw_tcon(tree, tctx, &tcon); 629 CHECK_STATUS(status, NT_STATUS_OK); 630 tree->tid = tcon.tconx.out.tid; 631 632 torture_comment(tctx, "testing cancel by exit\n"); 633 fname = BASEDIR "\\test_exit.txt"; 634 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE); 635 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 636 "Failed to reopen %s - %s\n", 637 fname, smbcli_errstr(tree))); 638 639 io.lockx.level = RAW_LOCK_LOCKX; 640 io.lockx.in.file.fnum = fnum; 641 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 642 io.lockx.in.timeout = 0; 643 io.lockx.in.ulock_cnt = 0; 644 io.lockx.in.lock_cnt = 1; 645 lock[0].pid = session->pid; 646 lock[0].offset = 100; 647 lock[0].count = 10; 648 io.lockx.in.locks = &lock[0]; 649 status = smb_raw_lock(tree, &io); 650 CHECK_STATUS(status, NT_STATUS_OK); 651 652 io.lockx.in.ulock_cnt = 0; 653 io.lockx.in.lock_cnt = 1; 654 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 655 io.lockx.in.timeout = 0; 656 status = smb_raw_lock(tree, &io); 657 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 658 659 io.lockx.in.timeout = 10000; 660 t = time(NULL); 661 req = smb_raw_lock_send(tree, &io); 662 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, 663 "Failed to setup timed lock (%s)\n", __location__)); 664 665 status = smb_raw_exit(session); 666 CHECK_STATUS(status, NT_STATUS_OK); 667 668 status = smbcli_request_simple_recv(req); 669 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 670 671 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx, 672 "lock cancel by exit was not immediate (%s)\n", __location__)); 673 674 torture_comment(tctx, "testing cancel by ulogoff\n"); 675 fname = BASEDIR "\\test_ulogoff.txt"; 676 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE); 677 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 678 "Failed to reopen %s - %s\n", 679 fname, smbcli_errstr(tree))); 680 681 io.lockx.level = RAW_LOCK_LOCKX; 682 io.lockx.in.file.fnum = fnum; 683 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 684 io.lockx.in.timeout = 0; 685 io.lockx.in.ulock_cnt = 0; 686 io.lockx.in.lock_cnt = 1; 687 lock[0].pid = session->pid; 688 lock[0].offset = 100; 689 lock[0].count = 10; 690 io.lockx.in.locks = &lock[0]; 691 status = smb_raw_lock(tree, &io); 692 CHECK_STATUS(status, NT_STATUS_OK); 693 694 io.lockx.in.ulock_cnt = 0; 695 io.lockx.in.lock_cnt = 1; 696 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 697 io.lockx.in.timeout = 0; 698 status = smb_raw_lock(tree, &io); 699 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 700 701 io.lockx.in.timeout = 10000; 702 t = time(NULL); 703 req = smb_raw_lock_send(tree, &io); 704 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, 705 "Failed to setup timed lock (%s)\n", __location__)); 706 707 status = smb_raw_ulogoff(session); 708 CHECK_STATUS(status, NT_STATUS_OK); 709 710 status = smbcli_request_simple_recv(req); 711 if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) { 712 torture_result(tctx, TORTURE_FAIL, 713 "lock not canceled by ulogoff - %s (ignored because of vfs_vifs fails it)\n", 714 nt_errstr(status)); 715 smb_tree_disconnect(tree); 716 smb_raw_exit(session); 717 goto done; 718 } 719 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 720 721 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx, 722 "lock cancel by ulogoff was not immediate (%s)\n", __location__)); 723 724 torture_comment(tctx, "testing cancel by tdis\n"); 725 tree->session = cli->session; 726 727 fname = BASEDIR "\\test_tdis.txt"; 728 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE); 729 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 730 "Failed to reopen %s - %s\n", 731 fname, smbcli_errstr(tree))); 732 733 io.lockx.level = RAW_LOCK_LOCKX; 734 io.lockx.in.file.fnum = fnum; 735 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 736 io.lockx.in.timeout = 0; 737 io.lockx.in.ulock_cnt = 0; 738 io.lockx.in.lock_cnt = 1; 739 lock[0].pid = cli->session->pid; 740 lock[0].offset = 100; 741 lock[0].count = 10; 742 io.lockx.in.locks = &lock[0]; 743 status = smb_raw_lock(tree, &io); 744 CHECK_STATUS(status, NT_STATUS_OK); 745 746 status = smb_raw_lock(tree, &io); 747 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 748 749 io.lockx.in.timeout = 10000; 750 t = time(NULL); 751 req = smb_raw_lock_send(tree, &io); 752 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, 753 "Failed to setup timed lock (%s)\n", __location__)); 754 755 status = smb_tree_disconnect(tree); 756 CHECK_STATUS(status, NT_STATUS_OK); 757 758 status = smbcli_request_simple_recv(req); 759 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 760 761 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx, 762 "lock cancel by tdis was not immediate (%s)\n", __location__)); 763 764done: 765 smb_raw_exit(cli->session); 766 smbcli_deltree(cli->tree, BASEDIR); 767 return ret; 768} 769 770/* 771 test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT 772*/ 773static bool test_errorcode(struct torture_context *tctx, 774 struct smbcli_state *cli) 775{ 776 union smb_lock io; 777 union smb_open op; 778 struct smb_lock_entry lock[2]; 779 NTSTATUS status; 780 bool ret = true; 781 int fnum, fnum2; 782 const char *fname; 783 struct smbcli_request *req; 784 time_t start; 785 int t; 786 int delay; 787 788 if (!torture_setup_dir(cli, BASEDIR)) { 789 return false; 790 } 791 792 torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n"); 793 794 torture_comment(tctx, "testing with timeout = 0\n"); 795 fname = BASEDIR "\\test0.txt"; 796 t = 0; 797 798 /* 799 * the first run is with t = 0, 800 * the second with t > 0 (=1) 801 */ 802next_run: 803 /* 804 * use the DENY_DOS mode, that creates two fnum's of one low-level file handle, 805 * this demonstrates that the cache is per fnum 806 */ 807 op.openx.level = RAW_OPEN_OPENX; 808 op.openx.in.fname = fname; 809 op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO; 810 op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_DOS; 811 op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE; 812 op.openx.in.search_attrs = 0; 813 op.openx.in.file_attrs = 0; 814 op.openx.in.write_time = 0; 815 op.openx.in.size = 0; 816 op.openx.in.timeout = 0; 817 818 status = smb_raw_open(cli->tree, tctx, &op); 819 CHECK_STATUS(status, NT_STATUS_OK); 820 fnum = op.openx.out.file.fnum; 821 822 status = smb_raw_open(cli->tree, tctx, &op); 823 CHECK_STATUS(status, NT_STATUS_OK); 824 fnum2 = op.openx.out.file.fnum; 825 826 io.lockx.level = RAW_LOCK_LOCKX; 827 io.lockx.in.file.fnum = fnum; 828 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 829 io.lockx.in.timeout = t; 830 io.lockx.in.ulock_cnt = 0; 831 io.lockx.in.lock_cnt = 1; 832 lock[0].pid = cli->session->pid; 833 lock[0].offset = 100; 834 lock[0].count = 10; 835 io.lockx.in.locks = &lock[0]; 836 status = smb_raw_lock(cli->tree, &io); 837 CHECK_STATUS(status, NT_STATUS_OK); 838 839 /* 840 * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED 841 * this also demonstrates that the error code cache is per file handle 842 * (LOCK_NOT_GRANTED is only be used when timeout is 0!) 843 */ 844 io.lockx.in.file.fnum = fnum2; 845 status = smb_raw_lock(cli->tree, &io); 846 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 847 848 io.lockx.in.file.fnum = fnum; 849 status = smb_raw_lock(cli->tree, &io); 850 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 851 852 /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */ 853 io.lockx.in.file.fnum = fnum; 854 status = smb_raw_lock(cli->tree, &io); 855 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 856 857 io.lockx.in.file.fnum = fnum2; 858 status = smb_raw_lock(cli->tree, &io); 859 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 860 861 io.lockx.in.file.fnum = fnum; 862 status = smb_raw_lock(cli->tree, &io); 863 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 864 865 io.lockx.in.file.fnum = fnum2; 866 status = smb_raw_lock(cli->tree, &io); 867 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 868 869 /* demonstrate that the smbpid doesn't matter */ 870 lock[0].pid++; 871 io.lockx.in.file.fnum = fnum; 872 status = smb_raw_lock(cli->tree, &io); 873 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 874 875 io.lockx.in.file.fnum = fnum2; 876 status = smb_raw_lock(cli->tree, &io); 877 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 878 lock[0].pid--; 879 880 /* 881 * demonstrate the a successful lock with count = 0 and the same offset, 882 * doesn't reset the error cache 883 */ 884 lock[0].offset = 100; 885 lock[0].count = 0; 886 io.lockx.in.file.fnum = fnum; 887 status = smb_raw_lock(cli->tree, &io); 888 CHECK_STATUS(status, NT_STATUS_OK); 889 890 io.lockx.in.file.fnum = fnum2; 891 status = smb_raw_lock(cli->tree, &io); 892 CHECK_STATUS(status, NT_STATUS_OK); 893 894 lock[0].offset = 100; 895 lock[0].count = 10; 896 io.lockx.in.file.fnum = fnum; 897 status = smb_raw_lock(cli->tree, &io); 898 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 899 900 io.lockx.in.file.fnum = fnum2; 901 status = smb_raw_lock(cli->tree, &io); 902 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 903 904 /* 905 * demonstrate the a successful lock with count = 0 and outside the locked range, 906 * doesn't reset the error cache 907 */ 908 lock[0].offset = 110; 909 lock[0].count = 0; 910 io.lockx.in.file.fnum = fnum; 911 status = smb_raw_lock(cli->tree, &io); 912 CHECK_STATUS(status, NT_STATUS_OK); 913 914 io.lockx.in.file.fnum = fnum2; 915 status = smb_raw_lock(cli->tree, &io); 916 CHECK_STATUS(status, NT_STATUS_OK); 917 918 lock[0].offset = 100; 919 lock[0].count = 10; 920 io.lockx.in.file.fnum = fnum; 921 status = smb_raw_lock(cli->tree, &io); 922 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 923 924 io.lockx.in.file.fnum = fnum2; 925 status = smb_raw_lock(cli->tree, &io); 926 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 927 928 lock[0].offset = 99; 929 lock[0].count = 0; 930 io.lockx.in.file.fnum = fnum; 931 status = smb_raw_lock(cli->tree, &io); 932 CHECK_STATUS(status, NT_STATUS_OK); 933 934 io.lockx.in.file.fnum = fnum2; 935 status = smb_raw_lock(cli->tree, &io); 936 CHECK_STATUS(status, NT_STATUS_OK); 937 938 lock[0].offset = 100; 939 lock[0].count = 10; 940 io.lockx.in.file.fnum = fnum; 941 status = smb_raw_lock(cli->tree, &io); 942 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 943 944 io.lockx.in.file.fnum = fnum2; 945 status = smb_raw_lock(cli->tree, &io); 946 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 947 948 /* demonstrate that a changing count doesn't reset the error cache */ 949 lock[0].offset = 100; 950 lock[0].count = 5; 951 io.lockx.in.file.fnum = fnum; 952 status = smb_raw_lock(cli->tree, &io); 953 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 954 955 io.lockx.in.file.fnum = fnum2; 956 status = smb_raw_lock(cli->tree, &io); 957 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 958 959 lock[0].offset = 100; 960 lock[0].count = 15; 961 io.lockx.in.file.fnum = fnum; 962 status = smb_raw_lock(cli->tree, &io); 963 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 964 965 io.lockx.in.file.fnum = fnum2; 966 status = smb_raw_lock(cli->tree, &io); 967 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 968 969 /* 970 * demonstrate the a lock with count = 0 and inside the locked range, 971 * fails and resets the error cache 972 */ 973 lock[0].offset = 101; 974 lock[0].count = 0; 975 io.lockx.in.file.fnum = fnum; 976 status = smb_raw_lock(cli->tree, &io); 977 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 978 status = smb_raw_lock(cli->tree, &io); 979 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 980 981 io.lockx.in.file.fnum = fnum2; 982 status = smb_raw_lock(cli->tree, &io); 983 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 984 status = smb_raw_lock(cli->tree, &io); 985 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 986 987 lock[0].offset = 100; 988 lock[0].count = 10; 989 io.lockx.in.file.fnum = fnum; 990 status = smb_raw_lock(cli->tree, &io); 991 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 992 status = smb_raw_lock(cli->tree, &io); 993 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 994 995 io.lockx.in.file.fnum = fnum2; 996 status = smb_raw_lock(cli->tree, &io); 997 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 998 status = smb_raw_lock(cli->tree, &io); 999 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1000 1001 /* demonstrate the a changing offset, resets the error cache */ 1002 lock[0].offset = 105; 1003 lock[0].count = 10; 1004 io.lockx.in.file.fnum = fnum; 1005 status = smb_raw_lock(cli->tree, &io); 1006 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1007 status = smb_raw_lock(cli->tree, &io); 1008 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1009 1010 io.lockx.in.file.fnum = fnum2; 1011 status = smb_raw_lock(cli->tree, &io); 1012 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1013 status = smb_raw_lock(cli->tree, &io); 1014 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1015 1016 lock[0].offset = 100; 1017 lock[0].count = 10; 1018 io.lockx.in.file.fnum = fnum; 1019 status = smb_raw_lock(cli->tree, &io); 1020 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1021 status = smb_raw_lock(cli->tree, &io); 1022 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1023 1024 io.lockx.in.file.fnum = fnum2; 1025 status = smb_raw_lock(cli->tree, &io); 1026 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1027 status = smb_raw_lock(cli->tree, &io); 1028 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1029 1030 lock[0].offset = 95; 1031 lock[0].count = 9; 1032 io.lockx.in.file.fnum = fnum; 1033 status = smb_raw_lock(cli->tree, &io); 1034 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1035 status = smb_raw_lock(cli->tree, &io); 1036 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1037 1038 io.lockx.in.file.fnum = fnum2; 1039 status = smb_raw_lock(cli->tree, &io); 1040 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1041 status = smb_raw_lock(cli->tree, &io); 1042 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1043 1044 lock[0].offset = 100; 1045 lock[0].count = 10; 1046 io.lockx.in.file.fnum = fnum; 1047 status = smb_raw_lock(cli->tree, &io); 1048 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1049 status = smb_raw_lock(cli->tree, &io); 1050 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1051 1052 io.lockx.in.file.fnum = fnum2; 1053 status = smb_raw_lock(cli->tree, &io); 1054 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1055 status = smb_raw_lock(cli->tree, &io); 1056 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1057 1058 /* 1059 * demonstrate the a successful lock in a different range, 1060 * doesn't reset the cache, the failing lock on the 2nd handle 1061 * resets the resets the cache 1062 */ 1063 lock[0].offset = 120; 1064 lock[0].count = 15; 1065 io.lockx.in.file.fnum = fnum; 1066 status = smb_raw_lock(cli->tree, &io); 1067 CHECK_STATUS(status, NT_STATUS_OK); 1068 1069 io.lockx.in.file.fnum = fnum2; 1070 status = smb_raw_lock(cli->tree, &io); 1071 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1072 1073 lock[0].offset = 100; 1074 lock[0].count = 10; 1075 io.lockx.in.file.fnum = fnum; 1076 status = smb_raw_lock(cli->tree, &io); 1077 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1078 status = smb_raw_lock(cli->tree, &io); 1079 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1080 1081 io.lockx.in.file.fnum = fnum2; 1082 status = smb_raw_lock(cli->tree, &io); 1083 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); 1084 status = smb_raw_lock(cli->tree, &io); 1085 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1086 1087 /* end of the loop */ 1088 if (t == 0) { 1089 smb_raw_exit(cli->session); 1090 t = 1; 1091 torture_comment(tctx, "testing with timeout > 0 (=%d)\n", 1092 t); 1093 fname = BASEDIR "\\test1.txt"; 1094 goto next_run; 1095 } 1096 1097 t = 4000; 1098 torture_comment(tctx, "testing special cases with timeout > 0 (=%d)\n", 1099 t); 1100 1101 /* 1102 * the following 3 test sections demonstrate that 1103 * the cache is only set when the error is reported 1104 * to the client (after the timeout went by) 1105 */ 1106 smb_raw_exit(cli->session); 1107 torture_comment(tctx, "testing a conflict while a lock is pending\n"); 1108 fname = BASEDIR "\\test2.txt"; 1109 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 1110 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 1111 "Failed to reopen %s - %s\n", 1112 fname, smbcli_errstr(cli->tree))); 1113 1114 io.lockx.level = RAW_LOCK_LOCKX; 1115 io.lockx.in.file.fnum = fnum; 1116 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 1117 io.lockx.in.timeout = 0; 1118 io.lockx.in.ulock_cnt = 0; 1119 io.lockx.in.lock_cnt = 1; 1120 lock[0].pid = cli->session->pid; 1121 lock[0].offset = 100; 1122 lock[0].count = 10; 1123 io.lockx.in.locks = &lock[0]; 1124 status = smb_raw_lock(cli->tree, &io); 1125 CHECK_STATUS(status, NT_STATUS_OK); 1126 1127 start = time(NULL); 1128 io.lockx.in.timeout = t; 1129 req = smb_raw_lock_send(cli->tree, &io); 1130 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, 1131 "Failed to setup timed lock (%s)\n", __location__)); 1132 1133 io.lockx.in.timeout = 0; 1134 lock[0].offset = 105; 1135 lock[0].count = 10; 1136 status = smb_raw_lock(cli->tree, &io); 1137 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 1138 1139 status = smbcli_request_simple_recv(req); 1140 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1141 1142 delay = t / 1000; 1143 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) { 1144 delay /= 2; 1145 } 1146 1147 torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx, 1148 "lock comes back to early timeout[%d] delay[%d]" 1149 "(%s)\n", t, delay, __location__)); 1150 1151 status = smb_raw_lock(cli->tree, &io); 1152 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 1153 1154 smbcli_close(cli->tree, fnum); 1155 fname = BASEDIR "\\test3.txt"; 1156 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 1157 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 1158 "Failed to reopen %s - %s\n", 1159 fname, smbcli_errstr(cli->tree))); 1160 1161 io.lockx.level = RAW_LOCK_LOCKX; 1162 io.lockx.in.file.fnum = fnum; 1163 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 1164 io.lockx.in.timeout = 0; 1165 io.lockx.in.ulock_cnt = 0; 1166 io.lockx.in.lock_cnt = 1; 1167 lock[0].pid = cli->session->pid; 1168 lock[0].offset = 100; 1169 lock[0].count = 10; 1170 io.lockx.in.locks = &lock[0]; 1171 status = smb_raw_lock(cli->tree, &io); 1172 CHECK_STATUS(status, NT_STATUS_OK); 1173 1174 start = time(NULL); 1175 io.lockx.in.timeout = t; 1176 req = smb_raw_lock_send(cli->tree, &io); 1177 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, 1178 "Failed to setup timed lock (%s)\n", __location__)); 1179 1180 io.lockx.in.timeout = 0; 1181 lock[0].offset = 105; 1182 lock[0].count = 10; 1183 status = smb_raw_lock(cli->tree, &io); 1184 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 1185 1186 status = smbcli_request_simple_recv(req); 1187 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1188 1189 delay = t / 1000; 1190 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) { 1191 delay /= 2; 1192 } 1193 1194 torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx, 1195 "lock comes back to early timeout[%d] delay[%d]" 1196 "(%s)\n", t, delay, __location__)); 1197 1198 lock[0].offset = 100; 1199 lock[0].count = 10; 1200 status = smb_raw_lock(cli->tree, &io); 1201 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1202 1203 smbcli_close(cli->tree, fnum); 1204 fname = BASEDIR "\\test4.txt"; 1205 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 1206 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 1207 "Failed to reopen %s - %s\n", 1208 fname, smbcli_errstr(cli->tree))); 1209 1210 io.lockx.level = RAW_LOCK_LOCKX; 1211 io.lockx.in.file.fnum = fnum; 1212 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; 1213 io.lockx.in.timeout = 0; 1214 io.lockx.in.ulock_cnt = 0; 1215 io.lockx.in.lock_cnt = 1; 1216 lock[0].pid = cli->session->pid; 1217 lock[0].offset = 100; 1218 lock[0].count = 10; 1219 io.lockx.in.locks = &lock[0]; 1220 status = smb_raw_lock(cli->tree, &io); 1221 CHECK_STATUS(status, NT_STATUS_OK); 1222 1223 start = time(NULL); 1224 io.lockx.in.timeout = t; 1225 req = smb_raw_lock_send(cli->tree, &io); 1226 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, 1227 "Failed to setup timed lock (%s)\n", __location__)); 1228 1229 io.lockx.in.timeout = 0; 1230 status = smb_raw_lock(cli->tree, &io); 1231 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 1232 1233 status = smbcli_request_simple_recv(req); 1234 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1235 1236 delay = t / 1000; 1237 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) { 1238 delay /= 2; 1239 } 1240 1241 torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx, 1242 "lock comes back to early timeout[%d] delay[%d]" 1243 "(%s)\n", t, delay, __location__)); 1244 1245 status = smb_raw_lock(cli->tree, &io); 1246 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); 1247 1248done: 1249 smb_raw_exit(cli->session); 1250 smbcli_deltree(cli->tree, BASEDIR); 1251 return ret; 1252} 1253 1254 1255/* 1256 test LOCKING_ANDX_CHANGE_LOCKTYPE 1257*/ 1258static bool test_changetype(struct torture_context *tctx, 1259 struct smbcli_state *cli) 1260{ 1261 union smb_lock io; 1262 struct smb_lock_entry lock[2]; 1263 NTSTATUS status; 1264 bool ret = true; 1265 int fnum; 1266 uint8_t c = 0; 1267 const char *fname = BASEDIR "\\test.txt"; 1268 1269 if (!torture_setup_dir(cli, BASEDIR)) { 1270 return false; 1271 } 1272 1273 torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n"); 1274 io.generic.level = RAW_LOCK_LOCKX; 1275 1276 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 1277 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 1278 "Failed to create %s - %s\n", 1279 fname, smbcli_errstr(cli->tree))); 1280 1281 io.lockx.level = RAW_LOCK_LOCKX; 1282 io.lockx.in.file.fnum = fnum; 1283 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; 1284 io.lockx.in.timeout = 0; 1285 io.lockx.in.ulock_cnt = 0; 1286 io.lockx.in.lock_cnt = 1; 1287 lock[0].pid = cli->session->pid; 1288 lock[0].offset = 100; 1289 lock[0].count = 10; 1290 io.lockx.in.locks = &lock[0]; 1291 status = smb_raw_lock(cli->tree, &io); 1292 CHECK_STATUS(status, NT_STATUS_OK); 1293 1294 if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) { 1295 torture_result(tctx, TORTURE_FAIL, 1296 "allowed write on read locked region (%s)\n", __location__); 1297 ret = false; 1298 goto done; 1299 } 1300 1301 /* windows server don't seem to support this */ 1302 io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE; 1303 status = smb_raw_lock(cli->tree, &io); 1304 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks)); 1305 1306 if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) { 1307 torture_result(tctx, TORTURE_FAIL, 1308 "allowed write after lock change (%s)\n", __location__); 1309 ret = false; 1310 goto done; 1311 } 1312 1313done: 1314 smbcli_close(cli->tree, fnum); 1315 smb_raw_exit(cli->session); 1316 smbcli_deltree(cli->tree, BASEDIR); 1317 return ret; 1318} 1319 1320struct double_lock_test { 1321 struct smb_lock_entry lock1; 1322 struct smb_lock_entry lock2; 1323 NTSTATUS exp_status; 1324}; 1325 1326/** 1327 * Tests zero byte locks. 1328 */ 1329static const struct double_lock_test zero_byte_tests[] = { 1330 /* {pid, offset, count}, {pid, offset, count}, status */ 1331 1332 /** First, takes a zero byte lock at offset 10. Then: 1333 * - Taking 0 byte lock at 10 should succeed. 1334 * - Taking 1 byte locks at 9,10,11 should succeed. 1335 * - Taking 2 byte lock at 9 should fail. 1336 * - Taking 2 byte lock at 10 should succeed. 1337 * - Taking 3 byte lock at 9 should fail. 1338 */ 1339 {{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK}, 1340 {{1000, 10, 0}, {1001, 9, 1}, NT_STATUS_OK}, 1341 {{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK}, 1342 {{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK}, 1343 {{1000, 10, 0}, {1001, 9, 2}, NT_STATUS_LOCK_NOT_GRANTED}, 1344 {{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK}, 1345 {{1000, 10, 0}, {1001, 9, 3}, NT_STATUS_LOCK_NOT_GRANTED}, 1346 1347 /** Same, but opposite order. */ 1348 {{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK}, 1349 {{1001, 9, 1}, {1000, 10, 0}, NT_STATUS_OK}, 1350 {{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK}, 1351 {{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK}, 1352 {{1001, 9, 2}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED}, 1353 {{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK}, 1354 {{1001, 9, 3}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED}, 1355 1356 /** Zero zero case. */ 1357 {{1000, 0, 0}, {1001, 0, 0}, NT_STATUS_OK}, 1358}; 1359 1360static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli) 1361{ 1362 union smb_lock io; 1363 NTSTATUS status; 1364 bool ret = true; 1365 int fnum, i; 1366 const char *fname = BASEDIR "\\zero.txt"; 1367 1368 torture_comment(tctx, "Testing zero length byte range locks:\n"); 1369 1370 if (!torture_setup_dir(cli, BASEDIR)) { 1371 return false; 1372 } 1373 1374 io.generic.level = RAW_LOCK_LOCKX; 1375 1376 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 1377 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, 1378 "Failed to create %s - %s\n", 1379 fname, smbcli_errstr(cli->tree))); 1380 1381 /* Setup initial parameters */ 1382 io.lockx.level = RAW_LOCK_LOCKX; 1383 io.lockx.in.file.fnum = fnum; 1384 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */ 1385 io.lockx.in.timeout = 0; 1386 1387 /* Try every combination of locks in zero_byte_tests. The first lock is 1388 * assumed to succeed. The second lock may contend, depending on the 1389 * expected status. */ 1390 for (i = 0; 1391 i < ARRAY_SIZE(zero_byte_tests); 1392 i++) { 1393 torture_comment(tctx, " ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n", 1394 zero_byte_tests[i].lock1.pid, 1395 zero_byte_tests[i].lock1.offset, 1396 zero_byte_tests[i].lock1.count, 1397 zero_byte_tests[i].lock2.pid, 1398 zero_byte_tests[i].lock2.offset, 1399 zero_byte_tests[i].lock2.count, 1400 nt_errstr(zero_byte_tests[i].exp_status)); 1401 1402 /* Lock both locks. */ 1403 io.lockx.in.ulock_cnt = 0; 1404 io.lockx.in.lock_cnt = 1; 1405 1406 io.lockx.in.locks = &zero_byte_tests[i].lock1; 1407 status = smb_raw_lock(cli->tree, &io); 1408 CHECK_STATUS(status, NT_STATUS_OK); 1409 1410 io.lockx.in.locks = &zero_byte_tests[i].lock2; 1411 status = smb_raw_lock(cli->tree, &io); 1412 1413 if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status, 1414 NT_STATUS_LOCK_NOT_GRANTED)) { 1415 /* Allow either of the failure messages and keep going 1416 * if we see the wrong status. */ 1417 CHECK_STATUS_OR_CONT(status, 1418 NT_STATUS_LOCK_NOT_GRANTED, 1419 NT_STATUS_FILE_LOCK_CONFLICT); 1420 1421 } else { 1422 CHECK_STATUS_CONT(status, 1423 zero_byte_tests[i].exp_status); 1424 } 1425 1426 /* Unlock both locks. */ 1427 io.lockx.in.ulock_cnt = 1; 1428 io.lockx.in.lock_cnt = 0; 1429 1430 if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) { 1431 status = smb_raw_lock(cli->tree, &io); 1432 CHECK_STATUS(status, NT_STATUS_OK); 1433 } 1434 1435 io.lockx.in.locks = &zero_byte_tests[i].lock1; 1436 status = smb_raw_lock(cli->tree, &io); 1437 CHECK_STATUS(status, NT_STATUS_OK); 1438 } 1439 1440done: 1441 smbcli_close(cli->tree, fnum); 1442 smb_raw_exit(cli->session); 1443 smbcli_deltree(cli->tree, BASEDIR); 1444 return ret; 1445} 1446 1447static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli) 1448{ 1449 union smb_lock io; 1450 NTSTATUS status; 1451 bool ret = true; 1452 int fnum1, fnum2; 1453 const char *fname = BASEDIR "\\unlock.txt"; 1454 struct smb_lock_entry lock1; 1455 struct smb_lock_entry lock2; 1456 1457 torture_comment(tctx, "Testing LOCKX unlock:\n"); 1458 1459 if (!torture_setup_dir(cli, BASEDIR)) { 1460 return false; 1461 } 1462 1463 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 1464 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx, 1465 "Failed to create %s - %s\n", 1466 fname, smbcli_errstr(cli->tree))); 1467 1468 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 1469 torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx, 1470 "Failed to create %s - %s\n", 1471 fname, smbcli_errstr(cli->tree))); 1472 1473 /* Setup initial parameters */ 1474 io.lockx.level = RAW_LOCK_LOCKX; 1475 io.lockx.in.timeout = 0; 1476 1477 lock1.pid = cli->session->pid; 1478 lock1.offset = 0; 1479 lock1.count = 10; 1480 lock2.pid = cli->session->pid - 1; 1481 lock2.offset = 0; 1482 lock2.count = 10; 1483 1484 /** 1485 * Take exclusive lock, then unlock it with a shared-unlock call. 1486 */ 1487 torture_comment(tctx, " taking exclusive lock.\n"); 1488 io.lockx.in.ulock_cnt = 0; 1489 io.lockx.in.lock_cnt = 1; 1490 io.lockx.in.mode = 0; 1491 io.lockx.in.file.fnum = fnum1; 1492 io.lockx.in.locks = &lock1; 1493 status = smb_raw_lock(cli->tree, &io); 1494 CHECK_STATUS(status, NT_STATUS_OK); 1495 1496 torture_comment(tctx, " unlock the exclusive with a shared unlock call.\n"); 1497 io.lockx.in.ulock_cnt = 1; 1498 io.lockx.in.lock_cnt = 0; 1499 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; 1500 io.lockx.in.file.fnum = fnum1; 1501 io.lockx.in.locks = &lock1; 1502 status = smb_raw_lock(cli->tree, &io); 1503 CHECK_STATUS(status, NT_STATUS_OK); 1504 1505 torture_comment(tctx, " try shared lock on pid2/fnum2, testing the unlock.\n"); 1506 io.lockx.in.ulock_cnt = 0; 1507 io.lockx.in.lock_cnt = 1; 1508 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; 1509 io.lockx.in.file.fnum = fnum2; 1510 io.lockx.in.locks = &lock2; 1511 status = smb_raw_lock(cli->tree, &io); 1512 CHECK_STATUS(status, NT_STATUS_OK); 1513 1514 /** 1515 * Unlock a shared lock with an exclusive-unlock call. 1516 */ 1517 torture_comment(tctx, " unlock new shared lock with exclusive unlock call.\n"); 1518 io.lockx.in.ulock_cnt = 1; 1519 io.lockx.in.lock_cnt = 0; 1520 io.lockx.in.mode = 0; 1521 io.lockx.in.file.fnum = fnum2; 1522 io.lockx.in.locks = &lock2; 1523 status = smb_raw_lock(cli->tree, &io); 1524 CHECK_STATUS(status, NT_STATUS_OK); 1525 1526 torture_comment(tctx, " try exclusive lock on pid1, testing the unlock.\n"); 1527 io.lockx.in.ulock_cnt = 0; 1528 io.lockx.in.lock_cnt = 1; 1529 io.lockx.in.mode = 0; 1530 io.lockx.in.file.fnum = fnum1; 1531 io.lockx.in.locks = &lock1; 1532 status = smb_raw_lock(cli->tree, &io); 1533 CHECK_STATUS(status, NT_STATUS_OK); 1534 1535 /* cleanup */ 1536 io.lockx.in.ulock_cnt = 1; 1537 io.lockx.in.lock_cnt = 0; 1538 status = smb_raw_lock(cli->tree, &io); 1539 CHECK_STATUS(status, NT_STATUS_OK); 1540 1541 /** 1542 * Test unlocking of 0-byte locks. 1543 */ 1544 1545 torture_comment(tctx, " lock shared and exclusive 0-byte locks, testing that Windows " 1546 "always unlocks the exclusive first.\n"); 1547 lock1.pid = cli->session->pid; 1548 lock1.offset = 10; 1549 lock1.count = 0; 1550 lock2.pid = cli->session->pid; 1551 lock2.offset = 5; 1552 lock2.count = 10; 1553 io.lockx.in.ulock_cnt = 0; 1554 io.lockx.in.lock_cnt = 1; 1555 io.lockx.in.file.fnum = fnum1; 1556 io.lockx.in.locks = &lock1; 1557 1558 /* lock 0-byte shared 1559 * Note: Order of the shared/exclusive locks doesn't matter. */ 1560 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; 1561 status = smb_raw_lock(cli->tree, &io); 1562 CHECK_STATUS(status, NT_STATUS_OK); 1563 1564 /* lock 0-byte exclusive */ 1565 io.lockx.in.mode = 0; 1566 status = smb_raw_lock(cli->tree, &io); 1567 CHECK_STATUS(status, NT_STATUS_OK); 1568 1569 /* test contention */ 1570 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; 1571 io.lockx.in.locks = &lock2; 1572 io.lockx.in.file.fnum = fnum2; 1573 status = smb_raw_lock(cli->tree, &io); 1574 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED, 1575 NT_STATUS_FILE_LOCK_CONFLICT); 1576 1577 /* unlock */ 1578 io.lockx.in.ulock_cnt = 1; 1579 io.lockx.in.lock_cnt = 0; 1580 io.lockx.in.file.fnum = fnum1; 1581 io.lockx.in.locks = &lock1; 1582 status = smb_raw_lock(cli->tree, &io); 1583 CHECK_STATUS(status, NT_STATUS_OK); 1584 1585 /* test - can we take a shared lock? */ 1586 io.lockx.in.ulock_cnt = 0; 1587 io.lockx.in.lock_cnt = 1; 1588 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; 1589 io.lockx.in.file.fnum = fnum2; 1590 io.lockx.in.locks = &lock2; 1591 status = smb_raw_lock(cli->tree, &io); 1592 1593 /* XXX Samba 3 will fail this test. This is temporary(because this isn't 1594 * new to Win7, it succeeds in WinXP too), until I can come to a 1595 * resolution as to whether Samba should support this or not. There is 1596 * code to preference unlocking exclusive locks before shared locks, 1597 * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */ 1598 if (TARGET_IS_SAMBA3(tctx)) { 1599 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED, 1600 NT_STATUS_FILE_LOCK_CONFLICT); 1601 } else { 1602 CHECK_STATUS(status, NT_STATUS_OK); 1603 } 1604 1605 /* cleanup */ 1606 io.lockx.in.ulock_cnt = 1; 1607 io.lockx.in.lock_cnt = 0; 1608 status = smb_raw_lock(cli->tree, &io); 1609 1610 /* XXX Same as above. */ 1611 if (TARGET_IS_SAMBA3(tctx)) { 1612 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 1613 } else { 1614 CHECK_STATUS(status, NT_STATUS_OK); 1615 } 1616 1617 io.lockx.in.file.fnum = fnum1; 1618 io.lockx.in.locks = &lock1; 1619 status = smb_raw_lock(cli->tree, &io); 1620 CHECK_STATUS(status, NT_STATUS_OK); 1621 1622done: 1623 smbcli_close(cli->tree, fnum1); 1624 smbcli_close(cli->tree, fnum2); 1625 smb_raw_exit(cli->session); 1626 smbcli_deltree(cli->tree, BASEDIR); 1627 return ret; 1628} 1629 1630static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli) 1631{ 1632 union smb_lock io; 1633 NTSTATUS status; 1634 bool ret = true; 1635 int fnum1; 1636 const char *fname = BASEDIR "\\unlock_multiple.txt"; 1637 struct smb_lock_entry lock1; 1638 struct smb_lock_entry lock2; 1639 struct smb_lock_entry locks[2]; 1640 1641 torture_comment(tctx, "Testing LOCKX multiple unlock:\n"); 1642 1643 if (!torture_setup_dir(cli, BASEDIR)) { 1644 return false; 1645 } 1646 1647 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 1648 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx, 1649 "Failed to create %s - %s\n", 1650 fname, smbcli_errstr(cli->tree))); 1651 1652 /* Setup initial parameters */ 1653 io.lockx.level = RAW_LOCK_LOCKX; 1654 io.lockx.in.timeout = 0; 1655 1656 lock1.pid = cli->session->pid; 1657 lock1.offset = 0; 1658 lock1.count = 10; 1659 lock2.pid = cli->session->pid; 1660 lock2.offset = 10; 1661 lock2.count = 10; 1662 1663 locks[0] = lock1; 1664 locks[1] = lock2; 1665 1666 io.lockx.in.file.fnum = fnum1; 1667 io.lockx.in.mode = 0; /* exclusive */ 1668 1669 /** Test1: Take second lock, but not first. */ 1670 torture_comment(tctx, " unlock 2 locks, first one not locked. Expect no locks " 1671 "unlocked. \n"); 1672 1673 io.lockx.in.ulock_cnt = 0; 1674 io.lockx.in.lock_cnt = 1; 1675 io.lockx.in.locks = &lock2; 1676 status = smb_raw_lock(cli->tree, &io); 1677 CHECK_STATUS(status, NT_STATUS_OK); 1678 1679 /* Try to unlock both locks. */ 1680 io.lockx.in.ulock_cnt = 2; 1681 io.lockx.in.lock_cnt = 0; 1682 io.lockx.in.locks = locks; 1683 1684 status = smb_raw_lock(cli->tree, &io); 1685 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 1686 1687 /* Second lock should not be unlocked. */ 1688 io.lockx.in.ulock_cnt = 0; 1689 io.lockx.in.lock_cnt = 1; 1690 io.lockx.in.locks = &lock2; 1691 status = smb_raw_lock(cli->tree, &io); 1692 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); 1693 1694 /* cleanup */ 1695 io.lockx.in.ulock_cnt = 1; 1696 io.lockx.in.lock_cnt = 0; 1697 io.lockx.in.locks = &lock2; 1698 status = smb_raw_lock(cli->tree, &io); 1699 CHECK_STATUS(status, NT_STATUS_OK); 1700 1701 /** Test2: Take first lock, but not second. */ 1702 torture_comment(tctx, " unlock 2 locks, second one not locked. Expect first lock " 1703 "unlocked.\n"); 1704 1705 io.lockx.in.ulock_cnt = 0; 1706 io.lockx.in.lock_cnt = 1; 1707 io.lockx.in.locks = &lock1; 1708 status = smb_raw_lock(cli->tree, &io); 1709 CHECK_STATUS(status, NT_STATUS_OK); 1710 1711 /* Try to unlock both locks. */ 1712 io.lockx.in.ulock_cnt = 2; 1713 io.lockx.in.lock_cnt = 0; 1714 io.lockx.in.locks = locks; 1715 1716 status = smb_raw_lock(cli->tree, &io); 1717 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); 1718 1719 /* First lock should be unlocked. */ 1720 io.lockx.in.ulock_cnt = 0; 1721 io.lockx.in.lock_cnt = 1; 1722 io.lockx.in.locks = &lock1; 1723 status = smb_raw_lock(cli->tree, &io); 1724 CHECK_STATUS(status, NT_STATUS_OK); 1725 1726 /* cleanup */ 1727 io.lockx.in.ulock_cnt = 1; 1728 io.lockx.in.lock_cnt = 0; 1729 io.lockx.in.locks = &lock1; 1730 status = smb_raw_lock(cli->tree, &io); 1731 CHECK_STATUS(status, NT_STATUS_OK); 1732 1733done: 1734 smbcli_close(cli->tree, fnum1); 1735 smb_raw_exit(cli->session); 1736 smbcli_deltree(cli->tree, BASEDIR); 1737 return ret; 1738} 1739 1740/** 1741 * torture_locktest5 covers stacking pretty well, but its missing two tests: 1742 * - stacking an exclusive on top of shared fails 1743 * - stacking two exclusives fail 1744 */ 1745static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli) 1746{ 1747 union smb_lock io; 1748 NTSTATUS status; 1749 bool ret = true; 1750 int fnum1; 1751 const char *fname = BASEDIR "\\stacking.txt"; 1752 struct smb_lock_entry lock1; 1753 struct smb_lock_entry lock2; 1754 1755 torture_comment(tctx, "Testing stacking:\n"); 1756 1757 if (!torture_setup_dir(cli, BASEDIR)) { 1758 return false; 1759 } 1760 1761 io.generic.level = RAW_LOCK_LOCKX; 1762 1763 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); 1764 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx, 1765 "Failed to create %s - %s\n", 1766 fname, smbcli_errstr(cli->tree))); 1767 1768 /* Setup initial parameters */ 1769 io.lockx.level = RAW_LOCK_LOCKX; 1770 io.lockx.in.timeout = 0; 1771 1772 lock1.pid = cli->session->pid; 1773 lock1.offset = 0; 1774 lock1.count = 10; 1775 lock2.pid = cli->session->pid - 1; 1776 lock2.offset = 0; 1777 lock2.count = 10; 1778 1779 /** 1780 * Try to take a shared lock, then stack an exclusive. 1781 */ 1782 torture_comment(tctx, " stacking an exclusive on top of a shared lock fails.\n"); 1783 io.lockx.in.file.fnum = fnum1; 1784 io.lockx.in.locks = &lock1; 1785 1786 io.lockx.in.ulock_cnt = 0; 1787 io.lockx.in.lock_cnt = 1; 1788 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; 1789 status = smb_raw_lock(cli->tree, &io); 1790 CHECK_STATUS(status, NT_STATUS_OK); 1791 1792 io.lockx.in.ulock_cnt = 0; 1793 io.lockx.in.lock_cnt = 1; 1794 io.lockx.in.mode = 0; 1795 status = smb_raw_lock(cli->tree, &io); 1796 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED, 1797 NT_STATUS_FILE_LOCK_CONFLICT); 1798 1799 /* cleanup */ 1800 io.lockx.in.ulock_cnt = 1; 1801 io.lockx.in.lock_cnt = 0; 1802 status = smb_raw_lock(cli->tree, &io); 1803 CHECK_STATUS(status, NT_STATUS_OK); 1804 1805 /** 1806 * Prove that two exclusive locks do not stack. 1807 */ 1808 torture_comment(tctx, " two exclusive locks do not stack.\n"); 1809 io.lockx.in.ulock_cnt = 0; 1810 io.lockx.in.lock_cnt = 1; 1811 io.lockx.in.mode = 0; 1812 status = smb_raw_lock(cli->tree, &io); 1813 CHECK_STATUS(status, NT_STATUS_OK); 1814 status = smb_raw_lock(cli->tree, &io); 1815 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED, 1816 NT_STATUS_FILE_LOCK_CONFLICT); 1817 1818 /* cleanup */ 1819 io.lockx.in.ulock_cnt = 1; 1820 io.lockx.in.lock_cnt = 0; 1821 status = smb_raw_lock(cli->tree, &io); 1822 CHECK_STATUS(status, NT_STATUS_OK); 1823 1824done: 1825 smbcli_close(cli->tree, fnum1); 1826 smb_raw_exit(cli->session); 1827 smbcli_deltree(cli->tree, BASEDIR); 1828 return ret; 1829} 1830 1831/* 1832 basic testing of lock calls 1833*/ 1834struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx) 1835{ 1836 struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK"); 1837 1838 torture_suite_add_1smb_test(suite, "lockx", test_lockx); 1839 torture_suite_add_1smb_test(suite, "lock", test_lock); 1840 torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh); 1841 torture_suite_add_1smb_test(suite, "async", test_async); 1842 torture_suite_add_1smb_test(suite, "errorcode", test_errorcode); 1843 torture_suite_add_1smb_test(suite, "changetype", test_changetype); 1844 1845 torture_suite_add_1smb_test(suite, "stacking", test_stacking); 1846 torture_suite_add_1smb_test(suite, "unlock", test_unlock); 1847 torture_suite_add_1smb_test(suite, "multiple_unlock", 1848 test_multiple_unlock); 1849 torture_suite_add_1smb_test(suite, "zerobytelocks", 1850 test_zerobytelocks); 1851 1852 return suite; 1853} 1854