summaryrefslogtreecommitdiff
path: root/source4/smb_server
diff options
context:
space:
mode:
Diffstat (limited to 'source4/smb_server')
-rw-r--r--source4/smb_server/config.mk1
-rw-r--r--source4/smb_server/handle.c137
-rw-r--r--source4/smb_server/smb/nttrans.c15
-rw-r--r--source4/smb_server/smb/receive.c4
-rw-r--r--source4/smb_server/smb/reply.c229
-rw-r--r--source4/smb_server/smb/request.c92
-rw-r--r--source4/smb_server/smb/service.c14
-rw-r--r--source4/smb_server/smb/trans2.c18
-rw-r--r--source4/smb_server/smb_server.h104
-rw-r--r--source4/smb_server/tcon.c13
10 files changed, 522 insertions, 105 deletions
diff --git a/source4/smb_server/config.mk b/source4/smb_server/config.mk
index 6130d7ce9f..abcade4999 100644
--- a/source4/smb_server/config.mk
+++ b/source4/smb_server/config.mk
@@ -11,6 +11,7 @@ PRIVATE_DEPENDENCIES = SMB_SERVER
# Start SUBSYSTEM SMB
[SUBSYSTEM::SMB_SERVER]
OBJ_FILES = \
+ handle.o \
tcon.o \
session.o \
management.o
diff --git a/source4/smb_server/handle.c b/source4/smb_server/handle.c
new file mode 100644
index 0000000000..c2fea9e91c
--- /dev/null
+++ b/source4/smb_server/handle.c
@@ -0,0 +1,137 @@
+/*
+ Unix SMB/CIFS implementation.
+ Manage smbsrv_handle structures
+ Copyright (C) Stefan Metzmacher 2006
+
+ 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.
+*/
+
+#include "includes.h"
+#include "dlinklist.h"
+#include "smb_server/smb_server.h"
+#include "ntvfs/ntvfs.h"
+
+
+/****************************************************************************
+init the handle structures
+****************************************************************************/
+NTSTATUS smbsrv_init_handles(struct smbsrv_tcon *tcon, uint64_t limit)
+{
+ /*
+ * the idr_* functions take 'int' as limit,
+ * and only work with a max limit 0x00FFFFFF
+ */
+ limit &= 0x00FFFFFF;
+
+ tcon->handles.idtree_hid = idr_init(tcon);
+ NT_STATUS_HAVE_NO_MEMORY(tcon->handles.idtree_hid);
+ tcon->handles.idtree_limit = limit;
+ tcon->handles.list = NULL;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+find a handle given a handle id
+****************************************************************************/
+static struct smbsrv_handle *smbsrv_handle_find(struct smbsrv_handles_context *handles_ctx,
+ uint64_t hid, struct timeval request_time)
+{
+ void *p;
+ struct smbsrv_handle *handle;
+
+ if (hid == 0) return NULL;
+
+ if (hid > handles_ctx->idtree_limit) return NULL;
+
+ p = idr_find(handles_ctx->idtree_hid, hid);
+ if (!p) return NULL;
+
+ handle = talloc_get_type(p, struct smbsrv_handle);
+ if (!handle) return NULL;
+
+ /* only give it away when the ntvfs subsystem has made the handle valid */
+ if (!handle->ntvfs) return NULL;
+
+ handle->statistics.last_use_time = request_time;
+
+ return handle;
+}
+
+struct smbsrv_handle *smbsrv_smb_handle_find(struct smbsrv_tcon *smb_tcon,
+ uint16_t fnum, struct timeval request_time)
+{
+ return smbsrv_handle_find(&smb_tcon->handles, fnum, request_time);
+}
+
+/*
+ destroy a connection structure
+*/
+static int smbsrv_handle_destructor(void *ptr)
+{
+ struct smbsrv_handle *handle = talloc_get_type(ptr, struct smbsrv_handle);
+ struct smbsrv_handles_context *handles_ctx;
+
+ handles_ctx = &handle->tcon->handles;
+
+ idr_remove(handles_ctx->idtree_hid, handle->hid);
+ DLIST_REMOVE(handles_ctx->list, handle);
+ DLIST_REMOVE(handle->session->handles, &handle->session_item);
+
+ /* tell the ntvfs backend that we are disconnecting */
+ if (handle->ntvfs) {
+ talloc_free(handle->ntvfs);
+ handle->ntvfs = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ find first available handle slot
+*/
+struct smbsrv_handle *smbsrv_handle_new(struct smbsrv_request *req)
+{
+ struct smbsrv_handles_context *handles_ctx = &req->tcon->handles;
+ struct smbsrv_handle *handle;
+ int i;
+
+ handle = talloc_zero(req, struct smbsrv_handle);
+ if (!handle) return NULL;
+ handle->tcon = req->tcon;
+ handle->session = req->session;
+
+ i = idr_get_new_above(handles_ctx->idtree_hid, handle, 1, handles_ctx->idtree_limit);
+ if (i == -1) {
+ DEBUG(1,("ERROR! Out of handle structures\n"));
+ goto failed;
+ }
+ handle->hid = i;
+ handle->session_item.handle = handle;
+
+ DLIST_ADD(handles_ctx->list, handle);
+ DLIST_ADD(handle->session->handles, &handle->session_item);
+ talloc_set_destructor(handle, smbsrv_handle_destructor);
+
+ /* now fill in some statistics */
+ handle->statistics.open_time = req->request_time;
+ handle->statistics.last_use_time = req->request_time;
+
+ return handle;
+
+failed:
+ talloc_free(handle);
+ return NULL;
+}
diff --git a/source4/smb_server/smb/nttrans.c b/source4/smb_server/smb/nttrans.c
index c5b950ec5b..3bc0ab69b2 100644
--- a/source4/smb_server/smb/nttrans.c
+++ b/source4/smb_server/smb/nttrans.c
@@ -75,7 +75,7 @@ static NTSTATUS nttrans_create_send(struct nttrans_op *op)
params = op->trans->out.params.data;
SSVAL(params, 0, io->ntcreatex.out.oplock_level);
- SSVAL(params, 2, io->ntcreatex.out.file.fnum);
+ smbsrv_push_fnum(params, 2, io->ntcreatex.out.file.ntvfs);
SIVAL(params, 4, io->ntcreatex.out.create_action);
SIVAL(params, 8, 0); /* ea error offset */
push_nttime(params, 12, io->ntcreatex.out.create_time);
@@ -230,12 +230,13 @@ static NTSTATUS nttrans_query_sec_desc(struct smbsrv_request *req,
NT_STATUS_HAVE_NO_MEMORY(io);
io->query_secdesc.level = RAW_FILEINFO_SEC_DESC;
- io->query_secdesc.in.file.fnum = SVAL(trans->in.params.data, 0);
+ io->query_secdesc.in.file.ntvfs = smbsrv_pull_fnum(req, trans->in.params.data, 0);
io->query_secdesc.in.secinfo_flags = IVAL(trans->in.params.data, 4);
op->op_info = io;
op->send_fn = nttrans_query_sec_desc_send;
+ SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io->query_secdesc.in.file.ntvfs);
return ntvfs_qfileinfo(req->ntvfs, io);
}
@@ -259,7 +260,7 @@ static NTSTATUS nttrans_set_sec_desc(struct smbsrv_request *req,
NT_STATUS_HAVE_NO_MEMORY(io);
io->set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
- io->set_secdesc.in.file.fnum = SVAL(trans->in.params.data, 0);
+ io->set_secdesc.in.file.ntvfs = smbsrv_pull_fnum(req, trans->in.params.data, 0);
io->set_secdesc.in.secinfo_flags = IVAL(trans->in.params.data, 4);
io->set_secdesc.in.sd = talloc(io, struct security_descriptor);
@@ -270,6 +271,7 @@ static NTSTATUS nttrans_set_sec_desc(struct smbsrv_request *req,
(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
NT_STATUS_NOT_OK_RETURN(status);
+ SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io->set_secdesc.in.file.ntvfs);
return ntvfs_setfileinfo(req->ntvfs, io);
}
@@ -304,6 +306,7 @@ static NTSTATUS nttrans_ioctl_send(struct nttrans_op *op)
return NT_STATUS_OK;
}
+
/*
parse NTTRANS_IOCTL request
*/
@@ -323,7 +326,7 @@ static NTSTATUS nttrans_ioctl(struct smbsrv_request *req,
nt->ntioctl.level = RAW_IOCTL_NTIOCTL;
nt->ntioctl.in.function = IVAL(trans->in.setup, 0);
- nt->ntioctl.in.file.fnum = SVAL(trans->in.setup, 4);
+ nt->ntioctl.in.file.ntvfs = smbsrv_pull_fnum(req, (uint8_t *)trans->in.setup, 4);
nt->ntioctl.in.fsctl = CVAL(trans->in.setup, 6);
nt->ntioctl.in.filter = CVAL(trans->in.setup, 7);
nt->ntioctl.in.max_data = trans->in.max_data;
@@ -332,6 +335,7 @@ static NTSTATUS nttrans_ioctl(struct smbsrv_request *req,
op->op_info = nt;
op->send_fn = nttrans_ioctl_send;
+ SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(nt->ntioctl.in.file.ntvfs);
return ntvfs_ioctl(req->ntvfs, nt);
}
@@ -408,13 +412,14 @@ static NTSTATUS nttrans_notify_change(struct smbsrv_request *req,
NT_STATUS_HAVE_NO_MEMORY(info);
info->in.completion_filter = IVAL(trans->in.setup, 0);
- info->in.file.fnum = SVAL(trans->in.setup, 4);
+ info->in.file.ntvfs = smbsrv_pull_fnum(req, (uint8_t *)trans->in.setup, 4);
info->in.recursive = SVAL(trans->in.setup, 6);
info->in.buffer_size = trans->in.max_param;
op->op_info = info;
op->send_fn = nttrans_notify_change_send;
+ SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(info->in.file.ntvfs);
return ntvfs_notify(req->ntvfs, info);
}
diff --git a/source4/smb_server/smb/receive.c b/source4/smb_server/smb/receive.c
index ee728e0ec5..a47d0a5442 100644
--- a/source4/smb_server/smb/receive.c
+++ b/source4/smb_server/smb/receive.c
@@ -31,7 +31,7 @@
/*
send an oplock break request to a client
*/
-NTSTATUS smbsrv_send_oplock_break(void *p, uint16_t fnum, uint8_t level)
+NTSTATUS smbsrv_send_oplock_break(void *p, struct ntvfs_handle *ntvfs, uint8_t level)
{
struct smbsrv_tcon *tcon = talloc_get_type(p, struct smbsrv_tcon);
struct smbsrv_request *req;
@@ -51,7 +51,7 @@ NTSTATUS smbsrv_send_oplock_break(void *p, uint16_t fnum, uint8_t level)
SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
SSVAL(req->out.vwv, VWV(1), 0);
- SSVAL(req->out.vwv, VWV(2), fnum);
+ smbsrv_push_fnum(req->out.vwv, VWV(2), ntvfs);
SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
SCVAL(req->out.vwv, VWV(3)+1, level);
SIVAL(req->out.vwv, VWV(4), 0);
diff --git a/source4/smb_server/smb/reply.c b/source4/smb_server/smb/reply.c
index 768fba1319..9abb35ad86 100644
--- a/source4/smb_server/smb/reply.c
+++ b/source4/smb_server/smb/reply.c
@@ -3,6 +3,7 @@
Main SMB reply routines
Copyright (C) Andrew Tridgell 1992-2003
Copyright (C) James J Myers 2003 <myersjj@samba.org>
+ Copyright (C) Stefan Metzmacher 2006
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
@@ -20,7 +21,7 @@
*/
/*
This file handles most of the reply_ calls that the server
- makes to handle specific protocols
+ makes to handle specific SMB commands
*/
#include "includes.h"
@@ -204,10 +205,11 @@ void smbsrv_reply_ioctl(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_ioctl_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
io->ioctl.level = RAW_IOCTL_IOCTL;
- io->ioctl.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ io->ioctl.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
io->ioctl.in.request = IVAL(req->in.vwv, VWV(1));
- /* call backend */
+ SMBSRV_CHECK_FILE_HANDLE_ERROR(io->ioctl.in.file.ntvfs,
+ NT_STATUS_DOS(ERRSRV, ERRerror));
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req->ntvfs, io));
}
@@ -353,7 +355,7 @@ static void reply_open_send(struct ntvfs_request *ntvfs)
/* construct reply */
smbsrv_setup_reply(req, 7, 0);
- SSVAL(req->out.vwv, VWV(0), oi->openold.out.file.fnum);
+ smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
SSVAL(req->out.vwv, VWV(1), oi->openold.out.attrib);
srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(2), oi->openold.out.write_time);
SIVAL(req->out.vwv, VWV(4), oi->openold.out.size);
@@ -408,7 +410,7 @@ static void reply_open_and_X_send(struct ntvfs_request *ntvfs)
SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
SSVAL(req->out.vwv, VWV(1), 0);
- SSVAL(req->out.vwv, VWV(2), oi->openx.out.file.fnum);
+ smbsrv_push_fnum(req->out.vwv, VWV(2), oi->openx.out.file.ntvfs);
SSVAL(req->out.vwv, VWV(3), oi->openx.out.attrib);
srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(4), oi->openx.out.write_time);
SIVAL(req->out.vwv, VWV(6), oi->openx.out.size);
@@ -423,7 +425,7 @@ static void reply_open_and_X_send(struct ntvfs_request *ntvfs)
SMBSRV_VWV_RESERVED(17, 2);
}
- req->chained_fnum = oi->openx.out.file.fnum;
+ req->chained_fnum = SVAL(req->out.vwv, VWV(2));
smbsrv_chain_reply(req);
}
@@ -475,7 +477,7 @@ static void reply_mknew_send(struct ntvfs_request *ntvfs)
/* build the reply */
smbsrv_setup_reply(req, 1, 0);
- SSVAL(req->out.vwv, VWV(0), oi->mknew.out.file.fnum);
+ smbsrv_push_fnum(req->out.vwv, VWV(0), oi->mknew.out.file.ntvfs);
smbsrv_send_reply(req);
}
@@ -524,7 +526,7 @@ static void reply_ctemp_send(struct ntvfs_request *ntvfs)
/* build the reply */
smbsrv_setup_reply(req, 1, 0);
- SSVAL(req->out.vwv, VWV(0), oi->ctemp.out.file.fnum);
+ smbsrv_push_fnum(req->out.vwv, VWV(0), oi->ctemp.out.file.ntvfs);
/* the returned filename is relative to the directory */
req_push_str(req, NULL, oi->ctemp.out.name, -1, STR_TERMINATE | STR_ASCII);
@@ -599,12 +601,16 @@ void smbsrv_reply_readbraw(struct smbsrv_request *req)
goto failed;
}
- io.readbraw.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ io.readbraw.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
io.readbraw.in.offset = IVAL(req->in.vwv, VWV(1));
io.readbraw.in.maxcnt = SVAL(req->in.vwv, VWV(3));
io.readbraw.in.mincnt = SVAL(req->in.vwv, VWV(4));
io.readbraw.in.timeout = IVAL(req->in.vwv, VWV(5));
+ if (!io.readbraw.in.file.ntvfs) {
+ goto failed;
+ }
+
/* the 64 bit variant */
if (req->in.wct == 10) {
uint32_t offset_high = IVAL(req->in.vwv, VWV(8));
@@ -695,17 +701,18 @@ void smbsrv_reply_lockread(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_lockread_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
io->lockread.level = RAW_READ_LOCKREAD;
- io->lockread.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ io->lockread.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
io->lockread.in.count = SVAL(req->in.vwv, VWV(1));
io->lockread.in.offset = IVAL(req->in.vwv, VWV(2));
io->lockread.in.remaining = SVAL(req->in.vwv, VWV(4));
-
+
/* setup the reply packet assuming the maximum possible read */
smbsrv_setup_reply(req, 5, 3 + io->lockread.in.count);
/* tell the backend where to put the data */
io->lockread.out.data = req->out.data + 3;
+ SMBSRV_CHECK_FILE_HANDLE(io->lockread.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
}
@@ -749,17 +756,18 @@ void smbsrv_reply_read(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_read_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
io->read.level = RAW_READ_READ;
- io->read.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ io->read.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
io->read.in.count = SVAL(req->in.vwv, VWV(1));
io->read.in.offset = IVAL(req->in.vwv, VWV(2));
io->read.in.remaining = SVAL(req->in.vwv, VWV(4));
-
+
/* setup the reply packet assuming the maximum possible read */
smbsrv_setup_reply(req, 5, 3 + io->read.in.count);
/* tell the backend where to put the data */
io->read.out.data = req->out.data + 3;
+ SMBSRV_CHECK_FILE_HANDLE(io->read.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
}
@@ -812,7 +820,7 @@ void smbsrv_reply_read_and_X(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_read_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
io->readx.level = RAW_READ_READX;
- io->readx.in.file.fnum = req_fnum(req, req->in.vwv, VWV(2));
+ io->readx.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
io->readx.in.offset = IVAL(req->in.vwv, VWV(3));
io->readx.in.maxcnt = SVAL(req->in.vwv, VWV(5));
io->readx.in.mincnt = SVAL(req->in.vwv, VWV(6));
@@ -847,6 +855,7 @@ void smbsrv_reply_read_and_X(struct smbsrv_request *req)
io->readx.out.data = req->out.data;
}
+ SMBSRV_CHECK_FILE_HANDLE(io->readx.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
}
@@ -890,7 +899,7 @@ void smbsrv_reply_writeunlock(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_writeunlock_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
io->writeunlock.level = RAW_WRITE_WRITEUNLOCK;
- io->writeunlock.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ io->writeunlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
io->writeunlock.in.count = SVAL(req->in.vwv, VWV(1));
io->writeunlock.in.offset = IVAL(req->in.vwv, VWV(2));
io->writeunlock.in.remaining = SVAL(req->in.vwv, VWV(4));
@@ -908,6 +917,7 @@ void smbsrv_reply_writeunlock(struct smbsrv_request *req)
return;
}
+ SMBSRV_CHECK_FILE_HANDLE(io->writeunlock.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
}
@@ -943,7 +953,7 @@ void smbsrv_reply_write(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_write_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
io->write.level = RAW_WRITE_WRITE;
- io->write.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ io->write.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
io->write.in.count = SVAL(req->in.vwv, VWV(1));
io->write.in.offset = IVAL(req->in.vwv, VWV(2));
io->write.in.remaining = SVAL(req->in.vwv, VWV(4));
@@ -961,6 +971,7 @@ void smbsrv_reply_write(struct smbsrv_request *req)
return;
}
+ SMBSRV_CHECK_FILE_HANDLE(io->write.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
}
@@ -1003,7 +1014,7 @@ void smbsrv_reply_write_and_X(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_write_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
io->writex.level = RAW_WRITE_WRITEX;
- io->writex.in.file.fnum = req_fnum(req, req->in.vwv, VWV(2));
+ io->writex.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
io->writex.in.offset = IVAL(req->in.vwv, VWV(3));
io->writex.in.wmode = SVAL(req->in.vwv, VWV(7));
io->writex.in.remaining = SVAL(req->in.vwv, VWV(8));
@@ -1021,8 +1032,9 @@ void smbsrv_reply_write_and_X(struct smbsrv_request *req)
if (req_data_oob(req, io->writex.in.data, io->writex.in.count)) {
smbsrv_send_error(req, NT_STATUS_FOOBAR);
return;
- }
+ }
+ SMBSRV_CHECK_FILE_HANDLE(io->writex.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
}
@@ -1056,10 +1068,11 @@ void smbsrv_reply_lseek(struct smbsrv_request *req)
SMBSRV_TALLOC_IO_PTR(io, union smb_seek);
SMBSRV_SETUP_NTVFS_REQUEST(reply_lseek_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
- io->lseek.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ io->lseek.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
io->lseek.in.mode = SVAL(req->in.vwv, VWV(1));
io->lseek.in.offset = IVALS(req->in.vwv, VWV(2));
+ SMBSRV_CHECK_FILE_HANDLE(io->lseek.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_seek(req->ntvfs, io));
}
@@ -1076,46 +1089,18 @@ void smbsrv_reply_flush(struct smbsrv_request *req)
SMBSRV_TALLOC_IO_PTR(io, union smb_flush);
SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
- fnum = req_fnum(req, req->in.vwv, VWV(0));
-
+ fnum = SVAL(req->in.vwv, VWV(0));
if (fnum == 0xFFFF) {
io->flush_all.level = RAW_FLUSH_ALL;
} else {
io->flush.level = RAW_FLUSH_FLUSH;
- io->flush.in.file.fnum = fnum;
+ io->flush.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
+ SMBSRV_CHECK_FILE_HANDLE(io->flush.in.file.ntvfs);
}
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_flush(req->ntvfs, io));
}
-
-/****************************************************************************
- Reply to a exit. This closes all files open by a smbpid
-****************************************************************************/
-void smbsrv_reply_exit(struct smbsrv_request *req)
-{
- NTSTATUS status;
- struct smbsrv_tcon *tcon;
- SMBSRV_CHECK_WCT(req, 0);
-
- for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
- req->tcon = tcon;
- SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
- status = ntvfs_exit(req->ntvfs);
- talloc_free(req->ntvfs);
- req->ntvfs = NULL;
- req->tcon = NULL;
- if (!NT_STATUS_IS_OK(status)) {
- smbsrv_send_error(req, status);
- return;
- }
- }
-
- smbsrv_setup_reply(req, 0, 0);
- smbsrv_send_reply(req);
-}
-
-
/****************************************************************************
Reply to a close
@@ -1131,9 +1116,10 @@ void smbsrv_reply_close(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
io->close.level = RAW_CLOSE_CLOSE;
- io->close.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ io->close.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
io->close.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
+ SMBSRV_CHECK_FILE_HANDLE(io->close.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
}
@@ -1171,12 +1157,12 @@ void smbsrv_reply_writeclose(struct smbsrv_request *req)
SMBSRV_TALLOC_IO_PTR(io, union smb_write);
SMBSRV_SETUP_NTVFS_REQUEST(reply_writeclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
- io->writeclose.level = RAW_WRITE_WRITECLOSE;
- io->writeclose.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
- io->writeclose.in.count = SVAL(req->in.vwv, VWV(1));
- io->writeclose.in.offset = IVAL(req->in.vwv, VWV(2));
- io->writeclose.in.mtime = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(4));
- io->writeclose.in.data = req->in.data + 1;
+ io->writeclose.level = RAW_WRITE_WRITECLOSE;
+ io->writeclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
+ io->writeclose.in.count = SVAL(req->in.vwv, VWV(1));
+ io->writeclose.in.offset = IVAL(req->in.vwv, VWV(2));
+ io->writeclose.in.mtime = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(4));
+ io->writeclose.in.data = req->in.data + 1;
/* make sure they gave us the data they promised */
if (req_data_oob(req, io->writeclose.in.data, io->writeclose.in.count)) {
@@ -1184,6 +1170,7 @@ void smbsrv_reply_writeclose(struct smbsrv_request *req)
return;
}
+ SMBSRV_CHECK_FILE_HANDLE(io->writeclose.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
}
@@ -1200,10 +1187,11 @@ void smbsrv_reply_lock(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
lck->lock.level = RAW_LOCK_LOCK;
- lck->lock.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ lck->lock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
lck->lock.in.count = IVAL(req->in.vwv, VWV(1));
lck->lock.in.offset = IVAL(req->in.vwv, VWV(3));
+ SMBSRV_CHECK_FILE_HANDLE(lck->lock.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
}
@@ -1221,10 +1209,11 @@ void smbsrv_reply_unlock(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
lck->unlock.level = RAW_LOCK_UNLOCK;
- lck->unlock.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ lck->unlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
lck->unlock.in.count = IVAL(req->in.vwv, VWV(1));
lck->unlock.in.offset = IVAL(req->in.vwv, VWV(3));
+ SMBSRV_CHECK_FILE_HANDLE(lck->unlock.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
}
@@ -1234,14 +1223,27 @@ void smbsrv_reply_unlock(struct smbsrv_request *req)
****************************************************************************/
void smbsrv_reply_tdis(struct smbsrv_request *req)
{
+ struct smbsrv_handle *h, *nh;
+
SMBSRV_CHECK_WCT(req, 0);
+ /*
+ * TODO: cancel all pending requests on this tcon
+ */
+
+ /*
+ * close all handles on this tcon
+ */
+ for (h=req->tcon->handles.list; h; h=nh) {
+ nh = h->next;
+ talloc_free(h);
+ }
+
+ /* finaly destroy the tcon */
talloc_free(req->tcon);
req->tcon = NULL;
- /* construct reply */
smbsrv_setup_reply(req, 0, 0);
-
smbsrv_send_reply(req);
}
@@ -1292,7 +1294,7 @@ static void reply_printopen_send(struct ntvfs_request *ntvfs)
/* construct reply */
smbsrv_setup_reply(req, 1, 0);
- SSVAL(req->out.vwv, VWV(0), oi->openold.out.file.fnum);
+ smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
smbsrv_send_reply(req);
}
@@ -1330,9 +1332,10 @@ void smbsrv_reply_printclose(struct smbsrv_request *req)
SMBSRV_TALLOC_IO_PTR(io, union smb_close);
SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
- io->splclose.level = RAW_CLOSE_SPLCLOSE;
- io->splclose.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ io->splclose.level = RAW_CLOSE_SPLCLOSE;
+ io->splclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
+ SMBSRV_CHECK_FILE_HANDLE(io->splclose.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
}
@@ -1414,16 +1417,15 @@ void smbsrv_reply_printwrite(struct smbsrv_request *req)
SMBSRV_TALLOC_IO_PTR(io, union smb_write);
SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
- io->splwrite.level = RAW_WRITE_SPLWRITE;
-
if (req->in.data_size < 3) {
smbsrv_send_error(req, NT_STATUS_FOOBAR);
return;
}
- io->splwrite.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
- io->splwrite.in.count = SVAL(req->in.data, 1);
- io->splwrite.in.data = req->in.data + 3;
+ io->splwrite.level = RAW_WRITE_SPLWRITE;
+ io->splwrite.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
+ io->splwrite.in.count = SVAL(req->in.data, 1);
+ io->splwrite.in.data = req->in.data + 3;
/* make sure they gave us the data they promised */
if (req_data_oob(req, io->splwrite.in.data, io->splwrite.in.count)) {
@@ -1431,6 +1433,7 @@ void smbsrv_reply_printwrite(struct smbsrv_request *req)
return;
}
+ SMBSRV_CHECK_FILE_HANDLE(io->splwrite.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
}
@@ -1621,7 +1624,7 @@ void smbsrv_reply_lockingX(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_lockingX_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
lck->lockx.level = RAW_LOCK_LOCKX;
- lck->lockx.in.file.fnum = req_fnum(req, req->in.vwv, VWV(2));
+ lck->lockx.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
lck->lockx.in.mode = SVAL(req->in.vwv, VWV(3));
lck->lockx.in.timeout = IVAL(req->in.vwv, VWV(4));
lck->lockx.in.ulock_cnt = SVAL(req->in.vwv, VWV(6));
@@ -1676,6 +1679,7 @@ void smbsrv_reply_lockingX(struct smbsrv_request *req)
p += lck_size;
}
+ SMBSRV_CHECK_FILE_HANDLE(lck->lockx.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
}
@@ -1702,11 +1706,12 @@ void smbsrv_reply_setattrE(struct smbsrv_request *req)
SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
info->setattre.level = RAW_SFILEINFO_SETATTRE;
- info->setattre.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ info->setattre.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
info->setattre.in.create_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(1));
info->setattre.in.access_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(3));
info->setattre.in.write_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(5));
+ SMBSRV_CHECK_FILE_HANDLE(info->setattre.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setfileinfo(req->ntvfs, info));
}
@@ -1765,9 +1770,10 @@ void smbsrv_reply_getattrE(struct smbsrv_request *req)
SMBSRV_TALLOC_IO_PTR(info, union smb_fileinfo);
SMBSRV_SETUP_NTVFS_REQUEST(reply_getattrE_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
- info->getattr.level = RAW_FILEINFO_GETATTRE;
- info->getattr.in.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ info->getattr.level = RAW_FILEINFO_GETATTRE;
+ info->getattr.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
+ SMBSRV_CHECK_FILE_HANDLE(info->getattr.in.file.ntvfs);
SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qfileinfo(req->ntvfs, info));
}
@@ -1988,26 +1994,81 @@ void smbsrv_reply_sesssetup(struct smbsrv_request *req)
}
/****************************************************************************
+ Reply to a exit. This closes all files open by a smbpid
+****************************************************************************/
+void smbsrv_reply_exit(struct smbsrv_request *req)
+{
+ struct smbsrv_handle_session_item *i, *ni;
+ struct smbsrv_handle *h;
+ struct smbsrv_tcon *tcon;
+ uint16_t smbpid;
+
+ SMBSRV_CHECK_WCT(req, 0);
+
+ smbpid = SVAL(req->in.hdr,HDR_PID);
+
+ /* first destroy all handles, which have the same PID as the request */
+ for (i=req->session->handles; i; i=ni) {
+ ni = i->next;
+ h = i->handle;
+ if (h->smbpid != smbpid) continue;
+
+ talloc_free(h);
+ }
+
+ /*
+ * then let the ntvfs backends proxy the call if they want to,
+ * but we didn't check the return value of the backends,
+ * as for the SMB client the call succeed
+ */
+ for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
+ req->tcon = tcon;
+ SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
+ ntvfs_exit(req->ntvfs);
+ talloc_free(req->ntvfs);
+ req->ntvfs = NULL;
+ req->tcon = NULL;
+ }
+
+ smbsrv_setup_reply(req, 0, 0);
+ smbsrv_send_reply(req);
+}
+
+/****************************************************************************
Reply to a SMBulogoffX.
****************************************************************************/
void smbsrv_reply_ulogoffX(struct smbsrv_request *req)
{
+ struct smbsrv_handle_session_item *i, *ni;
+ struct smbsrv_handle *h;
struct smbsrv_tcon *tcon;
- NTSTATUS status;
- /* in user level security we are supposed to close any files
- open by this user on all open tree connects */
+ SMBSRV_CHECK_WCT(req, 2);
+
+ /*
+ * TODO: cancel all pending requests
+ */
+
+
+ /* destroy all handles */
+ for (i=req->session->handles; i; i=ni) {
+ ni = i->next;
+ h = i->handle;
+ talloc_free(h);
+ }
+
+ /*
+ * then let the ntvfs backends proxy the call if they want to,
+ * but we didn't check the return value of the backends,
+ * as for the SMB client the call succeed
+ */
for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
req->tcon = tcon;
SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
- status = ntvfs_logoff(req->ntvfs);
+ ntvfs_logoff(req->ntvfs);
talloc_free(req->ntvfs);
req->ntvfs = NULL;
req->tcon = NULL;
- if (!NT_STATUS_IS_OK(status)) {
- smbsrv_send_error(req, status);
- return;
- }
}
talloc_free(req->session);
@@ -2018,7 +2079,7 @@ void smbsrv_reply_ulogoffX(struct smbsrv_request *req)
SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
SSVAL(req->out.vwv, VWV(1), 0);
-
+
smbsrv_chain_reply(req);
}
@@ -2067,7 +2128,7 @@ static void reply_ntcreate_and_X_send(struct ntvfs_request *ntvfs)
SCVAL(req->out.vwv, VWV(2), io->ntcreatex.out.oplock_level);
/* the rest of the parameters are not aligned! */
- SSVAL(req->out.vwv, 5, io->ntcreatex.out.file.fnum);
+ smbsrv_push_fnum(req->out.vwv, 5, io->ntcreatex.out.file.ntvfs);
SIVAL(req->out.vwv, 7, io->ntcreatex.out.create_action);
push_nttime(req->out.vwv, 11, io->ntcreatex.out.create_time);
push_nttime(req->out.vwv, 19, io->ntcreatex.out.access_time);
@@ -2080,7 +2141,7 @@ static void reply_ntcreate_and_X_send(struct ntvfs_request *ntvfs)
SSVAL(req->out.vwv, 65, io->ntcreatex.out.ipc_state);
SCVAL(req->out.vwv, 67, io->ntcreatex.out.is_directory);
- req->chained_fnum = io->ntcreatex.out.file.fnum;
+ req->chained_fnum = SVAL(req->out.vwv, 5);
smbsrv_chain_reply(req);
}
diff --git a/source4/smb_server/smb/request.c b/source4/smb_server/smb/request.c
index 21f89f40f9..2896a44d29 100644
--- a/source4/smb_server/smb/request.c
+++ b/source4/smb_server/smb/request.c
@@ -636,10 +636,100 @@ BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count
/*
pull an open file handle from a packet, taking account of the chained_fnum
*/
-uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
+static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
{
if (req->chained_fnum != -1) {
return req->chained_fnum;
}
return SVAL(base, offset);
}
+
+struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
+{
+ struct smbsrv_handle *handle;
+ uint16_t fnum = req_fnum(req, base, offset);
+
+ handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
+ if (!handle) {
+ return NULL;
+ }
+
+ return handle->ntvfs;
+}
+
+void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
+{
+ struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
+ struct smbsrv_handle);
+ SSVAL(base, offset, handle->hid);
+}
+
+NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
+{
+ struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
+ struct smbsrv_request);
+ struct smbsrv_handle *handle;
+ struct ntvfs_handle *h;
+
+ handle = smbsrv_handle_new(req);
+ if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
+
+ h = talloc_zero(handle, struct ntvfs_handle);
+ if (!h) goto nomem;
+
+ /*
+ * note: we don't set handle->ntvfs yet,
+ * this will be done by smbsrv_handle_make_valid()
+ * this makes sure the handle is invalid for clients
+ * until the ntvfs subsystem has made it valid
+ */
+ h->ctx = ntvfs->ctx;
+ h->session_info = ntvfs->session_info;
+ h->smbpid = ntvfs->smbpid;
+
+ h->frontend_data.private_data = handle;
+
+ *_h = h;
+ return NT_STATUS_OK;
+nomem:
+ talloc_free(handle);
+ return NT_STATUS_NO_MEMORY;
+}
+
+NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
+{
+ struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
+ struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
+ struct smbsrv_handle);
+ /* this tells the frontend that the handle is valid */
+ handle->ntvfs = h;
+ /* this moves the smbsrv_request to the smbsrv_tcon memory context */
+ talloc_steal(tcon, handle);
+ return NT_STATUS_OK;
+}
+
+void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
+{
+ struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
+ struct smbsrv_handle);
+ talloc_free(handle);
+}
+
+struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
+{
+ struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
+ struct smbsrv_request);
+
+ if (key->length != 2) return NULL;
+
+ return smbsrv_pull_fnum(req, key->data, 0);
+}
+
+DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
+{
+ uint8_t key[2];
+
+ smbsrv_push_fnum(key, 0, handle);
+
+ return data_blob_talloc(mem_ctx, key, sizeof(key));
+}
diff --git a/source4/smb_server/smb/service.c b/source4/smb_server/smb/service.c
index 13ef268a98..7c703c8920 100644
--- a/source4/smb_server/smb/service.c
+++ b/source4/smb_server/smb/service.c
@@ -110,7 +110,19 @@ static NTSTATUS make_connection_snum(struct smbsrv_request *req,
status = ntvfs_set_addr_callbacks(tcon->ntvfs, smbsrv_get_my_addr, smbsrv_get_peer_addr, req->smb_conn);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("make_connection: NTVFS failed to set the oplock handler!\n"));
+ DEBUG(0,("make_connection: NTVFS failed to set the addr callbacks!\n"));
+ goto failed;
+ }
+
+ status = ntvfs_set_handle_callbacks(tcon->ntvfs,
+ smbsrv_handle_create_new,
+ smbsrv_handle_make_valid,
+ smbsrv_handle_destroy,
+ smbsrv_handle_search_by_wire_key,
+ smbsrv_handle_get_wire_key,
+ tcon);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("make_connection: NTVFS failed to set the handle callbacks!\n"));
goto failed;
}
diff --git a/source4/smb_server/smb/trans2.c b/source4/smb_server/smb/trans2.c
index 1145a08426..69fa65010c 100644
--- a/source4/smb_server/smb/trans2.c
+++ b/source4/smb_server/smb/trans2.c
@@ -447,7 +447,7 @@ static NTSTATUS trans2_open_send(struct trans_op *op)
trans2_setup_reply(trans, 30, 0, 0);
- SSVAL(trans->out.params.data, VWV(0), io->t2open.out.file.fnum);
+ smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
srv_push_dos_date3(req->smb_conn, trans->out.params.data,
VWV(2), io->t2open.out.write_time);
@@ -847,7 +847,8 @@ static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op
struct smb_trans2 *trans = op->trans;
union smb_fileinfo *st;
NTSTATUS status;
- uint16_t level, fnum;
+ uint16_t level;
+ struct ntvfs_handle *h;
/* make sure we got enough parameters */
if (trans->in.params.length < 4) {
@@ -857,10 +858,10 @@ static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op
st = talloc(op, union smb_fileinfo);
NT_STATUS_HAVE_NO_MEMORY(st);
- fnum = SVAL(trans->in.params.data, 0);
+ h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
level = SVAL(trans->in.params.data, 2);
- st->generic.in.file.fnum = fnum;
+ st->generic.in.file.ntvfs = h;
/* work out the backend level - we make it 1-1 in the header */
st->generic.level = (enum smb_fileinfo_level)level;
if (st->generic.level >= RAW_FILEINFO_GENERIC) {
@@ -877,6 +878,7 @@ static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op
op->op_info = st;
op->send_fn = trans2_fileinfo_send;
+ SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
return ntvfs_qfileinfo(req->ntvfs, st);
}
@@ -985,7 +987,8 @@ static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *
struct smb_trans2 *trans = op->trans;
union smb_setfileinfo *st;
NTSTATUS status;
- uint16_t level, fnum;
+ uint16_t level;
+ struct ntvfs_handle *h;
/* make sure we got enough parameters */
if (trans->in.params.length < 4) {
@@ -995,10 +998,10 @@ static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *
st = talloc(op, union smb_setfileinfo);
NT_STATUS_HAVE_NO_MEMORY(st);
- fnum = SVAL(trans->in.params.data, 0);
+ h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
level = SVAL(trans->in.params.data, 2);
- st->generic.in.file.fnum = fnum;
+ st->generic.in.file.ntvfs = h;
/* work out the backend level - we make it 1-1 in the header */
st->generic.level = (enum smb_setfileinfo_level)level;
if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
@@ -1011,6 +1014,7 @@ static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *
op->op_info = st;
op->send_fn = trans2_simple_send;
+ SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
return ntvfs_setfileinfo(req->ntvfs, st);
}
diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h
index 12b12692f3..7c9ba6dc63 100644
--- a/source4/smb_server/smb_server.h
+++ b/source4/smb_server/smb_server.h
@@ -57,7 +57,19 @@ struct smbsrv_sessions_context {
/* also kept as a link list so it can be enumerated by
the management code */
struct smbsrv_session *list;
-} sessions;
+};
+
+struct smbsrv_handles_context {
+ /* an id tree used to allocate file handles */
+ struct idr_context *idtree_hid;
+
+ /* this is the limit of handle values for this context */
+ uint64_t idtree_limit;
+
+ /* also kept as a link list so it can be enumerated by
+ the management code */
+ struct smbsrv_handle *list;
+};
/* the current user context for a request */
struct smbsrv_session {
@@ -65,8 +77,18 @@ struct smbsrv_session {
struct smbsrv_connection *smb_conn;
+ /*
+ * in SMB2 tcons belong to just one session
+ * and not to the whole connection
+ */
struct smbsrv_tcons_context smb2_tcons;
+ /*
+ * the open file handles for this session,
+ * used for SMBexit, SMBulogoff and SMB2 SessionLogoff
+ */
+ struct smbsrv_handle_session_item *handles;
+
/*
* an index passed over the wire:
* - 16 bit for smb
@@ -78,7 +100,7 @@ struct smbsrv_session {
struct auth_session_info *session_info;
- /* some statictics for the management tools */
+ /* some statistics for the management tools */
struct {
/* the time when the session setup started */
struct timeval connect_time;
@@ -99,6 +121,9 @@ struct smbsrv_tcon {
/* the server context that this was created on */
struct smbsrv_connection *smb_conn;
+ /* the open file handles on this tcon */
+ struct smbsrv_handles_context handles;
+
/*
* an index passed over the wire:
* - 16 bit for smb
@@ -124,7 +149,7 @@ struct smbsrv_tcon {
struct smbsrv_session *session;
} smb2;
- /* some statictics for the management tools */
+ /* some statistics for the management tools */
struct {
/* the time when the tree connect started */
struct timeval connect_time;
@@ -133,6 +158,54 @@ struct smbsrv_tcon {
} statistics;
};
+struct smbsrv_handle {
+ struct smbsrv_handle *next, *prev;
+
+ /* the tcon the handle belongs to */
+ struct smbsrv_tcon *tcon;
+
+ /* the session the handle was opened on */
+ struct smbsrv_session *session;
+
+ /* the smbpid used on the open, used for SMBexit */
+ uint16_t smbpid;
+
+ /*
+ * this is for adding the handle into a linked list
+ * on the smbsrv_session, we can't use *next,*prev
+ * for this because they're used for the linked list on the
+ * smbsrv_tcon
+ */
+ struct smbsrv_handle_session_item {
+ struct smbsrv_handle_session_item *prev, *next;
+ struct smbsrv_handle *handle;
+ } session_item;
+
+ /*
+ * the value passed over the wire
+ * - 16 bit for smb
+ * - 64 bit for smb2
+ * Note: for SMB2 handles are 128 bit
+ * we'll fill the 2nd 64 bit with:
+ * - 32 bit TID
+ * - 32 bit 0xFFFFFFFF
+ */
+ uint64_t hid;
+
+ /*
+ * the ntvfs handle passed to the ntvfs backend
+ */
+ struct ntvfs_handle *ntvfs;
+
+ /* some statistics for the management tools */
+ struct {
+ /* the time when the tree connect started */
+ struct timeval open_time;
+ /* the time when the last request comes in */
+ struct timeval last_use_time;
+ } statistics;
+};
+
/* a set of flags to control handling of request structures */
#define SMBSRV_REQ_CONTROL_LARGE (1<<1) /* allow replies larger than max_xmit */
@@ -266,7 +339,7 @@ struct smbsrv_connection {
struct nbt_name *calling_name;
} negotiate;
- /* the context associated with open tree connects on a smb socket */
+ /* the context associated with open tree connects on a smb socket, not for SMB2 */
struct smbsrv_tcons_context smb_tcons;
/* context associated with currently valid session setups */
@@ -283,7 +356,7 @@ struct smbsrv_connection {
} *requests;
struct smb_signing_context signing;
-
+
struct stream_connection *connection;
/* this holds a partially received request */
@@ -350,6 +423,27 @@ struct smbsrv_connection {
smbsrv_send_error(req, NT_STATUS_NO_MEMORY); \
return; \
} \
+ req->ntvfs->frontend_data.private_data = req; \
+} while (0)
+
+#define SMBSRV_CHECK_FILE_HANDLE(handle) do { \
+ if (!handle) { \
+ smbsrv_send_error(req, NT_STATUS_INVALID_HANDLE); \
+ return; \
+ } \
+} while (0)
+
+#define SMBSRV_CHECK_FILE_HANDLE_ERROR(handle, _status) do { \
+ if (!handle) { \
+ smbsrv_send_error(req, _status); \
+ return; \
+ } \
+} while (0)
+
+#define SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(handle) do { \
+ if (!handle) { \
+ return NT_STATUS_INVALID_HANDLE; \
+ } \
} while (0)
/*
diff --git a/source4/smb_server/tcon.c b/source4/smb_server/tcon.c
index 8b100d11ce..dbd0677df1 100644
--- a/source4/smb_server/tcon.c
+++ b/source4/smb_server/tcon.c
@@ -3,6 +3,7 @@
Manage smbsrv_tcon structures
Copyright (C) Andrew Tridgell 1998
Copyright (C) Alexander Bokovoy 2002
+ Copyright (C) Stefan Metzmacher 2005-2006
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
@@ -109,6 +110,7 @@ static int smbsrv_tcon_destructor(void *ptr)
/* tell the ntvfs backend that we are disconnecting */
if (tcon->ntvfs) {
ntvfs_disconnect(tcon->ntvfs);
+ tcon->ntvfs = NULL;
}
if (tcon->smb2.session) {
@@ -132,6 +134,7 @@ static struct smbsrv_tcon *smbsrv_tcon_new(struct smbsrv_connection *smb_conn,
TALLOC_CTX *mem_ctx;
struct smbsrv_tcons_context *tcons_ctx;
struct smbsrv_tcon *tcon;
+ NTSTATUS status;
int i;
if (smb_sess) {
@@ -149,6 +152,16 @@ static struct smbsrv_tcon *smbsrv_tcon_new(struct smbsrv_connection *smb_conn,
tcon->share_name = talloc_strdup(tcon, share_name);
if (!tcon->share_name) goto failed;
+ /*
+ * the use -1 here, because we don't want to give away the wildcard
+ * fnum used in SMBflush
+ */
+ status = smbsrv_init_handles(tcon, UINT16_MAX - 1);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1,("ERROR! failed to init handles: %s\n", nt_errstr(status)));
+ goto failed;
+ }
+
i = idr_get_new_random(tcons_ctx->idtree_tid, tcon, tcons_ctx->idtree_limit);
if (i == -1) {
DEBUG(1,("ERROR! Out of connection structures\n"));