summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-05-16 00:07:38 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:22:08 -0500
commit32106b23951e01fb17f814584ebbcc8d7288cb75 (patch)
treee14389fd1be0e7dae592d74f8c8518dd9a1b60a0 /source3
parent074af4b39d12312fc376e8d2f7bf84f0fd830874 (diff)
downloadsamba-32106b23951e01fb17f814584ebbcc8d7288cb75.tar.gz
samba-32106b23951e01fb17f814584ebbcc8d7288cb75.tar.bz2
samba-32106b23951e01fb17f814584ebbcc8d7288cb75.zip
r22920: Add in the UNIX capability for 24-bit readX, as discussed
with the Apple guys and Linux kernel guys. Still looking at how to do writeX as there's no recvfile(). Jeremy. (This used to be commit a53268fb2082de586e2df250d8ddfcff53379102)
Diffstat (limited to 'source3')
-rw-r--r--source3/include/client.h2
-rw-r--r--source3/include/smb_macros.h4
-rw-r--r--source3/include/trans2.h6
-rw-r--r--source3/lib/util_sock.c18
-rw-r--r--source3/libsmb/clientgen.c127
-rw-r--r--source3/libsmb/clifsinfo.c2
-rw-r--r--source3/libsmb/clireadwrite.c50
-rw-r--r--source3/libsmb/smb_signing.c10
-rw-r--r--source3/smbd/reply.c169
-rw-r--r--source3/smbd/trans2.c5
10 files changed, 297 insertions, 96 deletions
diff --git a/source3/include/client.h b/source3/include/client.h
index 4df2459fb2..741ce6470d 100644
--- a/source3/include/client.h
+++ b/source3/include/client.h
@@ -29,6 +29,7 @@
#define CLI_BUFFER_SIZE (0xFFFF)
#define CLI_SAMBA_MAX_LARGE_READX_SIZE (127*1024) /* Works for Samba servers */
#define CLI_WINDOWS_MAX_LARGE_READX_SIZE ((64*1024)-2) /* Windows servers are broken.... */
+#define CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE (0xFFFF00) /* 24-bit len. */
/*
* These definitions depend on smb.h
@@ -152,6 +153,7 @@ struct cli_state {
int win95;
BOOL is_samba;
uint32 capabilities;
+ uint32 posix_capabilities;
BOOL dfsroot;
TALLOC_CTX *mem_ctx;
diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h
index bfed27c167..646c6bdce0 100644
--- a/source3/include/smb_macros.h
+++ b/source3/include/smb_macros.h
@@ -191,6 +191,10 @@
#define _smb_setlen(buf,len) do { buf[0] = 0; buf[1] = (len&0x10000)>>16; \
buf[2] = (len&0xFF00)>>8; buf[3] = len&0xFF; } while (0)
+#define smb_len_large(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
+#define _smb_setlen_large(buf,len) do { buf[0] = 0; buf[1] = (len&0xFF0000)>>16; \
+ buf[2] = (len&0xFF00)>>8; buf[3] = len&0xFF; } while (0)
+
/*******************************************************************
find the difference in milliseconds between two struct timeval
values
diff --git a/source3/include/trans2.h b/source3/include/trans2.h
index 5f7587d6ea..8b31b431c7 100644
--- a/source3/include/trans2.h
+++ b/source3/include/trans2.h
@@ -529,8 +529,10 @@ findfirst/findnext is SMB_FIND_FILE_UNIX_INFO2.
(chflags) and lsattr */
#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x10 /* Use POSIX pathnames on the wire. */
#define CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP 0x20 /* We can cope with POSIX open/mkdir/unlink etc. */
-#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x40 /* We can do SPNEGO negotiations for encryption. */
-#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x80 /* We *must* SPNEGO negotiations for encryption. */
+#define CIFS_UNIX_LARGE_READ_CAP 0x40 /* We can cope with 24 bit reads in readX. */
+#define CIFS_UNIX_LARGE_WRITE_CAP 0x80 /* We can cope with 24 bit writes in writeX. */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x100 /* We can do SPNEGO negotiations for encryption. */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x200 /* We *must* SPNEGO negotiations for encryption. */
#define SMB_QUERY_POSIX_FS_INFO 0x201
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
index 46bb709521..8f32e47bb8 100644
--- a/source3/lib/util_sock.c
+++ b/source3/lib/util_sock.c
@@ -658,10 +658,12 @@ ssize_t read_smb_length(int fd, char *inbuf, unsigned int timeout)
BUFFER_SIZE+SAFETY_MARGIN.
The timeout is in milliseconds.
This function will return on receipt of a session keepalive packet.
+ maxlen is the max number of bytes to return, not including the 4 byte
+ length. If zero it means BUFFER_SIZE+SAFETY_MARGIN limit.
Doesn't check the MAC on signed packets.
****************************************************************************/
-BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
+ssize_t receive_smb_raw(int fd, char *buffer, unsigned int timeout, size_t maxlen)
{
ssize_t len,ret;
@@ -679,7 +681,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
if (smb_read_error == 0)
smb_read_error = READ_ERROR;
- return False;
+ return -1;
}
/*
@@ -699,11 +701,15 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
if (smb_read_error == 0)
smb_read_error = READ_ERROR;
- return False;
+ return -1;
}
}
if(len > 0) {
+ if (maxlen) {
+ len = MIN(len,maxlen);
+ }
+
if (timeout > 0) {
ret = read_socket_with_timeout(fd,buffer+4,len,len,timeout);
} else {
@@ -714,7 +720,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
if (smb_read_error == 0) {
smb_read_error = READ_ERROR;
}
- return False;
+ return -1;
}
/* not all of samba3 properly checks for packet-termination of strings. This
@@ -722,7 +728,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
SSVAL(buffer+4,len, 0);
}
- return True;
+ return len;
}
/****************************************************************************
@@ -732,7 +738,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
BOOL receive_smb(int fd, char *buffer, unsigned int timeout)
{
- if (!receive_smb_raw(fd, buffer, timeout)) {
+ if (!receive_smb_raw(fd, buffer, timeout, 0)) {
return False;
}
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index e1dacb3921..1a4b1f770f 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -2,6 +2,7 @@
Unix SMB/CIFS implementation.
SMB client generic functions
Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2007.
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
@@ -54,20 +55,20 @@ int cli_set_port(struct cli_state *cli, int port)
should never go into a blocking read.
****************************************************************************/
-static BOOL client_receive_smb(struct cli_state *cli, BOOL eat_keepalives)
+static ssize_t client_receive_smb(struct cli_state *cli, BOOL eat_keepalives, size_t maxlen)
{
- BOOL ret;
+ ssize_t len;
int fd = cli->fd;
char *buffer = cli->inbuf;
unsigned int timeout = cli->timeout;
for(;;) {
- ret = receive_smb_raw(fd, buffer, timeout);
+ len = receive_smb_raw(fd, buffer, timeout, maxlen);
- if (!ret) {
+ if (len < 0) {
DEBUG(10,("client_receive_smb failed\n"));
show_msg(buffer);
- return ret;
+ return len;
}
/* Ignore session keepalive packets. */
@@ -85,11 +86,11 @@ static BOOL client_receive_smb(struct cli_state *cli, BOOL eat_keepalives)
cli->smb_rw_error = READ_BAD_DECRYPT;
close(cli->fd);
cli->fd = -1;
- return False;
+ return -1;
}
}
show_msg(buffer);
- return ret;
+ return len;
}
/****************************************************************************
@@ -98,21 +99,21 @@ static BOOL client_receive_smb(struct cli_state *cli, BOOL eat_keepalives)
BOOL cli_receive_smb_internal(struct cli_state *cli, BOOL eat_keepalives)
{
- BOOL ret;
+ ssize_t len;
/* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
if (cli->fd == -1)
return False;
again:
- ret = client_receive_smb(cli, eat_keepalives);
+ len = client_receive_smb(cli, eat_keepalives, 0);
- if (ret && !eat_keepalives && (CVAL(cli->inbuf,0) == SMBkeepalive)) {
+ if (len >= 0 && !eat_keepalives && (CVAL(cli->inbuf,0) == SMBkeepalive)) {
/* Give back the keepalive. */
return True;
}
- if (ret) {
+ if (len > 0) {
/* it might be an oplock break request */
if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
CVAL(cli->inbuf,smb_com) == SMBlockingX &&
@@ -121,7 +122,9 @@ BOOL cli_receive_smb_internal(struct cli_state *cli, BOOL eat_keepalives)
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;
+ if (!cli->oplock_handler(cli, fnum, level)) {
+ return False;
+ }
}
/* try to prevent loops */
SCVAL(cli->inbuf,smb_com,0xFF);
@@ -130,12 +133,12 @@ BOOL cli_receive_smb_internal(struct cli_state *cli, BOOL eat_keepalives)
}
/* If the server is not responding, note that now */
- if (!ret) {
+ if (len <= 0) {
DEBUG(0, ("Receiving SMB: Server stopped responding\n"));
cli->smb_rw_error = smb_read_error;
close(cli->fd);
cli->fd = -1;
- return ret;
+ return False;
}
if (!cli_check_sign_mac(cli)) {
@@ -187,6 +190,102 @@ BOOL cli_receive_smb_return_keepalive(struct cli_state *cli)
return cli_receive_smb_internal(cli, False);
}
+/****************************************************************************
+ Read the data portion of a readX smb.
+ The timeout is in milliseconds
+****************************************************************************/
+
+ssize_t cli_receive_smb_data(struct cli_state *cli, char *buffer, size_t len)
+{
+ if (cli->timeout > 0) {
+ return read_socket_with_timeout(cli->fd, buffer, len, len, cli->timeout);
+ } else {
+ return read_data(cli->fd, buffer, len);
+ }
+}
+
+/****************************************************************************
+ Read a smb readX header.
+ We can only use this if encryption and signing are off.
+****************************************************************************/
+
+BOOL cli_receive_smb_readX_header(struct cli_state *cli)
+{
+ ssize_t len, offset;
+
+ if (cli->fd == -1)
+ return False;
+
+ again:
+
+ /* Read up to the size of a readX header reply. */
+ len = client_receive_smb(cli, True, (smb_size - 4) + 24);
+
+ if (len > 0) {
+ /* it might be an oplock break request */
+ if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
+ CVAL(cli->inbuf,smb_com) == SMBlockingX &&
+ SVAL(cli->inbuf,smb_vwv6) == 0 &&
+ SVAL(cli->inbuf,smb_vwv7) == 0) {
+ ssize_t total_len = smb_len(cli->inbuf);
+
+ if (total_len > CLI_SAMBA_MAX_LARGE_READX_SIZE+SAFETY_MARGIN) {
+ goto read_err;
+ }
+
+ /* Read the rest of the data. */
+ if (!cli_receive_smb_data(cli,cli->inbuf+len,total_len - len)) {
+ goto read_err;
+ }
+
+ 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 */
+ SCVAL(cli->inbuf,smb_com,0xFF);
+ goto again;
+ }
+ }
+
+ /* Check it's a non-chained readX reply. */
+ if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) ||
+ (CVAL(cli->inbuf,smb_vwv0) != 0xFF) ||
+ (CVAL(cli->inbuf,smb_com) != SMBreadX)) {
+ /*
+ * We're not coping here with asnyc replies to
+ * other calls. Punt here - we need async client
+ * libs for this.
+ */
+ goto read_err;
+ }
+
+ /*
+ * We know it's a readX reply - ensure we've read the
+ * padding bytes also.
+ */
+
+ offset = SVAL(cli->inbuf,smb_vwv6);
+ if (offset > len) {
+ ssize_t ret;
+ size_t padbytes = offset - len;
+ ret = cli_receive_smb_data(cli,smb_buf(cli->inbuf),padbytes);
+ if (ret != padbytes) {
+ goto read_err;
+ }
+ }
+
+ return True;
+
+ read_err:
+
+ cli->smb_rw_error = smb_read_error = READ_ERROR;
+ close(cli->fd);
+ cli->fd = -1;
+ return False;
+}
+
static ssize_t write_socket(int fd, const char *buf, size_t len)
{
ssize_t ret=0;
diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c
index d8ada1a896..28facb511d 100644
--- a/source3/libsmb/clifsinfo.c
+++ b/source3/libsmb/clifsinfo.c
@@ -66,7 +66,7 @@ BOOL cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, uint16 *
*pmajor = SVAL(rdata,0);
*pminor = SVAL(rdata,2);
- *pcaplow = IVAL(rdata,4);
+ cli->posix_capabilities = *pcaplow = IVAL(rdata,4);
*pcaphigh = IVAL(rdata,8);
/* todo: but not yet needed
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
index 1c72cb2942..35d2afe2e7 100644
--- a/source3/libsmb/clireadwrite.c
+++ b/source3/libsmb/clireadwrite.c
@@ -46,7 +46,7 @@ static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
SIVAL(cli->outbuf,smb_vwv3,offset);
SSVAL(cli->outbuf,smb_vwv5,size);
SSVAL(cli->outbuf,smb_vwv6,size);
- SSVAL(cli->outbuf,smb_vwv7,((size >> 16) & 1));
+ SSVAL(cli->outbuf,smb_vwv7,(size >> 16));
SSVAL(cli->outbuf,smb_mid,cli->mid + i);
if (bigoffset) {
@@ -63,9 +63,11 @@ static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
{
char *p;
- int size2;
- int readsize;
+ size_t size2;
+ size_t readsize;
ssize_t total = 0;
+ /* We can only do direct reads if not signing. */
+ BOOL direct_reads = !client_is_signing_on(cli);
if (size == 0)
return 0;
@@ -75,7 +77,11 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
* rounded down to a multiple of 1024.
*/
- if (cli->capabilities & CAP_LARGE_READX) {
+ if (client_is_signing_on(cli) == False &&
+ cli_encryption_on(cli) == False &&
+ (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) {
+ readsize = CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE;
+ } else if (cli->capabilities & CAP_LARGE_READX) {
if (cli->is_samba) {
readsize = CLI_SAMBA_MAX_LARGE_READX_SIZE;
} else {
@@ -93,8 +99,13 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
if (!cli_issue_read(cli, fnum, offset, readsize, 0))
return -1;
- if (!cli_receive_smb(cli))
- return -1;
+ if (direct_reads) {
+ if (!cli_receive_smb_readX_header(cli))
+ return -1;
+ } else {
+ if (!cli_receive_smb(cli))
+ return -1;
+ }
/* Check for error. Make sure to check for DOS and NT
errors. */
@@ -125,7 +136,7 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
}
size2 = SVAL(cli->inbuf, smb_vwv5);
- size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7) & 1)) << 16);
+ size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7))) << 16);
if (size2 > readsize) {
DEBUG(5,("server returned more than we wanted!\n"));
@@ -135,10 +146,29 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
return -1;
}
- /* Copy data into buffer */
+ if (!direct_reads) {
+ /* Copy data into buffer */
+ p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
+ memcpy(buf + total, p, size2);
+ } else {
+ /* Ensure the remaining data matches the return size. */
+ ssize_t toread = smb_len_large(cli->inbuf) - SVAL(cli->inbuf,smb_vwv6);
- p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
- memcpy(buf + total, p, size2);
+ /* Ensure the size is correct. */
+ if (toread != size2) {
+ DEBUG(5,("direct read logic fail toread (%d) != size2 (%u)\n",
+ (int)toread, (unsigned int)size2 ));
+ return -1;
+ }
+
+ /* Read data directly into buffer */
+ toread = cli_receive_smb_data(cli,buf+total,size2);
+ if (toread != size2) {
+ DEBUG(5,("direct read read failure toread (%d) != size2 (%u)\n",
+ (int)toread, (unsigned int)size2 ));
+ return -1;
+ }
+ }
total += size2;
offset += size2;
diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c
index d3384ce365..30f41476e3 100644
--- a/source3/libsmb/smb_signing.c
+++ b/source3/libsmb/smb_signing.c
@@ -658,6 +658,16 @@ BOOL client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid)
}
/***********************************************************
+ Is client signing on ?
+************************************************************/
+
+BOOL client_is_signing_on(struct cli_state *cli)
+{
+ struct smb_sign_info *si = &cli->sign_info;
+ return si->doing_signing;
+}
+
+/***********************************************************
SMB signing - Server implementation - send the MAC.
************************************************************/
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 5353e392b1..4285e0ea77 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -2149,39 +2149,42 @@ static void fail_readraw(void)
exit_server_cleanly(errstr);
}
-#if defined(WITH_SENDFILE)
/****************************************************************************
Fake (read/write) sendfile. Returns -1 on read or write fail.
****************************************************************************/
-static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, int bufsize)
+static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, size_t bufsize)
{
- ssize_t ret=0;
+ size_t tosend = nread;
- /* Paranioa check... */
- if (nread > bufsize) {
- fail_readraw();
- }
+ while (tosend > 0) {
+ ssize_t ret;
+ size_t cur_read;
- if (nread > 0) {
- ret = read_file(fsp,buf,startpos,nread);
+ if (tosend > bufsize) {
+ cur_read = bufsize;
+ } else {
+ cur_read = tosend;
+ }
+ ret = read_file(fsp,buf,startpos,cur_read);
if (ret == -1) {
return -1;
}
- }
- /* If we had a short read, fill with zeros. */
- if (ret < nread) {
- memset(buf, '\0', nread - ret);
- }
+ /* If we had a short read, fill with zeros. */
+ if (ret < cur_read) {
+ memset(buf, '\0', cur_read - ret);
+ }
- if (write_data(smbd_server_fd(),buf,nread) != nread) {
- return -1;
- }
+ if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
+ return -1;
+ }
+ tosend -= cur_read;
+ startpos += cur_read;
+ }
return (ssize_t)nread;
}
-#endif
/****************************************************************************
Use sendfile in readbraw.
@@ -2526,16 +2529,54 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
}
/****************************************************************************
+ Setup readX header.
+****************************************************************************/
+
+static int setup_readX_header(char *inbuf, char *outbuf, size_t smb_maxcnt)
+{
+ int outsize;
+ char *data = smb_buf(outbuf);
+
+ SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
+ SSVAL(outbuf,smb_vwv5,smb_maxcnt);
+ SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+ SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
+ SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
+ SCVAL(outbuf,smb_vwv0,0xFF);
+ outsize = set_message(inbuf, outbuf,12,smb_maxcnt,False);
+ /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
+ _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
+ return outsize;
+}
+
+/****************************************************************************
Reply to a read and X - possibly using sendfile.
****************************************************************************/
int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, int len_outbuf,
files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
{
+ SMB_STRUCT_STAT sbuf;
int outsize = 0;
ssize_t nread = -1;
char *data = smb_buf(outbuf);
+ if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1) {
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ if (startpos > sbuf.st_size) {
+ smb_maxcnt = 0;
+ }
+
+ if (smb_maxcnt > (sbuf.st_size - startpos)) {
+ smb_maxcnt = (sbuf.st_size - startpos);
+ }
+
+ if (smb_maxcnt == 0) {
+ goto normal_read;
+ }
+
#if defined(WITH_SENDFILE)
/*
* We can only use sendfile on a non-chained packet
@@ -2545,33 +2586,15 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
if ((chain_size == 0) && (CVAL(inbuf,smb_vwv0) == 0xFF) &&
lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
- SMB_STRUCT_STAT sbuf;
DATA_BLOB header;
- if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- if (startpos > sbuf.st_size)
- goto normal_read;
-
- if (smb_maxcnt > (sbuf.st_size - startpos))
- smb_maxcnt = (sbuf.st_size - startpos);
-
- if (smb_maxcnt == 0)
- goto normal_read;
-
/*
* Set up the packet header before send. We
* assume here the sendfile will work (get the
* correct amount of data).
*/
- SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
- SSVAL(outbuf,smb_vwv5,smb_maxcnt);
- SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
- SSVAL(outbuf,smb_vwv7,((smb_maxcnt >> 16) & 1));
- SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
- SCVAL(outbuf,smb_vwv0,0xFF);
+ setup_readX_header(inbuf,outbuf,smb_maxcnt);
set_message(inbuf,outbuf,12,smb_maxcnt,False);
header.data = (uint8 *)outbuf;
header.length = data - outbuf;
@@ -2621,24 +2644,41 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
#endif
- nread = read_file(fsp,data,startpos,smb_maxcnt);
-
- if (nread < 0) {
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
+ if ((smb_maxcnt && 0xFF0000) > 0x10000) {
+ int sendlen = setup_readX_header(inbuf,outbuf,smb_maxcnt) - smb_maxcnt;
+ /* Send out the header. */
+ if (write_data(smbd_server_fd(),outbuf,sendlen) != sendlen) {
+ DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server_cleanly("send_file_readX sendfile failed");
+ }
+ if ((nread = fake_sendfile(fsp, startpos, smb_maxcnt, data,
+ len_outbuf - (data-outbuf))) == -1) {
+ DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server_cleanly("send_file_readX: fake_sendfile failed");
+ }
+ return -1;
+ } else {
+ nread = read_file(fsp,data,startpos,smb_maxcnt);
- outsize = set_message(inbuf,outbuf,12,nread,False);
- SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
- SSVAL(outbuf,smb_vwv5,nread);
- SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
- SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
- SSVAL(smb_buf(outbuf),-2,nread);
-
- DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
- fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+ if (nread < 0) {
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- /* Returning the number of bytes we want to send back - including header. */
- return outsize;
+ outsize = set_message(inbuf, outbuf,12,nread,False);
+ SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
+ SSVAL(outbuf,smb_vwv5,nread);
+ SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+ SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
+ SSVAL(smb_buf(outbuf),-2,nread);
+
+ DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
+ fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+
+ /* Returning the number of bytes we want to send back - including header. */
+ return outsize;
+ }
}
/****************************************************************************
@@ -2651,6 +2691,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
ssize_t nread = -1;
size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
+ BOOL big_readX = False;
#if 0
size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
#endif
@@ -2671,14 +2712,18 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
set_message(inbuf,outbuf,12,0,True);
if (global_client_caps & CAP_LARGE_READX) {
- if (SVAL(inbuf,smb_vwv7) == 1) {
- smb_maxcnt |= (1<<16);
- }
- if (smb_maxcnt > BUFFER_SIZE) {
- DEBUG(0,("reply_read_and_X - read too large (%u) for reply buffer %u\n",
- (unsigned int)smb_maxcnt, (unsigned int)BUFFER_SIZE));
- END_PROFILE(SMBreadX);
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ size_t upper_size = SVAL(inbuf,smb_vwv7);
+ smb_maxcnt |= (upper_size<<16);
+ if (upper_size > 1) {
+ /* Can't do this on a chained packet. */
+ if ((CVAL(inbuf,smb_vwv0) != 0xFF)) {
+ return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ }
+ /* We currently don't do this on signed or sealed data. */
+ if (srv_is_signing_active() || srv_encryption_on()) {
+ return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ }
+ big_readX = True;
}
}
@@ -2711,7 +2756,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
return ERROR_DOS(ERRDOS,ERRlock);
}
- if (schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) {
+ if (!big_readX && schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) {
END_PROFILE(SMBreadX);
return -1;
}
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 1c55684330..0730041899 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -2556,7 +2556,10 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
CIFS_UNIX_POSIX_PATHNAMES_CAP|
CIFS_UNIX_FCNTL_LOCKS_CAP|
CIFS_UNIX_EXTATTR_CAP|
- CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)));
+ CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
+ /* Ensure we don't do this on signed or sealed data. */
+ (srv_is_signing_active() ? 0 : CIFS_UNIX_LARGE_READ_CAP)
+ )));
break;
case SMB_QUERY_POSIX_FS_INFO: