summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2006-04-10 15:33:04 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:15:57 -0500
commit22dbd67708f1651a2341d70ce576fac360affccf (patch)
tree83b1bb601be996716bd4e8d3ae79e94df056df2e /source3/smbd
parent0f985dcb1978afd4b383116f01b3acf65c39ecd7 (diff)
downloadsamba-22dbd67708f1651a2341d70ce576fac360affccf.tar.gz
samba-22dbd67708f1651a2341d70ce576fac360affccf.tar.bz2
samba-22dbd67708f1651a2341d70ce576fac360affccf.zip
r15018: Merge Volker's ipc/trans2/nttrans changes over
into 3.0. Also merge the new POSIX lock code - this is not enabled unless -DDEVELOPER is defined. This doesn't yet map onto underlying system POSIX locks. Updates vfs to allow lock queries. Jeremy. (This used to be commit 08e52ead03304ff04229e1bfe544ff40e2564fc7)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/blocking.c277
-rw-r--r--source3/smbd/ipc.c452
-rw-r--r--source3/smbd/nttrans.c604
-rw-r--r--source3/smbd/process.c31
-rw-r--r--source3/smbd/reply.c112
-rw-r--r--source3/smbd/server.c3
-rw-r--r--source3/smbd/trans2.c963
-rw-r--r--source3/smbd/vfs-wrap.c12
-rw-r--r--source3/smbd/vfs.c1
9 files changed, 1561 insertions, 894 deletions
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 805e45f6ea..6b47d0466b 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -35,6 +35,8 @@ typedef struct _blocking_lock_record {
SMB_BIG_UINT offset;
SMB_BIG_UINT count;
uint16 lock_pid;
+ enum brl_flavour lock_flav;
+ enum brl_type lock_type;
char *inbuf;
int length;
} blocking_lock_record;
@@ -53,25 +55,6 @@ static void free_blocking_lock_record(blocking_lock_record *blr)
}
/****************************************************************************
- Get the files_struct given a particular queued SMB.
-*****************************************************************************/
-
-static files_struct *get_fsp_from_pkt(char *inbuf)
-{
- switch(CVAL(inbuf,smb_com)) {
- case SMBlock:
- case SMBlockread:
- return file_fsp(inbuf,smb_vwv0);
- case SMBlockingX:
- return file_fsp(inbuf,smb_vwv2);
- default:
- DEBUG(0,("get_fsp_from_pkt: PANIC - unknown type on blocking lock queue - exiting.!\n"));
- exit_server("PANIC - unknown type on blocking lock queue");
- }
- return NULL; /* Keep compiler happy. */
-}
-
-/****************************************************************************
Determine if this is a secondary element of a chained SMB.
**************************************************************************/
@@ -87,12 +70,19 @@ static void received_unlock_msg(int msg_type, struct process_id src,
Function to push a blocking lock request onto the lock queue.
****************************************************************************/
-BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
- int lock_num, uint16 lock_pid, SMB_BIG_UINT offset, SMB_BIG_UINT count)
+BOOL push_blocking_lock_request( char *inbuf, int length,
+ files_struct *fsp,
+ int lock_timeout,
+ int lock_num,
+ uint16 lock_pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ SMB_BIG_UINT offset, SMB_BIG_UINT count)
{
static BOOL set_lock_msg;
blocking_lock_record *blr, *tmp;
BOOL my_lock_ctx = False;
+ struct byte_range_lock *br_lck = NULL;
NTSTATUS status;
if(in_chained_smb() ) {
@@ -110,6 +100,9 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
return False;
}
+ blr->next = NULL;
+ blr->prev = NULL;
+
if((blr->inbuf = (char *)SMB_MALLOC(length)) == NULL) {
DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" ));
SAFE_FREE(blr);
@@ -117,19 +110,33 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
}
blr->com_type = CVAL(inbuf,smb_com);
- blr->fsp = get_fsp_from_pkt(inbuf);
+ blr->fsp = fsp;
blr->expire_time = (lock_timeout == -1) ? (time_t)-1 : time(NULL) + (time_t)lock_timeout;
blr->lock_num = lock_num;
blr->lock_pid = lock_pid;
+ blr->lock_flav = lock_flav;
+ blr->lock_type = lock_type;
blr->offset = offset;
blr->count = count;
memcpy(blr->inbuf, inbuf, length);
blr->length = length;
+ br_lck = brl_get_locks(NULL, blr->fsp);
+ if (!br_lck) {
+ free_blocking_lock_record(blr);
+ return False;
+ }
+
/* Add a pending lock record for this. */
- status = brl_lock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
- lock_pid, procid_self(), blr->fsp->conn->cnum,
- offset, count, PENDING_LOCK, &my_lock_ctx);
+ status = brl_lock(br_lck,
+ lock_pid,
+ procid_self(),
+ offset,
+ count,
+ PENDING_LOCK,
+ blr->lock_flav,
+ &my_lock_ctx);
+ TALLOC_FREE(br_lck);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
@@ -227,7 +234,6 @@ static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
{
char *inbuf = blr->inbuf;
files_struct *fsp = blr->fsp;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT) 0;
uint16 lock_pid;
@@ -261,7 +267,11 @@ static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
* request would never have been queued. JRA.
*/
- do_unlock(fsp,conn,lock_pid,count,offset);
+ do_unlock(fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
}
generic_blocking_lock_error(blr, status);
@@ -274,19 +284,41 @@ static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
{
switch(blr->com_type) {
+#if 0
+ /* We no longer push blocking lock requests for anything but lockingX and trans2. */
case SMBlock:
case SMBlockread:
generic_blocking_lock_error(blr, status);
break;
+#endif
case SMBlockingX:
reply_lockingX_error(blr, status);
break;
+ case SMBtrans2:
+ case SMBtranss2:
+ {
+ char *outbuf = get_OutBuffer();
+ char *inbuf = blr->inbuf;
+ construct_reply_common(inbuf, outbuf);
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBtranss2 which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBtrans2);
+ ERROR_NT(status);
+ if (!send_smb(smbd_server_fd(),outbuf)) {
+ exit_server("blocking_lock_reply_error: send_smb failed.");
+ }
+ break;
+ }
default:
DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n"));
exit_server("PANIC - unknown type on blocking lock queue");
}
}
+#if 0
+/* We no longer push blocking lock requests for anything but lockingX and trans2. */
+
/****************************************************************************
Attempt to finish off getting all pending blocking locks for a lockread call.
Returns True if we want to be removed from the list.
@@ -302,7 +334,6 @@ static BOOL process_lockread(blocking_lock_record *blr)
SMB_BIG_UINT startpos;
size_t numtoread;
NTSTATUS status;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
files_struct *fsp = blr->fsp;
BOOL my_lock_ctx = False;
@@ -312,7 +343,14 @@ static BOOL process_lockread(blocking_lock_record *blr)
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
- status = do_lock_spin( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, startpos, READ_LOCK, &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ SVAL(inbuf,smb_pid),
+ (SMB_BIG_UINT)numtoread,
+ startpos,
+ READ_LOCK,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
+
if (NT_STATUS_V(status)) {
if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
!NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
@@ -371,7 +409,6 @@ static BOOL process_lock(blocking_lock_record *blr)
int outsize;
SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
NTSTATUS status;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
files_struct *fsp = blr->fsp;
BOOL my_lock_ctx = False;
@@ -379,7 +416,14 @@ static BOOL process_lock(blocking_lock_record *blr)
offset = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
errno = 0;
- status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ SVAL(inbuf,smb_pid),
+ count,
+ offset,
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
+
if (NT_STATUS_IS_ERR(status)) {
if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
!NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
@@ -412,6 +456,7 @@ static BOOL process_lock(blocking_lock_record *blr)
send_blocking_reply(outbuf,outsize);
return True;
}
+#endif
/****************************************************************************
Attempt to finish off getting all pending blocking locks for a lockingX call.
@@ -423,7 +468,6 @@ static BOOL process_lockingX(blocking_lock_record *blr)
char *inbuf = blr->inbuf;
unsigned char locktype = CVAL(inbuf,smb_vwv3);
files_struct *fsp = blr->fsp;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
uint16 num_locks = SVAL(inbuf,smb_vwv7);
SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
@@ -452,9 +496,17 @@ static BOOL process_lockingX(blocking_lock_record *blr)
* request would never have been queued. JRA.
*/
errno = 0;
- status = do_lock_spin(fsp,conn,lock_pid,count,offset,
- ((locktype & 1) ? READ_LOCK : WRITE_LOCK), &my_lock_ctx);
- if (NT_STATUS_IS_ERR(status)) break;
+ status = do_lock_spin(fsp,
+ lock_pid,
+ count,
+ offset,
+ ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
+ WINDOWS_LOCK,
+ &my_lock_ctx);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ break;
+ }
}
if(blr->lock_num == num_locks) {
@@ -491,6 +543,51 @@ Waiting....\n",
}
/****************************************************************************
+ Attempt to get the posix lock request from a SMBtrans2 call.
+ Returns True if we want to be removed from the list.
+*****************************************************************************/
+
+static BOOL process_trans2(blocking_lock_record *blr)
+{
+ extern int max_send;
+ char *inbuf = blr->inbuf;
+ char *outbuf;
+ BOOL my_lock_ctx = False;
+ char params[2];
+ NTSTATUS status;
+
+ status = do_lock(blr->fsp,
+ blr->lock_pid,
+ blr->count,
+ blr->offset,
+ blr->lock_type,
+ blr->lock_flav,
+ &my_lock_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (ERROR_WAS_LOCK_DENIED(status)) {
+ /* Still can't get the lock, just keep waiting. */
+ return False;
+ }
+ /*
+ * We have other than a "can't get lock"
+ * error. Send an error and return True so we get dequeued.
+ */
+ blocking_lock_reply_error(blr, status);
+ return True;
+ }
+
+ /* We finally got the lock, return success. */
+ outbuf = get_OutBuffer();
+ construct_reply_common(inbuf, outbuf);
+ SCVAL(outbuf,smb_com,SMBtrans2);
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, max_send, params, 2, NULL, 0);
+ return True;
+}
+
+
+/****************************************************************************
Process a blocking lock SMB.
Returns True if we want to be removed from the list.
*****************************************************************************/
@@ -498,12 +595,18 @@ Waiting....\n",
static BOOL blocking_lock_record_process(blocking_lock_record *blr)
{
switch(blr->com_type) {
+#if 0
+ /* We no longer push blocking lock requests for anything but lockingX and trans2. */
case SMBlock:
return process_lock(blr);
case SMBlockread:
return process_lockread(blr);
+#endif
case SMBlockingX:
return process_lockingX(blr);
+ case SMBtrans2:
+ case SMBtranss2:
+ return process_trans2(blr);
default:
DEBUG(0,("blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.!\n"));
exit_server("PANIC - unknown type on blocking lock queue");
@@ -522,13 +625,21 @@ void remove_pending_lock_requests_by_fid(files_struct *fsp)
for(blr = blocking_lock_queue; blr; blr = next) {
next = blr->next;
if(blr->fsp->fnum == fsp->fnum) {
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
- DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \
+ if (br_lck) {
+ DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \
file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
- brl_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
- blr->lock_pid, procid_self(), blr->fsp->conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+
+ }
free_blocking_lock_record(blr);
}
@@ -547,14 +658,22 @@ void remove_pending_lock_requests_by_mid(int mid)
next = blr->next;
if(SVAL(blr->inbuf,smb_mid) == mid) {
files_struct *fsp = blr->fsp;
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
- DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \
+ if (br_lck) {
+ DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \
file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+
blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
- brl_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
- blr->lock_pid, procid_self(), blr->fsp->conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
free_blocking_lock_record(blr);
}
}
@@ -635,16 +754,25 @@ void process_blocking_lock_queue(time_t t)
fsp->fnum, fsp->fsp_name ));
if((blr->expire_time != -1) && (blr->expire_time <= t)) {
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+
/*
* Lock expired - throw away all previously
* obtained locks and return lock error.
*/
- DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
- fsp->fnum, fsp->fsp_name ));
- brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, procid_self(), conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ if (br_lck) {
+ DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
+ fsp->fnum, fsp->fsp_name ));
+
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
free_blocking_lock_record(blr);
@@ -652,32 +780,48 @@ void process_blocking_lock_queue(time_t t)
}
if(!change_to_user(conn,vuid)) {
- DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
- vuid ));
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+
/*
* Remove the entry and return an error to the client.
*/
- blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
- brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, procid_self(), conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ if (br_lck) {
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+ DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
+ vuid ));
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
free_blocking_lock_record(blr);
continue;
}
if(!set_current_service(conn,SVAL(blr->inbuf,smb_flg),True)) {
- DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+
/*
* Remove the entry and return an error to the client.
*/
- blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
- brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, procid_self(), conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ if (br_lck) {
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+ DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
free_blocking_lock_record(blr);
change_to_root_user();
continue;
@@ -690,10 +834,17 @@ void process_blocking_lock_queue(time_t t)
*/
if(blocking_lock_record_process(blr)) {
-
- brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, procid_self(), conn->cnum,
- blr->offset, blr->count, True, NULL, NULL);
+ struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+
+ if (br_lck) {
+ brl_remove_pending_lock(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
free_blocking_lock_record(blr);
}
diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c
index 427b6ae214..1b5a5f39c7 100644
--- a/source3/smbd/ipc.c
+++ b/source3/smbd/ipc.c
@@ -355,259 +355,349 @@ static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *na
return 0;
}
+static NTSTATUS handle_trans(connection_struct *conn,
+ struct trans_state *state,
+ char *outbuf, int *outsize)
+{
+ char *local_machine_name;
+ int name_offset = 0;
+
+ DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
+ state->name,state->total_data,state->total_param,
+ state->setup_count));
+
+ /*
+ * WinCE wierdness....
+ */
+
+ local_machine_name = talloc_asprintf(state, "\\%s\\",
+ get_local_machine_name());
+
+ if (local_machine_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (strnequal(state->name, local_machine_name,
+ strlen(local_machine_name))) {
+ name_offset = strlen(local_machine_name)-1;
+ }
+
+ if (!strnequal(&state->name[name_offset], "\\PIPE",
+ strlen("\\PIPE"))) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ name_offset += strlen("\\PIPE");
+
+ /* Win9x weirdness. When talking to a unicode server Win9x
+ only sends \PIPE instead of \PIPE\ */
+
+ if (state->name[name_offset] == '\\')
+ name_offset++;
+
+ DEBUG(5,("calling named_pipe\n"));
+ *outsize = named_pipe(conn, state->vuid, outbuf,
+ state->name+name_offset,
+ state->setup,state->data,
+ state->param,
+ state->setup_count,state->total_data,
+ state->total_param,
+ state->max_setup_return,
+ state->max_data_return,
+ state->max_param_return);
+
+ if (*outsize == 0) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (state->close_on_completion)
+ close_cnum(conn,state->vuid);
+
+ return NT_STATUS_OK;
+}
/****************************************************************************
Reply to a SMBtrans.
****************************************************************************/
-int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
+int reply_trans(connection_struct *conn, char *inbuf,char *outbuf,
+ int size, int bufsize)
{
- fstring name;
- int name_offset = 0;
- char *data=NULL,*params=NULL;
- uint16 *setup=NULL;
int outsize = 0;
- uint16 vuid = SVAL(inbuf,smb_uid);
- unsigned int tpscnt = SVAL(inbuf,smb_vwv0);
- unsigned int tdscnt = SVAL(inbuf,smb_vwv1);
- unsigned int mprcnt = SVAL(inbuf,smb_vwv2);
- unsigned int mdrcnt = SVAL(inbuf,smb_vwv3);
- unsigned int msrcnt = CVAL(inbuf,smb_vwv4);
- BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
- BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
- unsigned int pscnt = SVAL(inbuf,smb_vwv9);
- unsigned int psoff = SVAL(inbuf,smb_vwv10);
- unsigned int dscnt = SVAL(inbuf,smb_vwv11);
- unsigned int dsoff = SVAL(inbuf,smb_vwv12);
- unsigned int suwcnt = CVAL(inbuf,smb_vwv13);
- char *local_machine_name;
+ unsigned int dsoff = SVAL(inbuf, smb_dsoff);
+ unsigned int dscnt = SVAL(inbuf, smb_dscnt);
+ unsigned int psoff = SVAL(inbuf, smb_psoff);
+ unsigned int pscnt = SVAL(inbuf, smb_pscnt);
+ struct trans_state *state;
+ NTSTATUS result;
+
START_PROFILE(SMBtrans);
- memset(name, '\0',sizeof(name));
- srvstr_pull_buf(inbuf, name, smb_buf(inbuf), sizeof(name), STR_TERMINATE);
+ if (!NT_STATUS_IS_OK(allow_new_trans(conn->pending_trans,
+ SVAL(inbuf, smb_mid)))) {
+ DEBUG(2, ("Got invalid trans request: %s\n",
+ nt_errstr(result)));
+ END_PROFILE(SMBtrans);
+ return ERROR_NT(result);
+ }
- if (dscnt > tdscnt || pscnt > tpscnt)
+ if ((state = TALLOC_P(NULL, struct trans_state)) == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ END_PROFILE(SMBtrans);
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ state->cmd = SMBtrans;
+
+ state->mid = SVAL(inbuf, smb_mid);
+ state->vuid = SVAL(inbuf, smb_uid);
+ state->setup_count = CVAL(inbuf, smb_suwcnt);
+ state->total_param = SVAL(inbuf, smb_tpscnt);
+ state->param = NULL;
+ state->total_data = SVAL(inbuf, smb_tdscnt);
+ state->data = NULL;
+ state->max_param_return = SVAL(inbuf, smb_mprcnt);
+ state->max_data_return = SVAL(inbuf, smb_mdrcnt);
+ state->max_setup_return = CVAL(inbuf, smb_msrcnt);
+ state->close_on_completion = BITSETW(inbuf+smb_vwv5,0);
+ state->one_way = BITSETW(inbuf+smb_vwv5,1);
+
+ memset(state->name, '\0',sizeof(state->name));
+ srvstr_pull_buf(inbuf, state->name, smb_buf(inbuf),
+ sizeof(state->name), STR_TERMINATE);
+
+ if ((dscnt > state->total_data) || (pscnt > state->total_param))
goto bad_param;
-
- if (tdscnt) {
- if((data = (char *)SMB_MALLOC(tdscnt)) == NULL) {
- DEBUG(0,("reply_trans: data malloc fail for %u bytes !\n", tdscnt));
+
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->data = SMB_MALLOC(state->total_data);
+ if (state->data == NULL) {
+ DEBUG(0,("reply_trans: data malloc fail for %u "
+ "bytes !\n", state->total_data));
+ TALLOC_FREE(state);
END_PROFILE(SMBtrans);
return(ERROR_DOS(ERRDOS,ERRnomem));
}
if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
goto bad_param;
if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
- (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
+ (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
goto bad_param;
- memcpy(data,smb_base(inbuf)+dsoff,dscnt);
+ memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
}
- if (tpscnt) {
- if((params = (char *)SMB_MALLOC(tpscnt)) == NULL) {
- DEBUG(0,("reply_trans: param malloc fail for %u bytes !\n", tpscnt));
- SAFE_FREE(data);
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->param = SMB_MALLOC(state->total_param);
+ if (state->param == NULL) {
+ DEBUG(0,("reply_trans: param malloc fail for %u "
+ "bytes !\n", state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
END_PROFILE(SMBtrans);
return(ERROR_DOS(ERRDOS,ERRnomem));
}
if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
goto bad_param;
if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
- (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
+ (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
goto bad_param;
- memcpy(params,smb_base(inbuf)+psoff,pscnt);
+ memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
}
- if (suwcnt) {
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if (state->setup_count) {
unsigned int i;
- if((setup = SMB_MALLOC_ARRAY(uint16,suwcnt)) == NULL) {
- DEBUG(0,("reply_trans: setup malloc fail for %u bytes !\n", (unsigned int)(suwcnt * sizeof(uint16))));
- SAFE_FREE(data);
- SAFE_FREE(params);
+ if((state->setup = TALLOC_ARRAY(
+ state, uint16, state->setup_count)) == NULL) {
+ DEBUG(0,("reply_trans: setup malloc fail for %u "
+ "bytes !\n", (unsigned int)
+ (state->setup_count * sizeof(uint16))));
+ TALLOC_FREE(state);
END_PROFILE(SMBtrans);
return(ERROR_DOS(ERRDOS,ERRnomem));
}
- if (inbuf+smb_vwv14+(suwcnt*SIZEOFWORD) > inbuf + size)
+ if (inbuf+smb_vwv14+(state->setup_count*SIZEOFWORD) >
+ inbuf + size)
goto bad_param;
- if ((smb_vwv14+(suwcnt*SIZEOFWORD) < smb_vwv14) || (smb_vwv14+(suwcnt*SIZEOFWORD) < (suwcnt*SIZEOFWORD)))
+ if ((smb_vwv14+(state->setup_count*SIZEOFWORD) < smb_vwv14) ||
+ (smb_vwv14+(state->setup_count*SIZEOFWORD) <
+ (state->setup_count*SIZEOFWORD)))
goto bad_param;
- for (i=0;i<suwcnt;i++)
- setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
+ for (i=0;i<state->setup_count;i++)
+ state->setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
}
+ state->received_param = pscnt;
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
+ if ((state->received_param == state->total_param) &&
+ (state->received_data == state->total_data)) {
- if (pscnt < tpscnt || dscnt < tdscnt) {
- /* We need to send an interim response then receive the rest
- of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
- show_msg(outbuf);
- srv_signing_trans_stop();
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_trans: send_smb failed.");
- }
+ result = handle_trans(conn, state, outbuf, &outsize);
+
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
- /* receive the rest of the trans packet */
- while (pscnt < tpscnt || dscnt < tdscnt) {
- BOOL ret;
- unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
-
- ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
-
- /*
- * The sequence number for the trans reply is always
- * based on the last secondary received.
- */
-
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
-
- if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
- if(ret) {
- DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
- } else {
- DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
- (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
- }
- SAFE_FREE(params);
- SAFE_FREE(data);
- SAFE_FREE(setup);
+ if (!NT_STATUS_IS_OK(result)) {
END_PROFILE(SMBtrans);
- srv_signing_trans_stop();
- return(ERROR_DOS(ERRSRV,ERRerror));
+ return ERROR_NT(result);
}
- show_msg(inbuf);
-
- /* Revise total_params and total_data in case they have changed downwards */
- if (SVAL(inbuf,smb_vwv0) < tpscnt)
- tpscnt = SVAL(inbuf,smb_vwv0);
- if (SVAL(inbuf,smb_vwv1) < tdscnt)
- tdscnt = SVAL(inbuf,smb_vwv1);
-
- pcnt = SVAL(inbuf,smb_vwv2);
- poff = SVAL(inbuf,smb_vwv3);
- pdisp = SVAL(inbuf,smb_vwv4);
-
- dcnt = SVAL(inbuf,smb_vwv5);
- doff = SVAL(inbuf,smb_vwv6);
- ddisp = SVAL(inbuf,smb_vwv7);
-
- pscnt += pcnt;
- dscnt += dcnt;
-
- if (dscnt > tdscnt || pscnt > tpscnt)
- goto bad_param;
-
- if (pcnt) {
- if (pdisp+pcnt > tpscnt)
- goto bad_param;
- if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
- goto bad_param;
- if (pdisp > tpscnt)
- goto bad_param;
- if ((smb_base(inbuf) + poff + pcnt > inbuf + bufsize) ||
- (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
- goto bad_param;
- if (params + pdisp < params)
- goto bad_param;
-
- memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
+ if (outsize == 0) {
+ END_PROFILE(SMBtrans);
+ return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
}
- if (dcnt) {
- if (ddisp+dcnt > tdscnt)
- goto bad_param;
- if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
- goto bad_param;
- if (ddisp > tdscnt)
- goto bad_param;
- if ((smb_base(inbuf) + doff + dcnt > inbuf + bufsize) ||
- (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
- goto bad_param;
- if (data + ddisp < data)
- goto bad_param;
-
- memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
- }
+ END_PROFILE(SMBtrans);
+ return outsize;
}
- DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
- name,tdscnt,tpscnt,suwcnt));
+ DLIST_ADD(conn->pending_trans, state);
- /*
- * WinCE wierdness....
- */
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,True);
+ show_msg(outbuf);
+ END_PROFILE(SMBtrans);
+ return outsize;
- asprintf(&local_machine_name, "\\%s\\", get_local_machine_name());
+ bad_param:
- if (local_machine_name == NULL) {
- srv_signing_trans_stop();
- SAFE_FREE(data);
- SAFE_FREE(params);
- SAFE_FREE(setup);
- END_PROFILE(SMBtrans);
- return ERROR_NT(NT_STATUS_NO_MEMORY);
+ DEBUG(0,("reply_trans: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+}
+
+/****************************************************************************
+ Reply to a secondary SMBtrans.
+ ****************************************************************************/
+
+int reply_transs(connection_struct *conn, char *inbuf,char *outbuf,
+ int size, int bufsize)
+{
+ int outsize = 0;
+ unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
+ NTSTATUS result;
+
+ START_PROFILE(SMBtranss);
+
+ show_msg(inbuf);
+
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == SVAL(inbuf,smb_mid)) {
+ break;
+ }
}
- if (strnequal(name, local_machine_name, strlen(local_machine_name))) {
- name_offset = strlen(local_machine_name)-1;
+ if ((state == NULL) || (state->cmd != SMBtrans)) {
+ END_PROFILE(SMBtranss);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
- SAFE_FREE(local_machine_name);
+ /* Revise total_params and total_data in case they have changed
+ * downwards */
- if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) {
- name_offset += strlen("\\PIPE");
+ if (SVAL(inbuf, smb_vwv0) < state->total_param)
+ state->total_param = SVAL(inbuf,smb_vwv0);
+ if (SVAL(inbuf, smb_vwv1) < state->total_data)
+ state->total_data = SVAL(inbuf,smb_vwv1);
- /* Win9x weirdness. When talking to a unicode server Win9x
- only sends \PIPE instead of \PIPE\ */
+ pcnt = SVAL(inbuf, smb_spscnt);
+ poff = SVAL(inbuf, smb_spsoff);
+ pdisp = SVAL(inbuf, smb_spsdisp);
- if (name[name_offset] == '\\')
- name_offset++;
+ dcnt = SVAL(inbuf, smb_sdscnt);
+ doff = SVAL(inbuf, smb_sdsoff);
+ ddisp = SVAL(inbuf, smb_sdsdisp);
- DEBUG(5,("calling named_pipe\n"));
- outsize = named_pipe(conn,vuid,outbuf,
- name+name_offset,setup,data,params,
- suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
- } else {
- DEBUG(3,("invalid pipe name\n"));
- outsize = 0;
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
+
+ if (pcnt) {
+ if (pdisp+pcnt > state->total_param)
+ goto bad_param;
+ if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
+ goto bad_param;
+ if (pdisp > state->total_param)
+ goto bad_param;
+ if ((smb_base(inbuf) + poff + pcnt > inbuf + size) ||
+ (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->param + pdisp < state->param)
+ goto bad_param;
+
+ memcpy(state->param+pdisp,smb_base(inbuf)+poff,
+ pcnt);
}
-
- SAFE_FREE(data);
- SAFE_FREE(params);
- SAFE_FREE(setup);
-
- srv_signing_trans_stop();
+ if (dcnt) {
+ if (ddisp+dcnt > state->total_data)
+ goto bad_param;
+ if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
+ goto bad_param;
+ if (ddisp > state->total_data)
+ goto bad_param;
+ if ((smb_base(inbuf) + doff + dcnt > inbuf + size) ||
+ (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->data + ddisp < state->data)
+ goto bad_param;
- if (close_on_completion)
- close_cnum(conn,vuid);
+ memcpy(state->data+ddisp, smb_base(inbuf)+doff,
+ dcnt);
+ }
- if (one_way) {
- END_PROFILE(SMBtrans);
- return(-1);
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBtranss);
+ return -1;
}
-
- if (outsize == 0) {
- END_PROFILE(SMBtrans);
+
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBtranss which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBtrans);
+
+ result = handle_trans(conn, state, outbuf, &outsize);
+
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+
+ if ((outsize == 0) || !NT_STATUS_IS_OK(result)) {
+ END_PROFILE(SMBtranss);
return(ERROR_DOS(ERRSRV,ERRnosupport));
}
- END_PROFILE(SMBtrans);
+ END_PROFILE(SMBtranss);
return(outsize);
-
bad_param:
- srv_signing_trans_stop();
- DEBUG(0,("reply_trans: invalid trans parameters\n"));
- SAFE_FREE(data);
- SAFE_FREE(params);
- SAFE_FREE(setup);
- END_PROFILE(SMBtrans);
+ DEBUG(0,("reply_transs: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtranss);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 796eb44332..24d64ecfc7 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -1812,19 +1812,6 @@ int reply_ntrename(connection_struct *conn,
}
/****************************************************************************
- Reply to an unsolicited SMBNTtranss - just ignore it!
-****************************************************************************/
-
-int reply_nttranss(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
-{
- START_PROFILE(SMBnttranss);
- DEBUG(4,("Ignoring nttranss of length %d\n",length));
- END_PROFILE(SMBnttranss);
- return(-1);
-}
-
-/****************************************************************************
Reply to a notify change - queue the request and
don't allow a directory to be opened.
****************************************************************************/
@@ -2719,29 +2706,120 @@ static int call_nt_transact_set_user_quota(connection_struct *conn, char *inbuf,
}
#endif /* HAVE_SYS_QUOTAS */
+static int handle_nttrans(connection_struct *conn,
+ struct trans_state *state,
+ char *inbuf, char *outbuf, int size, int bufsize)
+{
+ int outsize;
+
+ if (Protocol >= PROTOCOL_NT1) {
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
+ }
+
+ /* Now we must call the relevant NT_TRANS function */
+ switch(state->call) {
+ case NT_TRANSACT_CREATE:
+ START_PROFILE_NESTED(NT_transact_create);
+ outsize = call_nt_transact_create(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_create);
+ break;
+ case NT_TRANSACT_IOCTL:
+ START_PROFILE_NESTED(NT_transact_ioctl);
+ outsize = call_nt_transact_ioctl(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_ioctl);
+ break;
+ case NT_TRANSACT_SET_SECURITY_DESC:
+ START_PROFILE_NESTED(NT_transact_set_security_desc);
+ outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_set_security_desc);
+ break;
+ case NT_TRANSACT_NOTIFY_CHANGE:
+ START_PROFILE_NESTED(NT_transact_notify_change);
+ outsize = call_nt_transact_notify_change(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_notify_change);
+ break;
+ case NT_TRANSACT_RENAME:
+ START_PROFILE_NESTED(NT_transact_rename);
+ outsize = call_nt_transact_rename(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_rename);
+ break;
+
+ case NT_TRANSACT_QUERY_SECURITY_DESC:
+ START_PROFILE_NESTED(NT_transact_query_security_desc);
+ outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_query_security_desc);
+ break;
+#ifdef HAVE_SYS_QUOTAS
+ case NT_TRANSACT_GET_USER_QUOTA:
+ START_PROFILE_NESTED(NT_transact_get_user_quota);
+ outsize = call_nt_transact_get_user_quota(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_get_user_quota);
+ break;
+ case NT_TRANSACT_SET_USER_QUOTA:
+ START_PROFILE_NESTED(NT_transact_set_user_quota);
+ outsize = call_nt_transact_set_user_quota(conn, inbuf, outbuf,
+ size, bufsize,
+ (char **)&state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_set_user_quota);
+ break;
+#endif /* HAVE_SYS_QUOTAS */
+ default:
+ /* Error in request */
+ DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n",
+ state->call));
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
+ return outsize;
+}
+
/****************************************************************************
Reply to a SMBNTtrans.
****************************************************************************/
int reply_nttrans(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+ char *inbuf,char *outbuf,int size,int bufsize)
{
int outsize = 0;
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
-#if 0 /* Not used. */
- uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount);
- uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount);
-#endif /* Not used. */
- uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount);
- uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount);
- uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount);
- uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset);
- uint32 data_count = IVAL(inbuf,smb_nt_DataCount);
- uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset);
- uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */
+ uint32 pscnt = IVAL(inbuf,smb_nt_ParameterCount);
+ uint32 psoff = IVAL(inbuf,smb_nt_ParameterOffset);
+ uint32 dscnt = IVAL(inbuf,smb_nt_DataCount);
+ uint32 dsoff = IVAL(inbuf,smb_nt_DataOffset);
+
uint16 function_code = SVAL( inbuf, smb_nt_Function);
- char *params = NULL, *data = NULL, *setup = NULL;
- uint32 num_params_sofar, num_data_sofar;
+ NTSTATUS result;
+ struct trans_state *state;
+
START_PROFILE(SMBnttrans);
if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
@@ -2749,319 +2827,269 @@ int reply_nttrans(connection_struct *conn,
return ERROR_DOS(ERRSRV,ERRaccess);
}
- outsize = set_message(outbuf,0,0,True);
+ if (!NT_STATUS_IS_OK(allow_new_trans(conn->pending_trans,
+ SVAL(inbuf, smb_mid)))) {
+ DEBUG(2, ("Got invalid nttrans request: %s\n", nt_errstr(result)));
+ END_PROFILE(SMBnttrans);
+ return ERROR_NT(result);
+ }
+
+ if ((state = TALLOC_P(NULL, struct trans_state)) == NULL) {
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRSRV,ERRaccess);
+ }
+
+ state->cmd = SMBnttrans;
+
+ state->mid = SVAL(inbuf,smb_mid);
+ state->vuid = SVAL(inbuf,smb_uid);
+ state->total_data = IVAL(inbuf, smb_nt_TotalDataCount);
+ state->data = NULL;
+ state->total_param = IVAL(inbuf, smb_nt_TotalParameterCount);
+ state->param = NULL;
+ state->max_data_return = IVAL(inbuf,smb_nt_MaxDataCount);
+
+ /* setup count is in *words* */
+ state->setup_count = 2*CVAL(inbuf,smb_nt_SetupCount);
+ state->call = function_code;
/*
- * All nttrans messages we handle have smb_wct == 19 + setup_count.
- * Ensure this is so as a sanity check.
+ * All nttrans messages we handle have smb_wct == 19 +
+ * state->setup_count. Ensure this is so as a sanity check.
*/
- if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) {
+ if(CVAL(inbuf, smb_wct) != 19 + (state->setup_count/2)) {
DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
- CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
+ CVAL(inbuf, smb_wct), 19 + (state->setup_count/2)));
goto bad_param;
}
/* Don't allow more than 128mb for each value. */
- if ((total_parameter_count > (1024*1024*128)) || (total_data_count > (1024*1024*128))) {
+ if ((state->total_data > (1024*1024*128)) ||
+ (state->total_param > (1024*1024*128))) {
END_PROFILE(SMBnttrans);
return ERROR_DOS(ERRDOS,ERRnomem);
}
- /* Allocate the space for the setup, the maximum needed parameters and data */
-
- if(setup_count > 0) {
- setup = (char *)SMB_MALLOC(setup_count);
- }
- if (total_parameter_count > 0) {
- params = (char *)SMB_MALLOC(total_parameter_count);
- }
- if (total_data_count > 0) {
- data = (char *)SMB_MALLOC(total_data_count);
- }
-
- if ((total_parameter_count && !params) || (total_data_count && !data) ||
- (setup_count && !setup)) {
- SAFE_FREE(setup);
- SAFE_FREE(params);
- SAFE_FREE(data);
- DEBUG(0,("reply_nttrans : Out of memory\n"));
- END_PROFILE(SMBnttrans);
- return ERROR_DOS(ERRDOS,ERRnomem);
- }
-
- /* Copy the param and data bytes sent with this request into the params buffer */
- num_params_sofar = parameter_count;
- num_data_sofar = data_count;
-
- if (parameter_count > total_parameter_count || data_count > total_data_count)
+ if ((dscnt > state->total_data) || (pscnt > state->total_param))
goto bad_param;
- if(setup) {
- DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count));
- if ((smb_nt_SetupStart + setup_count < smb_nt_SetupStart) ||
- (smb_nt_SetupStart + setup_count < setup_count)) {
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ if ((state->data = SMB_MALLOC(state->total_data)) == NULL) {
+ DEBUG(0,("reply_nttrans: data malloc fail for %u "
+ "bytes !\n", state->total_data));
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
goto bad_param;
- }
- if (smb_nt_SetupStart + setup_count > length) {
+ if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
+ (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
goto bad_param;
- }
- memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
- dump_data(10, setup, setup_count);
+ memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
}
- if(params) {
- DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count));
- if ((parameter_offset + parameter_count < parameter_offset) ||
- (parameter_offset + parameter_count < parameter_count)) {
+
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ if ((state->param = SMB_MALLOC(state->total_param)) == NULL) {
+ DEBUG(0,("reply_nttrans: param malloc fail for %u "
+ "bytes !\n", state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
goto bad_param;
- }
- if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length)||
- (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) {
+ if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
+ (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
goto bad_param;
- }
- memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
- dump_data(10, params, parameter_count);
+ memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
}
- if(data) {
- DEBUG(10,("reply_nttrans: data_count = %d\n",data_count));
- if ((data_offset + data_count < data_offset) || (data_offset + data_count < data_count)) {
+
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if(state->setup_count > 0) {
+ DEBUG(10,("reply_nttrans: state->setup_count = %d\n",
+ state->setup_count));
+ state->setup = TALLOC(state, state->setup_count);
+ if (state->setup == NULL) {
+ DEBUG(0,("reply_nttrans : Out of memory\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+
+ if ((smb_nt_SetupStart + state->setup_count < smb_nt_SetupStart) ||
+ (smb_nt_SetupStart + state->setup_count < state->setup_count)) {
goto bad_param;
}
- if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) ||
- (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) {
+ if (smb_nt_SetupStart + state->setup_count > size) {
goto bad_param;
}
- memcpy( data, smb_base(inbuf) + data_offset, data_count);
- dump_data(10, data, data_count);
+ memcpy( state->setup, &inbuf[smb_nt_SetupStart], state->setup_count);
+ dump_data(10, (char *)state->setup, state->setup_count);
}
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
+ if ((state->received_data == state->total_data) &&
+ (state->received_param == state->total_param)) {
+ outsize = handle_nttrans(conn, state, inbuf, outbuf,
+ size, bufsize);
+ SAFE_FREE(state->param);
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return outsize;
+ }
- if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
- /* We need to send an interim response then receive the rest
- of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
- srv_signing_trans_stop();
- show_msg(outbuf);
- if (!send_smb(smbd_server_fd(),outbuf)) {
- exit_server("reply_nttrans: send_smb failed.");
- }
+ DLIST_ADD(conn->pending_trans, state);
- while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
- BOOL ret;
- uint32 parameter_displacement;
- uint32 data_displacement;
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,True);
+ show_msg(outbuf);
+ END_PROFILE(SMBnttrans);
+ return outsize;
- ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+ bad_param:
- /* We need to re-calcuate the new length after we've read the secondary packet. */
- length = smb_len(inbuf) + 4;
+ DEBUG(0,("reply_nttrans: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+}
+
+/****************************************************************************
+ Reply to a SMBnttranss
+ ****************************************************************************/
- /*
- * The sequence number for the trans reply is always
- * based on the last secondary received.
- */
+int reply_nttranss(connection_struct *conn, char *inbuf,char *outbuf,
+ int size,int bufsize)
+{
+ int outsize = 0;
+ unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
+ START_PROFILE(SMBnttranss);
- if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) {
- outsize = set_message(outbuf,0,0,True);
- if(ret) {
- DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n"));
- } else {
- DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
- (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
- }
- goto bad_param;
- }
-
- /* Revise total_params and total_data in case they have changed downwards */
- if (IVAL(inbuf, smb_nts_TotalParameterCount) < total_parameter_count) {
- total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
- }
- if (IVAL(inbuf, smb_nts_TotalDataCount) < total_data_count) {
- total_data_count = IVAL(inbuf, smb_nts_TotalDataCount);
- }
+ show_msg(inbuf);
- parameter_count = IVAL(inbuf,smb_nts_ParameterCount);
- parameter_offset = IVAL(inbuf, smb_nts_ParameterOffset);
- parameter_displacement = IVAL(inbuf, smb_nts_ParameterDisplacement);
- num_params_sofar += parameter_count;
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == SVAL(inbuf,smb_mid)) {
+ break;
+ }
+ }
- data_count = IVAL(inbuf, smb_nts_DataCount);
- data_displacement = IVAL(inbuf, smb_nts_DataDisplacement);
- data_offset = IVAL(inbuf, smb_nts_DataOffset);
- num_data_sofar += data_count;
+ if ((state == NULL) || (state->cmd != SMBnttrans)) {
+ END_PROFILE(SMBnttranss);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
- if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) {
- DEBUG(0,("reply_nttrans2: data overflow in secondary nttrans packet"));
- goto bad_param;
- }
+ /* Revise state->total_param and state->total_data in case they have
+ changed downwards */
+ if (IVAL(inbuf, smb_nts_TotalParameterCount) < state->total_param) {
+ state->total_param = IVAL(inbuf, smb_nts_TotalParameterCount);
+ }
+ if (IVAL(inbuf, smb_nts_TotalDataCount) < state->total_data) {
+ state->total_data = IVAL(inbuf, smb_nts_TotalDataCount);
+ }
- if (parameter_count) {
- if (parameter_displacement + parameter_count > total_parameter_count) {
- goto bad_param;
- }
- if ((parameter_displacement + parameter_count < parameter_displacement) ||
- (parameter_displacement + parameter_count < parameter_count)) {
- goto bad_param;
- }
- if (parameter_displacement > total_parameter_count) {
- goto bad_param;
- }
- if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length) ||
- (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) {
- goto bad_param;
- }
- if (parameter_displacement + params < params) {
- goto bad_param;
- }
+ pcnt = IVAL(inbuf,smb_nts_ParameterCount);
+ poff = IVAL(inbuf, smb_nts_ParameterOffset);
+ pdisp = IVAL(inbuf, smb_nts_ParameterDisplacement);
- memcpy( &params[parameter_displacement], smb_base(inbuf) + parameter_offset, parameter_count);
- }
+ dcnt = IVAL(inbuf, smb_nts_DataCount);
+ ddisp = IVAL(inbuf, smb_nts_DataDisplacement);
+ doff = IVAL(inbuf, smb_nts_DataOffset);
- if (data_count) {
- if (data_displacement + data_count > total_data_count) {
- goto bad_param;
- }
- if ((data_displacement + data_count < data_displacement) ||
- (data_displacement + data_count < data_count)) {
- goto bad_param;
- }
- if (data_displacement > total_data_count) {
- goto bad_param;
- }
- if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) ||
- (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) {
- goto bad_param;
- }
- if (data_displacement + data < data) {
- goto bad_param;
- }
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
- memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count);
- }
- }
- }
+ if (pcnt) {
+ if (pdisp+pcnt > state->total_param)
+ goto bad_param;
+ if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
+ goto bad_param;
+ if (pdisp > state->total_param)
+ goto bad_param;
+ if ((smb_base(inbuf) + poff + pcnt > inbuf + size) ||
+ (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->param + pdisp < state->param)
+ goto bad_param;
- if (Protocol >= PROTOCOL_NT1) {
- SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME);
+ memcpy(state->param+pdisp,smb_base(inbuf)+poff,
+ pcnt);
}
- /* Now we must call the relevant NT_TRANS function */
- switch(function_code) {
- case NT_TRANSACT_CREATE:
- START_PROFILE_NESTED(NT_transact_create);
- outsize = call_nt_transact_create(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_create);
- break;
- case NT_TRANSACT_IOCTL:
- START_PROFILE_NESTED(NT_transact_ioctl);
- outsize = call_nt_transact_ioctl(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_ioctl);
- break;
- case NT_TRANSACT_SET_SECURITY_DESC:
- START_PROFILE_NESTED(NT_transact_set_security_desc);
- outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_set_security_desc);
- break;
- case NT_TRANSACT_NOTIFY_CHANGE:
- START_PROFILE_NESTED(NT_transact_notify_change);
- outsize = call_nt_transact_notify_change(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_notify_change);
- break;
- case NT_TRANSACT_RENAME:
- START_PROFILE_NESTED(NT_transact_rename);
- outsize = call_nt_transact_rename(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_rename);
- break;
+ if (dcnt) {
+ if (ddisp+dcnt > state->total_data)
+ goto bad_param;
+ if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
+ goto bad_param;
+ if (ddisp > state->total_data)
+ goto bad_param;
+ if ((smb_base(inbuf) + doff + dcnt > inbuf + size) ||
+ (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->data + ddisp < state->data)
+ goto bad_param;
- case NT_TRANSACT_QUERY_SECURITY_DESC:
- START_PROFILE_NESTED(NT_transact_query_security_desc);
- outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_query_security_desc);
- break;
-#ifdef HAVE_SYS_QUOTAS
- case NT_TRANSACT_GET_USER_QUOTA:
- START_PROFILE_NESTED(NT_transact_get_user_quota);
- outsize = call_nt_transact_get_user_quota(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_get_user_quota);
- break;
- case NT_TRANSACT_SET_USER_QUOTA:
- START_PROFILE_NESTED(NT_transact_set_user_quota);
- outsize = call_nt_transact_set_user_quota(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- &params, total_parameter_count,
- &data, total_data_count, max_data_count);
- END_PROFILE_NESTED(NT_transact_set_user_quota);
- break;
-#endif /* HAVE_SYS_QUOTAS */
- default:
- /* Error in request */
- DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
- SAFE_FREE(setup);
- SAFE_FREE(params);
- SAFE_FREE(data);
- END_PROFILE(SMBnttrans);
- srv_signing_trans_stop();
- return ERROR_DOS(ERRSRV,ERRerror);
+ memcpy(state->data+ddisp, smb_base(inbuf)+doff,
+ dcnt);
}
- /* As we do not know how many data packets will need to be
- returned here the various call_nt_transact_xxxx calls
- must send their own. Thus a call_nt_transact_xxxx routine only
- returns a value other than -1 when it wants to send
- an error packet.
- */
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBnttranss);
+ return -1;
+ }
- srv_signing_trans_stop();
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBnttranss which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBnttrans);
- SAFE_FREE(setup);
- SAFE_FREE(params);
- SAFE_FREE(data);
- END_PROFILE(SMBnttrans);
- return outsize; /* If a correct response was needed the call_nt_transact_xxxx
- calls have already sent it. If outsize != -1 then it is
- returning an error packet. */
+ outsize = handle_nttrans(conn, state, inbuf, outbuf,
+ size, bufsize);
- bad_param:
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
- srv_signing_trans_stop();
- SAFE_FREE(params);
- SAFE_FREE(data);
- SAFE_FREE(setup);
- END_PROFILE(SMBnttrans);
+ if (outsize == 0) {
+ END_PROFILE(SMBnttranss);
+ return(ERROR_DOS(ERRSRV,ERRnosupport));
+ }
+
+ END_PROFILE(SMBnttranss);
+ return(outsize);
+
+ bad_param:
+
+ DEBUG(0,("reply_nttranss: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttranss);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 40d26f7672..cdeccab5e8 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -505,22 +505,27 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
return receive_smb(smbd_server_fd(), buffer, 0);
}
-/****************************************************************************
-Get the next SMB packet, doing the local message processing automatically.
-****************************************************************************/
+/*
+ * Only allow 5 outstanding trans requests. We're allocating memory, so
+ * prevent a DoS.
+ */
-BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
+NTSTATUS allow_new_trans(struct trans_state *list, int mid)
{
- BOOL got_keepalive;
- BOOL ret;
+ int count = 0;
+ for (; list != NULL; list = list->next) {
- do {
- ret = receive_message_or_smb(inbuf,bufsize,timeout);
-
- got_keepalive = (ret && (CVAL(inbuf,0) == SMBkeepalive));
- } while (ret && got_keepalive);
+ if (list->mid == mid) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ count += 1;
+ }
+ if (count > 5) {
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
+ }
- return ret;
+ return NT_STATUS_OK;
}
/****************************************************************************
@@ -611,7 +616,7 @@ static const struct smb_message_struct {
/* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
/* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
-/* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
+/* 0x26 */ { "SMBtranss",reply_transs,AS_USER | CAN_IPC},
/* 0x27 */ { "SMBioctl",reply_ioctl,0},
/* 0x28 */ { "SMBioctls",NULL,AS_USER},
/* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index ce41266a1c..040f7710fd 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -269,10 +269,13 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *
switch(next_mb_char_size(s)) {
case 4:
*d++ = *s++;
+ /*fall through*/
case 3:
*d++ = *s++;
+ /*fall through*/
case 2:
*d++ = *s++;
+ /*fall through*/
case 1:
*d++ = *s++;
break;
@@ -374,10 +377,13 @@ NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
switch(next_mb_char_size(s)) {
case 4:
*d++ = *s++;
+ /*fall through*/
case 3:
*d++ = *s++;
+ /*fall through*/
case 2:
*d++ = *s++;
+ /*fall through*/
case 1:
*d++ = *s++;
break;
@@ -2319,7 +2325,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
/* ensure we don't overrun the packet size */
maxcount = MIN(65535,maxcount);
- if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+ if (!is_locked(fsp,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
SMB_STRUCT_STAT st;
SMB_OFF_T size = 0;
@@ -2390,8 +2396,13 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
* Note that the requested lock size is unaffected by max_recv.
*/
- status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid),
- (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ SVAL(inbuf,smb_pid),
+ (SMB_BIG_UINT)numtoread,
+ (SMB_BIG_UINT)startpos,
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
if (NT_STATUS_V(status)) {
#if 0
@@ -2407,8 +2418,15 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
* this smb into a queued request and push it
* onto the blocking lock queue.
*/
- if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)startpos,
- (SMB_BIG_UINT)numtoread)) {
+ if(push_blocking_lock_request(inbuf, length,
+ fsp,
+ -1,
+ 0,
+ SVAL(inbuf,smb_pid),
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ (SMB_BIG_UINT)startpos,
+ (SMB_BIG_UINT)numtoread)) {
END_PROFILE(SMBlockread);
return -1;
}
@@ -2486,7 +2504,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
data = smb_buf(outbuf) + 3;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK)) {
END_PROFILE(SMBread);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2694,7 +2712,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
}
- if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK)) {
END_PROFILE(SMBreadX);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2757,7 +2775,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
SCVAL(inbuf,smb_com,SMBwritec);
SCVAL(outbuf,smb_com,SMBwritec);
- if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwritebraw);
return(ERROR_DOS(ERRDOS,ERRlock));
}
@@ -2878,7 +2896,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (numtowrite && is_locked(fsp,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwriteunlock);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2900,8 +2918,12 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
}
if (numtowrite) {
- status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite,
- (SMB_BIG_UINT)startpos);
+ status = do_unlock(fsp,
+ SVAL(inbuf,smb_pid),
+ (SMB_BIG_UINT)numtowrite,
+ (SMB_BIG_UINT)startpos,
+ WINDOWS_LOCK);
+
if (NT_STATUS_V(status)) {
END_PROFILE(SMBwriteunlock);
return ERROR_NT(status);
@@ -2951,7 +2973,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwrite);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -3066,7 +3088,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
#endif /* LARGE_SMB_OFF_T */
}
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwriteX);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -3340,7 +3362,7 @@ int reply_writeclose(connection_struct *conn,
mtime = srv_make_unix_date3(inbuf+smb_vwv4);
data = smb_buf(inbuf) + 1;
- if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ if (numtowrite && is_locked(fsp,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwriteclose);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -3410,7 +3432,13 @@ int reply_lock(connection_struct *conn,
DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
- status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ SVAL(inbuf,smb_pid),
+ count,
+ offset,
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
if (NT_STATUS_V(status)) {
#if 0
/* Tests using Samba4 against W2K show this call never creates a blocking lock. */
@@ -3420,7 +3448,14 @@ int reply_lock(connection_struct *conn,
* this smb into a queued request and push it
* onto the blocking lock queue.
*/
- if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), offset, count)) {
+ if(push_blocking_lock_request(inbuf, length,
+ fsp,
+ -1,
+ 0,
+ SVAL(inbuf,smb_pid),
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ offset, count)) {
END_PROFILE(SMBlock);
return -1;
}
@@ -3452,7 +3487,12 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
- status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
+ status = do_unlock(fsp,
+ SVAL(inbuf,smb_pid),
+ count,
+ offset,
+ WINDOWS_LOCK);
+
if (NT_STATUS_V(status)) {
END_PROFILE(SMBunlock);
return ERROR_NT(status);
@@ -5279,7 +5319,12 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
"pid %u, file %s\n", (double)offset, (double)count,
(unsigned int)lock_pid, fsp->fsp_name ));
- status = do_unlock(fsp,conn,lock_pid,count,offset);
+ status = do_unlock(fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
+
if (NT_STATUS_V(status)) {
END_PROFILE(SMBlockingX);
return ERROR_NT(status);
@@ -5297,6 +5342,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
of smb_lkrng structs */
for(i = 0; i < (int)num_locks; i++) {
+ enum brl_type lock_type = ((locktype & 1) ? READ_LOCK:WRITE_LOCK);
lock_pid = get_lock_pid( data, i, large_file_format);
count = get_lock_count( data, i, large_file_format);
offset = get_lock_offset( data, i, large_file_format, &err);
@@ -5314,9 +5360,14 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
(double)count, (unsigned int)lock_pid,
fsp->fsp_name, (int)lock_timeout ));
- status = do_lock_spin(fsp,conn,lock_pid, count,offset,
- ((locktype & 1) ? READ_LOCK:WRITE_LOCK),
- &my_lock_ctx);
+ status = do_lock_spin(fsp,
+ lock_pid,
+ count,
+ offset,
+ lock_type,
+ WINDOWS_LOCK,
+ &my_lock_ctx);
+
if (NT_STATUS_V(status)) {
/*
* Interesting fact found by IFSTEST /t
@@ -5334,8 +5385,13 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
* onto the blocking lock queue.
*/
if(push_blocking_lock_request(inbuf, length,
- lock_timeout, i,
- lock_pid, offset,
+ fsp,
+ lock_timeout,
+ i,
+ lock_pid,
+ lock_type,
+ WINDOWS_LOCK,
+ offset,
count)) {
END_PROFILE(SMBlockingX);
return -1;
@@ -5368,7 +5424,11 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
- do_unlock(fsp,conn,lock_pid,count,offset);
+ do_unlock(fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
}
END_PROFILE(SMBlockingX);
return ERROR_NT(status);
@@ -5430,7 +5490,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
tcount = maxcount;
total_read = 0;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
END_PROFILE(SMBreadBmpx);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -5562,7 +5622,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
not an SMBwritebmpx - set this up now so we don't forget */
SCVAL(outbuf,smb_com,SMBwritec);
- if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK)) {
+ if (is_locked(fsp,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK)) {
END_PROFILE(SMBwriteBmpx);
return(ERROR_DOS(ERRDOS,ERRlock));
}
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index ba31827eb3..0880778f55 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -898,9 +898,8 @@ void build_options(BOOL screen);
* If we're interactive we want to set our own process group for
* signal management.
*/
- if (interactive && !no_process_group) {
+ if (interactive && !no_process_group)
setpgid( (pid_t)0, (pid_t)0);
- }
#endif
if (!directory_exist(lp_lockdir(), NULL))
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 4f5039e86c..19463403ac 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -563,7 +563,7 @@ static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *
HACK ! Always assumes smb_setup field is zero.
****************************************************************************/
-static int send_trans2_replies(char *outbuf,
+int send_trans2_replies(char *outbuf,
int bufsize,
char *params,
int paramsize,
@@ -1644,11 +1644,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
break;
case SMB_FIND_FILE_UNIX:
- if (!lp_unix_extensions())
- return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ if (!lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
break;
default:
- return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
srvstr_get_path_wcard(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, &mask_contains_wcard);
@@ -1926,11 +1927,12 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
break;
case SMB_FIND_FILE_UNIX:
- if (!lp_unix_extensions())
- return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ if (!lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
break;
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
if (info_level == SMB_FIND_EA_LIST) {
@@ -2398,13 +2400,21 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
*/
case SMB_QUERY_CIFS_UNIX_INFO:
- if (!lp_unix_extensions())
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (!lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
data_len = 12;
SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
- SBIG_UINT(pdata,4,((SMB_BIG_UINT)(CIFS_UNIX_POSIX_ACLS_CAP|
- CIFS_UNIX_POSIX_PATHNAMES_CAP))); /* We have POSIX ACLs and pathname capability. */
+ /* We have POSIX ACLs, pathname and locking capability. */
+ SBIG_UINT(pdata,4,((SMB_BIG_UINT)(
+ CIFS_UNIX_POSIX_ACLS_CAP|
+ CIFS_UNIX_POSIX_PATHNAMES_CAP|
+#if defined(DEVELOPER) /* Not quite finished yet... */
+ CIFS_UNIX_FCNTL_LOCKS_CAP)));
+#else
+ 0)));
+#endif
break;
case SMB_QUERY_POSIX_FS_INFO:
@@ -2412,9 +2422,10 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
int rc;
vfs_statvfs_struct svfs;
- if (!lp_unix_extensions())
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
-
+ if (!lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
+
rc = SMB_VFS_STATVFS(conn, ".", &svfs);
if (!rc) {
@@ -2430,7 +2441,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
#ifdef EOPNOTSUPP
} else if (rc == EOPNOTSUPP) {
- return ERROR_DOS(ERRDOS, ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
#endif /* EOPNOTSUPP */
} else {
DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
@@ -2451,7 +2462,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
}
/* drop through */
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
@@ -2495,7 +2506,7 @@ static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outb
uint32 client_unix_cap_high;
if (!lp_unix_extensions()) {
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
/* There should be 12 bytes of capabilities set. */
@@ -2515,8 +2526,15 @@ cap_low = 0x%x, cap_high = 0x%x\n",
(unsigned int)client_unix_cap_high ));
/* Here is where we must switch to posix pathname processing... */
- lp_set_posix_pathnames();
- mangle_change_to_posix();
+ if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+ lp_set_posix_pathnames();
+ mangle_change_to_posix();
+ }
+#if defined(DEVELOPER)
+ if (client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) {
+ lp_set_posix_cifsx_locktype(POSIX_LOCK);
+ }
+#endif
break;
}
case SMB_FS_QUOTA_INFORMATION:
@@ -2593,7 +2611,7 @@ cap_low = 0x%x, cap_high = 0x%x\n",
default:
DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
info_level));
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
break;
}
@@ -2768,13 +2786,14 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
char *fullpathname;
char *base_name;
char *p;
+ char *lock_data = NULL;
SMB_OFF_T pos = 0;
BOOL bad_path = False;
BOOL delete_pending = False;
int len;
time_t c_time;
files_struct *fsp = NULL;
- TALLOC_CTX *ea_ctx = NULL;
+ TALLOC_CTX *data_ctx = NULL;
struct ea_list *ea_list = NULL;
uint32 access_mask = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */
@@ -2893,8 +2912,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
nlink -= 1;
}
- if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n",
fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
@@ -2913,40 +2933,70 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
if (!(mode & aDIR))
file_size = get_file_size(sbuf);
- /* Pull any EA list from the data portion. */
- if (info_level == SMB_INFO_QUERY_EAS_FROM_LIST) {
- uint32 ea_size;
+ /* Pull out any data sent here before we realloc. */
+ switch (info_level) {
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ {
+ /* Pull any EA list from the data portion. */
+ uint32 ea_size;
- if (total_data < 4) {
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
- ea_size = IVAL(pdata,0);
+ if (total_data < 4) {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ ea_size = IVAL(pdata,0);
- if (total_data > 0 && ea_size != total_data) {
- DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
+ if (total_data > 0 && ea_size != total_data) {
+ DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
- if (!lp_ea_support(SNUM(conn))) {
- return ERROR_DOS(ERRDOS,ERReasnotsupported);
- }
+ if (!lp_ea_support(SNUM(conn))) {
+ return ERROR_DOS(ERRDOS,ERReasnotsupported);
+ }
- if ((ea_ctx = talloc_init("ea_list")) == NULL) {
- return ERROR_NT(NT_STATUS_NO_MEMORY);
+ if ((data_ctx = talloc_init("ea_list")) == NULL) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ /* Pull out the list of names. */
+ ea_list = read_ea_name_list(data_ctx, pdata + 4, ea_size - 4);
+ if (!ea_list) {
+ talloc_destroy(data_ctx);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ break;
}
+#if defined(DEVELOPER)
+ case SMB_QUERY_POSIX_LOCK:
+ {
+ if (fsp == NULL || fsp->fh->fd == -1) {
+ return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+ }
- /* Pull out the list of names. */
- ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4);
- if (!ea_list) {
- talloc_destroy(ea_ctx);
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ if (total_data != POSIX_LOCK_DATA_SIZE) {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if ((data_ctx = talloc_init("lock_request")) == NULL) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ /* Copy the lock range data. */
+ lock_data = talloc_memdup(data_ctx, pdata, total_data);
+ if (!lock_data) {
+ talloc_destroy(data_ctx);
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
}
+#endif
+ default:
+ break;
}
*pparams = SMB_REALLOC(*pparams,2);
if (*pparams == NULL) {
- talloc_destroy(ea_ctx);
+ talloc_destroy(data_ctx);
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
params = *pparams;
@@ -2954,7 +3004,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
*ppdata = SMB_REALLOC(*ppdata, data_size);
if (*ppdata == NULL ) {
- talloc_destroy(ea_ctx);
+ talloc_destroy(data_ctx);
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
pdata = *ppdata;
@@ -3040,18 +3090,18 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
- ea_file_list = get_ea_list_from_file(ea_ctx, conn, fsp, fname, &total_ea_len);
+ ea_file_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len);
ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
if (!ea_list || (total_ea_len > data_size)) {
- talloc_destroy(ea_ctx);
+ talloc_destroy(data_ctx);
data_size = 4;
SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
break;
}
- data_size = fill_ea_buffer(ea_ctx, pdata, data_size, conn, ea_list);
- talloc_destroy(ea_ctx);
+ data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list);
+ talloc_destroy(data_ctx);
break;
}
@@ -3062,21 +3112,21 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
- ea_ctx = talloc_init("ea_ctx");
- if (!ea_ctx) {
+ data_ctx = talloc_init("ea_ctx");
+ if (!data_ctx) {
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
- ea_list = get_ea_list_from_file(ea_ctx, conn, fsp, fname, &total_ea_len);
+ ea_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len);
if (!ea_list || (total_ea_len > data_size)) {
- talloc_destroy(ea_ctx);
+ talloc_destroy(data_ctx);
data_size = 4;
SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
break;
}
- data_size = fill_ea_buffer(ea_ctx, pdata, data_size, conn, ea_list);
- talloc_destroy(ea_ctx);
+ data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list);
+ talloc_destroy(data_ctx);
break;
}
@@ -3469,8 +3519,84 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
}
#endif
+
+#if defined(DEVELOPER)
+ case SMB_QUERY_POSIX_LOCK:
+ {
+ NTSTATUS status = NT_STATUS_INVALID_LEVEL;
+ SMB_BIG_UINT count;
+ SMB_BIG_UINT offset;
+ uint16 lock_pid;
+ enum brl_type lock_type;
+
+ if (total_data != POSIX_LOCK_DATA_SIZE) {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
+ case POSIX_LOCK_TYPE_READ:
+ lock_type = READ_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_WRITE:
+ lock_type = WRITE_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_UNLOCK:
+ default:
+ /* There's no point in asking for an unlock... */
+ talloc_destroy(data_ctx);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ lock_pid = (uint16)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
+#if defined(HAVE_LONGLONG)
+ offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
+ count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
+#else /* HAVE_LONGLONG */
+ offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
+ count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
+#endif /* HAVE_LONGLONG */
+
+ status = query_lock(fsp,
+ &lock_pid,
+ &count,
+ &offset,
+ &lock_type,
+ POSIX_LOCK);
+
+ if (ERROR_WAS_LOCK_DENIED(status)) {
+ /* Here we need to report who has it locked... */
+ data_size = POSIX_LOCK_DATA_SIZE;
+
+ SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
+ SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
+ SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid);
+#if defined(HAVE_LONGLONG)
+ SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
+ SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
+ SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
+ SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
+#else /* HAVE_LONGLONG */
+ SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
+ SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
+#endif /* HAVE_LONGLONG */
+
+ } else if (NT_STATUS_IS_OK(status)) {
+ /* For success we just return a copy of what we sent
+ with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
+ data_size = POSIX_LOCK_DATA_SIZE;
+ memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
+ SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
+ } else {
+ return ERROR_NT(status);
+ }
+ break;
+ }
+#endif
+
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size);
@@ -3674,8 +3800,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
if (!CAN_WRITE(conn))
return ERROR_DOS(ERRSRV,ERRaccess);
- if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
if (VALID_STAT(sbuf))
unixmode = sbuf.st_mode;
@@ -3843,8 +3970,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
#ifdef LARGE_SMB_OFF_T
allocation_size |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
#endif /* LARGE_SMB_OFF_T */
DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n",
fname, (double)allocation_size ));
@@ -3910,8 +4039,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
#ifdef LARGE_SMB_OFF_T
size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
#endif /* LARGE_SMB_OFF_T */
DEBUG(10,("call_trans2setfilepathinfo: Set end of file info for file %s to %.0f\n", fname, (double)size ));
break;
@@ -3964,8 +4095,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
#ifdef LARGE_SMB_OFF_T
position_information |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
#endif /* LARGE_SMB_OFF_T */
DEBUG(10,("call_trans2setfilepathinfo: Set file position information for file %s to %.0f\n",
fname, (double)position_information ));
@@ -4021,8 +4154,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
#ifdef LARGE_SMB_OFF_T
size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
#endif /* LARGE_SMB_OFF_T */
}
pdata+=24; /* ctime & st_blocks are not changed */
@@ -4329,8 +4464,109 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
}
#endif
+#if defined(DEVELOPER)
+ case SMB_SET_POSIX_LOCK:
+ {
+ SMB_BIG_UINT count;
+ SMB_BIG_UINT offset;
+ uint16 lock_pid;
+ BOOL lock_blocking;
+ enum brl_type lock_type;
+ BOOL my_lock_ctx;
+
+ if (fsp == NULL || fsp->fh->fd == -1) {
+ return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+ }
+
+ if (total_data != POSIX_LOCK_DATA_SIZE) {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
+ case POSIX_LOCK_TYPE_READ:
+ lock_type = READ_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_WRITE:
+ /* Return the right POSIX-mappable error code for files opened read-only. */
+ if (!fsp->can_write) {
+ return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+ }
+ lock_type = WRITE_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_UNLOCK:
+ lock_type = UNLOCK_LOCK;
+ break;
+ default:
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
+ lock_blocking = False;
+ } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
+ lock_blocking = True;
+ } else {
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ lock_pid = (uint16)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
+#if defined(HAVE_LONGLONG)
+ offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
+ count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
+#else /* HAVE_LONGLONG */
+ offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
+ count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
+#endif /* HAVE_LONGLONG */
+
+ if (lock_type == UNLOCK_LOCK) {
+ status = do_unlock(fsp,
+ lock_pid,
+ count,
+ offset,
+ POSIX_LOCK);
+ } else {
+ status = do_lock(fsp,
+ lock_pid,
+ count,
+ offset,
+ lock_type,
+ POSIX_LOCK,
+ &my_lock_ctx);
+
+ /* TODO: Deal with rescheduling blocking lock fail here... */
+ if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if(push_blocking_lock_request(inbuf, length,
+ fsp,
+ -1, /* infinite timeout. */
+ 0,
+ lock_pid,
+ lock_type,
+ POSIX_LOCK,
+ offset,
+ count)) {
+ return -1;
+ }
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
+
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
+ }
+#endif
+
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
/* get some defaults (no modifications) if any info is zero or -1. */
@@ -4582,7 +4818,7 @@ static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char
case 2:
break;
default:
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
/* Realloc the parameter and data sizes */
@@ -4759,331 +4995,418 @@ int reply_findnclose(connection_struct *conn,
return(outsize);
}
-/****************************************************************************
- Reply to a SMBtranss2 - just ignore it!
-****************************************************************************/
-
-int reply_transs2(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
-{
- START_PROFILE(SMBtranss2);
- DEBUG(4,("Ignoring transs2 of length %d\n",length));
- END_PROFILE(SMBtranss2);
- return(-1);
-}
-
-/****************************************************************************
- Reply to a SMBtrans2.
-****************************************************************************/
-
-int reply_trans2(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+int handle_trans2(connection_struct *conn,
+ struct trans_state *state,
+ char *inbuf, char *outbuf, int size, int bufsize)
{
- int outsize = 0;
- unsigned int total_params = SVAL(inbuf, smb_tpscnt);
- unsigned int total_data =SVAL(inbuf, smb_tdscnt);
- unsigned int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
-#if 0
- unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
- unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
- BOOL close_tid = BITSETW(inbuf+smb_flags,0);
- BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
- int32 timeout = IVALS(inbuf,smb_timeout);
-#endif
- unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
- unsigned int tran_call = SVAL(inbuf, smb_setup0);
- char *params = NULL, *data = NULL;
- unsigned int num_params, num_params_sofar, num_data, num_data_sofar;
- START_PROFILE(SMBtrans2);
-
- if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
- && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
- END_PROFILE(SMBtrans2);
- return ERROR_DOS(ERRSRV,ERRaccess);
- }
-
- outsize = set_message(outbuf,0,0,True);
-
- /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
- is so as a sanity check */
- if (suwcnt != 1) {
- /*
- * Need to have rc=0 for ioctl to get job id for OS/2.
- * Network printing will fail if function is not successful.
- * Similar function in reply.c will be used if protocol
- * is LANMAN1.0 instead of LM1.2X002.
- * Until DosPrintSetJobInfo with PRJINFO3 is supported,
- * outbuf doesn't have to be set(only job id is used).
- */
- if ( (suwcnt == 4) && (tran_call == TRANSACT2_IOCTL) &&
- (SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
- (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
- DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
- } else {
- DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",suwcnt));
- DEBUG(2,("Transaction is %d\n",tran_call));
- END_PROFILE(SMBtrans2);
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
- }
-
- /* Allocate the space for the maximum needed parameters and data */
- if (total_params > 0)
- params = (char *)SMB_MALLOC(total_params);
- if (total_data > 0)
- data = (char *)SMB_MALLOC(total_data);
-
- if ((total_params && !params) || (total_data && !data)) {
- DEBUG(2,("Out of memory in reply_trans2\n"));
- SAFE_FREE(params);
- SAFE_FREE(data);
- END_PROFILE(SMBtrans2);
- return ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
- /* Copy the param and data bytes sent with this request into
- the params buffer */
- num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
- num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
-
- if (num_params > total_params || num_data > total_data)
- exit_server("invalid params in reply_trans2");
-
- if(params) {
- unsigned int psoff = SVAL(inbuf, smb_psoff);
- if ((psoff + num_params < psoff) || (psoff + num_params < num_params))
- goto bad_param;
- if ((smb_base(inbuf) + psoff + num_params > inbuf + length) ||
- (smb_base(inbuf) + psoff + num_params < smb_base(inbuf)))
- goto bad_param;
- memcpy( params, smb_base(inbuf) + psoff, num_params);
- }
- if(data) {
- unsigned int dsoff = SVAL(inbuf, smb_dsoff);
- if ((dsoff + num_data < dsoff) || (dsoff + num_data < num_data))
- goto bad_param;
- if ((smb_base(inbuf) + dsoff + num_data > inbuf + length) ||
- (smb_base(inbuf) + dsoff + num_data < smb_base(inbuf)))
- goto bad_param;
- memcpy( data, smb_base(inbuf) + dsoff, num_data);
- }
-
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
-
- if(num_data_sofar < total_data || num_params_sofar < total_params) {
- /* We need to send an interim response then receive the rest
- of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
- srv_signing_trans_stop();
- show_msg(outbuf);
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_trans2: send_smb failed.");
-
- while (num_data_sofar < total_data ||
- num_params_sofar < total_params) {
- BOOL ret;
- unsigned int param_disp;
- unsigned int param_off;
- unsigned int data_disp;
- unsigned int data_off;
-
- ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
-
- /* We need to re-calcuate the new length after we've read the secondary packet. */
- length = smb_len(inbuf) + 4;
-
- /*
- * The sequence number for the trans reply is always
- * based on the last secondary received.
- */
+ int outsize;
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
-
- if ((ret &&
- (CVAL(inbuf, smb_com) != SMBtranss2)) || !ret) {
- outsize = set_message(outbuf,0,0,True);
- if(ret)
- DEBUG(0,("reply_trans2: Invalid secondary trans2 packet\n"));
- else
- DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n",
- (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
- goto bad_param;
- }
-
- /* Revise total_params and total_data in case
- they have changed downwards */
- if (SVAL(inbuf, smb_tpscnt) < total_params)
- total_params = SVAL(inbuf, smb_tpscnt);
- if (SVAL(inbuf, smb_tdscnt) < total_data)
- total_data = SVAL(inbuf, smb_tdscnt);
-
- num_params = SVAL(inbuf,smb_spscnt);
- param_off = SVAL(inbuf, smb_spsoff);
- param_disp = SVAL(inbuf, smb_spsdisp);
- num_params_sofar += num_params;
-
- num_data = SVAL(inbuf, smb_sdscnt);
- data_off = SVAL(inbuf, smb_sdsoff);
- data_disp = SVAL(inbuf, smb_sdsdisp);
- num_data_sofar += num_data;
-
- if (num_params_sofar > total_params || num_data_sofar > total_data)
- goto bad_param;
-
- if (num_params) {
- if (param_disp + num_params > total_params)
- goto bad_param;
- if ((param_disp + num_params < param_disp) ||
- (param_disp + num_params < num_params))
- goto bad_param;
- if (param_disp > total_params)
- goto bad_param;
- if ((smb_base(inbuf) + param_off + num_params > inbuf + length) ||
- (smb_base(inbuf) + param_off + num_params < smb_base(inbuf)))
- goto bad_param;
- if (params + param_disp < params)
- goto bad_param;
-
- memcpy( &params[param_disp], smb_base(inbuf) + param_off, num_params);
- }
- if (num_data) {
- if (data_disp + num_data > total_data)
- goto bad_param;
- if ((data_disp + num_data < data_disp) ||
- (data_disp + num_data < num_data))
- goto bad_param;
- if (data_disp > total_data)
- goto bad_param;
- if ((smb_base(inbuf) + data_off + num_data > inbuf + length) ||
- (smb_base(inbuf) + data_off + num_data < smb_base(inbuf)))
- goto bad_param;
- if (data + data_disp < data)
- goto bad_param;
-
- memcpy( &data[data_disp], smb_base(inbuf) + data_off, num_data);
- }
- }
- }
-
if (Protocol >= PROTOCOL_NT1) {
SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
}
/* Now we must call the relevant TRANS2 function */
- switch(tran_call) {
+ switch(state->call) {
case TRANSACT2_OPEN:
START_PROFILE_NESTED(Trans2_open);
- outsize = call_trans2open(conn, inbuf, outbuf, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2open(
+ conn, inbuf, outbuf, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_open);
break;
case TRANSACT2_FINDFIRST:
START_PROFILE_NESTED(Trans2_findfirst);
- outsize = call_trans2findfirst(conn, inbuf, outbuf, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2findfirst(
+ conn, inbuf, outbuf, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_findfirst);
break;
case TRANSACT2_FINDNEXT:
START_PROFILE_NESTED(Trans2_findnext);
- outsize = call_trans2findnext(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2findnext(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_findnext);
break;
case TRANSACT2_QFSINFO:
START_PROFILE_NESTED(Trans2_qfsinfo);
- outsize = call_trans2qfsinfo(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2qfsinfo(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_qfsinfo);
break;
case TRANSACT2_SETFSINFO:
START_PROFILE_NESTED(Trans2_setfsinfo);
- outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2setfsinfo(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_setfsinfo);
break;
case TRANSACT2_QPATHINFO:
case TRANSACT2_QFILEINFO:
START_PROFILE_NESTED(Trans2_qpathinfo);
- outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, tran_call,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2qfilepathinfo(
+ conn, inbuf, outbuf, size, bufsize, state->call,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_qpathinfo);
break;
case TRANSACT2_SETPATHINFO:
case TRANSACT2_SETFILEINFO:
START_PROFILE_NESTED(Trans2_setpathinfo);
- outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize, tran_call,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2setfilepathinfo(
+ conn, inbuf, outbuf, size, bufsize, state->call,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_setpathinfo);
break;
case TRANSACT2_FINDNOTIFYFIRST:
START_PROFILE_NESTED(Trans2_findnotifyfirst);
- outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2findnotifyfirst(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_findnotifyfirst);
break;
case TRANSACT2_FINDNOTIFYNEXT:
START_PROFILE_NESTED(Trans2_findnotifynext);
- outsize = call_trans2findnotifynext(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2findnotifynext(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_findnotifynext);
break;
case TRANSACT2_MKDIR:
START_PROFILE_NESTED(Trans2_mkdir);
- outsize = call_trans2mkdir(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2mkdir(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_mkdir);
break;
case TRANSACT2_GET_DFS_REFERRAL:
START_PROFILE_NESTED(Trans2_get_dfs_referral);
- outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2getdfsreferral(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_get_dfs_referral);
break;
case TRANSACT2_IOCTL:
START_PROFILE_NESTED(Trans2_ioctl);
- outsize = call_trans2ioctl(conn,inbuf,outbuf,length, bufsize,
- &params, total_params, &data, total_data, max_data_bytes);
+ outsize = call_trans2ioctl(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
END_PROFILE_NESTED(Trans2_ioctl);
break;
default:
/* Error in request */
- DEBUG(2,("Unknown request %d in trans2 call\n", tran_call));
- SAFE_FREE(params);
- SAFE_FREE(data);
+ DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
+ outsize = ERROR_DOS(ERRSRV,ERRerror);
+ }
+ return outsize;
+}
+
+/****************************************************************************
+ Reply to a SMBtrans2.
+ ****************************************************************************/
+
+int reply_trans2(connection_struct *conn, char *inbuf,char *outbuf,
+ int size, int bufsize)
+{
+ int outsize = 0;
+ unsigned int dsoff = SVAL(inbuf, smb_dsoff);
+ unsigned int dscnt = SVAL(inbuf, smb_dscnt);
+ unsigned int psoff = SVAL(inbuf, smb_psoff);
+ unsigned int pscnt = SVAL(inbuf, smb_pscnt);
+ unsigned int tran_call = SVAL(inbuf, smb_setup0);
+ struct trans_state *state;
+ NTSTATUS result;
+
+ START_PROFILE(SMBtrans2);
+
+ if (!NT_STATUS_IS_OK(allow_new_trans(conn->pending_trans,
+ SVAL(inbuf, smb_mid)))) {
+ DEBUG(2, ("Got invalid trans2 request: %s\n",
+ nt_errstr(result)));
END_PROFILE(SMBtrans2);
- srv_signing_trans_stop();
- return ERROR_DOS(ERRSRV,ERRerror);
+ return ERROR_NT(result);
}
-
- /* As we do not know how many data packets will need to be
- returned here the various call_trans2xxxx calls
- must send their own. Thus a call_trans2xxx routine only
- returns a value other than -1 when it wants to send
- an error packet.
- */
-
- srv_signing_trans_stop();
- SAFE_FREE(params);
- SAFE_FREE(data);
+ if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
+ && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
+ END_PROFILE(SMBtrans2);
+ return ERROR_DOS(ERRSRV,ERRaccess);
+ }
+
+ if ((state = TALLOC_P(NULL, struct trans_state)) == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ END_PROFILE(SMBtrans2);
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ state->cmd = SMBtrans2;
+
+ state->mid = SVAL(inbuf, smb_mid);
+ state->vuid = SVAL(inbuf, smb_uid);
+ state->setup_count = SVAL(inbuf, smb_suwcnt);
+ state->total_param = SVAL(inbuf, smb_tpscnt);
+ state->param = NULL;
+ state->total_data = SVAL(inbuf, smb_tdscnt);
+ state->data = NULL;
+ state->max_param_return = SVAL(inbuf, smb_mprcnt);
+ state->max_data_return = SVAL(inbuf, smb_mdrcnt);
+ state->max_setup_return = SVAL(inbuf, smb_msrcnt);
+ state->close_on_completion = BITSETW(inbuf+smb_vwv5,0);
+ state->one_way = BITSETW(inbuf+smb_vwv5,1);
+
+ state->call = tran_call;
+
+ /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
+ is so as a sanity check */
+ if (state->setup_count != 1) {
+ /*
+ * Need to have rc=0 for ioctl to get job id for OS/2.
+ * Network printing will fail if function is not successful.
+ * Similar function in reply.c will be used if protocol
+ * is LANMAN1.0 instead of LM1.2X002.
+ * Until DosPrintSetJobInfo with PRJINFO3 is supported,
+ * outbuf doesn't have to be set(only job id is used).
+ */
+ if ( (state->setup_count == 4) && (tran_call == TRANSACT2_IOCTL) &&
+ (SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
+ (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+ DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
+ } else {
+ DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
+ DEBUG(2,("Transaction is %d\n",tran_call));
+ END_PROFILE(SMBtrans2);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ }
+
+ if ((dscnt > state->total_data) || (pscnt > state->total_param))
+ goto bad_param;
+
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->data = SMB_MALLOC(state->total_data);
+ if (state->data == NULL) {
+ DEBUG(0,("reply_trans2: data malloc fail for %u "
+ "bytes !\n", state->total_data));
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans2);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
+ goto bad_param;
+ if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
+ (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
+ goto bad_param;
+
+ memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
+ }
+
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->param = SMB_MALLOC(state->total_param);
+ if (state->param == NULL) {
+ DEBUG(0,("reply_trans: param malloc fail for %u "
+ "bytes !\n", state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
+ goto bad_param;
+ if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
+ (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
+ goto bad_param;
+
+ memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
+ }
+
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if ((state->received_param == state->total_param) &&
+ (state->received_data == state->total_data)) {
+
+ outsize = handle_trans2(conn, state, inbuf, outbuf,
+ size, bufsize);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ return outsize;
+ }
+
+ DLIST_ADD(conn->pending_trans, state);
+
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,True);
+ show_msg(outbuf);
END_PROFILE(SMBtrans2);
- return outsize; /* If a correct response was needed the
- call_trans2xxx calls have already sent
- it. If outsize != -1 then it is returning */
+ return outsize;
bad_param:
- srv_signing_trans_stop();
- SAFE_FREE(params);
- SAFE_FREE(data);
+ DEBUG(0,("reply_trans2: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
END_PROFILE(SMBtrans2);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
+
+
+/****************************************************************************
+ Reply to a SMBtranss2
+ ****************************************************************************/
+
+int reply_transs2(connection_struct *conn,
+ char *inbuf,char *outbuf,int size,int bufsize)
+{
+ int outsize = 0;
+ unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
+
+ START_PROFILE(SMBtranss2);
+
+ show_msg(inbuf);
+
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == SVAL(inbuf,smb_mid)) {
+ break;
+ }
+ }
+
+ if ((state == NULL) || (state->cmd != SMBtrans2)) {
+ END_PROFILE(SMBtranss2);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ /* Revise state->total_param and state->total_data in case they have
+ changed downwards */
+
+ if (SVAL(inbuf, smb_tpscnt) < state->total_param)
+ state->total_param = SVAL(inbuf, smb_tpscnt);
+ if (SVAL(inbuf, smb_tdscnt) < state->total_data)
+ state->total_data = SVAL(inbuf, smb_tdscnt);
+
+ pcnt = SVAL(inbuf, smb_spscnt);
+ poff = SVAL(inbuf, smb_spsoff);
+ pdisp = SVAL(inbuf, smb_spsdisp);
+
+ dcnt = SVAL(inbuf, smb_sdscnt);
+ doff = SVAL(inbuf, smb_sdsoff);
+ ddisp = SVAL(inbuf, smb_sdsdisp);
+
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
+
+ if (pcnt) {
+ if (pdisp+pcnt > state->total_param)
+ goto bad_param;
+ if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
+ goto bad_param;
+ if (pdisp > state->total_param)
+ goto bad_param;
+ if ((smb_base(inbuf) + poff + pcnt > inbuf + size) ||
+ (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->param + pdisp < state->param)
+ goto bad_param;
+
+ memcpy(state->param+pdisp,smb_base(inbuf)+poff,
+ pcnt);
+ }
+
+ if (dcnt) {
+ if (ddisp+dcnt > state->total_data)
+ goto bad_param;
+ if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
+ goto bad_param;
+ if (ddisp > state->total_data)
+ goto bad_param;
+ if ((smb_base(inbuf) + doff + dcnt > inbuf + size) ||
+ (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->data + ddisp < state->data)
+ goto bad_param;
+
+ memcpy(state->data+ddisp, smb_base(inbuf)+doff,
+ dcnt);
+ }
+
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBtranss);
+ return -1;
+ }
+
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBtranss2 which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBtrans2);
+
+ outsize = handle_trans2(conn, state, inbuf, outbuf, size, bufsize);
+
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+
+ if (outsize == 0) {
+ END_PROFILE(SMBtranss);
+ return(ERROR_DOS(ERRSRV,ERRnosupport));
+ }
+
+ END_PROFILE(SMBtranss2);
+ return(outsize);
+
+ bad_param:
+
+ DEBUG(0,("reply_transs2: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtranss2);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+}
diff --git a/source3/smbd/vfs-wrap.c b/source3/smbd/vfs-wrap.c
index bbb7b5bb30..55bf146c20 100644
--- a/source3/smbd/vfs-wrap.c
+++ b/source3/smbd/vfs-wrap.c
@@ -759,11 +759,21 @@ BOOL vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, int op,
BOOL result;
START_PROFILE(syscall_fcntl_lock);
- result = fcntl_lock(fd, op, offset, count,type);
+ result = fcntl_lock(fd, op, offset, count, type);
END_PROFILE(syscall_fcntl_lock);
return result;
}
+BOOL vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+ BOOL result;
+
+ START_PROFILE(syscall_fcntl_getlock);
+ result = fcntl_getlock(fd, poffset, pcount, ptype, ppid);
+ END_PROFILE(syscall_fcntl_getlock);
+ return result;
+}
+
int vfswrap_symlink(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath)
{
int result;
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 07e18caa5c..9a6327b33b 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -95,6 +95,7 @@ static struct vfs_ops default_vfs = {
vfswrap_utime,
vfswrap_ftruncate,
vfswrap_lock,
+ vfswrap_getlock,
vfswrap_symlink,
vfswrap_readlink,
vfswrap_link,