From e324e21457b232acb13a06fa5a4b8f363b3dec7c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 18 Jun 2001 08:26:15 +0000 Subject: added a oplock break handler hook to the client code, this allows for more complete testing of oplocks from smbtorture and would also be essential if a client app ever really did want to use oplocks properly (This used to be commit 3d4a3bfacd9ef225aeaab801e5a216d12814b60a) --- source3/Makefile.in | 1 + source3/include/client.h | 3 ++ source3/include/proto.h | 6 ++++ source3/libsmb/clientgen.c | 54 +++++----------------------------- source3/libsmb/clioplock.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++ source3/utils/torture.c | 48 +++++++++++++++++++++++++++++-- 6 files changed, 135 insertions(+), 49 deletions(-) create mode 100644 source3/libsmb/clioplock.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 16c35ca41c..7d70e755b0 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -121,6 +121,7 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \ libsmb/namequery.o libsmb/nmblib.o libsmb/clistr.o \ libsmb/nterr.o libsmb/smbdes.o libsmb/smbencrypt.o \ libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \ + libsmb/clioplock.o \ libsmb/passchange.o libsmb/unexpected.o $(RPC_PARSE_OBJ1) LIBMSRPC_OBJ = libsmb/cli_lsarpc.o libsmb/cli_samr.o libsmb/cli_spoolss.o \ diff --git a/source3/include/client.h b/source3/include/client.h index bdc2383f8e..ecd97c1433 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -132,6 +132,9 @@ struct cli_state { BOOL use_oplocks; /* should we use oplocks? */ BOOL use_level_II_oplocks; /* should we use level II oplocks? */ + + /* a oplock break request handler */ + BOOL (*oplock_handler)(struct cli_state *cli, int fnum, unsigned char level); }; #endif /* _CLIENT_H */ diff --git a/source3/include/proto.h b/source3/include/proto.h index b2f41e231f..3bc62add3e 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1097,6 +1097,12 @@ BOOL cli_message_start(struct cli_state *cli, char *host, char *username, BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp); BOOL cli_message_end(struct cli_state *cli, int grp); +/* The following definitions come from libsmb/clioplock.c */ + +BOOL cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level); +void cli_oplock_handler(struct cli_state *cli, + BOOL (*handler)(struct cli_state *, int, unsigned char)); + /* The following definitions come from libsmb/cliprint.c */ int cli_print_queue(struct cli_state *cli, diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 8e00bca82a..e9f55850ac 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -25,7 +25,6 @@ extern int DEBUGLEVEL; -static void cli_process_oplock(struct cli_state *cli); /* * Change the port number used to call on @@ -53,7 +52,11 @@ BOOL cli_receive_smb(struct cli_state *cli) CVAL(cli->inbuf,smb_com) == SMBlockingX && SVAL(cli->inbuf,smb_vwv6) == 0 && SVAL(cli->inbuf,smb_vwv7) == 0) { - if (cli->use_oplocks) cli_process_oplock(cli); + if (cli->oplock_handler) { + int fnum = SVAL(cli->inbuf,smb_vwv2); + unsigned char level = CVAL(cli->inbuf,smb_vwv3+1); + if (!cli->oplock_handler(cli, fnum, level)) return False; + } /* try to prevent loops */ CVAL(cli->inbuf,smb_com) = 0xFF; goto again; @@ -125,51 +128,6 @@ void cli_setup_bcc(struct cli_state *cli, void *p) } -/**************************************************************************** -process an oplock break request from the server -****************************************************************************/ -static void cli_process_oplock(struct cli_state *cli) -{ - char *oldbuf = cli->outbuf; - pstring buf; - int fnum; - unsigned char level; - - fnum = SVAL(cli->inbuf,smb_vwv2); - level = CVAL(cli->inbuf,smb_vwv3+1); - - /* damn, we really need to keep a record of open files so we - can detect a oplock break and a close crossing on the - wire. for now this swallows the errors */ - if (fnum == 0) return; - - /* Ignore level II break to none's. */ - if (level == OPLOCKLEVEL_NONE) - return; - - cli->outbuf = buf; - - memset(buf,'\0',smb_size); - set_message(buf,8,0,True); - - CVAL(buf,smb_com) = SMBlockingX; - SSVAL(buf,smb_tid, cli->cnum); - cli_setup_packet(cli); - SSVAL(buf,smb_vwv0,0xFF); - SSVAL(buf,smb_vwv1,0); - SSVAL(buf,smb_vwv2,fnum); - if (cli->use_level_II_oplocks) - SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */ - else - SSVAL(buf,smb_vwv3,2); /* exclusive oplock break ack */ - SIVAL(buf,smb_vwv4,0); /* timoeut */ - SSVAL(buf,smb_vwv6,0); /* unlockcount */ - SSVAL(buf,smb_vwv7,0); /* lockcount */ - - cli_send_smb(cli); - - cli->outbuf = oldbuf; -} /**************************************************************************** initialise a client structure @@ -219,6 +177,8 @@ struct cli_state *cli_initialise(struct cli_state *cli) cli->max_xmit = cli->bufsize; cli->outbuf = (char *)malloc(cli->bufsize); cli->inbuf = (char *)malloc(cli->bufsize); + cli->oplock_handler = cli_oplock_ack; + if (!cli->outbuf || !cli->inbuf) { return NULL; diff --git a/source3/libsmb/clioplock.c b/source3/libsmb/clioplock.c new file mode 100644 index 0000000000..a52dcf3a3e --- /dev/null +++ b/source3/libsmb/clioplock.c @@ -0,0 +1,72 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0 + SMB client oplock functions + Copyright (C) Andrew Tridgell 2001 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define NO_SYSLOG + +#include "includes.h" +extern int DEBUGLEVEL; + + +/**************************************************************************** +send an ack for an oplock break request +****************************************************************************/ +BOOL cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level) +{ + char *oldbuf = cli->outbuf; + pstring buf; + BOOL ret; + + cli->outbuf = buf; + + memset(buf,'\0',smb_size); + set_message(buf,8,0,True); + + CVAL(buf,smb_com) = SMBlockingX; + SSVAL(buf,smb_tid, cli->cnum); + cli_setup_packet(cli); + SSVAL(buf,smb_vwv0,0xFF); + SSVAL(buf,smb_vwv1,0); + SSVAL(buf,smb_vwv2,fnum); + if (level == 1) + SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */ + else + SSVAL(buf,smb_vwv3,2); /* exclusive oplock break ack */ + SIVAL(buf,smb_vwv4,0); /* timoeut */ + SSVAL(buf,smb_vwv6,0); /* unlockcount */ + SSVAL(buf,smb_vwv7,0); /* lockcount */ + + ret = cli_send_smb(cli); + + cli->outbuf = oldbuf; + + return ret; +} + + +/**************************************************************************** +set the oplock handler for a connection +****************************************************************************/ +void cli_oplock_handler(struct cli_state *cli, + BOOL (*handler)(struct cli_state *, int, unsigned char)) +{ + cli->oplock_handler = handler; +} + diff --git a/source3/utils/torture.c b/source3/utils/torture.c index 982be77151..5f08887a60 100644 --- a/source3/utils/torture.c +++ b/source3/utils/torture.c @@ -2091,6 +2091,49 @@ static void run_oplock2(int dummy) printf("finished oplock test 2\n"); } +/* handler for oplock 3 tests */ +static BOOL oplock3_handler(struct cli_state *cli, int fnum, unsigned char level) +{ + printf("got oplock break fnum=%d level=%d\n", + fnum, level); + return cli_oplock_ack(cli, fnum, level); +} + +static void run_oplock3(int dummy) +{ + static struct cli_state cli; + char *fname = "\\oplockt3.dat"; + int fnum; + char buf[4] = "abcd"; + + printf("starting oplock test 3\n"); + + if (fork() == 0) { + /* Child code */ + if (!open_connection(&cli)) return; + sleep(2); + /* try to trigger a oplock break in parent */ + fnum = cli_open(&cli, fname, O_RDWR, DENY_NONE); + cli_write(&cli, fnum, 0, buf, 0, 4); + exit(0); + } + + /* parent code */ + use_oplocks = True; + use_level_II_oplocks = True; + if (!open_connection(&cli)) return; + cli_oplock_handler(&cli, oplock3_handler); + fnum = cli_open(&cli, fname, O_RDWR|O_CREAT, DENY_NONE); + cli_write(&cli, fnum, 0, buf, 0, 4); + cli_close(&cli, fnum); + fnum = cli_open(&cli, fname, O_RDWR, DENY_NONE); + cli.timeout = 20000; + cli_receive_smb(&cli); + printf("finished oplock test 3\n"); +} + + + /* Test delete on close semantics. */ @@ -2764,6 +2807,7 @@ static struct { {"NBWNT", run_nbwnt, 0}, {"OPLOCK1", run_oplock1, 0}, {"OPLOCK2", run_oplock2, 0}, + {"OPLOCK3", run_oplock3, 0}, {"DIR", run_dirtest, 0}, {"DENY1", run_denytest1, 0}, {"DENY2", run_denytest2, 0}, @@ -2790,8 +2834,8 @@ static void run_test(char *name) } for (i=0;torture_ops[i].name;i++) { - fstrcpy(randomfname, "\\XXXXXXX"); - mktemp(randomfname); + snprintf(randomfname, sizeof(randomfname), "\\XX%x", + (unsigned)random()); if (strequal(name, torture_ops[i].name)) { start_timer(); -- cgit