r15018: Merge Volker's ipc/trans2/nttrans changes over
authorJeremy Allison <jra@samba.org>
Mon, 10 Apr 2006 15:33:04 +0000 (15:33 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:15:57 +0000 (11:15 -0500)
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.

30 files changed:
examples/VFS/Makefile.in
examples/VFS/skel_opaque.c
examples/VFS/skel_transparent.c
source/include/smb.h
source/include/smbprofile.h
source/include/trans2.h
source/include/vfs.h
source/include/vfs_macros.h
source/lib/util.c
source/libsmb/clifile.c
source/libsmb/clitrans.c
source/libsmb/errormap.c
source/libsmb/smb_signing.c
source/locking/brlock.c
source/locking/locking.c
source/locking/posix.c
source/modules/vfs_full_audit.c
source/param/loadparm.c
source/smbd/blocking.c
source/smbd/ipc.c
source/smbd/nttrans.c
source/smbd/process.c
source/smbd/reply.c
source/smbd/server.c
source/smbd/trans2.c
source/smbd/vfs-wrap.c
source/smbd/vfs.c
source/tests/os2_delete.c
source/utils/net_sam.c
source/utils/status.c

index 79873c385769335408c375daeada074f7f79d425..caf8f030aa48163bc132df0fe84d6f01b2fc54a4 100644 (file)
@@ -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@
index e6af475da6ec36fb1120b73e20787f6926ca7178..a02bf3c146b1ad06d41ee62cbfb94385c3003971 100644 (file)
@@ -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},
index 14fa2276e1fa7c050450b5ba721e94f65f8b83c6..5996b2980602411a4f191b9ec615b36e7ca12f6c 100644 (file)
@@ -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},
index 8faf3877ce990e30fb8159bb9a96e72a93fe3ab7..9531ae2903c1035a09d2e129cb103a02bd601b14 100644 (file)
@@ -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 {
index ed6fce9a6d6c76c6a550a08c9d8cbbd0116adaa3..f68a1e240f2faefa7988cae58368a92a4818b9b1 100644 (file)
@@ -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;
index 1d5dfe3678eb1c2432ad5136d1572c68d3504665..92c5a2e963f9387bf32cfcc17ac305ff08149f6b 100644 (file)
@@ -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
index cde2039d1a1bdff893f9749b3782f099a3f5a0ed..fb99d8241253797f5734ee05401043baaf79dceb 100644 (file)
 /* 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;
index 33810c301f9494e206d98031bca5e8dd49e69b49..e08b386a6ac7014788fd72b0a699e49253906000 100644 (file)
@@ -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)))
 #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)))
 #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)))
index bfc5eb2a8da92ffb0847a584f8e0f749f67d58ba..87f15b8759d0eabefecf1fe6a68fed2e23c3d257 100644 (file)
@@ -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
index 443f51566534177c52bb8f9391054d525f2df351..80deb3a3320b1211c06195d783c12c6b8cdf1746 100644 (file)
@@ -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.
index 8296f7e94c17e54f39855f9e4b57b04d21ca4ac6..082da67bb8b774b9a6f0c3190c94466599d4144d 100644 (file)
@@ -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);
 }
index f6b5af068a54a20d62cadf32fbd2dc066ae15040..b3caa0a80ce416c9fdeb2ab2b724104964149029 100644 (file)
@@ -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},
index 52e4b1d04c5be9e88625bfef8da1b1ccb799284d..4ff74ca464c4fc03d4fc9270f415c379743cbebb 100644 (file)
@@ -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;
@@ -502,65 +469,6 @@ BOOL cli_simple_set_signing(struct cli_state *cli,
        return True;
 }
 
-/***********************************************************
- 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. 
 ************************************************************/
index 5078515b3e9b1244446681faad29e387ad982762..b95bb895cc3bc18723dd7308210fa30fff00f2b8 100644 (file)
@@ -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. */
@@ -65,6 +66,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;
+}
index 0ecc90c794c8bc5a6426d852f916938873beb4d6..0b3f625d03e98c1cedf5cd0216bce4dd41c3bcf6 100644 (file)
@@ -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);
 
        }
index 07246474f3f5dcd8006bd84c3ee3315f88728e1d..e7075c57a64a933528e7258b206c20750e3ee6f7 100644 (file)
@@ -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;
index 0ae48f48186f4cdacca7972fe64683631125c671..309f6d15ae72fc7dcface5fec665c893933199de 100644 (file)
@@ -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)
 {
index e0c6c0686f1389342e4540342976be61a931dfa6..af4293a11e8243963c1ef4dd24242b7c31f2d1c4 100644 (file)
@@ -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;
+}
index 805e45f6ea33f2d870e3905d88dd615b297eb882..6b47d0466bd8dd0fec84036e74ae56a8c9133c27 100644 (file)
@@ -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;
@@ -52,25 +54,6 @@ static void free_blocking_lock_record(blocking_lock_record *blr)
        SAFE_FREE(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) {
@@ -490,6 +542,51 @@ Waiting....\n",
        return False;
 }
 
+/****************************************************************************
+ 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);
                }
index 427b6ae2144e1ee1b0857b2a67475f66d9b6c2dd..1b5a5f39c72b82ee700eeab6c925e1a8c9f817b0 100644 (file)
@@ -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);
 }
index 796eb44332631273c43ca13fb3d3369fbadc416f..24d64ecfc76e9db6c3109deef2a4486cddb91954 100644 (file)
@@ -1811,19 +1811,6 @@ int reply_ntrename(connection_struct *conn,
        return(outsize);
 }
 
-/****************************************************************************
- 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);
 }
index 40d26f7672c20a4e07589ebd883d294e6e19562d..cdeccab5e81a48d7442e1aec061763a5f1cc292f 100644 (file)
@@ -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 },
index ce41266a1c83d54f9b0a1f245cde5eef625f14e5..040f7710fddc490e82a66c7770b9eed64a809613 100644 (file)
@@ -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));
        }
index ba31827eb3fd2da411a3120cf33895fe8cbadfe3..0880778f55f99804cefddb5719e5e1df08ab7dab 100644 (file)
@@ -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))
index 4f5039e86c332e0f97e00929342cbd4ae951d705..19463403aca98b090647e372df0cccbf7849317d 100644 (file)
@@ -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);
+}
index bbb7b5bb3086681636a8fe877a326439210f7fb0..55bf146c20fe1b21191e9887190d60cc10096b95 100644 (file)
@@ -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;
index 07e18caa5c648c406fadd7216386da170ed938e2..9a6327b33b5321a85f2c919d11bb4f975fec5496 100644 (file)
@@ -95,6 +95,7 @@ static struct vfs_ops default_vfs = {
                vfswrap_utime,
                vfswrap_ftruncate,
                vfswrap_lock,
+               vfswrap_getlock,
                vfswrap_symlink,
                vfswrap_readlink,
                vfswrap_link,
index 831fa367eb41c81810490ab6c451c1331dc2eb4b..b3aaf67f4186d170598d8a2c0f40386fa1eac8e5 100644 (file)
@@ -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;
+}
index fc7dfea02c56b4feb4bdaafe6b64b2eee65d77f1..945afb3a21016cb6e7793c285bb38ae1b0d6ec49 100644 (file)
@@ -1203,6 +1203,7 @@ failed:
        talloc_free(tc);
        return -1;
 }
+
 #endif
 
 /***********************************************************
index c334fe6982dbb9668125f82cc1b1cd7397519f5c..bc26be1ec937735e4e1ae7e812e74f2e5f766751 100644 (file)
@@ -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) {