1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

r15018: Merge Volker's ipc/trans2/nttrans changes over

into 3.0. Also merge the new POSIX lock code - this
is not enabled unless -DDEVELOPER is defined.
This doesn't yet map onto underlying system POSIX
locks. Updates vfs to allow lock queries.
Jeremy.
This commit is contained in:
Jeremy Allison 2006-04-10 15:33:04 +00:00 committed by Gerald (Jerry) Carter
parent b1bbe56831
commit 08e52ead03
30 changed files with 3310 additions and 1719 deletions

View 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@

View 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},

View 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},

View 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 {

View 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;

View 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

View File

@ -59,9 +59,10 @@
/* Changed to version 12 to add mask and attributes to opendir(). JRA
Also include aio calls. JRA. */
/* Changed to version 13 as the internal structure of files_struct has changed. JRA */
/* Changed to version 14 as the we had to change DIR to SMB_STRUCT_DIR. JRA */
/* Changed to version 15 as the we added the statvfs call. JRA */
#define SMB_VFS_INTERFACE_VERSION 15
/* Changed to version 14 as we had to change DIR to SMB_STRUCT_DIR. JRA */
/* Changed to version 15 as we added the statvfs call. JRA */
/* Changed to version 16 as we added the getlock call. JRA */
#define SMB_VFS_INTERFACE_VERSION 16
/* to bug old modules which are trying to compile with the old functions */
@ -141,6 +142,7 @@ typedef enum _vfs_op_type {
SMB_VFS_OP_UTIME,
SMB_VFS_OP_FTRUNCATE,
SMB_VFS_OP_LOCK,
SMB_VFS_OP_GETLOCK,
SMB_VFS_OP_SYMLINK,
SMB_VFS_OP_READLINK,
SMB_VFS_OP_LINK,
@ -262,6 +264,7 @@ struct vfs_ops {
int (*utime)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, struct utimbuf *times);
int (*ftruncate)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_OFF_T offset);
BOOL (*lock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
BOOL (*getlock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid);
int (*symlink)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *oldpath, const char *newpath);
int (*readlink)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, char *buf, size_t bufsiz);
int (*link)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *oldpath, const char *newpath);
@ -375,6 +378,7 @@ struct vfs_ops {
struct vfs_handle_struct *utime;
struct vfs_handle_struct *ftruncate;
struct vfs_handle_struct *lock;
struct vfs_handle_struct *getlock;
struct vfs_handle_struct *symlink;
struct vfs_handle_struct *readlink;
struct vfs_handle_struct *link;

View 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)))
@ -181,6 +182,7 @@
#define SMB_VFS_OPAQUE_UTIME(conn, path, times) ((conn)->vfs_opaque.ops.utime((conn)->vfs_opaque.handles.utime, (conn), (path), (times)))
#define SMB_VFS_OPAQUE_FTRUNCATE(fsp, fd, offset) ((fsp)->conn->vfs_opaque.ops.ftruncate((fsp)->conn->vfs_opaque.handles.ftruncate, (fsp), (fd), (offset)))
#define SMB_VFS_OPAQUE_LOCK(fsp, fd, op, offset, count, type) ((fsp)->conn->vfs_opaque.ops.lock((fsp)->conn->vfs_opaque.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type)))
#define SMB_VFS_OPAQUE_GETLOCK(fsp, fd, poffset, pcount, ptype, ppid) ((fsp)->conn->vfs_opaque.ops.getlock((fsp)->conn->vfs_opaque.handles.getlock, (fsp), (fd), (poffset), (pcount), (ptype), (ppid)))
#define SMB_VFS_OPAQUE_SYMLINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.symlink((conn)->vfs_opaque.handles.symlink, (conn), (oldpath), (newpath)))
#define SMB_VFS_OPAQUE_READLINK(conn, path, buf, bufsiz) ((conn)->vfs_opaque.ops.readlink((conn)->vfs_opaque.handles.readlink, (conn), (path), (buf), (bufsiz)))
#define SMB_VFS_OPAQUE_LINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.link((conn)->vfs_opaque.handles.link, (conn), (oldpath), (newpath)))
@ -293,6 +295,7 @@
#define SMB_VFS_NEXT_UTIME(handle, conn, path, times) ((handle)->vfs_next.ops.utime((handle)->vfs_next.handles.utime, (conn), (path), (times)))
#define SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, offset) ((handle)->vfs_next.ops.ftruncate((handle)->vfs_next.handles.ftruncate, (fsp), (fd), (offset)))
#define SMB_VFS_NEXT_LOCK(handle, fsp, fd, op, offset, count, type) ((handle)->vfs_next.ops.lock((handle)->vfs_next.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type)))
#define SMB_VFS_NEXT_GETLOCK(handle, fsp, fd, poffset, pcount, ptype, ppid) ((handle)->vfs_next.ops.getlock((handle)->vfs_next.handles.getlock, (fsp), (fd), (poffset), (pcount), (ptype), (ppid)))
#define SMB_VFS_NEXT_SYMLINK(handle, conn, oldpath, newpath) ((handle)->vfs_next.ops.symlink((handle)->vfs_next.handles.symlink, (conn), (oldpath), (newpath)))
#define SMB_VFS_NEXT_READLINK(handle, conn, path, buf, bufsiz) ((handle)->vfs_next.ops.readlink((handle)->vfs_next.handles.readlink, (conn), (path), (buf), (bufsiz)))
#define SMB_VFS_NEXT_LINK(handle, conn, oldpath, newpath) ((handle)->vfs_next.ops.link((handle)->vfs_next.handles.link, (conn), (oldpath), (newpath)))

View 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

View 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.

View 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);
}

View 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},

View 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.
************************************************************/

File diff suppressed because it is too large Load Diff

View 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 ));
/*
* 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(!ret && lp_posix_locking(snum)) {
ret = is_posix_locked(fsp, offset, count, lock_type);
DEBUG(10,("is_locked: posix start=%.0f len=%.0f %s for file %s\n",
(double)offset, (double)count, ret ? "locked" : "unlocked",
fsp->fsp_name ));
}
fsp->fnum, fsp->fsp_name ));
return ret;
}
/****************************************************************************
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;
if (!OPEN_FSP(fsp) || !fsp->can_lock) {
return NT_STATUS_INVALID_HANDLE;
}
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 ));
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 ));
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);
}
}
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.
*/
br_lck = brl_get_locks(NULL, fsp);
if (!br_lck) {
return NT_STATUS_NO_MEMORY;
}
posix_data.fsp = fsp;
posix_data.offset = offset;
posix_data.count = count;
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);
}

View 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;

View 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)
{

View 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;
}

View 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.
*/
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);
brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
blr->lock_pid, procid_self(), conn->cnum,
blr->offset, blr->count, True, NULL, NULL);
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.
*/
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);
brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
blr->lock_pid, procid_self(), conn->cnum,
blr->offset, blr->count, True, NULL, NULL);
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)) {
struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
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);
}
free_blocking_lock_record(blr);
}

View 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);
/* 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);
SAFE_FREE(state->data);
SAFE_FREE(state->param);
TALLOC_FREE(state);
/*
* 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);
}
}
DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
name,tdscnt,tpscnt,suwcnt));
/*
* WinCE wierdness....
*/
asprintf(&local_machine_name, "\\%s\\", get_local_machine_name());
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);
return outsize;
}
if (strnequal(name, local_machine_name, strlen(local_machine_name))) {
name_offset = strlen(local_machine_name)-1;
}
DLIST_ADD(conn->pending_trans, state);
SAFE_FREE(local_machine_name);
if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) {
name_offset += strlen("\\PIPE");
/* Win9x weirdness. When talking to a unicode server Win9x
only sends \PIPE instead of \PIPE\ */
if (name[name_offset] == '\\')
name_offset++;
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;
}
SAFE_FREE(data);
SAFE_FREE(params);
SAFE_FREE(setup);
srv_signing_trans_stop();
if (close_on_completion)
close_cnum(conn,vuid);
if (one_way) {
END_PROFILE(SMBtrans);
return(-1);
}
if (outsize == 0) {
END_PROFILE(SMBtrans);
return(ERROR_DOS(ERRSRV,ERRnosupport));
}
/* 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);
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);
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 ((state == NULL) || (state->cmd != SMBtrans)) {
END_PROFILE(SMBtranss);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
/* Revise total_params and total_data in case they have changed
* downwards */
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);
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 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(SMBtranss);
return(outsize);
bad_param:
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);
}

View 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);
}
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)) {
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;
}
memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
dump_data(10, params, parameter_count);
}
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)) {
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;
}
memcpy( data, smb_base(inbuf) + data_offset, data_count);
dump_data(10, data, data_count);
memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
}
srv_signing_trans_start(SVAL(inbuf,smb_mid));
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)+psoff+pscnt > inbuf + size) ||
(smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
goto bad_param;
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.");
}
while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
BOOL ret;
uint32 parameter_displacement;
uint32 data_displacement;
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.
*/
srv_signing_trans_start(SVAL(inbuf,smb_mid));
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);
}
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;
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 (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;
}
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;
}
memcpy( &params[parameter_displacement], smb_base(inbuf) + parameter_offset, parameter_count);
}
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;
}
memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count);
}
}
memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
}
if (Protocol >= PROTOCOL_NT1) {
SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME);
}
state->received_data = dscnt;
state->received_param = pscnt;
/* 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;
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);
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);
srv_signing_trans_stop();
return ERROR_DOS(ERRSRV,ERRerror);
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_nt_SetupStart + state->setup_count > size) {
goto bad_param;
}
memcpy( state->setup, &inbuf[smb_nt_SetupStart], state->setup_count);
dump_data(10, (char *)state->setup, state->setup_count);
}
/* 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_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;
}
srv_signing_trans_stop();
DLIST_ADD(conn->pending_trans, state);
SAFE_FREE(setup);
SAFE_FREE(params);
SAFE_FREE(data);
/* 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; /* 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. */
return outsize;
bad_param:
bad_param:
srv_signing_trans_stop();
SAFE_FREE(params);
SAFE_FREE(data);
SAFE_FREE(setup);
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
****************************************************************************/
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;
START_PROFILE(SMBnttranss);
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 != SMBnttrans)) {
END_PROFILE(SMBnttranss);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
/* 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);
}
pcnt = IVAL(inbuf,smb_nts_ParameterCount);
poff = IVAL(inbuf, smb_nts_ParameterOffset);
pdisp = IVAL(inbuf, smb_nts_ParameterDisplacement);
dcnt = IVAL(inbuf, smb_nts_DataCount);
ddisp = IVAL(inbuf, smb_nts_DataDisplacement);
doff = IVAL(inbuf, smb_nts_DataOffset);
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(SMBnttranss);
return -1;
}
/* construct_reply_common has done us the favor to pre-fill the
* command field with SMBnttranss which is wrong :-)
*/
SCVAL(outbuf,smb_com,SMBnttrans);
outsize = handle_nttrans(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(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);
}

View 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;
}
return ret;
count += 1;
}
if (count > 5) {
return NT_STATUS_INSUFFICIENT_RESOURCES;
}
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 },

View 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));
}

View 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))

File diff suppressed because it is too large Load Diff

View 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;

View 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,

View 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;
}

View File

@ -1203,6 +1203,7 @@ failed:
talloc_free(tc);
return -1;
}
#endif
/***********************************************************

View 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) {