summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2006-04-10 15:33:04 +0000
committerJeremy Allison <jra@samba.org>2006-04-10 15:33:04 +0000
commit57789e13784c7d509b9c7aad0db8489d68a3ff68 (patch)
tree60410c97498d60564ab49427fdbacd09e47acd01
parent3209ce21237073ba2f69c5ab3a6b6a790572789d (diff)
downloadsamba-57789e13784c7d509b9c7aad0db8489d68a3ff68.tar.gz
samba-57789e13784c7d509b9c7aad0db8489d68a3ff68.tar.xz
samba-57789e13784c7d509b9c7aad0db8489d68a3ff68.zip
r15018: Merge Volker's ipc/trans2/nttrans changes over
into 3.0. Also merge the new POSIX lock code - this is not enabled unless -DDEVELOPER is defined. This doesn't yet map onto underlying system POSIX locks. Updates vfs to allow lock queries. Jeremy.
-rw-r--r--examples/VFS/Makefile.in2
-rw-r--r--examples/VFS/skel_opaque.c6
-rw-r--r--examples/VFS/skel_transparent.c6
-rw-r--r--source/include/smb.h47
-rw-r--r--source/include/smbprofile.h2
-rw-r--r--source/include/trans2.h26
-rw-r--r--source/include/vfs.h10
-rw-r--r--source/include/vfs_macros.h3
-rw-r--r--source/lib/util.c61
-rw-r--r--source/libsmb/clifile.c105
-rw-r--r--source/libsmb/clitrans.c38
-rw-r--r--source/libsmb/errormap.c4
-rw-r--r--source/libsmb/smb_signing.c234
-rw-r--r--source/locking/brlock.c1300
-rw-r--r--source/locking/locking.c305
-rw-r--r--source/locking/posix.c91
-rw-r--r--source/modules/vfs_full_audit.c17
-rw-r--r--source/param/loadparm.c19
-rw-r--r--source/smbd/blocking.c277
-rw-r--r--source/smbd/ipc.c452
-rw-r--r--source/smbd/nttrans.c604
-rw-r--r--source/smbd/process.c31
-rw-r--r--source/smbd/reply.c112
-rw-r--r--source/smbd/server.c3
-rw-r--r--source/smbd/trans2.c963
-rw-r--r--source/smbd/vfs-wrap.c12
-rw-r--r--source/smbd/vfs.c1
-rw-r--r--source/tests/os2_delete.c107
-rw-r--r--source/utils/net_sam.c1
-rw-r--r--source/utils/status.c10
30 files changed, 3220 insertions, 1629 deletions
diff --git a/examples/VFS/Makefile.in b/examples/VFS/Makefile.in
index 79873c38576..caf8f030aa4 100644
--- a/examples/VFS/Makefile.in
+++ b/examples/VFS/Makefile.in
@@ -7,7 +7,7 @@ INSTALLCMD = @INSTALL@
SAMBA_SOURCE = @SAMBA_SOURCE@
SHLIBEXT = @SHLIBEXT@
OBJEXT = @OBJEXT@
-FLAGS = $(CFLAGS) -Iinclude -I$(SAMBA_SOURCE)/include -I$(SAMBA_SOURCE)/popt -I$(SAMBA_SOURCE)/ubiqx -I$(SAMBA_SOURCE)/smbwrapper -I. $(CPPFLAGS) -I$(SAMBA_SOURCE) -fPIC
+FLAGS = $(CFLAGS) -Iinclude -I$(SAMBA_SOURCE)/include -I$(SAMBA_SOURCE)/popt -I$(SAMBA_SOURCE)/smbwrapper -I. $(CPPFLAGS) -I$(SAMBA_SOURCE) -fPIC
prefix = @prefix@
diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c
index e6af475da6e..a02bf3c146b 100644
--- a/examples/VFS/skel_opaque.c
+++ b/examples/VFS/skel_opaque.c
@@ -226,6 +226,11 @@ static BOOL skel_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, int
return vfswrap_lock(NULL, fsp, fd, op, offset, count, type);
}
+static BOOL skel_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+ return vfswrap_getlock(NULL, fsp, fd, poffset, pcount, ptype, ppid);
+}
+
static int skel_symlink(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath)
{
return vfswrap_symlink(NULL, conn, oldpath, newpath);
@@ -576,6 +581,7 @@ static vfs_op_tuple skel_op_tuples[] = {
{SMB_VFS_OP(skel_utime), SMB_VFS_OP_UTIME, SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(skel_ftruncate), SMB_VFS_OP_FTRUNCATE, SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(skel_lock), SMB_VFS_OP_LOCK, SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(skel_getlock), SMB_VFS_OP_GETLOCK, SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(skel_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(skel_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(skel_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_OPAQUE},
diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c
index 14fa2276e1f..5996b298060 100644
--- a/examples/VFS/skel_transparent.c
+++ b/examples/VFS/skel_transparent.c
@@ -225,6 +225,11 @@ static BOOL skel_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, int
return SMB_VFS_NEXT_LOCK(handle, fsp, fd, op, offset, count, type);
}
+static BOOL skel_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+ return SMB_VFS_NEXT_GETLOCK(handle, fsp, fd, poffset, pcount, ptype, ppid);
+}
+
static int skel_symlink(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath)
{
return SMB_VFS_NEXT_SYMLINK(handle, conn, oldpath, newpath);
@@ -543,6 +548,7 @@ static vfs_op_tuple skel_op_tuples[] = {
{SMB_VFS_OP(skel_utime), SMB_VFS_OP_UTIME, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(skel_ftruncate), SMB_VFS_OP_FTRUNCATE, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(skel_lock), SMB_VFS_OP_LOCK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(skel_getlock), SMB_VFS_OP_GETLOCK, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(skel_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(skel_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(skel_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT},
diff --git a/source/include/smb.h b/source/include/smb.h
index 8faf3877ce9..9531ae2903c 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -486,6 +486,36 @@ typedef struct {
BOOL is_wild;
} name_compare_entry;
+struct trans_state {
+ struct trans_state *next, *prev;
+ uint16 vuid;
+ uint16 mid;
+
+ uint32 max_param_return;
+ uint32 max_data_return;
+ uint32 max_setup_return;
+
+ uint8 cmd; /* SMBtrans or SMBtrans2 */
+
+ fstring name; /* for trans requests */
+ uint16 call; /* for trans2 and nttrans requests */
+
+ BOOL close_on_completion;
+ BOOL one_way;
+
+ unsigned int setup_count;
+ uint16 *setup;
+
+ size_t received_data;
+ size_t received_param;
+
+ size_t total_param;
+ char *param;
+
+ size_t total_data;
+ char *data;
+};
+
/* Include VFS stuff */
#include "smb_acls.h"
@@ -550,6 +580,7 @@ typedef struct connection_struct {
name_compare_entry *veto_oplock_list; /* Per-share list of files to refuse oplocks on. */
name_compare_entry *aio_write_behind_list; /* Per-share list of files to use aio write behind on. */
struct dfree_cached_info *dfree_info;
+ struct trans_state *pending_trans;
} connection_struct;
struct current_user {
@@ -799,17 +830,29 @@ struct parm_struct {
#define FLAG_HIDE 0x2000 /* options that should be hidden in SWAT */
#define FLAG_DOS_STRING 0x4000 /* convert from UNIX to DOS codepage when reading this string. */
-/* passed to br lock code */
-enum brl_type {READ_LOCK, WRITE_LOCK, PENDING_LOCK};
+/* passed to br lock code - the UNLOCK_LOCK should never be stored into the tdb
+ and is used in calculating POSIX unlock ranges only. */
+
+enum brl_type {READ_LOCK, WRITE_LOCK, PENDING_LOCK, UNLOCK_LOCK};
+enum brl_flavour {WINDOWS_LOCK = 0, POSIX_LOCK = 1};
+
+struct byte_range_lock {
+ files_struct *fsp;
+ unsigned int num_locks;
+ BOOL modified;
+ void *lock_data;
+};
#define BRLOCK_FN_CAST() \
void (*)(SMB_DEV_T dev, SMB_INO_T ino, struct process_id pid, \
enum brl_type lock_type, \
+ enum brl_flavour lock_flav, \
br_off start, br_off size)
#define BRLOCK_FN(fn) \
void (*fn)(SMB_DEV_T dev, SMB_INO_T ino, struct process_id pid, \
enum brl_type lock_type, \
+ enum brl_flavour lock_flav, \
br_off start, br_off size)
struct bitmap {
diff --git a/source/include/smbprofile.h b/source/include/smbprofile.h
index ed6fce9a6d6..f68a1e240f2 100644
--- a/source/include/smbprofile.h
+++ b/source/include/smbprofile.h
@@ -110,6 +110,8 @@ struct profile_stats {
unsigned syscall_ftruncate_time;
unsigned syscall_fcntl_lock_count;
unsigned syscall_fcntl_lock_time;
+ unsigned syscall_fcntl_getlock_count;
+ unsigned syscall_fcntl_getlock_time;
unsigned syscall_readlink_count;
unsigned syscall_readlink_time;
unsigned syscall_symlink_count;
diff --git a/source/include/trans2.h b/source/include/trans2.h
index 1d5dfe3678e..92c5a2e963f 100644
--- a/source/include/trans2.h
+++ b/source/include/trans2.h
@@ -441,7 +441,9 @@ Offset Size Name
#define SMB_QUERY_ATTR_FLAGS 0x206 /* chflags, chattr */
#define SMB_SET_ATTR_FLAGS 0x206
#define SMB_QUERY_POSIX_PERMISSION 0x207
+/* Only valid for qfileinfo */
#define SMB_QUERY_POSIX_LOCK 0x208
+/* Only valid for setfileinfo */
#define SMB_SET_POSIX_LOCK 0x208
/* Transact 2 Find First levels */
@@ -576,4 +578,28 @@ number of entries sent will be zero.
#define SMB_POSIX_ACL_ENTRY_SIZE 10
#define SMB_POSIX_IGNORE_ACE_ENTRIES 0xFFFF
+
+/* Definition of SMB_SET_POSIX_LOCK */
+/*
+ [2 bytes] lock_type - 0 = Read, 1 = Write, 2 = Unlock
+ [2 bytes] lock_flags - 1 = Wait (only valid for setlock)
+ [4 bytes] pid = locking context.
+ [8 bytes] start = unsigned 64 bits.
+ [8 bytes] length = unsigned 64 bits.
+*/
+
+#define POSIX_LOCK_TYPE_OFFSET 0
+#define POSIX_LOCK_FLAGS_OFFSET 2
+#define POSIX_LOCK_PID_OFFSET 4
+#define POSIX_LOCK_START_OFFSET 8
+#define POSIX_LOCK_LEN_OFFSET 16
+#define POSIX_LOCK_DATA_SIZE 24
+
+#define POSIX_LOCK_FLAG_NOWAIT 0
+#define POSIX_LOCK_FLAG_WAIT 1
+
+#define POSIX_LOCK_TYPE_READ 0
+#define POSIX_LOCK_TYPE_WRITE 1
+#define POSIX_LOCK_TYPE_UNLOCK 2
+
#endif
diff --git a/source/include/vfs.h b/source/include/vfs.h
index cde2039d1a1..fb99d824125 100644
--- a/source/include/vfs.h
+++ b/source/include/vfs.h
@@ -59,9 +59,10 @@
/* Changed to version 12 to add mask and attributes to opendir(). JRA
Also include aio calls. JRA. */
/* Changed to version 13 as the internal structure of files_struct has changed. JRA */
-/* Changed to version 14 as the we had to change DIR to SMB_STRUCT_DIR. JRA */
-/* Changed to version 15 as the we added the statvfs call. JRA */
-#define SMB_VFS_INTERFACE_VERSION 15
+/* Changed to version 14 as we had to change DIR to SMB_STRUCT_DIR. JRA */
+/* Changed to version 15 as we added the statvfs call. JRA */
+/* Changed to version 16 as we added the getlock call. JRA */
+#define SMB_VFS_INTERFACE_VERSION 16
/* to bug old modules which are trying to compile with the old functions */
@@ -141,6 +142,7 @@ typedef enum _vfs_op_type {
SMB_VFS_OP_UTIME,
SMB_VFS_OP_FTRUNCATE,
SMB_VFS_OP_LOCK,
+ SMB_VFS_OP_GETLOCK,
SMB_VFS_OP_SYMLINK,
SMB_VFS_OP_READLINK,
SMB_VFS_OP_LINK,
@@ -262,6 +264,7 @@ struct vfs_ops {
int (*utime)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, struct utimbuf *times);
int (*ftruncate)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_OFF_T offset);
BOOL (*lock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+ BOOL (*getlock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid);
int (*symlink)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *oldpath, const char *newpath);
int (*readlink)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, char *buf, size_t bufsiz);
int (*link)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *oldpath, const char *newpath);
@@ -375,6 +378,7 @@ struct vfs_ops {
struct vfs_handle_struct *utime;
struct vfs_handle_struct *ftruncate;
struct vfs_handle_struct *lock;
+ struct vfs_handle_struct *getlock;
struct vfs_handle_struct *symlink;
struct vfs_handle_struct *readlink;
struct vfs_handle_struct *link;
diff --git a/source/include/vfs_macros.h b/source/include/vfs_macros.h
index 33810c301f9..e08b386a6ac 100644
--- a/source/include/vfs_macros.h
+++ b/source/include/vfs_macros.h
@@ -70,6 +70,7 @@
#define SMB_VFS_UTIME(conn, path, times) ((conn)->vfs.ops.utime((conn)->vfs.handles.utime, (conn), (path), (times)))
#define SMB_VFS_FTRUNCATE(fsp, fd, offset) ((fsp)->conn->vfs.ops.ftruncate((fsp)->conn->vfs.handles.ftruncate, (fsp), (fd), (offset)))
#define SMB_VFS_LOCK(fsp, fd, op, offset, count, type) ((fsp)->conn->vfs.ops.lock((fsp)->conn->vfs.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type)))
+#define SMB_VFS_GETLOCK(fsp, fd, poffset, pcount, ptype, ppid) ((fsp)->conn->vfs.ops.getlock((fsp)->conn->vfs.handles.getlock, (fsp), (fd) ,(poffset), (pcount), (ptype), (ppid)))
#define SMB_VFS_SYMLINK(conn, oldpath, newpath) ((conn)->vfs.ops.symlink((conn)->vfs.handles.symlink, (conn), (oldpath), (newpath)))
#define SMB_VFS_READLINK(conn, path, buf, bufsiz) ((conn)->vfs.ops.readlink((conn)->vfs.handles.readlink, (conn), (path), (buf), (bufsiz)))
#define SMB_VFS_LINK(conn, oldpath, newpath) ((conn)->vfs.ops.link((conn)->vfs.handles.link, (conn), (oldpath), (newpath)))
@@ -181,6 +182,7 @@
#define SMB_VFS_OPAQUE_UTIME(conn, path, times) ((conn)->vfs_opaque.ops.utime((conn)->vfs_opaque.handles.utime, (conn), (path), (times)))
#define SMB_VFS_OPAQUE_FTRUNCATE(fsp, fd, offset) ((fsp)->conn->vfs_opaque.ops.ftruncate((fsp)->conn->vfs_opaque.handles.ftruncate, (fsp), (fd), (offset)))
#define SMB_VFS_OPAQUE_LOCK(fsp, fd, op, offset, count, type) ((fsp)->conn->vfs_opaque.ops.lock((fsp)->conn->vfs_opaque.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type)))
+#define SMB_VFS_OPAQUE_GETLOCK(fsp, fd, poffset, pcount, ptype, ppid) ((fsp)->conn->vfs_opaque.ops.getlock((fsp)->conn->vfs_opaque.handles.getlock, (fsp), (fd), (poffset), (pcount), (ptype), (ppid)))
#define SMB_VFS_OPAQUE_SYMLINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.symlink((conn)->vfs_opaque.handles.symlink, (conn), (oldpath), (newpath)))
#define SMB_VFS_OPAQUE_READLINK(conn, path, buf, bufsiz) ((conn)->vfs_opaque.ops.readlink((conn)->vfs_opaque.handles.readlink, (conn), (path), (buf), (bufsiz)))
#define SMB_VFS_OPAQUE_LINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.link((conn)->vfs_opaque.handles.link, (conn), (oldpath), (newpath)))
@@ -293,6 +295,7 @@
#define SMB_VFS_NEXT_UTIME(handle, conn, path, times) ((handle)->vfs_next.ops.utime((handle)->vfs_next.handles.utime, (conn), (path), (times)))
#define SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, offset) ((handle)->vfs_next.ops.ftruncate((handle)->vfs_next.handles.ftruncate, (fsp), (fd), (offset)))
#define SMB_VFS_NEXT_LOCK(handle, fsp, fd, op, offset, count, type) ((handle)->vfs_next.ops.lock((handle)->vfs_next.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type)))
+#define SMB_VFS_NEXT_GETLOCK(handle, fsp, fd, poffset, pcount, ptype, ppid) ((handle)->vfs_next.ops.getlock((handle)->vfs_next.handles.getlock, (fsp), (fd), (poffset), (pcount), (ptype), (ppid)))
#define SMB_VFS_NEXT_SYMLINK(handle, conn, oldpath, newpath) ((handle)->vfs_next.ops.symlink((handle)->vfs_next.handles.symlink, (conn), (oldpath), (newpath)))
#define SMB_VFS_NEXT_READLINK(handle, conn, path, buf, bufsiz) ((handle)->vfs_next.ops.readlink((handle)->vfs_next.handles.readlink, (conn), (path), (buf), (bufsiz)))
#define SMB_VFS_NEXT_LINK(handle, conn, oldpath, newpath) ((handle)->vfs_next.ops.link((handle)->vfs_next.handles.link, (conn), (oldpath), (newpath)))
diff --git a/source/lib/util.c b/source/lib/util.c
index bfc5eb2a8da..87f15b8759d 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -1876,6 +1876,7 @@ void free_namearray(name_compare_entry *name_array)
/****************************************************************************
Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
is dealt with in posix.c
+ Returns True if the lock was granted, False otherwise.
****************************************************************************/
BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
@@ -1893,34 +1894,54 @@ BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
ret = sys_fcntl_ptr(fd,op,&lock);
- if (ret == -1 && errno != 0)
- DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
-
- /* a lock query - return True if this region is locked, False if not locked. */
- if (op == SMB_F_GETLK) {
- if ((ret != -1) &&
- (lock.l_type != F_UNLCK) &&
- (lock.l_pid != 0) &&
- (lock.l_pid != sys_getpid())) {
- DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
- return(True);
- }
-
- /* it must be not locked or locked by me */
- return(False);
- }
-
- /* a lock set or unset */
if (ret == -1) {
DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
(double)offset,(double)count,op,type,strerror(errno)));
- return(False);
+ return False;
}
/* everything went OK */
DEBUG(8,("fcntl_lock: Lock call successful\n"));
- return(True);
+ return True;
+}
+
+/****************************************************************************
+ Simple routine to query existing file locks. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
+ Returns True if we have information regarding this lock region (and returns
+ F_UNLCK in *ptype if the region is unlocked). False if the call failed.
+****************************************************************************/
+
+BOOL fcntl_getlock(int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+ SMB_STRUCT_FLOCK lock;
+ int ret;
+
+ DEBUG(8,("fcntl_getlock %d %.0f %.0f %d\n",fd,(double)*poffset,(double)*pcount,*ptype));
+
+ lock.l_type = *ptype;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = *poffset;
+ lock.l_len = *pcount;
+ lock.l_pid = 0;
+
+ ret = sys_fcntl_ptr(fd,SMB_F_GETLK,&lock);
+
+ if (ret == -1) {
+ DEBUG(3,("fcntl_getlock: lock request failed at offset %.0f count %.0f type %d (%s)\n",
+ (double)*poffset,(double)*pcount,*ptype,strerror(errno)));
+ return False;
+ }
+
+ *ptype = lock.l_type;
+ *poffset = lock.l_start;
+ *pcount = lock.l_len;
+ *ppid = lock.l_pid;
+
+ DEBUG(3,("fcntl_getlock: fd %d is returned info %d pid %u\n",
+ fd, (int)lock.l_type, (unsigned int)lock.l_pid));
+ return True;
}
#undef DBGC_CLASS
diff --git a/source/libsmb/clifile.c b/source/libsmb/clifile.c
index 443f5156653..80deb3a3320 100644
--- a/source/libsmb/clifile.c
+++ b/source/libsmb/clifile.c
@@ -816,6 +816,7 @@ BOOL cli_close(struct cli_state *cli, int fnum)
send a lock with a specified locktype
this is used for testing LOCKING_ANDX_CANCEL_LOCK
****************************************************************************/
+
NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
uint32 offset, uint32 len, int timeout, unsigned char locktype)
{
@@ -863,11 +864,11 @@ NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
return cli_nt_error(cli);
}
-
/****************************************************************************
Lock a file.
note that timeout is in units of 2 milliseconds
****************************************************************************/
+
BOOL cli_lock(struct cli_state *cli, int fnum,
uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
{
@@ -1068,6 +1069,108 @@ BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_
return True;
}
+/****************************************************************************
+ Get/unlock a POSIX lock on a file - internal function.
+****************************************************************************/
+
+static BOOL cli_posix_lock_internal(struct cli_state *cli, int fnum,
+ SMB_BIG_UINT offset, SMB_BIG_UINT len, BOOL wait_lock, enum brl_type lock_type)
+{
+ unsigned int param_len = 4;
+ unsigned int data_len = POSIX_LOCK_DATA_SIZE;
+ uint16 setup = TRANSACT2_SETFILEINFO;
+ char param[4];
+ unsigned char data[POSIX_LOCK_DATA_SIZE];
+ char *rparam=NULL, *rdata=NULL;
+ int saved_timeout = cli->timeout;
+
+ SSVAL(param,0,fnum);
+ SSVAL(param,2,SMB_SET_POSIX_LOCK);
+
+ switch (lock_type) {
+ case READ_LOCK:
+ SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_READ);
+ break;
+ case WRITE_LOCK:
+ SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_WRITE);
+ break;
+ case UNLOCK_LOCK:
+ SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
+ break;
+ default:
+ return False;
+ }
+
+ if (wait_lock) {
+ SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_WAIT);
+ cli->timeout = 0x7FFFFFFF;
+ } else {
+ SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_NOWAIT);
+ }
+
+ SIVAL(data, POSIX_LOCK_PID_OFFSET, cli->pid);
+ SOFF_T(data, POSIX_LOCK_START_OFFSET, offset);
+ SOFF_T(data, POSIX_LOCK_LEN_OFFSET, len);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ cli->timeout = saved_timeout;
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ cli->timeout = saved_timeout;
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return False;
+ }
+
+ cli->timeout = saved_timeout;
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/****************************************************************************
+ POSIX Lock a file.
+****************************************************************************/
+
+BOOL cli_posix_lock(struct cli_state *cli, int fnum,
+ SMB_BIG_UINT offset, SMB_BIG_UINT len,
+ BOOL wait_lock, enum brl_type lock_type)
+{
+ if (lock_type != READ_LOCK || lock_type != WRITE_LOCK) {
+ return False;
+ }
+ return cli_posix_lock_internal(cli, fnum, offset, len, wait_lock, lock_type);
+}
+
+/****************************************************************************
+ POSIX Unlock a file.
+****************************************************************************/
+
+BOOL cli_posix_unlock(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len)
+{
+ return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK);
+}
+
+/****************************************************************************
+ POSIX Get any lock covering a file.
+****************************************************************************/
+
+BOOL cli_posix_getlock(struct cli_state *cli, int fnum, SMB_BIG_UINT *poffset, SMB_BIG_UINT *plen)
+{
+ return True;
+}
/****************************************************************************
Do a SMBgetattrE call.
diff --git a/source/libsmb/clitrans.c b/source/libsmb/clitrans.c
index 8296f7e94c1..082da67bb8b 100644
--- a/source/libsmb/clitrans.c
+++ b/source/libsmb/clitrans.c
@@ -153,7 +153,6 @@ BOOL cli_send_trans(struct cli_state *cli, int trans,
/* Note we're in a trans state. Save the sequence
* numbers for replies. */
- cli_signing_trans_start(cli, mid);
return(True);
}
@@ -173,7 +172,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
*data_len = *param_len = 0;
if (!cli_receive_smb(cli)) {
- cli_signing_trans_stop(cli);
return False;
}
@@ -184,7 +182,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
DEBUG(0,("Expected %s response, got command 0x%02x\n",
trans==SMBtrans?"SMBtrans":"SMBtrans2",
CVAL(cli->inbuf,smb_com)));
- cli_signing_trans_stop(cli);
return(False);
}
@@ -197,7 +194,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
status = cli_nt_error(cli);
if (NT_STATUS_IS_ERR(status) || NT_STATUS_EQUAL(status,STATUS_NO_MORE_FILES)) {
- cli_signing_trans_stop(cli);
return False;
}
@@ -210,7 +206,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
*data = SMB_REALLOC(*data,total_data);
if (!(*data)) {
DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
- cli_signing_trans_stop(cli);
return False;
}
}
@@ -219,7 +214,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
*param = SMB_REALLOC(*param,total_param);
if (!(*param)) {
DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
- cli_signing_trans_stop(cli);
return False;
}
}
@@ -231,7 +225,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
if (this_data + *data_len > total_data ||
this_param + *param_len > total_param) {
DEBUG(1,("Data overflow in cli_receive_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
@@ -240,7 +233,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
this_param + *param_len < this_param ||
this_param + *param_len < *param_len) {
DEBUG(1,("Data overflow in cli_receive_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
@@ -253,7 +245,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
data_offset_out + this_data < data_offset_out ||
data_offset_out + this_data < this_data) {
DEBUG(1,("Data overflow in cli_receive_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
if (data_offset_in > cli->bufsize ||
@@ -261,7 +252,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
data_offset_in + this_data < data_offset_in ||
data_offset_in + this_data < this_data) {
DEBUG(1,("Data overflow in cli_receive_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
@@ -276,7 +266,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
param_offset_out + this_param < param_offset_out ||
param_offset_out + this_param < this_param) {
DEBUG(1,("Param overflow in cli_receive_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
if (param_offset_in > cli->bufsize ||
@@ -284,7 +273,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
param_offset_in + this_param < param_offset_in ||
param_offset_in + this_param < this_param) {
DEBUG(1,("Param overflow in cli_receive_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
@@ -297,7 +285,6 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
break;
if (!cli_receive_smb(cli)) {
- cli_signing_trans_stop(cli);
return False;
}
@@ -308,11 +295,9 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
DEBUG(0,("Expected %s response, got command 0x%02x\n",
trans==SMBtrans?"SMBtrans":"SMBtrans2",
CVAL(cli->inbuf,smb_com)));
- cli_signing_trans_stop(cli);
return(False);
}
if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
- cli_signing_trans_stop(cli);
return(False);
}
@@ -326,8 +311,7 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
break;
}
-
- cli_signing_trans_stop(cli);
+
return(True);
}
@@ -453,7 +437,6 @@ BOOL cli_send_nt_trans(struct cli_state *cli,
/* Note we're in a trans state. Save the sequence
* numbers for replies. */
- cli_signing_trans_start(cli, mid);
return(True);
}
@@ -474,7 +457,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
*data_len = *param_len = 0;
if (!cli_receive_smb(cli)) {
- cli_signing_trans_stop(cli);
return False;
}
@@ -484,7 +466,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
CVAL(cli->inbuf,smb_com)));
- cli_signing_trans_stop(cli);
return(False);
}
@@ -496,7 +477,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode);
if (!(eclass == ERRDOS && ecode == ERRmoredata)) {
- cli_signing_trans_stop(cli);
return(False);
}
}
@@ -507,7 +487,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
if (cli_is_nt_error(cli)) {
if (!NT_STATUS_EQUAL(cli_nt_error(cli),
NT_STATUS_BUFFER_TOO_SMALL)) {
- cli_signing_trans_stop(cli);
return(False);
}
}
@@ -521,7 +500,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
*data = SMB_REALLOC(*data,total_data);
if (!(*data)) {
DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
- cli_signing_trans_stop(cli);
return False;
}
}
@@ -530,7 +508,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
*param = SMB_REALLOC(*param,total_param);
if (!(*param)) {
DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
- cli_signing_trans_stop(cli);
return False;
}
}
@@ -542,7 +519,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
if (this_data + *data_len > total_data ||
this_param + *param_len > total_param) {
DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
@@ -551,7 +527,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
this_param + *param_len < this_param ||
this_param + *param_len < *param_len) {
DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
@@ -564,7 +539,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
data_offset_out + this_data < data_offset_out ||
data_offset_out + this_data < this_data) {
DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
if (data_offset_in > cli->bufsize ||
@@ -572,7 +546,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
data_offset_in + this_data < data_offset_in ||
data_offset_in + this_data < this_data) {
DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
@@ -588,7 +561,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
param_offset_out + this_param < param_offset_out ||
param_offset_out + this_param < this_param) {
DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
if (param_offset_in > cli->bufsize ||
@@ -596,7 +568,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
param_offset_in + this_param < param_offset_in ||
param_offset_in + this_param < this_param) {
DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
- cli_signing_trans_stop(cli);
return False;
}
@@ -610,7 +581,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
break;
if (!cli_receive_smb(cli)) {
- cli_signing_trans_stop(cli);
return False;
}
@@ -620,13 +590,11 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
CVAL(cli->inbuf,smb_com)));
- cli_signing_trans_stop(cli);
return(False);
}
if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode);
if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
- cli_signing_trans_stop(cli);
return(False);
}
}
@@ -636,7 +604,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
if (cli_is_nt_error(cli)) {
if (!NT_STATUS_EQUAL(cli_nt_error(cli),
NT_STATUS_BUFFER_TOO_SMALL)) {
- cli_signing_trans_stop(cli);
return(False);
}
}
@@ -650,7 +617,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
if (total_data <= *data_len && total_param <= *param_len)
break;
}
-
- cli_signing_trans_stop(cli);
+
return(True);
}
diff --git a/source/libsmb/errormap.c b/source/libsmb/errormap.c
index f6b5af068a5..b3caa0a80ce 100644
--- a/source/libsmb/errormap.c
+++ b/source/libsmb/errormap.c
@@ -407,7 +407,7 @@ static const struct {
{ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE},
{ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED},
{ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE},
- {ERRDOS, 124, NT_STATUS_INVALID_LEVEL},
+ {ERRDOS, ERRunknownlevel, NT_STATUS_INVALID_LEVEL},
{ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE},
{ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT},
{ERRDOS, 109, NT_STATUS_PIPE_BROKEN},
@@ -680,7 +680,7 @@ static const struct {
{ERRDOS, 121, NT_STATUS_IO_TIMEOUT},
{ERRDOS, 122, NT_STATUS_BUFFER_TOO_SMALL},
{ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID},
- {ERRDOS, 124, NT_STATUS_INVALID_LEVEL},
+ {ERRDOS, ERRunknownlevel, NT_STATUS_INVALID_LEVEL},
{ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND},
{ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
{ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
diff --git a/source/libsmb/smb_signing.c b/source/libsmb/smb_signing.c
index 52e4b1d04c5..4ff74ca464c 100644
--- a/source/libsmb/smb_signing.c
+++ b/source/libsmb/smb_signing.c
@@ -28,17 +28,9 @@ struct outstanding_packet_lookup {
struct outstanding_packet_lookup *prev, *next;
};
-/* Store the data for an ongoing trans/trans2/nttrans operation. */
-struct trans_info_context {
- uint16 mid;
- uint32 send_seq_num;
- uint32 reply_seq_num;
-};
-
struct smb_basic_signing_context {
DATA_BLOB mac_key;
uint32 send_seq_num;
- struct trans_info_context *trans_info;
struct outstanding_packet_lookup *outstanding_packet_list;
};
@@ -315,7 +307,6 @@ static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
{
unsigned char calc_md5_mac[16];
struct smb_basic_signing_context *data = si->signing_context;
- uint32 send_seq_num;
if (!si->doing_signing)
return;
@@ -330,12 +321,8 @@ static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
/* mark the packet as signed - BEFORE we sign it...*/
mark_packet_signed(outbuf);
- if (data->trans_info)
- send_seq_num = data->trans_info->send_seq_num;
- else
- send_seq_num = data->send_seq_num;
-
- simple_packet_signature(data, (const unsigned char *)outbuf, send_seq_num, calc_md5_mac);
+ simple_packet_signature(data, (const unsigned char *)outbuf,
+ data->send_seq_num, calc_md5_mac);
DEBUG(10, ("client_sign_outgoing_message: sent SMB signature of\n"));
dump_data(10, (const char *)calc_md5_mac, 8);
@@ -345,13 +332,7 @@ static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
/* cli->outbuf[smb_ss_field+2]=0;
Uncomment this to test if the remote server actually verifies signatures...*/
- if (data->trans_info)
- return;
-
- data->send_seq_num++;
- store_sequence_for_reply(&data->outstanding_packet_list,
- SVAL(outbuf,smb_mid), data->send_seq_num);
- data->send_seq_num++;
+ data->send_seq_num += 2;
}
/***********************************************************
@@ -362,7 +343,6 @@ static BOOL client_check_incoming_message(char *inbuf, struct smb_sign_info *si,
{
BOOL good;
uint32 reply_seq_number;
- uint32 saved_seq;
unsigned char calc_md5_mac[16];
unsigned char *server_sent_mac;
@@ -376,17 +356,9 @@ static BOOL client_check_incoming_message(char *inbuf, struct smb_sign_info *si,
return False;
}
- if (data->trans_info) {
- reply_seq_number = data->trans_info->reply_seq_num;
- } else if (!get_sequence_for_reply(&data->outstanding_packet_list,
- SVAL(inbuf, smb_mid), &reply_seq_number)) {
- DEBUG(1, ("client_check_incoming_message: failed to get sequence number %u for reply.\n",
- (unsigned int) SVAL(inbuf, smb_mid) ));
- return False;
- }
-
- saved_seq = reply_seq_number;
- simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
+ reply_seq_number = data->send_seq_num - 1;
+ simple_packet_signature(data, (const unsigned char *)inbuf,
+ reply_seq_number, calc_md5_mac);
server_sent_mac = (unsigned char *)&inbuf[smb_ss_field];
good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
@@ -400,12 +372,11 @@ static BOOL client_check_incoming_message(char *inbuf, struct smb_sign_info *si,
#if 1 /* JRATEST */
{
int i;
- reply_seq_number -= 5;
- for (i = 0; i < 10; i++, reply_seq_number++) {
- simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
+ for (i = -5; i < 5; i++) {
+ simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number+i, calc_md5_mac);
if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) {
DEBUG(0,("client_check_incoming_message: out of seq. seq num %u matches. \
-We were expecting seq %u\n", reply_seq_number, saved_seq ));
+We were expecting seq %u\n", reply_seq_number+i, reply_seq_number ));
break;
}
}
@@ -416,7 +387,7 @@ We were expecting seq %u\n", reply_seq_number, saved_seq ));
DEBUG(10, ("client_check_incoming_message: seq %u: got good SMB signature of\n", (unsigned int)reply_seq_number));
dump_data(10, (const char *)server_sent_mac, 8);
}
- return signing_good(inbuf, si, good, saved_seq, must_be_ok);
+ return signing_good(inbuf, si, good, reply_seq_number, must_be_ok);
}
/***********************************************************
@@ -437,10 +408,6 @@ static void simple_free_signing_context(struct smb_sign_info *si)
data_blob_free(&data->mac_key);
- if (data->trans_info) {
- SAFE_FREE(data->trans_info);
- }
-
SAFE_FREE(si->signing_context);
return;
@@ -503,65 +470,6 @@ BOOL cli_simple_set_signing(struct cli_state *cli,
}
/***********************************************************
- Tell client code we are in a multiple trans reply state.
- We call this after the last outgoing trans2 packet (which
- has incremented the sequence numbers), so we must save the
- current mid and sequence number -2.
-************************************************************/
-
-void cli_signing_trans_start(struct cli_state *cli, uint16 mid)
-{
- struct smb_basic_signing_context *data = cli->sign_info.signing_context;
- uint32 reply_seq_num;
-
- if (!cli->sign_info.doing_signing || !data)
- return;
-
- data->trans_info = SMB_XMALLOC_P(struct trans_info_context);
- ZERO_STRUCTP(data->trans_info);
-
- /* This ensures the sequence is pulled off the outstanding packet list */
- if (!get_sequence_for_reply(&data->outstanding_packet_list,
- mid, &reply_seq_num)) {
- DEBUG(1, ("get_sequence_for_reply failed - did we enter the trans signing state without sending a packet?\n"));
- return;
- }
-
- data->trans_info->send_seq_num = reply_seq_num - 1;
- data->trans_info->mid = mid;
- data->trans_info->reply_seq_num = reply_seq_num;
-
- DEBUG(10,("cli_signing_trans_start: storing mid = %u, reply_seq_num = %u, send_seq_num = %u \
-data->send_seq_num = %u\n",
- (unsigned int)data->trans_info->mid,
- (unsigned int)data->trans_info->reply_seq_num,
- (unsigned int)data->trans_info->send_seq_num,
- (unsigned int)data->send_seq_num ));
-}
-
-/***********************************************************
- Tell client code we are out of a multiple trans reply state.
-************************************************************/
-
-void cli_signing_trans_stop(struct cli_state *cli)
-{
- struct smb_basic_signing_context *data = cli->sign_info.signing_context;
-
- if (!cli->sign_info.doing_signing || !data)
- return;
-
- DEBUG(10,("cli_signing_trans_stop: freeing mid = %u, reply_seq_num = %u, send_seq_num = %u \
-data->send_seq_num = %u\n",
- (unsigned int)data->trans_info->mid,
- (unsigned int)data->trans_info->reply_seq_num,
- (unsigned int)data->trans_info->send_seq_num,
- (unsigned int)data->send_seq_num ));
-
- SAFE_FREE(data->trans_info);
- data->trans_info = NULL;
-}
-
-/***********************************************************
SMB signing - TEMP implementation - calculate a MAC to send.
************************************************************/
@@ -659,8 +567,7 @@ static void srv_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
{
unsigned char calc_md5_mac[16];
struct smb_basic_signing_context *data = si->signing_context;
- uint32 send_seq_number = data->send_seq_num;
- BOOL was_deferred_packet = False;
+ uint32 send_seq_number = data->send_seq_num-1;
uint16 mid;
if (!si->doing_signing) {
@@ -680,13 +587,7 @@ static void srv_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
mid = SVAL(outbuf, smb_mid);
/* See if this is a reply for a deferred packet. */
- was_deferred_packet = get_sequence_for_reply(&data->outstanding_packet_list, mid, &send_seq_number);
-
- if (data->trans_info && (data->trans_info->mid == mid)) {
- /* This is a reply in a trans stream. Use the sequence
- * number associated with the stream mid. */
- send_seq_number = data->trans_info->send_seq_num;
- }
+ get_sequence_for_reply(&data->outstanding_packet_list, mid, &send_seq_number);
simple_packet_signature(data, (const unsigned char *)outbuf, send_seq_number, calc_md5_mac);
@@ -697,36 +598,6 @@ static void srv_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
/* cli->outbuf[smb_ss_field+2]=0;
Uncomment this to test if the remote client actually verifies signatures...*/
-
- /* Don't mess with the sequence number for a deferred packet. */
- if (was_deferred_packet) {
- return;
- }
-
- if (!data->trans_info) {
- /* Always increment if not in a trans stream. */
- data->send_seq_num++;
- } else if ((data->trans_info->send_seq_num == data->send_seq_num) || (data->trans_info->mid != mid)) {
- /* Increment if this is the first reply in a trans stream or a
- * packet that doesn't belong to this stream (different mid). */
- data->send_seq_num++;
- }
-}
-
-/***********************************************************
- Is an incoming packet an oplock break reply ?
-************************************************************/
-
-static BOOL is_oplock_break(char *inbuf)
-{
- if (CVAL(inbuf,smb_com) != SMBlockingX)
- return False;
-
- if (!(CVAL(inbuf,smb_vwv3) & LOCKING_ANDX_OPLOCK_RELEASE))
- return False;
-
- DEBUG(10,("is_oplock_break: Packet is oplock break\n"));
- return True;
}
/***********************************************************
@@ -753,23 +624,8 @@ static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si, BO
mid = SVAL(inbuf, smb_mid);
- /* Is this part of a trans stream ? */
- if (data->trans_info && (data->trans_info->mid == mid)) {
- /* If so we don't increment the sequence. */
- reply_seq_number = data->trans_info->reply_seq_num;
- } else {
- /* We always increment the sequence number. */
- data->send_seq_num++;
-
- /* If we get an asynchronous oplock break reply and there
- * isn't a reply pending we need to re-sync the sequence
- * number.
- */
- if (is_oplock_break(inbuf)) {
- DEBUG(10,("srv_check_incoming_message: oplock break at seq num %u\n", data->send_seq_num));
- data->send_seq_num++;
- }
- }
+ /* We always increment the sequence number. */
+ data->send_seq_num += 2;
saved_seq = reply_seq_number;
simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
@@ -885,9 +741,8 @@ void srv_defer_sign_response(uint16 mid)
* Ensure we only store this mid reply once...
*/
- if (store_sequence_for_reply(&data->outstanding_packet_list, mid, data->send_seq_num)) {
- data->send_seq_num++;
- }
+ store_sequence_for_reply(&data->outstanding_packet_list, mid,
+ data->send_seq_num-1);
}
/***********************************************************
@@ -974,63 +829,6 @@ BOOL srv_signing_started(void)
return True;
}
-
-/***********************************************************
- Tell server code we are in a multiple trans reply state.
-************************************************************/
-
-void srv_signing_trans_start(uint16 mid)
-{
- struct smb_basic_signing_context *data;
-
- if (!srv_sign_info.doing_signing)
- return;
-
- data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
- if (!data)
- return;
-
- data->trans_info = SMB_XMALLOC_P(struct trans_info_context);
- ZERO_STRUCTP(data->trans_info);
-
- data->trans_info->reply_seq_num = data->send_seq_num-1;
- data->trans_info->mid = mid;
- data->trans_info->send_seq_num = data->send_seq_num;
-
- DEBUG(10,("srv_signing_trans_start: storing mid = %u, reply_seq_num = %u, send_seq_num = %u \
-data->send_seq_num = %u\n",
- (unsigned int)mid,
- (unsigned int)data->trans_info->reply_seq_num,
- (unsigned int)data->trans_info->send_seq_num,
- (unsigned int)data->send_seq_num ));
-}
-
-/***********************************************************
- Tell server code we are out of a multiple trans reply state.
-************************************************************/
-
-void srv_signing_trans_stop(void)
-{
- struct smb_basic_signing_context *data;
-
- if (!srv_sign_info.doing_signing)
- return;
-
- data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
- if (!data || !data->trans_info)
- return;
-
- DEBUG(10,("srv_signing_trans_stop: removing mid = %u, reply_seq_num = %u, send_seq_num = %u \
-data->send_seq_num = %u\n",
- (unsigned int)data->trans_info->mid,
- (unsigned int)data->trans_info->reply_seq_num,
- (unsigned int)data->trans_info->send_seq_num,
- (unsigned int)data->send_seq_num ));
-
- SAFE_FREE(data->trans_info);
- data->trans_info = NULL;
-}
-
/***********************************************************
Turn on signing from this packet onwards.
************************************************************/
diff --git a/source/locking/brlock.c b/source/locking/brlock.c
index 5078515b3e9..b95bb895cc3 100644
--- a/source/locking/brlock.c
+++ b/source/locking/brlock.c
@@ -52,6 +52,7 @@ struct lock_struct {
br_off size;
int fnum;
enum brl_type lock_type;
+ enum brl_flavour lock_flav;
};
/* The key used in the brlock database. */
@@ -66,6 +67,26 @@ struct lock_key {
static TDB_CONTEXT *tdb;
/****************************************************************************
+ Debug info at level 10 for lock struct.
+****************************************************************************/
+
+static void print_lock_struct(unsigned int i, struct lock_struct *pls)
+{
+ DEBUG(10,("[%u]: smbpid = %u, tid = %u, pid = %u, ",
+ i,
+ (unsigned int)pls->context.smbpid,
+ (unsigned int)pls->context.tid,
+ (unsigned int)procid_to_pid(&pls->context.pid) ));
+
+ DEBUG(10,("start = %.0f, size = %.0f, fnum = %d, %s %s\n",
+ (double)pls->start,
+ (double)pls->size,
+ pls->fnum,
+ lock_type_name(pls->lock_type),
+ lock_flav_name(pls->lock_flav) ));
+}
+
+/****************************************************************************
Create a locking key - ensuring zero filled for pad purposes.
****************************************************************************/
@@ -86,8 +107,8 @@ static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
See if two locking contexts are equal.
****************************************************************************/
-static BOOL brl_same_context(struct lock_context *ctx1,
- struct lock_context *ctx2)
+static BOOL brl_same_context(const struct lock_context *ctx1,
+ const struct lock_context *ctx2)
{
return (procid_equal(&ctx1->pid, &ctx2->pid) &&
(ctx1->smbpid == ctx2->smbpid) &&
@@ -98,8 +119,8 @@ static BOOL brl_same_context(struct lock_context *ctx1,
See if lck1 and lck2 overlap.
****************************************************************************/
-static BOOL brl_overlap(struct lock_struct *lck1,
- struct lock_struct *lck2)
+static BOOL brl_overlap(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
{
/* this extra check is not redundent - it copes with locks
that go beyond the end of 64 bit file space */
@@ -120,12 +141,14 @@ static BOOL brl_overlap(struct lock_struct *lck1,
See if lock2 can be added when lock1 is in place.
****************************************************************************/
-static BOOL brl_conflict(struct lock_struct *lck1,
- struct lock_struct *lck2)
+static BOOL brl_conflict(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
{
+ /* Ignore PENDING locks. */
if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
return False;
+ /* Read locks never conflict. */
if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
return False;
}
@@ -138,9 +161,42 @@ static BOOL brl_conflict(struct lock_struct *lck1,
return brl_overlap(lck1, lck2);
}
+/****************************************************************************
+ See if lock2 can be added when lock1 is in place - when both locks are POSIX
+ flavour. POSIX locks ignore fnum - they only care about dev/ino which we
+ know already match.
+****************************************************************************/
+
+static BOOL brl_conflict_posix(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
+{
+#if defined(DEVELOPER)
+ SMB_ASSERT(lck1->lock_flav == POSIX_LOCK);
+ SMB_ASSERT(lck2->lock_flav == POSIX_LOCK);
+#endif
+
+ /* Ignore PENDING locks. */
+ if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+ return False;
+
+ /* Read locks never conflict. */
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
+ return False;
+ }
+
+ /* Locks on the same context con't conflict. Ignore fnum. */
+ if (brl_same_context(&lck1->context, &lck2->context)) {
+ return False;
+ }
+
+ /* One is read, the other write, or the context is different,
+ do they overlap ? */
+ return brl_overlap(lck1, lck2);
+}
+
#if ZERO_ZERO
-static BOOL brl_conflict1(struct lock_struct *lck1,
- struct lock_struct *lck2)
+static BOOL brl_conflict1(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
{
if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
return False;
@@ -169,10 +225,11 @@ static BOOL brl_conflict1(struct lock_struct *lck1,
/****************************************************************************
Check to see if this lock conflicts, but ignore our own locks on the
- same fnum only.
+ same fnum only. This is the read/write lock check code path.
+ This is never used in the POSIX lock case.
****************************************************************************/
-static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
+static BOOL brl_conflict_other(const struct lock_struct *lck1, const struct lock_struct *lck2)
{
if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
return False;
@@ -180,6 +237,12 @@ static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck
if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
return False;
+ /* POSIX flavour locks never conflict here - this is only called
+ in the read/write path. */
+
+ if (lck1->lock_flav == POSIX_LOCK && lck2->lock_flav == POSIX_LOCK)
+ return False;
+
/*
* Incoming WRITE locks conflict with existing READ locks even
* if the context is the same. JRA. See LOCKTEST7 in smbtorture.
@@ -200,7 +263,7 @@ static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck
app depends on this ?
****************************************************************************/
-static NTSTATUS brl_lock_failed(struct lock_struct *lock)
+static NTSTATUS brl_lock_failed(const struct lock_struct *lock)
{
static struct lock_struct last_lock_failure;
@@ -222,146 +285,432 @@ static NTSTATUS brl_lock_failed(struct lock_struct *lock)
return NT_STATUS_LOCK_NOT_GRANTED;
}
-#if DONT_DO_THIS
- /* doing this traversal could kill solaris machines under high load (tridge) */
- /* delete any dead locks */
-
/****************************************************************************
- Delete a record if it is for a dead process, if check_self is true, then
- delete any records belonging to this pid also (there shouldn't be any).
+ Open up the brlock.tdb database.
****************************************************************************/
-static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+void brl_init(int read_only)
{
- struct lock_struct *locks;
- int count, i;
- BOOL check_self = *(BOOL *)state;
- pid_t mypid = sys_getpid();
-
- tdb_chainlock(tdb, kbuf);
+ if (tdb) {
+ return;
+ }
+ tdb = tdb_open_log(lock_path("brlock.tdb"),
+ lp_open_files_db_hash_size(),
+ TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
+ read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
+ if (!tdb) {
+ DEBUG(0,("Failed to open byte range locking database %s\n",
+ lock_path("brlock.tdb")));
+ return;
+ }
+}
- locks = (struct lock_struct *)dbuf.dptr;
+/****************************************************************************
+ Close down the brlock.tdb database.
+****************************************************************************/
- count = dbuf.dsize / sizeof(*locks);
- for (i=0; i<count; i++) {
- struct lock_struct *lock = &locks[i];
+void brl_shutdown(int read_only)
+{
+ if (!tdb) {
+ return;
+ }
+ tdb_close(tdb);
+}
- /* If check_self is true we want to remove our own records. */
- if (check_self && (mypid == lock->context.pid)) {
+#if ZERO_ZERO
+/****************************************************************************
+ Compare two locks for sorting.
+****************************************************************************/
- DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
- (unsigned int)lock->context.pid ));
+static int lock_compare(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
+{
+ if (lck1->start != lck2->start) {
+ return (lck1->start - lck2->start);
+ }
+ if (lck2->size != lck1->size) {
+ return ((int)lck1->size - (int)lck2->size);
+ }
+ return 0;
+}
+#endif
- } else if (process_exists(&lock->context.pid)) {
+/****************************************************************************
+ Lock a range of bytes - Windows lock semantics.
+****************************************************************************/
- DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
- continue;
+static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
+ const struct lock_struct *plock,
+ BOOL *my_lock_ctx)
+{
+ unsigned int i;
+ files_struct *fsp = br_lck->fsp;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+
+ for (i=0; i < br_lck->num_locks; i++) {
+ /* Do any Windows or POSIX locks conflict ? */
+ if (brl_conflict(&locks[i], plock)) {
+ NTSTATUS status = brl_lock_failed(plock);;
+ /* Did we block ourselves ? */
+ if (brl_same_context(&locks[i].context, &plock->context)) {
+ *my_lock_ctx = True;
+ }
+ return status;
+ }
+#if ZERO_ZERO
+ if (plock->start == 0 && plock->size == 0 &&
+ locks[i].size == 0) {
+ break;
}
+#endif
+ }
- DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
- (unsigned int)lock->context.pid ));
+ /* We can get the Windows lock, now see if it needs to
+ be mapped into a lower level POSIX one, and if so can
+ we get it ? We tell the lower lock layer about the
+ lock type so it can cope with the difference between
+ Windows "stacking" locks and POSIX "flat" ones. */
- if (count > 1 && i < count-1) {
- memmove(&locks[i], &locks[i+1],
- sizeof(*locks)*((count-1) - i));
+ if ((plock->lock_type != PENDING_LOCK) && lp_posix_locking(SNUM(fsp->conn))) {
+ if (!set_posix_lock(fsp, plock->start, plock->size, plock->lock_type, WINDOWS_LOCK)) {
+ if (errno == EACCES || errno == EAGAIN) {
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ } else {
+ return map_nt_error_from_unix(errno);
+ }
}
- count--;
- i--;
}
- if (count == 0) {
- tdb_delete(tdb, kbuf);
- } else if (count < (dbuf.dsize / sizeof(*locks))) {
- dbuf.dsize = count * sizeof(*locks);
- tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ /* no conflicts - add it to the list of locks */
+ locks = (struct lock_struct *)SMB_REALLOC(locks, (br_lck->num_locks + 1) * sizeof(*locks));
+ if (!locks) {
+ return NT_STATUS_NO_MEMORY;
}
- tdb_chainunlock(tdb, kbuf);
- return 0;
+ memcpy(&locks[br_lck->num_locks], plock, sizeof(struct lock_struct));
+ br_lck->num_locks += 1;
+ br_lck->lock_data = (void *)locks;
+ br_lck->modified = True;
+
+ return NT_STATUS_OK;
}
-#endif
/****************************************************************************
- Open up the brlock.tdb database.
+ Cope with POSIX range splits and merges.
****************************************************************************/
-void brl_init(int read_only)
+static unsigned int brlock_posix_split_merge(struct lock_struct *lck_arr,
+ const struct lock_struct *ex,
+ const struct lock_struct *plock,
+ BOOL *lock_was_added)
{
- if (tdb)
- return;
- tdb = tdb_open_log(lock_path("brlock.tdb"),
- lp_open_files_db_hash_size(),
- TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
- read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
- if (!tdb) {
- DEBUG(0,("Failed to open byte range locking database\n"));
- return;
+ BOOL lock_types_differ = (ex->lock_type != plock->lock_type);
+
+ /* We can't merge non-conflicting locks on different context - ignore fnum. */
+
+ if (!brl_same_context(&ex->context, &plock->context)) {
+ /* Just copy. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ return 1;
}
-#if DONT_DO_THIS
- /* doing this traversal could kill solaris machines under high load (tridge) */
- /* delete any dead locks */
- if (!read_only) {
- BOOL check_self = False;
- tdb_traverse(tdb, delete_fn, &check_self);
+ /* We now know we have the same context. */
+
+ /* Did we overlap ? */
+
+/*********************************************
+ +---------+
+ | ex |
+ +---------+
+ +-------+
+ | plock |
+ +-------+
+OR....
+ +---------+
+ | ex |
+ +---------+
+**********************************************/
+
+ if ( (ex->start >= (plock->start + plock->size)) ||
+ (plock->start >= (ex->start + ex->size))) {
+ /* No overlap with this lock - copy existing. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ return 1;
}
-#endif
+
+/*********************************************
+ +---------+
+ | ex |
+ +---------+
+ +---------------------------+
+ | plock | -> replace with plock.
+ +---------------------------+
+**********************************************/
+
+ if ( (ex->start >= plock->start) &&
+ (ex->start + ex->size <= plock->start + plock->size) ) {
+ memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+ *lock_was_added = True;
+ return 1;
+ }
+
+/*********************************************
+ +---------------+
+ | ex |
+ +---------------+
+ +---------------+
+ | plock |
+ +---------------+
+BECOMES....
+ +---------------+-------+
+ | plock | ex | - different lock types.
+ +---------------+-------+
+OR....
+ +-----------------------+
+ | ex | - same lock type.
+ +-----------------------+
+**********************************************/
+
+ if ( (ex->start >= plock->start) &&
+ (ex->start < plock->start + plock->size) &&
+ (ex->start + ex->size > plock->start + plock->size) ) {
+
+ *lock_was_added = True;
+
+ /* If the lock types are the same, we merge, if different, we
+ add the new lock before the old. */
+
+ if (lock_types_differ) {
+ /* Add new. */
+ memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+ memcpy(&lck_arr[1], ex, sizeof(struct lock_struct));
+ /* Adjust existing start and size. */
+ lck_arr[1].start = plock->start + plock->size;
+ lck_arr[1].size = (ex->start + ex->size) - (plock->start + plock->size);
+ return 2;
+ } else {
+ /* Merge. */
+ memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+ /* Set new start and size. */
+ lck_arr[0].start = plock->start;
+ lck_arr[0].size = (ex->start + ex->size) - plock->start;
+ return 1;
+ }
+ }
+
+/*********************************************
+ +---------------+
+ | ex |
+ +---------------+
+ +---------------+
+ | plock |
+ +---------------+
+BECOMES....
+ +-------+---------------+
+ | ex | plock | - different lock types
+ +-------+---------------+
+
+OR
+ +-----------------------+
+ | ex | - same lock type.
+ +-----------------------+
+
+**********************************************/
+
+ if ( (ex->start < plock->start) &&
+ (ex->start + ex->size > plock->start) &&
+ (ex->start + ex->size <= plock->start + plock->size) ) {
+
+ *lock_was_added = True;
+
+ /* If the lock types are the same, we merge, if different, we
+ add the new lock after the old. */
+
+ if (lock_types_differ) {
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ memcpy(&lck_arr[1], plock, sizeof(struct lock_struct));
+ /* Adjust existing size. */
+ lck_arr[0].size = plock->start - ex->start;
+ return 2;
+ } else {
+ /* Merge. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ /* Adjust existing size. */
+ lck_arr[0].size = (plock->start + plock->size) - ex->start;
+ return 1;
+ }
+ }
+
+/*********************************************
+ +---------------------------+
+ | ex |
+ +---------------------------+
+ +---------+
+ | plock |
+ +---------+
+BECOMES.....
+ +-------+---------+---------+
+ | ex | plock | ex | - different lock types.
+ +-------+---------+---------+
+OR
+ +---------------------------+
+ | ex | - same lock type.
+ +---------------------------+
+**********************************************/
+
+ if ( (ex->start < plock->start) && (ex->start + ex->size > plock->start + plock->size) ) {
+ *lock_was_added = True;
+
+ if (lock_types_differ) {
+
+ /* We have to split ex into two locks here. */
+
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ memcpy(&lck_arr[1], plock, sizeof(struct lock_struct));
+ memcpy(&lck_arr[2], ex, sizeof(struct lock_struct));
+
+ /* Adjust first existing size. */
+ lck_arr[0].size = plock->start - ex->start;
+
+ /* Adjust second existing start and size. */
+ lck_arr[2].start = plock->start + plock->size;
+ lck_arr[2].size = (ex->start + ex->size) - (plock->start + plock->size);
+ return 3;
+ } else {
+ /* Just eat plock. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ return 1;
+ }
+ }
+
+ /* Never get here. */
+ smb_panic("brlock_posix_split_merge\n");
+ /* Notreached. */
+ abort();
}
/****************************************************************************
- Close down the brlock.tdb database.
+ Lock a range of bytes - POSIX lock semantics.
+ We must cope with range splits and merges.
****************************************************************************/
-void brl_shutdown(int read_only)
+static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
+ const struct lock_struct *plock,
+ BOOL *my_lock_ctx)
{
- if (!tdb)
- return;
+ unsigned int i, count;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+ struct lock_struct *tp;
+ files_struct *fsp = br_lck->fsp;
+ BOOL lock_was_added = False;
+
+ /* No zero-zero locks for POSIX. */
+ if (plock->start == 0 && plock->size == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Don't allow 64-bit lock wrap. */
+ if (plock->start + plock->size < plock->start ||
+ plock->start + plock->size < plock->size) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* The worst case scenario here is we have to split an
+ existing POSIX lock range into two, and add our lock,
+ so we need at most 2 more entries. */
+
+ tp = SMB_MALLOC_ARRAY(struct lock_struct, (br_lck->num_locks + 2));
+ if (!tp) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ count = 0;
+ for (i=0; i < br_lck->num_locks; i++) {
+ if (locks[i].lock_flav == WINDOWS_LOCK) {
+ /* Do any Windows flavour locks conflict ? */
+ if (brl_conflict(&locks[i], plock)) {
+ /* Did we block ourselves ? */
+ if (brl_same_context(&locks[i].context, &plock->context)) {
+ *my_lock_ctx = True;
+ }
+ /* No games with error messages. */
+ SAFE_FREE(tp);
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+ /* Just copy the Windows lock into the new array. */
+ memcpy(&tp[count], &locks[i], sizeof(struct lock_struct));
+ count++;
+ } else {
+ /* POSIX conflict semantics are different. */
+ if (brl_conflict_posix(&locks[i], plock)) {
+ /* Can't block ourselves with POSIX locks. */
+ /* No games with error messages. */
+ SAFE_FREE(tp);
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ /* Work out overlaps. */
+ count += brlock_posix_split_merge(&tp[count], &locks[i], plock, &lock_was_added);
+ }
+ }
+
+ /* We can get the POSIX lock, now see if it needs to
+ be mapped into a lower level POSIX one, and if so can
+ we get it ? We well the lower lock layer about the
+ lock type so it can cope with the difference between
+ Windows "stacking" locks and POSIX "flat" ones. */
+
+#if 0
+ /* FIXME - this call doesn't work correctly yet for POSIX locks... */
-#if DONT_DO_THIS
- /* doing this traversal could kill solaris machines under high load (tridge) */
- /* delete any dead locks */
- if (!read_only) {
- BOOL check_self = True;
- tdb_traverse(tdb, delete_fn, &check_self);
+ if ((plock->lock_type != PENDING_LOCK) && lp_posix_locking(SNUM(fsp->conn))) {
+
+
+ if (!set_posix_lock(fsp, plock->start, plock->size, plock->lock_type, POSIX_LOCK)) {
+ if (errno == EACCES || errno == EAGAIN) {
+ SAFE_FREE(tp);
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ } else {
+ SAFE_FREE(tp);
+ return map_nt_error_from_unix(errno);
+ }
+ }
}
#endif
- tdb_close(tdb);
-}
+ if (!lock_was_added) {
+ memcpy(&tp[count], plock, sizeof(struct lock_struct));
+ count++;
+ }
-#if ZERO_ZERO
-/****************************************************************************
-compare two locks for sorting
-****************************************************************************/
-static int lock_compare(struct lock_struct *lck1,
- struct lock_struct *lck2)
-{
- if (lck1->start != lck2->start) return (lck1->start - lck2->start);
- if (lck2->size != lck1->size) {
- return ((int)lck1->size - (int)lck2->size);
+ /* Realloc so we don't leak entries per lock call. */
+ tp = (struct lock_struct *)SMB_REALLOC(tp, count * sizeof(*locks));
+ if (!tp) {
+ return NT_STATUS_NO_MEMORY;
}
- return 0;
+ br_lck->num_locks = count;
+ br_lck->lock_data = (void *)tp;
+ br_lck->modified = True;
+ return NT_STATUS_OK;
}
-#endif
/****************************************************************************
Lock a range of bytes.
****************************************************************************/
-NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
- uint16 smbpid, struct process_id pid, uint16 tid,
- br_off start, br_off size,
- enum brl_type lock_type, BOOL *my_lock_ctx)
+NTSTATUS brl_lock(struct byte_range_lock *br_lck,
+ uint16 smbpid,
+ struct process_id pid,
+ br_off start,
+ br_off size,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ BOOL *my_lock_ctx)
{
- TDB_DATA kbuf, dbuf;
- int count, i;
- struct lock_struct lock, *locks;
- NTSTATUS status = NT_STATUS_OK;
+ NTSTATUS ret;
+ struct lock_struct lock;
*my_lock_ctx = False;
- kbuf = locking_key(dev,ino);
-
- dbuf.dptr = NULL;
#if !ZERO_ZERO
if (start == 0 && size == 0) {
@@ -369,66 +718,27 @@ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
}
#endif
- tdb_chainlock(tdb, kbuf);
- dbuf = tdb_fetch(tdb, kbuf);
-
lock.context.smbpid = smbpid;
lock.context.pid = pid;
- lock.context.tid = tid;
+ lock.context.tid = br_lck->fsp->conn->cnum;
lock.start = start;
lock.size = size;
- lock.fnum = fnum;
+ lock.fnum = br_lck->fsp->fnum;
lock.lock_type = lock_type;
+ lock.lock_flav = lock_flav;
- if (dbuf.dptr) {
- /* there are existing locks - make sure they don't conflict */
- locks = (struct lock_struct *)dbuf.dptr;
- count = dbuf.dsize / sizeof(*locks);
- for (i=0; i<count; i++) {
- if (brl_conflict(&locks[i], &lock)) {
- status = brl_lock_failed(&lock);;
- /* Did we block ourselves ? */
- if (brl_same_context(&locks[i].context, &lock.context))
- *my_lock_ctx = True;
- goto fail;
- }
-#if ZERO_ZERO
- if (lock.start == 0 && lock.size == 0 &&
- locks[i].size == 0) {
- break;
- }
-#endif
- }
+ if (lock_flav == WINDOWS_LOCK) {
+ ret = brl_lock_windows(br_lck, &lock, my_lock_ctx);
+ } else {
+ ret = brl_lock_posix(br_lck, &lock, my_lock_ctx);
}
- /* no conflicts - add it to the list of locks */
- dbuf.dptr = SMB_REALLOC(dbuf.dptr, dbuf.dsize + sizeof(*locks));
- if (!dbuf.dptr) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
- dbuf.dsize += sizeof(lock);
-
#if ZERO_ZERO
/* sort the lock list */
- qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare);
+ qsort(br_lck->lock_data, (size_t)br_lck->num_locks, sizeof(lock), lock_compare);
#endif
- if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
- status = NT_STATUS_INTERNAL_DB_CORRUPTION;
- goto fail;
- }
-
- SAFE_FREE(dbuf.dptr);
- tdb_chainunlock(tdb, kbuf);
- return NT_STATUS_OK;
-
- fail:
-
- SAFE_FREE(dbuf.dptr);
- tdb_chainunlock(tdb, kbuf);
- return status;
+ return ret;
}
/****************************************************************************
@@ -445,260 +755,532 @@ static BOOL brl_pending_overlap(struct lock_struct *lock, struct lock_struct *pe
}
/****************************************************************************
- Unlock a range of bytes.
+ Unlock a range of bytes - Windows semantics.
****************************************************************************/
-BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
- uint16 smbpid, struct process_id pid, uint16 tid,
- br_off start, br_off size,
- BOOL remove_pending_locks_only,
- void (*pre_unlock_fn)(void *),
- void *pre_unlock_data)
+static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock_struct *plock)
{
- TDB_DATA kbuf, dbuf;
- int count, i, j;
- struct lock_struct *locks;
- struct lock_context context;
+ unsigned int i, j;
+ struct lock_struct *lock = NULL;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
- kbuf = locking_key(dev,ino);
+#if ZERO_ZERO
+ for (i = 0; i < br_lck->num_locks; i++) {
+ lock = &locks[i];
- dbuf.dptr = NULL;
+ if (lock->lock_type == WRITE_LOCK &&
+ brl_same_context(&lock->context, &plock->context) &&
+ lock->fnum == plock->fnum &&
+ lock->lock_flav == WINDOWS_LOCK &&
+ lock->start == plock->start &&
+ lock->size == plock->size) {
- tdb_chainlock(tdb, kbuf);
- dbuf = tdb_fetch(tdb, kbuf);
+ /* found it - delete it */
+ if (i < br_lck->num_locks - 1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((br_lck->num_locks-1) - i));
+ }
- if (!dbuf.dptr) {
- DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
- goto fail;
+ br_lck->num_locks -= 1;
+ br_lck->modified = True;
+ return True;
+ }
}
+#endif
- context.smbpid = smbpid;
- context.pid = pid;
- context.tid = tid;
+ for (i = 0; i < br_lck->num_locks; i++) {
+ lock = &locks[i];
- /* there are existing locks - find a match */
- locks = (struct lock_struct *)dbuf.dptr;
- count = dbuf.dsize / sizeof(*locks);
+ /* Only remove our own locks that match in start, size, and flavour. */
+ if (brl_same_context(&lock->context, &plock->context) &&
+ lock->fnum == plock->fnum &&
+ lock->lock_flav == WINDOWS_LOCK &&
+ lock->start == plock->start &&
+ lock->size == plock->size ) {
+ break;
+ }
+ }
-#if ZERO_ZERO
- for (i=0; i<count; i++) {
- struct lock_struct *lock = &locks[i];
+ if (i == br_lck->num_locks) {
+ /* we didn't find it */
+ return False;
+ }
- if (lock->lock_type == WRITE_LOCK &&
- brl_same_context(&lock->context, &context) &&
- lock->fnum == fnum &&
- lock->start == start &&
- lock->size == size) {
+ /* Unlock any POSIX regions. */
+ if(lp_posix_locking(br_lck->fsp->conn->cnum)) {
+ release_posix_lock(br_lck->fsp, plock->start, plock->size);
+ }
- if (pre_unlock_fn)
- (*pre_unlock_fn)(pre_unlock_data);
+ /* Send unlock messages to any pending waiters that overlap. */
+ for (j=0; j < br_lck->num_locks; j++) {
+ struct lock_struct *pend_lock = &locks[j];
- /* found it - delete it */
- if (count == 1) {
- tdb_delete(tdb, kbuf);
- } else {
- if (i < count-1) {
- memmove(&locks[i], &locks[i+1],
- sizeof(*locks)*((count-1) - i));
- }
- dbuf.dsize -= sizeof(*locks);
- tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
- }
+ /* Ignore non-pending locks. */
+ if (pend_lock->lock_type != PENDING_LOCK) {
+ continue;
+ }
- SAFE_FREE(dbuf.dptr);
- tdb_chainunlock(tdb, kbuf);
- return True;
+ /* We could send specific lock info here... */
+ if (brl_pending_overlap(lock, pend_lock)) {
+ DEBUG(10,("brl_unlock: sending unlock message to pid %s\n",
+ procid_str_static(&pend_lock->context.pid )));
+
+ become_root();
+ message_send_pid(pend_lock->context.pid,
+ MSG_SMB_UNLOCK,
+ NULL, 0, True);
+ unbecome_root();
}
}
-#endif
- locks = (struct lock_struct *)dbuf.dptr;
- count = dbuf.dsize / sizeof(*locks);
- for (i=0; i<count; i++) {
- struct lock_struct *lock = &locks[i];
+ /* Actually delete the lock. */
+ if (i < br_lck->num_locks - 1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((br_lck->num_locks-1) - i));
+ }
- if (brl_same_context(&lock->context, &context) &&
- lock->fnum == fnum &&
- lock->start == start &&
- lock->size == size) {
+ br_lck->num_locks -= 1;
+ br_lck->modified = True;
+ return True;
+}
+
+/****************************************************************************
+ Unlock a range of bytes - POSIX semantics.
+****************************************************************************/
- if (remove_pending_locks_only && lock->lock_type != PENDING_LOCK)
- continue;
+static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_struct *plock)
+{
+ unsigned int i, j, count;
+ struct lock_struct *lock = NULL;
+ struct lock_struct *tp;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+ BOOL overlap_found = False;
+
+ /* No zero-zero locks for POSIX. */
+ if (plock->start == 0 && plock->size == 0) {
+ return False;
+ }
- if (lock->lock_type != PENDING_LOCK) {
+ /* Don't allow 64-bit lock wrap. */
+ if (plock->start + plock->size < plock->start ||
+ plock->start + plock->size < plock->size) {
+ DEBUG(10,("brl_unlock_posix: lock wrap\n"));
+ return False;
+ }
- /* Do any POSIX unlocks needed. */
- if (pre_unlock_fn)
- (*pre_unlock_fn)(pre_unlock_data);
+ /* The worst case scenario here is we have to split an
+ existing POSIX lock range into two, so we need at most
+ 1 more entry. */
- /* Send unlock messages to any pending waiters that overlap. */
- for (j=0; j<count; j++) {
- struct lock_struct *pend_lock = &locks[j];
+ tp = SMB_MALLOC_ARRAY(struct lock_struct, (br_lck->num_locks + 1));
+ if (!tp) {
+ DEBUG(10,("brl_unlock_posix: malloc fail\n"));
+ return False;
+ }
- /* Ignore non-pending locks. */
- if (pend_lock->lock_type != PENDING_LOCK)
- continue;
+ count = 0;
+ for (i = 0; i < br_lck->num_locks; i++) {
+ struct lock_struct tmp_lock[3];
+ BOOL lock_was_added = False;
+ unsigned int tmp_count;
- /* We could send specific lock info here... */
- if (brl_pending_overlap(lock, pend_lock)) {
- DEBUG(10,("brl_unlock: sending unlock message to pid %s\n",
- procid_str_static(&pend_lock->context.pid )));
+ lock = &locks[i];
- message_send_pid(pend_lock->context.pid,
- MSG_SMB_UNLOCK,
- NULL, 0, True);
- }
- }
- }
+ /* Only remove our own locks - ignore fnum. */
+ if (lock->lock_type == PENDING_LOCK ||
+ !brl_same_context(&lock->context, &plock->context)) {
+ memcpy(&tp[count], lock, sizeof(struct lock_struct));
+ count++;
+ continue;
+ }
- /* found it - delete it */
- if (count == 1) {
- tdb_delete(tdb, kbuf);
+ /* Work out overlaps. */
+ tmp_count = brlock_posix_split_merge(&tmp_lock[0], &locks[i], plock, &lock_was_added);
+
+ if (tmp_count == 1) {
+ /* Ether the locks didn't overlap, or the unlock completely
+ overlapped this lock. If it didn't overlap, then there's
+ no change in the locks. */
+ if (tmp_lock[0].lock_type != UNLOCK_LOCK) {
+ SMB_ASSERT(tmp_lock[0].lock_type == locks[i].lock_type);
+ /* No change in this lock. */
+ memcpy(&tp[count], &tmp_lock[0], sizeof(struct lock_struct));
+ count++;
} else {
- if (i < count-1) {
- memmove(&locks[i], &locks[i+1],
- sizeof(*locks)*((count-1) - i));
- }
- dbuf.dsize -= sizeof(*locks);
- tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ SMB_ASSERT(tmp_lock[0].lock_type == UNLOCK_LOCK);
+ overlap_found = True;
}
+ continue;
+ } else if (tmp_count == 2) {
+ /* The unlock overlapped an existing lock. Copy the truncated
+ lock into the lock array. */
+ if (tmp_lock[0].lock_type != UNLOCK_LOCK) {
+ SMB_ASSERT(tmp_lock[0].lock_type == locks[i].lock_type);
+ SMB_ASSERT(tmp_lock[1].lock_type == UNLOCK_LOCK);
+ memcpy(&tp[count], &tmp_lock[0], sizeof(struct lock_struct));
+ } else {
+ SMB_ASSERT(tmp_lock[0].lock_type == UNLOCK_LOCK);
+ SMB_ASSERT(tmp_lock[1].lock_type == locks[i].lock_type);
+ memcpy(&tp[count], &tmp_lock[1], sizeof(struct lock_struct));
+ }
+ count++;
+ overlap_found = True;
+ continue;
+ } else {
+ /* tmp_count == 3 - (we split a lock range in two). */
+ SMB_ASSERT(tmp_lock[0].lock_type == locks[i].lock_type);
+ SMB_ASSERT(tmp_lock[1].lock_type == UNLOCK_LOCK);
+ SMB_ASSERT(tmp_lock[2].lock_type != locks[i].lock_type);
+
+ memcpy(&tp[count], &tmp_lock[0], sizeof(struct lock_struct));
+ count++;
+ memcpy(&tp[count], &tmp_lock[2], sizeof(struct lock_struct));
+ count++;
+ overlap_found = True;
+ /* Optimisation... */
+ /* We know we're finished here as we can't overlap any
+ more POSIX locks. Copy the rest of the lock array. */
+ if (i < br_lck->num_locks - 1) {
+ memcpy(&tp[count], &locks[i+1],
+ sizeof(*locks)*((br_lck->num_locks-1) - i));
+ count += ((br_lck->num_locks-1) - i);
+ }
+ break;
+ }
+ }
- SAFE_FREE(dbuf.dptr);
- tdb_chainunlock(tdb, kbuf);
- return True;
+ if (!overlap_found) {
+ /* Just ignore - no change. */
+ SAFE_FREE(tp);
+ DEBUG(10,("brl_unlock_posix: No overlap - unlocked.\n"));
+ return True;
+ }
+
+#if 0
+ /* FIXME - this call doesn't work correctly yet for POSIX locks... */
+
+ /* Unlock any POSIX regions. */
+ if(lp_posix_locking(br_lck->fsp->conn->cnum)) {
+ release_posix_lock(br_lck->fsp, plock->start, plock->size);
+ }
+#endif
+
+ /* Realloc so we don't leak entries per unlock call. */
+ if (count) {
+ tp = (struct lock_struct *)SMB_REALLOC(tp, count * sizeof(*locks));
+ if (!tp) {
+ DEBUG(10,("brl_unlock_posix: realloc fail\n"));
+ return False;
}
+ } else {
+ /* We deleted the last lock. */
+ SAFE_FREE(tp);
+ tp = NULL;
}
- /* we didn't find it */
+ br_lck->num_locks = count;
+ br_lck->lock_data = (void *)tp;
+ br_lck->modified = True;
- fail:
- SAFE_FREE(dbuf.dptr);
- tdb_chainunlock(tdb, kbuf);
- return False;
-}
+ /* Send unlock messages to any pending waiters that overlap. */
+ locks = tp;
+ for (j=0; j < br_lck->num_locks; j++) {
+ struct lock_struct *pend_lock = &locks[j];
+
+ /* Ignore non-pending locks. */
+ if (pend_lock->lock_type != PENDING_LOCK) {
+ continue;
+ }
+
+ /* We could send specific lock info here... */
+ if (brl_pending_overlap(lock, pend_lock)) {
+ DEBUG(10,("brl_unlock: sending unlock message to pid %s\n",
+ procid_str_static(&pend_lock->context.pid )));
+
+ become_root();
+ message_send_pid(pend_lock->context.pid,
+ MSG_SMB_UNLOCK,
+ NULL, 0, True);
+ unbecome_root();
+ }
+ }
+
+ return True;
+}
/****************************************************************************
- Test if we could add a lock if we wanted to.
+ Unlock a range of bytes.
****************************************************************************/
-BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
- uint16 smbpid, struct process_id pid, uint16 tid,
- br_off start, br_off size,
- enum brl_type lock_type)
+BOOL brl_unlock(struct byte_range_lock *br_lck,
+ uint16 smbpid,
+ struct process_id pid,
+ br_off start,
+ br_off size,
+ enum brl_flavour lock_flav)
{
- TDB_DATA kbuf, dbuf;
- int count, i;
- struct lock_struct lock, *locks;
+ struct lock_struct lock;
- kbuf = locking_key(dev,ino);
+ lock.context.smbpid = smbpid;
+ lock.context.pid = pid;
+ lock.context.tid = br_lck->fsp->conn->cnum;
+ lock.start = start;
+ lock.size = size;
+ lock.fnum = br_lck->fsp->fnum;
+ lock.lock_type = UNLOCK_LOCK;
+ lock.lock_flav = lock_flav;
+
+ if (lock_flav == WINDOWS_LOCK) {
+ return brl_unlock_windows(br_lck, &lock);
+ } else {
+ return brl_unlock_posix(br_lck, &lock);
+ }
+}
- dbuf.dptr = NULL;
+/****************************************************************************
+ Test if we could add a lock if we wanted to.
+ Returns True if the region required is currently unlocked, False if locked.
+****************************************************************************/
- dbuf = tdb_fetch(tdb, kbuf);
+BOOL brl_locktest(struct byte_range_lock *br_lck,
+ uint16 smbpid,
+ struct process_id pid,
+ br_off start,
+ br_off size,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav)
+{
+ BOOL ret = True;
+ unsigned int i;
+ struct lock_struct lock;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+ files_struct *fsp = br_lck->fsp;
lock.context.smbpid = smbpid;
lock.context.pid = pid;
- lock.context.tid = tid;
+ lock.context.tid = br_lck->fsp->conn->cnum;
lock.start = start;
lock.size = size;
- lock.fnum = fnum;
+ lock.fnum = fsp->fnum;
lock.lock_type = lock_type;
-
- if (dbuf.dptr) {
- /* there are existing locks - make sure they don't conflict */
- locks = (struct lock_struct *)dbuf.dptr;
- count = dbuf.dsize / sizeof(*locks);
- for (i=0; i<count; i++) {
- /*
- * Our own locks don't conflict.
- */
- if (brl_conflict_other(&locks[i], &lock))
- goto fail;
+ lock.lock_flav = lock_flav;
+
+ /* Make sure existing locks don't conflict */
+ for (i=0; i < br_lck->num_locks; i++) {
+ /*
+ * Our own locks don't conflict.
+ */
+ if (brl_conflict_other(&locks[i], &lock)) {
+ return False;
}
}
+ /*
+ * There is no lock held by an SMB daemon, check to
+ * see if there is a POSIX lock from a UNIX or NFS process.
+ * This only conflicts with Windows locks, not POSIX locks.
+ */
+
+ if(lp_posix_locking(fsp->conn->cnum) && (lock_flav == WINDOWS_LOCK)) {
+ ret = is_posix_locked(fsp, &start, &size, &lock_type, WINDOWS_LOCK);
+
+ DEBUG(10,("brl_locktest: posix start=%.0f len=%.0f %s for fnum %d file %s\n",
+ (double)start, (double)size, ret ? "locked" : "unlocked",
+ fsp->fnum, fsp->fsp_name ));
+
+ /* We need to return the inverse of is_posix_locked. */
+ ret = !ret;
+ }
+
/* no conflicts - we could have added it */
- SAFE_FREE(dbuf.dptr);
- return True;
+ return ret;
+}
- fail:
- SAFE_FREE(dbuf.dptr);
- return False;
+/****************************************************************************
+ Query for existing locks.
+****************************************************************************/
+
+NTSTATUS brl_lockquery(struct byte_range_lock *br_lck,
+ uint16 *psmbpid,
+ struct process_id pid,
+ br_off *pstart,
+ br_off *psize,
+ enum brl_type *plock_type,
+ enum brl_flavour lock_flav)
+{
+ unsigned int i;
+ struct lock_struct lock;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+ files_struct *fsp = br_lck->fsp;
+
+ lock.context.smbpid = *psmbpid;
+ lock.context.pid = pid;
+ lock.context.tid = br_lck->fsp->conn->cnum;
+ lock.start = *pstart;
+ lock.size = *psize;
+ lock.fnum = fsp->fnum;
+ lock.lock_type = *plock_type;
+ lock.lock_flav = lock_flav;
+
+ /* Make sure existing locks don't conflict */
+ for (i=0; i < br_lck->num_locks; i++) {
+ struct lock_struct *exlock = &locks[i];
+ BOOL conflict = False;
+
+ if (exlock->lock_flav == WINDOWS_LOCK) {
+ conflict = brl_conflict(exlock, &lock);
+ } else {
+ conflict = brl_conflict_posix(exlock, &lock);
+ }
+
+ if (conflict) {
+ *psmbpid = exlock->context.smbpid;
+ *pstart = exlock->start;
+ *psize = exlock->size;
+ *plock_type = exlock->lock_type;
+ return NT_STATUS_LOCK_NOT_GRANTED;
+ }
+ }
+
+ /*
+ * There is no lock held by an SMB daemon, check to
+ * see if there is a POSIX lock from a UNIX or NFS process.
+ */
+
+ if(lp_posix_locking(fsp->conn->cnum)) {
+ BOOL ret = is_posix_locked(fsp, pstart, psize, plock_type, POSIX_LOCK);
+
+ DEBUG(10,("brl_lockquery: posix start=%.0f len=%.0f %s for fnum %d file %s\n",
+ (double)*pstart, (double)*psize, ret ? "locked" : "unlocked",
+ fsp->fnum, fsp->fsp_name ));
+
+ if (ret) {
+ /* Hmmm. No clue what to set smbpid to - use -1. */
+ *psmbpid = 0xFFFF;
+ return NT_STATUS_LOCK_NOT_GRANTED;
+ }
+ }
+
+ return NT_STATUS_OK;
}
+
/****************************************************************************
- Remove any locks associated with a open file.
+ Remove a particular pending lock.
****************************************************************************/
-void brl_close(SMB_DEV_T dev, SMB_INO_T ino, struct process_id pid, int tid, int fnum)
+BOOL brl_remove_pending_lock(struct byte_range_lock *br_lck,
+ uint16 smbpid,
+ struct process_id pid,
+ br_off start,
+ br_off size,
+ enum brl_flavour lock_flav)
{
- TDB_DATA kbuf, dbuf;
- int count, i, j, dcount=0;
- struct lock_struct *locks;
+ unsigned int i;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+ struct lock_context context;
+
+ context.smbpid = smbpid;
+ context.pid = pid;
+ context.tid = br_lck->fsp->conn->cnum;
+
+ for (i = 0; i < br_lck->num_locks; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ /* For pending locks we *always* care about the fnum. */
+ if (brl_same_context(&lock->context, &context) &&
+ lock->fnum == br_lck->fsp->fnum &&
+ lock->lock_type == PENDING_LOCK &&
+ lock->lock_flav == lock_flav &&
+ lock->start == start &&
+ lock->size == size) {
+ break;
+ }
+ }
- kbuf = locking_key(dev,ino);
+ if (i == br_lck->num_locks) {
+ /* Didn't find it. */
+ return False;
+ }
- dbuf.dptr = NULL;
+ if (i < br_lck->num_locks - 1) {
+ /* Found this particular pending lock - delete it */
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((br_lck->num_locks-1) - i));
+ }
- tdb_chainlock(tdb, kbuf);
- dbuf = tdb_fetch(tdb, kbuf);
+ br_lck->num_locks -= 1;
+ br_lck->modified = True;
+ return True;
+}
- if (!dbuf.dptr) goto fail;
- /* there are existing locks - remove any for this fnum */
- locks = (struct lock_struct *)dbuf.dptr;
- count = dbuf.dsize / sizeof(*locks);
+/****************************************************************************
+ Remove any locks associated with a open file.
+****************************************************************************/
+
+void brl_close_fnum(struct byte_range_lock *br_lck, struct process_id pid)
+{
+ files_struct *fsp = br_lck->fsp;
+ uint16 tid = fsp->conn->cnum;
+ int fnum = fsp->fnum;
+ unsigned int i, j, dcount=0;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+
+ /* Remove any existing locks for this fnum (or any fnum if they're POSIX). */
- for (i=0; i<count; i++) {
+ for (i=0; i < br_lck->num_locks; i++) {
struct lock_struct *lock = &locks[i];
+ BOOL del_this_lock = False;
- if (lock->context.tid == tid &&
- procid_equal(&lock->context.pid, &pid) &&
- lock->fnum == fnum) {
+ if (lock->context.tid == tid && procid_equal(&lock->context.pid, &pid)) {
+ if ((lock->lock_flav == WINDOWS_LOCK) && (lock->fnum == fnum)) {
+ del_this_lock = True;
+ } else if (lock->lock_flav == POSIX_LOCK) {
+ del_this_lock = True;
+ }
+ }
+ if (del_this_lock) {
/* Send unlock messages to any pending waiters that overlap. */
- for (j=0; j<count; j++) {
+ for (j=0; j < br_lck->num_locks; j++) {
struct lock_struct *pend_lock = &locks[j];
/* Ignore our own or non-pending locks. */
- if (pend_lock->lock_type != PENDING_LOCK)
+ if (pend_lock->lock_type != PENDING_LOCK) {
continue;
+ }
+ /* Optimisation - don't send to this fnum as we're
+ closing it. */
if (pend_lock->context.tid == tid &&
procid_equal(&pend_lock->context.pid, &pid) &&
- pend_lock->fnum == fnum)
+ pend_lock->fnum == fnum) {
continue;
+ }
/* We could send specific lock info here... */
- if (brl_pending_overlap(lock, pend_lock))
+ if (brl_pending_overlap(lock, pend_lock)) {
+ become_root();
message_send_pid(pend_lock->context.pid,
MSG_SMB_UNLOCK,
NULL, 0, True);
+ unbecome_root();
+ }
}
/* found it - delete it */
- if (count > 1 && i < count-1) {
+ if (br_lck->num_locks > 1 && i < br_lck->num_locks - 1) {
memmove(&locks[i], &locks[i+1],
- sizeof(*locks)*((count-1) - i));
+ sizeof(*locks)*((br_lck->num_locks-1) - i));
}
- count--;
+ br_lck->num_locks--;
+ br_lck->modified = True;
i--;
dcount++;
}
}
-
- if (count == 0) {
- tdb_delete(tdb, kbuf);
- } else if (count < (dbuf.dsize / sizeof(*locks))) {
- dbuf.dsize -= dcount * sizeof(*locks);
- tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
- }
-
- /* we didn't find it */
- fail:
- SAFE_FREE(dbuf.dptr);
- tdb_chainunlock(tdb, kbuf);
}
/****************************************************************************
@@ -718,9 +1300,11 @@ static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *st
key = (struct lock_key *)kbuf.dptr;
for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
- traverse_callback(key->device, key->inode,
+ traverse_callback(key->device,
+ key->inode,
locks[i].context.pid,
locks[i].lock_type,
+ locks[i].lock_flav,
locks[i].start,
locks[i].size);
}
@@ -733,6 +1317,92 @@ static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *st
int brl_forall(BRLOCK_FN(fn))
{
- if (!tdb) return 0;
+ if (!tdb) {
+ return 0;
+ }
return tdb_traverse(tdb, traverse_fn, (void *)fn);
}
+
+/*******************************************************************
+ Store a potentially modified set of byte range lock data back into
+ the database.
+ Unlock the record.
+********************************************************************/
+
+static int byte_range_lock_destructor(void *p)
+{
+ struct byte_range_lock *br_lck =
+ talloc_get_type_abort(p, struct byte_range_lock);
+ TDB_DATA key = locking_key(br_lck->fsp->dev, br_lck->fsp->inode);
+
+ if (!br_lck->modified) {
+ goto done;
+ }
+
+ if (br_lck->num_locks == 0) {
+ /* No locks - delete this entry. */
+ if (tdb_delete(tdb, key) == -1) {
+ smb_panic("Could not delete byte range lock entry\n");
+ }
+ } else {
+ TDB_DATA data;
+ data.dptr = br_lck->lock_data;
+ data.dsize = br_lck->num_locks * sizeof(struct lock_struct);
+
+ if (tdb_store(tdb, key, data, TDB_REPLACE) == -1) {
+ smb_panic("Could not store byte range mode entry\n");
+ }
+ }
+
+ done:
+
+ SAFE_FREE(br_lck->lock_data);
+ tdb_chainunlock(tdb, key);
+ return 0;
+}
+
+/*******************************************************************
+ Fetch a set of byte range lock data from the database.
+ Leave the record locked.
+********************************************************************/
+
+struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
+ files_struct *fsp)
+{
+ TDB_DATA key = locking_key(fsp->dev, fsp->inode);
+ TDB_DATA data;
+ struct byte_range_lock *br_lck;
+
+ br_lck = TALLOC_P(mem_ctx, struct byte_range_lock);
+ if (br_lck == NULL) {
+ return NULL;
+ }
+
+ br_lck->fsp = fsp;
+ br_lck->num_locks = 0;
+ br_lck->modified = False;
+
+ if (tdb_chainlock(tdb, key) != 0) {
+ DEBUG(3, ("Could not lock byte range lock entry\n"));
+ TALLOC_FREE(br_lck);
+ return NULL;
+ }
+
+ talloc_set_destructor(br_lck, byte_range_lock_destructor);
+
+ data = tdb_fetch(tdb, key);
+ br_lck->lock_data = (void *)data.dptr;
+ br_lck->num_locks = data.dsize / sizeof(struct lock_struct);
+
+ if (DEBUGLEVEL >= 10) {
+ unsigned int i;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+ DEBUG(10,("brl_get_locks: %u current locks on dev=%.0f, inode=%.0f\n",
+ br_lck->num_locks,
+ (double)fsp->dev, (double)fsp->inode ));
+ for( i = 0; i < br_lck->num_locks; i++) {
+ print_lock_struct(i, &locks[i]);
+ }
+ }
+ return br_lck;
+}
diff --git a/source/locking/locking.c b/source/locking/locking.c
index 0ecc90c794c..0b3f625d03e 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
Locking functions
Copyright (C) Andrew Tridgell 1992-2000
- Copyright (C) Jeremy Allison 1992-2000
+ Copyright (C) Jeremy Allison 1992-2006
Copyright (C) Volker Lendecke 2005
This program is free software; you can redistribute it and/or modify
@@ -33,6 +33,7 @@
rewrtten completely to use new tdb code. Tridge, Dec '99
Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
+ Added Unix Extensions POSIX locking support. Jeremy Allison Mar 2006.
*/
#include "includes.h"
@@ -45,120 +46,179 @@ uint16 global_smbpid;
static TDB_CONTEXT *tdb;
/****************************************************************************
- Debugging aid :-).
+ Debugging aids :-).
****************************************************************************/
-static const char *lock_type_name(enum brl_type lock_type)
+const char *lock_type_name(enum brl_type lock_type)
{
- return (lock_type == READ_LOCK) ? "READ" : "WRITE";
+ switch (lock_type) {
+ case READ_LOCK:
+ return "READ";
+ case WRITE_LOCK:
+ return "WRITE";
+ case PENDING_LOCK:
+ return "PENDING";
+ default:
+ return "other";
+ }
+}
+
+const char *lock_flav_name(enum brl_flavour lock_flav)
+{
+ return (lock_flav == WINDOWS_LOCK) ? "WINDOWS_LOCK" : "POSIX_LOCK";
}
/****************************************************************************
Utility function called to see if a file region is locked.
+ Called in the read/write codepath.
****************************************************************************/
-BOOL is_locked(files_struct *fsp,connection_struct *conn,
- SMB_BIG_UINT count,SMB_BIG_UINT offset,
- enum brl_type lock_type)
+BOOL is_locked(files_struct *fsp,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_type lock_type)
{
- int snum = SNUM(conn);
+ int snum = SNUM(fsp->conn);
int strict_locking = lp_strict_locking(snum);
- BOOL ret;
+ enum brl_flavour lock_flav = lp_posix_cifsu_locktype();
+ BOOL ret = True;
- if (count == 0)
- return(False);
+ if (count == 0) {
+ return False;
+ }
- if (!lp_locking(snum) || !strict_locking)
- return(False);
+ if (!lp_locking(snum) || !strict_locking) {
+ return False;
+ }
if (strict_locking == Auto) {
if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && (lock_type == READ_LOCK || lock_type == WRITE_LOCK)) {
DEBUG(10,("is_locked: optimisation - exclusive oplock on file %s\n", fsp->fsp_name ));
- ret = 0;
+ ret = False;
} else if ((fsp->oplock_type == LEVEL_II_OPLOCK) &&
(lock_type == READ_LOCK)) {
DEBUG(10,("is_locked: optimisation - level II oplock on file %s\n", fsp->fsp_name ));
- ret = 0;
+ ret = False;
} else {
- ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum,
- global_smbpid, procid_self(), conn->cnum,
- offset, count, lock_type);
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+ if (!br_lck) {
+ return False;
+ }
+ ret = !brl_locktest(br_lck,
+ global_smbpid,
+ procid_self(),
+ offset,
+ count,
+ lock_type,
+ lock_flav);
+ TALLOC_FREE(br_lck);
}
} else {
- ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum,
- global_smbpid, procid_self(), conn->cnum,
- offset, count, lock_type);
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+ if (!br_lck) {
+ return False;
+ }
+ ret = !brl_locktest(br_lck,
+ global_smbpid,
+ procid_self(),
+ offset,
+ count,
+ lock_type,
+ lock_flav);
+ TALLOC_FREE(br_lck);
}
- DEBUG(10,("is_locked: brl start=%.0f len=%.0f %s for file %s\n",
+ DEBUG(10,("is_locked: flavour = %s brl start=%.0f len=%.0f %s for fnum %d file %s\n",
+ lock_flav_name(lock_flav),
(double)offset, (double)count, ret ? "locked" : "unlocked",
- fsp->fsp_name ));
+ fsp->fnum, fsp->fsp_name ));
- /*
- * There is no lock held by an SMB daemon, check to
- * see if there is a POSIX lock from a UNIX or NFS process.
- */
+ return ret;
+}
- if(!ret && lp_posix_locking(snum)) {
- ret = is_posix_locked(fsp, offset, count, lock_type);
+/****************************************************************************
+ Find out if a lock could be granted - return who is blocking us if we can't.
+****************************************************************************/
+
+NTSTATUS query_lock(files_struct *fsp,
+ uint16 *psmbpid,
+ SMB_BIG_UINT *pcount,
+ SMB_BIG_UINT *poffset,
+ enum brl_type *plock_type,
+ enum brl_flavour lock_flav)
+{
+ struct byte_range_lock *br_lck = NULL;
+ NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED;
- DEBUG(10,("is_locked: posix start=%.0f len=%.0f %s for file %s\n",
- (double)offset, (double)count, ret ? "locked" : "unlocked",
- fsp->fsp_name ));
+ if (!OPEN_FSP(fsp) || !fsp->can_lock) {
+ return NT_STATUS_INVALID_HANDLE;
}
- return ret;
+ if (!lp_locking(SNUM(fsp->conn))) {
+ return NT_STATUS_OK;
+ }
+
+ br_lck = brl_get_locks(NULL, fsp);
+ if (!br_lck) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = brl_lockquery(br_lck,
+ psmbpid,
+ procid_self(),
+ poffset,
+ pcount,
+ plock_type,
+ lock_flav);
+
+ TALLOC_FREE(br_lck);
+ return status;
}
/****************************************************************************
Utility function called by locking requests.
****************************************************************************/
-static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
- SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type, BOOL *my_lock_ctx)
+NTSTATUS do_lock(files_struct *fsp,
+ uint16 lock_pid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ BOOL *my_lock_ctx)
{
+ struct byte_range_lock *br_lck = NULL;
NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED;
- if (!lp_locking(SNUM(conn)))
+ if (!OPEN_FSP(fsp) || !fsp->can_lock) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (!lp_locking(SNUM(fsp->conn))) {
return NT_STATUS_OK;
+ }
/* NOTE! 0 byte long ranges ARE allowed and should be stored */
- DEBUG(10,("do_lock: lock type %s start=%.0f len=%.0f requested for file %s\n",
- lock_type_name(lock_type), (double)offset, (double)count, fsp->fsp_name ));
-
- if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn)) {
- status = brl_lock(fsp->dev, fsp->inode, fsp->fnum,
- lock_pid, procid_self(), conn->cnum,
- offset, count,
- lock_type, my_lock_ctx);
-
- if (NT_STATUS_IS_OK(status) && lp_posix_locking(SNUM(conn))) {
-
- /*
- * Try and get a POSIX lock on this range.
- * Note that this is ok if it is a read lock
- * overlapping on a different fd. JRA.
- */
-
- if (!set_posix_lock(fsp, offset, count, lock_type)) {
- if (errno == EACCES || errno == EAGAIN)
- status = NT_STATUS_FILE_LOCK_CONFLICT;
- else
- status = map_nt_error_from_unix(errno);
-
- /*
- * We failed to map - we must now remove the brl
- * lock entry.
- */
- (void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- lock_pid, procid_self(), conn->cnum,
- offset, count, False,
- NULL, NULL);
- }
- }
+ DEBUG(10,("do_lock: lock flavour %s lock type %s start=%.0f len=%.0f requested for fnum %d file %s\n",
+ lock_flav_name(lock_flav), lock_type_name(lock_type),
+ (double)offset, (double)count, fsp->fnum, fsp->fsp_name ));
+
+ br_lck = brl_get_locks(NULL, fsp);
+ if (!br_lck) {
+ return NT_STATUS_NO_MEMORY;
}
+ status = brl_lock(br_lck,
+ lock_pid,
+ procid_self(),
+ offset,
+ count,
+ lock_type,
+ lock_flav,
+ my_lock_ctx);
+
+ TALLOC_FREE(br_lck);
return status;
}
@@ -169,20 +229,33 @@ static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_p
it, we need this. JRA.
****************************************************************************/
-NTSTATUS do_lock_spin(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
- SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type, BOOL *my_lock_ctx)
+NTSTATUS do_lock_spin(files_struct *fsp,
+ uint16 lock_pid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ BOOL *my_lock_ctx)
{
int j, maxj = lp_lock_spin_count();
int sleeptime = lp_lock_sleep_time();
NTSTATUS status, ret;
- if (maxj <= 0)
+ if (maxj <= 0) {
maxj = 1;
+ }
ret = NT_STATUS_OK; /* to keep dumb compilers happy */
for (j = 0; j < maxj; j++) {
- status = do_lock(fsp, conn, lock_pid, count, offset, lock_type, my_lock_ctx);
+ status = do_lock(fsp,
+ lock_pid,
+ count,
+ offset,
+ lock_type,
+ lock_flav,
+ my_lock_ctx);
+
if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED) &&
!NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
return status;
@@ -191,72 +264,66 @@ NTSTATUS do_lock_spin(files_struct *fsp,connection_struct *conn, uint16 lock_pid
if (j == 0) {
ret = status;
/* Don't spin if we blocked ourselves. */
- if (*my_lock_ctx)
+ if (*my_lock_ctx) {
return ret;
+ }
+
+ /* Only spin for Windows locks. */
+ if (lock_flav == POSIX_LOCK) {
+ return ret;
+ }
}
- if (sleeptime)
+
+ if (sleeptime) {
sys_usleep(sleeptime);
+ }
}
return ret;
}
-/* Struct passed to brl_unlock. */
-struct posix_unlock_data_struct {
- files_struct *fsp;
- SMB_BIG_UINT offset;
- SMB_BIG_UINT count;
-};
-
-/****************************************************************************
- Function passed to brl_unlock to allow POSIX unlock to be done first.
-****************************************************************************/
-
-static void posix_unlock(void *pre_data)
-{
- struct posix_unlock_data_struct *pdata = (struct posix_unlock_data_struct *)pre_data;
-
- if (lp_posix_locking(SNUM(pdata->fsp->conn)))
- release_posix_lock(pdata->fsp, pdata->offset, pdata->count);
-}
-
/****************************************************************************
Utility function called by unlocking requests.
****************************************************************************/
-NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
- SMB_BIG_UINT count,SMB_BIG_UINT offset)
+NTSTATUS do_unlock(files_struct *fsp,
+ uint16 lock_pid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_flavour lock_flav)
{
BOOL ok = False;
- struct posix_unlock_data_struct posix_data;
+ struct byte_range_lock *br_lck = NULL;
- if (!lp_locking(SNUM(conn)))
+ if (!lp_locking(SNUM(fsp->conn))) {
return NT_STATUS_OK;
+ }
- if (!OPEN_FSP(fsp) || !fsp->can_lock || (fsp->conn != conn)) {
+ if (!OPEN_FSP(fsp) || !fsp->can_lock) {
return NT_STATUS_INVALID_HANDLE;
}
- DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
- (double)offset, (double)count, fsp->fsp_name ));
+ DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for fnum %d file %s\n",
+ (double)offset, (double)count, fsp->fnum, fsp->fsp_name ));
- /*
- * Remove the existing lock record from the tdb lockdb
- * before looking at POSIX locks. If this record doesn't
- * match then don't bother looking to remove POSIX locks.
- */
-
- posix_data.fsp = fsp;
- posix_data.offset = offset;
- posix_data.count = count;
+ br_lck = brl_get_locks(NULL, fsp);
+ if (!br_lck) {
+ return NT_STATUS_NO_MEMORY;
+ }
- ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- lock_pid, procid_self(), conn->cnum, offset, count,
- False, posix_unlock, (void *)&posix_data);
+ ok = brl_unlock(br_lck,
+ lock_pid,
+ procid_self(),
+ offset,
+ count,
+ lock_flav);
+ TALLOC_FREE(br_lck);
+
if (!ok) {
DEBUG(10,("do_unlock: returning ERRlock.\n" ));
return NT_STATUS_RANGE_NOT_LOCKED;
}
+
return NT_STATUS_OK;
}
@@ -266,6 +333,7 @@ NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
void locking_close_file(files_struct *fsp)
{
+ struct byte_range_lock *br_lck;
struct process_id pid = procid_self();
if (!lp_locking(SNUM(fsp->conn)))
@@ -275,13 +343,14 @@ void locking_close_file(files_struct *fsp)
* Just release all the brl locks, no need to release individually.
*/
- brl_close(fsp->dev, fsp->inode, pid, fsp->conn->cnum, fsp->fnum);
+ br_lck = brl_get_locks(NULL,fsp);
+ if (br_lck) {
+ brl_close_fnum(br_lck, pid);
+ TALLOC_FREE(br_lck);
+ }
if(lp_posix_locking(SNUM(fsp->conn))) {
-
- /*
- * Release all the POSIX locks.
- */
+ /* Release all the POSIX locks.*/
posix_locking_close_file(fsp);
}
diff --git a/source/locking/posix.c b/source/locking/posix.c
index 07246474f3f..e7075c57a64 100644
--- a/source/locking/posix.c
+++ b/source/locking/posix.c
@@ -644,8 +644,7 @@ static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
/****************************************************************************
Actual function that does POSIX locks. Copes with 64 -> 32 bit cruft and
- broken NFS implementations. Returns True if we got the lock or the region
- is unlocked in the F_GETLK case, False otherwise.
+ broken NFS implementations.
****************************************************************************/
static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
@@ -654,9 +653,6 @@ static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OF
DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fh->fd,op,(double)offset,(double)count,type));
- /* In the F_GETLK case this returns True if the region
- was locked, False if unlocked. */
-
ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
@@ -686,39 +682,97 @@ static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OF
}
DEBUG(8,("posix_fcntl_lock: Lock call %s\n", ret ? "successful" : "failed"));
+ return ret;
+}
+
+/****************************************************************************
+ Actual function that gets POSIX locks. Copes with 64 -> 32 bit cruft and
+ broken NFS implementations.
+****************************************************************************/
+static BOOL posix_fcntl_getlock(files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype)
+{
+ pid_t pid;
+ BOOL ret;
+
+ DEBUG(8,("posix_fcntl_getlock %d %.0f %.0f %d\n",
+ fsp->fh->fd,(double)*poffset,(double)*pcount,*ptype));
+
+ ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,poffset,pcount,ptype,&pid);
+
+ if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
+
+ DEBUG(0,("posix_fcntl_getlock: WARNING: lock request at offset %.0f, length %.0f returned\n",
+ (double)*poffset,(double)*pcount));
+ DEBUG(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
+ DEBUG(0,("on 32 bit NFS mounted file systems.\n"));
+
+ /*
+ * If the offset is > 0x7FFFFFFF then this will cause problems on
+ * 32 bit NFS mounted filesystems. Just ignore it.
+ */
+
+ if (*poffset & ~((SMB_OFF_T)0x7fffffff)) {
+ DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
+ return True;
+ }
+
+ if (*pcount & ~((SMB_OFF_T)0x7fffffff)) {
+ /* 32 bit NFS file system, retry with smaller offset */
+ DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
+ errno = 0;
+ *pcount &= 0x7fffffff;
+ ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,poffset,pcount,ptype,&pid);
+ }
+ }
+
+ DEBUG(8,("posix_fcntl_getlock: Lock query call %s\n", ret ? "successful" : "failed"));
return ret;
}
+
/****************************************************************************
POSIX function to see if a file region is locked. Returns True if the
region is locked, False otherwise.
****************************************************************************/
-BOOL is_posix_locked(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
+BOOL is_posix_locked(files_struct *fsp,
+ SMB_BIG_UINT *pu_offset,
+ SMB_BIG_UINT *pu_count,
+ enum brl_type *plock_type,
+ enum brl_flavour lock_flav)
{
SMB_OFF_T offset;
SMB_OFF_T count;
- int posix_lock_type = map_posix_lock_type(fsp,lock_type);
+ int posix_lock_type = map_posix_lock_type(fsp,*plock_type);
DEBUG(10,("is_posix_locked: File %s, offset = %.0f, count = %.0f, type = %s\n",
- fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
+ fsp->fsp_name, (double)*pu_offset, (double)*pu_count, posix_lock_type_name(*plock_type) ));
/*
* If the requested lock won't fit in the POSIX range, we will
* never set it, so presume it is not locked.
*/
- if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
+ if(!posix_lock_in_range(&offset, &count, *pu_offset, *pu_count)) {
return False;
+ }
- /*
- * Note that most UNIX's can *test* for a write lock on
- * a read-only fd, just not *set* a write lock on a read-only
- * fd. So we don't need to use map_lock_type here.
- */
+ if (!posix_fcntl_getlock(fsp,&offset,&count,&posix_lock_type)) {
+ return False;
+ }
- return posix_fcntl_lock(fsp,SMB_F_GETLK,offset,count,posix_lock_type);
+ if (posix_lock_type == F_UNLCK) {
+ return False;
+ }
+
+ if (lock_flav == POSIX_LOCK) {
+ /* Only POSIX lock queries need to know the details. */
+ *pu_offset = (SMB_BIG_UINT)offset;
+ *pu_count = (SMB_BIG_UINT)count;
+ *plock_type = (posix_lock_type == F_RDLCK) ? READ_LOCK : WRITE_LOCK;
+ }
+ return True;
}
/*
@@ -958,9 +1012,14 @@ lock: start = %.0f, size = %.0f\n", (double)l_curr->start, (double)l_curr->size,
/****************************************************************************
POSIX function to acquire a lock. Returns True if the
lock could be granted, False if not.
+ TODO -- Fix POSIX lock flavour semantics.
****************************************************************************/
-BOOL set_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
+BOOL set_posix_lock(files_struct *fsp,
+ SMB_BIG_UINT u_offset,
+ SMB_BIG_UINT u_count,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav)
{
SMB_OFF_T offset;
SMB_OFF_T count;
diff --git a/source/modules/vfs_full_audit.c b/source/modules/vfs_full_audit.c
index 0ae48f48186..309f6d15ae7 100644
--- a/source/modules/vfs_full_audit.c
+++ b/source/modules/vfs_full_audit.c
@@ -161,6 +161,8 @@ static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp
int fd, SMB_OFF_T len);
static BOOL smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int fd,
int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+static BOOL smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd,
+ SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid);
static int smb_full_audit_symlink(vfs_handle_struct *handle, connection_struct *conn,
const char *oldpath, const char *newpath);
static int smb_full_audit_readlink(vfs_handle_struct *handle, connection_struct *conn,
@@ -399,6 +401,8 @@ static vfs_op_tuple audit_op_tuples[] = {
SMB_VFS_LAYER_LOGGER},
{SMB_VFS_OP(smb_full_audit_lock), SMB_VFS_OP_LOCK,
SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_getlock), SMB_VFS_OP_GETLOCK,
+ SMB_VFS_LAYER_LOGGER},
{SMB_VFS_OP(smb_full_audit_symlink), SMB_VFS_OP_SYMLINK,
SMB_VFS_LAYER_LOGGER},
{SMB_VFS_OP(smb_full_audit_readlink), SMB_VFS_OP_READLINK,
@@ -564,6 +568,7 @@ static struct {
{ SMB_VFS_OP_UTIME, "utime" },
{ SMB_VFS_OP_FTRUNCATE, "ftruncate" },
{ SMB_VFS_OP_LOCK, "lock" },
+ { SMB_VFS_OP_GETLOCK, "getlock" },
{ SMB_VFS_OP_SYMLINK, "symlink" },
{ SMB_VFS_OP_READLINK, "readlink" },
{ SMB_VFS_OP_LINK, "link" },
@@ -1313,6 +1318,18 @@ static BOOL smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, in
return result;
}
+static BOOL smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd,
+ SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+ BOOL result;
+
+ result = SMB_VFS_NEXT_GETLOCK(handle, fsp, fd, poffset, pcount, ptype, ppid);
+
+ do_log(SMB_VFS_OP_GETLOCK, (result >= 0), handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
static int smb_full_audit_symlink(vfs_handle_struct *handle, connection_struct *conn,
const char *oldpath, const char *newpath)
{
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index e0c6c0686f1..af4293a11e8 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -5444,3 +5444,22 @@ void lp_set_posix_pathnames(void)
{
posix_pathnames = True;
}
+
+/*******************************************************************
+ Global state for POSIX lock processing - CIFS unix extensions.
+********************************************************************/
+
+static enum brl_flavour posix_cifsx_locktype; /* By default 0 == WINDOWS_LOCK */
+
+enum brl_flavour lp_posix_cifsu_locktype(void)
+{
+ return posix_cifsx_locktype;
+}
+
+/*******************************************************************
+********************************************************************/
+
+void lp_set_posix_cifsx_locktype(enum brl_flavour val)
+{
+ posix_cifsx_locktype = val;
+}
diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c
index 805e45f6ea3..6b47d0466bd 100644
--- a/source/smbd/blocking.c
+++ b/source/smbd/blocking.c
@@ -35,6 +35,8 @@ typedef struct _blocking_lock_record {
SMB_BIG_UINT offset;
SMB_BIG_UINT count;
uint16 lock_pid;
+ enum brl_flavour lock_flav;
+ enum brl_type lock_type;
char *inbuf;
int length;
} blocking_lock_record;
@@ -53,25 +55,6 @@ static void free_blocking_lock_record(blocking_lock_record *blr)
}
/****************************************************************************
- Get the files_struct given a particular queued SMB.
-*****************************************************************************/
-
-static files_struct *get_fsp_from_pkt(char *inbuf)
-{
- switch(CVAL(inbuf,smb_com)) {
- case SMBlock:
- case SMBlockread:
- return file_fsp(inbuf,smb_vwv0);
- case SMBlockingX:
- return file_fsp(inbuf,smb_vwv2);
- default:
- DEBUG(0,("get_fsp_from_pkt: PANIC - unknown type on blocking lock queue - exiting.!\n"));
- exit_server("PANIC - unknown type on blocking lock queue");
- }
- return NULL; /* Keep compiler happy. */
-}
-
-/****************************************************************************
Determine if this is a secondary element of a chained SMB.
**************************************************************************/
@@ -87,12 +70,19 @@ static void received_unlock_msg(int msg_type, struct process_id src,
Function to push a blocking lock request onto the lock queue.
****************************************************************************/
-BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
- int lock_num, uint16 lock_pid, SMB_BIG_UINT offset, SMB_BIG_UINT count)
+BOOL push_blocking_lock_request( char *inbuf, int length,
+ files_struct *fsp,
+ int lock_timeout,
+ int lock_num,
+ uint16 lock_pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ SMB_BIG_UINT offset, SMB_BIG_UINT count)
{
static BOOL set_lock_msg;
blocking_lock_record *blr, *tmp;
BOOL my_lock_ctx = False;
+ struct byte_range_lock *br_lck = NULL;
NTSTATUS status;
if(in_chained_smb() ) {
@@ -110,6 +100,9 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
return False;
}
+ blr->next = NULL;
+ blr->prev = NULL;
+
if((blr->inbuf = (char *)SMB_MALLOC(length)) == NULL) {
DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" ));
SAFE_FREE(blr);
@@ -117,19 +110,33 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
}
blr->com_type = CVAL(inbuf,smb_com);
- blr->fsp = get_fsp_from_pkt(inbuf);
+ blr->fsp = fsp;
blr->expire_time = (lock_timeout == -1) ? (time_t)-1 : time(NULL) + (time_t)lock_timeout;
blr->lock_num = lock_num;
blr->lock_pid = lock_pid;
+ blr->lock_flav = lock_flav;
+ blr->lock_type = lock_type;
blr->offset = offset;
blr->count = count;
memcpy(blr->inbuf, inbuf, length);
blr->length = length;
+ br_lck = brl_get_locks(NULL, blr->fsp);
+ if (!br_lck) {
+ free_blocking_lock_record(blr);
+ return False;
+ }
+
/* Add a pending lock record for this. */
- status = brl_lock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
- lock_pid, procid_self(), blr->fsp->conn->cnum,
- offset, count, PENDING_LOCK, &my_lock_ctx);
+ status = brl_lock(br_lck,
+ lock_pid,
+ procid_self(),
+ offset,
+ count,
+ PENDING_LOCK,
+ blr->lock_flav,
+ &my_lock_ctx);
+ TALLOC_FREE(br_lck);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
@@ -227,7 +234,6 @@ static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
{
char *inbuf = blr->inbuf;
files_struct *fsp = blr->fsp;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT) 0;
uint16 lock_pid;
@@ -261,7 +267,11 @@ static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
* request would never have been queued. JRA.
*/
- do_unlock(fsp,conn,lock_pid,count,offset);
+ do_unlock(fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
}
generic_blocking_lock_error(blr, status);
@@ -274,19 +284,41 @@ static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
{
switch(blr->com_type) {
+#if 0
+ /* We no longer push blocking lock requests for anything but lockingX and trans2. */
case SMBlock:
case SMBlockread:
generic_blocking_lock_error(blr, status);
break;
+#endif
case SMBlockingX:
reply_lockingX_error(blr, status);
break;
+ case SMBtrans2:
+ case SMBtranss2:
+ {
+ char *outbuf = get_OutBuffer();
+ char *inbuf = blr->inbuf;
+ construct_reply_common(inbuf, outbuf);
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBtranss2 which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBtrans2);
+ ERROR_NT(status);
+ if (!send_smb(smbd_server_fd(),outbuf)) {
+ exit_server("blocking_lock_reply_error: send_smb failed.");
+ }
+ break;
+ }
default:
DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n"));
exit_server("PANIC - unknown type on blocking lock queue");
}
}
+#if 0
+/* We no longer push blocking lock requests for anything but lockingX and trans2. */
+
/****************************************************************************
Attempt to finish off getting all pending blocking locks for a lockread call.
Returns True if we want to be removed from the list.
@@ -302,7 +334,6 @@ static BOOL process_lockread(blocking_lock_record *blr)
SMB_BIG_UINT startpos;
size_t numtoread;
NTSTATUS status;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
files_struct *fsp = blr->fsp;
BOOL my_lock_ctx = False;
@@ -312,7 +343,14 @@ static BOOL process_lockread(blocking_lock_record *blr)
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
- status = do_lock_spin( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, startpos, READ_LOCK, &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ SVAL(inbuf,smb_pid),
+ (SMB_BIG_UINT)numtoread,
+ startpos,
+ READ_LOCK,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
+
if (NT_STATUS_V(status)) {
if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
!NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
@@ -371,7 +409,6 @@ static BOOL process_lock(blocking_lock_record *blr)
int outsize;
SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
NTSTATUS status;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
files_struct *fsp = blr->fsp;
BOOL my_lock_ctx = False;
@@ -379,7 +416,14 @@ static BOOL process_lock(blocking_lock_record *blr)
offset = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
errno = 0;
- status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ SVAL(inbuf,smb_pid),
+ count,
+ offset,
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
+
if (NT_STATUS_IS_ERR(status)) {
if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
!NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
@@ -412,6 +456,7 @@ static BOOL process_lock(blocking_lock_record *blr)
send_blocking_reply(outbuf,outsize);
return True;
}
+#endif
/****************************************************************************
Attempt to finish off getting all pending blocking locks for a lockingX call.
@@ -423,7 +468,6 @@ static BOOL process_lockingX(blocking_lock_record *blr)
char *inbuf = blr->inbuf;
unsigned char locktype = CVAL(inbuf,smb_vwv3);
files_struct *fsp = blr->fsp;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
uint16 num_locks = SVAL(inbuf,smb_vwv7);
SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
@@ -452,9 +496,17 @@ static BOOL process_lockingX(blocking_lock_record *blr)
* request would never have been queued. JRA.
*/
errno = 0;
- status = do_lock_spin(fsp,conn,lock_pid,count,offset,
- ((locktype & 1) ? READ_LOCK : WRITE_LOCK), &my_lock_ctx);
- if (NT_STATUS_IS_ERR(status)) break;
+ status = do_lock_spin(fsp,
+ lock_pid,
+ count,
+ offset,
+ ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
+ WINDOWS_LOCK,
+ &my_lock_ctx);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ break;
+ }
}
if(blr->lock_num == num_locks) {
@@ -491,6 +543,51 @@ Waiting....\n",
}
/****************************************************************************
+ Attempt to get the posix lock request from a SMBtrans2 call.
+ Returns True if we want to be removed from the list.
+*****************************************************************************/
+
+static BOOL process_trans2(blocking_lock_record *blr)
+{
+ extern int max_send;
+ char *inbuf = blr->inbuf;
+ char *outbuf;
+ BOOL my_lock_ctx = False;
+ char params[2];
+ NTSTATUS status;
+
+ status = do_lock(blr->fsp,
+ blr->lock_pid,
+ blr->count,
+ blr->offset,
+ blr->lock_type,
+ blr->lock_flav,
+ &my_lock_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (ERROR_WAS_LOCK_DENIED(status)) {
+ /* Still can't get the lock, just keep waiting. */
+ return False;
+ }
+ /*
+ * We have other than a "can't get lock"
+ * error. Send an error and return True so we get dequeued.
+ */
+ blocking_lock_reply_error(blr, status);
+ return True;
+ }
+
+ /* We finally got the lock, return success. */
+ outbuf = get_OutBuffer();
+ construct_reply_common(inbuf, outbuf);
+ SCVAL(outbuf,smb_com,SMBtrans2);
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, max_send, params, 2, NULL, 0);
+ return True;
+}
+
+
+/****************************************************************************
Process a blocking lock SMB.
Returns True if we want to be removed from the list.
*****************************************************************************/
@@ -498,12 +595,18 @@ Waiting....\n",
static BOOL blocking_lock_record_process(blocking_lock_record *blr)
{
switch(blr->com_type) {
+#if 0
+ /* We no longer push blocking lock requests for anything but lockingX and trans2. */
case SMBlock:
return process_lock(blr);
case SMBlockread:
return process_lockread(blr);
+#endif
case SMBlockingX:
return process_lockingX(blr);
+ case SMBtrans2:
+ case SMBtranss2:
+ return process_trans2(blr);
default:
DEBUG(0,("blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.!\n"));
exit_server("PANIC - unknown type on blocking lock queue");
@@ -522,13 +625,21 @@ void remove_pending_lock_requests_by_fid(files_struct *fsp)
for(blr = blocking_lock_queue; blr; blr = next) {
next = blr->next;
if(blr->fsp->fnum == fsp->fnum) {
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
- DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \
+ if (br_lck) {
+ DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \
file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
- brl_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
- blr->lock_pid, procid_self(), blr->fsp->conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+
+ }
free_blocking_lock_record(blr);
}
@@ -547,14 +658,22 @@ void remove_pending_lock_requests_by_mid(int mid)
next = blr->next;
if(SVAL(blr->inbuf,smb_mid) == mid) {
files_struct *fsp = blr->fsp;
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
- DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \
+ if (br_lck) {
+ DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \
file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+
blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
- brl_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
- blr->lock_pid, procid_self(), blr->fsp->conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
free_blocking_lock_record(blr);
}
}
@@ -635,16 +754,25 @@ void process_blocking_lock_queue(time_t t)
fsp->fnum, fsp->fsp_name ));
if((blr->expire_time != -1) && (blr->expire_time <= t)) {
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+
/*
* Lock expired - throw away all previously
* obtained locks and return lock error.
*/
- DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
- fsp->fnum, fsp->fsp_name ));
- brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, procid_self(), conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ if (br_lck) {
+ DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
+ fsp->fnum, fsp->fsp_name ));
+
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
free_blocking_lock_record(blr);
@@ -652,32 +780,48 @@ void process_blocking_lock_queue(time_t t)
}
if(!change_to_user(conn,vuid)) {
- DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
- vuid ));
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+
/*
* Remove the entry and return an error to the client.
*/
- blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
- brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, procid_self(), conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ if (br_lck) {
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+ DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
+ vuid ));
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
free_blocking_lock_record(blr);
continue;
}
if(!set_current_service(conn,SVAL(blr->inbuf,smb_flg),True)) {
- DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+
/*
* Remove the entry and return an error to the client.
*/
- blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
- brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, procid_self(), conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ if (br_lck) {
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+ DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
free_blocking_lock_record(blr);
change_to_root_user();
continue;
@@ -690,10 +834,17 @@ void process_blocking_lock_queue(time_t t)
*/
if(blocking_lock_record_process(blr)) {
-
- brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, procid_self(), conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+
+ if (br_lck) {
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
free_blocking_lock_record(blr);
}
diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c
index 427b6ae2144..1b5a5f39c72 100644
--- a/source/smbd/ipc.c
+++ b/source/smbd/ipc.c
@@ -355,259 +355,349 @@ static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *na
return 0;
}
+static NTSTATUS handle_trans(connection_struct *conn,
+ struct trans_state *state,
+ char *outbuf, int *outsize)
+{
+ char *local_machine_name;
+ int name_offset = 0;
+
+ DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
+ state->name,state->total_data,state->total_param,
+ state->setup_count));
+
+ /*
+ * WinCE wierdness....
+ */
+
+ local_machine_name = talloc_asprintf(state, "\\%s\\",
+ get_local_machine_name());
+
+ if (local_machine_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (strnequal(state->name, local_machine_name,
+ strlen(local_machine_name))) {
+ name_offset = strlen(local_machine_name)-1;
+ }
+
+ if (!strnequal(&state->name[name_offset], "\\PIPE",
+ strlen("\\PIPE"))) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ name_offset += strlen("\\PIPE");
+
+ /* Win9x weirdness. When talking to a unicode server Win9x
+ only sends \PIPE instead of \PIPE\ */
+
+ if (state->name[name_offset] == '\\')
+ name_offset++;
+
+ DEBUG(5,("calling named_pipe\n"));
+ *outsize = named_pipe(conn, state->vuid, outbuf,
+ state->name+name_offset,
+ state->setup,state->data,
+ state->param,
+ state->setup_count,state->total_data,
+ state->total_param,
+ state->max_setup_return,
+ state->max_data_return,
+ state->max_param_return);
+
+ if (*outsize == 0) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (state->close_on_completion)
+ close_cnum(conn,state->vuid);
+
+ return NT_STATUS_OK;
+}
/****************************************************************************
Reply to a SMBtrans.
****************************************************************************/
-int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
+int reply_trans(connection_struct *conn, char *inbuf,char *outbuf,
+ int size, int bufsize)
{
- fstring name;
- int name_offset = 0;
- char *data=NULL,*params=NULL;
- uint16 *setup=NULL;
int outsize = 0;
- uint16 vuid = SVAL(inbuf,smb_uid);
- unsigned int tpscnt = SVAL(inbuf,smb_vwv0);
- unsigned int tdscnt = SVAL(inbuf,smb_vwv1);
- unsigned int mprcnt = SVAL(inbuf,smb_vwv2);
- unsigned int mdrcnt = SVAL(inbuf,smb_vwv3);
- unsigned int msrcnt = CVAL(inbuf,smb_vwv4);
- BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
- BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
- unsigned int pscnt = SVAL(inbuf,smb_vwv9);
- unsigned int psoff = SVAL(inbuf,smb_vwv10);
- unsigned int dscnt = SVAL(inbuf,smb_vwv11);
- unsigned int dsoff = SVAL(inbuf,smb_vwv12);
- unsigned int suwcnt = CVAL(inbuf,smb_vwv13);
- char *local_machine_name;
+ unsigned int dsoff = SVAL(inbuf, smb_dsoff);
+ unsigned int dscnt = SVAL(inbuf, smb_dscnt);
+ unsigned int psoff = SVAL(inbuf, smb_psoff);
+ unsigned int pscnt = SVAL(inbuf, smb_pscnt);
+ struct trans_state *state;
+ NTSTATUS result;
+
START_PROFILE(SMBtrans);
- memset(name, '\0',sizeof(name));
- srvstr_pull_buf(inbuf, name, smb_buf(inbuf), sizeof(name), STR_TERMINATE);
+ if (!NT_STATUS_IS_OK(allow_new_trans(conn->pending_trans,
+ SVAL(inbuf, smb_mid)))) {
+ DEBUG(2, ("Got invalid trans request: %s\n",
+ nt_errstr(result)));
+ END_PROFILE(SMBtrans);
+ return ERROR_NT(result);
+ }
- if (dscnt > tdscnt || pscnt > tpscnt)
+ if ((state = TALLOC_P(NULL, struct trans_state)) == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ END_PROFILE(SMBtrans);
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ state->cmd = SMBtrans;
+
+ state->mid = SVAL(inbuf, smb_mid);
+ state->vuid = SVAL(inbuf, smb_uid);
+ state->setup_count = CVAL(inbuf, smb_suwcnt);
+ state->total_param = SVAL(inbuf, smb_tpscnt);
+ state->param = NULL;
+ state->total_data = SVAL(inbuf, smb_tdscnt);
+ state->data = NULL;
+ state->max_param_return = SVAL(inbuf, smb_mprcnt);
+ state->max_data_return = SVAL(inbuf, smb_mdrcnt);
+ state->max_setup_return = CVAL(inbuf, smb_msrcnt);
+ state->close_on_completion = BITSETW(inbuf+smb_vwv5,0);
+ state->one_way = BITSETW(inbuf+smb_vwv5,1);
+
+ memset(state->name, '\0',sizeof(state->name));
+ srvstr_pull_buf(inbuf, state->name, smb_buf(inbuf),
+ sizeof(state->name), STR_TERMINATE);
+
+ if ((dscnt > state->total_data) || (pscnt > state->total_param))
goto bad_param;
-
- if (tdscnt) {
- if((data = (char *)SMB_MALLOC(tdscnt)) == NULL) {
- DEBUG(0,("reply_trans: data malloc fail for %u bytes !\n", tdscnt));
+
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->data = SMB_MALLOC(state->total_data);
+ if (state->data == NULL) {
+ DEBUG(0,("reply_trans: data malloc fail for %u "
+ "bytes !\n", state->total_data));
+ TALLOC_FREE(state);
END_PROFILE(SMBtrans);
return(ERROR_DOS(ERRDOS,ERRnomem));
}
if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
goto bad_param;
if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
- (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
+ (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
goto bad_param;
- memcpy(data,smb_base(inbuf)+dsoff,dscnt);
+ memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
}
- if (tpscnt) {
- if((params = (char *)SMB_MALLOC(tpscnt)) == NULL) {
- DEBUG(0,("reply_trans: param malloc fail for %u bytes !\n", tpscnt));
- SAFE_FREE(data);
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->param = SMB_MALLOC(state->total_param);
+ if (state->param == NULL) {
+ DEBUG(0,("reply_trans: param malloc fail for %u "
+ "bytes !\n", state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
END_PROFILE(SMBtrans);
return(ERROR_DOS(ERRDOS,ERRnomem));
}
if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
goto bad_param;
if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
- (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
+ (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
goto bad_param;
- memcpy(params,smb_base(inbuf)+psoff,pscnt);
+ memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
}
- if (suwcnt) {
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if (state->setup_count) {
unsigned int i;
- if((setup = SMB_MALLOC_ARRAY(uint16,suwcnt)) == NULL) {
- DEBUG(0,("reply_trans: setup malloc fail for %u bytes !\n", (unsigned int)(suwcnt * sizeof(uint16))));
- SAFE_FREE(data);
- SAFE_FREE(params);
+ if((state->setup = TALLOC_ARRAY(
+ state, uint16, state->setup_count)) == NULL) {
+ DEBUG(0,("reply_trans: setup malloc fail for %u "
+ "bytes !\n", (unsigned int)
+ (state->setup_count * sizeof(uint16))));
+ TALLOC_FREE(state);
END_PROFILE(SMBtrans);
return(ERROR_DOS(ERRDOS,ERRnomem));
}
- if (inbuf+smb_vwv14+(suwcnt*SIZEOFWORD) > inbuf + size)
+ if (inbuf+smb_vwv14+(state->setup_count*SIZEOFWORD) >
+ inbuf + size)
goto bad_param;
- if ((smb_vwv14+(suwcnt*SIZEOFWORD) < smb_vwv14) || (smb_vwv14+(suwcnt*SIZEOFWORD) < (suwcnt*SIZEOFWORD)))
+ if ((smb_vwv14+(state->setup_count*SIZEOFWORD) < smb_vwv14) ||
+ (smb_vwv14+(state->setup_count*SIZEOFWORD) <
+ (state->setup_count*SIZEOFWORD)))
goto bad_param;
- for (i=0;i<suwcnt;i++)
- setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
+ for (i=0;i<state->setup_count;i++)
+ state->setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
}
+ state->received_param = pscnt;
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
+ if ((state->received_param == state->total_param) &&
+ (state->received_data == state->total_data)) {
- if (pscnt < tpscnt || dscnt < tdscnt) {
- /* We need to send an interim response then receive the rest
- of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
- show_msg(outbuf);
- srv_signing_trans_stop();
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_trans: send_smb failed.");
- }
+ result = handle_trans(conn, state, outbuf, &outsize);
+
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
- /* receive the rest of the trans packet */
- while (pscnt < tpscnt || dscnt < tdscnt) {
- BOOL ret;
- unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
-
- ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
-
- /*
- * The sequence number for the trans reply is always
- * based on the last secondary received.
- */
-
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
-
- if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
- if(ret) {
- DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
- } else {
- DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
- (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
- }
- SAFE_FREE(params);
- SAFE_FREE(data);
- SAFE_FREE(setup);
+ if (!NT_STATUS_IS_OK(result)) {
END_PROFILE(SMBtrans);
- srv_signing_trans_stop();
- return(ERROR_DOS(ERRSRV,ERRerror));
+ return ERROR_NT(result);
}
- show_msg(inbuf);
-
- /* Revise total_params and total_data in case they have changed downwards */
- if (SVAL(inbuf,smb_vwv0) < tpscnt)
- tpscnt = SVAL(inbuf,smb_vwv0);
- if (SVAL(inbuf,smb_vwv1) < tdscnt)
- tdscnt = SVAL(inbuf,smb_vwv1);
-
- pcnt = SVAL(inbuf,smb_vwv2);
- poff = SVAL(inbuf,smb_vwv3);
- pdisp = SVAL(inbuf,smb_vwv4);
-
- dcnt = SVAL(inbuf,smb_vwv5);
- doff = SVAL(inbuf,smb_vwv6);
- ddisp = SVAL(inbuf,smb_vwv7);
-
- pscnt += pcnt;
- dscnt += dcnt;
-
- if (dscnt > tdscnt || pscnt > tpscnt)
- goto bad_param;
-
- if (pcnt) {
- if (pdisp+pcnt > tpscnt)
- goto bad_param;
- if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
- goto bad_param;
- if (pdisp > tpscnt)
- goto bad_param;
- if ((smb_base(inbuf) + poff + pcnt > inbuf + bufsize) ||
- (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
- goto bad_param;
- if (params + pdisp < params)
- goto bad_param;
-
- memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
+ if (outsize == 0) {
+ END_PROFILE(SMBtrans);
+ return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
}
- if (dcnt) {
- if (ddisp+dcnt > tdscnt)
- goto bad_param;
- if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
- goto bad_param;
- if (ddisp > tdscnt)
- goto bad_param;
- if ((smb_base(inbuf) + doff + dcnt > inbuf + bufsize) ||
- (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
- goto bad_param;
- if (data + ddisp < data)
- goto bad_param;
-
- memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
- }
+ END_PROFILE(SMBtrans);
+ return outsize;
}
- DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
- name,tdscnt,tpscnt,suwcnt));
+ DLIST_ADD(conn->pending_trans, state);
- /*
- * WinCE wierdness....
- */
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,True);
+ show_msg(outbuf);
+ END_PROFILE(SMBtrans);
+ return outsize;
- asprintf(&local_machine_name, "\\%s\\", get_local_machine_name());
+ bad_param:
- if (local_machine_name == NULL) {
- srv_signing_trans_stop();
- SAFE_FREE(data);
- SAFE_FREE(params);
- SAFE_FREE(setup);
- END_PROFILE(SMBtrans);
- return ERROR_NT(NT_STATUS_NO_MEMORY);
+ DEBUG(0,("reply_trans: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+}
+
+/****************************************************************************
+ Reply to a secondary SMBtrans.
+ ****************************************************************************/
+
+int reply_transs(connection_struct *conn, char *inbuf,char *outbuf,
+ int size, int bufsize)
+{
+ int outsize = 0;
+ unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
+ NTSTATUS result;
+
+ START_PROFILE(SMBtranss);
+
+ show_msg(inbuf);
+
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == SVAL(inbuf,smb_mid)) {
+ break;
+ }
}
- if (strnequal(name, local_machine_name, strlen(local_machine_name))) {
- name_offset = strlen(local_machine_name)-1;
+ if ((state == NULL) || (state->cmd != SMBtrans)) {
+ END_PROFILE(SMBtranss);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
- SAFE_FREE(local_machine_name);
+ /* Revise total_params and total_data in case they have changed
+ * downwards */
- if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) {
- name_offset += strlen("\\PIPE");
+ if (SVAL(inbuf, smb_vwv0) < state->total_param)
+ state->total_param = SVAL(inbuf,smb_vwv0);
+ if (SVAL(inbuf, smb_vwv1) < state->total_data)
+ state->total_data = SVAL(inbuf,smb_vwv1);
- /* Win9x weirdness. When talking to a unicode server Win9x
- only sends \PIPE instead of \PIPE\ */
+ pcnt = SVAL(inbuf, smb_spscnt);
+ poff = SVAL(inbuf, smb_spsoff);
+ pdisp = SVAL(inbuf, smb_spsdisp);
- if (name[name_offset] == '\\')
- name_offset++;
+ dcnt = SVAL(inbuf, smb_sdscnt);
+ doff = SVAL(inbuf, smb_sdsoff);
+ ddisp = SVAL(inbuf, smb_sdsdisp);
- DEBUG(5,("calling named_pipe\n"));
- outsize = named_pipe(conn,vuid,outbuf,
- name+name_offset,setup,data,params,
- suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
- } else {
- DEBUG(3,("invalid pipe name\n"));
- outsize = 0;
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
+
+ if (pcnt) {
+ if (pdisp+pcnt > state->total_param)
+ goto bad_param;
+ if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
+ goto bad_param;
+ if (pdisp > state->total_param)
+ goto bad_param;
+ if ((smb_base(inbuf) + poff + pcnt > inbuf + size) ||
+ (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->param + pdisp < state->param)
+ goto bad_param;
+
+ memcpy(state->param+pdisp,smb_base(inbuf)+poff,
+ pcnt);
}
-
- SAFE_FREE(data);
- SAFE_FREE(params);
- SAFE_FREE(setup);
-
- srv_signing_trans_stop();
+ if (dcnt) {
+ if (ddisp+dcnt > state->total_data)
+ goto bad_param;
+ if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
+ goto bad_param;
+ if (ddisp > state->total_data)
+ goto bad_param;
+ if ((smb_base(inbuf) + doff + dcnt > inbuf + size) ||
+ (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->data + ddisp < state->data)
+ goto bad_param;
- if (close_on_completion)
- close_cnum(conn,vuid);
+ memcpy(state->data+ddisp, smb_base(inbuf)+doff,
+ dcnt);
+ }
- if (one_way) {
- END_PROFILE(SMBtrans);
- return(-1);
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBtranss);
+ return -1;
}
-
- if (outsize == 0) {
- END_PROFILE(SMBtrans);
+
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBtranss which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBtrans);
+
+ result = handle_trans(conn, state, outbuf, &outsize);
+
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+
+ if ((outsize == 0) || !NT_STATUS_IS_OK(result)) {
+ END_PROFILE(SMBtranss);
return(ERROR_DOS(ERRSRV,ERRnosupport));
}
- END_PROFILE(SMBtrans);
+ END_PROFILE(SMBtranss);
return(outsize);
-
bad_param:
- srv_signing_trans_stop();
- DEBUG(0,("reply_trans: invalid trans parameters\n"));
- SAFE_FREE(data);
- SAFE_FREE(params);
- SAFE_FREE(setup);
- END_PROFILE(SMBtrans);
+ DEBUG(0,("reply_transs: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtranss);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index 796eb443326..24d64ecfc76 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -1812,19 +1812,6 @@ int reply_ntrename(connection_struct *conn,
}
/****************************************************************************
- Reply to an unsolicited SMBNTtranss - just ignore it!
-****************************************************************************/
-
-int reply_nttranss(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
-{
- START_PROFILE(SMBnttranss);
- DEBUG(4,("Ignoring nttranss of length %d\n",length));
- END_PROFILE(SMBnttranss);
- return(-1);
-}
-
-/****************************************************************************
Reply to a notify change - queue the request and
don't allow a directory to be opened.
****************************************************************************/
@@ -2719,29 +2706,120 @@ static int call_nt_transact_set_user_quota(connection_struct *conn, char *inbuf,
}
#endif /* HAVE_SYS_QUOTAS */
+static int handle_nttrans(connection_struct *conn,
+ struct trans_state *state,
+ char *inbuf, char *outbuf, int size, int bufsize)
+{
+ int outsize;
+
+ if (Protocol >= PROTOCOL_NT1) {
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
+ }
+
+ /* Now we must call the relevant NT_TRANS function */
+ switch(state->call) {
+ case NT_TRANSACT_CREATE:
+ START_PROFILE_NESTED(NT_transact_create);
+ outsize = call_nt_transact_create(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_create);
+ break;
+ case NT_TRANSACT_IOCTL:
+ START_PROFILE_NESTED(NT_transact_ioctl);
+ outsize = call_nt_transact_ioctl(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_ioctl);
+ break;
+ case NT_TRANSACT_SET_SECURITY_DESC:
+ START_PROFILE_NESTED(NT_transact_set_security_desc);
+ outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_set_security_desc);
+ break;
+ case NT_TRANSACT_NOTIFY_CHANGE:
+ START_PROFILE_NESTED(NT_transact_notify_change);
+ outsize = call_nt_transact_notify_change(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_notify_change);
+ break;
+ case NT_TRANSACT_RENAME:
+ START_PROFILE_NESTED(NT_transact_rename);
+ outsize = call_nt_transact_rename(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_rename);
+ break;
+
+ case NT_TRANSACT_QUERY_SECURITY_DESC:
+ START_PROFILE_NESTED(NT_transact_query_security_desc);
+ outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_query_security_desc);
+ break;
+#ifdef HAVE_SYS_QUOTAS
+ case NT_TRANSACT_GET_USER_QUOTA:
+ START_PROFILE_NESTED(NT_transact_get_user_quota);
+ outsize = call_nt_transact_get_user_quota(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_get_user_quota);
+ break;
+ case NT_TRANSACT_SET_USER_QUOTA:
+ START_PROFILE_NESTED(NT_transact_set_user_quota);
+ outsize = call_nt_transact_set_user_quota(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_set_user_quota);
+ break;
+#endif /* HAVE_SYS_QUOTAS */
+ default:
+ /* Error in request */
+ DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n",
+ state->call));
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
+ return outsize;
+}
+
/****************************************************************************
Reply to a SMBNTtrans.
****************************************************************************/
int reply_nttrans(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+ char *inbuf,char *outbuf,int size,int bufsize)
{
int outsize = 0;
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
-#if 0 /* Not used. */
- uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount);
- uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount);
-#endif /* Not used. */
- uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount);
- uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount);
- uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount);
- uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset);
- uint32 data_count = IVAL(inbuf,smb_nt_DataCount);
- uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset);
- uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */
+ uint32 pscnt = IVAL(inbuf,smb_nt_ParameterCount);
+ uint32 psoff = IVAL(inbuf,smb_nt_ParameterOffset);
+ uint32 dscnt = IVAL(inbuf,smb_nt_DataCount);
+ uint32 dsoff = IVAL(inbuf,smb_nt_DataOffset);
+
uint16 function_code = SVAL( inbuf, smb_nt_Function);
- char *params = NULL, *data = NULL, *setup = NULL;
- uint32 num_params_sofar, num_data_sofar;
+ NTSTATUS result;
+ struct trans_state *state;
+
START_PROFILE(SMBnttrans);
if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
@@ -2749,319 +2827,269 @@ int reply_nttrans(connection_struct *conn,
return ERROR_DOS(ERRSRV,ERRaccess);
}
- outsize = set_message(outbuf,0,0,True);
+ if (!NT_STATUS_IS_OK(allow_new_trans(conn->pending_trans,
+ SVAL(inbuf, smb_mid)))) {
+ DEBUG(2, ("Got invalid nttrans request: %s\n", nt_errstr(result)));
+ END_PROFILE(SMBnttrans);
+ return ERROR_NT(result);
+ }
+
+ if ((state = TALLOC_P(NULL, struct trans_state)) == NULL) {
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRSRV,ERRaccess);
+ }
+
+ state->cmd = SMBnttrans;
+
+ state->mid = SVAL(inbuf,smb_mid);
+ state->vuid = SVAL(inbuf,smb_uid);
+ state->total_data = IVAL(inbuf, smb_nt_TotalDataCount);
+ state->data = NULL;
+ state->total_param = IVAL(inbuf, smb_nt_TotalParameterCount);
+ state->param = NULL;
+ state->max_data_return = IVAL(inbuf,smb_nt_MaxDataCount);
+
+ /* setup count is in *words* */
+ state->setup_count = 2*CVAL(inbuf,smb_nt_SetupCount);
+ state->call = function_code;
/*
- * All nttrans messages we handle have smb_wct == 19 + setup_count.
- * Ensure this is so as a sanity check.
+ * All nttrans messages we handle have smb_wct == 19 +
+ * state->setup_count. Ensure this is so as a sanity check.
*/
- if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) {
+ if(CVAL(inbuf, smb_wct) != 19 + (state->setup_count/2)) {
DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
- CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
+ CVAL(inbuf, smb_wct), 19 + (state->setup_count/2)));
goto bad_param;
}
/* Don't allow more than 128mb for each value. */
- if ((total_parameter_count > (1024*1024*128)) || (total_data_count > (1024*1024*128))) {
+ if ((state->total_data > (1024*1024*128)) ||
+ (state->total_param > (1024*1024*128))) {
END_PROFILE(SMBnttrans);
return ERROR_DOS(ERRDOS,ERRnomem);
}
- /* Allocate the space for the setup, the maximum needed parameters and data */
-
- if(setup_count > 0) {
- setup = (char *)SMB_MALLOC(setup_count);
- }
- if (total_parameter_count > 0) {
- params = (char *)SMB_MALLOC(total_parameter_count);
- }
- if (total_data_count > 0) {
- data = (char *)SMB_MALLOC(total_data_count);
- }
-
- if ((total_parameter_count && !params) || (total_data_count && !data) ||
- (setup_count && !setup)) {
- SAFE_FREE(setup);
- SAFE_FREE(params);
- SAFE_FREE(data);
- DEBUG(0,("reply_nttrans : Out of memory\n"));
- END_PROFILE(SMBnttrans);
- return ERROR_DOS(ERRDOS,ERRnomem);
- }
-
- /* Copy the param and data bytes sent with this request into the params buffer */
- num_params_sofar = parameter_count;
- num_data_sofar = data_count;
-
- if (parameter_count > total_parameter_count || data_count > total_data_count)
+ if ((dscnt > state->total_data) || (pscnt > state->total_param))
goto bad_param;
- if(setup) {
- DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count));
- if ((smb_nt_SetupStart + setup_count < smb_nt_SetupStart) ||
- (smb_nt_SetupStart + setup_count < setup_count)) {
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ if ((state->data = SMB_MALLOC(state->total_data)) == NULL) {
+ DEBUG(0,("reply_nttrans: data malloc fail for %u "
+ "bytes !\n", state->total_data));
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
goto bad_param;
- }
- if (smb_nt_SetupStart + setup_count > length) {
+ if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
+ (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
goto bad_param;
- }
- memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
- dump_data(10, setup, setup_count);
+ memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
}
- if(params) {
- DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count));
- if ((parameter_offset + parameter_count < parameter_offset) ||
- (parameter_offset + parameter_count < parameter_count)) {
+
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ if ((state->param = SMB_MALLOC(state->total_param)) == NULL) {
+ DEBUG(0,("reply_nttrans: param malloc fail for %u "
+ "bytes !\n", state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
goto bad_param;
- }
- if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length)||
- (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) {
+ if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
+ (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
goto bad_param;
- }
- memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
- dump_data(10, params, parameter_count);
+ memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
}
- if(data) {
- DEBUG(10,("reply_nttrans: data_count = %d\n",data_count));
- if ((data_offset + data_count < data_offset) || (data_offset + data_count < data_count)) {
+
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if(state->setup_count > 0) {
+ DEBUG(10,("reply_nttrans: state->setup_count = %d\n",
+ state->setup_count));
+ state->setup = TALLOC(state, state->setup_count);
+ if (state->setup == NULL) {
+ DEBUG(0,("reply_nttrans : Out of memory\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+
+ if ((smb_nt_SetupStart + state->setup_count < smb_nt_SetupStart) ||
+ (smb_nt_SetupStart + state->setup_count < state->setup_count)) {
goto bad_param;
}
- if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) ||
- (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) {
+ if (smb_nt_SetupStart + state->setup_count > size) {
goto bad_param;
}
- memcpy( data, smb_base(inbuf) + data_offset, data_count);
- dump_data(10, data, data_count);
+ memcpy( state->setup, &inbuf[smb_nt_SetupStart], state->setup_count);
+ dump_data(10, (char *)state->setup, state->setup_count);
}
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
+ if ((state->received_data == state->total_data) &&
+ (state->received_param == state->total_param)) {
+ outsize = handle_nttrans(conn, state, inbuf, outbuf,
+ size, bufsize);
+ SAFE_FREE(state->param);
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return outsize;
+ }
- if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
- /* We need to send an interim response then receive the rest
- of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
- srv_signing_trans_stop();
- show_msg(outbuf);
- if (!send_smb(smbd_server_fd(),outbuf)) {
- exit_server("reply_nttrans: send_smb failed.");
- }
+ DLIST_ADD(conn->pending_trans, state);
- while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
- BOOL ret;
- uint32 parameter_displacement;
- uint32 data_displacement;
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,True);
+ show_msg(outbuf);
+ END_PROFILE(SMBnttrans);
+ return outsize;
- ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+ bad_param:
- /* We need to re-calcuate the new length after we've read the secondary packet. */
- length = smb_len(inbuf) + 4;
+ DEBUG(0,("reply_nttrans: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+}
+
+/****************************************************************************
+ Reply to a SMBnttranss
+ ****************************************************************************/
- /*
- * The sequence number for the trans reply is always
- * based on the last secondary received.
- */
+int reply_nttranss(connection_struct *conn, char *inbuf,char *outbuf,
+ int size,int bufsize)
+{
+ int outsize = 0;
+ unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
+ START_PROFILE(SMBnttranss);
- if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) {
- outsize = set_message(outbuf,0,0,True);
- if(ret) {
- DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n"));
- } else {
- DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
- (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
- }
- goto bad_param;
- }
-
- /* Revise total_params and total_data in case they have changed downwards */
- if (IVAL(inbuf, smb_nts_TotalParameterCount) < total_parameter_count) {
- total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
- }
- if (IVAL(inbuf, smb_nts_TotalDataCount) < total_data_count) {
- total_data_count = IVAL(inbuf, smb_nts_TotalDataCount);
- }
+ show_msg(inbuf);
- parameter_count = IVAL(inbuf,smb_nts_ParameterCount);
- parameter_offset = IVAL(inbuf, smb_nts_ParameterOffset);
- parameter_displacement = IVAL(inbuf, smb_nts_ParameterDisplacement);
- num_params_sofar += parameter_count;
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == SVAL(inbuf,smb_mid)) {
+ break;
+ }
+ }
- data_count = IVAL(inbuf, smb_nts_DataCount);
- data_displacement = IVAL(inbuf, smb_nts_DataDisplacement);
- data_offset = IVAL(inbuf, smb_nts_DataOffset);
- num_data_sofar += data_count;
+ if ((state == NULL) || (state->cmd != SMBnttrans)) {
+ END_PROFILE(SMBnttranss);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
- if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) {
- DEBUG(0,("reply_nttrans2: data overflow in secondary nttrans packet"));
- goto bad_param;
- }
+ /* Revise state->total_param and state->total_data in case they have
+ changed downwards */
+ if (IVAL(inbuf, smb_nts_TotalParameterCount) < state->total_param) {
+ state->total_param = IVAL(inbuf, smb_nts_TotalParameterCount);
+ }
+ if (IVAL(inbuf, smb_nts_TotalDataCount) < state->total_data) {
+ state->total_data = IVAL(inbuf, smb_nts_TotalDataCount);
+ }
- if (parameter_count) {
- if (parameter_displacement + parameter_count > total_parameter_count) {
- goto bad_param;
- }
- if ((parameter_displacement + parameter_count < parameter_displacement) ||
- (parameter_displacement + parameter_count < parameter_count)) {
- goto bad_param;
- }
- if (parameter_displacement > total_parameter_count) {
- goto bad_param;
- }
- if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length) ||
- (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) {
- goto bad_param;
- }
- if (parameter_displacement + params < params) {
- goto bad_param;
- }
+ pcnt = IVAL(inbuf,smb_nts_ParameterCount);
+ poff = IVAL(inbuf, smb_nts_ParameterOffset);
+ pdisp = IVAL(inbuf, smb_nts_ParameterDisplacement);
- memcpy( &params[parameter_displacement], smb_base(inbuf) + parameter_offset, parameter_count);
- }
+ dcnt = IVAL(inbuf, smb_nts_DataCount);
+ ddisp = IVAL(inbuf, smb_nts_DataDisplacement);
+ doff = IVAL(inbuf, smb_nts_DataOffset);
- if (data_count) {
- if (data_displacement + data_count > total_data_count) {
- goto bad_param;
- }
- if ((data_displacement + data_count < data_displacement) ||
- (data_displacement + data_count < data_count)) {
- goto bad_param;
- }
- if (data_displacement > total_data_count) {
- goto bad_param;
- }
- if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) ||
- (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) {
- goto bad_param;
- }
- if (data_displacement + data < data) {
- goto bad_param;
- }
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
- memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count);
- }
- }
- }
+ if (pcnt) {
+ if (pdisp+pcnt > state->total_param)
+ goto bad_param;
+ if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
+ goto bad_param;
+ if (pdisp > state->total_param)
+ goto bad_param;
+ if ((smb_base(inbuf) + poff + pcnt > inbuf + size) ||
+ (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->param + pdisp < state->param)
+ goto bad_param;
- if (Protocol >= PROTOCOL_NT1) {
- SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME);
+ memcpy(state->param+pdisp,smb_base(inbuf)+poff,
+ pcnt);
}
- /* Now we must call the relevant NT_TRANS function */
- switch(function_code) {
- case NT_TRANSACT_CREATE:
- START_PROFILE_NESTED(NT_transact_create);
- outsize = call_nt_transact_create(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_create);
- break;
- case NT_TRANSACT_IOCTL:
- START_PROFILE_NESTED(NT_transact_ioctl);
- outsize = call_nt_transact_ioctl(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_ioctl);
- break;
- case NT_TRANSACT_SET_SECURITY_DESC:
- START_PROFILE_NESTED(NT_transact_set_security_desc);
- outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_set_security_desc);
- break;
- case NT_TRANSACT_NOTIFY_CHANGE:
- START_PROFILE_NESTED(NT_transact_notify_change);
- outsize = call_nt_transact_notify_change(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_notify_change);
- break;
- case NT_TRANSACT_RENAME:
- START_PROFILE_NESTED(NT_transact_rename);
- outsize = call_nt_transact_rename(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_rename);
- break;
+ if (dcnt) {
+ if (ddisp+dcnt > state->total_data)
+ goto bad_param;
+ if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
+ goto bad_param;
+ if (ddisp > state->total_data)
+ goto bad_param;
+ if ((smb_base(inbuf) + doff + dcnt > inbuf + size) ||
+ (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->data + ddisp < state->data)
+ goto bad_param;
- case NT_TRANSACT_QUERY_SECURITY_DESC:
- START_PROFILE_NESTED(NT_transact_query_security_desc);
- outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_query_security_desc);
- break;
-#ifdef HAVE_SYS_QUOTAS
- case NT_TRANSACT_GET_USER_QUOTA:
- START_PROFILE_NESTED(NT_transact_get_user_quota);
- outsize = call_nt_transact_get_user_quota(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_get_user_quota);
- break;
- case NT_TRANSACT_SET_USER_QUOTA:
- START_PROFILE_NESTED(NT_transact_set_user_quota);
- outsize = call_nt_transact_set_user_quota(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_set_user_quota);
- break;
-#endif /* HAVE_SYS_QUOTAS */
- default:
- /* Error in request */
- DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
- SAFE_FREE(setup);
- SAFE_FREE(params);
- SAFE_FREE(data);
- END_PROFILE(SMBnttrans);
- srv_signing_trans_stop();
- return ERROR_DOS(ERRSRV,ERRerror);
+ memcpy(state->data+ddisp, smb_base(inbuf)+doff,
+ dcnt);
}
- /* As we do not know how many data packets will need to be
- returned here the various call_nt_transact_xxxx calls
- must send their own. Thus a call_nt_transact_xxxx routine only
- returns a value other than -1 when it wants to send
- an error packet.
- */
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBnttranss);
+ return -1;
+ }
- srv_signing_trans_stop();
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBnttranss which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBnttrans);
- SAFE_FREE(setup);
- SAFE_FREE(params);
- SAFE_FREE(data);
- END_PROFILE(SMBnttrans);
- return outsize; /* If a correct response was needed the call_nt_transact_xxxx
- calls have already sent it. If outsize != -1 then it is
- returning an error packet. */
+ outsize = handle_nttrans(conn, state, inbuf, outbuf,
+ size, bufsize);
- bad_param:
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
- srv_signing_trans_stop();
- SAFE_FREE(params);
- SAFE_FREE(data);
- SAFE_FREE(setup);
- END_PROFILE(SMBnttrans);
+ if (outsize == 0) {
+ END_PROFILE(SMBnttranss);
+ return(ERROR_DOS(ERRSRV,ERRnosupport));
+ }
+
+ END_PROFILE(SMBnttranss);
+ return(outsize);
+
+ bad_param:
+
+ DEBUG(0,("reply_nttranss: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttranss);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
diff --git a/source/smbd/process.c b/source/smbd/process.c
index 40d26f7672c..cdeccab5e81 100644
--- a/source/smbd/process.c
+++ b/source/smbd/process.c
@@ -505,22 +505,27 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
return receive_smb(smbd_server_fd(), buffer, 0);
}
-/****************************************************************************
-Get the next SMB packet, doing the local message processing automatically.
-****************************************************************************/
+/*
+ * Only allow 5 outstanding trans requests. We're allocating memory, so
+ * prevent a DoS.
+ */
-BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
+NTSTATUS allow_new_trans(struct trans_state *list, int mid)
{
- BOOL got_keepalive;
- BOOL ret;
+ int count = 0;
+ for (; list != NULL; list = list->next) {
- do {
- ret = receive_message_or_smb(inbuf,bufsize,timeout);
-
- got_keepalive = (ret && (CVAL(inbuf,0) == SMBkeepalive));
- } while (ret && got_keepalive);
+ if (list->mid == mid) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ count += 1;
+ }
+ if (count > 5) {
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
+ }
- return ret;
+ return NT_STATUS_OK;
}
/****************************************************************************
@@ -611,7 +616,7 @@ static const struct smb_message_struct {
/* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
/* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
-/* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
+/* 0x26 */ { "SMBtranss",reply_transs,AS_USER | CAN_IPC},
/* 0x27 */ { "SMBioctl",reply_ioctl,0},
/* 0x28 */ { "SMBioctls",NULL,AS_USER},
/* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index ce41266a1c8..040f7710fdd 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -269,10 +269,13 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *
switch(next_mb_char_size(s)) {
case 4:
*d++ = *s++;
+ /*fall through*/
case 3:
*d++ = *s++;
+ /*fall through*/
case 2:
*d++ = *s++;
+ /*fall through*/
case 1:
*d++ = *s++;
break;
@@ -374,10 +377,13 @@ NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
switch(next_mb_char_size(s)) {
case 4:
*d++ = *s++;
+ /*fall through*/
case 3:
*d++ = *s++;
+ /*fall through*/
case 2:
*d++ = *s++;
+ /*fall through*/
case 1:
*d++ = *s++;
break;
@@ -2319,7 +2325,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
/* ensure we don't overrun the packet size */
maxcount = MIN(65535,maxcount);
- if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+ if (!is_locked(fsp,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
SMB_STRUCT_STAT st;
SMB_OFF_T size = 0;
@@ -2390,8 +2396,13 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
* Note that the requested lock size is unaffected by max_recv.
*/
- status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid),
- (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ SVAL(inbuf,smb_pid),
+ (SMB_BIG_UINT)numtoread,
+ (SMB_BIG_UINT)startpos,
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
if (NT_STATUS_V(status)) {
#if 0
@@ -2407,8 +2418,15 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
* this smb into a queued request and push it
* onto the blocking lock queue.
*/
- if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)startpos,
- (SMB_BIG_UINT)numtoread)) {
+ if(push_blocking_lock_request(inbuf, length,
+ fsp,
+ -1,
+ 0,
+ SVAL(inbuf,smb_pid),
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ (SMB_BIG_UINT)startpos,
+ (SMB_BIG_UINT)numtoread)) {
END_PROFILE(SMBlockread);
return -1;
}
@@ -2486,7 +2504,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
data = smb_buf(outbuf) + 3;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK)) {
END_PROFILE(SMBread);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2694,7 +2712,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
}
- if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK)) {
END_PROFILE(SMBreadX);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2757,7 +2775,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
SCVAL(inbuf,smb_com,SMBwritec);
SCVAL(outbuf,smb_com,SMBwritec);
- if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwritebraw);
return(ERROR_DOS(ERRDOS,ERRlock));
}
@@ -2878,7 +2896,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (numtowrite && is_locked(fsp,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwriteunlock);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2900,8 +2918,12 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
}
if (numtowrite) {
- status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite,
- (SMB_BIG_UINT)startpos);
+ status = do_unlock(fsp,
+ SVAL(inbuf,smb_pid),
+ (SMB_BIG_UINT)numtowrite,
+ (SMB_BIG_UINT)startpos,
+ WINDOWS_LOCK);
+
if (NT_STATUS_V(status)) {
END_PROFILE(SMBwriteunlock);
return ERROR_NT(status);
@@ -2951,7 +2973,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwrite);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -3066,7 +3088,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
#endif /* LARGE_SMB_OFF_T */
}
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwriteX);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -3340,7 +3362,7 @@ int reply_writeclose(connection_struct *conn,
mtime = srv_make_unix_date3(inbuf+smb_vwv4);
data = smb_buf(inbuf) + 1;
- if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (numtowrite && is_locked(fsp,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwriteclose);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -3410,7 +3432,13 @@ int reply_lock(connection_struct *conn,
DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
- status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ SVAL(inbuf,smb_pid),
+ count,
+ offset,
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
if (NT_STATUS_V(status)) {
#if 0
/* Tests using Samba4 against W2K show this call never creates a blocking lock. */
@@ -3420,7 +3448,14 @@ int reply_lock(connection_struct *conn,
* this smb into a queued request and push it
* onto the blocking lock queue.
*/
- if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), offset, count)) {
+ if(push_blocking_lock_request(inbuf, length,
+ fsp,
+ -1,
+ 0,
+ SVAL(inbuf,smb_pid),
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ offset, count)) {
END_PROFILE(SMBlock);
return -1;
}
@@ -3452,7 +3487,12 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
- status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
+ status = do_unlock(fsp,
+ SVAL(inbuf,smb_pid),
+ count,
+ offset,
+ WINDOWS_LOCK);
+
if (NT_STATUS_V(status)) {
END_PROFILE(SMBunlock);
return ERROR_NT(status);
@@ -5279,7 +5319,12 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
"pid %u, file %s\n", (double)offset, (double)count,
(unsigned int)lock_pid, fsp->fsp_name ));
- status = do_unlock(fsp,conn,lock_pid,count,offset);
+ status = do_unlock(fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
+
if (NT_STATUS_V(status)) {
END_PROFILE(SMBlockingX);
return ERROR_NT(status);
@@ -5297,6 +5342,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
of smb_lkrng structs */
for(i = 0; i < (int)num_locks; i++) {
+ enum brl_type lock_type = ((locktype & 1) ? READ_LOCK:WRITE_LOCK);
lock_pid = get_lock_pid( data, i, large_file_format);
count = get_lock_count( data, i, large_file_format);
offset = get_lock_offset( data, i, large_file_format, &err);
@@ -5314,9 +5360,14 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
(double)count, (unsigned int)lock_pid,
fsp->fsp_name, (int)lock_timeout ));
- status = do_lock_spin(fsp,conn,lock_pid, count,offset,
- ((locktype & 1) ? READ_LOCK:WRITE_LOCK),
- &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ lock_pid,
+ count,
+ offset,
+ lock_type,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
+
if (NT_STATUS_V(status)) {
/*
* Interesting fact found by IFSTEST /t
@@ -5334,8 +5385,13 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
* onto the blocking lock queue.
*/
if(push_blocking_lock_request(inbuf, length,
- lock_timeout, i,
- lock_pid, offset,
+ fsp,
+ lock_timeout,
+ i,
+ lock_pid,
+ lock_type,
+ WINDOWS_LOCK,
+ offset,
count)) {
END_PROFILE(SMBlockingX);
return -1;
@@ -5368,7 +5424,11 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
- do_unlock(fsp,conn,lock_pid,count,offset);
+ do_unlock(fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
}
END_PROFILE(SMBlockingX);
return ERROR_NT(status);
@@ -5430,7 +5490,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
tcount = maxcount;
total_read = 0;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
END_PROFILE(SMBreadBmpx);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -5562,7 +5622,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
not an SMBwritebmpx - set this up now so we don't forget */
SCVAL(outbuf,smb_com,SMBwritec);
- if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK)) {
END_PROFILE(SMBwriteBmpx);
return(ERROR_DOS(ERRDOS,ERRlock));
}
diff --git a/source/smbd/server.c b/source/smbd/server.c
index ba31827eb3f..0880778f55f 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -898,9 +898,8 @@ void build_options(BOOL screen);
* If we're interactive we want to set our own process group for
* signal management.
*/
- if (interactive && !no_process_group) {
+ if (interactive && !no_process_group)
setpgid( (pid_t)0, (pid_t)0);
- }
#endif
if (!directory_exist(lp_lockdir(), NULL))
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 4f5039e86c3..19463403aca 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -563,7 +563,7 @@ static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *
HACK ! Always assumes smb_setup field is zero.
****************************************************************************/
-static int send_trans2_replies(char *outbuf,
+int send_trans2_replies(char *outbuf,
int bufsize,
char *params,
int paramsize,
@@ -1644,11 +1644,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
break;
case SMB_FIND_FILE_UNIX:
- if (!lp_unix_extensions())
- return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ if (!lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
break;
default:
- return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
srvstr_get_path_wcard(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, &mask_contains_wcard);
@@ -1926,11 +1927,12 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
break;
case SMB_FIND_FILE_UNIX:
- if (!lp_unix_extensions())
- return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ if (!lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
break;
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
if (info_level == SMB_FIND_EA_LIST) {
@@ -2398,13 +2400,21 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
*/
case SMB_QUERY_CIFS_UNIX_INFO:
- if (!lp_unix_extensions())
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (!lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
data_len = 12;
SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
- SBIG_UINT(pdata,4,((SMB_BIG_UINT)(CIFS_UNIX_POSIX_ACLS_CAP|
- CIFS_UNIX_POSIX_PATHNAMES_CAP))); /* We have POSIX ACLs and pathname capability. */
+ /* We have POSIX ACLs, pathname and locking capability. */
+ SBIG_UINT(pdata,4,((SMB_BIG_UINT)(
+ CIFS_UNIX_POSIX_ACLS_CAP|
+ CIFS_UNIX_POSIX_PATHNAMES_CAP|
+#if defined(DEVELOPER) /* Not quite finished yet... */
+ CIFS_UNIX_FCNTL_LOCKS_CAP)));
+#else
+ 0)));
+#endif
break;
case SMB_QUERY_POSIX_FS_INFO:
@@ -2412,9 +2422,10 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
int rc;
vfs_statvfs_struct svfs;
- if (!lp_unix_extensions())
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
-
+ if (!lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
+
rc = SMB_VFS_STATVFS(conn, ".", &svfs);
if (!rc) {
@@ -2430,7 +2441,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
#ifdef EOPNOTSUPP
} else if (rc == EOPNOTSUPP) {
- return ERROR_DOS(ERRDOS, ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
#endif /* EOPNOTSUPP */
} else {
DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
@@ -2451,7 +2462,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
}
/* drop through */
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
@@ -2495,7 +2506,7 @@ static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outb
uint32 client_unix_cap_high;
if (!lp_unix_extensions()) {
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
/* There should be 12 bytes of capabilities set. */
@@ -2515,8 +2526,15 @@ cap_low = 0x%x, cap_high = 0x%x\n",
(unsigned int)client_unix_cap_high ));
/* Here is where we must switch to posix pathname processing... */
- lp_set_posix_pathnames();
- mangle_change_to_posix();
+ if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+ lp_set_posix_pathnames();
+ mangle_change_to_posix();
+ }
+#if defined(DEVELOPER)
+ if (client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) {
+ lp_set_posix_cifsx_locktype(POSIX_LOCK);
+ }
+#endif
break;
}
case SMB_FS_QUOTA_INFORMATION:
@@ -2593,7 +2611,7 @@ cap_low = 0x%x, cap_high = 0x%x\n",
default:
DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
info_level));
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
break;
}
@@ -2768,13 +2786,14 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
char *fullpathname;
char *base_name;
char *p;
+ char *lock_data = NULL;
SMB_OFF_T pos = 0;
BOOL bad_path = False;
BOOL delete_pending = False;
int len;
time_t c_time;
files_struct *fsp = NULL;
- TALLOC_CTX *ea_ctx = NULL;
+ TALLOC_CTX *data_ctx = NULL;
struct ea_list *ea_list = NULL;
uint32 access_mask = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */
@@ -2893,8 +2912,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
nlink -= 1;
}
- if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n",
fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
@@ -2913,40 +2933,70 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
if (!(mode & aDIR))
file_size = get_file_size(sbuf);
- /* Pull any EA list from the data portion. */
- if (info_level == SMB_INFO_QUERY_EAS_FROM_LIST) {
- uint32 ea_size;
+ /* Pull out any data sent here before we realloc. */
+ switch (info_level) {
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ {
+ /* Pull any EA list from the data portion. */
+ uint32 ea_size;
- if (total_data < 4) {
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
- ea_size = IVAL(pdata,0);
+ if (total_data < 4) {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ ea_size = IVAL(pdata,0);
- if (total_data > 0 && ea_size != total_data) {
- DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
+ if (total_data > 0 && ea_size != total_data) {
+ DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
- if (!lp_ea_support(SNUM(conn))) {
- return ERROR_DOS(ERRDOS,ERReasnotsupported);
- }
+ if (!lp_ea_support(SNUM(conn))) {
+ return ERROR_DOS(ERRDOS,ERReasnotsupported);
+ }
- if ((ea_ctx = talloc_init("ea_list")) == NULL) {
- return ERROR_NT(NT_STATUS_NO_MEMORY);
+ if ((data_ctx = talloc_init("ea_list")) == NULL) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ /* Pull out the list of names. */
+ ea_list = read_ea_name_list(data_ctx, pdata + 4, ea_size - 4);
+ if (!ea_list) {
+ talloc_destroy(data_ctx);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ break;
}
+#if defined(DEVELOPER)
+ case SMB_QUERY_POSIX_LOCK:
+ {
+ if (fsp == NULL || fsp->fh->fd == -1) {
+ return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+ }
- /* Pull out the list of names. */
- ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4);
- if (!ea_list) {
- talloc_destroy(ea_ctx);
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ if (total_data != POSIX_LOCK_DATA_SIZE) {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if ((data_ctx = talloc_init("lock_request")) == NULL) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ /* Copy the lock range data. */
+ lock_data = talloc_memdup(data_ctx, pdata, total_data);
+ if (!lock_data) {
+ talloc_destroy(data_ctx);
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
}
+#endif
+ default:
+ break;
}
*pparams = SMB_REALLOC(*pparams,2);
if (*pparams == NULL) {
- talloc_destroy(ea_ctx);
+ talloc_destroy(data_ctx);
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
params = *pparams;
@@ -2954,7 +3004,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
*ppdata = SMB_REALLOC(*ppdata, data_size);
if (*ppdata == NULL ) {
- talloc_destroy(ea_ctx);
+ talloc_destroy(data_ctx);
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
pdata = *ppdata;
@@ -3040,18 +3090,18 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
- ea_file_list = get_ea_list_from_file(ea_ctx, conn, fsp, fname, &total_ea_len);
+ ea_file_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len);
ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
if (!ea_list || (total_ea_len > data_size)) {
- talloc_destroy(ea_ctx);
+ talloc_destroy(data_ctx);
data_size = 4;
SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
break;
}
- data_size = fill_ea_buffer(ea_ctx, pdata, data_size, conn, ea_list);
- talloc_destroy(ea_ctx);
+ data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list);
+ talloc_destroy(data_ctx);
break;
}
@@ -3062,21 +3112,21 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
- ea_ctx = talloc_init("ea_ctx");
- if (!ea_ctx) {
+ data_ctx = talloc_init("ea_ctx");
+ if (!data_ctx) {
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
- ea_list = get_ea_list_from_file(ea_ctx, conn, fsp, fname, &total_ea_len);
+ ea_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len);
if (!ea_list || (total_ea_len > data_size)) {
- talloc_destroy(ea_ctx);
+ talloc_destroy(data_ctx);
data_size = 4;
SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
break;
}
- data_size = fill_ea_buffer(ea_ctx, pdata, data_size, conn, ea_list);
- talloc_destroy(ea_ctx);
+ data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list);
+ talloc_destroy(data_ctx);
break;
}
@@ -3469,8 +3519,84 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
}
#endif
+
+#if defined(DEVELOPER)
+ case SMB_QUERY_POSIX_LOCK:
+ {
+ NTSTATUS status = NT_STATUS_INVALID_LEVEL;
+ SMB_BIG_UINT count;
+ SMB_BIG_UINT offset;
+ uint16 lock_pid;
+ enum brl_type lock_type;
+
+ if (total_data != POSIX_LOCK_DATA_SIZE) {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
+ case POSIX_LOCK_TYPE_READ:
+ lock_type = READ_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_WRITE:
+ lock_type = WRITE_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_UNLOCK:
+ default:
+ /* There's no point in asking for an unlock... */
+ talloc_destroy(data_ctx);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ lock_pid = (uint16)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
+#if defined(HAVE_LONGLONG)
+ offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
+ count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
+#else /* HAVE_LONGLONG */
+ offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
+ count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
+#endif /* HAVE_LONGLONG */
+
+ status = query_lock(fsp,
+ &lock_pid,
+ &count,
+ &offset,
+ &lock_type,
+ POSIX_LOCK);
+
+ if (ERROR_WAS_LOCK_DENIED(status)) {
+ /* Here we need to report who has it locked... */
+ data_size = POSIX_LOCK_DATA_SIZE;
+
+ SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
+ SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
+ SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid);
+#if defined(HAVE_LONGLONG)
+ SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
+ SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
+ SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
+ SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
+#else /* HAVE_LONGLONG */
+ SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
+ SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
+#endif /* HAVE_LONGLONG */
+
+ } else if (NT_STATUS_IS_OK(status)) {
+ /* For success we just return a copy of what we sent
+ with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
+ data_size = POSIX_LOCK_DATA_SIZE;
+ memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
+ SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
+ } else {
+ return ERROR_NT(status);
+ }
+ break;
+ }
+#endif
+
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size);
@@ -3674,8 +3800,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
if (!CAN_WRITE(conn))
return ERROR_DOS(ERRSRV,ERRaccess);
- if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
if (VALID_STAT(sbuf))
unixmode = sbuf.st_mode;
@@ -3843,8 +3970,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
#ifdef LARGE_SMB_OFF_T
allocation_size |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
#endif /* LARGE_SMB_OFF_T */
DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n",
fname, (double)allocation_size ));
@@ -3910,8 +4039,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
#ifdef LARGE_SMB_OFF_T
size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
#endif /* LARGE_SMB_OFF_T */
DEBUG(10,("call_trans2setfilepathinfo: Set end of file info for file %s to %.0f\n", fname, (double)size ));
break;
@@ -3964,8 +4095,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
#ifdef LARGE_SMB_OFF_T
position_information |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
#endif /* LARGE_SMB_OFF_T */
DEBUG(10,("call_trans2setfilepathinfo: Set file position information for file %s to %.0f\n",
fname, (double)position_information ));
@@ -4021,8 +4154,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
#ifdef LARGE_SMB_OFF_T
size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
#endif /* LARGE_SMB_OFF_T */
}
pdata+=24; /* ctime & st_blocks are not changed */
@@ -4329,8 +4464,109 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
}
#endif
+#if defined(DEVELOPER)
+ case SMB_SET_POSIX_LOCK:
+ {
+ SMB_BIG_UINT count;
+ SMB_BIG_UINT offset;
+ uint16 lock_pid;
+ BOOL lock_blocking;
+ enum brl_type lock_type;
+ BOOL my_lock_ctx;
+
+ if (fsp == NULL || fsp->fh->fd == -1) {
+ return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+ }
+
+ if (total_data != POSIX_LOCK_DATA_SIZE) {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
+ case POSIX_LOCK_TYPE_READ:
+ lock_type = READ_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_WRITE:
+ /* Return the right POSIX-mappable error code for files opened read-only. */
+ if (!fsp->can_write) {
+ return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+ }
+ lock_type = WRITE_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_UNLOCK:
+ lock_type = UNLOCK_LOCK;
+ break;
+ default:
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
+ lock_blocking = False;
+ } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
+ lock_blocking = True;
+ } else {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ lock_pid = (uint16)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
+#if defined(HAVE_LONGLONG)
+ offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
+ count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
+#else /* HAVE_LONGLONG */
+ offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
+ count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
+#endif /* HAVE_LONGLONG */
+
+ if (lock_type == UNLOCK_LOCK) {
+ status = do_unlock(fsp,
+ lock_pid,
+ count,
+ offset,
+ POSIX_LOCK);
+ } else {
+ status = do_lock(fsp,
+ lock_pid,
+ count,
+ offset,
+ lock_type,
+ POSIX_LOCK,
+ &my_lock_ctx);
+
+ /* TODO: Deal with rescheduling blocking lock fail here... */
+ if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if(push_blocking_lock_request(inbuf, length,
+ fsp,
+ -1, /* infinite timeout. */
+ 0,
+ lock_pid,
+ lock_type,
+ POSIX_LOCK,
+ offset,
+ count)) {
+ return -1;
+ }
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
+
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
+ }
+#endif
+
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
/* get some defaults (no modifications) if any info is zero or -1. */
@@ -4582,7 +4818,7 @@ static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char
case 2:
break;
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
/* Realloc the parameter and data sizes */
@@ -4759,331 +4995,418 @@ int reply_findnclose(connection_struct *conn,
return(outsize);
}
-/****************************************************************************
- Reply to a SMBtranss2 - just ignore it!
-****************************************************************************/
-
-int reply_transs2(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
-{
- START_PROFILE(SMBtranss2);
- DEBUG(4,("Ignoring transs2 of length %d\n",length));
- END_PROFILE(SMBtranss2);
- return(-1);
-}
-
-/****************************************************************************
- Reply to a SMBtrans2.
-****************************************************************************/
-
-int reply_trans2(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+int handle_trans2(connection_struct *conn,
+ struct trans_state *state,
+ char *inbuf, char *outbuf, int size, int bufsize)
{
- int outsize = 0;
- unsigned int total_params = SVAL(inbuf, smb_tpscnt);
- unsigned int total_data =SVAL(inbuf, smb_tdscnt);
- unsigned int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
-#if 0
- unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
- unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
- BOOL close_tid = BITSETW(inbuf+smb_flags,0);
- BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
- int32 timeout = IVALS(inbuf,smb_timeout);
-#endif
- unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
- unsigned int tran_call = SVAL(inbuf, smb_setup0);
- char *params = NULL, *data = NULL;
- unsigned int num_params, num_params_sofar, num_data, num_data_sofar;
- START_PROFILE(SMBtrans2);
-
- if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
- && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
- END_PROFILE(SMBtrans2);
- return ERROR_DOS(ERRSRV,ERRaccess);
- }
-
- outsize = set_message(outbuf,0,0,True);
-
- /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
- is so as a sanity check */
- if (suwcnt != 1) {
- /*
- * Need to have rc=0 for ioctl to get job id for OS/2.
- * Network printing will fail if function is not successful.
- * Similar function in reply.c will be used if protocol
- * is LANMAN1.0 instead of LM1.2X002.
- * Until DosPrintSetJobInfo with PRJINFO3 is supported,
- * outbuf doesn't have to be set(only job id is used).
- */
- if ( (suwcnt == 4) && (tran_call == TRANSACT2_IOCTL) &&
- (SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
- (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
- DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
- } else {
- DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",suwcnt));
- DEBUG(2,("Transaction is %d\n",tran_call));
- END_PROFILE(SMBtrans2);
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
- }
-
- /* Allocate the space for the maximum needed parameters and data */
- if (total_params > 0)
- params = (char *)SMB_MALLOC(total_params);
- if (total_data > 0)
- data = (char *)SMB_MALLOC(total_data);
-
- if ((total_params && !params) || (total_data && !data)) {
- DEBUG(2,("Out of memory in reply_trans2\n"));
- SAFE_FREE(params);
- SAFE_FREE(data);
- END_PROFILE(SMBtrans2);
- return ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
- /* Copy the param and data bytes sent with this request into
- the params buffer */
- num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
- num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
-
- if (num_params > total_params || num_data > total_data)
- exit_server("invalid params in reply_trans2");
-
- if(params) {
- unsigned int psoff = SVAL(inbuf, smb_psoff);
- if ((psoff + num_params < psoff) || (psoff + num_params < num_params))
- goto bad_param;
- if ((smb_base(inbuf) + psoff + num_params > inbuf + length) ||
- (smb_base(inbuf) + psoff + num_params < smb_base(inbuf)))
- goto bad_param;
- memcpy( params, smb_base(inbuf) + psoff, num_params);
- }
- if(data) {
- unsigned int dsoff = SVAL(inbuf, smb_dsoff);
- if ((dsoff + num_data < dsoff) || (dsoff + num_data < num_data))
- goto bad_param;
- if ((smb_base(inbuf) + dsoff + num_data > inbuf + length) ||
- (smb_base(inbuf) + dsoff + num_data < smb_base(inbuf)))
- goto bad_param;
- memcpy( data, smb_base(inbuf) + dsoff, num_data);
- }
-
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
-
- if(num_data_sofar < total_data || num_params_sofar < total_params) {
- /* We need to send an interim response then receive the rest
- of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
- srv_signing_trans_stop();
- show_msg(outbuf);
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_trans2: send_smb failed.");
-
- while (num_data_sofar < total_data ||
- num_params_sofar < total_params) {
- BOOL ret;
- unsigned int param_disp;
- unsigned int param_off;
- unsigned int data_disp;
- unsigned int data_off;
-
- ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
-
- /* We need to re-calcuate the new length after we've read the secondary packet. */
- length = smb_len(inbuf) + 4;
-
- /*
- * The sequence number for the trans reply is always
- * based on the last secondary received.
- */
+ int outsize;
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
-
- if ((ret &&
- (CVAL(inbuf, smb_com) != SMBtranss2)) || !ret) {
- outsize = set_message(outbuf,0,0,True);
- if(ret)
- DEBUG(0,("reply_trans2: Invalid secondary trans2 packet\n"));
- else
- DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n",
- (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
- goto bad_param;
- }
-
- /* Revise total_params and total_data in case
- they have changed downwards */
- if (SVAL(inbuf, smb_tpscnt) < total_params)
- total_params = SVAL(inbuf, smb_tpscnt);
- if (SVAL(inbuf, smb_tdscnt) < total_data)
- total_data = SVAL(inbuf, smb_tdscnt);
-
- num_params = SVAL(inbuf,smb_spscnt);
- param_off = SVAL(inbuf, smb_spsoff);
- param_disp = SVAL(inbuf, smb_spsdisp);
- num_params_sofar += num_params;
-
- num_data = SVAL(inbuf, smb_sdscnt);
- data_off = SVAL(inbuf, smb_sdsoff);
- data_disp = SVAL(inbuf, smb_sdsdisp);
- num_data_sofar += num_data;
-
- if (num_params_sofar > total_params || num_data_sofar > total_data)
- goto bad_param;
-
- if (num_params) {
- if (param_disp + num_params > total_params)
- goto bad_param;
- if ((param_disp + num_params < param_disp) ||
- (param_disp + num_params < num_params))
- goto bad_param;
- if (param_disp > total_params)
- goto bad_param;
- if ((smb_base(inbuf) + param_off + num_params > inbuf + length) ||
- (smb_base(inbuf) + param_off + num_params < smb_base(inbuf)))
- goto bad_param;
- if (params + param_disp < params)
- goto bad_param;
-
- memcpy( &params[param_disp], smb_base(inbuf) + param_off, num_params);
- }
- if (num_data) {
- if (data_disp + num_data > total_data)
- goto bad_param;
- if ((data_disp + num_data < data_disp) ||
- (data_disp + num_data < num_data))
- goto bad_param;
- if (data_disp > total_data)
- goto bad_param;
- if ((smb_base(inbuf) + data_off + num_data > inbuf + length) ||
- (smb_base(inbuf) + data_off + num_data < smb_base(inbuf)))
- goto bad_param;
- if (data + data_disp < data)
- goto bad_param;
-
- memcpy( &data[data_disp], smb_base(inbuf) + data_off, num_data);
- }
- }
- }
-
if (Protocol >= PROTOCOL_NT1) {
SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
}
/* Now we must call the relevant TRANS2 function */
- switch(tran_call) {
+ switch(state->call) {
case TRANSACT2_OPEN:
START_PROFILE_NESTED(Trans2_open);
- outsize = call_trans2open(conn, inbuf, outbuf, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2open(
+ conn, inbuf, outbuf, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_open);
break;
case TRANSACT2_FINDFIRST:
START_PROFILE_NESTED(Trans2_findfirst);
- outsize = call_trans2findfirst(conn, inbuf, outbuf, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2findfirst(
+ conn, inbuf, outbuf, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_findfirst);
break;
case TRANSACT2_FINDNEXT:
START_PROFILE_NESTED(Trans2_findnext);
- outsize = call_trans2findnext(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2findnext(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_findnext);
break;
case TRANSACT2_QFSINFO:
START_PROFILE_NESTED(Trans2_qfsinfo);
- outsize = call_trans2qfsinfo(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2qfsinfo(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_qfsinfo);
break;
case TRANSACT2_SETFSINFO:
START_PROFILE_NESTED(Trans2_setfsinfo);
- outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2setfsinfo(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_setfsinfo);
break;
case TRANSACT2_QPATHINFO:
case TRANSACT2_QFILEINFO:
START_PROFILE_NESTED(Trans2_qpathinfo);
- outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, tran_call,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2qfilepathinfo(
+ conn, inbuf, outbuf, size, bufsize, state->call,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_qpathinfo);
break;
case TRANSACT2_SETPATHINFO:
case TRANSACT2_SETFILEINFO:
START_PROFILE_NESTED(Trans2_setpathinfo);
- outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize, tran_call,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2setfilepathinfo(
+ conn, inbuf, outbuf, size, bufsize, state->call,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_setpathinfo);
break;
case TRANSACT2_FINDNOTIFYFIRST:
START_PROFILE_NESTED(Trans2_findnotifyfirst);
- outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2findnotifyfirst(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_findnotifyfirst);
break;
case TRANSACT2_FINDNOTIFYNEXT:
START_PROFILE_NESTED(Trans2_findnotifynext);
- outsize = call_trans2findnotifynext(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2findnotifynext(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_findnotifynext);
break;
case TRANSACT2_MKDIR:
START_PROFILE_NESTED(Trans2_mkdir);
- outsize = call_trans2mkdir(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2mkdir(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_mkdir);
break;
case TRANSACT2_GET_DFS_REFERRAL:
START_PROFILE_NESTED(Trans2_get_dfs_referral);
- outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2getdfsreferral(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_get_dfs_referral);
break;
case TRANSACT2_IOCTL:
START_PROFILE_NESTED(Trans2_ioctl);
- outsize = call_trans2ioctl(conn,inbuf,outbuf,length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2ioctl(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_ioctl);
break;
default:
/* Error in request */
- DEBUG(2,("Unknown request %d in trans2 call\n", tran_call));
- SAFE_FREE(params);
- SAFE_FREE(data);
+ DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
+ outsize = ERROR_DOS(ERRSRV,ERRerror);
+ }
+ return outsize;
+}
+
+/****************************************************************************
+ Reply to a SMBtrans2.
+ ****************************************************************************/
+
+int reply_trans2(connection_struct *conn, char *inbuf,char *outbuf,
+ int size, int bufsize)
+{
+ int outsize = 0;
+ unsigned int dsoff = SVAL(inbuf, smb_dsoff);
+ unsigned int dscnt = SVAL(inbuf, smb_dscnt);
+ unsigned int psoff = SVAL(inbuf, smb_psoff);
+ unsigned int pscnt = SVAL(inbuf, smb_pscnt);
+ unsigned int tran_call = SVAL(inbuf, smb_setup0);
+ struct trans_state *state;
+ NTSTATUS result;
+
+ START_PROFILE(SMBtrans2);
+
+ if (!NT_STATUS_IS_OK(allow_new_trans(conn->pending_trans,
+ SVAL(inbuf, smb_mid)))) {
+ DEBUG(2, ("Got invalid trans2 request: %s\n",
+ nt_errstr(result)));
END_PROFILE(SMBtrans2);
- srv_signing_trans_stop();
- return ERROR_DOS(ERRSRV,ERRerror);
+ return ERROR_NT(result);
}
-
- /* As we do not know how many data packets will need to be
- returned here the various call_trans2xxxx calls
- must send their own. Thus a call_trans2xxx routine only
- returns a value other than -1 when it wants to send
- an error packet.
- */
-
- srv_signing_trans_stop();
- SAFE_FREE(params);
- SAFE_FREE(data);
+ if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
+ && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
+ END_PROFILE(SMBtrans2);
+ return ERROR_DOS(ERRSRV,ERRaccess);
+ }
+
+ if ((state = TALLOC_P(NULL, struct trans_state)) == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ END_PROFILE(SMBtrans2);
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ state->cmd = SMBtrans2;
+
+ state->mid = SVAL(inbuf, smb_mid);
+ state->vuid = SVAL(inbuf, smb_uid);
+ state->setup_count = SVAL(inbuf, smb_suwcnt);
+ state->total_param = SVAL(inbuf, smb_tpscnt);
+ state->param = NULL;
+ state->total_data = SVAL(inbuf, smb_tdscnt);
+ state->data = NULL;
+ state->max_param_return = SVAL(inbuf, smb_mprcnt);
+ state->max_data_return = SVAL(inbuf, smb_mdrcnt);
+ state->max_setup_return = SVAL(inbuf, smb_msrcnt);
+ state->close_on_completion = BITSETW(inbuf+smb_vwv5,0);
+ state->one_way = BITSETW(inbuf+smb_vwv5,1);
+
+ state->call = tran_call;
+
+ /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
+ is so as a sanity check */
+ if (state->setup_count != 1) {
+ /*
+ * Need to have rc=0 for ioctl to get job id for OS/2.
+ * Network printing will fail if function is not successful.
+ * Similar function in reply.c will be used if protocol
+ * is LANMAN1.0 instead of LM1.2X002.
+ * Until DosPrintSetJobInfo with PRJINFO3 is supported,
+ * outbuf doesn't have to be set(only job id is used).
+ */
+ if ( (state->setup_count == 4) && (tran_call == TRANSACT2_IOCTL) &&
+ (SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
+ (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+ DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
+ } else {
+ DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
+ DEBUG(2,("Transaction is %d\n",tran_call));
+ END_PROFILE(SMBtrans2);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ }
+
+ if ((dscnt > state->total_data) || (pscnt > state->total_param))
+ goto bad_param;
+
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->data = SMB_MALLOC(state->total_data);
+ if (state->data == NULL) {
+ DEBUG(0,("reply_trans2: data malloc fail for %u "
+ "bytes !\n", state->total_data));
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans2);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
+ goto bad_param;
+ if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
+ (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
+ goto bad_param;
+
+ memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
+ }
+
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->param = SMB_MALLOC(state->total_param);
+ if (state->param == NULL) {
+ DEBUG(0,("reply_trans: param malloc fail for %u "
+ "bytes !\n", state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
+ goto bad_param;
+ if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
+ (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
+ goto bad_param;
+
+ memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
+ }
+
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if ((state->received_param == state->total_param) &&
+ (state->received_data == state->total_data)) {
+
+ outsize = handle_trans2(conn, state, inbuf, outbuf,
+ size, bufsize);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return outsize;
+ }
+
+ DLIST_ADD(conn->pending_trans, state);
+
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,True);
+ show_msg(outbuf);
END_PROFILE(SMBtrans2);
- return outsize; /* If a correct response was needed the
- call_trans2xxx calls have already sent
- it. If outsize != -1 then it is returning */
+ return outsize;
bad_param:
- srv_signing_trans_stop();
- SAFE_FREE(params);
- SAFE_FREE(data);
+ DEBUG(0,("reply_trans2: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
END_PROFILE(SMBtrans2);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
+
+
+/****************************************************************************
+ Reply to a SMBtranss2
+ ****************************************************************************/
+
+int reply_transs2(connection_struct *conn,
+ char *inbuf,char *outbuf,int size,int bufsize)
+{
+ int outsize = 0;
+ unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
+
+ START_PROFILE(SMBtranss2);
+
+ show_msg(inbuf);
+
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == SVAL(inbuf,smb_mid)) {
+ break;
+ }
+ }
+
+ if ((state == NULL) || (state->cmd != SMBtrans2)) {
+ END_PROFILE(SMBtranss2);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ /* Revise state->total_param and state->total_data in case they have
+ changed downwards */
+
+ if (SVAL(inbuf, smb_tpscnt) < state->total_param)
+ state->total_param = SVAL(inbuf, smb_tpscnt);
+ if (SVAL(inbuf, smb_tdscnt) < state->total_data)
+ state->total_data = SVAL(inbuf, smb_tdscnt);
+
+ pcnt = SVAL(inbuf, smb_spscnt);
+ poff = SVAL(inbuf, smb_spsoff);
+ pdisp = SVAL(inbuf, smb_spsdisp);
+
+ dcnt = SVAL(inbuf, smb_sdscnt);
+ doff = SVAL(inbuf, smb_sdsoff);
+ ddisp = SVAL(inbuf, smb_sdsdisp);
+
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
+
+ if (pcnt) {
+ if (pdisp+pcnt > state->total_param)
+ goto bad_param;
+ if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
+ goto bad_param;
+ if (pdisp > state->total_param)
+ goto bad_param;
+ if ((smb_base(inbuf) + poff + pcnt > inbuf + size) ||
+ (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->param + pdisp < state->param)
+ goto bad_param;
+
+ memcpy(state->param+pdisp,smb_base(inbuf)+poff,
+ pcnt);
+ }
+
+ if (dcnt) {
+ if (ddisp+dcnt > state->total_data)
+ goto bad_param;
+ if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
+ goto bad_param;
+ if (ddisp > state->total_data)
+ goto bad_param;
+ if ((smb_base(inbuf) + doff + dcnt > inbuf + size) ||
+ (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->data + ddisp < state->data)
+ goto bad_param;
+
+ memcpy(state->data+ddisp, smb_base(inbuf)+doff,
+ dcnt);
+ }
+
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBtranss);
+ return -1;
+ }
+
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBtranss2 which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBtrans2);
+
+ outsize = handle_trans2(conn, state, inbuf, outbuf, size, bufsize);
+
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+
+ if (outsize == 0) {
+ END_PROFILE(SMBtranss);
+ return(ERROR_DOS(ERRSRV,ERRnosupport));
+ }
+
+ END_PROFILE(SMBtranss2);
+ return(outsize);
+
+ bad_param:
+
+ DEBUG(0,("reply_transs2: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtranss2);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+}
diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c
index bbb7b5bb308..55bf146c20f 100644
--- a/source/smbd/vfs-wrap.c
+++ b/source/smbd/vfs-wrap.c
@@ -759,11 +759,21 @@ BOOL vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, int op,
BOOL result;
START_PROFILE(syscall_fcntl_lock);
- result = fcntl_lock(fd, op, offset, count,type);
+ result = fcntl_lock(fd, op, offset, count, type);
END_PROFILE(syscall_fcntl_lock);
return result;
}
+BOOL vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+ BOOL result;
+
+ START_PROFILE(syscall_fcntl_getlock);
+ result = fcntl_getlock(fd, poffset, pcount, ptype, ppid);
+ END_PROFILE(syscall_fcntl_getlock);
+ return result;
+}
+
int vfswrap_symlink(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath)
{
int result;
diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c
index 07e18caa5c6..9a6327b33b5 100644
--- a/source/smbd/vfs.c
+++ b/source/smbd/vfs.c
@@ -95,6 +95,7 @@ static struct vfs_ops default_vfs = {
vfswrap_utime,
vfswrap_ftruncate,
vfswrap_lock,
+ vfswrap_getlock,
vfswrap_symlink,
vfswrap_readlink,
vfswrap_link,
diff --git a/source/tests/os2_delete.c b/source/tests/os2_delete.c
index 831fa367eb4..b3aaf67f418 100644
--- a/source/tests/os2_delete.c
+++ b/source/tests/os2_delete.c
@@ -105,3 +105,110 @@ int main(void)
return 0;
}
+/*
+ test readdir/unlink pattern that OS/2 uses
+ tridge@samba.org July 2005
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#define NUM_FILES 700
+#define READDIR_SIZE 100
+#define DELETE_SIZE 4
+
+#define TESTDIR "test.dir"
+
+#define FAILED(d) (fprintf(stderr, "Failed for %s - %s\n", d, strerror(errno)), exit(1), 1)
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+static void cleanup(void)
+{
+ /* I'm a lazy bastard */
+ system("rm -rf " TESTDIR);
+ mkdir(TESTDIR, 0700) == 0 || FAILED("mkdir");
+}
+
+static void create_files()
+{
+ int i;
+ for (i=0;i<NUM_FILES;i++) {
+ char fname[40];
+ sprintf(fname, TESTDIR "/test%u.txt", i);
+ close(open(fname, O_CREAT|O_RDWR, 0600)) == 0 || FAILED("close");
+ }
+}
+
+static int os2_delete(DIR *d)
+{
+ off_t offsets[READDIR_SIZE];
+ int i, j;
+ struct dirent *de;
+ char names[READDIR_SIZE][30];
+
+ /* scan, remembering offsets */
+ for (i=0, de=readdir(d);
+ de && i < READDIR_SIZE;
+ de=readdir(d), i++) {
+ offsets[i] = telldir(d);
+ strcpy(names[i], de->d_name);
+ }
+
+ if (i == 0) {
+ return 0;
+ }
+
+ /* delete the first few */
+ for (j=0; j<MIN(i, DELETE_SIZE); j++) {
+ char fname[40];
+ sprintf(fname, TESTDIR "/%s", names[j]);
+ unlink(fname) == 0 || FAILED("unlink");
+ }
+
+ /* seek to just after the deletion */
+ seekdir(d, offsets[j-1]);
+
+ /* return number deleted */
+ return j;
+}
+
+int main(void)
+{
+ int total_deleted = 0;
+ DIR *d;
+ struct dirent *de;
+
+ cleanup();
+ create_files();
+
+ d = opendir(TESTDIR);
+
+ /* skip past . and .. */
+ de = readdir(d);
+ strcmp(de->d_name, ".") == 0 || FAILED("match .");
+ de = readdir(d);
+ strcmp(de->d_name, "..") == 0 || FAILED("match ..");
+
+ while (1) {
+ int n = os2_delete(d);
+ if (n == 0) break;
+ total_deleted += n;
+ }
+ closedir(d);
+
+ printf("Deleted %d files of %d\n", total_deleted, NUM_FILES);
+
+ rmdir(TESTDIR) == 0 || FAILED("rmdir");
+
+ return 0;
+}
diff --git a/source/utils/net_sam.c b/source/utils/net_sam.c
index fc7dfea02c5..945afb3a210 100644
--- a/source/utils/net_sam.c
+++ b/source/utils/net_sam.c
@@ -1203,6 +1203,7 @@ failed:
talloc_free(tc);
return -1;
}
+
#endif
/***********************************************************
diff --git a/source/utils/status.c b/source/utils/status.c
index c334fe6982d..bc26be1ec93 100644
--- a/source/utils/status.c
+++ b/source/utils/status.c
@@ -159,9 +159,13 @@ static void print_share_mode(const struct share_mode_entry *e, const char *share
}
}
-static void print_brl(SMB_DEV_T dev, SMB_INO_T ino, struct process_id pid,
- enum brl_type lock_type,
- br_off start, br_off size)
+static void print_brl(SMB_DEV_T dev,
+ SMB_INO_T ino,
+ struct process_id pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ br_off start,
+ br_off size)
{
static int count;
if (count==0) {