📄 oplock.c
字号:
/* Unix SMB/CIFS implementation. basic raw test suite for oplocks Copyright (C) Andrew Tridgell 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "torture/torture.h"#include "librpc/gen_ndr/security.h"#include "libcli/raw/libcliraw.h"#include "libcli/raw/raw_proto.h"#include "libcli/libcli.h"#include "torture/util.h"#include "lib/events/events.h"#include "param/param.h"#include "lib/cmdline/popt_common.h"#include "libcli/resolve/resolve.h"#define CHECK_VAL(v, correct) do { \ if ((v) != (correct)) { \ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \ __location__, #v, (int)v, (int)correct); \ ret = false; \ }} while (0)#define CHECK_RANGE(v, min, max) do { \ if ((v) < (min) || (v) > (max)) { \ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got %d - should be between %d and %d\n", \ __location__, #v, (int)v, (int)min, (int)max); \ ret = false; \ }} while (0)#define CHECK_STRMATCH(v, correct) do { \ if (!v || strstr((v),(correct)) == NULL) { \ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got '%s' - should be '%s'\n", \ __location__, #v, v?v:"NULL", correct); \ ret = false; \ } \} while (0)#define CHECK_STATUS(tctx, status, correct) do { \ if (!NT_STATUS_EQUAL(status, correct)) { \ torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \ nt_errstr(status), nt_errstr(correct)); \ ret = false; \ goto done; \ }} while (0)static struct { int fnum; uint8_t level; int count; int failures;} break_info;#define BASEDIR "\\test_oplock"/* a handler function for oplock break requests. Ack it as a break to level II if possible*/static bool oplock_handler_ack_to_given(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private){ struct smbcli_tree *tree = (struct smbcli_tree *)private; const char *name; break_info.fnum = fnum; break_info.level = level; break_info.count++; switch (level) { case OPLOCK_BREAK_TO_LEVEL_II: name = "level II"; break; case OPLOCK_BREAK_TO_NONE: name = "none"; break; default: name = "unknown"; break_info.failures++; } printf("Acking to %s [0x%02X] in oplock handler\n", name, level); return smbcli_oplock_ack(tree, fnum, level);}/* a handler function for oplock break requests. Ack it as a break to none*/static bool oplock_handler_ack_to_none(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private){ struct smbcli_tree *tree = (struct smbcli_tree *)private; break_info.fnum = fnum; break_info.level = level; break_info.count++; printf("Acking to none in oplock handler\n"); return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);}/* a handler function for oplock break requests. Let it timeout*/static bool oplock_handler_timeout(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private){ break_info.fnum = fnum; break_info.level = level; break_info.count++; printf("Let oplock break timeout\n"); return true;}static void oplock_handler_close_recv(struct smbcli_request *req){ NTSTATUS status; status = smbcli_request_simple_recv(req); if (!NT_STATUS_IS_OK(status)) { printf("close failed in oplock_handler_close\n"); break_info.failures++; }}/* a handler function for oplock break requests - close the file*/static bool oplock_handler_close(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private){ union smb_close io; struct smbcli_tree *tree = (struct smbcli_tree *)private; struct smbcli_request *req; break_info.fnum = fnum; break_info.level = level; break_info.count++; io.close.level = RAW_CLOSE_CLOSE; io.close.in.file.fnum = fnum; io.close.in.write_time = 0; req = smb_raw_close_send(tree, &io); if (req == NULL) { printf("failed to send close in oplock_handler_close\n"); return false; } req->async.fn = oplock_handler_close_recv; req->async.private = NULL; return true;}static bool open_connection_no_level2_oplocks(struct torture_context *tctx, struct smbcli_state **c){ NTSTATUS status; struct smbcli_options options; lp_smbcli_options(tctx->lp_ctx, &options); options.use_level2_oplocks = false; status = smbcli_full_connection(tctx, c, torture_setting_string(tctx, "host", NULL), lp_smb_ports(tctx->lp_ctx), torture_setting_string(tctx, "share", NULL), NULL, cmdline_credentials, lp_resolve_context(tctx->lp_ctx), tctx->ev, &options); if (!NT_STATUS_IS_OK(status)) { printf("Failed to open connection - %s\n", nt_errstr(status)); return false; } return true;}static bool test_raw_oplock_exclusive1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2){ const char *fname = BASEDIR "\\test_exclusive1.dat"; NTSTATUS status; bool ret = true; union smb_open io; union smb_unlink unl; uint16_t fnum=0; if (!torture_setup_dir(cli1, BASEDIR)) { return false; } /* cleanup */ smbcli_unlink(cli1->tree, fname); smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms */ io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive oplock (share mode: none)\n"); ZERO_STRUCT(break_info); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; status = smb_raw_open(cli1->tree, tctx, &io); CHECK_STATUS(tctx, status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN); torture_comment(tctx, "a 2nd open should not cause a break\n"); status = smb_raw_open(cli2->tree, tctx, &io); CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); CHECK_VAL(break_info.count, 0); CHECK_VAL(break_info.failures, 0); torture_comment(tctx, "unlink it - should also be no break\n"); unl.unlink.in.pattern = fname; unl.unlink.in.attrib = 0; status = smb_raw_unlink(cli2->tree, &unl); CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); CHECK_VAL(break_info.count, 0); CHECK_VAL(break_info.failures, 0); smbcli_close(cli1->tree, fnum);done: smb_raw_exit(cli1->session); smb_raw_exit(cli2->session); smbcli_deltree(cli1->tree, BASEDIR); return ret;}static bool test_raw_oplock_exclusive2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2){ const char *fname = BASEDIR "\\test_exclusive2.dat"; NTSTATUS status; bool ret = true; union smb_open io; union smb_unlink unl; uint16_t fnum=0, fnum2=0; if (!torture_setup_dir(cli1, BASEDIR)) { return false; } /* cleanup */ smbcli_unlink(cli1->tree, fname); smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms */ io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive oplock (share mode: all)\n"); ZERO_STRUCT(break_info); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE| NTCREATEX_SHARE_ACCESS_DELETE; status = smb_raw_open(cli1->tree, tctx, &io); CHECK_STATUS(tctx, status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN); torture_comment(tctx, "a 2nd open should cause a break to level 2\n"); status = smb_raw_open(cli2->tree, tctx, &io); CHECK_STATUS(tctx, status, NT_STATUS_OK); fnum2 = io.ntcreatex.out.file.fnum; CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); CHECK_VAL(break_info.count, 1); CHECK_VAL(break_info.fnum, fnum); CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); CHECK_VAL(break_info.failures, 0); ZERO_STRUCT(break_info); /* now we have 2 level II oplocks... */ torture_comment(tctx, "try to unlink it - should not cause a break, but a sharing violation\n"); unl.unlink.in.pattern = fname; unl.unlink.in.attrib = 0; status = smb_raw_unlink(cli2->tree, &unl); CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); CHECK_VAL(break_info.count, 0); CHECK_VAL(break_info.failures, 0); torture_comment(tctx, "close 1st handle\n"); smbcli_close(cli1->tree, fnum); torture_comment(tctx, "try to unlink it - should not cause a break, but a sharing violation\n"); unl.unlink.in.pattern = fname; unl.unlink.in.attrib = 0; status = smb_raw_unlink(cli2->tree, &unl); CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); CHECK_VAL(break_info.count, 0); CHECK_VAL(break_info.failures, 0); torture_comment(tctx, "close 1st handle\n"); smbcli_close(cli2->tree, fnum2); torture_comment(tctx, "unlink it\n"); unl.unlink.in.pattern = fname; unl.unlink.in.attrib = 0; status = smb_raw_unlink(cli2->tree, &unl); CHECK_STATUS(tctx, status, NT_STATUS_OK); CHECK_VAL(break_info.count, 0); CHECK_VAL(break_info.failures, 0);done: smb_raw_exit(cli1->session); smb_raw_exit(cli2->session); smbcli_deltree(cli1->tree, BASEDIR); return ret;}static bool test_raw_oplock_exclusive3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2){ const char *fname = BASEDIR "\\test_exclusive3.dat"; NTSTATUS status; bool ret = true; union smb_open io; union smb_setfileinfo sfi; uint16_t fnum=0; if (!torture_setup_dir(cli1, BASEDIR)) { return false; } /* cleanup */ smbcli_unlink(cli1->tree, fname); smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms */ io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive oplock (share mode: none)\n"); ZERO_STRUCT(break_info); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; status = smb_raw_open(cli1->tree, tctx, &io); CHECK_STATUS(tctx, status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN); torture_comment(tctx, "setpathinfo EOF should trigger a break to none\n"); ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; sfi.generic.in.file.path = fname; sfi.end_of_file_info.in.size = 100; status = smb_raw_setpathinfo(cli2->tree, &sfi);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -