root/source4/torture/basic/locking.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. torture_locktest1
  2. torture_locktest2
  3. torture_locktest3
  4. torture_locktest4
  5. torture_locktest5
  6. torture_locktest6
  7. torture_locktest7
  8. torture_base_locktest

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    basic locking tests
   5 
   6    Copyright (C) Andrew Tridgell 2000-2004
   7    Copyright (C) Jeremy Allison 2000-2004
   8    
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13    
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18    
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 #include "libcli/raw/libcliraw.h"
  25 #include "libcli/libcli.h"
  26 #include "torture/smbtorture.h"
  27 #include "torture/util.h"
  28 #include "system/time.h"
  29 #include "system/filesys.h"
  30 
  31 #define BASEDIR "\\locktest"
  32 
  33 /*
  34   This test checks for two things:
  35 
  36   1) correct support for retaining locks over a close (ie. the server
  37      must not use posix semantics)
  38   2) support for lock timeouts
  39  */
  40 static bool torture_locktest1(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
  41                               struct smbcli_state *cli1,
  42                               struct smbcli_state *cli2)
  43 {
  44         const char *fname = BASEDIR "\\lockt1.lck";
  45         int fnum1, fnum2, fnum3;
  46         time_t t1, t2;
  47         uint_t lock_timeout;
  48 
  49         if (!torture_setup_dir(cli1, BASEDIR)) {
  50                 return false;
  51         }
  52 
  53         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
  54         torture_assert(tctx, fnum1 != -1,
  55                                    talloc_asprintf(tctx, 
  56                 "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
  57         fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
  58         torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, 
  59                 "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
  60         fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
  61         torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx, 
  62                 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
  63 
  64         torture_assert_ntstatus_ok(tctx, 
  65                 smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK),
  66                 talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
  67 
  68         torture_assert(tctx, 
  69                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
  70                 "lock2 succeeded! This is a locking bug\n");
  71 
  72         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
  73                          NT_STATUS_LOCK_NOT_GRANTED)) return false;
  74 
  75         torture_assert(tctx,
  76                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
  77                 "lock2 succeeded! This is a locking bug\n");
  78 
  79         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
  80                                  NT_STATUS_FILE_LOCK_CONFLICT)) return false;
  81 
  82         torture_assert_ntstatus_ok(tctx, 
  83                 smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
  84                 talloc_asprintf(tctx, 
  85                 "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
  86 
  87         torture_assert(tctx, 
  88                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
  89                 "lock2 succeeded! This is a locking bug");
  90         
  91         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
  92                                  NT_STATUS_LOCK_NOT_GRANTED)) return false;
  93 
  94         torture_assert(tctx, 
  95                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
  96                 "lock2 succeeded! This is a locking bug");
  97         
  98         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
  99                                  NT_STATUS_LOCK_NOT_GRANTED)) return false;
 100 
 101         torture_assert(tctx, 
 102                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
 103                 "lock2 succeeded! This is a locking bug");
 104 
 105         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
 106                          NT_STATUS_FILE_LOCK_CONFLICT)) return false;
 107 
 108         lock_timeout = (6 + (random() % 20));
 109         torture_comment(tctx, "Testing lock timeout with timeout=%u\n", 
 110                                         lock_timeout);
 111         t1 = time(NULL);
 112         torture_assert(tctx, 
 113                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)),
 114                 "lock3 succeeded! This is a locking bug\n");
 115 
 116         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
 117                                  NT_STATUS_FILE_LOCK_CONFLICT)) return false;
 118         t2 = time(NULL);
 119 
 120         if (t2 - t1 < 5) {
 121                 torture_fail(tctx, 
 122                         "error: This server appears not to support timed lock requests");
 123         }
 124         torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
 125                (uint_t)(t2-t1), lock_timeout);
 126 
 127         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
 128                 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
 129 
 130         torture_assert(tctx, 
 131                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
 132                 "lock4 succeeded! This is a locking bug");
 133                 
 134         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
 135                          NT_STATUS_FILE_LOCK_CONFLICT)) return false;
 136 
 137         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
 138                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
 139 
 140         torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
 141                 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
 142 
 143         torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
 144                 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
 145 
 146         return true;
 147 }
 148 
 149 
 150 /*
 151   This test checks that 
 152 
 153   1) the server supports multiple locking contexts on the one SMB
 154   connection, distinguished by PID.  
 155 
 156   2) the server correctly fails overlapping locks made by the same PID (this
 157      goes against POSIX behaviour, which is why it is tricky to implement)
 158 
 159   3) the server denies unlock requests by an incorrect client PID
 160 */
 161 static bool torture_locktest2(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 162                               struct smbcli_state *cli)
 163 {
 164         const char *fname = BASEDIR "\\lockt2.lck";
 165         int fnum1, fnum2, fnum3;
 166 
 167         if (!torture_setup_dir(cli, BASEDIR)) {
 168                 return false;
 169         }
 170 
 171         torture_comment(tctx, "Testing pid context\n");
 172         
 173         cli->session->pid = 1;
 174 
 175         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
 176         torture_assert(tctx, fnum1 != -1, 
 177                 talloc_asprintf(tctx, 
 178                 "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
 179 
 180         fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
 181         torture_assert(tctx, fnum2 != -1,
 182                 talloc_asprintf(tctx, "open2 of %s failed (%s)", 
 183                        fname, smbcli_errstr(cli->tree)));
 184 
 185         cli->session->pid = 2;
 186 
 187         fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
 188         torture_assert(tctx, fnum3 != -1,
 189                 talloc_asprintf(tctx, 
 190                 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)));
 191 
 192         cli->session->pid = 1;
 193 
 194         torture_assert_ntstatus_ok(tctx, 
 195                 smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK),
 196                 talloc_asprintf(tctx, 
 197                 "lock1 failed (%s)", smbcli_errstr(cli->tree)));
 198 
 199         torture_assert(tctx, 
 200                 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
 201                 "WRITE lock1 succeeded! This is a locking bug");
 202                 
 203         if (!check_error(__location__, cli, ERRDOS, ERRlock, 
 204                          NT_STATUS_LOCK_NOT_GRANTED)) return false;
 205 
 206         torture_assert(tctx, 
 207                 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
 208                 "WRITE lock2 succeeded! This is a locking bug");
 209 
 210         if (!check_error(__location__, cli, ERRDOS, ERRlock, 
 211                          NT_STATUS_LOCK_NOT_GRANTED)) return false;
 212 
 213         torture_assert(tctx, 
 214                 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
 215                 "READ lock2 succeeded! This is a locking bug");
 216 
 217         if (!check_error(__location__, cli, ERRDOS, ERRlock, 
 218                          NT_STATUS_FILE_LOCK_CONFLICT)) return false;
 219 
 220         torture_assert_ntstatus_ok(tctx, 
 221                 smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK),
 222                 talloc_asprintf(tctx, 
 223                 "lock at 100 failed (%s)", smbcli_errstr(cli->tree)));
 224 
 225         cli->session->pid = 2;
 226 
 227         torture_assert(tctx, 
 228                 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
 229                 "unlock at 100 succeeded! This is a locking bug");
 230 
 231         torture_assert(tctx, 
 232                 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
 233                 "unlock1 succeeded! This is a locking bug");
 234 
 235         if (!check_error(__location__, cli, 
 236                                  ERRDOS, ERRnotlocked, 
 237                                  NT_STATUS_RANGE_NOT_LOCKED)) return false;
 238 
 239         torture_assert(tctx, 
 240                 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
 241                 "unlock2 succeeded! This is a locking bug");
 242 
 243         if (!check_error(__location__, cli, 
 244                          ERRDOS, ERRnotlocked, 
 245                          NT_STATUS_RANGE_NOT_LOCKED)) return false;
 246 
 247         torture_assert(tctx, 
 248                 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
 249                 "lock3 succeeded! This is a locking bug");
 250 
 251         if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
 252 
 253         cli->session->pid = 1;
 254 
 255         torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1), 
 256                 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
 257 
 258         torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
 259                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
 260 
 261         torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
 262                 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
 263 
 264         return true;
 265 }
 266 
 267 
 268 /*
 269   This test checks that 
 270 
 271   1) the server supports the full offset range in lock requests
 272 */
 273 static bool torture_locktest3(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 274                               struct smbcli_state *cli1,
 275                               struct smbcli_state *cli2)
 276 {
 277         const char *fname = BASEDIR "\\lockt3.lck";
 278         int fnum1, fnum2, i;
 279         uint32_t offset;
 280         extern int torture_numops;
 281 
 282 #define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
 283 
 284         torture_comment(tctx, "Testing 32 bit offset ranges");
 285 
 286         if (!torture_setup_dir(cli1, BASEDIR)) {
 287                 return false;
 288         }
 289 
 290         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
 291         torture_assert(tctx, fnum1 != -1, 
 292                 talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
 293         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
 294         torture_assert(tctx, fnum2 != -1,
 295                 talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
 296 
 297         torture_comment(tctx, "Establishing %d locks\n", torture_numops);
 298 
 299         for (offset=i=0;i<torture_numops;i++) {
 300                 NEXT_OFFSET;
 301                 torture_assert_ntstatus_ok(tctx, 
 302                         smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK),
 303                         talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree)));
 304 
 305                 torture_assert_ntstatus_ok(tctx, 
 306                         smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK),
 307                         talloc_asprintf(tctx, "lock2 %d failed (%s)", 
 308                                i, smbcli_errstr(cli1->tree)));
 309         }
 310 
 311         torture_comment(tctx, "Testing %d locks\n", torture_numops);
 312 
 313         for (offset=i=0;i<torture_numops;i++) {
 314                 NEXT_OFFSET;
 315 
 316                 torture_assert(tctx, 
 317                         !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)),
 318                         talloc_asprintf(tctx, "error: lock1 %d succeeded!", i));
 319 
 320                 torture_assert(tctx, 
 321                         !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)),
 322                         talloc_asprintf(tctx, "error: lock2 %d succeeded!", i));
 323 
 324                 torture_assert(tctx, 
 325                         !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)),
 326                         talloc_asprintf(tctx, "error: lock3 %d succeeded!", i));
 327 
 328                 torture_assert(tctx, 
 329                         !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)),
 330                         talloc_asprintf(tctx, "error: lock4 %d succeeded!", i));
 331         }
 332 
 333         torture_comment(tctx, "Removing %d locks\n", torture_numops);
 334 
 335         for (offset=i=0;i<torture_numops;i++) {
 336                 NEXT_OFFSET;
 337 
 338                 torture_assert_ntstatus_ok(tctx, 
 339                                         smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
 340                                         talloc_asprintf(tctx, "unlock1 %d failed (%s)", 
 341                                i,
 342                                smbcli_errstr(cli1->tree)));
 343 
 344                 torture_assert_ntstatus_ok(tctx, 
 345                         smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
 346                         talloc_asprintf(tctx, "unlock2 %d failed (%s)", 
 347                                i,
 348                                smbcli_errstr(cli1->tree)));
 349         }
 350 
 351         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
 352                 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
 353 
 354         torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
 355                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
 356 
 357         torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
 358                 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
 359 
 360         return true;
 361 }
 362 
 363 #define EXPECTED(ret, v) if ((ret) != (v)) { \
 364         torture_comment(tctx, "** "); correct = false; \
 365         }
 366 
 367 /*
 368   looks at overlapping locks
 369 */
 370 static bool torture_locktest4(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 371                               struct smbcli_state *cli1,
 372                               struct smbcli_state *cli2)
 373 {
 374         const char *fname = BASEDIR "\\lockt4.lck";
 375         int fnum1, fnum2, f;
 376         bool ret;
 377         uint8_t buf[1000];
 378         bool correct = true;
 379 
 380         if (!torture_setup_dir(cli1, BASEDIR)) {
 381                 return false;
 382         }
 383 
 384         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
 385         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
 386 
 387         memset(buf, 0, sizeof(buf));
 388 
 389         if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
 390                 torture_comment(tctx, "Failed to create file\n");
 391                 correct = false;
 392                 goto fail;
 393         }
 394 
 395         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
 396               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK));
 397         EXPECTED(ret, false);
 398         torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot");
 399             
 400         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) &&
 401               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK));
 402         EXPECTED(ret, true);
 403         torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
 404 
 405         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
 406               NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 22, 4, 0, WRITE_LOCK));
 407         EXPECTED(ret, false);
 408         torture_comment(tctx, "a different connection %s set overlapping write locks\n", ret?"can":"cannot");
 409             
 410         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 30, 4, 0, READ_LOCK)) &&
 411                 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 32, 4, 0, READ_LOCK));
 412         EXPECTED(ret, true);
 413         torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
 414         
 415         ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 40, 4, 0, WRITE_LOCK))) &&
 416               NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 42, 4, 0, WRITE_LOCK)));
 417         EXPECTED(ret, false);
 418         torture_comment(tctx, "a different pid %s set overlapping write locks\n", ret?"can":"cannot");
 419             
 420         ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 50, 4, 0, READ_LOCK))) &&
 421               NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 52, 4, 0, READ_LOCK)));
 422         EXPECTED(ret, true);
 423         torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
 424 
 425         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK)) &&
 426               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK));
 427         EXPECTED(ret, true);
 428         torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
 429 
 430         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK)) &&
 431               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK));
 432         EXPECTED(ret, false);
 433         torture_comment(tctx, "the same process %s set the same write lock twice\n", ret?"can":"cannot");
 434 
 435         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, READ_LOCK)) &&
 436               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, WRITE_LOCK));
 437         EXPECTED(ret, false);
 438         torture_comment(tctx, "the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
 439 
 440         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, WRITE_LOCK)) &&
 441               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, READ_LOCK));
 442         EXPECTED(ret, true);
 443         torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
 444 
 445         ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, WRITE_LOCK))) &&
 446               NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, READ_LOCK)));
 447         EXPECTED(ret, false);
 448         torture_comment(tctx, "a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
 449 
 450         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 110, 4, 0, READ_LOCK)) &&
 451               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 112, 4, 0, READ_LOCK)) &&
 452               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 110, 6));
 453         EXPECTED(ret, false);
 454         torture_comment(tctx, "the same process %s coalesce read locks\n", ret?"can":"cannot");
 455 
 456 
 457         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 120, 4, 0, WRITE_LOCK)) &&
 458               (smbcli_read(cli2->tree, fnum2, buf, 120, 4) == 4);
 459         EXPECTED(ret, false);
 460         torture_comment(tctx, "this server %s strict write locking\n", ret?"doesn't do":"does");
 461 
 462         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK)) &&
 463               (smbcli_write(cli2->tree, fnum2, 0, buf, 130, 4) == 4);
 464         EXPECTED(ret, false);
 465         torture_comment(tctx, "this server %s strict read locking\n", ret?"doesn't do":"does");
 466 
 467 
 468         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
 469               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
 470               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4)) &&
 471               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4));
 472         EXPECTED(ret, true);
 473         torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
 474 
 475 
 476         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, WRITE_LOCK)) &&
 477               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, READ_LOCK)) &&
 478               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4)) &&
 479               (smbcli_read(cli2->tree, fnum2, buf, 150, 4) == 4) &&
 480               !(smbcli_write(cli2->tree, fnum2, 0, buf, 150, 4) == 4) &&
 481               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4));
 482         EXPECTED(ret, true);
 483         torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
 484 
 485         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 160, 4, 0, READ_LOCK)) &&
 486               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 160, 4)) &&
 487               (smbcli_write(cli2->tree, fnum2, 0, buf, 160, 4) == 4) &&         
 488               (smbcli_read(cli2->tree, fnum2, buf, 160, 4) == 4);               
 489         EXPECTED(ret, true);
 490         torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
 491 
 492         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 170, 4, 0, WRITE_LOCK)) &&
 493               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 170, 4)) &&
 494               (smbcli_write(cli2->tree, fnum2, 0, buf, 170, 4) == 4) &&         
 495               (smbcli_read(cli2->tree, fnum2, buf, 170, 4) == 4);               
 496         EXPECTED(ret, true);
 497         torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
 498 
 499         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, WRITE_LOCK)) &&
 500               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, READ_LOCK)) &&
 501               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 190, 4)) &&
 502               !(smbcli_write(cli2->tree, fnum2, 0, buf, 190, 4) == 4) &&                
 503               (smbcli_read(cli2->tree, fnum2, buf, 190, 4) == 4);               
 504         EXPECTED(ret, true);
 505         torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
 506 
 507         smbcli_close(cli1->tree, fnum1);
 508         smbcli_close(cli2->tree, fnum2);
 509         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
 510         f = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
 511         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
 512               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, f, 0, 1, 0, READ_LOCK)) &&
 513               NT_STATUS_IS_OK(smbcli_close(cli1->tree, fnum1)) &&
 514               ((fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE)) != -1) &&
 515               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
 516         smbcli_close(cli1->tree, f);
 517         smbcli_close(cli1->tree, fnum1);
 518         EXPECTED(ret, true);
 519         torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
 520 
 521  fail:
 522         smbcli_close(cli1->tree, fnum1);
 523         smbcli_close(cli2->tree, fnum2);
 524         smbcli_unlink(cli1->tree, fname);
 525 
 526         return correct;
 527 }
 528 
 529 /*
 530   looks at lock upgrade/downgrade.
 531 */
 532 static bool torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1, 
     /* [<][>][^][v][top][bottom][index][help] */
 533                               struct smbcli_state *cli2)
 534 {
 535         const char *fname = BASEDIR "\\lockt5.lck";
 536         int fnum1, fnum2, fnum3;
 537         bool ret;
 538         uint8_t buf[1000];
 539         bool correct = true;
 540 
 541         if (!torture_setup_dir(cli1, BASEDIR)) {
 542                 return false;
 543         }
 544 
 545         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
 546         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
 547         fnum3 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
 548 
 549         memset(buf, 0, sizeof(buf));
 550 
 551         torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
 552                 "Failed to create file");
 553 
 554         /* Check for NT bug... */
 555         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
 556                   NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 1, 0, READ_LOCK));
 557         smbcli_close(cli1->tree, fnum1);
 558         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
 559         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
 560         EXPECTED(ret, true);
 561         torture_comment(tctx, "this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
 562         smbcli_close(cli1->tree, fnum1);
 563         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
 564         smbcli_unlock(cli1->tree, fnum3, 0, 1);
 565 
 566         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
 567               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 1, 1, 0, READ_LOCK));
 568         EXPECTED(ret, true);
 569         torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
 570 
 571         ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
 572         EXPECTED(ret, false);
 573 
 574         torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
 575 
 576         /* Unlock the process 2 lock. */
 577         smbcli_unlock(cli2->tree, fnum2, 0, 4);
 578 
 579         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
 580         EXPECTED(ret, false);
 581 
 582         torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
 583 
 584         /* Unlock the process 1 fnum3 lock. */
 585         smbcli_unlock(cli1->tree, fnum3, 0, 4);
 586 
 587         /* Stack 2 more locks here. */
 588         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK)) &&
 589                   NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK));
 590 
 591         EXPECTED(ret, true);
 592         torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
 593 
 594         /* Unlock the first process lock, then check this was the WRITE lock that was
 595                 removed. */
 596 
 597 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
 598         NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
 599 
 600         EXPECTED(ret, true);
 601         torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
 602 
 603         /* Unlock the process 2 lock. */
 604         smbcli_unlock(cli2->tree, fnum2, 0, 4);
 605 
 606         /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
 607 
 608         ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 1, 1)) &&
 609                   NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
 610                   NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
 611 
 612         EXPECTED(ret, true);
 613         torture_comment(tctx, "the same process %s unlock the stack of 3 locks\n", ret?"can":"cannot");
 614 
 615         /* Ensure the next unlock fails. */
 616         ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
 617         EXPECTED(ret, false);
 618         torture_comment(tctx, "the same process %s count the lock stack\n", !ret?"can":"cannot"); 
 619 
 620         /* Ensure connection 2 can get a write lock. */
 621         ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, WRITE_LOCK));
 622         EXPECTED(ret, true);
 623 
 624         torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
 625 
 626 
 627         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
 628                 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
 629 
 630         torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
 631                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
 632 
 633         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum3),
 634                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
 635 
 636         torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
 637                 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
 638 
 639         return correct;
 640 }
 641 
 642 /*
 643   tries the unusual lockingX locktype bits
 644 */
 645 static bool torture_locktest6(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 646                               struct smbcli_state *cli)
 647 {
 648         const char *fname[1] = { "\\lock6.txt" };
 649         int i;
 650         int fnum;
 651         NTSTATUS status;
 652 
 653         if (!torture_setup_dir(cli, BASEDIR)) {
 654                 return false;
 655         }
 656 
 657         for (i=0;i<1;i++) {
 658                 torture_comment(tctx, "Testing %s\n", fname[i]);
 659 
 660                 smbcli_unlink(cli->tree, fname[i]);
 661 
 662                 fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
 663                 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
 664                 smbcli_close(cli->tree, fnum);
 665                 torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
 666 
 667                 fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
 668                 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
 669                 smbcli_close(cli->tree, fnum);
 670                 torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
 671 
 672                 smbcli_unlink(cli->tree, fname[i]);
 673         }
 674 
 675         return true;
 676 }
 677 
 678 static bool torture_locktest7(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 679                               struct smbcli_state *cli1)
 680 {
 681         const char *fname = BASEDIR "\\lockt7.lck";
 682         int fnum1;
 683         int fnum2 = -1;
 684         size_t size;
 685         uint8_t buf[200];
 686         bool correct = false;
 687 
 688         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
 689                                    talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
 690 
 691         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
 692 
 693         memset(buf, 0, sizeof(buf));
 694 
 695         torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
 696                 "Failed to create file");
 697 
 698         cli1->session->pid = 1;
 699 
 700         torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
 701                 talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s", 
 702                        smbcli_errstr(cli1->tree)));
 703 
 704         torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
 705 
 706         torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4, 
 707                         talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)", 
 708                        smbcli_errstr(cli1->tree)));
 709 
 710         torture_comment(tctx, "pid1 successfully read the range 130:4\n");
 711 
 712         if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
 713                 torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
 714                 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
 715                         "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
 716         } else {
 717                 torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
 718         }
 719 
 720         cli1->session->pid = 2;
 721 
 722         if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
 723                 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
 724         } else {
 725                 torture_comment(tctx, "pid2 successfully read the range 130:4\n");
 726         }
 727 
 728         if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
 729                 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
 730                 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT, 
 731                         "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
 732         } else {
 733                 torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)"); 
 734         }
 735 
 736         cli1->session->pid = 1;
 737         smbcli_unlock(cli1->tree, fnum1, 130, 4);
 738 
 739         torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
 740                 talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s", 
 741                        smbcli_errstr(cli1->tree)));
 742         torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
 743 
 744         torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4, 
 745                 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s", 
 746                        smbcli_errstr(cli1->tree)));
 747         torture_comment(tctx, "pid1 successfully read the range 130:4\n");
 748 
 749         torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4, 
 750                 talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
 751                        smbcli_errstr(cli1->tree)));
 752         torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
 753 
 754         cli1->session->pid = 2;
 755 
 756         if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
 757                 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", 
 758                        smbcli_errstr(cli1->tree));
 759                 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT, 
 760                         "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
 761         } else {
 762                 torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
 763         }
 764 
 765         if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
 766                 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", 
 767                        smbcli_errstr(cli1->tree));
 768                 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
 769                         torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
 770                                __location__);
 771                         goto fail;
 772                 }
 773         } else {
 774                 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n", 
 775                        __location__);
 776                 goto fail;
 777         }
 778 
 779         torture_comment(tctx, "Testing truncate of locked file.\n");
 780 
 781         fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
 782 
 783         torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
 784 
 785         torture_comment(tctx, "Truncated locked file.\n");
 786 
 787         torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL), 
 788                 talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
 789 
 790         torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
 791 
 792         cli1->session->pid = 1;
 793 
 794         smbcli_unlock(cli1->tree, fnum1, 130, 4);
 795         correct = true;
 796 
 797 fail:
 798         smbcli_close(cli1->tree, fnum1);
 799         smbcli_close(cli1->tree, fnum2);
 800         smbcli_unlink(cli1->tree, fname);
 801 
 802         return correct;
 803 }
 804 
 805 struct torture_suite *torture_base_locktest(TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 806 {
 807         struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
 808         torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
 809         torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
 810         torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
 811         torture_suite_add_2smb_test(suite, "LOCK4",  torture_locktest4);
 812         torture_suite_add_2smb_test(suite, "LOCK5",  torture_locktest5);
 813         torture_suite_add_1smb_test(suite, "LOCK6",  torture_locktest6);
 814         torture_suite_add_1smb_test(suite, "LOCK7",  torture_locktest7);
 815 
 816         return suite;
 817 }

/* [<][>][^][v][top][bottom][index][help] */