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
+ 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,
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.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
#include "includes.h"
#include "smb_server/smb_server.h"
-#include "smb_server/service_smb_proto.h"
#include "smbd/service_stream.h"
#include "lib/stream/packet.h"
#include "ntvfs/ntvfs.h"
/* we over allocate the data buffer to prevent too many realloc calls */
#define REQ_OVER_ALLOCATION 0
+/* setup the bufinfo used for strings and range checking */
+void smbsrv_setup_bufinfo(struct smbsrv_request *req)
+{
+ req->in.bufinfo.mem_ctx = req;
+ req->in.bufinfo.flags = 0;
+ if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
+ req->in.bufinfo.flags |= BUFINFO_FLAG_UNICODE;
+ }
+ req->in.bufinfo.align_base = req->in.buffer;
+ req->in.bufinfo.data = req->in.data;
+ req->in.bufinfo.data_size = req->in.data_size;
+}
+
+
+static int smbsrv_request_destructor(struct smbsrv_request *req)
+{
+ DLIST_REMOVE(req->smb_conn->requests, req);
+ return 0;
+}
+
/****************************************************************************
construct a basic request packet, mostly used to construct async packets
such as change notify and oplock break requests
/* setup the request context */
req->smb_conn = smb_conn;
+ talloc_set_destructor(req, smbsrv_request_destructor);
+
return req;
}
/*
setup a chained reply in req->out with the given word count and initial data buffer size.
*/
-static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
+static void req_setup_chain_reply(struct smbsrv_request *req, unsigned int wct, unsigned int buflen)
{
uint32_t chain_base_size = req->out.size;
the caller will then fill in the command words and data before calling req_send_reply() to
send the reply on its way
*/
-void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
+void smbsrv_setup_reply(struct smbsrv_request *req, unsigned int wct, size_t buflen)
{
uint16_t flags2;
flags2 = FLAGS2_LONG_PATH_COMPONENTS |
FLAGS2_EXTENDED_ATTRIBUTES |
FLAGS2_IS_LONG_NAME;
- flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
+#define _SMB_FLAGS2_ECHOED_FLAGS ( \
+ FLAGS2_UNICODE_STRINGS | \
+ FLAGS2_EXTENDED_SECURITY | \
+ FLAGS2_SMB_SECURITY_SIGNATURES \
+)
+ flags2 |= (req->flags2 & _SMB_FLAGS2_ECHOED_FLAGS);
if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
flags2 |= FLAGS2_32_BIT_ERROR_CODES;
}
To cope with this req->out.ptr is supplied. This will be updated to
point at the same offset into the packet as before this call
*/
-static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
+static void req_grow_allocation(struct smbsrv_request *req, unsigned int new_size)
{
int delta;
uint8_t *buf2;
if (req->smb_conn->connection->event.fde == NULL) {
/* we are in the process of shutting down this connection */
+ talloc_free(req);
return;
}
if (req->out.size > NBT_HDR_SIZE) {
- _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
+ _smb_setlen_nbt(req->out.buffer, req->out.size - NBT_HDR_SIZE);
}
blob = data_blob_const(req->out.buffer, req->out.size);
*/
void smbsrv_send_reply(struct smbsrv_request *req)
{
+ if (req->smb_conn->connection->event.fde == NULL) {
+ /* we are in the process of shutting down this connection */
+ talloc_free(req);
+ return;
+ }
smbsrv_sign_packet(req);
smbsrv_send_reply_nosign(req);
size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
{
size_t len;
- uint_t grow_size;
+ unsigned int grow_size;
uint8_t *buf0;
const int max_bytes_per_char = 3;
req_grow_data(req, byte_len + 3 + req->out.data_size);
return byte_len + 3;
}
-/*
+/**
pull a UCS2 string from a request packet, returning a talloced unix string
the string length is limited by the 3 things:
on failure zero is returned and *dest is set to NULL, otherwise the number
of bytes consumed in the packet is returned
*/
-static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
+static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
{
int src_len, src_len2, alignment=0;
- ssize_t ret;
+ bool ret;
char *dest2;
+ size_t converted_size = 0;
- if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
+ if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
src++;
alignment=1;
if (byte_len != -1) {
if (flags & STR_NO_RANGE_CHECK) {
src_len = byte_len;
} else {
- src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
+ src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
if (byte_len != -1 && src_len > byte_len) {
src_len = byte_len;
}
src_len2 = utf16_len_n(src, src_len);
if (src_len2 == 0) {
- *dest = talloc_strdup(req, "");
+ *dest = talloc_strdup(bufinfo->mem_ctx, "");
return src_len2 + alignment;
}
- ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
+ ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &converted_size);
- if (ret == -1) {
+ if (!ret) {
*dest = NULL;
return 0;
}
return src_len2 + alignment;
}
-/*
+/**
pull a ascii string from a request packet, returning a talloced string
the string length is limited by the 3 things:
on failure zero is returned and *dest is set to NULL, otherwise the number
of bytes consumed in the packet is returned
*/
-static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
+static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
{
int src_len, src_len2;
- ssize_t ret;
+ bool ret;
char *dest2;
+ size_t converted_size = 0;
if (flags & STR_NO_RANGE_CHECK) {
src_len = byte_len;
} else {
- src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
+ src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
if (src_len < 0) {
*dest = NULL;
return 0;
src_len2++;
}
- ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
+ ret = convert_string_talloc(bufinfo->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, &converted_size);
- if (ret == -1) {
+ if (!ret) {
*dest = NULL;
return 0;
}
return src_len2;
}
-/*
+/**
pull a string from a request packet, returning a talloced string
the string length is limited by the 3 things:
on failure zero is returned and *dest is set to NULL, otherwise the number
of bytes consumed in the packet is returned
*/
-size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
+size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
{
if (!(flags & STR_ASCII) &&
- (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
- return req_pull_ucs2(req, dest, src, byte_len, flags);
+ (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
+ return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
}
- return req_pull_ascii(req, dest, src, byte_len, flags);
+ return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
}
-/*
+/**
pull a ASCII4 string buffer from a request packet, returning a talloced string
an ASCII4 buffer is a null terminated string that has a prefix
on failure *dest is set to the zero length string. This seems to
match win2000 behaviour
*/
-size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
+size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, unsigned int flags)
{
ssize_t ret;
- if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
+ if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
/* win2000 treats this as the empty string! */
- (*dest) = talloc_strdup(req, "");
+ (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
return 0;
}
behaviour */
src++;
- ret = req_pull_string(req, dest, src, -1, flags);
+ ret = req_pull_string(bufinfo, dest, src, -1, flags);
if (ret == -1) {
- (*dest) = talloc_strdup(req, "");
+ (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
return 1;
}
return ret + 1;
}
-/*
+/**
pull a DATA_BLOB from a request packet, returning a talloced blob
- return False if any part is outside the data portion of the packet
+ return false if any part is outside the data portion of the packet
*/
-BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
+bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
{
- if (len != 0 && req_data_oob(req, src, len)) {
- return False;
+ if (len != 0 && req_data_oob(bufinfo, src, len)) {
+ return false;
}
- (*blob) = data_blob_talloc(req, src, len);
+ (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
- return True;
+ return true;
}
/* check that a lump of data in a request is within the bounds of the data section of
the packet */
-BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
+bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
{
if (count == 0) {
- return False;
+ return false;
}
/* be careful with wraparound! */
- if (ptr < req->in.data ||
- ptr >= req->in.data + req->in.data_size ||
- count > req->in.data_size ||
- ptr + count > req->in.data + req->in.data_size) {
- return True;
+ if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
+ (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
+ count > bufinfo->data_size ||
+ (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
+ return true;
}
- return False;
+ return false;
}
/*
pull an open file handle from a packet, taking account of the chained_fnum
*/
-static 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, unsigned int 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 ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, unsigned int offset)
{
struct smbsrv_handle *handle;
uint16_t fnum = req_fnum(req, base, offset);
return NULL;
}
+ /*
+ * For SMB tcons and sessions can be mixed!
+ * But we need to make sure that file handles
+ * are only accessed by the opening session!
+ *
+ * So check if the handle is valid for the given session!
+ */
+ if (handle->session != req->session) {
+ return NULL;
+ }
+
return handle->ntvfs;
}
-void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
+void smbsrv_push_fnum(uint8_t *base, unsigned int offset, struct ntvfs_handle *ntvfs)
{
struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
struct smbsrv_handle);
struct smbsrv_handle *handle;
struct ntvfs_handle *h;
- handle = smbsrv_handle_new(req);
+ handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
h = talloc_zero(handle, struct ntvfs_handle);