summaryrefslogtreecommitdiffstats
path: root/source/smbd
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2002-02-01 22:15:18 +0000
committerJeremy Allison <jra@samba.org>2002-02-01 22:15:18 +0000
commit8d63a817bb04da3c7cc43e342a9034f5f23c5041 (patch)
treede549371c7728978ab045eab1a658b29007cc9ad /source/smbd
parentf98c14e8d6d8f1def0edcd02e1dfe66bab8a2ab6 (diff)
downloadsamba-8d63a817bb04da3c7cc43e342a9034f5f23c5041.tar.gz
samba-8d63a817bb04da3c7cc43e342a9034f5f23c5041.tar.xz
samba-8d63a817bb04da3c7cc43e342a9034f5f23c5041.zip
Move over to RELEASE branch.
Jeremy.
Diffstat (limited to 'source/smbd')
-rw-r--r--source/smbd/.cvsignore2
-rw-r--r--source/smbd/blocking.c490
-rw-r--r--source/smbd/chgpasswd.c8
-rw-r--r--source/smbd/close.c47
-rw-r--r--source/smbd/conn.c6
-rw-r--r--source/smbd/connection.c11
-rw-r--r--source/smbd/dfree.c3
-rw-r--r--source/smbd/dir.c59
-rw-r--r--source/smbd/dosmode.c2
-rw-r--r--source/smbd/error.c111
-rw-r--r--source/smbd/fileio.c161
-rw-r--r--source/smbd/filename.c28
-rw-r--r--source/smbd/files.c81
-rw-r--r--source/smbd/groupname.c17
-rw-r--r--source/smbd/ipc.c35
-rw-r--r--source/smbd/lanman.c146
-rw-r--r--source/smbd/mangle.c9
-rw-r--r--source/smbd/message.c10
-rw-r--r--source/smbd/negprot.c5
-rw-r--r--source/smbd/noquotas.c2
-rw-r--r--source/smbd/notify.c55
-rw-r--r--source/smbd/notify_hash.c78
-rw-r--r--source/smbd/notify_kernel.c3
-rw-r--r--source/smbd/nttrans.c361
-rw-r--r--source/smbd/open.c109
-rw-r--r--source/smbd/oplock.c1623
-rw-r--r--source/smbd/oplock_irix.c180
-rw-r--r--source/smbd/oplock_linux.c97
-rw-r--r--source/smbd/password.c440
-rw-r--r--source/smbd/pipes.c20
-rw-r--r--source/smbd/posix_acls.c102
-rw-r--r--source/smbd/process.c68
-rw-r--r--source/smbd/quotas.c49
-rw-r--r--source/smbd/reply.c1155
-rw-r--r--source/smbd/sec_ctx.c23
-rw-r--r--source/smbd/server.c114
-rw-r--r--source/smbd/service.c98
-rw-r--r--source/smbd/session.c9
-rw-r--r--source/smbd/trans2.c4250
-rw-r--r--source/smbd/uid.c251
-rw-r--r--source/smbd/utmp.c79
-rw-r--r--source/smbd/vfs-wrap.c123
-rw-r--r--source/smbd/vfs.c111
43 files changed, 6007 insertions, 4624 deletions
diff --git a/source/smbd/.cvsignore b/source/smbd/.cvsignore
index e69de29bb2d..5f2a5c4cf75 100644
--- a/source/smbd/.cvsignore
+++ b/source/smbd/.cvsignore
@@ -0,0 +1,2 @@
+*.po
+*.po32
diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c
index 6f633c0bc20..0d2a99b3f07 100644
--- a/source/smbd/blocking.c
+++ b/source/smbd/blocking.c
@@ -20,7 +20,7 @@
*/
#include "includes.h"
-extern int DEBUGLEVEL;
+
extern char *OutBuffer;
/****************************************************************************
@@ -46,8 +46,8 @@ static ubi_slList blocking_lock_queue = { NULL, (ubi_slNodePtr)&blocking_lock_qu
static void free_blocking_lock_record(blocking_lock_record *blr)
{
- free(blr->inbuf);
- free((char *)blr);
+ SAFE_FREE(blr->inbuf);
+ SAFE_FREE(blr);
}
/****************************************************************************
@@ -103,7 +103,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int
if((blr->inbuf = (char *)malloc(length)) == NULL) {
DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" ));
- free((char *)blr);
+ SAFE_FREE(blr);
return False;
}
@@ -134,7 +134,7 @@ static void send_blocking_reply(char *outbuf, int outsize)
smb_setlen(outbuf,outsize - 4);
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("send_blocking_reply: send_smb failed.\n");
+ exit_server("send_blocking_reply: send_smb failed.");
}
/****************************************************************************
@@ -170,15 +170,15 @@ static void reply_lockingX_success(blocking_lock_record *blr)
Return a generic lock fail error blocking call.
*****************************************************************************/
-static void generic_blocking_lock_error(blocking_lock_record *blr, int eclass, int32 ecode)
+static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS status)
{
char *outbuf = OutBuffer;
char *inbuf = blr->inbuf;
construct_reply_common(inbuf, outbuf);
- ERROR(eclass,ecode);
+ ERROR_NT(status);
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("generic_blocking_lock_error: send_smb failed.\n");
+ exit_server("generic_blocking_lock_error: send_smb failed.");
}
/****************************************************************************
@@ -186,72 +186,68 @@ static void generic_blocking_lock_error(blocking_lock_record *blr, int eclass, i
obtained first.
*****************************************************************************/
-static void reply_lockingX_error(blocking_lock_record *blr, int eclass, int32 ecode)
+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;
- unsigned char locktype = CVAL(inbuf,smb_vwv3);
- BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
- char *data;
- int i;
-
- data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
-
- /*
- * Data now points at the beginning of the list
- * of smb_lkrng structs.
- */
-
- /*
- * Ensure we don't do a remove on the lock that just failed,
- * as under POSIX rules, if we have a lock already there, we
- * will delete it (and we shouldn't) .....
- */
-
- for(i = blr->lock_num - 1; i >= 0; i--) {
- int dummy1;
- uint32 dummy2;
- BOOL err;
-
- 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);
-
- /*
- * We know err cannot be set as if it was the lock
- * request would never have been queued. JRA.
- */
-
- do_unlock(fsp,conn,lock_pid,count,offset,&dummy1,&dummy2);
- }
-
- generic_blocking_lock_error(blr, eclass, ecode);
+ 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;
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ char *data;
+ int i;
+
+ data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
+
+ /*
+ * Data now points at the beginning of the list
+ * of smb_lkrng structs.
+ */
+
+ /*
+ * Ensure we don't do a remove on the lock that just failed,
+ * as under POSIX rules, if we have a lock already there, we
+ * will delete it (and we shouldn't) .....
+ */
+
+ for(i = blr->lock_num - 1; i >= 0; i--) {
+ BOOL err;
+
+ 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);
+
+ /*
+ * We know err cannot be set as if it was the lock
+ * request would never have been queued. JRA.
+ */
+
+ do_unlock(fsp,conn,lock_pid,count,offset);
+ }
+
+ generic_blocking_lock_error(blr, status);
}
/****************************************************************************
Return a lock fail error.
*****************************************************************************/
-static void blocking_lock_reply_error(blocking_lock_record *blr, int eclass, int32 ecode)
+static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
{
- switch(blr->com_type) {
- case SMBlock:
- generic_blocking_lock_error(blr, eclass, ecode);
- break;
- case SMBlockread:
- generic_blocking_lock_error(blr, eclass, ecode);
- break;
- case SMBlockingX:
- reply_lockingX_error(blr, eclass, ecode);
- 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");
- }
+ switch(blr->com_type) {
+ case SMBlock:
+ case SMBlockread:
+ generic_blocking_lock_error(blr, status);
+ break;
+ case SMBlockingX:
+ reply_lockingX_error(blr, status);
+ 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");
+ }
}
/****************************************************************************
@@ -261,65 +257,68 @@ static void blocking_lock_reply_error(blocking_lock_record *blr, int eclass, int
static BOOL process_lockread(blocking_lock_record *blr)
{
- char *outbuf = OutBuffer;
- char *inbuf = blr->inbuf;
- ssize_t nread = -1;
- char *data;
- int outsize = 0;
- SMB_OFF_T startpos;
- size_t numtoread;
- int eclass;
- uint32 ecode;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
- files_struct *fsp = blr->fsp;
-
- numtoread = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
-
- numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
- data = smb_buf(outbuf) + 3;
+ char *outbuf = OutBuffer;
+ char *inbuf = blr->inbuf;
+ ssize_t nread = -1;
+ char *data, *p;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t numtoread;
+ NTSTATUS status;
+ connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
+ files_struct *fsp = blr->fsp;
+
+ numtoread = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+
+ numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
+ data = smb_buf(outbuf) + 3;
- if(!do_lock( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, READ_LOCK, &eclass, &ecode)) {
- if((errno != EACCES) && (errno != EAGAIN)) {
- /*
- * We have other than a "can't get lock" POSIX
- * error. Send an error.
- * Return True so we get dequeued.
- */
-
- generic_blocking_lock_error(blr, eclass, ecode);
- return True;
- }
-
- /*
- * Still waiting for lock....
- */
-
- DEBUG(10,("process_lockread: failed to get lock for file = %s. Still waiting....\n",
- fsp->fsp_name));
- return False;
- }
-
- nread = read_file(fsp,data,startpos,numtoread);
-
- if (nread < 0) {
- generic_blocking_lock_error(blr,ERRDOS,ERRnoaccess);
- return True;
- }
-
- construct_reply_common(inbuf, outbuf);
- outsize = set_message(outbuf,5,3,True);
-
- outsize += nread;
- SSVAL(outbuf,smb_vwv0,nread);
- SSVAL(outbuf,smb_vwv5,nread+3);
- SSVAL(smb_buf(outbuf),1,nread);
-
- DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%d nread=%d\n",
- fsp->fsp_name, fsp->fnum, (int)numtoread, (int)nread ) );
-
- send_blocking_reply(outbuf,outsize);
- return True;
+ status = do_lock( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread,
+ (SMB_BIG_UINT)startpos, READ_LOCK);
+ if (NT_STATUS_V(status)) {
+ if ((errno != EACCES) && (errno != EAGAIN)) {
+ /*
+ * We have other than a "can't get lock" POSIX
+ * error. Send an error.
+ * Return True so we get dequeued.
+ */
+ generic_blocking_lock_error(blr, status);
+ return True;
+ }
+
+ /*
+ * Still waiting for lock....
+ */
+
+ DEBUG(10,("process_lockread: failed to get lock for file = %s. Still waiting....\n",
+ fsp->fsp_name));
+ return False;
+ }
+
+ nread = read_file(fsp,data,startpos,numtoread);
+
+ if (nread < 0) {
+ generic_blocking_lock_error(blr,NT_STATUS_ACCESS_DENIED);
+ return True;
+ }
+
+ construct_reply_common(inbuf, outbuf);
+ outsize = set_message(outbuf,5,0,True);
+
+ outsize += nread;
+ SSVAL(outbuf,smb_vwv0,nread);
+ SSVAL(outbuf,smb_vwv5,nread+3);
+ p = smb_buf(outbuf);
+ *p++ = 1;
+ SSVAL(p,0,nread); p += 2;
+ set_message_end(outbuf, p+nread);
+
+ DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%d nread=%d\n",
+ fsp->fsp_name, fsp->fnum, (int)numtoread, (int)nread ) );
+
+ send_blocking_reply(outbuf,outsize);
+ return True;
}
/****************************************************************************
@@ -329,52 +328,50 @@ static BOOL process_lockread(blocking_lock_record *blr)
static BOOL process_lock(blocking_lock_record *blr)
{
- char *outbuf = OutBuffer;
- char *inbuf = blr->inbuf;
- int outsize;
- SMB_OFF_T count = 0, offset = 0;
- int eclass;
- uint32 ecode;
- connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
- files_struct *fsp = blr->fsp;
-
- count = IVAL(inbuf,smb_vwv1);
- offset = IVAL(inbuf,smb_vwv3);
-
- errno = 0;
- if (!do_lock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)count, (SMB_BIG_UINT)offset, WRITE_LOCK, &eclass, &ecode)) {
- if((errno != EACCES) && (errno != EAGAIN)) {
-
- /*
- * We have other than a "can't get lock" POSIX
- * error. Send an error.
- * Return True so we get dequeued.
- */
-
- blocking_lock_reply_error(blr, eclass, ecode);
- return True;
- }
-
- /*
- * Still can't get the lock - keep waiting.
- */
-
- DEBUG(10,("process_lock: failed to get lock for file = %s. Still waiting....\n",
- fsp->fsp_name));
- return False;
- }
-
- /*
- * Success - we got the lock.
- */
-
- DEBUG(3,("process_lock : file=%s fnum=%d offset=%.0f count=%.0f\n",
- fsp->fsp_name, fsp->fnum, (double)offset, (double)count));
-
- construct_reply_common(inbuf, outbuf);
- outsize = set_message(outbuf,0,0,True);
- send_blocking_reply(outbuf,outsize);
- return True;
+ char *outbuf = OutBuffer;
+ char *inbuf = blr->inbuf;
+ int outsize;
+ SMB_OFF_T count = 0, offset = 0;
+ NTSTATUS status;
+ connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
+ files_struct *fsp = blr->fsp;
+
+ count = IVAL(inbuf,smb_vwv1);
+ offset = IVAL(inbuf,smb_vwv3);
+
+ errno = 0;
+ status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)count,
+ (SMB_BIG_UINT)offset, WRITE_LOCK);
+ if (NT_STATUS_IS_ERR(status)) {
+ if((errno != EACCES) && (errno != EAGAIN)) {
+ /*
+ * We have other than a "can't get lock" POSIX
+ * error. Send an error.
+ * Return True so we get dequeued.
+ */
+
+ blocking_lock_reply_error(blr, status);
+ return True;
+ }
+ /*
+ * Still can't get the lock - keep waiting.
+ */
+ DEBUG(10,("process_lock: failed to get lock for file = %s. Still waiting....\n",
+ fsp->fsp_name));
+ return False;
+ }
+
+ /*
+ * Success - we got the lock.
+ */
+
+ DEBUG(3,("process_lock : file=%s fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fsp_name, fsp->fnum, (double)offset, (double)count));
+
+ construct_reply_common(inbuf, outbuf);
+ outsize = set_message(outbuf,0,0,True);
+ send_blocking_reply(outbuf,outsize);
+ return True;
}
/****************************************************************************
@@ -384,75 +381,72 @@ static BOOL process_lock(blocking_lock_record *blr)
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;
- uint16 lock_pid;
- BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
- char *data;
- int eclass=0;
- uint32 ecode=0;
-
- data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
-
- /*
- * Data now points at the beginning of the list
- * of smb_lkrng structs.
- */
-
- for(; blr->lock_num < num_locks; blr->lock_num++) {
- BOOL err;
-
- lock_pid = get_lock_pid( data, blr->lock_num, large_file_format);
- count = get_lock_count( data, blr->lock_num, large_file_format);
- offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
-
- /*
- * We know err cannot be set as if it was the lock
- * request would never have been queued. JRA.
- */
- errno = 0;
- if(!do_lock(fsp,conn,lock_pid,count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
- &eclass, &ecode))
- break;
- }
-
- if(blr->lock_num == num_locks) {
-
- /*
- * Success - we got all the locks.
- */
-
- DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n",
- fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) );
-
- reply_lockingX_success(blr);
- return True;
-
- } else if((errno != EACCES) && (errno != EAGAIN)) {
-
- /*
- * We have other than a "can't get lock" POSIX
- * error. Free any locks we had and return an error.
- * Return True so we get dequeued.
- */
-
- blocking_lock_reply_error(blr, eclass, ecode);
- return True;
- }
-
- /*
- * Still can't get all the locks - keep waiting.
- */
-
- DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \
-Waiting....\n", blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum));
-
- return False;
+ 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;
+ uint16 lock_pid;
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ char *data;
+ NTSTATUS status = NT_STATUS_OK;
+
+ data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
+
+ /*
+ * Data now points at the beginning of the list
+ * of smb_lkrng structs.
+ */
+
+ for(; blr->lock_num < num_locks; blr->lock_num++) {
+ BOOL err;
+
+ lock_pid = get_lock_pid( data, blr->lock_num, large_file_format);
+ count = get_lock_count( data, blr->lock_num, large_file_format);
+ offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
+
+ /*
+ * We know err cannot be set as if it was the lock
+ * request would never have been queued. JRA.
+ */
+ errno = 0;
+ status = do_lock(fsp,conn,lock_pid,count,offset,
+ ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
+ if (NT_STATUS_IS_ERR(status)) break;
+ }
+
+ if(blr->lock_num == num_locks) {
+ /*
+ * Success - we got all the locks.
+ */
+
+ DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n",
+ fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) );
+
+ reply_lockingX_success(blr);
+ return True;
+ } else if ((errno != EACCES) && (errno != EAGAIN)) {
+ /*
+ * We have other than a "can't get lock" POSIX
+ * error. Free any locks we had and return an error.
+ * Return True so we get dequeued.
+ */
+
+ blocking_lock_reply_error(blr, status);
+ return True;
+ }
+
+ /*
+ * Still can't get all the locks - keep waiting.
+ */
+
+ DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \
+Waiting....\n",
+ blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum));
+
+ return False;
}
/****************************************************************************
@@ -517,7 +511,7 @@ void remove_pending_lock_requests_by_mid(int mid)
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 ));
- blocking_lock_reply_error(blr,0,NT_STATUS_CANCELLED);
+ blocking_lock_reply_error(blr,NT_STATUS_CANCELLED);
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
continue;
@@ -582,33 +576,33 @@ void process_blocking_lock_queue(time_t t)
DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
fsp->fnum, fsp->fsp_name ));
- blocking_lock_reply_error(blr,ERRSRV,ERRaccess);
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
continue;
}
- if(!become_user(conn,vuid)) {
+ if(!change_to_user(conn,vuid)) {
DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
vuid ));
/*
* Remove the entry and return an error to the client.
*/
- blocking_lock_reply_error(blr,ERRSRV,ERRaccess);
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
continue;
}
- if(!become_service(conn,True)) {
+ if(!set_current_service(conn,True)) {
DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
/*
* Remove the entry and return an error to the client.
*/
- blocking_lock_reply_error(blr,ERRSRV,ERRaccess);
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
- unbecome_user();
+ change_to_root_user();
continue;
}
@@ -621,11 +615,11 @@ void process_blocking_lock_queue(time_t t)
if(blocking_lock_record_process(blr)) {
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
- unbecome_user();
+ change_to_root_user();
continue;
}
- unbecome_user();
+ change_to_root_user();
/*
* Move to the next in the list.
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index 245c1d1ea9b..bc91d776936 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -49,7 +49,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
extern struct passdb_ops pdb_ops;
#if ALLOW_CHANGE_PASSWORD
@@ -309,6 +308,12 @@ static int talktochild(int master, char *seq)
pwd_sub(issue);
}
+ if (!strequal(issue, ".")) {
+ /* we have one final issue to send */
+ fstrcpy(expected, ".");
+ if (!expect(master, issue, expected))
+ return False;
+ }
return (count > 0);
}
@@ -754,6 +759,7 @@ BOOL check_oem_password(char *user,
if (ret == False) {
DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
+ pdb_free_sam(sampass);
return False;
}
diff --git a/source/smbd/close.c b/source/smbd/close.c
index 7c0672efe0d..ca030ed1404 100644
--- a/source/smbd/close.c
+++ b/source/smbd/close.c
@@ -21,8 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
/****************************************************************************
run a file if it is a magic script
****************************************************************************/
@@ -102,10 +100,7 @@ static int close_filestruct(files_struct *fsp)
fsp->stat_open = False;
conn->num_files_open--;
- if(fsp->wbmpx_ptr) {
- free((char *)fsp->wbmpx_ptr);
- fsp->wbmpx_ptr = NULL;
- }
+ SAFE_FREE(fsp->wbmpx_ptr);
return ret;
}
@@ -172,21 +167,21 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
* reference to a file.
*/
- if (normal_close && delete_on_close) {
- DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n",
- fsp->fsp_name));
+ if (normal_close && delete_on_close) {
+ DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n",
+ fsp->fsp_name));
if(fsp->conn->vfs_ops.unlink(conn,dos_to_unix(fsp->fsp_name, False)) != 0) {
- /*
- * This call can potentially fail as another smbd may have
- * had the file open with delete on close set and deleted
- * it when its last reference to this file went away. Hence
- * we log this but not at debug level zero.
- */
-
- DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \
+ /*
+ * This call can potentially fail as another smbd may have
+ * had the file open with delete on close set and deleted
+ * it when its last reference to this file went away. Hence
+ * we log this but not at debug level zero.
+ */
+
+ DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \
with error %s\n", fsp->fsp_name, strerror(errno) ));
- }
- }
+ }
+ }
unlock_share_entry_fsp(fsp);
@@ -202,14 +197,22 @@ with error %s\n", fsp->fsp_name, strerror(errno) ));
check_magic(fsp,conn);
}
+ /*
+ * Ensure pending modtime is set after close.
+ */
+
+ if(fsp->pending_modtime) {
+ int saved_errno = errno;
+ set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
+ errno = saved_errno;
+ }
DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
conn->user,fsp->fsp_name,
conn->num_files_open, err ? strerror(err) : ""));
- if (fsp->fsp_name) {
+ if (fsp->fsp_name)
string_free(&fsp->fsp_name);
- }
file_free(fsp);
@@ -244,7 +247,7 @@ static int close_directory(files_struct *fsp, BOOL normal_close)
if(ok)
remove_pending_change_notify_requests_by_filename(fsp);
- }
+ }
/*
* Do the code common to files and directories.
diff --git a/source/smbd/conn.c b/source/smbd/conn.c
index 725ab22dc44..7e8a8383213 100644
--- a/source/smbd/conn.c
+++ b/source/smbd/conn.c
@@ -21,8 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
/* set these to define the limits of the server. NOTE These are on a
per-client basis. Thus any one machine can't connect to more than
MAX_CONNECTIONS services, but any number of machines may connect at
@@ -177,7 +175,7 @@ void conn_free(connection_struct *conn)
DLIST_REMOVE(Connections, conn);
if (conn->ngroups && conn->groups) {
- free(conn->groups);
+ SAFE_FREE(conn->groups);
conn->groups = NULL;
conn->ngroups = 0;
}
@@ -196,7 +194,7 @@ void conn_free(connection_struct *conn)
num_open--;
ZERO_STRUCTP(conn);
- free(conn);
+ SAFE_FREE(conn);
}
diff --git a/source/smbd/connection.c b/source/smbd/connection.c
index 9e074a8e809..3ca4021abe4 100644
--- a/source/smbd/connection.c
+++ b/source/smbd/connection.c
@@ -25,8 +25,6 @@
extern fstring remote_machine;
static TDB_CONTEXT *tdb;
-extern int DEBUGLEVEL;
-
/****************************************************************************
Return the connection tdb context (used for message send all).
****************************************************************************/
@@ -40,7 +38,7 @@ TDB_CONTEXT *conn_tdb_ctx(void)
Delete a connection record.
****************************************************************************/
-BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
+BOOL yield_connection(connection_struct *conn,char *name)
{
struct connections_key key;
TDB_DATA kbuf;
@@ -59,8 +57,9 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
kbuf.dsize = sizeof(key);
if (tdb_delete(tdb, kbuf) != 0) {
- DEBUG(0,("yield_connection: tdb_delete for name %s failed with error %s.\n",
- name, tdb_errorstr(tdb) ));
+ int dbg_lvl = (!conn && (tdb_error(tdb) == TDB_ERR_NOEXIST)) ? 3 : 0;
+ DEBUG(dbg_lvl,("yield_connection: tdb_delete for name %s failed with error %s.\n",
+ name, tdb_errorstr(tdb) ));
return (False);
}
@@ -88,7 +87,7 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u
memcpy(&crec, dbuf.dptr, sizeof(crec));
- if (crec.cnum == -1)
+ if (crec.cnum == -1)
return 0;
/* If the pid was not found delete the entry from connections.tdb */
diff --git a/source/smbd/dfree.c b/source/smbd/dfree.c
index 64c6182cd8d..034e1a093d3 100644
--- a/source/smbd/dfree.c
+++ b/source/smbd/dfree.c
@@ -21,9 +21,6 @@
#include "includes.h"
-
-extern int DEBUGLEVEL;
-
/****************************************************************************
normalise for DOS usage
****************************************************************************/
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index fa9cbdc4a2a..789ff919eea 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -21,8 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
/*
This module implements directory related functions for Samba.
*/
@@ -246,10 +244,9 @@ static void dptr_close_internal(dptr_struct *dptr)
}
/* Lanman 2 specific code */
- if (dptr->wcard)
- free(dptr->wcard);
+ SAFE_FREE(dptr->wcard);
string_set(&dptr->path,"");
- free((char *)dptr);
+ SAFE_FREE(dptr);
}
/****************************************************************************
@@ -438,7 +435,7 @@ int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect
if(dptr->dnum == -1 || dptr->dnum > 254) {
DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
- free((char *)dptr);
+ SAFE_FREE(dptr);
return -1;
}
}
@@ -467,7 +464,7 @@ int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect
if(dptr->dnum == -1 || dptr->dnum < 255) {
DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
- free((char *)dptr);
+ SAFE_FREE(dptr);
return -1;
}
}
@@ -669,12 +666,47 @@ check to see if a user can read a file. This is only approximate,
it is used as part of the "hide unreadable" option. Don't
use it for anything security sensitive
********************************************************************/
+
static BOOL user_can_read_file(connection_struct *conn, char *name)
{
+ extern struct current_user current_user;
SMB_STRUCT_STAT ste;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ files_struct *fsp;
+ int smb_action;
+ NTSTATUS status;
+ uint32 access_granted;
+
+ ZERO_STRUCT(ste);
/* if we can't stat it does not show it */
- if (vfs_stat(conn, name, &ste) != 0) return False;
+ if (vfs_stat(conn, name, &ste) != 0)
+ return False;
+
+ /* Pseudo-open the file (note - no fd's created). */
+
+ if(S_ISDIR(ste.st_mode))
+ fsp = open_directory(conn, name, &ste, SET_DENY_MODE(DENY_NONE), FILE_OPEN,
+ unix_mode(conn,aRONLY|aDIR, name), &smb_action);
+ else
+ fsp = open_file_stat(conn,name,&ste,DOS_OPEN_RDONLY,&smb_action);
+ if (!fsp)
+ return False;
+
+ /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
+ sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
+ close_file(fsp, True);
+
+ /* No access if SD get failed. */
+ if (!sd_size)
+ return False;
+
+ return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
+ &access_granted, &status);
+
+#if 0
+ /* Old - crappy check :-). JRA */
if (ste.st_uid == conn->uid) {
return (ste.st_mode & S_IRUSR) == S_IRUSR;
@@ -691,6 +723,7 @@ static BOOL user_can_read_file(connection_struct *conn, char *name)
}
return (ste.st_mode & S_IROTH) == S_IROTH;
+#endif
}
/*******************************************************************
@@ -733,7 +766,7 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
ret = user_can_read_file(conn, entry);
- free(entry);
+ SAFE_FREE(entry);
}
if (!ret) continue;
}
@@ -768,8 +801,8 @@ void CloseDir(void *p)
{
Dir *dirp = (Dir *)p;
if (!dirp) return;
- if (dirp->data) free(dirp->data);
- free(dirp);
+ SAFE_FREE(dirp->data);
+ SAFE_FREE(dirp);
}
/*******************************************************************
@@ -878,7 +911,7 @@ void DirCacheAdd( char *path, char *name, char *dname, int snum )
/* Free excess cache entries. */
while( DIRCACHESIZE < dir_cache->count )
- free( ubi_dlRemTail( dir_cache ) );
+ safe_free( ubi_dlRemTail( dir_cache ) );
}
@@ -930,7 +963,7 @@ void DirCacheFlush(int snum)
NULL != entry; ) {
next = ubi_dlNext( entry );
if( entry->snum == snum )
- free( ubi_dlRemThis( dir_cache, entry ) );
+ safe_free( ubi_dlRemThis( dir_cache, entry ) );
entry = (dir_cache_entry *)next;
}
}
diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c
index 9ec1fa26069..d7b40198771 100644
--- a/source/smbd/dosmode.c
+++ b/source/smbd/dosmode.c
@@ -21,8 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
/****************************************************************************
change a dos mode to a unix mode
base permission for files:
diff --git a/source/smbd/error.c b/source/smbd/error.c
index 164f4e42a56..0a63d520ee6 100644
--- a/source/smbd/error.c
+++ b/source/smbd/error.c
@@ -21,50 +21,39 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-extern uint32 global_client_caps;
-
/* these can be set by some functions to override the error codes */
int unix_ERR_class=SMB_SUCCESS;
int unix_ERR_code=0;
-struct {
- int unixerror;
- int smbclass;
- int smbcode;
-} unix_smb_errmap[] = {
- {EPERM,ERRDOS,ERRnoaccess},
- {EACCES,ERRDOS,ERRnoaccess},
- {ENOENT,ERRDOS,ERRbadfile},
- {ENOTDIR,ERRDOS,ERRbadpath},
- {EIO,ERRHRD,ERRgeneral},
- {EBADF,ERRDOS,ERRbadfid},
- {EINVAL,ERRSRV,ERRsrverror},
- {EEXIST,ERRDOS,ERRfilexists},
- {ENFILE,ERRDOS,ERRnofids},
- {EMFILE,ERRDOS,ERRnofids},
- {ENOSPC,ERRHRD,ERRdiskfull},
-#ifdef EDQUOT
- {EDQUOT,ERRHRD,ERRdiskfull},
-#endif
-#ifdef ENOTEMPTY
- {ENOTEMPTY,ERRDOS,ERRnoaccess},
-#endif
-#ifdef EXDEV
- {EXDEV,ERRDOS,ERRdiffdevice},
-#endif
- {EROFS,ERRHRD,ERRnowrite},
- {0,0,0}
-};
+/* From lib/error.c */
+extern struct unix_error_map unix_dos_nt_errmap[];
+
+/****************************************************************************
+ Create an error packet from a cached error.
+****************************************************************************/
+
+int cached_error_packet(char *outbuf,files_struct *fsp,int line,const char *file)
+{
+ write_bmpx_struct *wbmpx = fsp->wbmpx_ptr;
+
+ int32 eclass = wbmpx->wr_errclass;
+ int32 err = wbmpx->wr_error;
+
+ /* We can now delete the auxiliary struct */
+ SAFE_FREE(wbmpx);
+ return error_packet(outbuf,NT_STATUS_OK,eclass,err,line,file);
+}
/****************************************************************************
Create an error packet from errno.
****************************************************************************/
-int unix_error_packet(char *outbuf,int def_class,uint32 def_code,int line, const char *file)
+int unix_error_packet(char *outbuf,int def_class,uint32 def_code,
+ int line, const char *file)
{
int eclass=def_class;
int ecode=def_code;
+ NTSTATUS ntstatus = NT_STATUS_OK;
int i=0;
if (unix_ERR_class != SMB_SUCCESS) {
@@ -73,44 +62,62 @@ int unix_error_packet(char *outbuf,int def_class,uint32 def_code,int line, const
unix_ERR_class = SMB_SUCCESS;
unix_ERR_code = 0;
} else {
- while (unix_smb_errmap[i].smbclass != 0) {
- if (unix_smb_errmap[i].unixerror == errno) {
- eclass = unix_smb_errmap[i].smbclass;
- ecode = unix_smb_errmap[i].smbcode;
+ while (unix_dos_nt_errmap[i].dos_class != 0) {
+ if (unix_dos_nt_errmap[i].unix_error == errno) {
+ eclass = unix_dos_nt_errmap[i].dos_class;
+ ecode = unix_dos_nt_errmap[i].dos_code;
+ ntstatus = unix_dos_nt_errmap[i].nt_error;
break;
}
i++;
}
}
- return(error_packet(outbuf,0,eclass,ecode,line,file));
+ return error_packet(outbuf,ntstatus,eclass,ecode,line,file);
}
+
/****************************************************************************
Create an error packet. Normally called using the ERROR() macro.
****************************************************************************/
-int error_packet(char *outbuf,uint32 nt_err, int error_class,uint32 error_code,int line, const char *file)
+int error_packet(char *outbuf,NTSTATUS ntstatus,
+ uint8 eclass,uint32 ecode,int line, const char *file)
{
int outsize = set_message(outbuf,0,0,True);
- int cmd = CVAL(outbuf,smb_com);
+ extern uint32 global_client_caps;
if (errno != 0)
DEBUG(3,("error string = %s\n",strerror(errno)));
- if ((global_client_caps & CAP_STATUS32) && (nt_err != 0)) {
- SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
- SIVAL(outbuf,smb_rcls,nt_err);
-
- DEBUG( 3, ( "32 bit error packet at %s(%d) cmd=%d (%s) eclass=%08x [%s]\n",
- file, line, cmd, smb_fn_name(cmd), nt_err, smb_errstr(outbuf) ) );
+ if (global_client_caps & CAP_STATUS32) {
+ if (NT_STATUS_V(ntstatus) == 0 && eclass) {
+ ntstatus = dos_to_ntstatus(eclass, ecode);
+ }
+ SIVAL(outbuf,smb_rcls,NT_STATUS_V(ntstatus));
+ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)|FLAGS2_32_BIT_ERROR_CODES);
+ DEBUG(3,("error packet at %s(%d) cmd=%d (%s) %s\n",
+ file, line,
+ (int)CVAL(outbuf,smb_com),
+ smb_fn_name(CVAL(outbuf,smb_com)),
+ get_nt_error_msg(ntstatus)));
+ return outsize;
+ }
- } else {
- CVAL(outbuf,smb_rcls) = error_class;
- SSVAL(outbuf,smb_err,error_code);
- DEBUG( 3, ( "error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
- file, line, cmd, smb_fn_name(cmd), error_class, error_code ) );
+ if (eclass == 0 && NT_STATUS_V(ntstatus)) {
+ ntstatus_to_dos(ntstatus, &eclass, &ecode);
}
-
- return(outsize);
+
+ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)&~FLAGS2_32_BIT_ERROR_CODES);
+ SSVAL(outbuf,smb_rcls,eclass);
+ SSVAL(outbuf,smb_err,ecode);
+
+ DEBUG(3,("error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
+ file, line,
+ (int)CVAL(outbuf,smb_com),
+ smb_fn_name(CVAL(outbuf,smb_com)),
+ eclass,
+ ecode));
+
+ return outsize;
}
diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c
index c79f0aa89e0..ba60690383b 100644
--- a/source/smbd/fileio.c
+++ b/source/smbd/fileio.c
@@ -21,8 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
static BOOL setup_write_cache(files_struct *, SMB_OFF_T);
/****************************************************************************
@@ -93,34 +91,50 @@ read from a file
ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
{
- ssize_t ret=0,readret;
+ ssize_t ret=0,readret;
- /* you can't read from print files */
- if (fsp->print_file) {
- return -1;
- }
+ /* you can't read from print files */
+ if (fsp->print_file)
+ return -1;
- /*
- * Serve from write cache if we can.
- */
- if(read_from_write_cache(fsp, data, pos, n))
- return n;
+ /*
+ * Serve from write cache if we can.
+ */
- flush_write_cache(fsp, READ_FLUSH);
+ if(read_from_write_cache(fsp, data, pos, n))
+ return n;
- if (seek_file(fsp,pos) == -1) {
- DEBUG(3,("read_file: Failed to seek to %.0f\n",(double)pos));
- return(ret);
- }
+ flush_write_cache(fsp, READ_FLUSH);
+
+ if (seek_file(fsp,pos) == -1) {
+ DEBUG(3,("read_file: Failed to seek to %.0f\n",(double)pos));
+ return(ret);
+ }
- if (n > 0) {
- readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n);
- if (readret == -1)
- return -1;
- if (readret > 0) ret += readret;
- }
+ if (n > 0) {
+#ifdef DMF_FIX
+ int numretries = 3;
+tryagain:
+ readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n);
+ if (readret == -1) {
+ if ((errno == EAGAIN) && numretries) {
+ DEBUG(3,("read_file EAGAIN retry in 10 seconds\n"));
+ (void)sleep(10);
+ --numretries;
+ goto tryagain;
+ }
+ return -1;
+ }
+#else /* NO DMF fix. */
+ readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n);
+ if (readret == -1)
+ return -1;
+#endif
+ if (readret > 0)
+ ret += readret;
+ }
- return(ret);
+ return(ret);
}
/* how many write cache buffers have been allocated */
@@ -163,6 +177,7 @@ ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
if (fsp->conn->vfs_ops.fstat(fsp,fsp->fd,&st) == 0) {
int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
+ fsp->size = st.st_size;
if (MAP_ARCHIVE(fsp->conn) && !IS_DOS_ARCHIVE(dosmode)) {
file_chmod(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st);
}
@@ -223,11 +238,14 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
if(!wcp) {
DO_PROFILE_INC(writecache_direct_writes);
- return real_write_file(fsp, data, pos, n);
+ total_written = real_write_file(fsp, data, pos, n);
+ if ((total_written != -1) && (pos + total_written > fsp->size))
+ fsp->size = pos + total_written;
+ return total_written;
}
- DEBUG(9,("write_file(fd=%d pos=%d size=%d) wofs=%d wsize=%d\n",
- fsp->fd, (int)pos, (int)n, (int)wcp->offset, (int)wcp->data_size));
+ DEBUG(9,("write_file(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n",
+ fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size));
/*
* If we have active cache and it isn't contiguous then we flush.
@@ -256,6 +274,13 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
wcp->data_size = pos + data_used - wcp->offset;
/*
+ * Update the file size if changed.
+ */
+
+ if (wcp->offset + wcp->data_size > wcp->file_size)
+ fsp->size = wcp->file_size = wcp->offset + wcp->data_size;
+
+ /*
* If we used all the data then
* return here.
*/
@@ -298,6 +323,13 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
wcp->data_size = pos + n - wcp->offset;
/*
+ * Update the file size if changed.
+ */
+
+ if (wcp->offset + wcp->data_size > wcp->file_size)
+ fsp->size = wcp->file_size = wcp->offset + wcp->data_size;
+
+ /*
* We don't need to move the start of data, but we
* cut down the amount left by the amount used.
*/
@@ -316,12 +348,15 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
write_path = 2;
} else if ( (pos >= wcp->file_size) &&
+ (wcp->offset + wcp->data_size == wcp->file_size) &&
(pos > wcp->offset + wcp->data_size) &&
(pos < wcp->offset + wcp->alloc_size) ) {
/*
* Non-contiguous write part of which fits within
- * the cache buffer and is extending the file.
+ * the cache buffer and is extending the file
+ * and the cache contents reflect the current
+ * data up to the current end of the file.
*/
size_t data_used;
@@ -348,10 +383,11 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
wcp->data_size = pos + data_used - wcp->offset;
/*
- * Update the known file length.
+ * Update the file size if changed.
*/
- wcp->file_size = wcp->offset + wcp->data_size;
+ if (wcp->offset + wcp->data_size > wcp->file_size)
+ fsp->size = wcp->file_size = wcp->offset + wcp->data_size;
/*
* If we used all the data then
@@ -392,7 +428,7 @@ len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigne
*/
if(pos + n > wcp->file_size)
- wcp->file_size = pos + n;
+ fsp->size = wcp->file_size = pos + n;
/*
* If write would fit in the cache, and is larger than
@@ -404,8 +440,16 @@ len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigne
if ( n <= wcp->alloc_size && n > wcp->data_size) {
cache_flush_needed = True;
} else {
- DO_PROFILE_INC(writecache_direct_writes);
- return real_write_file(fsp, data, pos, n);
+ ssize_t ret = real_write_file(fsp, data, pos, n);
+
+ DO_PROFILE_INC(writecache_direct_writes);
+ if (ret == -1)
+ return ret;
+
+ if (pos + ret > wcp->file_size)
+ fsp->size = wcp->file_size = pos + ret;
+
+ return ret;
}
write_path = 4;
@@ -413,7 +457,7 @@ len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigne
}
if(wcp->data_size > wcp->file_size)
- wcp->file_size = wcp->data_size;
+ fsp->size = wcp->file_size = wcp->data_size;
if (cache_flush_needed) {
DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
@@ -431,8 +475,13 @@ n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
*/
if (n > wcp->alloc_size ) {
- if(real_write_file(fsp, data, pos, n) == -1)
+ ssize_t ret = real_write_file(fsp, data, pos, n);
+ if (ret == -1)
return -1;
+
+ if (pos + ret > wcp->file_size)
+ fsp->size = wcp->file_size = pos + n;
+
DO_PROFILE_INC(writecache_direct_writes);
return total_written + n;
}
@@ -455,7 +504,16 @@ n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
DO_PROFILE_INC(writecache_num_write_caches);
}
wcp->data_size += n;
- DEBUG(9,("cache return %u\n", (unsigned int)n));
+
+ /*
+ * Update the file size if changed.
+ */
+
+ if (wcp->offset + wcp->data_size > wcp->file_size)
+ fsp->size = wcp->file_size = wcp->offset + wcp->data_size;
+ DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n",
+ (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n));
+
total_written += n;
return total_written; /* .... that's a write :) */
}
@@ -482,10 +540,8 @@ void delete_write_cache(files_struct *fsp)
SMB_ASSERT(wcp->data_size == 0);
- free(wcp->data);
- free(wcp);
-
- fsp->wcp = NULL;
+ SAFE_FREE(wcp->data);
+ SAFE_FREE(fsp->wcp);
DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name ));
@@ -518,10 +574,12 @@ static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size)
if((wcp->data = malloc(wcp->alloc_size)) == NULL) {
DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
(unsigned int)wcp->alloc_size ));
- free(wcp);
+ SAFE_FREE(wcp);
return False;
}
+ memset(wcp->data, '\0', wcp->alloc_size );
+
fsp->wcp = wcp;
DO_PROFILE_INC(writecache_allocated_write_caches);
allocated_write_caches++;
@@ -538,8 +596,15 @@ static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size)
void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size)
{
+ fsp->size = file_size;
if(fsp->wcp) {
- flush_write_cache(fsp, SIZECHANGE_FLUSH);
+ /* The cache *must* have been flushed before we do this. */
+ if (fsp->wcp->data_size != 0) {
+ pstring msg;
+ slprintf(msg, sizeof(msg)-1, "set_filelen_write_cache: size change \
+on file %s with write cache size = %u\n", fsp->fsp_name, fsp->wcp->data_size );
+ smb_panic(msg);
+ }
fsp->wcp->file_size = file_size;
}
}
@@ -552,6 +617,7 @@ ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
{
write_cache *wcp = fsp->wcp;
size_t data_size;
+ ssize_t ret;
if(!wcp || !wcp->data_size)
return 0;
@@ -569,7 +635,16 @@ ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
DO_PROFILE_INC(writecache_num_perfect_writes);
#endif
- return real_write_file(fsp, wcp->data, wcp->offset, data_size);
+ ret = real_write_file(fsp, wcp->data, wcp->offset, data_size);
+
+ /*
+ * Ensure file size if kept up to date if write extends file.
+ */
+
+ if ((ret != -1) && (wcp->offset + ret > wcp->file_size))
+ wcp->file_size = wcp->offset + ret;
+
+ return ret;
}
/*******************************************************************
diff --git a/source/smbd/filename.c b/source/smbd/filename.c
index bdbcd81b644..601c488fc9c 100644
--- a/source/smbd/filename.c
+++ b/source/smbd/filename.c
@@ -27,7 +27,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
extern BOOL case_sensitive;
extern BOOL case_preserve;
extern BOOL short_case_preserve;
@@ -293,7 +292,7 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
} else {
pstring rest;
- /* Stat failed - ensure we don't use it. */
+ /* Stat failed - ensure we don't use it. */
ZERO_STRUCT(st);
*rest = 0;
@@ -330,7 +329,7 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
/*
* Just the last part of the name doesn't exist.
- * We may need to strupper() or strlower() it in case
+ * We may need to strupper() or strlower() it in case
* this conversion is being used for file creation
* purposes. If the filename is of mixed case then
* don't normalise it.
@@ -353,11 +352,14 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
}
/*
- * Restore the rest of the string.
+ * Restore the rest of the string. If the string was mangled the size
+ * may have changed.
*/
if (end) {
- pstrcpy(start+strlen(start)+1,rest);
end = start + strlen(start);
+ pstrcat(start,"/");
+ pstrcat(start,rest);
+ *end = '\0';
}
} /* end else */
@@ -495,11 +497,25 @@ static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL d
if (*dname == '.' && (strequal(dname,".") || strequal(dname,"..")))
continue;
+ /*
+ * dname here is the unmangled name.
+ */
pstrcpy(name2,dname);
if (!name_map_mangle(name2,False,True,SNUM(conn)))
continue;
- if ((mangled && mangled_equal(name,name2)) || fname_equal(name, name2)) {
+ /*
+ * At this point name2 is the mangled name, dname is the unmangled name.
+ * name is either mangled or not, depending on the state of the "mangled"
+ * variable. JRA.
+ */
+
+ /*
+ * Check mangled name against mangled name, or unmangled name
+ * against unmangled name.
+ */
+
+ if ((mangled && mangled_equal(name,name2)) || fname_equal(name, dname)) {
/* we've found the file, change it's name and return */
if (docache)
DirCacheAdd(path,name,dname,SNUM(conn));
diff --git a/source/smbd/files.c b/source/smbd/files.c
index 27dfad7c483..3935a12442b 100644
--- a/source/smbd/files.c
+++ b/source/smbd/files.c
@@ -21,8 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
static int real_max_open_files;
#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < real_max_open_files))
@@ -41,8 +39,22 @@ static files_struct *oplock_save_chain_fsp = NULL;
static int files_used;
/****************************************************************************
- find first available file slot
+ Return a unique number identifying this fsp over the life of this pid.
+****************************************************************************/
+
+static unsigned long get_gen_count(void)
+{
+ static unsigned long file_gen_counter;
+
+ if ((++file_gen_counter) == 0)
+ return ++file_gen_counter;
+ return file_gen_counter;
+}
+
+/****************************************************************************
+ Find first available file slot.
****************************************************************************/
+
files_struct *file_new(connection_struct *conn)
{
int i;
@@ -92,6 +104,8 @@ files_struct *file_new(connection_struct *conn)
ZERO_STRUCTP(fsp);
fsp->fd = -1;
fsp->conn = conn;
+ fsp->file_id = get_gen_count();
+ GetTimeOfDay(&fsp->open_time);
first_file = (i+1) % real_max_open_files;
@@ -111,10 +125,10 @@ files_struct *file_new(connection_struct *conn)
return fsp;
}
-
/****************************************************************************
-close all open files for a connection
+ Close all open files for a connection.
****************************************************************************/
+
void file_close_conn(connection_struct *conn)
{
files_struct *fsp, *next;
@@ -128,7 +142,7 @@ void file_close_conn(connection_struct *conn)
}
/****************************************************************************
-initialise file structures
+ Initialise file structures.
****************************************************************************/
#define MAX_OPEN_FUDGEFACTOR 10
@@ -164,10 +178,10 @@ open files, %d are available.\n", request_max_open_files, real_max_open_files));
set_pipe_handle_offset(real_max_open_files);
}
-
/****************************************************************************
-close files open by a specified vuid
+ Close files open by a specified vuid.
****************************************************************************/
+
void file_close_user(int vuid)
{
files_struct *fsp, *next;
@@ -180,13 +194,32 @@ void file_close_user(int vuid)
}
}
+/****************************************************************************
+ Find a fsp given a file descriptor.
+****************************************************************************/
+
+files_struct *file_find_fd(int fd)
+{
+ int count=0;
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next,count++) {
+ if (fsp->fd == fd) {
+ if (count > 10) {
+ DLIST_PROMOTE(Files, fsp);
+ }
+ return fsp;
+ }
+ }
+
+ return NULL;
+}
/****************************************************************************
- Find a fsp given a device, inode and timevalue
- If this is from a kernel oplock break request then tval may be NULL.
+ Find a fsp given a device, inode and file_id.
****************************************************************************/
-files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
+files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id)
{
int count=0;
files_struct *fsp;
@@ -195,8 +228,7 @@ files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval
if (fsp->fd != -1 &&
fsp->dev == dev &&
fsp->inode == inode &&
- (tval ? (fsp->open_time.tv_sec == tval->tv_sec) : True ) &&
- (tval ? (fsp->open_time.tv_usec == tval->tv_usec) : True )) {
+ fsp->file_id == file_id ) {
if (count > 10) {
DLIST_PROMOTE(Files, fsp);
}
@@ -260,8 +292,9 @@ files_struct *file_find_di_next(files_struct *start_fsp)
}
/****************************************************************************
-find a fsp that is open for printing
+ Find a fsp that is open for printing.
****************************************************************************/
+
files_struct *file_find_print(void)
{
files_struct *fsp;
@@ -273,10 +306,10 @@ files_struct *file_find_print(void)
return NULL;
}
-
/****************************************************************************
-sync open files on a connection
+ Sync open files on a connection.
****************************************************************************/
+
void file_sync_all(connection_struct *conn)
{
files_struct *fsp, *next;
@@ -289,10 +322,10 @@ void file_sync_all(connection_struct *conn)
}
}
-
/****************************************************************************
-free up a fsp
+ Free up a fsp.
****************************************************************************/
+
void file_free(files_struct *fsp)
{
DLIST_REMOVE(Files, fsp);
@@ -311,19 +344,20 @@ void file_free(files_struct *fsp)
if (fsp == chain_fsp) chain_fsp = NULL;
- free(fsp);
+ SAFE_FREE(fsp);
}
-
/****************************************************************************
-get a fsp from a packet given the offset of a 16 bit fnum
+ Get a fsp from a packet given the offset of a 16 bit fnum.
****************************************************************************/
+
files_struct *file_fsp(char *buf, int where)
{
int fnum, count=0;
files_struct *fsp;
- if (chain_fsp) return chain_fsp;
+ if (chain_fsp)
+ return chain_fsp;
fnum = SVAL(buf, where);
@@ -340,7 +374,7 @@ files_struct *file_fsp(char *buf, int where)
}
/****************************************************************************
- Reset the chained fsp - done at the start of a packet reply
+ Reset the chained fsp - done at the start of a packet reply.
****************************************************************************/
void file_chain_reset(void)
@@ -360,6 +394,7 @@ void file_chain_save(void)
/****************************************************************************
Restore the chained fsp - done after an oplock break.
****************************************************************************/
+
void file_chain_restore(void)
{
chain_fsp = oplock_save_chain_fsp;
diff --git a/source/smbd/groupname.c b/source/smbd/groupname.c
index d44e9a7a39c..2c7440d75a7 100644
--- a/source/smbd/groupname.c
+++ b/source/smbd/groupname.c
@@ -22,7 +22,6 @@
#ifdef USING_GROUPNAME_MAP
#include "includes.h"
-extern int DEBUGLEVEL;
extern DOM_SID global_sam_sid;
@@ -53,11 +52,9 @@ static void delete_groupname_map_list(void)
groupname_map_entry *gmep;
while((gmep = (groupname_map_entry *)ubi_slRemHead( &groupname_map_list )) != NULL) {
- if(gmep->windows_name)
- free(gmep->windows_name);
- if(gmep->unix_name)
- free(gmep->unix_name);
- free((char *)gmep);
+ SAFE_FREE(gmep->windows_name);
+ SAFE_FREE(gmep->unix_name);
+ SAFE_FREE(gmep);
}
}
@@ -188,11 +185,9 @@ Error was %s.\n", unixname, strerror(errno) ));
if(new_ep->windows_name == NULL || new_ep->unix_name == NULL) {
DEBUG(0,("load_groupname_map: malloc fail for names in groupname_map_entry.\n"));
fclose(fp);
- if(new_ep->windows_name != NULL)
- free(new_ep->windows_name);
- if(new_ep->unix_name != NULL)
- free(new_ep->unix_name);
- free((char *)new_ep);
+ SAFE_FREE(new_ep->windows_name);
+ SAFE_FREE(new_ep->unix_name);
+ SAFE_FREE(new_ep);
file_lines_free(lines);
return;
}
diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c
index 3ec6d1f1cff..e1c3e7fe4d3 100644
--- a/source/smbd/ipc.c
+++ b/source/smbd/ipc.c
@@ -28,7 +28,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
extern int max_send;
extern fstring local_machine;
@@ -108,7 +107,7 @@ void send_trans_reply(char *outbuf,
SCVAL(outbuf, smb_rcls, ERRDOS);
} else {
SIVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
- SIVAL(outbuf, smb_rcls, 0x80000000 | STATUS_BUFFER_OVERFLOW);
+ SIVAL(outbuf, smb_rcls, NT_STATUS_V(STATUS_BUFFER_OVERFLOW));
}
}
@@ -184,13 +183,13 @@ static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p)
}
if((data_len = read_from_pipe( p, rdata, p->max_trans_reply)) < 0) {
- free(rdata);
+ SAFE_FREE(rdata);
return False;
}
send_trans_reply(outbuf, NULL, 0, rdata, data_len, p->out_data.current_pdu_len > data_len);
- free(rdata);
+ SAFE_FREE(rdata);
return True;
}
@@ -394,7 +393,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
if((data = (char *)malloc(tdscnt)) == NULL) {
DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
END_PROFILE(SMBtrans);
- return(ERROR(ERRDOS,ERRnomem));
+ return(ERROR_DOS(ERRDOS,ERRnomem));
}
memcpy(data,smb_base(inbuf)+dsoff,dscnt);
}
@@ -403,7 +402,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
if((params = (char *)malloc(tpscnt)) == NULL) {
DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
END_PROFILE(SMBtrans);
- return(ERROR(ERRDOS,ERRnomem));
+ return(ERROR_DOS(ERRDOS,ERRnomem));
}
memcpy(params,smb_base(inbuf)+psoff,pscnt);
}
@@ -413,7 +412,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16))));
END_PROFILE(SMBtrans);
- return(ERROR(ERRDOS,ERRnomem));
+ return(ERROR_DOS(ERRDOS,ERRnomem));
}
for (i=0;i<suwcnt;i++)
setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
@@ -443,14 +442,11 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
(smb_read_error == READ_ERROR) ? "error" : "timeout" ));
}
- if (params)
- free(params);
- if (data)
- free(data);
- if (setup)
- free(setup);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ SAFE_FREE(setup);
END_PROFILE(SMBtrans);
- return(ERROR(ERRSRV,ERRerror));
+ return(ERROR_DOS(ERRSRV,ERRerror));
}
show_msg(inbuf);
@@ -510,12 +506,9 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
}
- if (data)
- free(data);
- if (params)
- free(params);
- if (setup)
- free(setup);
+ SAFE_FREE(data);
+ SAFE_FREE(params);
+ SAFE_FREE(setup);
if (close_on_completion)
close_cnum(conn,vuid);
@@ -527,7 +520,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
if (outsize == 0) {
END_PROFILE(SMBtrans);
- return(ERROR(ERRSRV,ERRnosupport));
+ return(ERROR_DOS(ERRSRV,ERRnosupport));
}
END_PROFILE(SMBtrans);
diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c
index 3d8844d5be1..70d79a5f566 100644
--- a/source/smbd/lanman.c
+++ b/source/smbd/lanman.c
@@ -33,8 +33,6 @@
#endif
#define CHECK_TYPES 0
-extern int DEBUGLEVEL;
-
extern fstring local_machine;
extern pstring global_myname;
extern fstring global_myworkgroup;
@@ -748,6 +746,8 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
PACKS(desc,"z","WinPrint"); /* pszPrProc */
PACKS(desc,"z",NULL); /* pszParms */
PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
+ /* "don't ask" that it's done this way to fix corrupted
+ Win9X/ME printer comments. */
if (!status) {
PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
} else {
@@ -956,10 +956,8 @@ static BOOL api_DosPrintQGetInfo(connection_struct *conn,
DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
- if (queue)
- free(queue);
- if (tmpdata)
- free (tmpdata);
+ SAFE_FREE(queue);
+ SAFE_FREE(tmpdata);
return(True);
}
@@ -1049,7 +1047,7 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param,
}
}
- if (subcntarr) free(subcntarr);
+ SAFE_FREE(subcntarr);
*rdata_len = desc.usedlen;
*rparam_len = 8;
@@ -1060,11 +1058,11 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param,
SSVAL(*rparam,6,queuecnt);
for (i = 0; i < queuecnt; i++) {
- if (queue && queue[i]) free(queue[i]);
+ if (queue) SAFE_FREE(queue[i]);
}
- if (queue) free(queue);
- if (status) free(status);
+ SAFE_FREE(queue);
+ SAFE_FREE(status);
return True;
}
@@ -1137,13 +1135,13 @@ static int get_server_info(uint32 servertype,
struct srv_info_struct *ts;
alloced += 10;
- ts = (struct srv_info_struct *)Realloc(*servers,sizeof(**servers)*alloced);
+ ts = (struct srv_info_struct *)
+ Realloc(*servers,sizeof(**servers)*alloced);
if (!ts) {
DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
return(0);
}
- else
- *servers = ts;
+ else *servers = ts;
memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
}
s = &(*servers)[count];
@@ -1414,7 +1412,7 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param
SSVAL(*rparam,4,counted);
SSVAL(*rparam,6,counted+missed);
- if (servers) free(servers);
+ SAFE_FREE(servers);
DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
domain,uLevel,counted,counted+missed));
@@ -1527,7 +1525,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
if (uLevel > 0)
{
int type;
- CVAL(p,13) = 0;
+ SCVAL(p,13,0);
type = STYPE_DISKTREE;
if (lp_print_ok(snum)) type = STYPE_PRINTQ;
if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
@@ -1705,16 +1703,16 @@ static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,ch
t = LocalTime(&unixdate);
SIVAL(p,4,0); /* msecs ? */
- CVAL(p,8) = t->tm_hour;
- CVAL(p,9) = t->tm_min;
- CVAL(p,10) = t->tm_sec;
- CVAL(p,11) = 0; /* hundredths of seconds */
+ SCVAL(p,8,t->tm_hour);
+ SCVAL(p,9,t->tm_min);
+ SCVAL(p,10,t->tm_sec);
+ SCVAL(p,11,0); /* hundredths of seconds */
SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
- CVAL(p,16) = t->tm_mday;
- CVAL(p,17) = t->tm_mon + 1;
+ SCVAL(p,16,t->tm_mday);
+ SCVAL(p,17,t->tm_mon + 1);
SSVAL(p,18,1900+t->tm_year);
- CVAL(p,20) = t->tm_wday;
+ SCVAL(p,20,t->tm_wday);
}
@@ -1795,6 +1793,8 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param
if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
SSVAL(*rparam,0,NERR_badpass);
}
+
+ pdb_free_sam(sampass);
}
/*
@@ -1830,6 +1830,7 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param
{
SSVAL(*rparam,0,NERR_Success);
}
+ pdb_free_sam(sampass);
}
memset((char *)pass1,'\0',sizeof(fstring));
@@ -1911,6 +1912,7 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param
char *p = skip_string(str2,1);
int jobid, errcode;
extern struct current_user current_user;
+ WERROR werr = WERR_OK;
jobid = SVAL(p,0);
@@ -1931,19 +1933,22 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param
switch (function) {
case 81: /* delete */
- if (print_job_delete(&current_user, jobid, &errcode))
+ if (print_job_delete(&current_user, jobid, &werr))
errcode = NERR_Success;
break;
case 82: /* pause */
- if (print_job_pause(&current_user, jobid, &errcode))
+ if (print_job_pause(&current_user, jobid, &werr))
errcode = NERR_Success;
break;
case 83: /* resume */
- if (print_job_resume(&current_user, jobid, &errcode))
+ if (print_job_resume(&current_user, jobid, &werr))
errcode = NERR_Success;
break;
}
+ if (!W_ERROR_IS_OK(werr))
+ errcode = W_ERROR_V(werr);
+
out:
SSVAL(*rparam,0,errcode);
SSVAL(*rparam,2,0); /* converter word */
@@ -1965,6 +1970,7 @@ static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param
char *QueueName = skip_string(str2,1);
int errcode = NERR_notsupported;
int snum;
+ WERROR werr = WERR_OK;
extern struct current_user current_user;
/* check it's a supported varient */
@@ -1984,16 +1990,17 @@ static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param
switch (function) {
case 74: /* Pause queue */
- if (print_queue_pause(&current_user, snum, &errcode)) errcode = NERR_Success;
+ if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
break;
case 75: /* Resume queue */
- if (print_queue_resume(&current_user, snum, &errcode)) errcode = NERR_Success;
+ if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
break;
case 103: /* Purge */
- if (print_queue_purge(&current_user, snum, &errcode)) errcode = NERR_Success;
+ if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
break;
}
+ if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
out:
SSVAL(*rparam,0,errcode);
SSVAL(*rparam,2,0); /* converter word */
@@ -2162,7 +2169,7 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par
pstrcpy(comment,servers[i].comment);
}
}
- if (servers) free(servers);
+ SAFE_FREE(servers);
SCVAL(p,0,lp_major_announce_version());
SCVAL(p,1,lp_minor_announce_version());
@@ -2827,8 +2834,8 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para
SSVAL(*rparam,2,0);
SSVAL(*rparam,4,desc.neededlen);
- if (queue) free(queue);
- if (tmpdata) free(tmpdata);
+ SAFE_FREE(queue);
+ SAFE_FREE(tmpdata);
DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
return(True);
@@ -2897,7 +2904,7 @@ static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *pa
SSVAL(*rparam,4,succnt);
SSVAL(*rparam,6,count);
- if (queue) free(queue);
+ SAFE_FREE(queue);
DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
return(True);
@@ -3016,7 +3023,7 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par
SSVAL(*rparam,4,desc.neededlen);
DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
- if (tmpdata) free (tmpdata);
+ SAFE_FREE(tmpdata);
return(True);
}
@@ -3267,35 +3274,44 @@ struct
int,int,char **,char **,int *,int *);
int flags;
} api_commands[] = {
- {"RNetShareEnum", 0, api_RNetShareEnum,0},
- {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
- {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
- {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
- {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
- {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
- {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
- {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
- {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
- {"WPrintQueuePause", 74, api_WPrintQueueCtrl,0},
- {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
- {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
- {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
- {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
- {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
- {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
- {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
- {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
- {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
- {"WPrintQueuePurge", 103, api_WPrintQueueCtrl,0},
- {"NetServerEnum", 104, api_RNetServerEnum,0},
- {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
- {"SetUserPassword", 115, api_SetUserPassword,0},
- {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
- {"PrintJobInfo", 147, api_PrintJobInfo,0},
- {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
- {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
- {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
- {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
+ {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum,0},
+ {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo,0},
+#if 0 /* Not yet implemented. */
+ {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd,0},
+#endif
+ {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo,0},
+#if 0 /* Not yet implemented. */
+ {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum,0},
+#endif
+ {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers,0},
+#if 0 /* Not yet implemented. */
+ {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum,0},
+#endif
+ {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo,0},
+ {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups,0},
+ {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo,0},
+ {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum,0},
+ {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo,0},
+ {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl,0},
+ {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl,0},
+ {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate,0},
+ {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo,0},
+ {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel,0},
+ {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel,0},
+ {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel,0},
+ {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum,0},
+ {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo,0},
+ {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD,0},
+ {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl,0},
+ {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum,0},
+ {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms,0},
+ {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword,0},
+ {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon,0},
+ {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo,0},
+ {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum,0},
+ {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum,0},
+ {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum,0},
+ {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword,0},
{NULL, -1, api_Unsupported,0}};
@@ -3364,10 +3380,8 @@ int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *
send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
- if (rdata )
- free(rdata);
- if (rparam)
- free(rparam);
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
return -1;
}
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c
index d6d470c2dab..3d214d46589 100644
--- a/source/smbd/mangle.c
+++ b/source/smbd/mangle.c
@@ -52,7 +52,6 @@
* External Variables...
*/
-extern int DEBUGLEVEL; /* Global debug level. */
extern int case_default; /* Are conforming 8.3 names all upper or lower? */
extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */
@@ -466,7 +465,7 @@ static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
static void cache_free_entry( ubi_trNodePtr WarrenZevon )
{
ZERO_STRUCTP(WarrenZevon);
- free( WarrenZevon );
+ SAFE_FREE( WarrenZevon );
} /* cache_free_entry */
/* ************************************************************************** **
@@ -633,7 +632,7 @@ BOOL check_mangled_cache( char *s )
{
/* Replace the saved_ext as it was truncated. */
(void)pstrcat( s, saved_ext );
- free(saved_ext);
+ SAFE_FREE(saved_ext);
}
return( False );
}
@@ -649,7 +648,7 @@ BOOL check_mangled_cache( char *s )
{
/* Replace the saved_ext as it was truncated. */
(void)pstrcat( s, saved_ext );
- free(saved_ext);
+ SAFE_FREE(saved_ext);
}
DEBUG( 3, ("as %s\n", s) );
@@ -1017,7 +1016,7 @@ BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
if(tmp != NULL) {
cache_mangled_name(OutName, tmp);
- free(tmp);
+ SAFE_FREE(tmp);
}
}
diff --git a/source/smbd/message.c b/source/smbd/message.c
index b3da3f2b611..0097b15b8b4 100644
--- a/source/smbd/message.c
+++ b/source/smbd/message.c
@@ -27,8 +27,6 @@
#include "includes.h"
/* look in server.c for some explanation of these variables */
-extern int DEBUGLEVEL;
-
static char msgbuf[1600];
static int msgpos=0;
@@ -113,7 +111,7 @@ int reply_sends(connection_struct *conn,
if (! (*lp_msg_command())) {
END_PROFILE(SMBsends);
- return(ERROR(ERRSRV,ERRmsgoff));
+ return(ERROR_DOS(ERRSRV,ERRmsgoff));
}
outsize = set_message(outbuf,0,0,True);
@@ -154,7 +152,7 @@ int reply_sendstrt(connection_struct *conn,
if (! (*lp_msg_command())) {
END_PROFILE(SMBsendstrt);
- return(ERROR(ERRSRV,ERRmsgoff));
+ return(ERROR_DOS(ERRSRV,ERRmsgoff));
}
outsize = set_message(outbuf,1,0,True);
@@ -188,7 +186,7 @@ int reply_sendtxt(connection_struct *conn,
if (! (*lp_msg_command())) {
END_PROFILE(SMBsendtxt);
- return(ERROR(ERRSRV,ERRmsgoff));
+ return(ERROR_DOS(ERRSRV,ERRmsgoff));
}
outsize = set_message(outbuf,0,0,True);
@@ -219,7 +217,7 @@ int reply_sendend(connection_struct *conn,
if (! (*lp_msg_command())) {
END_PROFILE(SMBsendend);
- return(ERROR(ERRSRV,ERRmsgoff));
+ return(ERROR_DOS(ERRSRV,ERRmsgoff));
}
outsize = set_message(outbuf,0,0,True);
diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c
index 25419caf625..1f5de570c66 100644
--- a/source/smbd/negprot.c
+++ b/source/smbd/negprot.c
@@ -21,7 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
extern int Protocol;
extern int max_recv;
extern fstring global_myworkgroup;
@@ -158,7 +157,7 @@ reply for the nt protocol
static int reply_nt1(char *outbuf)
{
/* dual names + lock_and_read + nt SMBs + remote API calls */
- int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|CAP_LEVEL_II_OPLOCKS|
+ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|CAP_LEVEL_II_OPLOCKS|CAP_STATUS32| (lp_unix_extensions() ? CAP_UNIX : 0) |
(lp_nt_smb_support() ? CAP_NT_SMBS | CAP_RPC_REMOTE_APIS : 0) |
((lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) ?
CAP_LARGE_READX | CAP_LARGE_WRITEX | CAP_W2K_SMBS : 0) |
@@ -217,7 +216,7 @@ static int reply_nt1(char *outbuf)
set_message(outbuf,17,data_len,True);
pstrcpy(smb_buf(outbuf)+crypt_len, global_myworkgroup);
- CVAL(outbuf,smb_vwv1) = secword;
+ SCVAL(outbuf,smb_vwv1,secword);
SSVALS(outbuf,smb_vwv16+1,crypt_len);
if (doencrypt)
memcpy(smb_buf(outbuf), cryptkey, 8);
diff --git a/source/smbd/noquotas.c b/source/smbd/noquotas.c
index 5c55bb47c8e..a6951d97fc5 100644
--- a/source/smbd/noquotas.c
+++ b/source/smbd/noquotas.c
@@ -25,7 +25,7 @@
* Needed for auto generation of proto.h.
*/
-BOOL disk_quotas(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
{
(*bsize) = 512; /* This value should be ignored */
diff --git a/source/smbd/notify.c b/source/smbd/notify.c
index d0966289fe7..52df3558aa7 100644
--- a/source/smbd/notify.c
+++ b/source/smbd/notify.c
@@ -22,16 +22,13 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-extern uint32 global_client_caps;
-
static struct cnotify_fns *cnotify;
/****************************************************************************
This is the structure to queue to implement NT change
notify. It consists of smb_size bytes stored from the
transact command (to keep the mid, tid etc around).
- Plus the fid to examine and notify private data
+ Plus the fid to examine and notify private data.
*****************************************************************************/
struct change_notify {
@@ -48,26 +45,14 @@ static struct change_notify *change_notify_list;
/****************************************************************************
Setup the common parts of the return packet and send it.
*****************************************************************************/
-static void change_notify_reply_packet(char *inbuf, uint32 error_code)
+static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code)
{
char outbuf[smb_size+38];
memset(outbuf, '\0', sizeof(outbuf));
construct_reply_common(inbuf, outbuf);
- /*
- * If we're returning a 'too much in the directory changed' we need to
- * set this is an NT error status flags. If we don't then the (probably
- * untested) code in the NT redirector has a bug in that it doesn't re-issue
- * the change notify.... Ah - I *love* it when I get so deeply into this I
- * can even determine how MS failed to test stuff and why.... :-). JRA.
- */
-
- if (global_client_caps & CAP_STATUS32) {
- ERROR(0,error_code);
- } else {
- ERROR(ERRDOS,STATUS_NOTIFY_ENUM_DIR);
- }
+ ERROR_NT(error_code);
/*
* Seems NT needs a transact command with an error code
@@ -76,26 +61,26 @@ static void change_notify_reply_packet(char *inbuf, uint32 error_code)
set_message(outbuf,18,0,False);
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("change_notify_reply_packet: send_smb failed.\n");
+ exit_server("change_notify_reply_packet: send_smb failed.");
}
/****************************************************************************
-remove an entry from the list and free it, also closing any
-directory handle if necessary
-Notice the horrible stuff we have to do because this is a singly linked list.
+ Remove an entry from the list and free it, also closing any
+ directory handle if necessary.
*****************************************************************************/
+
static void change_notify_remove(struct change_notify *cnbp)
{
cnotify->remove_notify(cnbp->change_data);
DLIST_REMOVE(change_notify_list, cnbp);
ZERO_STRUCTP(cnbp);
- free(cnbp);
+ SAFE_FREE(cnbp);
}
-
/****************************************************************************
Delete entries by fnum from the change notify pending queue.
*****************************************************************************/
+
void remove_pending_change_notify_requests_by_fid(files_struct *fsp)
{
struct change_notify *cnbp, *next;
@@ -111,6 +96,7 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp)
/****************************************************************************
Delete entries by mid from the change notify pending queue. Always send reply.
*****************************************************************************/
+
void remove_pending_change_notify_requests_by_mid(int mid)
{
struct change_notify *cnbp, *next;
@@ -128,6 +114,7 @@ void remove_pending_change_notify_requests_by_mid(int mid)
Delete entries by filename and cnum from the change notify pending queue.
Always send reply.
*****************************************************************************/
+
void remove_pending_change_notify_requests_by_filename(files_struct *fsp)
{
struct change_notify *cnbp, *next;
@@ -148,6 +135,7 @@ void remove_pending_change_notify_requests_by_filename(files_struct *fsp)
/****************************************************************************
Return true if there are pending change notifies.
****************************************************************************/
+
int change_notify_timeout(void)
{
return cnotify->select_time;
@@ -158,6 +146,7 @@ int change_notify_timeout(void)
Returns True if there are still outstanding change notify requests on the
queue.
*****************************************************************************/
+
BOOL process_pending_change_notify_queue(time_t t)
{
struct change_notify *cnbp, *next;
@@ -167,8 +156,9 @@ BOOL process_pending_change_notify_queue(time_t t)
next=cnbp->next;
vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid);
-
+
if (cnotify->check_notify(cnbp->conn, vuid, cnbp->fsp->fsp_name, cnbp->flags, cnbp->change_data, t)) {
+ DEBUG(10,("process_pending_change_notify_queue: dir %s changed !\n", cnbp->fsp->fsp_name ));
change_notify_reply_packet(cnbp->request_buf,STATUS_NOTIFY_ENUM_DIR);
change_notify_remove(cnbp);
}
@@ -178,11 +168,12 @@ BOOL process_pending_change_notify_queue(time_t t)
}
/****************************************************************************
- * Now queue an entry on the notify change list.
- * We only need to save smb_size bytes from this incoming packet
- * as we will always by returning a 'read the directory yourself'
- * error.
+ Now queue an entry on the notify change list.
+ We only need to save smb_size bytes from this incoming packet
+ as we will always by returning a 'read the directory yourself'
+ error.
****************************************************************************/
+
BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags)
{
struct change_notify *cnbp;
@@ -201,7 +192,7 @@ BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn,
cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name, flags);
if (!cnbp->change_data) {
- free(cnbp);
+ SAFE_FREE(cnbp);
return False;
}
@@ -210,10 +201,10 @@ BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn,
return True;
}
-
/****************************************************************************
-initialise the change notify subsystem
+ Initialise the change notify subsystem.
****************************************************************************/
+
BOOL init_change_notify(void)
{
#if HAVE_KERNEL_CHANGE_NOTIFY
diff --git a/source/smbd/notify_hash.c b/source/smbd/notify_hash.c
index a0a61569a8b..90eb88ac814 100644
--- a/source/smbd/notify_hash.c
+++ b/source/smbd/notify_hash.c
@@ -22,21 +22,20 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
-
struct change_data {
time_t last_check_time; /* time we last checked this entry */
time_t modify_time; /* Info from the directory we're monitoring. */
time_t status_time; /* Info from the directory we're monitoring. */
time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
unsigned int num_entries; /* Zero or the number of files in the directory. */
+ unsigned int mode_sum;
+ unsigned char name_hash[16];
};
-
/****************************************************************************
Create the hash we will use to determine if the contents changed.
*****************************************************************************/
+
static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
struct change_data *data, struct change_data *old_data)
{
@@ -50,7 +49,8 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
ZERO_STRUCTP(data);
- if(vfs_stat(conn,path, &st) == -1) return False;
+ if(vfs_stat(conn,path, &st) == -1)
+ return False;
data->modify_time = st.st_mtime;
data->status_time = st.st_ctime;
@@ -76,10 +76,9 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
* larger than the max time_t value).
*/
- if (!(flags & (FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE))) return True;
-
dp = OpenDir(conn, path, True);
- if (dp == NULL) return False;
+ if (dp == NULL)
+ return False;
data->num_entries = 0;
@@ -91,7 +90,8 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
p = &full_name[fullname_len];
while ((fname = ReadDirName(dp))) {
- if(strequal(fname, ".") || strequal(fname, "..")) continue;
+ if(strequal(fname, ".") || strequal(fname, ".."))
+ continue;
data->num_entries++;
safe_strcpy(p, fname, remaining_len);
@@ -102,7 +102,31 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
* Do the stat - but ignore errors.
*/
vfs_stat(conn,full_name, &st);
+
+ /*
+ * Always sum the times.
+ */
+
data->total_time += (st.st_mtime + st.st_ctime);
+
+ /*
+ * If requested hash the names.
+ */
+
+ if (flags & (FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_FILE)) {
+ int i;
+ unsigned char tmp_hash[16];
+ mdfour(tmp_hash, (unsigned char *)fname, strlen(fname));
+ for (i=0;i<16;i++)
+ data->name_hash[i] ^= tmp_hash[i];
+ }
+
+ /*
+ * If requested sum the mode_t's.
+ */
+
+ if (flags & (FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_SECURITY))
+ data->mode_sum = st.st_mode;
}
CloseDir(dp);
@@ -110,15 +134,16 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
return True;
}
-
/****************************************************************************
-register a change notify request
+ Register a change notify request.
*****************************************************************************/
+
static void *hash_register_notify(connection_struct *conn, char *path, uint32 flags)
{
struct change_data data;
- if (!notify_hash(conn, path, flags, &data, NULL)) return NULL;
+ if (!notify_hash(conn, path, flags, &data, NULL))
+ return NULL;
data.last_check_time = time(NULL);
@@ -129,16 +154,19 @@ static void *hash_register_notify(connection_struct *conn, char *path, uint32 fl
Check if a change notify should be issued.
A time of zero means instantaneous check - don't modify the last check time.
*****************************************************************************/
+
static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
{
struct change_data *data = (struct change_data *)datap;
struct change_data data2;
- if (t && t < data->last_check_time + lp_change_notify_timeout()) return False;
+ if (t && t < data->last_check_time + lp_change_notify_timeout())
+ return False;
- if (!become_user(conn,vuid)) return True;
- if (!become_service(conn,True)) {
- unbecome_user();
+ if (!change_to_user(conn,vuid))
+ return True;
+ if (!set_current_service(conn,True)) {
+ change_to_root_user();
return True;
}
@@ -146,31 +174,34 @@ static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path,
data2.modify_time != data->modify_time ||
data2.status_time != data->status_time ||
data2.total_time != data->total_time ||
- data2.num_entries != data->num_entries) {
- unbecome_user();
+ data2.num_entries != data->num_entries ||
+ data2.mode_sum != data->mode_sum ||
+ memcmp(data2.name_hash, data->name_hash, sizeof(data2.name_hash))) {
+ change_to_root_user();
return True;
}
if (t)
data->last_check_time = t;
- unbecome_user();
+ change_to_root_user();
return False;
}
/****************************************************************************
-remove a change notify data structure
+ Remove a change notify data structure.
*****************************************************************************/
+
static void hash_remove_notify(void *datap)
{
- free(datap);
+ SAFE_FREE(datap);
}
-
/****************************************************************************
-setup hash based change notify
+ Setup hash based change notify.
****************************************************************************/
+
struct cnotify_fns *hash_notify_init(void)
{
static struct cnotify_fns cnotify;
@@ -183,7 +214,6 @@ struct cnotify_fns *hash_notify_init(void)
return &cnotify;
}
-
/*
change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
diff --git a/source/smbd/notify_kernel.c b/source/smbd/notify_kernel.c
index f1e40793c85..96164a3199b 100644
--- a/source/smbd/notify_kernel.c
+++ b/source/smbd/notify_kernel.c
@@ -23,7 +23,6 @@
#if HAVE_KERNEL_CHANGE_NOTIFY
-extern int DEBUGLEVEL;
static VOLATILE sig_atomic_t fd_pending;
static VOLATILE sig_atomic_t signals_received;
static VOLATILE sig_atomic_t signals_processed;
@@ -111,7 +110,7 @@ static void kernel_remove_notify(void *datap)
}
close(fd);
}
- free(data);
+ SAFE_FREE(data);
DEBUG(3,("removed kernel change notify fd=%d\n", fd));
}
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index e913daef18a..110d7ed7d26 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -21,14 +21,12 @@
#include "includes.h"
-extern int DEBUGLEVEL;
extern int Protocol;
extern int smb_read_error;
extern int global_oplock_break;
extern BOOL case_sensitive;
extern BOOL case_preserve;
extern BOOL short_case_preserve;
-extern uint32 global_client_caps;
static char *known_nt_pipes[] = {
"\\LANMAN",
@@ -64,8 +62,8 @@ struct generic_mapping file_generic_mapping = {
HACK ! Always assumes smb_setup field is zero.
****************************************************************************/
-static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, uint32 nt_error, int eclass, uint32 ecode,
- char *params, int paramsize, char *pdata, int datasize)
+static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_error, char *params,
+ int paramsize, char *pdata, int datasize)
{
extern int max_send;
int data_to_send = datasize;
@@ -84,8 +82,8 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, uint32 nt_err
set_message(outbuf,18,0,True);
- if(nt_error != 0) {
- ERROR_BOTH(nt_error,eclass,ecode);
+ if(NT_STATUS_V(nt_error)) {
+ ERROR_NT(nt_error);
}
/*
@@ -95,7 +93,7 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, uint32 nt_err
if(params_to_send == 0 && data_to_send == 0) {
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("send_nt_replies: send_smb failed.\n");
+ exit_server("send_nt_replies: send_smb failed.");
return 0;
}
@@ -225,7 +223,7 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, uint32 nt_err
/* Send the packet */
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("send_nt_replies: send_smb failed.\n");
+ exit_server("send_nt_replies: send_smb failed.");
pp += params_sent_thistime;
pd += data_sent_thistime;
@@ -397,7 +395,7 @@ static int map_create_disposition( uint32 create_disposition)
return -1;
}
- DEBUG(10,("map_create_disposition: Mapped create_disposition %lx to %x\n",
+ DEBUG(10,("map_create_disposition: Mapped create_disposition 0x%lx to 0x%x\n",
(unsigned long)create_disposition, ret ));
return ret;
@@ -407,7 +405,7 @@ static int map_create_disposition( uint32 create_disposition)
Utility function to map share modes.
****************************************************************************/
-static int map_share_mode( BOOL *pstat_open_only, char *fname,
+static int map_share_mode( BOOL *pstat_open_only, char *fname, uint32 create_options,
uint32 desired_access, uint32 share_access, uint32 file_attributes)
{
int smb_open_mode = -1;
@@ -471,7 +469,7 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname,
smb_open_mode = DOS_OPEN_RDONLY;
} else {
- DEBUG(0,("map_share_mode: Incorrect value %lx for desired_access to file %s\n",
+ DEBUG(0,("map_share_mode: Incorrect value 0x%lx for desired_access to file %s\n",
(unsigned long)desired_access, fname));
return -1;
}
@@ -485,7 +483,7 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname,
if(share_access & FILE_SHARE_DELETE) {
smb_open_mode |= ALLOW_SHARE_DELETE;
- DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = %x\n", smb_open_mode));
+ DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = 0x%x\n", smb_open_mode));
}
/*
@@ -497,7 +495,14 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname,
if(desired_access & DELETE_ACCESS) {
smb_open_mode |= DELETE_ACCESS_REQUESTED;
- DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = %x\n", smb_open_mode));
+ DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = 0x%x\n", smb_open_mode));
+ }
+
+ if (create_options & FILE_DELETE_ON_CLOSE) {
+ /* Implicit delete access requested... */
+ smb_open_mode |= DELETE_ACCESS_REQUESTED;
+ smb_open_mode |= DELETE_ON_CLOSE_FLAG;
+ DEBUG(10,("map_share_mode: FILE_DELETE_ON_CLOSE requested. open_mode = 0x%x\n", smb_open_mode));
}
/* Add in the requested share mode. */
@@ -523,8 +528,8 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname,
if(file_attributes & FILE_FLAG_WRITE_THROUGH)
smb_open_mode |= FILE_SYNC_OPENMODE;
- DEBUG(10,("map_share_mode: Mapped desired access %lx, share access %lx, file attributes %lx \
-to open_mode %x\n", (unsigned long)desired_access, (unsigned long)share_access,
+ DEBUG(10,("map_share_mode: Mapped desired access 0x%lx, share access 0x%lx, file attributes 0x%lx \
+to open_mode 0x%x\n", (unsigned long)desired_access, (unsigned long)share_access,
(unsigned long)file_attributes, smb_open_mode ));
return smb_open_mode;
@@ -546,14 +551,14 @@ static int nt_open_pipe(char *fname, connection_struct *conn,
/* See if it is one we want to handle. */
if (lp_disable_spoolss() && strequal(fname, "\\spoolss"))
- return(ERROR(ERRSRV,ERRaccess));
+ return(ERROR_DOS(ERRSRV,ERRaccess));
for( i = 0; known_nt_pipes[i]; i++ )
if( strequal(fname,known_nt_pipes[i]))
break;
if ( known_nt_pipes[i] == NULL )
- return(ERROR(ERRSRV,ERRaccess));
+ return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe));
/* Strip \\ off the name. */
fname++;
@@ -562,7 +567,7 @@ static int nt_open_pipe(char *fname, connection_struct *conn,
p = open_rpc_pipe_p(fname, conn, vuid);
if (!p)
- return(ERROR(ERRSRV,ERRnofids));
+ return(ERROR_DOS(ERRSRV,ERRnofids));
*ppnum = p->pnum;
@@ -657,7 +662,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
return do_ntcreate_pipe_open(conn,inbuf,outbuf,length,bufsize);
} else {
END_PROFILE(SMBntcreateX);
- return(ERROR(ERRDOS,ERRbadaccess));
+ return(ERROR_DOS(ERRDOS,ERRbadaccess));
}
}
@@ -669,87 +674,87 @@ int reply_ntcreate_and_X(connection_struct *conn,
if((smb_ofun = map_create_disposition( create_disposition )) == -1) {
END_PROFILE(SMBntcreateX);
- return(ERROR(ERRDOS,ERRbadaccess));
+ return(ERROR_DOS(ERRDOS,ERRbadaccess));
}
/*
* Get the file name.
*/
- if(root_dir_fid != 0) {
- /*
- * This filename is relative to a directory fid.
- */
- files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid);
- size_t dir_name_len;
+ if(root_dir_fid != 0) {
+ /*
+ * This filename is relative to a directory fid.
+ */
+ files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid);
+ size_t dir_name_len;
- if(!dir_fsp) {
- END_PROFILE(SMBntcreateX);
- return(ERROR(ERRDOS,ERRbadfid));
- }
+ if(!dir_fsp) {
+ END_PROFILE(SMBntcreateX);
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
+ }
- if(!dir_fsp->is_directory) {
- /*
- * Check to see if this is a mac fork of some kind.
- */
+ if(!dir_fsp->is_directory) {
+ /*
+ * Check to see if this is a mac fork of some kind.
+ */
- get_filename(&fname[0], inbuf, smb_buf(inbuf)-inbuf,
- smb_buflen(inbuf),fname_len);
+ get_filename(&fname[0], inbuf, smb_buf(inbuf)-inbuf,
+ smb_buflen(inbuf),fname_len);
- if( strchr(fname, ':')) {
- END_PROFILE(SMBntcreateX);
- return(ERROR_BOTH(NT_STATUS_OBJECT_PATH_NOT_FOUND,ERRDOS,ERRbadpath));
- }
- END_PROFILE(SMBntcreateX);
- return(ERROR(ERRDOS,ERRbadfid));
- }
+ if( strchr(fname, ':')) {
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+ END_PROFILE(SMBntcreateX);
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
+ }
- /*
- * Copy in the base directory name.
- */
+ /*
+ * Copy in the base directory name.
+ */
- pstrcpy( fname, dir_fsp->fsp_name );
- dir_name_len = strlen(fname);
+ pstrcpy( fname, dir_fsp->fsp_name );
+ dir_name_len = strlen(fname);
- /*
- * Ensure it ends in a '\'.
- */
+ /*
+ * Ensure it ends in a '\'.
+ */
- if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
- pstrcat(fname, "\\");
- dir_name_len++;
- }
+ if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+ pstrcat(fname, "\\");
+ dir_name_len++;
+ }
- /*
- * This next calculation can refuse a correct filename if we're dealing
- * with the Win2k unicode bug, but that would be rare. JRA.
- */
+ /*
+ * This next calculation can refuse a correct filename if we're dealing
+ * with the Win2k unicode bug, but that would be rare. JRA.
+ */
- if(fname_len + dir_name_len >= sizeof(pstring)) {
- END_PROFILE(SMBntcreateX);
- return(ERROR(ERRSRV,ERRfilespecs));
- }
+ if(fname_len + dir_name_len >= sizeof(pstring)) {
+ END_PROFILE(SMBntcreateX);
+ return(ERROR_DOS(ERRSRV,ERRfilespecs));
+ }
- get_filename(&fname[dir_name_len], inbuf, smb_buf(inbuf)-inbuf,
- smb_buflen(inbuf),fname_len);
+ get_filename(&fname[dir_name_len], inbuf, smb_buf(inbuf)-inbuf,
+ smb_buflen(inbuf),fname_len);
- } else {
+ } else {
- get_filename(fname, inbuf, smb_buf(inbuf)-inbuf,
- smb_buflen(inbuf),fname_len);
- }
+ get_filename(fname, inbuf, smb_buf(inbuf)-inbuf,
+ smb_buflen(inbuf),fname_len);
+ }
/*
* Now contruct the smb_open_mode value from the filename,
- * desired access and the share access.
+ * desired access and the share access.
*/
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
- if((smb_open_mode = map_share_mode(&stat_open_only, fname, desired_access,
+ if((smb_open_mode = map_share_mode(&stat_open_only, fname, create_options, desired_access,
share_access,
file_attributes)) == -1) {
END_PROFILE(SMBntcreateX);
- return(ERROR(ERRDOS,ERRbadaccess));
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
}
oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
@@ -776,15 +781,12 @@ int reply_ntcreate_and_X(connection_struct *conn,
if(create_options & FILE_DIRECTORY_FILE) {
oplock_request = 0;
- fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action);
+ fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action);
restore_case_semantics(file_attributes);
if(!fsp) {
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBntcreateX);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -837,19 +839,18 @@ int reply_ntcreate_and_X(connection_struct *conn,
if (create_options & FILE_NON_DIRECTORY_FILE) {
restore_case_semantics(file_attributes);
+ SSVAL(outbuf, smb_flg2,
+ SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
END_PROFILE(SMBntcreateX);
- return(ERROR_BOTH(NT_STATUS_FILE_IS_A_DIRECTORY,ERRDOS,ERRbadaccess));
+ return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
}
oplock_request = 0;
- fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action);
+ fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action);
if(!fsp) {
restore_case_semantics(file_attributes);
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBntcreateX);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -875,12 +876,8 @@ int reply_ntcreate_and_X(connection_struct *conn,
} else {
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
-
restore_case_semantics(file_attributes);
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBntcreateX);
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -897,7 +894,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
if (!fsp->is_directory && (fmode & aDIR)) {
close_file(fsp,False);
END_PROFILE(SMBntcreateX);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
/*
@@ -912,7 +909,12 @@ int reply_ntcreate_and_X(connection_struct *conn,
if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
smb_action |= EXTENDED_OPLOCK_GRANTED;
+#if 1 /* JRATEST */
+ /* W2K sends back 42 words here ! */
+ set_message(outbuf,42,0,True);
+#else
set_message(outbuf,34,0,True);
+#endif
p = outbuf + smb_vwv2;
@@ -921,10 +923,10 @@ int reply_ntcreate_and_X(connection_struct *conn,
* exclusive & batch here.
*/
- if (smb_action & EXTENDED_OPLOCK_GRANTED)
- SCVAL(p,0, BATCH_OPLOCK_RETURN);
+ if (smb_action & EXTENDED_OPLOCK_GRANTED)
+ SCVAL(p,0, BATCH_OPLOCK_RETURN);
else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
- SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
+ SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
else
SCVAL(p,0,NO_OPLOCK_RETURN);
@@ -990,7 +992,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn,
if(total_parameter_count < 54) {
DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)total_parameter_count));
- return(ERROR(ERRDOS,ERRbadaccess));
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
}
fname_len = MIN(((uint32)IVAL(params,44)),((uint32)sizeof(fname)-1));
@@ -1004,7 +1006,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn,
/* Realloc the size of parameters and data we will return */
params = Realloc(*ppparams, 69);
if(params == NULL)
- return(ERROR(ERRDOS,ERRnomem));
+ return ERROR_DOS(ERRDOS,ERRnomem);
*ppparams = params;
@@ -1030,7 +1032,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn,
DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname));
/* Send the required number of replies */
- send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, params, 69, *ppdata, 0);
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
return -1;
}
@@ -1164,7 +1166,7 @@ static int call_nt_transact_create(connection_struct *conn,
return do_nt_transact_create_pipe(conn, inbuf, outbuf, length,
bufsize, ppsetup, ppparams, ppdata);
else
- return(ERROR(ERRDOS,ERRbadaccess));
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
}
/*
@@ -1173,7 +1175,7 @@ static int call_nt_transact_create(connection_struct *conn,
if(total_parameter_count < 54) {
DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)total_parameter_count));
- return(ERROR(ERRDOS,ERRbadaccess));
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
}
flags = IVAL(params,0);
@@ -1193,7 +1195,7 @@ static int call_nt_transact_create(connection_struct *conn,
*/
if((smb_ofun = map_create_disposition( create_disposition )) == -1)
- return(ERROR(ERRDOS,ERRbadmem));
+ return ERROR_DOS(ERRDOS,ERRbadmem);
/*
* Get the file name.
@@ -1208,7 +1210,7 @@ static int call_nt_transact_create(connection_struct *conn,
size_t dir_name_len;
if(!dir_fsp)
- return(ERROR(ERRDOS,ERRbadfid));
+ return ERROR_DOS(ERRDOS,ERRbadfid);
if(!dir_fsp->is_directory) {
/*
@@ -1222,7 +1224,7 @@ static int call_nt_transact_create(connection_struct *conn,
return(ERROR_BOTH(NT_STATUS_OBJECT_PATH_NOT_FOUND,ERRDOS,ERRbadpath));
}
- return(ERROR(ERRDOS,ERRbadfid));
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
}
/*
@@ -1247,7 +1249,7 @@ static int call_nt_transact_create(connection_struct *conn,
*/
if(fname_len + dir_name_len >= sizeof(pstring))
- return(ERROR(ERRSRV,ERRfilespecs));
+ return(ERROR_DOS(ERRSRV,ERRfilespecs));
get_filename_transact(&fname[dir_name_len], params, 53,
total_parameter_count - 53 - fname_len, fname_len);
@@ -1262,9 +1264,9 @@ static int call_nt_transact_create(connection_struct *conn,
* and the share access.
*/
- if((smb_open_mode = map_share_mode( &stat_open_only, fname, desired_access,
+ if((smb_open_mode = map_share_mode( &stat_open_only, fname, create_options, desired_access,
share_access, file_attributes)) == -1)
- return(ERROR(ERRDOS,ERRbadaccess));
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
@@ -1295,14 +1297,11 @@ static int call_nt_transact_create(connection_struct *conn,
* CreateDirectory() call.
*/
- fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action);
+ fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action);
if(!fsp) {
restore_case_semantics(file_attributes);
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ set_bad_path_error(errno, bad_path);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -1325,18 +1324,17 @@ static int call_nt_transact_create(connection_struct *conn,
if (create_options & FILE_NON_DIRECTORY_FILE) {
restore_case_semantics(file_attributes);
- return(ERROR_BOTH(NT_STATUS_FILE_IS_A_DIRECTORY,ERRDOS, ERRbadaccess));
+ SSVAL(outbuf, smb_flg2,
+ SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+ return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
}
oplock_request = 0;
- fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action);
+ fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action);
if(!fsp) {
restore_case_semantics(file_attributes);
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ set_bad_path_error(errno, bad_path);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
#ifdef EROFS
@@ -1360,12 +1358,8 @@ static int call_nt_transact_create(connection_struct *conn,
}
} else {
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
-
restore_case_semantics(file_attributes);
+ set_bad_path_error(errno, bad_path);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -1379,7 +1373,7 @@ static int call_nt_transact_create(connection_struct *conn,
if (fmode & aDIR) {
close_file(fsp,False);
restore_case_semantics(file_attributes);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
/*
@@ -1402,7 +1396,7 @@ static int call_nt_transact_create(connection_struct *conn,
if (!set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION, &error_class, &error_code)) {
close_file(fsp,False);
restore_case_semantics(file_attributes);
- return(ERROR(error_class, error_code));
+ return ERROR_DOS(error_class, error_code);
}
restore_case_semantics(file_attributes);
@@ -1410,7 +1404,7 @@ static int call_nt_transact_create(connection_struct *conn,
/* Realloc the size of parameters and data we will return */
params = Realloc(*ppparams, 69);
if(params == NULL)
- return(ERROR(ERRDOS,ERRnomem));
+ return ERROR_DOS(ERRDOS,ERRnomem);
*ppparams = params;
@@ -1457,7 +1451,7 @@ static int call_nt_transact_create(connection_struct *conn,
DEBUG(5,("call_nt_transact_create: open name = %s\n", fname));
/* Send the required number of replies */
- send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, params, 69, *ppdata, 0);
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
return -1;
}
@@ -1515,10 +1509,10 @@ static int call_nt_transact_notify_change(connection_struct *conn,
DEBUG(3,("call_nt_transact_notify_change\n"));
if(!fsp)
- return(ERROR(ERRDOS,ERRbadfid));
+ return ERROR_DOS(ERRDOS,ERRbadfid);
if((!fsp->is_directory) || (conn != fsp->conn))
- return(ERROR(ERRDOS,ERRbadfid));
+ return ERROR_DOS(ERRDOS,ERRbadfid);
if (!change_notify_set(inbuf, fsp, conn, flags)) {
return(UNIXERROR(ERRDOS,ERRbadfid));
@@ -1539,30 +1533,30 @@ static int call_nt_transact_rename(connection_struct *conn,
int bufsize,
char **ppsetup, char **ppparams, char **ppdata)
{
- char *params = *ppparams;
- pstring new_name;
- files_struct *fsp = file_fsp(params, 0);
- BOOL replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
- uint32 fname_len = MIN((((uint32)IVAL(inbuf,smb_nt_TotalParameterCount)-4)),
- ((uint32)sizeof(new_name)-1));
- int outsize = 0;
-
- CHECK_FSP(fsp, conn);
- StrnCpy(new_name,params+4,fname_len);
- new_name[fname_len] = '\0';
-
- outsize = rename_internals(conn, inbuf, outbuf, fsp->fsp_name,
+ char *params = *ppparams;
+ pstring new_name;
+ files_struct *fsp = file_fsp(params, 0);
+ BOOL replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
+ NTSTATUS status;
+ uint32 fname_len = MIN((((uint32)IVAL(inbuf,smb_nt_TotalParameterCount)-4)),
+ ((uint32)sizeof(new_name)-1));
+
+ CHECK_FSP(fsp, conn);
+ StrnCpy(new_name,params+4,fname_len);
+ new_name[fname_len] = '\0';
+
+ status = rename_internals(conn, fsp->fsp_name,
new_name, replace_if_exists);
- if(outsize == 0) {
- /*
- * Rename was successful.
- */
- send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, NULL, 0, NULL, 0);
+ if (!NT_STATUS_IS_OK(status))
+ return ERROR_NT(status);
- DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n",
- fsp->fsp_name, new_name));
+ /*
+ * Rename was successful.
+ */
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
- outsize = -1;
+ DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n",
+ fsp->fsp_name, new_name));
/*
* Win2k needs a changenotify request response before it will
@@ -1570,9 +1564,8 @@ static int call_nt_transact_rename(connection_struct *conn,
*/
process_pending_change_notify_queue((time_t)0);
- }
- return(outsize);
+ return -1;
}
/******************************************************************************
@@ -1593,7 +1586,7 @@ static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd)
return sd_size;
}
-/**************************************************************************n
+/****************************************************************************
Reply to query a security descriptor - currently this is not implemented (it
is planned to be though). Right now it just returns the same thing NT would
when queried on a FAT filesystem. JRA.
@@ -1615,19 +1608,19 @@ static int call_nt_transact_query_security_desc(connection_struct *conn,
files_struct *fsp = file_fsp(params,0);
if(!fsp)
- return(ERROR(ERRDOS,ERRbadfid));
+ return ERROR_DOS(ERRDOS,ERRbadfid);
DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name ));
params = Realloc(*ppparams, 4);
if(params == NULL)
- return(ERROR(ERRDOS,ERRnomem));
+ return ERROR_DOS(ERRDOS,ERRnomem);
*ppparams = params;
if ((mem_ctx = talloc_init()) == NULL) {
DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n"));
- return(ERROR(ERRDOS,ERRnomem));
+ return ERROR_DOS(ERRDOS,ERRnomem);
}
/*
@@ -1650,7 +1643,7 @@ static int call_nt_transact_query_security_desc(connection_struct *conn,
if(max_data_count < sd_size) {
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL, ERRDOS, 122,
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL,
params, 4, *ppdata, 0);
talloc_destroy(mem_ctx);
return -1;
@@ -1663,7 +1656,7 @@ static int call_nt_transact_query_security_desc(connection_struct *conn,
data = Realloc(*ppdata, sd_size);
if(data == NULL) {
talloc_destroy(mem_ctx);
- return(ERROR(ERRDOS,ERRnomem));
+ return ERROR_DOS(ERRDOS,ERRnomem);
}
*ppdata = data;
@@ -1703,7 +1696,7 @@ security descriptor.\n"));
talloc_destroy(mem_ctx);
- send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, params, 4, data, (int)sd_size);
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size);
return -1;
}
@@ -1726,10 +1719,10 @@ static int call_nt_transact_set_security_desc(connection_struct *conn,
uint32 error_code;
if(total_parameter_count < 8)
- return(ERROR(ERRDOS,ERRbadfunc));
+ return ERROR_DOS(ERRDOS,ERRbadfunc);
if((fsp = file_fsp(params,0)) == NULL)
- return(ERROR(ERRDOS,ERRbadfid));
+ return ERROR_DOS(ERRDOS,ERRbadfid);
if(!lp_nt_acl_support(SNUM(conn)))
goto done;
@@ -1740,11 +1733,11 @@ static int call_nt_transact_set_security_desc(connection_struct *conn,
(unsigned int)security_info_sent ));
if (!set_sd( fsp, data, total_data_count, security_info_sent, &error_class, &error_code))
- return (ERROR(error_class, error_code));
+ return ERROR_DOS(error_class, error_code);
done:
- send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, NULL, 0, NULL, 0);
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
return -1;
}
@@ -1759,10 +1752,10 @@ static int call_nt_transact_ioctl(connection_struct *conn,
static BOOL logged_message = False;
if(!logged_message) {
- DEBUG(0,("call_nt_transact_ioctl: Currently not implemented.\n"));
+ DEBUG(2,("call_nt_transact_ioctl: Currently not implemented.\n"));
logged_message = True; /* Only print this once... */
}
- return(ERROR_BOTH(NT_STATUS_NOT_IMPLEMENTED,ERRSRV,ERRnosupport));
+ return ERROR_DOS(ERRSRV,ERRnosupport);
}
/****************************************************************************
@@ -1804,7 +1797,7 @@ due to being in oplock break state.\n" ));
if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
END_PROFILE(SMBnttrans);
- return (ERROR(ERRSRV,ERRaccess));
+ return ERROR_DOS(ERRSRV,ERRaccess);
}
outsize = set_message(outbuf,0,0,True);
@@ -1818,7 +1811,7 @@ due to being in oplock break state.\n" ));
DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
END_PROFILE(SMBnttrans);
- return(ERROR(ERRSRV,ERRerror));
+ return ERROR_DOS(ERRSRV,ERRerror);
}
/* Allocate the space for the setup, the maximum needed parameters and data */
@@ -1837,7 +1830,7 @@ due to being in oplock break state.\n" ));
safe_free(data);
DEBUG(0,("reply_nttrans : Out of memory\n"));
END_PROFILE(SMBnttrans);
- return(ERROR(ERRDOS,ERRnomem));
+ return ERROR_DOS(ERRDOS,ERRnomem);
}
/* Copy the param and data bytes sent with this request into
@@ -1846,7 +1839,7 @@ due to being in oplock break state.\n" ));
num_data_sofar = data_count;
if (parameter_count > total_parameter_count || data_count > total_data_count)
- exit_server("reply_nttrans: invalid sizes in packet.\n");
+ exit_server("reply_nttrans: invalid sizes in packet.");
if(setup) {
memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
@@ -1869,7 +1862,7 @@ due to being in oplock break state.\n" ));
of the parameter/data bytes */
outsize = set_message(outbuf,0,0,True);
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_nttrans: send_smb failed.\n");
+ exit_server("reply_nttrans: send_smb failed.");
while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
BOOL ret;
@@ -1884,14 +1877,11 @@ due to being in oplock break state.\n" ));
DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
(smb_read_error == READ_ERROR) ? "error" : "timeout" ));
}
- if(params)
- free(params);
- if(data)
- free(data);
- if(setup)
- free(setup);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ SAFE_FREE(setup);
END_PROFILE(SMBnttrans);
- return(ERROR(ERRSRV,ERRerror));
+ return ERROR_DOS(ERRSRV,ERRerror);
}
/* Revise total_params and total_data in case they have changed downwards */
@@ -1900,7 +1890,7 @@ due to being in oplock break state.\n" ));
num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount));
num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount));
if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count)
- exit_server("reply_nttrans2: data overflow in secondary nttrans packet\n");
+ exit_server("reply_nttrans2: data overflow in secondary nttrans packet");
memcpy( &params[ IVAL(inbuf, smb_nts_ParameterDisplacement)],
smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count);
@@ -1910,8 +1900,7 @@ due to being in oplock break state.\n" ));
}
if (Protocol >= PROTOCOL_NT1) {
- uint16 flg2 = SVAL(outbuf,smb_flg2);
- SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
}
/* Now we must call the relevant NT_TRANS function */
@@ -1961,14 +1950,11 @@ due to being in oplock break state.\n" ));
default:
/* Error in request */
DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
- if(setup)
- free(setup);
- if(params)
- free(params);
- if(data)
- free(data);
+ SAFE_FREE(setup);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
END_PROFILE(SMBnttrans);
- return (ERROR(ERRSRV,ERRerror));
+ return ERROR_DOS(ERRSRV,ERRerror);
}
/* As we do not know how many data packets will need to be
@@ -1978,12 +1964,9 @@ due to being in oplock break state.\n" ));
an error packet.
*/
- if(setup)
- free(setup);
- if(params)
- free(params);
- if(data)
- free(data);
+ 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
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 6919249a226..9cefcc9b45e 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -22,8 +22,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
extern userdom_struct current_user_info;
extern uint16 global_oplock_port;
extern BOOL global_client_failed_oplock_break;
@@ -36,8 +34,10 @@ static int fd_open(struct connection_struct *conn, char *fname,
int flags, mode_t mode)
{
int fd;
-#ifdef O_NONBLOCK
- flags |= O_NONBLOCK;
+
+#ifdef O_NOFOLLOW
+ if (!lp_symlinks(SNUM(conn)))
+ flags |= O_NOFOLLOW;
#endif
fd = conn->vfs_ops.open(conn,dos_to_unix(fname,False),flags,mode);
@@ -184,7 +184,6 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
fsp->mode = psbuf->st_mode;
fsp->inode = psbuf->st_ino;
fsp->dev = psbuf->st_dev;
- GetTimeOfDay(&fsp->open_time);
fsp->vuid = current_user.vuid;
fsp->size = psbuf->st_size;
fsp->pos = -1;
@@ -216,16 +215,6 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
conn->num_files_open + 1));
- /*
- * Take care of inherited ACLs on created files. JRA.
- */
-
- if ((flags & O_CREAT) && (conn->vfs_ops.fchmod_acl != NULL)) {
- int saved_errno = errno; /* We might get ENOSYS in the next call.. */
- if (conn->vfs_ops.fchmod_acl(fsp, fsp->fd, mode) == -1 && errno == ENOSYS)
- errno = saved_errno; /* Ignore ENOSYS */
- }
-
return True;
}
@@ -364,7 +353,7 @@ static int access_table(int new_deny,int old_deny,int old_mode,
check if we can open a file with a share mode
****************************************************************************/
-static int check_share_mode( share_mode_entry *share, int share_mode,
+static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode,
const char *fname, BOOL fcbopen, int *flags)
{
int deny_mode = GET_DENY_MODE(share_mode);
@@ -372,6 +361,14 @@ static int check_share_mode( share_mode_entry *share, int share_mode,
int old_deny_mode = GET_DENY_MODE(share->share_mode);
/*
+ * share modes = false means don't bother to check for
+ * DENY mode conflict. This is a *really* bad idea :-). JRA.
+ */
+
+ if(!lp_share_modes(SNUM(conn)))
+ return True;
+
+ /*
* Don't allow any opens once the delete on close flag has been
* set.
*/
@@ -500,7 +497,7 @@ dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsi
/* Oplock break - unlock to request it. */
unlock_share_entry(conn, dev, inode);
- opb_ret = request_oplock_break(share_entry, dev, inode);
+ opb_ret = request_oplock_break(share_entry);
/* Now relock. */
lock_share_entry(conn, dev, inode);
@@ -508,7 +505,7 @@ dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsi
if(opb_ret == False) {
DEBUG(0,("open_mode_check: FAILED when breaking oplock (%x) on file %s, \
dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode));
- free((char *)old_shares);
+ SAFE_FREE(old_shares);
errno = EACCES;
unix_ERR_class = ERRDOS;
unix_ERR_code = ERRbadshare;
@@ -526,8 +523,8 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
/* someone else has a share lock on it, check to see
if we can too */
- if(check_share_mode(share_entry, share_mode, fname, fcbopen, p_flags) == False) {
- free((char *)old_shares);
+ if(check_share_mode(conn, share_entry, share_mode, fname, fcbopen, p_flags) == False) {
+ SAFE_FREE(old_shares);
errno = EACCES;
return -1;
}
@@ -535,7 +532,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
} /* end for */
if(broke_oplock) {
- free((char *)old_shares);
+ SAFE_FREE(old_shares);
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
oplock_contention_count++;
@@ -555,11 +552,8 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fname, (unsigned int)dev, (double)inode));
if (process_exists(broken_entry.pid)) {
- pstring errmsg;
- slprintf(errmsg, sizeof(errmsg)-1,
- "open_mode_check: Existant process %d left active oplock.\n",
- broken_entry.pid );
- smb_panic(errmsg);
+ DEBUG(0,("open_mode_check: Existent process %d left active oplock.\n",
+ broken_entry.pid ));
}
if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) {
@@ -574,7 +568,7 @@ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fn
* other process's entry.
*/
- free((char *)old_shares);
+ SAFE_FREE(old_shares);
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
break;
}
@@ -583,8 +577,7 @@ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fn
} while(broke_oplock);
- if(old_shares != 0)
- free((char *)old_shares);
+ SAFE_FREE(old_shares);
/*
* Refuse to grant an oplock in case the contention limit is
@@ -629,6 +622,7 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
int deny_mode = GET_DENY_MODE(share_mode);
BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode);
BOOL delete_access_requested = GET_DELETE_ACCESS_REQUESTED(share_mode);
+ BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode);
BOOL file_existed = VALID_STAT(*psbuf);
BOOL fcbopen = False;
SMB_DEV_T dev = 0;
@@ -645,7 +639,7 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
of the passed parameters are ignored */
*Access = DOS_OPEN_WRONLY;
*action = FILE_WAS_CREATED;
- return print_fsp_open(conn);
+ return print_fsp_open(conn, fname);
}
fsp = file_new(conn);
@@ -688,10 +682,10 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
return NULL;
}
- if (GET_FILE_CREATE_DISPOSITION(ofun) == FILE_CREATE_IF_NOT_EXIST)
+ if (CAN_WRITE(conn) && (GET_FILE_CREATE_DISPOSITION(ofun) == FILE_CREATE_IF_NOT_EXIST))
flags2 |= O_CREAT;
- if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)
+ if (CAN_WRITE(conn) && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE))
flags2 |= O_TRUNC;
if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL)
@@ -916,6 +910,27 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
set_share_mode(fsp, port, oplock_request);
+ if (delete_on_close) {
+ NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close);
+
+ if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) {
+ unlock_share_entry_fsp(fsp);
+ fd_close(conn,fsp);
+ file_free(fsp);
+ return NULL;
+ }
+ }
+
+ /*
+ * Take care of inherited ACLs on created files. JRA.
+ */
+
+ if (!file_existed && (conn->vfs_ops.fchmod_acl != NULL)) {
+ int saved_errno = errno; /* We might get ENOSYS in the next call.. */
+ if (conn->vfs_ops.fchmod_acl(fsp, fsp->fd, mode) == -1 && errno == ENOSYS)
+ errno = saved_errno; /* Ignore ENOSYS */
+ }
+
unlock_share_entry_fsp(fsp);
conn->num_files_open++;
@@ -956,11 +971,9 @@ files_struct *open_file_stat(connection_struct *conn, char *fname,
* Setup the files_struct for it.
*/
- fsp->fd = -1;
fsp->mode = psbuf->st_mode;
fsp->inode = psbuf->st_ino;
fsp->dev = psbuf->st_dev;
- GetTimeOfDay(&fsp->open_time);
fsp->size = psbuf->st_size;
fsp->vuid = current_user.vuid;
fsp->pos = -1;
@@ -985,7 +998,7 @@ files_struct *open_file_stat(connection_struct *conn, char *fname,
*/
string_set(&fsp->fsp_name,fname);
fsp->wbmpx_ptr = NULL;
- fsp->wcp = NULL; /* Write cache pointer. */
+ fsp->wcp = NULL; /* Write cache pointer. */
conn->num_files_open++;
@@ -1040,11 +1053,12 @@ int close_file_fchmod(files_struct *fsp)
****************************************************************************/
files_struct *open_directory(connection_struct *conn, char *fname,
- SMB_STRUCT_STAT *psbuf, int smb_ofun, mode_t unixmode, int *action)
+ SMB_STRUCT_STAT *psbuf, int share_mode, int smb_ofun, mode_t unixmode, int *action)
{
extern struct current_user current_user;
BOOL got_stat = False;
files_struct *fsp = file_new(conn);
+ BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode);
if(!fsp)
return NULL;
@@ -1128,18 +1142,16 @@ files_struct *open_directory(connection_struct *conn, char *fname,
* Setup the files_struct for it.
*/
- fsp->fd = -1;
fsp->mode = psbuf->st_mode;
fsp->inode = psbuf->st_ino;
fsp->dev = psbuf->st_dev;
- GetTimeOfDay(&fsp->open_time);
fsp->size = psbuf->st_size;
fsp->vuid = current_user.vuid;
fsp->pos = -1;
fsp->can_lock = True;
fsp->can_read = False;
fsp->can_write = False;
- fsp->share_mode = 0;
+ fsp->share_mode = share_mode;
fsp->print_file = False;
fsp->modified = False;
fsp->oplock_type = NO_OPLOCK;
@@ -1147,6 +1159,16 @@ files_struct *open_directory(connection_struct *conn, char *fname,
fsp->is_directory = True;
fsp->directory_delete_on_close = False;
fsp->conn = conn;
+
+ if (delete_on_close) {
+ NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close);
+
+ if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) {
+ file_free(fsp);
+ return NULL;
+ }
+ }
+
/*
* Note that the file name here is the *untranslated* name
* ie. it is still in the DOS codepage sent from the client.
@@ -1256,12 +1278,12 @@ dev = %x, inode = %.0f\n", share_entry->op_type, fname, (unsigned int)dev, (doub
/* Oplock break.... */
unlock_share_entry(conn, dev, inode);
- if(request_oplock_break(share_entry, dev, inode) == False)
+ if(request_oplock_break(share_entry) == False)
{
DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode));
- free((char *)old_shares);
+ SAFE_FREE(old_shares);
return False;
}
lock_share_entry(conn, dev, inode);
@@ -1291,7 +1313,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
if(broke_oplock)
{
- free((char *)old_shares);
+ SAFE_FREE(old_shares);
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
}
} while(broke_oplock);
@@ -1312,7 +1334,6 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
free_and_exit:
unlock_share_entry(conn, dev, inode);
- if(old_shares != NULL)
- free((char *)old_shares);
+ SAFE_FREE(old_shares);
return(ret);
}
diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c
index 7033eddc163..cae94bc7a8f 100644
--- a/source/smbd/oplock.c
+++ b/source/smbd/oplock.c
@@ -1,8 +1,9 @@
/*
Unix SMB/Netbios implementation.
- Version 1.9.
+ Version 2.2.x
oplock processing
Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998 - 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,8 +22,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
/* Oplock ipc UDP socket. */
static int oplock_sock = -1;
uint16 global_oplock_port = 0;
@@ -37,7 +36,7 @@ extern int smb_read_error;
static struct kernel_oplocks *koplocks;
-static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local);
+static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id, BOOL local);
/****************************************************************************
Get the number of current exclusive oplocks.
@@ -76,97 +75,97 @@ BOOL oplock_message_waiting(fd_set *fds)
BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeout)
{
- struct sockaddr_in from;
- int fromlen = sizeof(from);
- int32 msg_len = 0;
-
- smb_read_error = 0;
-
- if(timeout != 0) {
- struct timeval to;
- int selrtn;
- int maxfd = oplock_sock;
-
- if (koplocks && koplocks->notification_fd != -1) {
- FD_SET(koplocks->notification_fd, fds);
- maxfd = MAX(maxfd, koplocks->notification_fd);
- }
-
- to.tv_sec = timeout / 1000;
- to.tv_usec = (timeout % 1000) * 1000;
-
- selrtn = sys_select(maxfd+1,fds,&to);
-
- if (selrtn == -1 && errno == EINTR) {
- /* could be a kernel oplock interrupt */
- if (koplocks && koplocks->msg_waiting(fds)) {
- return koplocks->receive_message(fds, buffer, buffer_len);
- }
- }
-
- /* Check if error */
- if(selrtn == -1) {
- /* something is wrong. Maybe the socket is dead? */
- smb_read_error = READ_ERROR;
- return False;
- }
-
- /* Did we timeout ? */
- if (selrtn == 0) {
- smb_read_error = READ_TIMEOUT;
- return False;
- }
- }
-
- if (koplocks && koplocks->msg_waiting(fds)) {
- return koplocks->receive_message(fds, buffer, buffer_len);
- }
-
- if (!FD_ISSET(oplock_sock, fds)) return False;
-
- /*
- * From here down we deal with the smbd <--> smbd
- * oplock break protocol only.
- */
-
- /*
- * Read a loopback udp message.
- */
- msg_len = recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN],
- buffer_len - OPBRK_CMD_HEADER_LEN, 0,
- (struct sockaddr *)&from, &fromlen);
-
- if(msg_len < 0) {
- DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno)));
- return False;
- }
-
- /* Validate message length. */
- if(msg_len > (buffer_len - OPBRK_CMD_HEADER_LEN)) {
- DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n",
- msg_len,
- buffer_len - OPBRK_CMD_HEADER_LEN));
- return False;
- }
-
- /* Validate message from address (must be localhost). */
- if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
- DEBUG(0,("receive_local_message: invalid 'from' address \
-(was %lx should be 127.0.0.1\n", (long)from.sin_addr.s_addr));
- return False;
- }
-
- /* Setup the message header */
- SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,msg_len);
- SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,ntohs(from.sin_port));
-
- return True;
+ struct sockaddr_in from;
+ int fromlen = sizeof(from);
+ int32 msg_len = 0;
+
+ smb_read_error = 0;
+
+ if(timeout != 0) {
+ struct timeval to;
+ int selrtn;
+ int maxfd = oplock_sock;
+
+ if (koplocks && koplocks->notification_fd != -1) {
+ FD_SET(koplocks->notification_fd, fds);
+ maxfd = MAX(maxfd, koplocks->notification_fd);
+ }
+
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+
+ selrtn = sys_select(maxfd+1,fds,NULL,NULL,&to);
+
+ if (selrtn == -1 && errno == EINTR) {
+ /* could be a kernel oplock interrupt */
+ if (koplocks && koplocks->msg_waiting(fds)) {
+ return koplocks->receive_message(fds, buffer, buffer_len);
+ }
+ }
+
+ /* Check if error */
+ if(selrtn == -1) {
+ /* something is wrong. Maybe the socket is dead? */
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ smb_read_error = READ_TIMEOUT;
+ return False;
+ }
+ }
+
+ if (koplocks && koplocks->msg_waiting(fds)) {
+ return koplocks->receive_message(fds, buffer, buffer_len);
+ }
+
+ if (!FD_ISSET(oplock_sock, fds))
+ return False;
+
+ /*
+ * From here down we deal with the smbd <--> smbd
+ * oplock break protocol only.
+ */
+
+ /*
+ * Read a loopback udp message.
+ */
+ msg_len = recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN],
+ buffer_len - OPBRK_CMD_HEADER_LEN, 0, (struct sockaddr *)&from, &fromlen);
+
+ if(msg_len < 0) {
+ DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno)));
+ return False;
+ }
+
+ /* Validate message length. */
+ if(msg_len > (buffer_len - OPBRK_CMD_HEADER_LEN)) {
+ DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n", msg_len,
+ buffer_len - OPBRK_CMD_HEADER_LEN));
+ return False;
+ }
+
+ /* Validate message from address (must be localhost). */
+ if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
+ DEBUG(0,("receive_local_message: invalid 'from' address \
+(was %lx should be 127.0.0.1)\n", (long)from.sin_addr.s_addr));
+ return False;
+ }
+
+ /* Setup the message header */
+ SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,msg_len);
+ SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,ntohs(from.sin_port));
+
+ return True;
}
/****************************************************************************
Attempt to set an oplock on a file. Always succeeds if kernel oplocks are
disabled (just sets flags). Returns True if oplock set.
****************************************************************************/
+
BOOL set_file_oplock(files_struct *fsp, int oplock_type)
{
if (koplocks && !koplocks->set_oplock(fsp, oplock_type))
@@ -179,8 +178,9 @@ BOOL set_file_oplock(files_struct *fsp, int oplock_type)
else
exclusive_oplocks_open++;
- DEBUG(5,("set_file_oplock: granted oplock on file %s, dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
- fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode,
+ DEBUG(5,("set_file_oplock: granted oplock on file %s, dev = %x, inode = %.0f, file_id = %lu, \
+tv_sec = %x, tv_usec = %x\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id,
(int)fsp->open_time.tv_sec, (int)fsp->open_time.tv_usec ));
return True;
@@ -192,7 +192,8 @@ BOOL set_file_oplock(files_struct *fsp, int oplock_type)
void release_file_oplock(files_struct *fsp)
{
- if (koplocks) koplocks->release_oplock(fsp);
+ if (koplocks)
+ koplocks->release_oplock(fsp);
if (fsp->oplock_type == LEVEL_II_OPLOCK)
level_II_oplocks_open--;
@@ -211,7 +212,8 @@ void release_file_oplock(files_struct *fsp)
static void downgrade_file_oplock(files_struct *fsp)
{
- if (koplocks) koplocks->release_oplock(fsp);
+ if (koplocks)
+ koplocks->release_oplock(fsp);
fsp->oplock_type = LEVEL_II_OPLOCK;
exclusive_oplocks_open--;
level_II_oplocks_open++;
@@ -293,161 +295,142 @@ int setup_oplock_select_set( fd_set *fds)
Process an oplock break message - whether it came from the UDP socket
or from the kernel.
****************************************************************************/
+
BOOL process_local_message(char *buffer, int buf_size)
{
- int32 msg_len;
- uint16 from_port;
- char *msg_start;
- SMB_DEV_T dev;
- SMB_INO_T inode;
- pid_t remotepid;
- struct timeval tval;
- struct timeval *ptval = NULL;
- uint16 break_cmd_type;
-
- msg_len = IVAL(buffer,OPBRK_CMD_LEN_OFFSET);
- from_port = SVAL(buffer,OPBRK_CMD_PORT_OFFSET);
-
- msg_start = &buffer[OPBRK_CMD_HEADER_LEN];
-
- DEBUG(5,("process_local_message: Got a message of length %d from port (%d)\n",
- msg_len, from_port));
-
- /*
- * Pull the info out of the requesting packet.
- */
-
- break_cmd_type = SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET);
-
- switch(break_cmd_type)
- {
- case KERNEL_OPLOCK_BREAK_CMD:
- if (!koplocks) {
- DEBUG(0,("unexpected kernel oplock break!\n"));
- break;
- }
- if (!koplocks->parse_message(msg_start, msg_len, &inode, &dev)) {
- DEBUG(0,("kernel oplock break parse failure!\n"));
- }
- break;
-
- case OPLOCK_BREAK_CMD:
- case LEVEL_II_OPLOCK_BREAK_CMD:
-
- /* Ensure that the msg length is correct. */
- if(msg_len != OPLOCK_BREAK_MSG_LEN)
- {
- DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, should be %d).\n",
- (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN));
- return False;
- }
- {
- long usec;
- time_t sec;
-
- memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
- memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
- memcpy((char *)&sec, msg_start+OPLOCK_BREAK_SEC_OFFSET,sizeof(sec));
- tval.tv_sec = sec;
- memcpy((char *)&usec, msg_start+OPLOCK_BREAK_USEC_OFFSET, sizeof(usec));
- tval.tv_usec = usec;
-
- ptval = &tval;
-
- memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
-
- DEBUG(5,("process_local_message: (%s) oplock break request from \
-pid %d, port %d, dev = %x, inode = %.0f\n",
- (break_cmd_type == OPLOCK_BREAK_CMD) ? "exclusive" : "level II",
- (int)remotepid, from_port, (unsigned int)dev, (double)inode));
- }
- break;
-
- /*
- * Keep this as a debug case - eventually we can remove it.
- */
- case 0x8001:
- DEBUG(0,("process_local_message: Received unsolicited break \
+ int32 msg_len;
+ uint16 from_port;
+ char *msg_start;
+ pid_t remotepid;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ unsigned long file_id;
+ uint16 break_cmd_type;
+
+ msg_len = IVAL(buffer,OPBRK_CMD_LEN_OFFSET);
+ from_port = SVAL(buffer,OPBRK_CMD_PORT_OFFSET);
+
+ msg_start = &buffer[OPBRK_CMD_HEADER_LEN];
+
+ DEBUG(5,("process_local_message: Got a message of length %d from port (%d)\n",
+ msg_len, from_port));
+
+ /*
+ * Pull the info out of the requesting packet.
+ */
+
+ break_cmd_type = SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET);
+
+ switch(break_cmd_type) {
+ case KERNEL_OPLOCK_BREAK_CMD:
+ if (!koplocks) {
+ DEBUG(0,("unexpected kernel oplock break!\n"));
+ break;
+ }
+ if (!koplocks->parse_message(msg_start, msg_len, &inode, &dev, &file_id)) {
+ DEBUG(0,("kernel oplock break parse failure!\n"));
+ }
+ break;
+
+ case OPLOCK_BREAK_CMD:
+ case LEVEL_II_OPLOCK_BREAK_CMD:
+
+ /* Ensure that the msg length is correct. */
+ if(msg_len != OPLOCK_BREAK_MSG_LEN) {
+ DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, should be %d).\n",
+ (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+
+ memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
+ memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
+ memcpy((char *)&file_id, msg_start+OPLOCK_BREAK_FILEID_OFFSET,sizeof(file_id));
+
+ DEBUG(5,("process_local_message: (%s) oplock break request from \
+pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n",
+ (break_cmd_type == OPLOCK_BREAK_CMD) ? "exclusive" : "level II",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id));
+ break;
+
+ /*
+ * Keep this as a debug case - eventually we can remove it.
+ */
+ case 0x8001:
+ DEBUG(0,("process_local_message: Received unsolicited break \
reply - dumping info.\n"));
- if(msg_len != OPLOCK_BREAK_MSG_LEN)
- {
- DEBUG(0,("process_local_message: ubr: incorrect length for reply \
+ if(msg_len != OPLOCK_BREAK_MSG_LEN) {
+ DEBUG(0,("process_local_message: ubr: incorrect length for reply \
(was %d, should be %d).\n", (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN));
- return False;
- }
-
- {
- memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
- memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
- memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
-
- DEBUG(0,("process_local_message: unsolicited oplock break reply from \
-pid %d, port %d, dev = %x, inode = %.0f\n", (int)remotepid, from_port, (unsigned int)dev, (double)inode));
-
- }
- return False;
-
- default:
- DEBUG(0,("process_local_message: unknown UDP message command code (%x) - ignoring.\n",
- (unsigned int)SVAL(msg_start,0)));
- return False;
- }
-
- /*
- * Now actually process the break request.
- */
-
- if((exclusive_oplocks_open + level_II_oplocks_open) != 0)
- {
- if (oplock_break(dev, inode, ptval, False) == False)
- {
- DEBUG(0,("process_local_message: oplock break failed.\n"));
- return False;
- }
- }
- else
- {
- /*
- * If we have no record of any currently open oplocks,
- * it's not an error, as a close command may have
- * just been issued on the file that was oplocked.
- * Just log a message and return success in this case.
- */
- DEBUG(3,("process_local_message: oplock break requested with no outstanding \
+ return False;
+ }
+
+ memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
+ memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
+ memcpy((char *)&file_id, msg_start+OPLOCK_BREAK_FILEID_OFFSET,sizeof(file_id));
+
+ DEBUG(0,("process_local_message: unsolicited oplock break reply from \
+pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id));
+
+ return False;
+
+ default:
+ DEBUG(0,("process_local_message: unknown UDP message command code (%x) - ignoring.\n",
+ (unsigned int)SVAL(msg_start,0)));
+ return False;
+ }
+
+ /*
+ * Now actually process the break request.
+ */
+
+ if((exclusive_oplocks_open + level_II_oplocks_open) != 0) {
+ if (oplock_break(dev, inode, file_id, False) == False) {
+ DEBUG(0,("process_local_message: oplock break failed.\n"));
+ return False;
+ }
+ } else {
+ /*
+ * If we have no record of any currently open oplocks,
+ * it's not an error, as a close command may have
+ * just been issued on the file that was oplocked.
+ * Just log a message and return success in this case.
+ */
+ DEBUG(3,("process_local_message: oplock break requested with no outstanding \
oplocks. Returning success.\n"));
- }
-
- /*
- * Do the appropriate reply - none in the kernel or level II case.
- */
-
- if(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET) == OPLOCK_BREAK_CMD)
- {
- struct sockaddr_in toaddr;
-
- /* Send the message back after OR'ing in the 'REPLY' bit. */
- SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY);
-
- memset((char *)&toaddr,'\0',sizeof(toaddr));
- toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- toaddr.sin_port = htons(from_port);
- toaddr.sin_family = AF_INET;
-
- if(sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0,
- (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0)
- {
- DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n",
- (int)remotepid, strerror(errno)));
- return False;
- }
-
- DEBUG(5,("process_local_message: oplock break reply sent to \
-pid %d, port %d, for file dev = %x, inode = %.0f\n",
- (int)remotepid, from_port, (unsigned int)dev, (double)inode));
- }
-
- return True;
+ }
+
+ /*
+ * Do the appropriate reply - none in the kernel or level II case.
+ */
+
+ if(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET) == OPLOCK_BREAK_CMD) {
+ struct sockaddr_in toaddr;
+
+ /* Send the message back after OR'ing in the 'REPLY' bit. */
+ SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY);
+
+ memset((char *)&toaddr,'\0',sizeof(toaddr));
+ toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ toaddr.sin_port = htons(from_port);
+ toaddr.sin_family = AF_INET;
+
+ if(sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0,
+ (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) {
+ DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n",
+ (int)remotepid, strerror(errno)));
+ return False;
+ }
+
+ DEBUG(5,("process_local_message: oplock break reply sent to \
+pid %d, port %d, for file dev = %x, inode = %.0f, file_id = %lu\n",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id));
+ }
+
+ return True;
}
/****************************************************************************
@@ -476,81 +459,82 @@ static void prepare_break_message(char *outbuf, files_struct *fsp, BOOL level2)
static void wait_before_sending_break(BOOL local_request)
{
- extern struct timeval smb_last_time;
+ extern struct timeval smb_last_time;
- if(local_request) {
- struct timeval cur_tv;
- long wait_left = (long)lp_oplock_break_wait_time();
+ if(local_request) {
+ struct timeval cur_tv;
+ long wait_left = (long)lp_oplock_break_wait_time();
- if (wait_left == 0)
- return;
+ if (wait_left == 0)
+ return;
- GetTimeOfDay(&cur_tv);
+ GetTimeOfDay(&cur_tv);
- wait_left -= ((cur_tv.tv_sec - smb_last_time.tv_sec)*1000) +
+ wait_left -= ((cur_tv.tv_sec - smb_last_time.tv_sec)*1000) +
((cur_tv.tv_usec - smb_last_time.tv_usec)/1000);
- if(wait_left > 0) {
- wait_left = MIN(wait_left, 1000);
- sys_usleep(wait_left * 1000);
- }
- }
+ if(wait_left > 0) {
+ wait_left = MIN(wait_left, 1000);
+ sys_usleep(wait_left * 1000);
+ }
+ }
}
/****************************************************************************
Ensure that we have a valid oplock.
****************************************************************************/
-static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
+
+static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id)
{
- files_struct *fsp = NULL;
-
- if( DEBUGLVL( 3 ) )
- {
- dbgtext( "initial_break_processing: called for dev = %x, inode = %.0f tv_sec = %x, tv_usec = %x.\n",
- (unsigned int)dev, (double)inode, tval ? (int)tval->tv_sec : 0,
- tval ? (int)tval->tv_usec : 0);
- dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
- exclusive_oplocks_open, level_II_oplocks_open );
- }
-
- /* We need to search the file open table for the
- entry containing this dev and inode, and ensure
- we have an oplock on it. */
- fsp = file_find_dit(dev, inode, tval);
-
- if(fsp == NULL)
- {
- /* The file could have been closed in the meantime - return success. */
- if( DEBUGLVL( 3 ) )
- {
- dbgtext( "initial_break_processing: cannot find open file with " );
- dbgtext( "dev = %x, inode = %.0f ", (unsigned int)dev, (double)inode);
- dbgtext( "allowing break to succeed.\n" );
- }
- return NULL;
- }
-
- /* Ensure we have an oplock on the file */
-
- /* There is a potential race condition in that an oplock could
- have been broken due to another udp request, and yet there are
- still oplock break messages being sent in the udp message
- queue for this file. So return true if we don't have an oplock,
- as we may have just freed it.
- */
-
- if(fsp->oplock_type == NO_OPLOCK)
- {
- if( DEBUGLVL( 3 ) )
- {
- dbgtext( "initial_break_processing: file %s ", fsp->fsp_name );
- dbgtext( "(dev = %x, inode = %.0f) has no oplock.\n", (unsigned int)dev, (double)inode );
- dbgtext( "Allowing break to succeed regardless.\n" );
- }
- return NULL;
- }
-
- return fsp;
+ files_struct *fsp = NULL;
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "initial_break_processing: called for dev = %x, inode = %.0f file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id);
+ dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
+ exclusive_oplocks_open, level_II_oplocks_open );
+ }
+
+ /*
+ * We need to search the file open table for the
+ * entry containing this dev and inode, and ensure
+ * we have an oplock on it.
+ */
+
+ fsp = file_find_dif(dev, inode, file_id);
+
+ if(fsp == NULL) {
+ /* The file could have been closed in the meantime - return success. */
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "initial_break_processing: cannot find open file with " );
+ dbgtext( "dev = %x, inode = %.0f file_id = %lu", (unsigned int)dev,
+ (double)inode, file_id);
+ dbgtext( "allowing break to succeed.\n" );
+ }
+ return NULL;
+ }
+
+ /* Ensure we have an oplock on the file */
+
+ /*
+ * There is a potential race condition in that an oplock could
+ * have been broken due to another udp request, and yet there are
+ * still oplock break messages being sent in the udp message
+ * queue for this file. So return true if we don't have an oplock,
+ * as we may have just freed it.
+ */
+
+ if(fsp->oplock_type == NO_OPLOCK) {
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "initial_break_processing: file %s ", fsp->fsp_name );
+ dbgtext( "(dev = %x, inode = %.0f, file_id = %lu) has no oplock.\n",
+ (unsigned int)dev, (double)inode, fsp->file_id );
+ dbgtext( "Allowing break to succeed regardless.\n" );
+ }
+ return NULL;
+ }
+
+ return fsp;
}
/****************************************************************************
@@ -559,336 +543,322 @@ static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, st
BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token)
{
- extern uint32 global_client_caps;
- char outbuf[128];
- BOOL got_lock = False;
- SMB_DEV_T dev = fsp->dev;
- SMB_INO_T inode = fsp->inode;
-
- /*
- * We can have a level II oplock even if the client is not
- * level II oplock aware. In this case just remove the
- * flags and don't send the break-to-none message to
- * the client.
- */
-
- if (global_client_caps & CAP_LEVEL_II_OPLOCKS) {
- /*
- * If we are sending an oplock break due to an SMB sent
- * by our own client we ensure that we wait at leat
- * lp_oplock_break_wait_time() milliseconds before sending
- * the packet. Sending the packet sooner can break Win9x
- * and has reported to cause problems on NT. JRA.
- */
-
- wait_before_sending_break(local_request);
-
- /* Prepare the SMBlockingX message. */
-
- prepare_break_message( outbuf, fsp, False);
- if (!send_smb(smbd_server_fd(), outbuf))
- exit_server("oplock_break_level2: send_smb failed.\n");
- }
-
- /*
- * Now we must update the shared memory structure to tell
- * everyone else we no longer have a level II oplock on
- * this open file. If local_request is true then token is
- * the existing lock on the shared memory area.
- */
-
- if(!local_request && lock_share_entry_fsp(fsp) == False) {
- DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name ));
- } else {
- got_lock = True;
- }
-
- if(remove_share_oplock(fsp)==False) {
- DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name ));
- }
-
- if (!local_request && got_lock)
- unlock_share_entry_fsp(fsp);
-
- fsp->oplock_type = NO_OPLOCK;
- level_II_oplocks_open--;
-
- if(level_II_oplocks_open < 0)
- {
- DEBUG(0,("oplock_break_level2: level_II_oplocks_open < 0 (%d). PANIC ERROR\n",
- level_II_oplocks_open));
- abort();
- }
-
- if( DEBUGLVL( 3 ) )
- {
- dbgtext( "oplock_break_level2: returning success for " );
- dbgtext( "dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
- dbgtext( "Current level II oplocks_open = %d\n", level_II_oplocks_open );
- }
-
- return True;
+ extern uint32 global_client_caps;
+ char outbuf[128];
+ BOOL got_lock = False;
+ SMB_DEV_T dev = fsp->dev;
+ SMB_INO_T inode = fsp->inode;
+
+ /*
+ * We can have a level II oplock even if the client is not
+ * level II oplock aware. In this case just remove the
+ * flags and don't send the break-to-none message to
+ * the client.
+ */
+
+ if (global_client_caps & CAP_LEVEL_II_OPLOCKS) {
+ /*
+ * If we are sending an oplock break due to an SMB sent
+ * by our own client we ensure that we wait at leat
+ * lp_oplock_break_wait_time() milliseconds before sending
+ * the packet. Sending the packet sooner can break Win9x
+ * and has reported to cause problems on NT. JRA.
+ */
+
+ wait_before_sending_break(local_request);
+
+ /* Prepare the SMBlockingX message. */
+
+ prepare_break_message( outbuf, fsp, False);
+ if (!send_smb(smbd_server_fd(), outbuf))
+ exit_server("oplock_break_level2: send_smb failed.\n");
+ }
+
+ /*
+ * Now we must update the shared memory structure to tell
+ * everyone else we no longer have a level II oplock on
+ * this open file. If local_request is true then token is
+ * the existing lock on the shared memory area.
+ */
+
+ if(!local_request && lock_share_entry_fsp(fsp) == False) {
+ DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name ));
+ } else {
+ got_lock = True;
+ }
+
+ if(remove_share_oplock(fsp)==False) {
+ DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name ));
+ }
+
+ if (!local_request && got_lock)
+ unlock_share_entry_fsp(fsp);
+
+ fsp->oplock_type = NO_OPLOCK;
+ level_II_oplocks_open--;
+
+ if(level_II_oplocks_open < 0) {
+ DEBUG(0,("oplock_break_level2: level_II_oplocks_open < 0 (%d). PANIC ERROR\n",
+ level_II_oplocks_open));
+ abort();
+ }
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "oplock_break_level2: returning success for " );
+ dbgtext( "dev = %x, inode = %.0f, file_id = %lu\n", (unsigned int)dev, (double)inode, fsp->file_id );
+ dbgtext( "Current level II oplocks_open = %d\n", level_II_oplocks_open );
+ }
+
+ return True;
}
/****************************************************************************
Process an oplock break directly.
****************************************************************************/
-static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local_request)
+static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id, BOOL local_request)
{
- extern uint32 global_client_caps;
- extern struct current_user current_user;
- char *inbuf = NULL;
- char *outbuf = NULL;
- files_struct *fsp = NULL;
- time_t start_time;
- BOOL shutdown_server = False;
- BOOL oplock_timeout = False;
- connection_struct *saved_user_conn;
- connection_struct *saved_fsp_conn;
- int saved_vuid;
- pstring saved_dir;
- int timeout = (OPLOCK_BREAK_TIMEOUT * 1000);
- pstring file_name;
- BOOL using_levelII;
-
- if((fsp = initial_break_processing(dev, inode, tval)) == NULL)
- return True;
-
- /*
- * Deal with a level II oplock going break to none separately.
- */
-
- if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
- return oplock_break_level2(fsp, local_request, -1);
-
- /* Mark the oplock break as sent - we don't want to send twice! */
- if (fsp->sent_oplock_break)
- {
- if( DEBUGLVL( 0 ) )
- {
- dbgtext( "oplock_break: ERROR: oplock_break already sent for " );
- dbgtext( "file %s ", fsp->fsp_name);
- dbgtext( "(dev = %x, inode = %.0f)\n", (unsigned int)dev, (double)inode );
- }
-
- /* We have to fail the open here as we cannot send another oplock break on
- this file whilst we are awaiting a response from the client - neither
- can we allow another open to succeed while we are waiting for the
- client.
- */
- return False;
- }
-
- if(global_oplock_break) {
- DEBUG(0,("ABORT : ABORT : recursion in oplock_break !!!!!\n"));
- abort();
- }
-
- /* Now comes the horrid part. We must send an oplock break to the client,
- and then process incoming messages until we get a close or oplock release.
- At this point we know we need a new inbuf/outbuf buffer pair.
- We cannot use these staticaly as we may recurse into here due to
- messages crossing on the wire.
- */
-
- if((inbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL)
- {
- DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
- return False;
- }
-
- if((outbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL)
- {
- DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
- free(inbuf);
- inbuf = NULL;
- return False;
- }
-
- /*
- * If we are sending an oplock break due to an SMB sent
- * by our own client we ensure that we wait at leat
- * lp_oplock_break_wait_time() milliseconds before sending
- * the packet. Sending the packet sooner can break Win9x
- * and has reported to cause problems on NT. JRA.
- */
-
- wait_before_sending_break(local_request);
-
- /* Prepare the SMBlockingX message. */
-
- if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
- !koplocks && /* NOTE: we force levelII off for kernel oplocks -
- this will change when it is supported */
- lp_level2_oplocks(SNUM(fsp->conn))) {
- using_levelII = True;
- } else {
- using_levelII = False;
- }
-
- prepare_break_message( outbuf, fsp, using_levelII);
- /* Remember if we just sent a break to level II on this file. */
- fsp->sent_oplock_break = using_levelII?
- LEVEL_II_BREAK_SENT:EXCLUSIVE_BREAK_SENT;
-
- if (!send_smb(smbd_server_fd(), outbuf))
- exit_server("oplock_break: send_smb failed.\n");
-
- /* We need this in case a readraw crosses on the wire. */
- global_oplock_break = True;
+ extern uint32 global_client_caps;
+ extern struct current_user current_user;
+ char *inbuf = NULL;
+ char *outbuf = NULL;
+ files_struct *fsp = NULL;
+ time_t start_time;
+ BOOL shutdown_server = False;
+ BOOL oplock_timeout = False;
+ connection_struct *saved_user_conn;
+ connection_struct *saved_fsp_conn;
+ int saved_vuid;
+ pstring saved_dir;
+ int timeout = (OPLOCK_BREAK_TIMEOUT * 1000);
+ pstring file_name;
+ BOOL using_levelII;
+
+ if((fsp = initial_break_processing(dev, inode, file_id)) == NULL)
+ return True;
+
+ /*
+ * Deal with a level II oplock going break to none separately.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ return oplock_break_level2(fsp, local_request, -1);
+
+ /* Mark the oplock break as sent - we don't want to send twice! */
+ if (fsp->sent_oplock_break) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "oplock_break: ERROR: oplock_break already sent for " );
+ dbgtext( "file %s ", fsp->fsp_name);
+ dbgtext( "(dev = %x, inode = %.0f, file_id = %lu)\n", (unsigned int)dev, (double)inode, fsp->file_id );
+ }
+
+ /*
+ * We have to fail the open here as we cannot send another oplock break on
+ * this file whilst we are awaiting a response from the client - neither
+ * can we allow another open to succeed while we are waiting for the client.
+ */
+ return False;
+ }
+
+ if(global_oplock_break) {
+ DEBUG(0,("ABORT : ABORT : recursion in oplock_break !!!!!\n"));
+ abort();
+ }
+
+ /*
+ * Now comes the horrid part. We must send an oplock break to the client,
+ * and then process incoming messages until we get a close or oplock release.
+ * At this point we know we need a new inbuf/outbuf buffer pair.
+ * We cannot use these staticaly as we may recurse into here due to
+ * messages crossing on the wire.
+ */
+
+ if((inbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) {
+ DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+ return False;
+ }
+
+ if((outbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) {
+ DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+ SAFE_FREE(inbuf);
+ return False;
+ }
+
+ /*
+ * If we are sending an oplock break due to an SMB sent
+ * by our own client we ensure that we wait at leat
+ * lp_oplock_break_wait_time() milliseconds before sending
+ * the packet. Sending the packet sooner can break Win9x
+ * and has reported to cause problems on NT. JRA.
+ */
+
+ wait_before_sending_break(local_request);
+
+ /* Prepare the SMBlockingX message. */
+
+ if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
+ !koplocks && /* NOTE: we force levelII off for kernel oplocks - this will change when it is supported */
+ lp_level2_oplocks(SNUM(fsp->conn))) {
+ using_levelII = True;
+ } else {
+ using_levelII = False;
+ }
+
+ prepare_break_message( outbuf, fsp, using_levelII);
+ /* Remember if we just sent a break to level II on this file. */
+ fsp->sent_oplock_break = using_levelII? LEVEL_II_BREAK_SENT:EXCLUSIVE_BREAK_SENT;
+
+ if (!send_smb(smbd_server_fd(), outbuf))
+ exit_server("oplock_break: send_smb failed.\n");
+
+ /* We need this in case a readraw crosses on the wire. */
+ global_oplock_break = True;
- /* Process incoming messages. */
-
- /* JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT
- seconds we should just die.... */
-
- start_time = time(NULL);
-
- /*
- * Save the information we need to re-become the
- * user, then unbecome the user whilst we're doing this.
- */
- saved_user_conn = current_user.conn;
- saved_vuid = current_user.vuid;
- saved_fsp_conn = fsp->conn;
- vfs_GetWd(saved_fsp_conn,saved_dir);
- unbecome_user();
- /* Save the chain fnum. */
- file_chain_save();
-
- /*
- * From Charles Hoch <hoch@exemplary.com>. If the break processing
- * code closes the file (as it often does), then the fsp pointer here
- * points to free()'d memory. We *must* revalidate fsp each time
- * around the loop.
- */
-
- pstrcpy(file_name, fsp->fsp_name);
-
- while((fsp = initial_break_processing(dev, inode, tval)) &&
- OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
- {
- if(receive_smb(smbd_server_fd(),inbuf, timeout) == False)
- {
- /*
- * Die if we got an error.
- */
-
- if (smb_read_error == READ_EOF) {
- DEBUG( 0, ( "oplock_break: end of file from client\n" ) );
- shutdown_server = True;
- } else if (smb_read_error == READ_ERROR) {
- DEBUG( 0, ("oplock_break: receive_smb error (%s)\n", strerror(errno)) );
- shutdown_server = True;
- } else if (smb_read_error == READ_TIMEOUT) {
- DEBUG( 0, ( "oplock_break: receive_smb timed out after %d seconds.\n",
- OPLOCK_BREAK_TIMEOUT ) );
- oplock_timeout = True;
- }
-
- DEBUGADD( 0, ( "oplock_break failed for file %s ", file_name ) );
- DEBUGADD( 0, ( "(dev = %x, inode = %.0f).\n", (unsigned int)dev, (double)inode));
-
- break;
- }
-
- /*
- * There are certain SMB requests that we shouldn't allow
- * to recurse. opens, renames and deletes are the obvious
- * ones. This is handled in the switch_message() function.
- * If global_oplock_break is set they will push the packet onto
- * the pending smb queue and return -1 (no reply).
- * JRA.
- */
-
- process_smb(inbuf, outbuf);
-
- /*
- * Die if we go over the time limit.
- */
-
- if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
- {
- if( DEBUGLVL( 0 ) )
- {
- dbgtext( "oplock_break: no break received from client " );
- dbgtext( "within %d seconds.\n", OPLOCK_BREAK_TIMEOUT );
- dbgtext( "oplock_break failed for file %s ", fsp->fsp_name );
- dbgtext( "(dev = %x, inode = %.0f).\n", (unsigned int)dev, (double)inode );
- }
- oplock_timeout = True;
- break;
- }
- }
-
- /*
- * Go back to being the user who requested the oplock
- * break.
- */
- if((saved_user_conn != NULL) && (saved_vuid != UID_FIELD_INVALID) && !become_user(saved_user_conn, saved_vuid))
- {
- DEBUG( 0, ( "oplock_break: unable to re-become user!" ) );
- DEBUGADD( 0, ( "Shutting down server\n" ) );
- close(oplock_sock);
- exit_server("unable to re-become user");
- }
- /* Including the directory. */
- vfs_ChDir(saved_fsp_conn,saved_dir);
-
- /* Restore the chain fnum. */
- file_chain_restore();
-
- /* Free the buffers we've been using to recurse. */
- free(inbuf);
- free(outbuf);
-
- /* We need this in case a readraw crossed on the wire. */
- if(global_oplock_break)
- global_oplock_break = False;
-
- /*
- * If the client timed out then clear the oplock (or go to level II)
- * and continue. This seems to be what NT does and is better than dropping
- * the connection.
- */
-
- if(oplock_timeout && (fsp = initial_break_processing(dev, inode, tval)) &&
- OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
- {
- DEBUG(0,("oplock_break: client failure in oplock break in file %s\n", fsp->fsp_name));
- remove_oplock(fsp,True);
- global_client_failed_oplock_break = True; /* Never grant this client an oplock again. */
- }
-
- /*
- * If the client had an error we must die.
- */
-
- if(shutdown_server)
- {
- DEBUG( 0, ( "oplock_break: client failure in break - " ) );
- DEBUGADD( 0, ( "shutting down this smbd.\n" ) );
- close(oplock_sock);
- exit_server("oplock break failure");
- }
-
- /* Santity check - remove this later. JRA */
- if(exclusive_oplocks_open < 0)
- {
- DEBUG(0,("oplock_break: exclusive_oplocks_open < 0 (%d). PANIC ERROR\n",
- exclusive_oplocks_open));
- abort();
- }
-
- if( DEBUGLVL( 3 ) )
- {
- dbgtext( "oplock_break: returning success for " );
- dbgtext( "dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
- dbgtext( "Current exclusive_oplocks_open = %d\n", exclusive_oplocks_open );
- }
-
- return True;
+ /* Process incoming messages. */
+
+ /*
+ * JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT
+ * seconds we should just die....
+ */
+
+ start_time = time(NULL);
+
+ /*
+ * Save the information we need to re-become the
+ * user, then unbecome the user whilst we're doing this.
+ */
+ saved_user_conn = current_user.conn;
+ saved_vuid = current_user.vuid;
+ saved_fsp_conn = fsp->conn;
+ vfs_GetWd(saved_fsp_conn,saved_dir);
+ change_to_root_user();
+ /* Save the chain fnum. */
+ file_chain_save();
+
+ /*
+ * From Charles Hoch <hoch@exemplary.com>. If the break processing
+ * code closes the file (as it often does), then the fsp pointer here
+ * points to free()'d memory. We *must* revalidate fsp each time
+ * around the loop.
+ */
+
+ pstrcpy(file_name, fsp->fsp_name);
+
+ while((fsp = initial_break_processing(dev, inode, file_id)) &&
+ OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ if(receive_smb(smbd_server_fd(),inbuf, timeout) == False) {
+ /*
+ * Die if we got an error.
+ */
+
+ if (smb_read_error == READ_EOF) {
+ DEBUG( 0, ( "oplock_break: end of file from client\n" ) );
+ shutdown_server = True;
+ } else if (smb_read_error == READ_ERROR) {
+ DEBUG( 0, ("oplock_break: receive_smb error (%s)\n", strerror(errno)) );
+ shutdown_server = True;
+ } else if (smb_read_error == READ_TIMEOUT) {
+ DEBUG( 0, ( "oplock_break: receive_smb timed out after %d seconds.\n", OPLOCK_BREAK_TIMEOUT ) );
+ oplock_timeout = True;
+ }
+
+ DEBUGADD( 0, ( "oplock_break failed for file %s ", file_name ) );
+ DEBUGADD( 0, ( "(dev = %x, inode = %.0f, file_id = %lu).\n",
+ (unsigned int)dev, (double)inode, file_id));
+
+ break;
+ }
+
+ /*
+ * There are certain SMB requests that we shouldn't allow
+ * to recurse. opens, renames and deletes are the obvious
+ * ones. This is handled in the switch_message() function.
+ * If global_oplock_break is set they will push the packet onto
+ * the pending smb queue and return -1 (no reply).
+ * JRA.
+ */
+
+ process_smb(inbuf, outbuf);
+
+ /*
+ * Die if we go over the time limit.
+ */
+
+ if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "oplock_break: no break received from client " );
+ dbgtext( "within %d seconds.\n", OPLOCK_BREAK_TIMEOUT );
+ dbgtext( "oplock_break failed for file %s ", fsp->fsp_name );
+ dbgtext( "(dev = %x, inode = %.0f, file_id = %lu).\n",
+ (unsigned int)dev, (double)inode, file_id );
+ }
+ oplock_timeout = True;
+ break;
+ }
+ }
+
+ /*
+ * Go back to being the user who requested the oplock
+ * break.
+ */
+ if((saved_user_conn != NULL) && (saved_vuid != UID_FIELD_INVALID) && !change_to_user(saved_user_conn, saved_vuid)) {
+ DEBUG( 0, ( "oplock_break: unable to re-become user!" ) );
+ DEBUGADD( 0, ( "Shutting down server\n" ) );
+ close(oplock_sock);
+ exit_server("unable to re-become user");
+ }
+
+ /* Including the directory. */
+ vfs_ChDir(saved_fsp_conn,saved_dir);
+
+ /* Restore the chain fnum. */
+ file_chain_restore();
+
+ /* Free the buffers we've been using to recurse. */
+ SAFE_FREE(inbuf);
+ SAFE_FREE(outbuf);
+
+ /* We need this in case a readraw crossed on the wire. */
+ if(global_oplock_break)
+ global_oplock_break = False;
+
+ /*
+ * If the client timed out then clear the oplock (or go to level II)
+ * and continue. This seems to be what NT does and is better than dropping
+ * the connection.
+ */
+
+ if(oplock_timeout && (fsp = initial_break_processing(dev, inode, file_id)) &&
+ OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ DEBUG(0,("oplock_break: client failure in oplock break in file %s\n", fsp->fsp_name));
+ remove_oplock(fsp,True);
+ global_client_failed_oplock_break = True; /* Never grant this client an oplock again. */
+ }
+
+ /*
+ * If the client had an error we must die.
+ */
+
+ if(shutdown_server) {
+ DEBUG( 0, ( "oplock_break: client failure in break - " ) );
+ DEBUGADD( 0, ( "shutting down this smbd.\n" ) );
+ close(oplock_sock);
+ exit_server("oplock break failure");
+ }
+
+ /* Santity check - remove this later. JRA */
+ if(exclusive_oplocks_open < 0) {
+ DEBUG(0,("oplock_break: exclusive_oplocks_open < 0 (%d). PANIC ERROR\n", exclusive_oplocks_open));
+ abort();
+ }
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "oplock_break: returning success for " );
+ dbgtext( "dev = %x, inode = %.0f, file_id = %lu\n", (unsigned int)dev, (double)inode, file_id );
+ dbgtext( "Current exclusive_oplocks_open = %d\n", exclusive_oplocks_open );
+ }
+
+ return True;
}
/****************************************************************************
@@ -896,212 +866,187 @@ Send an oplock break message to another smbd process. If the oplock is held
by the local smbd then call the oplock break function directly.
****************************************************************************/
-BOOL request_oplock_break(share_mode_entry *share_entry,
- SMB_DEV_T dev, SMB_INO_T inode)
+BOOL request_oplock_break(share_mode_entry *share_entry)
{
- char op_break_msg[OPLOCK_BREAK_MSG_LEN];
- struct sockaddr_in addr_out;
- pid_t pid = sys_getpid();
- time_t start_time;
- int time_left;
- long usec;
- time_t sec;
-
- if(pid == share_entry->pid)
- {
- /* We are breaking our own oplock, make sure it's us. */
- if(share_entry->op_port != global_oplock_port)
- {
- DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \
+ char op_break_msg[OPLOCK_BREAK_MSG_LEN];
+ struct sockaddr_in addr_out;
+ pid_t pid = sys_getpid();
+ time_t start_time;
+ int time_left;
+ SMB_DEV_T dev = share_entry->dev;
+ SMB_INO_T inode = share_entry->inode;
+ unsigned long file_id = share_entry->share_file_id;
+
+ if(pid == share_entry->pid) {
+ /* We are breaking our own oplock, make sure it's us. */
+ if(share_entry->op_port != global_oplock_port) {
+ DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \
should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));
- return False;
- }
+ return False;
+ }
- DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
+ DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
#if 1 /* JRA PARANOIA TEST.... */
- {
- files_struct *fsp = file_find_dit(dev, inode, &share_entry->time);
- if (!fsp) {
- DEBUG(0,("request_oplock_break: PANIC : breaking our own oplock requested for \
-dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x and no fsp found !\n",
- (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
- (int)share_entry->time.tv_usec ));
- smb_panic("request_oplock_break: no fsp found for our own oplock\n");
- }
- }
+ {
+ files_struct *fsp = file_find_dif(dev, inode, file_id);
+ if (!fsp) {
+ DEBUG(0,("request_oplock_break: PANIC : breaking our own oplock requested for \
+dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n",
+ (unsigned int)dev, (double)inode, file_id ));
+ smb_panic("request_oplock_break: no fsp found for our own oplock\n");
+ }
+ }
#endif /* END JRA PARANOIA TEST... */
- /* Call oplock break direct. */
- return oplock_break(dev, inode, &share_entry->time, True);
- }
-
- /* We need to send a OPLOCK_BREAK_CMD message to the
- port in the share mode entry. */
-
- if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
- SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,LEVEL_II_OPLOCK_BREAK_CMD);
- } else {
- SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
- }
- memcpy(op_break_msg+OPLOCK_BREAK_PID_OFFSET,(char *)&pid,sizeof(pid));
- sec = (time_t)share_entry->time.tv_sec;
- memcpy(op_break_msg+OPLOCK_BREAK_SEC_OFFSET,(char *)&sec,sizeof(sec));
- usec = (long)share_entry->time.tv_usec;
- memcpy(op_break_msg+OPLOCK_BREAK_USEC_OFFSET,(char *)&usec,sizeof(usec));
- memcpy(op_break_msg+OPLOCK_BREAK_DEV_OFFSET,(char *)&dev,sizeof(dev));
- memcpy(op_break_msg+OPLOCK_BREAK_INODE_OFFSET,(char *)&inode,sizeof(inode));
-
- /* set the address and port */
- memset((char *)&addr_out,'\0',sizeof(addr_out));
- addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- addr_out.sin_port = htons( share_entry->op_port );
- addr_out.sin_family = AF_INET;
+ /* Call oplock break direct. */
+ return oplock_break(dev, inode, file_id, True);
+ }
+
+ /* We need to send a OPLOCK_BREAK_CMD message to the port in the share mode entry. */
+
+ if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,LEVEL_II_OPLOCK_BREAK_CMD);
+ } else {
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
+ }
+
+ memcpy(op_break_msg+OPLOCK_BREAK_PID_OFFSET,(char *)&pid,sizeof(pid));
+ memcpy(op_break_msg+OPLOCK_BREAK_DEV_OFFSET,(char *)&dev,sizeof(dev));
+ memcpy(op_break_msg+OPLOCK_BREAK_INODE_OFFSET,(char *)&inode,sizeof(inode));
+ memcpy(op_break_msg+OPLOCK_BREAK_FILEID_OFFSET,(char *)&file_id,sizeof(file_id));
+
+ /* Set the address and port. */
+ memset((char *)&addr_out,'\0',sizeof(addr_out));
+ addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr_out.sin_port = htons( share_entry->op_port );
+ addr_out.sin_family = AF_INET;
- if( DEBUGLVL( 3 ) )
- {
- dbgtext( "request_oplock_break: sending a oplock break message to " );
- dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port );
- dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
- (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
- (int)share_entry->time.tv_usec );
-
- }
-
- if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
- (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0)
- {
- if( DEBUGLVL( 0 ) )
- {
- dbgtext( "request_oplock_break: failed when sending a oplock " );
- dbgtext( "break message to pid %d ", (int)share_entry->pid );
- dbgtext( "on port %d ", share_entry->op_port );
- dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
- (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
- (int)share_entry->time.tv_usec );
- dbgtext( "Error was %s\n", strerror(errno) );
- }
- return False;
- }
-
- /*
- * If we just sent a message to a level II oplock share entry then
- * we are done and may return.
- */
-
- if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
- DEBUG(3,("request_oplock_break: sent break message to level II entry.\n"));
- return True;
- }
-
- /*
- * Now we must await the oplock broken message coming back
- * from the target smbd process. Timeout if it fails to
- * return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds.
- * While we get messages that aren't ours, loop.
- */
-
- start_time = time(NULL);
- time_left = OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR;
-
- while(time_left >= 0)
- {
- char op_break_reply[OPBRK_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
- uint16 reply_from_port;
- char *reply_msg_start;
- fd_set fds;
-
- FD_ZERO(&fds);
- FD_SET(oplock_sock,&fds);
-
- if (koplocks && koplocks->notification_fd != -1) {
- FD_SET(koplocks->notification_fd, &fds);
- }
-
- if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply),
- time_left ? time_left * 1000 : 1) == False)
- {
- if(smb_read_error == READ_TIMEOUT)
- {
- if( DEBUGLVL( 0 ) )
- {
- dbgtext( "request_oplock_break: no response received to oplock " );
- dbgtext( "break request to pid %d ", (int)share_entry->pid );
- dbgtext( "on port %d ", share_entry->op_port );
- dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
- dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
- (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
- (int)share_entry->time.tv_usec );
- }
-
- /*
- * This is a hack to make handling of failing clients more robust.
- * If a oplock break response message is not received in the timeout
- * period we may assume that the smbd servicing that client holding
- * the oplock has died and the client changes were lost anyway, so
- * we should continue to try and open the file.
- */
- break;
- }
- else
- if( DEBUGLVL( 0 ) )
- {
- dbgtext( "request_oplock_break: error in response received " );
- dbgtext( "to oplock break request to pid %d ", (int)share_entry->pid );
- dbgtext( "on port %d ", share_entry->op_port );
- dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
- (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
- (int)share_entry->time.tv_usec );
- dbgtext( "Error was (%s).\n", strerror(errno) );
- }
- return False;
- }
-
- reply_from_port = SVAL(op_break_reply,OPBRK_CMD_PORT_OFFSET);
-
- reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN];
-
-
- /*
- * Test to see if this is the reply we are awaiting.
- */
- if((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & CMD_REPLY) &&
- ((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & ~CMD_REPLY) == OPLOCK_BREAK_CMD) &&
- (reply_from_port == share_entry->op_port) &&
- (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET],
- &op_break_msg[OPLOCK_BREAK_PID_OFFSET],
- OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) == 0))
- {
- /*
- * This is the reply we've been waiting for.
- */
- break;
- }
- else
- {
- /*
- * This is another message - a break request.
- * Note that both kernel oplock break requests
- * and UDP inter-smbd oplock break requests will
- * be processed here.
- *
- * Process it to prevent potential deadlock.
- * Note that the code in switch_message() prevents
- * us from recursing into here as any SMB requests
- * we might process that would cause another oplock
- * break request to be made will be queued.
- * JRA.
- */
-
- process_local_message(op_break_reply, sizeof(op_break_reply));
- }
-
- time_left -= (time(NULL) - start_time);
- }
-
- DEBUG(3,("request_oplock_break: broke oplock.\n"));
-
- return True;
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "request_oplock_break: sending a oplock break message to " );
+ dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ }
+
+ if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
+ (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "request_oplock_break: failed when sending a oplock " );
+ dbgtext( "break message to pid %d ", (int)share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ dbgtext( "Error was %s\n", strerror(errno) );
+ }
+ return False;
+ }
+
+ /*
+ * If we just sent a message to a level II oplock share entry then
+ * we are done and may return.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ DEBUG(3,("request_oplock_break: sent break message to level II entry.\n"));
+ return True;
+ }
+
+ /*
+ * Now we must await the oplock broken message coming back
+ * from the target smbd process. Timeout if it fails to
+ * return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds.
+ * While we get messages that aren't ours, loop.
+ */
+
+ start_time = time(NULL);
+ time_left = OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR;
+
+ while(time_left >= 0) {
+ char op_break_reply[OPBRK_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
+ uint16 reply_from_port;
+ char *reply_msg_start;
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(oplock_sock,&fds);
+
+ if (koplocks && koplocks->notification_fd != -1) {
+ FD_SET(koplocks->notification_fd, &fds);
+ }
+
+ if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply),
+ time_left ? time_left * 1000 : 1) == False) {
+ if(smb_read_error == READ_TIMEOUT) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "request_oplock_break: no response received to oplock " );
+ dbgtext( "break request to pid %d ", (int)share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ }
+
+ /*
+ * This is a hack to make handling of failing clients more robust.
+ * If a oplock break response message is not received in the timeout
+ * period we may assume that the smbd servicing that client holding
+ * the oplock has died and the client changes were lost anyway, so
+ * we should continue to try and open the file.
+ */
+ break;
+ } else {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "request_oplock_break: error in response received " );
+ dbgtext( "to oplock break request to pid %d ", (int)share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ dbgtext( "Error was (%s).\n", strerror(errno) );
+ }
+ }
+ return False;
+ }
+
+ reply_from_port = SVAL(op_break_reply,OPBRK_CMD_PORT_OFFSET);
+ reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN];
+
+ /*
+ * Test to see if this is the reply we are awaiting.
+ */
+ if((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & CMD_REPLY) &&
+ ((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & ~CMD_REPLY) == OPLOCK_BREAK_CMD) &&
+ (reply_from_port == share_entry->op_port) &&
+ (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET], &op_break_msg[OPLOCK_BREAK_PID_OFFSET],
+ OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) == 0)) {
+
+ /*
+ * This is the reply we've been waiting for.
+ */
+ break;
+ } else {
+ /*
+ * This is another message - a break request.
+ * Note that both kernel oplock break requests
+ * and UDP inter-smbd oplock break requests will
+ * be processed here.
+ *
+ * Process it to prevent potential deadlock.
+ * Note that the code in switch_message() prevents
+ * us from recursing into here as any SMB requests
+ * we might process that would cause another oplock
+ * break request to be made will be queued.
+ * JRA.
+ */
+
+ process_local_message(op_break_reply, sizeof(op_break_reply));
+ }
+
+ time_left -= (time(NULL) - start_time);
+ }
+
+ DEBUG(3,("request_oplock_break: broke oplock.\n"));
+
+ return True;
}
/****************************************************************************
@@ -1111,20 +1056,20 @@ dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x and no fsp found !\n",
Used as a last ditch attempt to free a space in the
file table when we have run out.
****************************************************************************/
+
BOOL attempt_close_oplocked_file(files_struct *fsp)
{
+ DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fsp->fsp_name));
- DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fsp->fsp_name));
-
- if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !fsp->sent_oplock_break && (fsp->fd != -1)) {
- /* Try and break the oplock. */
- if (oplock_break(fsp->dev, fsp->inode, &fsp->open_time, True)) {
- if(file_find_fsp(fsp) == NULL) /* Did the oplock break close the file ? */
- return True;
- }
- }
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !fsp->sent_oplock_break && (fsp->fd != -1)) {
+ /* Try and break the oplock. */
+ if (oplock_break(fsp->dev, fsp->inode, fsp->file_id, True)) {
+ if(file_find_fsp(fsp) == NULL) /* Did the oplock break close the file ? */
+ return True;
+ }
+ }
- return False;
+ return False;
}
/****************************************************************************
@@ -1192,7 +1137,7 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
*/
if (pid == share_entry->pid) {
- files_struct *new_fsp = file_find_dit(fsp->dev, fsp->inode, &share_entry->time);
+ files_struct *new_fsp = file_find_dif(share_entry->dev, share_entry->inode, share_entry->share_file_id);
/* Paranoia check... */
if(new_fsp == NULL) {
@@ -1213,12 +1158,11 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
*/
DEBUG(10,("release_level_2_oplocks_on_change: breaking remote oplock.\n"));
- request_oplock_break(share_entry, fsp->dev, fsp->inode);
+ request_oplock_break(share_entry);
}
}
- if (share_list)
- free((char *)share_list);
+ SAFE_FREE(share_list);
unlock_share_entry_fsp(fsp);
/* Paranoia check... */
@@ -1231,6 +1175,7 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
/****************************************************************************
setup oplocks for this process
****************************************************************************/
+
BOOL init_oplocks(void)
{
struct sockaddr_in sock_name;
diff --git a/source/smbd/oplock_irix.c b/source/smbd/oplock_irix.c
index faf7e8e3c87..10520461753 100644
--- a/source/smbd/oplock_irix.c
+++ b/source/smbd/oplock_irix.c
@@ -22,14 +22,14 @@
#include "includes.h"
#if HAVE_KERNEL_OPLOCKS_IRIX
-extern int DEBUGLEVEL;
static int oplock_pipe_write = -1;
static int oplock_pipe_read = -1;
/****************************************************************************
-test to see if IRIX kernel oplocks work
+ Test to see if IRIX kernel oplocks work.
****************************************************************************/
+
static BOOL irix_oplocks_available(void)
{
int fd;
@@ -82,106 +82,113 @@ Disabling kernel oplock support.\n", strerror(errno) ));
return True;
}
-
-
/****************************************************************************
* Deal with the IRIX kernel <--> smbd
* oplock break protocol.
****************************************************************************/
+
static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
{
extern int smb_read_error;
- oplock_stat_t os;
- SMB_DEV_T dev;
- SMB_INO_T inode;
- char dummy;
-
- /*
- * Read one byte of zero to clear the
- * kernel break notify message.
- */
-
- if(read(oplock_pipe_read, &dummy, 1) != 1) {
- DEBUG(0,("receive_local_message: read of kernel notification failed. \
+ oplock_stat_t os;
+ char dummy;
+ files_struct *fsp;
+
+ /*
+ * Read one byte of zero to clear the
+ * kernel break notify message.
+ */
+
+ if(read(oplock_pipe_read, &dummy, 1) != 1) {
+ DEBUG(0,("receive_local_message: read of kernel notification failed. \
Error was %s.\n", strerror(errno) ));
- smb_read_error = READ_ERROR;
- return False;
- }
-
- /*
- * Do a query to get the
- * device and inode of the file that has the break
- * request outstanding.
- */
-
- if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
- DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /*
+ * Do a query to get the
+ * device and inode of the file that has the break
+ * request outstanding.
+ */
+
+ if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
+ DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \
Error was %s.\n", strerror(errno) ));
- if(errno == EAGAIN) {
- /*
- * Duplicate kernel break message - ignore.
- */
- memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN);
- return True;
- }
- smb_read_error = READ_ERROR;
- return False;
- }
-
- dev = (SMB_DEV_T)os.os_dev;
- inode = (SMB_INO_T)os.os_ino;
-
- DEBUG(5,("receive_local_message: kernel oplock break request received for \
-dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
-
- /*
- * Create a kernel oplock break message.
- */
-
- /* Setup the message header */
- SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN);
- SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0);
-
- buffer += OPBRK_CMD_HEADER_LEN;
+ if(errno == EAGAIN) {
+ /*
+ * Duplicate kernel break message - ignore.
+ */
+ memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN);
+ return True;
+ }
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /*
+ * We only have device and inode info here - we have to guess that this
+ * is the first fsp open with this dev,ino pair.
+ */
+
+ if ((fsp = file_find_di_first((SMB_DEV_T)os.os_dev, (SMB_INO_T)os.os_ino)) == NULL) {
+ DEBUG(0,("receive_local_message: unable to find open file with dev = %x, inode = %.0f\n",
+ (unsigned int)os.os_dev, (double)os.os_ino ));
+ return False;
+ }
- SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD);
+ DEBUG(5,("receive_local_message: kernel oplock break request received for \
+dev = %x, inode = %.0f\n, file_id = %ul", (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id ));
- memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&dev, sizeof(dev));
- memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&inode, sizeof(inode));
+ /*
+ * Create a kernel oplock break message.
+ */
+
+ /* Setup the message header */
+ SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN);
+ SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0);
+
+ buffer += OPBRK_CMD_HEADER_LEN;
- return True;
+ SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD);
+
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&fsp->dev, sizeof(fsp->dev));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id));
+
+ return True;
}
-
/****************************************************************************
Attempt to set an kernel oplock on a file.
****************************************************************************/
+
static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
{
if (fcntl(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) {
if(errno != EAGAIN) {
DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \
-inode = %.0f. Error was %s\n",
- fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode,
+inode = %.0f, file_id = %ul. Error was %s\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id,
strerror(errno) ));
} else {
DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
-inode = %.0f. Another process had the file open.\n",
- fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode ));
+inode = %.0f, file_id = %ul. Another process had the file open.\n",
+ fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id ));
}
return False;
}
- DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n",
- fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode));
+ DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %ul\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id));
return True;
}
-
/****************************************************************************
Release a kernel oplock on a file.
****************************************************************************/
+
static void irix_release_kernel_oplock(files_struct *fsp)
{
if (DEBUGLVL(10)) {
@@ -190,9 +197,9 @@ static void irix_release_kernel_oplock(files_struct *fsp)
* oplock state of this file.
*/
int state = fcntl(fsp->fd, F_OPLKACK, -1);
- dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f has kernel \
+ dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %ul, has kernel \
oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
- (double)fsp->inode, state );
+ (double)fsp->inode, fsp->file_id, state );
}
/*
@@ -201,18 +208,19 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
if(fcntl(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) {
if( DEBUGLVL( 0 )) {
dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
- dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n",
+ dbgtext("%s, dev = %x, inode = %.0f, file_id = %ul. Error was %s\n",
fsp->fsp_name, (unsigned int)fsp->dev,
- (double)fsp->inode, strerror(errno) );
+ (double)fsp->inode, fsp->file_id, strerror(errno) );
}
}
}
-
/****************************************************************************
-parse a kernel oplock message
+ Parse a kernel oplock message.
****************************************************************************/
-static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev)
+
+static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len,
+ SMB_INO_T *inode, SMB_DEV_T *dev, unsigned long *file_id)
{
/* Ensure that the msg length is correct. */
if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) {
@@ -221,36 +229,39 @@ static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *in
return False;
}
- memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
- memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
+ memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
+ memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
+ memcpy((char *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id));
- DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f\n",
- (unsigned int)*dev, (double)*inode));
+ DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f, file_id = %ul\n",
+ (unsigned int)*dev, (double)*inode, *file_id));
return True;
}
-
/****************************************************************************
-set *maxfd to include oplock read pipe
+ Set *maxfd to include oplock read pipe.
****************************************************************************/
+
static BOOL irix_oplock_msg_waiting(fd_set *fds)
{
- if (oplock_pipe_read == -1) return False;
+ if (oplock_pipe_read == -1)
+ return False;
return FD_ISSET(oplock_pipe_read,fds);
}
-
/****************************************************************************
-setup kernel oplocks
+ Setup kernel oplocks.
****************************************************************************/
+
struct kernel_oplocks *irix_init_kernel_oplocks(void)
{
int pfd[2];
static struct kernel_oplocks koplocks;
- if (!irix_oplocks_available()) return NULL;
+ if (!irix_oplocks_available())
+ return NULL;
if(pipe(pfd) != 0) {
DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n",
@@ -270,9 +281,6 @@ struct kernel_oplocks *irix_init_kernel_oplocks(void)
return &koplocks;
}
-
-
-
#else
void oplock_irix_dummy(void) {}
#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
diff --git a/source/smbd/oplock_linux.c b/source/smbd/oplock_linux.c
index 39ee3eb86b3..3f22956aa02 100644
--- a/source/smbd/oplock_linux.c
+++ b/source/smbd/oplock_linux.c
@@ -23,8 +23,6 @@
#if HAVE_KERNEL_OPLOCKS_LINUX
-extern int DEBUGLEVEL;
-
static VOLATILE sig_atomic_t signals_received;
static VOLATILE sig_atomic_t signals_processed;
static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal */
@@ -50,8 +48,9 @@ static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal
#endif
/****************************************************************************
-handle a LEASE signal, incrementing the signals_received and blocking the signal
+ Handle a LEASE signal, incrementing the signals_received and blocking the signal.
****************************************************************************/
+
static void signal_handler(int sig, siginfo_t *info, void *unused)
{
BlockSignals(True, sig);
@@ -61,8 +60,10 @@ static void signal_handler(int sig, siginfo_t *info, void *unused)
}
/****************************************************************************
-try to gain a linux capability
-****************************************************************************/static void set_capability(unsigned capability)
+ Try to gain a linux capability.
+****************************************************************************/
+
+static void set_capability(unsigned capability)
{
#ifndef _LINUX_CAPABILITY_VERSION
#define _LINUX_CAPABILITY_VERSION 0x19980330
@@ -94,11 +95,11 @@ try to gain a linux capability
}
}
-
/****************************************************************************
-call SETLEASE. If we get EACCES then we try setting up the right capability and
-try again
+ Call SETLEASE. If we get EACCES then we try setting up the right capability and
+ try again
****************************************************************************/
+
static int linux_setlease(int fd, int leasetype)
{
int ret;
@@ -117,31 +118,27 @@ static int linux_setlease(int fd, int leasetype)
return ret;
}
-
/****************************************************************************
* Deal with the Linux kernel <--> smbd
* oplock break protocol.
****************************************************************************/
+
static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
{
- SMB_DEV_T dev;
- SMB_INO_T inode;
- SMB_STRUCT_STAT sbuf;
BOOL ret = True;
+ struct files_struct *fsp;
- if (signals_received == signals_processed) return False;
+ if (signals_received == signals_processed)
+ return False;
- if (sys_fstat((int)fd_pending,&sbuf) == -1) {
+ if ((fsp = file_find_fd(fd_pending)) == NULL) {
DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd_pending));
ret = False;
goto out;
}
- dev = sbuf.st_dev;
- inode = sbuf.st_ino;
-
DEBUG(3,("receive_local_message: kernel oplock break request received for \
-dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
+dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
/*
* Create a kernel oplock break message.
@@ -155,8 +152,9 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD);
- memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&dev, sizeof(dev));
- memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&inode, sizeof(inode));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&fsp->dev, sizeof(fsp->dev));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id));
out:
/* now we can receive more signals */
@@ -167,10 +165,10 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
return ret;
}
-
/****************************************************************************
Attempt to set an kernel oplock on a file.
****************************************************************************/
+
static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
{
if (linux_setlease(fsp->fd, F_WRLCK) == -1) {
@@ -181,16 +179,16 @@ inode = %.0f. (%s)\n",
return False;
}
- DEBUG(3,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n",
- fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode));
+ DEBUG(3,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %lu\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id));
return True;
}
-
/****************************************************************************
Release a kernel oplock on a file.
****************************************************************************/
+
static void linux_release_kernel_oplock(files_struct *fsp)
{
if (DEBUGLVL(10)) {
@@ -199,9 +197,9 @@ static void linux_release_kernel_oplock(files_struct *fsp)
* oplock state of this file.
*/
int state = fcntl(fsp->fd, F_GETLEASE, 0);
- dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f has kernel \
+ dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \
oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
- (double)fsp->inode, state );
+ (double)fsp->inode, fsp->file_id, state );
}
/*
@@ -210,18 +208,19 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
if (linux_setlease(fsp->fd, F_UNLCK) == -1) {
if (DEBUGLVL(0)) {
dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
- dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n",
+ dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. Error was %s\n",
fsp->fsp_name, (unsigned int)fsp->dev,
- (double)fsp->inode, strerror(errno) );
+ (double)fsp->inode, fsp->file_id, strerror(errno) );
}
}
}
-
/****************************************************************************
-parse a kernel oplock message
+ Parse a kernel oplock message.
****************************************************************************/
-static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev)
+
+static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode,
+ SMB_DEV_T *dev, unsigned long *file_id)
{
/* Ensure that the msg length is correct. */
if (msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) {
@@ -230,41 +229,44 @@ static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *i
return False;
}
- memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
- memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
+ memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
+ memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
+ memcpy((char *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id));
- DEBUG(3,("kernel oplock break request for file dev = %x, inode = %.0f\n",
- (unsigned int)*dev, (double)*inode));
+ DEBUG(3,("kernel oplock break request for file dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)*dev, (double)*inode, *file_id));
return True;
}
-
/****************************************************************************
-see if a oplock message is waiting
+ See if a oplock message is waiting.
****************************************************************************/
+
static BOOL linux_oplock_msg_waiting(fd_set *fds)
{
return signals_processed != signals_received;
}
/****************************************************************************
-see if the kernel supports oplocks
+ See if the kernel supports oplocks.
****************************************************************************/
+
static BOOL linux_oplocks_available(void)
{
int fd, ret;
fd = open("/dev/null", O_RDONLY);
- if (fd == -1) return False; /* uggh! */
+ if (fd == -1)
+ return False; /* uggh! */
ret = fcntl(fd, F_GETLEASE, 0);
close(fd);
return ret == F_UNLCK;
}
-
/****************************************************************************
-setup kernel oplocks
+ Setup kernel oplocks.
****************************************************************************/
+
struct kernel_oplocks *linux_init_kernel_oplocks(void)
{
static struct kernel_oplocks koplocks;
@@ -275,13 +277,13 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void)
return NULL;
}
- act.sa_handler = NULL;
- act.sa_sigaction = signal_handler;
- act.sa_flags = SA_SIGINFO;
- if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) {
+ act.sa_handler = NULL;
+ act.sa_sigaction = signal_handler;
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) {
DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler\n"));
return NULL;
- }
+ }
koplocks.receive_message = linux_oplock_receive_message;
koplocks.set_oplock = linux_set_kernel_oplock;
@@ -294,9 +296,6 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void)
return &koplocks;
}
-
-
-
#else
void oplock_linux_dummy(void) {}
#endif /* HAVE_KERNEL_OPLOCKS_LINUX */
diff --git a/source/smbd/password.c b/source/smbd/password.c
index c6be5f68eda..4ccade52cec 100644
--- a/source/smbd/password.c
+++ b/source/smbd/password.c
@@ -21,7 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
extern int Protocol;
extern struct in_addr ipzero;
@@ -44,6 +43,7 @@ static BOOL challenge_sent=False;
/*******************************************************************
Get the next challenge value - no repeats.
********************************************************************/
+
void generate_next_challenge(char *challenge)
{
unsigned char buf[8];
@@ -56,23 +56,26 @@ void generate_next_challenge(char *challenge)
}
/*******************************************************************
-set the last challenge sent, usually from a password server
+ Set the last challenge sent, usually from a password server.
********************************************************************/
+
BOOL set_challenge(unsigned char *challenge)
{
- memcpy(saved_challenge,challenge,8);
- challenge_sent = True;
- return(True);
+ memcpy(saved_challenge,challenge,8);
+ challenge_sent = True;
+ return(True);
}
/*******************************************************************
-get the last challenge sent
+ Get the last challenge sent.
********************************************************************/
+
static BOOL last_challenge(unsigned char *challenge)
{
- if (!challenge_sent) return(False);
- memcpy(challenge,saved_challenge,8);
- return(True);
+ if (!challenge_sent)
+ return(False);
+ memcpy(challenge,saved_challenge,8);
+ return(True);
}
/* this holds info on user ids that are already validated for this VC */
@@ -81,10 +84,11 @@ static int next_vuid = VUID_OFFSET;
static int num_validated_vuids;
/****************************************************************************
-check if a uid has been validated, and return an pointer to the user_struct
-if it has. NULL if not. vuid is biased by an offset. This allows us to
-tell random client vuid's (normally zero) from valid vuids.
+ Check if a uid has been validated, and return an pointer to the user_struct
+ if it has. NULL if not. vuid is biased by an offset. This allows us to
+ tell random client vuid's (normally zero) from valid vuids.
****************************************************************************/
+
user_struct *get_valid_user_struct(uint16 vuid)
{
user_struct *usp;
@@ -106,8 +110,9 @@ user_struct *get_valid_user_struct(uint16 vuid)
}
/****************************************************************************
-invalidate a uid
+ Invalidate a uid.
****************************************************************************/
+
void invalidate_vuid(uint16 vuid)
{
user_struct *vuser = get_valid_user_struct(vuid);
@@ -119,15 +124,16 @@ void invalidate_vuid(uint16 vuid)
DLIST_REMOVE(validated_users, vuser);
- safe_free(vuser->groups);
+ SAFE_FREE(vuser->groups);
delete_nt_token(&vuser->nt_user_token);
safe_free(vuser);
num_validated_vuids--;
}
/****************************************************************************
-invalidate all vuid entries for this process
+ Invalidate all vuid entries for this process.
****************************************************************************/
+
void invalidate_all_vuids(void)
{
user_struct *usp, *next=NULL;
@@ -140,8 +146,9 @@ void invalidate_all_vuids(void)
}
/****************************************************************************
-return a validated username
+ Return a validated username.
****************************************************************************/
+
char *validated_username(uint16 vuid)
{
user_struct *vuser = get_valid_user_struct(vuid);
@@ -151,8 +158,9 @@ char *validated_username(uint16 vuid)
}
/****************************************************************************
-return a validated domain
+ Return a validated domain.
****************************************************************************/
+
char *validated_domain(uint16 vuid)
{
user_struct *vuser = get_valid_user_struct(vuid);
@@ -161,12 +169,11 @@ char *validated_domain(uint16 vuid)
return(vuser->user.domain);
}
-
/****************************************************************************
Create the SID list for this user.
****************************************************************************/
-NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, BOOL is_guest)
+NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, BOOL is_guest, NT_USER_TOKEN *sup_tok)
{
extern DOM_SID global_sid_World;
extern DOM_SID global_sid_Network;
@@ -186,8 +193,11 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups,
/* We always have uid/gid plus World and Network and Authenticated Users or Guest SIDs. */
num_sids = 5 + ngroups;
+ if (sup_tok && sup_tok->num_sids)
+ num_sids += sup_tok->num_sids;
+
if ((token->user_sids = (DOM_SID *)malloc( num_sids*sizeof(DOM_SID))) == NULL) {
- free(token);
+ SAFE_FREE(token);
return NULL;
}
@@ -198,13 +208,15 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups,
* se_access_check depends on this.
*/
- uid_to_sid( &psids[psid_ndx++], uid);
+ uid_to_sid( &psids[PRIMARY_USER_SID_INDEX], uid);
+ psid_ndx++;
/*
* Primary group SID is second in token. Convention.
*/
- gid_to_sid( &psids[psid_ndx++], gid);
+ gid_to_sid( &psids[PRIMARY_GROUP_SID_INDEX], gid);
+ psid_ndx++;
/* Now add the group SIDs. */
@@ -214,6 +226,12 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups,
}
}
+ /* Now add the additional SIDs from the supplimentary token. */
+ if (sup_tok) {
+ for (i = 0; i < sup_tok->num_sids; i++)
+ sid_copy( &psids[psid_ndx++], &sup_tok->user_sids[i] );
+ }
+
/*
* Finally add the "standard" SIDs.
* The only difference between guest and "anonymous" (which we
@@ -241,13 +259,13 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups,
}
/****************************************************************************
-register a uid/name pair as being valid and that a valid password
-has been given. vuid is biased by an offset. This allows us to
-tell random client vuid's (normally zero) from valid vuids.
+ Register a uid/name pair as being valid and that a valid password
+ has been given. vuid is biased by an offset. This allows us to
+ tell random client vuid's (normally zero) from valid vuids.
****************************************************************************/
int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name,
- char *domain,BOOL guest)
+ char *domain,BOOL guest, NT_USER_TOKEN **pptok)
{
user_struct *vuser = NULL;
struct passwd *pwfile; /* for getting real name from passwd file */
@@ -292,12 +310,15 @@ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name,
vuser->groups = NULL;
/* Find all the groups this uid is in and store them.
- Used by become_user() */
+ Used by change_to_user() */
initialise_groups(unix_name, uid, gid);
get_current_groups( &vuser->n_groups, &vuser->groups);
+ if (*pptok)
+ add_supplementary_nt_login_groups(&vuser->n_groups, &vuser->groups, pptok);
+
/* Create an NT_USER_TOKEN struct for this user. */
- vuser->nt_user_token = create_nt_token(uid,gid, vuser->n_groups, vuser->groups, guest);
+ vuser->nt_user_token = create_nt_token(uid,gid, vuser->n_groups, vuser->groups, guest, *pptok);
next_vuid++;
num_validated_vuids++;
@@ -321,33 +342,32 @@ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name,
return vuser->vuid;
}
-
/****************************************************************************
-add a name to the session users list
+ Add a name to the session users list.
****************************************************************************/
+
void add_session_user(char *user)
{
- fstring suser;
- StrnCpy(suser,user,sizeof(suser)-1);
+ fstring suser;
+ StrnCpy(suser,user,sizeof(suser)-1);
- if (!Get_Pwnam(suser,True)) return;
+ if (!Get_Pwnam(suser,True))
+ return;
- if (suser && *suser && !in_list(suser,session_users,False))
- {
- if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
- DEBUG(1,("Too many session users??\n"));
- else
- {
- pstrcat(session_users," ");
- pstrcat(session_users,suser);
+ if (suser && *suser && !in_list(suser,session_users,False)) {
+ if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
+ DEBUG(1,("Too many session users??\n"));
+ else {
+ pstrcat(session_users," ");
+ pstrcat(session_users,suser);
+ }
}
- }
}
-
/****************************************************************************
-update the encrypted smbpasswd file from the plaintext username and password
+ Update the encrypted smbpasswd file from the plaintext username and password.
*****************************************************************************/
+
static BOOL update_smbpassword_file(char *user, char *password)
{
SAM_ACCOUNT *sampass = NULL;
@@ -383,56 +403,55 @@ static BOOL update_smbpassword_file(char *user, char *password)
return ret;
}
-
-
-
-
/****************************************************************************
-core of smb password checking routine.
+ Core of smb password checking routine.
****************************************************************************/
+
BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
{
- /* Finish the encryption of part_passwd. */
- unsigned char p21[21];
- unsigned char p24[24];
-
- if (part_passwd == NULL)
- DEBUG(10,("No password set - allowing access\n"));
- /* No password set - always true ! */
- if (part_passwd == NULL)
- return 1;
-
- memset(p21,'\0',21);
- memcpy(p21,part_passwd,16);
- E_P24(p21, c8, p24);
+ /* Finish the encryption of part_passwd. */
+ unsigned char p21[21];
+ unsigned char p24[24];
+
+ if (part_passwd == NULL)
+ DEBUG(10,("No password set - allowing access\n"));
+
+ /* No password set - always true ! */
+ if (part_passwd == NULL)
+ return True;
+
+ memset(p21,'\0',21);
+ memcpy(p21,part_passwd,16);
+ E_P24(p21, c8, p24);
#if DEBUG_PASSWORD
- {
- int i;
- DEBUG(100,("Part password (P16) was |"));
- for(i = 0; i < 16; i++)
- DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
- DEBUG(100,("|\n"));
- DEBUG(100,("Password from client was |"));
- for(i = 0; i < 24; i++)
- DEBUG(100,("%X ", (unsigned char)password[i]));
- DEBUG(100,("|\n"));
- DEBUG(100,("Given challenge was |"));
- for(i = 0; i < 8; i++)
- DEBUG(100,("%X ", (unsigned char)c8[i]));
- DEBUG(100,("|\n"));
- DEBUG(100,("Value from encryption was |"));
- for(i = 0; i < 24; i++)
- DEBUG(100,("%X ", (unsigned char)p24[i]));
- DEBUG(100,("|\n"));
- }
+ {
+ int i;
+ DEBUG(100,("Part password (P16) was |"));
+ for(i = 0; i < 16; i++)
+ DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
+ DEBUG(100,("|\n"));
+ DEBUG(100,("Password from client was |"));
+ for(i = 0; i < 24; i++)
+ DEBUG(100,("%X ", (unsigned char)password[i]));
+ DEBUG(100,("|\n"));
+ DEBUG(100,("Given challenge was |"));
+ for(i = 0; i < 8; i++)
+ DEBUG(100,("%X ", (unsigned char)c8[i]));
+ DEBUG(100,("|\n"));
+ DEBUG(100,("Value from encryption was |"));
+ for(i = 0; i < 24; i++)
+ DEBUG(100,("%X ", (unsigned char)p24[i]));
+ DEBUG(100,("|\n"));
+ }
#endif
- return (memcmp(p24, password, 24) == 0);
+ return (memcmp(p24, password, 24) == 0);
}
/****************************************************************************
Do a specific test for an smb password being correct, given a smb_password and
the lanman and NT responses.
****************************************************************************/
+
BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8],
uchar lm_pass[24], uchar nt_pass[24])
{
@@ -482,8 +501,7 @@ BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8],
lm_pw = pdb_get_lanman_passwd(sampass);
- if((lm_pw == NULL) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ))
- {
+ if((lm_pw == NULL) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) {
DEBUG(4,("smb_password_ok: no password required for user %s\n",user_name));
return True;
}
@@ -500,11 +518,9 @@ BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8],
return False;
}
-
/****************************************************************************
-check if a username/password is OK assuming the password is a 24 byte
-SMB hash
-return True if the password is correct, False otherwise
+ Check if a username/password is OK assuming the password is a 24 byte
+ SMB hash. Return True if the password is correct, False otherwise.
****************************************************************************/
BOOL pass_check_smb(char *user, char *domain, uchar *chal,
@@ -513,27 +529,21 @@ BOOL pass_check_smb(char *user, char *domain, uchar *chal,
SAM_ACCOUNT *sampass = NULL;
if (!lm_pwd || !nt_pwd)
- {
return(False);
- }
#if 0 /* JERRY */
/* FIXME! this code looks to be unnecessary now that the passdb
validates that the username exists and has a valid uid */
- if (pwd != NULL && user == NULL)
- {
+ if (pwd != NULL && user == NULL) {
pass = (struct passwd *) pwd;
user = pass->pw_name;
- }
- else
- {
+ } else {
/* I don't get this call here. I think it should be moved.
Need to check on it. --jerry */
pass = smb_getpwnam(user,True);
}
- if (pass == NULL)
- {
+ if (pass == NULL) {
DEBUG(1,("Couldn't find user '%s' in UNIX password database.\n",user));
return(False);
}
@@ -541,8 +551,7 @@ BOOL pass_check_smb(char *user, char *domain, uchar *chal,
/* get the account information */
pdb_init_sam(&sampass);
- if (!pdb_getsampwnam(sampass, user))
- {
+ if (!pdb_getsampwnam(sampass, user)) {
DEBUG(1,("Couldn't find user '%s' in passdb.\n", user));
return(False);
}
@@ -550,39 +559,40 @@ BOOL pass_check_smb(char *user, char *domain, uchar *chal,
/* Quit if the account was disabled. */
if(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
DEBUG(1,("Account for user '%s' was disabled.\n", user));
+ pdb_free_sam(sampass);
return(False);
}
- if (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)
- {
- if (lp_null_passwords())
- {
+ if (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) {
+ if (lp_null_passwords()) {
DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", user));
+ pdb_free_sam(sampass);
return(True);
- }
- else
- {
+ } else {
DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", user));
+ pdb_free_sam(sampass);
return(False);
}
}
- if (smb_password_ok(sampass, chal, lm_pwd, nt_pwd))
- {
+ if (smb_password_ok(sampass, chal, lm_pwd, nt_pwd)) {
+ pdb_free_sam(sampass);
return(True);
}
-
+
DEBUG(2,("pass_check_smb failed - invalid password for user [%s]\n", user));
+ pdb_free_sam(sampass);
return False;
}
/****************************************************************************
-check if a username/password pair is OK either via the system password
-database or the encrypted SMB password database
-return True if the password is correct, False otherwise
+ Check if a username/password pair is OK either via the system password
+ database or the encrypted SMB password database
+ return True if the password is correct, False otherwise.
****************************************************************************/
+
BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd)
{
@@ -612,7 +622,7 @@ BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd)
*/
if (ret)
- return (smb_pam_accountcheck(user) == NT_STATUS_OK);
+ return (NT_STATUS_V(smb_pam_accountcheck(user)) == NT_STATUS_V(NT_STATUS_OK));
return ret;
}
@@ -623,8 +633,9 @@ BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd)
}
/****************************************************************************
-check if a username is valid
+ Check if a username is valid
****************************************************************************/
+
BOOL user_ok(char *user,int snum)
{
pstring valid, invalid;
@@ -638,9 +649,8 @@ BOOL user_ok(char *user,int snum)
ret = !user_in_list(user,invalid);
- if (ret && valid && *valid) {
+ if (ret && valid && *valid)
ret = user_in_list(user,valid);
- }
if (ret && lp_onlyuser(snum)) {
char *user_list = lp_username(snum);
@@ -651,13 +661,11 @@ BOOL user_ok(char *user,int snum)
return(ret);
}
-
-
-
/****************************************************************************
-validate a group username entry. Return the username or NULL
+ Validate a group username entry. Return the username or NULL.
****************************************************************************/
-static char *validate_group(char *group,char *password,int pwlen,int snum)
+
+static char *validate_group(const char *group,char *password,int pwlen,int snum)
{
#ifdef HAVE_NETGROUP
{
@@ -676,66 +684,24 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
}
#endif
-#ifdef HAVE_GETGRENT
{
- struct group *gptr;
- setgrent();
- while ((gptr = (struct group *)getgrent())) {
- if (strequal(gptr->gr_name,group))
- break;
- }
-
- /*
- * As user_ok can recurse doing a getgrent(), we must
- * copy the member list into a pstring on the stack before
- * use. Bug pointed out by leon@eatworms.swmed.edu.
- */
-
- if (gptr) {
- pstring member_list;
- char *member;
- size_t copied_len = 0;
- int i;
-
- *member_list = '\0';
- member = member_list;
-
- for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) {
- size_t member_len = strlen(gptr->gr_mem[i]) + 1;
- if( copied_len + member_len < sizeof(pstring)) {
-
- DEBUG(10,("validate_group: = gr_mem = %s\n", gptr->gr_mem[i]));
-
- safe_strcpy(member, gptr->gr_mem[i], sizeof(pstring) - copied_len - 1);
- copied_len += member_len;
- member += copied_len;
- } else {
- *member = '\0';
- }
+ struct sys_userlist *user_list = get_users_in_group(group);
+ struct sys_userlist *member;
+
+ for (member = user_list; member; member = member->next) {
+ static fstring name;
+ fstrcpy(name,member->unix_name);
+ if (user_ok(name,snum) &&
+ password_ok(name,password,pwlen,NULL)) {
+ free_userlist(user_list);
+ return(&name[0]);
}
- endgrent();
-
- member = member_list;
- while (*member) {
- static fstring name;
- fstrcpy(name,member);
- if (user_ok(name,snum) &&
- password_ok(name,password,pwlen,NULL)) {
- endgrent();
- return(&name[0]);
- }
-
- DEBUG(10,("validate_group = member = %s\n", member));
-
- member += strlen(member) + 1;
- }
- } else {
- endgrent();
- return NULL;
+ DEBUG(10,("validate_group = member = %s\n", member->unix_name));
}
+ free_userlist(user_list);
}
-#endif
+
return(NULL);
}
@@ -835,7 +801,7 @@ and given password ok\n", user));
}
}
- free(user_list);
+ SAFE_FREE(user_list);
}
/* check for a previously validated username/password pair */
@@ -864,7 +830,7 @@ and given password ok\n", user));
pstring_sub(user_list,"%S",lp_servicename(snum));
for (auser=strtok(user_list,LIST_SEP); auser && !ok;
- auser = strtok(NULL,LIST_SEP)) {
+ auser = strtok(NULL,LIST_SEP)) {
if (*auser == '@') {
auser = validate_group(auser+1,password,pwlen,snum);
if (auser) {
@@ -1016,41 +982,39 @@ static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
return False;
}
-
/****************************************************************************
-check for a possible hosts equiv or rhosts entry for the user
+ Check for a possible hosts equiv or rhosts entry for the user.
****************************************************************************/
+
BOOL check_hosts_equiv(char *user)
{
- char *fname = NULL;
- pstring rhostsfile;
- struct passwd *pass = Get_Pwnam(user,True);
+ char *fname = NULL;
+ pstring rhostsfile;
+ struct passwd *pass = Get_Pwnam(user,True);
- if (!pass)
- return(False);
+ if (!pass)
+ return(False);
- fname = lp_hosts_equiv();
+ fname = lp_hosts_equiv();
- /* note: don't allow hosts.equiv on root */
- if (fname && *fname && (pass->pw_uid != 0)) {
- if (check_user_equiv(user,client_name(),fname))
- return(True);
- }
+ /* note: don't allow hosts.equiv on root */
+ if (fname && *fname && (pass->pw_uid != 0)) {
+ if (check_user_equiv(user,client_name(),fname))
+ return(True);
+ }
- if (lp_use_rhosts())
- {
- char *home = get_user_home_dir(user);
- if (home) {
- slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
- if (check_user_equiv(user,client_name(),rhostsfile))
- return(True);
- }
- }
+ if (lp_use_rhosts()) {
+ char *home = get_user_service_home_dir(user);
+ if (home) {
+ slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
+ if (check_user_equiv(user,client_name(),rhostsfile))
+ return(True);
+ }
+ }
- return(False);
+ return(False);
}
-
/****************************************************************************
Return the client state structure.
****************************************************************************/
@@ -1102,7 +1066,7 @@ struct cli_state *server_cryptkey(void)
}
}
- free(pserver);
+ SAFE_FREE(pserver);
if (!connected_ok) {
DEBUG(0,("password server not available\n"));
@@ -1266,7 +1230,7 @@ static BOOL connect_to_domain_password_server(struct cli_state *pcli,
return False;
}
- if (!name_status_find(0x20, to_ip, remote_machine)) {
+ if (!name_status_find("*", 0, 0x20, to_ip, remote_machine)) {
DEBUG(1, ("connect_to_domain_password_server: Can't "
"resolve name for IP %s\n", server));
return False;
@@ -1367,7 +1331,7 @@ machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
return False;
}
- if (cli_nt_setup_creds(pcli, trust_passwd) == False) {
+ if (!NT_STATUS_IS_OK(cli_nt_setup_creds(pcli, trust_passwd))) {
DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \
%s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
cli_nt_session_close(pcli);
@@ -1394,18 +1358,17 @@ static BOOL attempt_connect_to_dc(struct cli_state *pcli, struct in_addr *ip, un
if (ip_equal(ipzero, *ip))
return False;
- if (!lookup_pdc_name(global_myname, lp_workgroup(), ip, dc_name))
+ if (!lookup_dc_name(global_myname, lp_workgroup(), ip, dc_name))
return False;
return connect_to_domain_password_server(pcli, dc_name, trust_passwd);
}
-
-
/***********************************************************************
We have been asked to dynamcially determine the IP addresses of
the PDC and BDC's for this DOMAIN, and query them in turn.
************************************************************************/
+
static BOOL find_connect_pdc(struct cli_state *pcli, unsigned char *trust_passwd, time_t last_change_time)
{
struct in_addr *ip_list = NULL;
@@ -1468,15 +1431,11 @@ static BOOL find_connect_pdc(struct cli_state *pcli, unsigned char *trust_passwd
}
}
- if(ip_list != NULL)
- free((char *)ip_list);
-
+ SAFE_FREE(ip_list);
return connected_ok;
}
-
-
/***********************************************************************
Do the same as security=server, but using NT Domain calls and a session
key from the machine password.
@@ -1485,7 +1444,7 @@ static BOOL find_connect_pdc(struct cli_state *pcli, unsigned char *trust_passwd
BOOL domain_client_validate( char *user, char *domain,
char *smb_apasswd, int smb_apasslen,
char *smb_ntpasswd, int smb_ntpasslen,
- BOOL *user_exists)
+ BOOL *user_exists, NT_USER_TOKEN **pptoken)
{
unsigned char local_challenge[8];
unsigned char local_lm_response[24];
@@ -1499,6 +1458,10 @@ BOOL domain_client_validate( char *user, char *domain,
uint32 smb_uid_low;
BOOL connected_ok = False;
time_t last_change_time;
+ NTSTATUS status;
+
+ if (pptoken)
+ *pptoken = NULL;
if(user_exists != NULL)
*user_exists = True; /* Only set false on a very specific error. */
@@ -1598,20 +1561,20 @@ BOOL domain_client_validate( char *user, char *domain,
ZERO_STRUCT(info3);
- if(cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge,
+ status = cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge,
((smb_apasslen != 0) ? smb_apasswd : NULL),
((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
- &ctr, &info3) == False) {
- uint32 nt_rpc_err;
+ &ctr, &info3);
+
+ if (!NT_STATUS_IS_OK(status)) {
- cli_error(&cli, NULL, NULL, &nt_rpc_err);
DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
-%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
+%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, get_nt_error_msg(status) ));
cli_nt_session_close(&cli);
cli_ulogoff(&cli);
cli_shutdown(&cli);
- if((nt_rpc_err == NT_STATUS_NO_SUCH_USER) && (user_exists != NULL))
+ if((NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NO_SUCH_USER)) && (user_exists != NULL))
*user_exists = False;
return False;
@@ -1621,6 +1584,43 @@ BOOL domain_client_validate( char *user, char *domain,
* Here, if we really want it, we have lots of info about the user in info3.
*/
+ /* Return group membership as returned by NT. This contains group
+ membership in nested groups which doesn't seem to be accessible by any
+ other means. We merge this into the NT_USER_TOKEN associated with the vuid
+ later on. */
+
+ if (pptoken && (info3.num_groups2 != 0)) {
+ NT_USER_TOKEN *ptok;
+ int i;
+ DOM_SID domain_sid;
+
+ *pptoken = NULL;
+
+ if ((ptok = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL) {
+ DEBUG(0, ("domain_client_validate: Out of memory allocating NT_USER_TOKEN\n"));
+ return False;
+ }
+
+ ptok->num_sids = (size_t)info3.num_groups2;
+ if ((ptok->user_sids = (DOM_SID *)malloc( sizeof(DOM_SID) * ptok->num_sids )) == NULL) {
+ DEBUG(0, ("domain_client_validate: Out of memory allocating group SIDS\n"));
+ SAFE_FREE(ptok);
+ return False;
+ }
+
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+ DEBUG(0, ("domain_client_validate: unable to fetch domain sid.\n"));
+ delete_nt_token(&ptok);
+ return False;
+ }
+
+ for (i = 0; i < ptok->num_sids; i++) {
+ sid_copy(&ptok->user_sids[i], &domain_sid);
+ sid_append_rid(&ptok->user_sids[i], info3.gids[i].g_rid);
+ }
+ *pptoken = ptok;
+ }
+
#if 0
/*
* We don't actually need to do this - plus it fails currently with
diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c
index 366707cd589..2837187f4bf 100644
--- a/source/smbd/pipes.c
+++ b/source/smbd/pipes.c
@@ -31,8 +31,6 @@
#define PIPE "\\PIPE\\"
#define PIPELEN strlen(PIPE)
-extern int DEBUGLEVEL;
-
extern struct pipe_id_info pipe_names[];
/****************************************************************************
@@ -58,7 +56,7 @@ int reply_open_pipe_and_X(connection_struct *conn,
/* at a mailslot or something we really, really don't understand, */
/* not just something we really don't understand. */
if ( strncmp(fname,PIPE,PIPELEN) != 0 )
- return(ERROR(ERRSRV,ERRaccess));
+ return(ERROR_DOS(ERRSRV,ERRaccess));
DEBUG(4,("Opening pipe %s.\n", fname));
@@ -68,7 +66,7 @@ int reply_open_pipe_and_X(connection_struct *conn,
break;
if (pipe_names[i].client_pipe == NULL)
- return(ERROR(ERRSRV,ERRaccess));
+ return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe));
/* Strip \PIPE\ off the name. */
pstrcpy(fname,smb_buf(inbuf) + PIPELEN);
@@ -78,7 +76,7 @@ int reply_open_pipe_and_X(connection_struct *conn,
* Hack for NT printers... JRA.
*/
if(should_fail_next_srvsvc_open(fname))
- return(ERROR(ERRSRV,ERRaccess));
+ return(ERROR_DOS(ERRSRV,ERRaccess));
#endif
/* Known pipes arrive with DIR attribs. Remove it so a regular file */
@@ -87,7 +85,7 @@ int reply_open_pipe_and_X(connection_struct *conn,
smb_ofun |= FILE_CREATE_IF_NOT_EXIST;
p = open_rpc_pipe_p(fname, conn, vuid);
- if (!p) return(ERROR(ERRSRV,ERRnofids));
+ if (!p) return(ERROR_DOS(ERRSRV,ERRnofids));
/* Prepare the reply */
set_message(outbuf,15,0,True);
@@ -123,7 +121,7 @@ int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize)
char *data;
if (!p)
- return(ERROR(ERRDOS,ERRbadfid));
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
data = smb_buf(inbuf) + 3;
@@ -163,7 +161,7 @@ int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
char *data;
if (!p)
- return(ERROR(ERRDOS,ERRbadfid));
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
data = smb_base(inbuf) + smb_doff;
@@ -223,7 +221,7 @@ int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
#endif
if (!p)
- return(ERROR(ERRDOS,ERRbadfid));
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
set_message(outbuf,12,0,True);
data = smb_buf(outbuf);
@@ -252,12 +250,12 @@ int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf)
int outsize = set_message(outbuf,0,0,True);
if (!p)
- return(ERROR(ERRDOS,ERRbadfid));
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
DEBUG(5,("reply_pipe_close: pnum:%x\n", p->pnum));
if (!close_rpc_pipe_hnd(p, conn))
- return(ERROR(ERRDOS,ERRbadfid));
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
return(outsize);
}
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c
index 5c22b89a8d8..99c5760314b 100644
--- a/source/smbd/posix_acls.c
+++ b/source/smbd/posix_acls.c
@@ -38,7 +38,7 @@ typedef struct canon_ace {
struct canon_ace *next, *prev;
SMB_ACL_TAG_T type;
mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
- DOM_SID sid;
+ DOM_SID trustee;
enum ace_owner owner_type;
enum ace_attribute attr;
posix_id unix_ug;
@@ -74,7 +74,7 @@ static void free_canon_ace_list( canon_ace *list_head )
while (list_head) {
canon_ace *old_head = list_head;
DLIST_REMOVE(list_head, list_head);
- free(old_head);
+ SAFE_FREE(old_head);
}
}
@@ -103,13 +103,13 @@ static void print_canon_ace(canon_ace *pace, int num)
fstring str;
dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
- dbgtext( "SID = %s ", sid_to_string( str, &pace->sid));
+ dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
if (pace->owner_type == UID_ACE) {
- struct passwd *pass = sys_getpwuid(pace->unix_ug.uid);
- dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, pass ? pass->pw_name : "UNKNOWN");
+ char *u_name = uidtoname(pace->unix_ug.uid);
+ dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name);
} else if (pace->owner_type == GID_ACE) {
- struct group *grp = getgrgid(pace->unix_ug.gid);
- dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, grp ? grp->gr_name : "UNKNOWN");
+ char *g_name = gidtoname(pace->unix_ug.gid);
+ dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name);
} else
dbgtext( "other ");
switch (pace->type) {
@@ -243,7 +243,7 @@ static void merge_aces( canon_ace **pp_list_head )
curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
- if (sid_equal(&curr_ace->sid, &curr_ace_outer->sid) &&
+ if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
(curr_ace->attr == curr_ace_outer->attr)) {
if( DEBUGLVL( 10 )) {
@@ -256,7 +256,7 @@ static void merge_aces( canon_ace **pp_list_head )
curr_ace_outer->perms |= curr_ace->perms;
DLIST_REMOVE(list_head, curr_ace);
- free(curr_ace);
+ SAFE_FREE(curr_ace);
curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
}
}
@@ -283,7 +283,7 @@ static void merge_aces( canon_ace **pp_list_head )
* we've put on the ACL, we know the deny must be the first one.
*/
- if (sid_equal(&curr_ace->sid, &curr_ace_outer->sid) &&
+ if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
(curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
if( DEBUGLVL( 10 )) {
@@ -301,7 +301,7 @@ static void merge_aces( canon_ace **pp_list_head )
*/
DLIST_REMOVE(list_head, curr_ace);
- free(curr_ace);
+ SAFE_FREE(curr_ace);
curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
} else {
@@ -317,7 +317,8 @@ static void merge_aces( canon_ace **pp_list_head )
*/
DLIST_REMOVE(list_head, curr_ace_outer);
- free(curr_ace_outer);
+ SAFE_FREE(curr_ace_outer);
+ break;
}
}
@@ -572,7 +573,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
pace->type = SMB_ACL_USER_OBJ;
pace->owner_type = UID_ACE;
pace->unix_ug.uid = pst->st_uid;
- pace->sid = *pfile_owner_sid;
+ pace->trustee = *pfile_owner_sid;
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
pace->attr = ALLOW_ACE;
@@ -589,7 +590,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
pace->type = SMB_ACL_GROUP_OBJ;
pace->owner_type = GID_ACE;
pace->unix_ug.uid = pst->st_gid;
- pace->sid = *pfile_grp_sid;
+ pace->trustee = *pfile_grp_sid;
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
pace->attr = ALLOW_ACE;
@@ -606,7 +607,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
pace->type = SMB_ACL_OTHER;
pace->owner_type = WORLD_ACE;
pace->unix_ug.world = -1;
- pace->sid = global_sid_World;
+ pace->trustee = global_sid_World;
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
pace->attr = ALLOW_ACE;
@@ -688,7 +689,7 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
if (psa1->info.mask != psa2->info.mask)
continue;
- if (!sid_equal(&psa1->sid, &psa2->sid))
+ if (!sid_equal(&psa1->trustee, &psa2->trustee))
continue;
/*
@@ -718,10 +719,10 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
* Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
*/
- if (non_mappable_sid(&psa->sid)) {
+ if (non_mappable_sid(&psa->trustee)) {
fstring str;
DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
- sid_to_string(str, &psa->sid) ));
+ sid_to_string(str, &psa->trustee) ));
continue;
}
@@ -738,28 +739,28 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
ZERO_STRUCTP(current_ace);
- sid_copy(&current_ace->sid, &psa->sid);
+ sid_copy(&current_ace->trustee, &psa->trustee);
/*
* Try and work out if the SID is a user or group
* as we need to flag these differently for POSIX.
*/
- if( sid_equal(&current_ace->sid, &global_sid_World)) {
+ if( sid_equal(&current_ace->trustee, &global_sid_World)) {
current_ace->owner_type = WORLD_ACE;
current_ace->unix_ug.world = -1;
- } else if (sid_to_uid( &current_ace->sid, &current_ace->unix_ug.uid, &sid_type)) {
+ } else if (sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid, &sid_type)) {
current_ace->owner_type = UID_ACE;
- } else if (sid_to_gid( &current_ace->sid, &current_ace->unix_ug.gid, &sid_type)) {
+ } else if (sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid, &sid_type)) {
current_ace->owner_type = GID_ACE;
} else {
fstring str;
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
- free(current_ace);
DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
- sid_to_string(str, &current_ace->sid) ));
+ sid_to_string(str, &current_ace->trustee) ));
+ SAFE_FREE(current_ace);
return False;
}
@@ -775,15 +776,15 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
* Now note what kind of a POSIX ACL this should map to.
*/
- if(sid_equal(&current_ace->sid, pfile_owner_sid)) {
+ if(sid_equal(&current_ace->trustee, pfile_owner_sid)) {
current_ace->type = SMB_ACL_USER_OBJ;
- } else if( sid_equal(&current_ace->sid, pfile_grp_sid)) {
+ } else if( sid_equal(&current_ace->trustee, pfile_grp_sid)) {
current_ace->type = SMB_ACL_GROUP_OBJ;
- } else if( sid_equal(&current_ace->sid, &global_sid_World)) {
+ } else if( sid_equal(&current_ace->trustee, &global_sid_World)) {
current_ace->type = SMB_ACL_OTHER;
@@ -827,7 +828,7 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
- free(current_ace);
+ SAFE_FREE(current_ace);
return False;
}
@@ -878,7 +879,7 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
- free(current_ace);
+ SAFE_FREE(current_ace);
return False;
}
@@ -894,8 +895,7 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
* Free if ACE was not added.
*/
- if (current_ace)
- free(current_ace);
+ SAFE_FREE(current_ace);
}
if (fsp->is_directory && all_aces_are_inherit_only) {
@@ -926,26 +926,23 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
{
extern DOM_SID global_sid_World;
- struct passwd *pass = NULL;
- struct group *gptr = NULL;
+ fstring u_name;
+ fstring g_name;
/* "Everyone" always matches every uid. */
- if (sid_equal(&group_ace->sid, &global_sid_World))
+ if (sid_equal(&group_ace->trustee, &global_sid_World))
return True;
- if (!(pass = sys_getpwuid(uid_ace->unix_ug.uid)))
- return False;
-
- if (!(gptr = getgrgid(group_ace->unix_ug.gid)))
- return False;
+ fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
+ fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
/*
* Due to the winbind interfaces we need to do this via names,
* not uids/gids.
*/
- return user_in_group_list(pass->pw_name, gptr->gr_name );
+ return user_in_group_list(u_name, g_name );
}
/****************************************************************************
@@ -1068,7 +1065,7 @@ static void process_deny_list( canon_ace **pp_ace_list )
continue;
}
- if (!sid_equal(&curr_ace->sid, &global_sid_World))
+ if (!sid_equal(&curr_ace->trustee, &global_sid_World))
continue;
/* JRATEST - assert. */
@@ -1519,7 +1516,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_
ace->type = tagtype;
ace->perms = convert_permset_to_mode_t(permset);
ace->attr = ALLOW_ACE;
- ace->sid = sid;
+ ace->trustee = sid;
ace->unix_ug = unix_ug;
ace->owner_type = owner_type;
@@ -1720,6 +1717,12 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
if(default_ace || fsp->is_directory || fsp->fd == -1) {
if (sys_acl_set_file(dos_to_unix(fsp->fsp_name,False), the_acl_type, the_acl) == -1) {
+ /*
+ * Some systems allow all the above calls and only fail with no ACL support
+ * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
+ */
+ if (errno == ENOSYS)
+ *pacl_set_support = False;
DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
fsp->fsp_name, strerror(errno) ));
@@ -1727,6 +1730,12 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
}
} else {
if (sys_acl_set_fd(fsp->fd, the_acl) == -1) {
+ /*
+ * Some systems allow all the above calls and only fail with no ACL support
+ * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
+ */
+ if (errno == ENOSYS)
+ *pacl_set_support = False;
DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
fsp->fsp_name, strerror(errno) ));
goto done;
@@ -1938,14 +1947,14 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
for (i = 0; i < num_acls; i++, ace = ace->next) {
SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
- init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0);
+ init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 0);
}
ace = dir_ace;
for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
- init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc,
+ init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
}
@@ -1979,8 +1988,7 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
sys_acl_free_acl(dir_acl);
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
- if (nt_ace_list)
- free(nt_ace_list);
+ SAFE_FREE(nt_ace_list);
return sd_size;
}
@@ -2244,7 +2252,7 @@ static int chmod_acl_internals( SMB_ACL_T posix_acl, mode_t mode)
Note that name is in UNIX character set.
****************************************************************************/
-int chmod_acl(char *name, mode_t mode)
+int chmod_acl(const char *name, mode_t mode)
{
SMB_ACL_T posix_acl = NULL;
int ret = -1;
diff --git a/source/smbd/process.c b/source/smbd/process.c
index 5c329a7c8ac..1299fd20e3a 100644
--- a/source/smbd/process.c
+++ b/source/smbd/process.c
@@ -21,7 +21,8 @@
#include "includes.h"
-extern int DEBUGLEVEL;
+/* To be removed.... JRA */
+#define SMB_ALIGNMENT 1
struct timeval smb_last_time;
@@ -44,9 +45,6 @@ int max_recv = BUFFER_SIZE;
extern int last_message;
extern int global_oplock_break;
extern userdom_struct current_user_info;
-extern char *last_inbuf;
-extern char *InBuffer;
-extern char *OutBuffer;
extern int smb_read_error;
extern VOLATILE sig_atomic_t reload_after_sighup;
extern BOOL global_machine_password_needs_changing;
@@ -87,7 +85,7 @@ static BOOL push_message(ubi_slList *list_head, char *buf, int msg_len)
if(msg->msg_buf == NULL)
{
DEBUG(0,("push_message: malloc fail (2)\n"));
- free((char *)msg);
+ SAFE_FREE(msg);
return False;
}
@@ -125,7 +123,7 @@ static void async_processing(fd_set *fds, char *buffer, int buffer_len)
/* check for sighup processing */
if (reload_after_sighup) {
- unbecome_user();
+ change_to_root_user();
DEBUG(1,("Reloading services after SIGHUP\n"));
reload_services(False);
reload_after_sighup = False;
@@ -180,8 +178,8 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
/* Free the message we just copied. */
- free((char *)msg->msg_buf);
- free((char *)msg);
+ SAFE_FREE(msg->msg_buf);
+ SAFE_FREE(msg);
DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
return True;
@@ -199,7 +197,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
to.tv_sec = timeout / 1000;
to.tv_usec = (timeout % 1000) * 1000;
- selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,timeout>0?&to:NULL);
+ selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,timeout>0?&to:NULL);
/* if we get EINTR then maybe we have received an oplock
signal - treat this as select returning 1. This is ugly, but
@@ -366,11 +364,11 @@ struct smb_message_struct
/* 0x18 */ { NULL, NULL, 0 },
/* 0x19 */ { NULL, NULL, 0 },
/* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
-/* 0x1b */ { "SMBreadBmpx",NULL,0},
+/* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
/* 0x1c */ { "SMBreadBs",NULL,0},
/* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
-/* 0x1e */ { "SMBwriteBmpx",NULL,0},
-/* 0x1f */ { "SMBwriteBs",NULL,0},
+/* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
+/* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
/* 0x20 */ { "SMBwritec",NULL,0},
/* 0x21 */ { NULL, NULL, 0 },
/* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
@@ -615,7 +613,9 @@ static void smb_dump(char *name, int type, char *data, ssize_t len)
if (fd != -1 || errno != EEXIST) break;
}
if (fd != -1) {
- write(fd, data, len);
+ ssize_t ret = write(fd, data, len);
+ if (ret != len)
+ DEBUG(0,("smb_dump: problem: write returned %d\n", (int)ret ));
close(fd);
DEBUG(0,("created %s len %d\n", fname, len));
}
@@ -708,20 +708,20 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
/* does this protocol need to be run as root? */
if (!(flags & AS_USER))
- unbecome_user();
+ change_to_root_user();
/* does this protocol need a valid tree connection? */
if ((flags & AS_USER) && !conn) {
- return ERROR(ERRSRV, ERRinvnid);
+ return ERROR_DOS(ERRSRV, ERRinvnid);
}
/* does this protocol need to be run as the connected user? */
- if ((flags & AS_USER) && !become_user(conn,session_tag)) {
+ if ((flags & AS_USER) && !change_to_user(conn,session_tag)) {
if (flags & AS_GUEST)
flags &= ~AS_USER;
else
- return(ERROR(ERRSRV,ERRaccess));
+ return(ERROR_DOS(ERRSRV,ERRaccess));
}
/* this code is to work around a bug is MS client 3 without
@@ -732,23 +732,23 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
/* does it need write permission? */
if ((flags & NEED_WRITE) && !CAN_WRITE(conn))
- return(ERROR(ERRSRV,ERRaccess));
+ return(ERROR_DOS(ERRSRV,ERRaccess));
/* ipc services are limited */
if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC)) {
- return(ERROR(ERRSRV,ERRaccess));
+ return(ERROR_DOS(ERRSRV,ERRaccess));
}
/* load service specific parameters */
- if (conn && !become_service(conn,(flags & AS_USER)?True:False)) {
- return(ERROR(ERRSRV,ERRaccess));
+ if (conn && !set_current_service(conn,(flags & AS_USER)?True:False)) {
+ return(ERROR_DOS(ERRSRV,ERRaccess));
}
/* does this protocol need to be run as guest? */
if ((flags & AS_GUEST) &&
- (!become_guest() ||
+ (!change_to_guest() ||
!check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) {
- return(ERROR(ERRSRV,ERRaccess));
+ return(ERROR_DOS(ERRSRV,ERRaccess));
}
last_inbuf = inbuf;
@@ -797,7 +797,7 @@ static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
****************************************************************************/
static BOOL smbd_process_limit(void)
{
- int total_smbds;
+ int32 total_smbds;
if (lp_max_smbd_processes()) {
@@ -813,7 +813,7 @@ set. Ignoring max smbd restriction.\n"));
return False;
}
- if (tdb_change_int_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1)
+ if (tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1)
return True;
return total_smbds > lp_max_smbd_processes();
@@ -920,11 +920,11 @@ void construct_reply_common(char *inbuf,char *outbuf)
memset(outbuf,'\0',smb_size);
set_message(outbuf,0,0,True);
- CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com);
+ SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));
memcpy(outbuf+4,inbuf+4,4);
- CVAL(outbuf,smb_rcls) = SMB_SUCCESS;
- CVAL(outbuf,smb_reh) = 0;
+ SCVAL(outbuf,smb_rcls,SMB_SUCCESS);
+ SCVAL(outbuf,smb_reh,0);
SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); /* bit 7 set
means a reply */
SSVAL(outbuf,smb_flg2,FLAGS2_LONG_PATH_COMPONENTS);
@@ -955,7 +955,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
/* maybe its not chained */
if (smb_com2 == 0xFF) {
- CVAL(outbuf,smb_vwv0) = 0xFF;
+ SCVAL(outbuf,smb_vwv0,0xFF);
return outsize;
}
@@ -975,7 +975,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
/* we need to tell the client where the next part of the reply will be */
SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));
- CVAL(outbuf,smb_vwv0) = smb_com2;
+ SCVAL(outbuf,smb_vwv0,smb_com2);
/* remember how much the caller added to the chain, only counting stuff
after the parameter words */
@@ -997,7 +997,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
memmove(inbuf2,inbuf,smb_wct);
/* create the in buffer */
- CVAL(inbuf2,smb_com) = smb_com2;
+ SCVAL(inbuf2,smb_com,smb_com2);
/* create the out buffer */
construct_reply_common(inbuf2, outbuf2);
@@ -1012,7 +1012,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
/* copy the new reply and request headers over the old ones, but
preserve the smb_com field */
memmove(orig_outbuf,outbuf2,smb_wct);
- CVAL(orig_outbuf,smb_com) = smb_com1;
+ SCVAL(orig_outbuf,smb_com,smb_com1);
/* restore the saved data, being careful not to overwrite any
data from the reply header */
@@ -1102,7 +1102,7 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t
last_idle_closed_check = t;
/* become root again if waiting */
- unbecome_user();
+ change_to_root_user();
/* check if we need to reload services */
check_reload(t);
@@ -1141,7 +1141,7 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t
return False;
}
- if(global_machine_password_needs_changing)
+ if(global_machine_password_needs_changing && lp_security() == SEC_DOMAIN)
{
unsigned char trust_passwd_hash[16];
time_t lct;
diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c
index 46693a6fe1e..5e744bc97dd 100644
--- a/source/smbd/quotas.c
+++ b/source/smbd/quotas.c
@@ -28,8 +28,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
#if defined(VXFS_QUOTA)
/*
@@ -57,6 +55,9 @@ BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_B
*/
#include <linux/quota.h>
+#ifdef HAVE_LINUX_XQM_H
+#include <linux/xqm.h>
+#endif
#include <mntent.h>
#include <linux/unistd.h>
@@ -75,10 +76,35 @@ typedef struct _LINUX_SMB_DISK_QUOTA {
} LINUX_SMB_DISK_QUOTA;
/****************************************************************************
+ Abstract out the XFS Quota Manager quota get call.
+****************************************************************************/
+
+static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+#ifdef HAVE_LINUX_XQM_H
+ struct fs_disk_quota D;
+ ZERO_STRUCT(D);
+
+ if ((ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
+ return ret;
+
+ dp->bsize = (SMB_BIG_UINT)512;
+ dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.d_icount;
+ dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
+#endif
+ return ret;
+}
+
+/****************************************************************************
Abstract out the old and new Linux quota get calls.
****************************************************************************/
-static int get_smb_linux_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
+static int get_smb_linux_vfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
{
int ret;
#ifdef LINUX_QUOTAS_1
@@ -116,7 +142,7 @@ static int get_smb_linux_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA
try to get the disk space from disk quotas (LINUX version)
****************************************************************************/
-BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
int r;
SMB_STRUCT_STAT S;
@@ -156,7 +182,10 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
save_re_uid();
set_effective_uid(0);
- r=get_smb_linux_quota(mnt->mnt_fsname, euser_id, &D);
+ if (strcmp(mnt->mnt_type, "xfs") == 0)
+ r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D);
+ else
+ r=get_smb_linux_vfs_quota(mnt->mnt_fsname, euser_id, &D);
restore_re_uid();
/* Use softlimit to determine disk space, except when it has been exceeded */
@@ -201,7 +230,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
try to get the disk space from disk quotas (CRAY VERSION)
****************************************************************************/
-BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
struct mntent *mnt;
FILE *fd;
@@ -481,7 +510,7 @@ try to get the disk space from disk quotas (SunOS & Solaris2 version)
Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
****************************************************************************/
-BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
uid_t euser_id;
int ret;
@@ -641,7 +670,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
try to get the disk space from disk quotas - OSF1 version
****************************************************************************/
-BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
int r, save_errno;
struct dqblk D;
@@ -707,7 +736,7 @@ try to get the disk space from disk quotas (IRIX 6.2 version)
#include <sys/quota.h>
#include <mntent.h>
-BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
uid_t euser_id;
int r;
@@ -845,7 +874,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
try to get the disk space from disk quotas - default version
****************************************************************************/
-BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
int r;
struct dqblk D;
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index ffcbe6d8986..0d89adf25b6 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -28,7 +28,6 @@
/* look in server.c for some explanation of these variables */
extern int Protocol;
-extern int DEBUGLEVEL;
extern int max_send;
extern int max_recv;
extern char magic_char;
@@ -80,8 +79,8 @@ int reply_special(char *inbuf,char *outbuf)
switch (msg_type) {
case 0x81: /* session request */
- CVAL(outbuf,0) = 0x82;
- CVAL(outbuf,3) = 0;
+ SCVAL(outbuf,0,0x82);
+ SCVAL(outbuf,3,0);
if (name_len(inbuf+4) > 50 ||
name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
DEBUG(0,("Invalid name length in session request\n"));
@@ -114,7 +113,7 @@ int reply_special(char *inbuf,char *outbuf)
if (name_type == 'R') {
/* We are being asked for a pathworks session ---
no thanks! */
- CVAL(outbuf, 0) = 0x83;
+ SCVAL(outbuf, 0, 0x83);
break;
}
@@ -127,16 +126,15 @@ int reply_special(char *inbuf,char *outbuf)
reload_services(True);
reopen_logs();
- if (lp_status(-1)) {
- claim_connection(NULL,"",MAXSTATUS,True);
- }
+ if (lp_status(-1))
+ claim_connection(NULL,"",0,True);
break;
case 0x89: /* session keepalive request
(some old clients produce this?) */
- CVAL(outbuf,0) = 0x85;
- CVAL(outbuf,3) = 0;
+ SCVAL(outbuf,0,0x85);
+ SCVAL(outbuf,3,0);
break;
case 0x82: /* positive session response */
@@ -161,12 +159,12 @@ int reply_special(char *inbuf,char *outbuf)
work out what error to give to a failed connection
********************************************************************/
-static int connection_error(char *inbuf,char *outbuf,int ecode)
+static int connection_error(char *outbuf, int ecode)
{
if (ecode == ERRnoipc || ecode == ERRnosuchshare)
- return(ERROR(ERRDOS,ecode));
-
- return(ERROR(ERRSRV,ecode));
+ return(ERROR_DOS(ERRDOS,ecode));
+
+ return(ERROR_DOS(ERRSRV,ecode));
}
/****************************************************************************
@@ -258,7 +256,7 @@ int reply_tcon(connection_struct *conn,
if (!conn) {
END_PROFILE(SMBtcon);
- return(connection_error(inbuf,outbuf,ecode));
+ return(connection_error(outbuf,ecode));
}
outsize = set_message(outbuf,2,0,True);
@@ -300,7 +298,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
if (passlen > MAX_PASS_LEN) {
overflow_attack(passlen);
- return(ERROR(ERRDOS,ERRbuftoosmall));
+ return(ERROR_DOS(ERRDOS,ERRbuftoosmall));
}
memcpy(password,smb_buf(inbuf),passlen);
@@ -321,7 +319,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
p = strchr(path+2,'\\');
if (!p) {
END_PROFILE(SMBtconX);
- return(ERROR(ERRDOS,ERRnosuchshare));
+ return(ERROR_DOS(ERRDOS,ERRnosuchshare));
}
fstrcpy(service,p+1);
}
@@ -368,7 +366,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
if (!conn) {
END_PROFILE(SMBtconX);
- return(connection_error(inbuf,outbuf,ecode));
+ return(connection_error(outbuf,ecode));
}
if (Protocol < PROTOCOL_NT1) {
@@ -416,7 +414,7 @@ int reply_unknown(char *inbuf,char *outbuf)
DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
smb_fn_name(type), type, type));
- return(ERROR(ERRSRV,ERRunknownsmb));
+ return(ERROR_DOS(ERRSRV,ERRunknownsmb));
}
/****************************************************************************
@@ -442,7 +440,7 @@ int reply_ioctl(connection_struct *conn,
break;
default:
END_PROFILE(SMBioctl);
- return(ERROR(ERRSRV,ERRnosupport));
+ return(ERROR_DOS(ERRSRV,ERRnosupport));
}
outsize = set_message(outbuf,8,replysize+1,True);
@@ -466,7 +464,6 @@ int reply_ioctl(connection_struct *conn,
/****************************************************************************
Always return an error: it's just a matter of which one...
- FIXME: memory leak - no call to pdb_free_sam() --jerry
****************************************************************************/
static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user,
@@ -491,32 +488,38 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out
} else {
if ((smb_passlen != 24) || (smb_nt_passlen != 24)) {
DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user));
+ pdb_free_sam(sam_trust_acct);
return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw));
}
if (!smb_password_ok(sam_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) {
DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
+ pdb_free_sam(sam_trust_acct);
return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw));
}
acct_ctrl = pdb_get_acct_ctrl(sam_trust_acct);
if (acct_ctrl & ACB_DOMTRUST) {
DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user));
+ pdb_free_sam(sam_trust_acct);
return(ERROR_BOTH(NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT,ERRDOS,1807));
}
if (acct_ctrl & ACB_SVRTRUST) {
DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user));
+ pdb_free_sam(sam_trust_acct);
return(ERROR_BOTH(NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT,ERRDOS,1809));
}
if (acct_ctrl & ACB_WSTRUST) {
DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user));
+ pdb_free_sam(sam_trust_acct);
return(ERROR_BOTH(NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT,ERRDOS,1808));
}
}
/* don't know what to do: indicate logon failure */
+ pdb_free_sam(sam_trust_acct);
return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRDOS,1326));
}
@@ -526,17 +529,18 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out
int smb_create_user(char *unix_user, char *homedir)
{
- pstring add_script;
- int ret;
-
- pstrcpy(add_script, lp_adduser_script());
- if (! *add_script) return -1;
- all_string_sub(add_script, "%u", unix_user, sizeof(pstring));
- if (homedir)
- all_string_sub(add_script, "%H", homedir, sizeof(pstring));
- ret = smbrun(add_script,NULL);
- DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
- return ret;
+ pstring add_script;
+ int ret;
+
+ pstrcpy(add_script, lp_adduser_script());
+ if (! *add_script)
+ return -1;
+ all_string_sub(add_script, "%u", unix_user, sizeof(pstring));
+ if (homedir)
+ all_string_sub(add_script, "%H", homedir, sizeof(pstring));
+ ret = smbrun(add_script,NULL);
+ DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
+ return ret;
}
/****************************************************************************
@@ -545,15 +549,16 @@ int smb_create_user(char *unix_user, char *homedir)
static int smb_delete_user(char *unix_user)
{
- pstring del_script;
- int ret;
-
- pstrcpy(del_script, lp_deluser_script());
- if (! *del_script) return -1;
- all_string_sub(del_script, "%u", unix_user, sizeof(pstring));
- ret = smbrun(del_script,NULL);
- DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
- return ret;
+ pstring del_script;
+ int ret;
+
+ pstrcpy(del_script, lp_deluser_script());
+ if (! *del_script)
+ return -1;
+ all_string_sub(del_script, "%u", unix_user, sizeof(pstring));
+ ret = smbrun(del_script,NULL);
+ DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
+ return ret;
}
/****************************************************************************
@@ -611,19 +616,6 @@ static BOOL check_server_security(char *orig_user, char *domain, char *unix_user
if(lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True)))
smb_create_user(unix_user, NULL);
-
- if(lp_adduser_script() && pwd) {
- SMB_STRUCT_STAT st;
-
- /*
- * Also call smb_create_user if the users home directory
- * doesn't exist. Used with winbindd to allow the script to
- * create the home directory for a user mapped with winbindd.
- */
-
- if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT))
- smb_create_user(unix_user, pwd->pw_dir);
- }
}
return ret;
@@ -635,7 +627,7 @@ static BOOL check_server_security(char *orig_user, char *domain, char *unix_user
static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user,
char *smb_apasswd, int smb_apasslen,
- char *smb_ntpasswd, int smb_ntpasslen)
+ char *smb_ntpasswd, int smb_ntpasslen, NT_USER_TOKEN **pptoken)
{
BOOL ret = False;
BOOL user_exists = True;
@@ -650,7 +642,7 @@ static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user
ret = domain_client_validate(orig_user, domain,
smb_apasswd, smb_apasslen,
smb_ntpasswd, smb_ntpasslen,
- &user_exists);
+ &user_exists, pptoken);
if(ret) {
/*
@@ -712,6 +704,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
static BOOL done_sesssetup = False;
BOOL doencrypt = SMBENCRYPT();
fstring domain;
+ NT_USER_TOKEN *ptok = NULL;
+
START_PROFILE(SMBsesssetupX);
*smb_apasswd = 0;
@@ -724,7 +718,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
smb_apasslen = SVAL(inbuf,smb_vwv7);
if (smb_apasslen > MAX_PASS_LEN) {
overflow_attack(smb_apasslen);
- return(ERROR(ERRDOS,ERRbuftoosmall));
+ return(ERROR_DOS(ERRDOS,ERRbuftoosmall));
}
memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
@@ -764,7 +758,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
if (passlen1 > MAX_PASS_LEN) {
overflow_attack(passlen1);
- return(ERROR(ERRDOS,ERRbuftoosmall));
+ return(ERROR_DOS(ERRDOS,ERRbuftoosmall));
}
passlen1 = MIN(passlen1, MAX_PASS_LEN);
@@ -887,7 +881,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
if (!*user && !*smb_apasswd && !*domain) {
DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n"));
END_PROFILE(SMBsesssetupX);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
}
}
@@ -950,7 +944,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
if (!guest && !check_server_security(orig_user, domain, user,
smb_apasswd, smb_apasslen, smb_ntpasswd, smb_ntpasslen) &&
!check_domain_security(orig_user, domain, user, smb_apasswd,
- smb_apasslen, smb_ntpasswd, smb_ntpasslen) &&
+ smb_apasslen, smb_ntpasswd, smb_ntpasslen, &ptok) &&
!check_hosts_equiv(user))
{
@@ -992,6 +986,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
{
if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
{
+ delete_nt_token(&ptok);
DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
END_PROFILE(SMBsesssetupX);
return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
@@ -1001,6 +996,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
{
if (smb_getpwnam(user,True))
{
+ delete_nt_token(&ptok);
DEBUG(1,("Rejecting user '%s': bad password\n", user));
END_PROFILE(SMBsesssetupX);
return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
@@ -1029,7 +1025,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
if (!strequal(user,lp_guestaccount(-1)) &&
lp_servicenumber(user) < 0)
{
- add_home_service(user,get_user_home_dir(user));
+ add_home_service(user,get_user_service_home_dir(user));
}
@@ -1054,6 +1050,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
{
const struct passwd *pw = smb_getpwnam(user,False);
if (!pw) {
+ delete_nt_token(&ptok);
DEBUG(1,("Username %s is invalid on this system\n",user));
END_PROFILE(SMBsesssetupX);
return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
@@ -1068,13 +1065,14 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
/* register the name and uid as being validated, so further connections
to a uid can get through without a password, on the same VC */
- sess_vuid = register_vuid(uid,gid,user,current_user_info.smb_name,domain,guest);
+ sess_vuid = register_vuid(uid,gid,user,current_user_info.smb_name,domain,guest,&ptok);
+
+ delete_nt_token(&ptok);
if (sess_vuid == -1) {
- return(ERROR(ERRDOS,ERRnoaccess));
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
}
-
SSVAL(outbuf,smb_uid,sess_vuid);
SSVAL(inbuf,smb_uid,sess_vuid);
@@ -1116,29 +1114,16 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
ok = S_ISDIR(sbuf.st_mode);
}
- if (!ok)
- {
+ if (!ok) {
/* We special case this - as when a Windows machine
is parsing a path is steps through the components
one at a time - if a component fails it expects
ERRbadpath, not ERRbadfile.
*/
- if(errno == ENOENT)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
+ if(errno == ENOENT) {
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
}
-#if 0
- /* Ugly - NT specific hack - maybe not needed ? (JRA) */
- if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
- (get_remote_arch() == RA_WINNT))
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbaddirectory;
- }
-#endif
-
return(UNIXERROR(ERRDOS,ERRbadpath));
}
@@ -1201,12 +1186,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if (!ok)
{
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
-
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBgetatr);
return(UNIXERROR(ERRDOS,ERRbadfile));
}
@@ -1221,11 +1201,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
SIVAL(outbuf,smb_vwv3,(uint32)size);
if (Protocol >= PROTOCOL_NT1) {
- char *p = strrchr(fname,'/');
- uint16 flg2 = SVAL(outbuf,smb_flg2);
- if (!p) p = fname;
- if (!is_8_3(fname, True))
- SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
}
DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
@@ -1264,12 +1240,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if (!ok)
{
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
-
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBsetatr);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -1387,7 +1358,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if (strlen(directory) == 0)
pstrcpy(directory,"./");
memset((char *)status,'\0',21);
- CVAL(status,0) = dirtype;
+ SCVAL(status,0,dirtype);
}
else
{
@@ -1413,16 +1384,12 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
{
if(dptr_num == -2)
{
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- END_PROFILE(SMBsearch);
+ set_bad_path_error(errno, bad_path);
+ END_PROFILE(SMBsearch);
return (UNIXERROR(ERRDOS,ERRnofids));
}
END_PROFILE(SMBsearch);
- return(ERROR(ERRDOS,ERRnofids));
+ return ERROR_DOS(ERRDOS,ERRnofids);
}
dptr_set_wcard(dptr_num, strdup(mask));
}
@@ -1471,7 +1438,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if ( (numentries == 0) || !ok)
{
- CVAL(outbuf,smb_rcls) = ERRDOS;
+ SCVAL(outbuf,smb_rcls,ERRDOS);
SSVAL(outbuf,smb_err,ERRnofiles);
dptr_close(&dptr_num);
}
@@ -1482,7 +1449,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if(ok && expect_close && numentries == 0 && status_len == 0)
{
- CVAL(outbuf,smb_rcls) = ERRDOS;
+ SCVAL(outbuf,smb_rcls,ERRDOS);
SSVAL(outbuf,smb_err,ERRnofiles);
/* Also close the dptr - we know it's gone */
dptr_close(&dptr_num);
@@ -1494,12 +1461,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
SSVAL(outbuf,smb_vwv0,numentries);
SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
- CVAL(smb_buf(outbuf),0) = 5;
+ SCVAL(smb_buf(outbuf),0,5);
SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
if (Protocol >= PROTOCOL_NT1) {
- uint16 flg2 = SVAL(outbuf,smb_flg2);
- SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
}
outsize += DIR_STRUCT_SIZE*numentries;
@@ -1536,7 +1502,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if (status_len == 0) {
END_PROFILE(SMBfclose);
- return(ERROR(ERRSRV,ERRsrverror));
+ return ERROR_DOS(ERRSRV,ERRsrverror);
}
memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
@@ -1590,11 +1556,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (!fsp)
{
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBopen);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -1607,7 +1569,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
DEBUG(3,("attempt to open a directory %s\n",fname));
close_file(fsp,False);
END_PROFILE(SMBopen);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
outsize = set_message(outbuf,7,0,True);
@@ -1621,11 +1583,11 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
SSVAL(outbuf,smb_vwv6,rmode);
if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
}
if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
END_PROFILE(SMBopen);
return(outsize);
}
@@ -1666,7 +1628,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
} else {
END_PROFILE(SMBopenX);
- return (ERROR(ERRSRV,ERRaccess));
+ return ERROR_DOS(ERRSRV,ERRaccess);
}
}
@@ -1685,11 +1647,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
if (!fsp)
{
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBopenX);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -1700,7 +1658,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
if (fmode & aDIR) {
close_file(fsp,False);
END_PROFILE(SMBopenX);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
/* If the caller set the extended oplock request bit
@@ -1722,11 +1680,11 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
*/
if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
}
if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
}
set_message(outbuf,15,0,True);
@@ -1824,11 +1782,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (!fsp)
{
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBcreate);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -1837,11 +1791,11 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
SSVAL(outbuf,smb_vwv0,fsp->fnum);
if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
}
if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
DEBUG( 2, ( "new file %s\n", fname ) );
DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
@@ -1898,10 +1852,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
close(tmpfd);
if (!fsp) {
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBctemp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -1923,11 +1874,11 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
pstrcpy(p,s);
if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
}
if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
DEBUG( 2, ( "created temp file %s\n", fname ) );
DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
@@ -1937,27 +1888,36 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return(outsize);
}
-
/*******************************************************************
-check if a user is allowed to delete a file
+ Check if a user is allowed to delete a file.
********************************************************************/
-static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
+
+static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
{
- SMB_STRUCT_STAT sbuf;
- int fmode;
+ SMB_STRUCT_STAT sbuf;
+ int fmode;
- if (!CAN_WRITE(conn)) return(False);
+ if (!CAN_WRITE(conn))
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
- if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False);
- fmode = dos_mode(conn,fname,&sbuf);
- if (fmode & aDIR) return(False);
- if (!lp_delete_readonly(SNUM(conn))) {
- if (fmode & aRONLY) return(False);
- }
- if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
- return(False);
- if (!check_file_sharing(conn,fname,False)) return(False);
- return(True);
+ if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0)
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ fmode = dos_mode(conn,fname,&sbuf);
+ if (fmode & aDIR)
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ if (!lp_delete_readonly(SNUM(conn))) {
+ if (fmode & aRONLY)
+ return NT_STATUS_CANNOT_DELETE;
+ }
+
+ if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
+ return NT_STATUS_CANNOT_DELETE;
+
+ if (!check_file_sharing(conn,fname,False))
+ return NT_STATUS_SHARING_VIOLATION;
+
+ return NT_STATUS_OK;
}
/****************************************************************************
@@ -1965,14 +1925,13 @@ static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
code.
****************************************************************************/
-int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
- int dirtype, char *name)
+NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
{
pstring directory;
pstring mask;
char *p;
int count=0;
- int error = ERRnoaccess;
+ NTSTATUS error = NT_STATUS_OK;
BOOL has_wild;
BOOL exists=False;
BOOL bad_path = False;
@@ -2010,8 +1969,12 @@ int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
if (!has_wild) {
pstrcat(directory,"/");
pstrcat(directory,mask);
- if (can_delete(directory,conn,dirtype) && !vfs_unlink(conn,directory))
+ error = can_delete(directory,conn,dirtype);
+ if (!NT_STATUS_IS_OK(error)) return error;
+
+ if (vfs_unlink(conn,directory) == 0) {
count++;
+ }
if (!count)
exists = vfs_file_exist(conn,directory,&sbuf);
} else {
@@ -2026,43 +1989,33 @@ int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
We don't implement this yet XXXX
*/
- if (dirptr)
- {
- error = ERRbadfile;
+ if (dirptr) {
+ error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
if (strequal(mask,"????????.???"))
pstrcpy(mask,"*");
- while ((dname = ReadDirName(dirptr)))
- {
+ while ((dname = ReadDirName(dirptr))) {
pstring fname;
pstrcpy(fname,dname);
if(!mask_match(fname, mask, case_sensitive)) continue;
- error = ERRnoaccess;
slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
- if (!can_delete(fname,conn,dirtype)) continue;
- if (!vfs_unlink(conn,fname)) count++;
+ error = can_delete(fname,conn,dirtype);
+ if (!NT_STATUS_IS_OK(error)) continue;
+ if (vfs_unlink(conn,fname) == 0) count++;
DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
}
CloseDir(dirptr);
}
}
- if (count == 0) {
- if (exists)
- return(ERROR(ERRDOS,error));
- else {
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,error));
- }
+ if (count == 0 && NT_STATUS_IS_OK(error)) {
+ error = map_nt_error_from_unix(errno);
}
- return 0;
+ return error;
}
/****************************************************************************
@@ -2074,6 +2027,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
int outsize = 0;
pstring name;
int dirtype;
+ NTSTATUS status;
START_PROFILE(SMBunlink);
dirtype = SVAL(inbuf,smb_vwv0);
@@ -2084,8 +2038,8 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
DEBUG(3,("reply_unlink : %s\n",name));
- outsize = unlink_internals(conn, inbuf, outbuf, dirtype, name);
- if(outsize == 0) {
+ status = unlink_internals(conn, dirtype, name);
+ if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
/*
* Win2k needs a changenotify request response before it will
@@ -2095,10 +2049,9 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
process_pending_change_notify_queue((time_t)0);
outsize = set_message(outbuf,0,0,True);
- }
END_PROFILE(SMBunlink);
- return(outsize);
+ return outsize;
}
/****************************************************************************
@@ -2108,7 +2061,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
void fail_readraw(void)
{
pstring errstr;
- slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)\n",
+ slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
strerror(errno) );
exit_server(errstr);
}
@@ -2119,7 +2072,7 @@ void fail_readraw(void)
int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
{
- size_t maxcount,mincount;
+ ssize_t maxcount,mincount;
size_t nread = 0;
SMB_OFF_T startpos;
char *header = outbuf;
@@ -2210,9 +2163,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
if (size < sizeneeded) {
SMB_STRUCT_STAT st;
if (vfs_fstat(fsp,fsp->fd,&st) == 0)
- size = st.st_size;
- if (!fsp->can_write)
- fsp->size = size;
+ fsp->size = size = st.st_size;
}
if (startpos >= size)
@@ -2253,8 +2204,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
int outsize = 0;
SMB_OFF_T startpos;
size_t numtoread;
- int eclass;
- uint32 ecode;
+ NTSTATUS status;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
START_PROFILE(SMBlockread);
@@ -2277,8 +2227,11 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
* for a write lock. JRA.
*/
- if(!do_lock( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &eclass, &ecode)) {
- if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
+ status = do_lock(fsp, conn, SVAL(inbuf,smb_pid),
+ (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
+
+ if (NT_STATUS_V(status)) {
+ if (lp_blocking_locks(SNUM(conn))) {
/*
* A blocking lock was requested. Package up
* this smb into a queued request and push it
@@ -2289,7 +2242,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
return -1;
}
END_PROFILE(SMBlockread);
- return (ERROR(eclass,ecode));
+ return ERROR_NT(status);
}
nread = read_file(fsp,data,startpos,numtoread);
@@ -2338,7 +2291,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int
if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
END_PROFILE(SMBread);
- return(ERROR(ERRDOS,ERRlock));
+ return ERROR_DOS(ERRDOS,ERRlock);
}
if (numtoread > 0)
@@ -2352,7 +2305,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int
outsize += nread;
SSVAL(outbuf,smb_vwv0,nread);
SSVAL(outbuf,smb_vwv5,nread+3);
- CVAL(smb_buf(outbuf),0) = 1;
+ SCVAL(smb_buf(outbuf),0,1);
SSVAL(smb_buf(outbuf),1,nread);
DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
@@ -2405,7 +2358,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
END_PROFILE(SMBreadX);
- return(ERROR(ERRDOS,ERRbadaccess));
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
}
#endif /* LARGE_SMB_OFF_T */
@@ -2414,7 +2367,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,False)) {
END_PROFILE(SMBreadX);
- return(ERROR(ERRDOS,ERRlock));
+ return ERROR_DOS(ERRDOS,ERRlock);
}
nread = read_file(fsp,data,startpos,smb_maxcnt);
@@ -2470,12 +2423,12 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
}
/* force the error type */
- CVAL(inbuf,smb_com) = SMBwritec;
- CVAL(outbuf,smb_com) = SMBwritec;
+ 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,False)) {
END_PROFILE(SMBwritebraw);
- return(ERROR(ERRDOS,ERRlock));
+ return(ERROR_DOS(ERRDOS,ERRlock));
}
if (numtowrite>0)
@@ -2492,11 +2445,11 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
total_written = nwritten;
/* Return a message to the redirector to tell it to send more bytes */
- CVAL(outbuf,smb_com) = SMBwritebraw;
+ SCVAL(outbuf,smb_com,SMBwritebraw);
SSVALS(outbuf,smb_vwv0,-1);
outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_writebraw: send_smb failed.\n");
+ exit_server("reply_writebraw: send_smb failed.");
/* Now read the raw data into the buffer and write it */
if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
@@ -2508,7 +2461,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
/* Set up outbuf to return the correct return */
outsize = set_message(outbuf,1,0,True);
- CVAL(outbuf,smb_com) = SMBwritec;
+ SCVAL(outbuf,smb_com,SMBwritec);
SSVAL(outbuf,smb_vwv0,total_written);
if (numtowrite != 0) {
@@ -2533,7 +2486,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
if (nwritten < (ssize_t)numtowrite) {
- CVAL(outbuf,smb_rcls) = ERRHRD;
+ SCVAL(outbuf,smb_rcls,ERRHRD);
SSVAL(outbuf,smb_err,ERRdiskfull);
}
@@ -2572,8 +2525,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int siz
size_t numtowrite;
SMB_OFF_T startpos;
char *data;
- int eclass;
- uint32 ecode;
+ NTSTATUS status;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
int outsize = 0;
START_PROFILE(SMBwriteunlock);
@@ -2585,9 +2537,10 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int siz
startpos = IVAL(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos,
+ WRITE_LOCK,False)) {
END_PROFILE(SMBwriteunlock);
- return(ERROR(ERRDOS,ERRlock));
+ return ERROR_DOS(ERRDOS,ERRlock);
}
/* The special X/Open SMB protocol handling of
@@ -2606,9 +2559,11 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int siz
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- if(!do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, (SMB_BIG_UINT)startpos, &eclass, &ecode)) {
+ status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite,
+ (SMB_BIG_UINT)startpos);
+ if (NT_STATUS_V(status)) {
END_PROFILE(SMBwriteunlock);
- return(ERROR(eclass,ecode));
+ return ERROR_NT(status);
}
outsize = set_message(outbuf,1,0,True);
@@ -2622,27 +2577,6 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int siz
return(outsize);
}
-/****************************************************************************
- Return correct error for space allocation fail.
-****************************************************************************/
-
-int allocate_space_error(char *inbuf,char *outbuf, int errno_val)
-{
- errno = errno_val;
- if (!(global_client_caps & CAP_STATUS32))
- return (UNIXERROR(ERRHRD,ERRdiskfull));
-
- /* Use more specific WNT/W2K error codes. */
-#ifdef EDQUOT
- if (errno_val == ENOSPC || errno_val == EDQUOT) {
-#else
- if (errno_val == ENOSPC) {
-#endif
- return(ERROR(0,NT_STATUS_DISK_FULL));
- }
-
- return (UNIXERROR(ERRHRD,ERRdiskfull));
-}
/****************************************************************************
Reply to a write.
@@ -2650,68 +2584,76 @@ int allocate_space_error(char *inbuf,char *outbuf, int errno_val)
int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
{
- size_t numtowrite;
- ssize_t nwritten = -1;
- SMB_OFF_T startpos;
- char *data;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- int outsize = 0;
- START_PROFILE(SMBwrite);
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ SMB_OFF_T startpos;
+ char *data;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
+ START_PROFILE(SMBwrite);
- /* If it's an IPC, pass off the pipe handler. */
- if (IS_IPC(conn)) {
- END_PROFILE(SMBwrite);
- return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
- }
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ END_PROFILE(SMBwrite);
+ return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
+ }
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
- numtowrite = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- data = smb_buf(inbuf) + 3;
+ numtowrite = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+ data = smb_buf(inbuf) + 3;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
- END_PROFILE(SMBwrite);
- return(ERROR(ERRDOS,ERRlock));
- }
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ END_PROFILE(SMBwrite);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
- /* X/Open SMB protocol says that if smb_vwv1 is
- zero then the file size should be extended or
- truncated to the size given in smb_vwv[2-3] */
- if(numtowrite == 0) {
- /* This is actually an allocate call, not set EOF. JRA */
- nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
- if (nwritten < 0) {
- int ret = allocate_space_error(inbuf, outbuf, errno);
- END_PROFILE(SMBwrite);
- return ret;
- }
- } else
- nwritten = write_file(fsp,data,startpos,numtowrite);
+ /*
+ * X/Open SMB protocol says that if smb_vwv1 is
+ * zero then the file size should be extended or
+ * truncated to the size given in smb_vwv[2-3].
+ */
+
+ if(numtowrite == 0) {
+ /*
+ * This is actually an allocate call, and set EOF. JRA.
+ */
+ nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
+ if (nwritten < 0) {
+ END_PROFILE(SMBwrite);
+ return ERROR_NT(NT_STATUS_DISK_FULL);
+ }
+ nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
+ if (nwritten < 0) {
+ END_PROFILE(SMBwrite);
+ return ERROR_NT(NT_STATUS_DISK_FULL);
+ }
+ } else
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if (lp_syncalways(SNUM(conn)))
- sync_file(conn,fsp);
+ if (lp_syncalways(SNUM(conn)))
+ sync_file(conn,fsp);
- if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
- END_PROFILE(SMBwrite);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+ END_PROFILE(SMBwrite);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- outsize = set_message(outbuf,1,0,True);
+ outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,nwritten);
+ SSVAL(outbuf,smb_vwv0,nwritten);
- if (nwritten < (ssize_t)numtowrite) {
- CVAL(outbuf,smb_rcls) = ERRHRD;
- SSVAL(outbuf,smb_err,ERRdiskfull);
- }
+ if (nwritten < (ssize_t)numtowrite) {
+ SCVAL(outbuf,smb_rcls,ERRHRD);
+ SSVAL(outbuf,smb_err,ERRdiskfull);
+ }
- DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
- fsp->fnum, (int)numtowrite, (int)nwritten));
+ DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
- END_PROFILE(SMBwrite);
- return(outsize);
+ END_PROFILE(SMBwrite);
+ return(outsize);
}
@@ -2746,7 +2688,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
END_PROFILE(SMBwriteX);
- return(ERROR(ERRDOS,ERRbadmem));
+ return ERROR_DOS(ERRDOS,ERRbadmem);
}
data = smb_base(inbuf) + smb_doff;
@@ -2768,7 +2710,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
END_PROFILE(SMBwriteX);
- return(ERROR(ERRDOS,ERRbadaccess));
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
}
#endif /* LARGE_SMB_OFF_T */
@@ -2776,7 +2718,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
END_PROFILE(SMBwriteX);
- return(ERROR(ERRDOS,ERRlock));
+ return ERROR_DOS(ERRDOS,ERRlock);
}
/* X/Open SMB protocol says that, unlike SMBwrite
@@ -2800,7 +2742,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
if (nwritten < (ssize_t)numtowrite) {
- CVAL(outbuf,smb_rcls) = ERRHRD;
+ SCVAL(outbuf,smb_rcls,ERRHRD);
SSVAL(outbuf,smb_err,ERRdiskfull);
}
@@ -2963,7 +2905,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
if(!fsp || (fsp->conn != conn)) {
END_PROFILE(SMBclose);
- return(ERROR(ERRDOS,ERRbadfid));
+ return ERROR_DOS(ERRDOS,ERRbadfid);
}
if(fsp->is_directory || fsp->stat_open) {
@@ -2978,21 +2920,10 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
* Close ordinary file.
*/
int close_err;
+ pstring file_name;
- /*
- * If there was a modify time outstanding,
- * try and set it here.
- */
- if(fsp->pending_modtime)
- set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
-
- /*
- * Now take care of any time sent in the close.
- */
- mtime = make_unix_date3(inbuf+smb_vwv1);
-
- /* try and set the date */
- set_filetime(conn, fsp->fsp_name,mtime);
+ /* Save the name for time set in close. */
+ pstrcpy( file_name, fsp->fsp_name);
DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
fsp->fd, fsp->fnum,
@@ -3009,6 +2940,16 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
END_PROFILE(SMBclose);
return (UNIXERROR(ERRHRD,ERRgeneral));
}
+
+ /*
+ * Now take care of any time sent in the close.
+ */
+
+ mtime = make_unix_date3(inbuf+smb_vwv1);
+
+ /* try and set the date */
+ set_filetime(conn, file_name, mtime);
+
}
END_PROFILE(SMBclose);
@@ -3043,7 +2984,7 @@ int reply_writeclose(connection_struct *conn,
if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
END_PROFILE(SMBwriteclose);
- return(ERROR(ERRDOS,ERRlock));
+ return ERROR_DOS(ERRDOS,ERRlock);
}
nwritten = write_file(fsp,data,startpos,numtowrite);
@@ -3083,8 +3024,7 @@ int reply_lock(connection_struct *conn,
{
int outsize = set_message(outbuf,0,0,True);
SMB_BIG_UINT count,offset;
- int eclass;
- uint32 ecode;
+ NTSTATUS status;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
START_PROFILE(SMBlock);
@@ -3098,8 +3038,9 @@ int reply_lock(connection_struct *conn,
DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
fsp->fd, fsp->fnum, (double)offset, (double)count));
- if (!do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &eclass, &ecode)) {
- if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
+ status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
+ if (NT_STATUS_V(status)) {
+ if (lp_blocking_locks(SNUM(conn))) {
/*
* A blocking lock was requested. Package up
* this smb into a queued request and push it
@@ -3111,7 +3052,7 @@ int reply_lock(connection_struct *conn,
}
}
END_PROFILE(SMBlock);
- return (ERROR(eclass,ecode));
+ return ERROR_NT(status);
}
END_PROFILE(SMBlock);
@@ -3126,8 +3067,7 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, in
{
int outsize = set_message(outbuf,0,0,True);
SMB_BIG_UINT count,offset;
- int eclass;
- uint32 ecode;
+ NTSTATUS status;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
START_PROFILE(SMBunlock);
@@ -3136,9 +3076,10 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, in
count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
- if(!do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, &eclass, &ecode)) {
+ status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
+ if (NT_STATUS_V(status)) {
END_PROFILE(SMBunlock);
- return (ERROR(eclass,ecode));
+ return ERROR_NT(status);
}
DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
@@ -3164,7 +3105,7 @@ int reply_tdis(connection_struct *conn,
if (!conn) {
DEBUG(4,("Invalid connection in tdis\n"));
END_PROFILE(SMBtdis);
- return(ERROR(ERRSRV,ERRinvnid));
+ return ERROR_DOS(ERRSRV,ERRinvnid);
}
conn->used = False;
@@ -3206,7 +3147,7 @@ int reply_echo(connection_struct *conn,
smb_setlen(outbuf,outsize - 4);
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_echo: send_smb failed.\n");
+ exit_server("reply_echo: send_smb failed.");
}
DEBUG(3,("echo %d times\n", smb_reverb));
@@ -3230,11 +3171,11 @@ int reply_printopen(connection_struct *conn,
if (!CAN_PRINT(conn)) {
END_PROFILE(SMBsplopen);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
/* Open for exclusive use, write only. */
- fsp = print_fsp_open(conn);
+ fsp = print_fsp_open(conn, NULL);
if (!fsp) {
END_PROFILE(SMBsplopen);
@@ -3267,7 +3208,7 @@ int reply_printclose(connection_struct *conn,
if (!CAN_PRINT(conn)) {
END_PROFILE(SMBsplclose);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
DEBUG(3,("printclose fd=%d fnum=%d\n",
@@ -3303,12 +3244,12 @@ int reply_printqueue(connection_struct *conn,
get it right (tridge) */
if (!CAN_PRINT(conn)) {
END_PROFILE(SMBsplretq);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
SSVAL(outbuf,smb_vwv0,0);
SSVAL(outbuf,smb_vwv1,0);
- CVAL(smb_buf(outbuf),0) = 1;
+ SCVAL(smb_buf(outbuf),0,1);
SSVAL(smb_buf(outbuf),1,0);
DEBUG(3,("printqueue start_index=%d max_count=%d\n",
@@ -3316,8 +3257,9 @@ int reply_printqueue(connection_struct *conn,
{
print_queue_struct *queue = NULL;
+ print_status_struct status;
char *p = smb_buf(outbuf) + 3;
- int count = print_queue_status(SNUM(conn), &queue,NULL);
+ int count = print_queue_status(SNUM(conn), &queue, &status);
int num_to_get = ABS(max_count);
int first = (max_count>0?start_index:start_index+max_count+1);
int i;
@@ -3330,10 +3272,10 @@ int reply_printqueue(connection_struct *conn,
for (i=first;i<first+num_to_get;i++) {
put_dos_date2(p,0,queue[i].time);
- CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
+ SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
SSVAL(p,5, queue[i].job);
SIVAL(p,7,queue[i].size);
- CVAL(p,11) = 0;
+ SCVAL(p,11,0);
StrnCpy(p+12,queue[i].user,16);
p += 28;
}
@@ -3342,11 +3284,11 @@ int reply_printqueue(connection_struct *conn,
outsize = set_message(outbuf,2,28*count+3,False);
SSVAL(outbuf,smb_vwv0,count);
SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
- CVAL(smb_buf(outbuf),0) = 1;
+ SCVAL(smb_buf(outbuf),0,1);
SSVAL(smb_buf(outbuf),1,28*count);
}
- if (queue) free(queue);
+ SAFE_FREE(queue);
DEBUG(3,("%d entries returned in queue\n",count));
}
@@ -3369,7 +3311,7 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
if (!CAN_PRINT(conn)) {
END_PROFILE(SMBsplwr);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
CHECK_FSP(fsp,conn);
@@ -3394,7 +3336,7 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
The guts of the mkdir command, split out so it may be called by the NT SMB
code.
****************************************************************************/
-int mkdir_internal(connection_struct *conn, char *inbuf, char *outbuf, pstring directory)
+NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
{
BOOL bad_path = False;
SMB_STRUCT_STAT sbuf;
@@ -3405,34 +3347,31 @@ int mkdir_internal(connection_struct *conn, char *inbuf, char *outbuf, pstring d
if (check_name(directory, conn))
ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
- if (ret < 0)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
}
- return ret;
+ return NT_STATUS_OK;
}
/****************************************************************************
- Reply to a mkdir
+ Reply to a mkdir.
****************************************************************************/
int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring directory;
int outsize;
+ NTSTATUS status;
START_PROFILE(SMBmkdir);
pstrcpy(directory,smb_buf(inbuf) + 1);
- outsize=mkdir_internal(conn, inbuf, outbuf, directory);
- if(outsize == 0)
- outsize = set_message(outbuf,0,0,True);
+ status = mkdir_internal(conn, directory);
+ if (!NT_STATUS_IS_OK(status))
+ return ERROR_NT(status);
+
+ outsize = set_message(outbuf,0,0,True);
DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
@@ -3600,11 +3539,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (!ok)
{
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ set_bad_path_error(errno, bad_path);
END_PROFILE(SMBrmdir);
return(UNIXERROR(ERRDOS,ERRbadpath));
}
@@ -3683,26 +3618,26 @@ static BOOL resolve_wildcards(char *name1,char *name2)
}
/*******************************************************************
-check if a user is allowed to rename a file
+ Check if a user is allowed to rename a file.
********************************************************************/
-static BOOL can_rename(char *fname,connection_struct *conn)
+
+static NTSTATUS can_rename(char *fname,connection_struct *conn)
{
- SMB_STRUCT_STAT sbuf;
+ if (!CAN_WRITE(conn))
+ return NT_STATUS_ACCESS_DENIED;
- if (!CAN_WRITE(conn)) return(False);
+ if (!check_file_sharing(conn,fname,True))
+ return NT_STATUS_SHARING_VIOLATION;
- if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False);
- if (!check_file_sharing(conn,fname,True)) return(False);
- return(True);
+ return NT_STATUS_OK;
}
/****************************************************************************
The guts of the rename command, split out so it may be called by the NT SMB
code.
****************************************************************************/
-int rename_internals(connection_struct *conn,
- char *inbuf, char *outbuf, char *name,
- char *newname, BOOL replace_if_exists)
+
+NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BOOL replace_if_exists)
{
pstring directory;
pstring mask;
@@ -3712,11 +3647,9 @@ int rename_internals(connection_struct *conn,
BOOL bad_path1 = False;
BOOL bad_path2 = False;
int count=0;
- int error = ERRnoaccess;
- BOOL exists=False;
+ NTSTATUS error = NT_STATUS_OK;
BOOL rc = True;
SMB_STRUCT_STAT sbuf1, sbuf2;
- pstring zdirectory;
*directory = *mask = 0;
@@ -3758,6 +3691,9 @@ int rename_internals(connection_struct *conn,
has_wild = ms_has_wild(mask);
if (!has_wild) {
+ pstring zdirectory;
+ pstring znewname;
+
/*
* No wildcards - just process the one file.
*/
@@ -3776,7 +3712,8 @@ int rename_internals(connection_struct *conn,
pstrcpy(newname, tmpstr);
}
- DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
+ DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
+directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
case_sensitive, case_preserve, short_case_preserve, directory,
newname, newname_last_component, is_short_name));
@@ -3814,37 +3751,82 @@ int rename_internals(connection_struct *conn,
}
}
- pstrcpy(zdirectory, dos_to_unix(directory, False));
- if(replace_if_exists) {
- /*
- * NT SMB specific flag - rename can overwrite
- * file with the same name so don't check for
- * vfs_file_exist().
- */
- if(resolve_wildcards(directory,newname) &&
- can_rename(directory,conn) &&
- !conn->vfs_ops.rename(conn,zdirectory,
- dos_to_unix(newname,False)))
- count++;
- } else {
- if (resolve_wildcards(directory,newname) &&
- can_rename(directory,conn) &&
- !vfs_file_exist(conn,newname,NULL) &&
- !conn->vfs_ops.rename(conn,zdirectory,
- dos_to_unix(newname,False)))
- count++;
+ resolve_wildcards(directory,newname);
+
+ /*
+ * The source object must exist.
+ */
+
+ if (!vfs_object_exist(conn, directory, NULL)) {
+ DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n",
+ directory,newname));
+
+ if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) {
+ /*
+ * Must return different errors depending on whether the parent
+ * directory existed or not.
+ */
+
+ p = strrchr(directory, '/');
+ if (!p)
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ *p = '\0';
+ if (vfs_object_exist(conn, directory, NULL))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+ error = map_nt_error_from_unix(errno);
+ DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+ get_nt_error_msg(error), directory,newname));
+
+ return error;
}
- DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
- directory,newname));
-
- if (!count) exists = vfs_file_exist(conn,directory,NULL);
- if (!count && exists && vfs_file_exist(conn,newname,NULL)) {
- exists = True;
- error = ERRrename;
+ error = can_rename(directory,conn);
+
+ if (!NT_STATUS_IS_OK(error)) {
+ DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+ get_nt_error_msg(error), directory,newname));
+ return error;
}
+
+ pstrcpy(zdirectory, dos_to_unix(directory, False));
+ pstrcpy(znewname, dos_to_unix(newname,False));
+
+ /*
+ * If the src and dest names are identical - including case,
+ * don't do the rename, just return success.
+ */
+
+ if (strcsequal(zdirectory, znewname)) {
+ DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory));
+ return NT_STATUS_OK;
+ }
+
+ if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
+ DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n",
+ directory,newname));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ if(conn->vfs_ops.rename(conn,zdirectory, znewname) == 0) {
+ DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
+ directory,newname));
+ return NT_STATUS_OK;
+ }
+
+ if (errno == ENOTDIR || errno == EISDIR)
+ error = NT_STATUS_OBJECT_NAME_COLLISION;
+ else
+ error = map_nt_error_from_unix(errno);
+
+ DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+ get_nt_error_msg(error), directory,newname));
+
+ return error;
} else {
+
/*
* Wildcards - process each file that matches.
*/
@@ -3856,7 +3838,7 @@ int rename_internals(connection_struct *conn,
dirptr = OpenDir(conn, directory, True);
if (dirptr) {
- error = ERRbadfile;
+ error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
if (strequal(mask,"????????.???"))
pstrcpy(mask,"*");
@@ -3869,10 +3851,11 @@ int rename_internals(connection_struct *conn,
if(!mask_match(fname, mask, case_sensitive))
continue;
- error = ERRnoaccess;
+ error = NT_STATUS_ACCESS_DENIED;
slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
- if (!can_rename(fname,conn)) {
- DEBUG(6,("rename %s refused\n", fname));
+ error = can_rename(fname,conn);
+ if (!NT_STATUS_IS_OK(error)) {
+ DEBUG(6,("rename %s failed. Error %s\n", fname, get_nt_error_msg(error)));
continue;
}
pstrcpy(destname,newname);
@@ -3884,9 +3867,9 @@ int rename_internals(connection_struct *conn,
}
if (!replace_if_exists &&
- vfs_file_exist(conn,destname, NULL)) {
+ vfs_object_exist(conn,destname, NULL)) {
DEBUG(6,("file_exist %s\n", destname));
- error = 183;
+ error = NT_STATUS_OBJECT_NAME_COLLISION;
continue;
}
@@ -3898,20 +3881,12 @@ int rename_internals(connection_struct *conn,
CloseDir(dirptr);
}
}
-
- if (count == 0) {
- if (exists)
- return(ERROR(ERRDOS,error));
- else {
- if((errno == ENOENT) && (bad_path1 || bad_path2)) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,error));
- }
+
+ if (count == 0 && NT_STATUS_IS_OK(error)) {
+ error = map_nt_error_from_unix(errno);
}
- return 0;
+ return error;
}
/****************************************************************************
@@ -3920,34 +3895,34 @@ int rename_internals(connection_struct *conn,
int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int outsize = 0;
- pstring name;
- pstring newname;
- START_PROFILE(SMBmv);
+ int outsize = 0;
+ pstring name;
+ pstring newname;
+ NTSTATUS status;
+ START_PROFILE(SMBmv);
- pstrcpy(name,smb_buf(inbuf) + 1);
- pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
+ pstrcpy(name,smb_buf(inbuf) + 1);
+ pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
- RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
- RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
- DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
+ DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
- outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
- if(outsize == 0) {
+ status = rename_internals(conn, name, newname, False);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
/*
- * Win2k needs a changenotify request response before it will
- * update after a rename..
- */
-
- process_pending_change_notify_queue((time_t)0);
-
- outsize = set_message(outbuf,0,0,True);
- }
+ * Win2k needs a changenotify request response before it will
+ * update after a rename..
+ */
+ process_pending_change_notify_queue((time_t)0);
+ outsize = set_message(outbuf,0,0,True);
- END_PROFILE(SMBmv);
- return(outsize);
+ END_PROFILE(SMBmv);
+ return(outsize);
}
/*******************************************************************
@@ -4014,6 +3989,10 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
close_file(fsp1,False);
+
+ /* Ensure the modtime is set correctly on the destination file. */
+ fsp2->pending_modtime = src_sbuf.st_mtime;
+
/*
* As we are opening fsp1 read-only we only expect
* an error on close on fsp2 if we are out of space.
@@ -4063,7 +4042,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
/* can't currently handle inter share copies XXXX */
DEBUG(3,("Rejecting inter-share copy\n"));
END_PROFILE(SMBcopy);
- return(ERROR(ERRSRV,ERRinvdevice));
+ return ERROR_DOS(ERRSRV,ERRinvdevice);
}
RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
@@ -4076,19 +4055,19 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if ((flags&1) && target_is_directory) {
END_PROFILE(SMBcopy);
- return(ERROR(ERRDOS,ERRbadfile));
+ return ERROR_DOS(ERRDOS,ERRbadfile);
}
if ((flags&2) && !target_is_directory) {
END_PROFILE(SMBcopy);
- return(ERROR(ERRDOS,ERRbadpath));
+ return ERROR_DOS(ERRDOS,ERRbadpath);
}
if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
/* wants a tree copy! XXXX */
DEBUG(3,("Rejecting tree copy\n"));
END_PROFILE(SMBcopy);
- return(ERROR(ERRSRV,ERRerror));
+ return ERROR_DOS(ERRSRV,ERRerror);
}
p = strrchr(name,'/');
@@ -4170,7 +4149,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (exists) {
END_PROFILE(SMBcopy);
- return(ERROR(ERRDOS,error));
+ return ERROR_DOS(ERRDOS,error);
} else
{
if((errno == ENOENT) && (bad_path1 || bad_path2))
@@ -4204,7 +4183,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
snum = SNUM(conn);
if (!CAN_SETDIR(snum)) {
END_PROFILE(pathworks_setdir);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
pstrcpy(newdir,smb_buf(inbuf) + 1);
@@ -4221,11 +4200,11 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if (!ok) {
END_PROFILE(pathworks_setdir);
- return(ERROR(ERRDOS,ERRbadpath));
+ return ERROR_DOS(ERRDOS,ERRbadpath);
}
outsize = set_message(outbuf,0,0,True);
- CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
+ SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh));
DEBUG(3,("setdir %s\n", newdir));
@@ -4242,7 +4221,7 @@ uint16 get_lock_pid( char *data, int data_offset, BOOL large_file_format)
if(!large_file_format)
return SVAL(data,SMB_LPID_OFFSET(data_offset));
else
- return SVAL(data,SMB_LARGE__LPID_OFFSET(data_offset));
+ return SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
}
/****************************************************************************
@@ -4382,10 +4361,10 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
int32 lock_timeout = IVAL(inbuf,smb_vwv4);
int i;
char *data;
- uint32 ecode=0, dummy2;
- int eclass=0, dummy1;
BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
BOOL err;
+ NTSTATUS status;
+
START_PROFILE(SMBlockingX);
CHECK_FSP(fsp,conn);
@@ -4395,8 +4374,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
/* Check if this is an oplock break on a file
we have granted an oplock on.
*/
- if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
- {
+ if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
/* Client can insist on breaking to none. */
BOOL break_to_none = (oplocklevel == 0);
@@ -4407,18 +4385,17 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
* Make sure we have granted an exclusive or batch oplock on this file.
*/
- if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
- {
+ if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
/* if this is a pure oplock break request then don't send a reply */
if (num_locks == 0 && num_ulocks == 0) {
- END_PROFILE(SMBlockingX);
+ END_PROFILE(SMBlockingX);
return -1;
} else {
- END_PROFILE(SMBlockingX);
- return ERROR(ERRDOS,ERRlock);
+ END_PROFILE(SMBlockingX);
+ return ERROR_DOS(ERRDOS,ERRlock);
}
}
@@ -4428,8 +4405,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
}
/* if this is a pure oplock break request then don't send a reply */
- if (num_locks == 0 && num_ulocks == 0)
- {
+ if (num_locks == 0 && num_ulocks == 0) {
/* Sanity check - ensure a pure oplock break is not a
chained request. */
if(CVAL(inbuf,smb_vwv0) != 0xff)
@@ -4459,15 +4435,16 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
*/
if(err) {
END_PROFILE(SMBlockingX);
- return ERROR(ERRDOS,ERRnoaccess);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n",
(double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
- if(!do_unlock(fsp,conn,lock_pid,count,offset, &eclass, &ecode)) {
+ status = do_unlock(fsp,conn,lock_pid,count,offset);
+ if (NT_STATUS_V(status)) {
END_PROFILE(SMBlockingX);
- return ERROR(eclass,ecode);
+ return ERROR_NT(status);
}
}
@@ -4490,15 +4467,16 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
*/
if(err) {
END_PROFILE(SMBlockingX);
- return ERROR(ERRDOS,ERRnoaccess);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n",
(double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
- if(!do_lock(fsp,conn,lock_pid, count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
- &eclass, &ecode)) {
- if((ecode == ERRlock) && (lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
+ status = do_lock(fsp,conn,lock_pid, count,offset,
+ ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
+ if (NT_STATUS_V(status)) {
+ if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
/*
* A blocking lock was requested. Package up
* this smb into a queued request and push it
@@ -4531,13 +4509,13 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
*/
if(err) {
END_PROFILE(SMBlockingX);
- return ERROR(ERRDOS,ERRnoaccess);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
- do_unlock(fsp,conn,lock_pid,count,offset,&dummy1,&dummy2);
+ do_unlock(fsp,conn,lock_pid,count,offset);
}
END_PROFILE(SMBlockingX);
- return ERROR(eclass,ecode);
+ return ERROR_NT(status);
}
set_message(outbuf,2,0,True);
@@ -4549,8 +4527,86 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
return chain_reply(inbuf,outbuf,length,bufsize);
}
+/* Back from the dead for OS/2..... JRA. */
+
/****************************************************************************
- reply to a SMBsetattrE
+ Reply to a SMBreadbmpx (read block multiplex) request
+****************************************************************************/
+
+int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+{
+ ssize_t nread = -1;
+ ssize_t total_read;
+ char *data;
+ SMB_OFF_T startpos;
+ int outsize;
+ size_t maxcount;
+ int max_per_packet;
+ size_t tcount;
+ int pad;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBreadBmpx);
+
+ /* this function doesn't seem to work - disable by default */
+ if (!lp_readbmpx()) {
+ END_PROFILE(SMBreadBmpx);
+ return ERROR_DOS(ERRSRV,ERRuseSTD);
+ }
+
+ outsize = set_message(outbuf,8,0,True);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
+
+ startpos = IVAL(inbuf,smb_vwv1);
+ maxcount = SVAL(inbuf,smb_vwv3);
+
+ data = smb_buf(outbuf);
+ pad = ((long)data)%4;
+ if (pad)
+ pad = 4 - pad;
+ data += pad;
+
+ max_per_packet = bufsize-(outsize+pad);
+ tcount = maxcount;
+ total_read = 0;
+
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK, False)) {
+ END_PROFILE(SMBreadBmpx);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
+
+ do {
+ size_t N = MIN(max_per_packet,tcount-total_read);
+
+ nread = read_file(fsp,data,startpos,N);
+
+ if (nread <= 0)
+ nread = 0;
+
+ if (nread < (ssize_t)N)
+ tcount = total_read + nread;
+
+ set_message(outbuf,8,nread,False);
+ SIVAL(outbuf,smb_vwv0,startpos);
+ SSVAL(outbuf,smb_vwv2,tcount);
+ SSVAL(outbuf,smb_vwv6,nread);
+ SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
+
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("reply_readbmpx: send_smb failed.");
+
+ total_read += nread;
+ startpos += nread;
+ } while (total_read < (ssize_t)tcount);
+
+ END_PROFILE(SMBreadBmpx);
+ return(-1);
+}
+
+/****************************************************************************
+ Reply to a SMBsetattrE.
****************************************************************************/
int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
@@ -4595,7 +4651,7 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
/* Set the date on this file */
if(file_utime(conn, fsp->fsp_name, &unix_times)) {
END_PROFILE(SMBsetattrE);
- return(ERROR(ERRDOS,ERRnoaccess));
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
@@ -4606,8 +4662,199 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
}
+/* Back from the dead for OS/2..... JRA. */
+
+/****************************************************************************
+ Reply to a SMBwritebmpx (write block multiplex primary) request.
+****************************************************************************/
+
+int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+{
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
+ char *data;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBwriteBmpx);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ tcount = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv3);
+ write_through = BITSETW(inbuf+smb_vwv7,0);
+ numtowrite = SVAL(inbuf,smb_vwv10);
+ smb_doff = SVAL(inbuf,smb_vwv11);
+
+ data = smb_base(inbuf) + smb_doff;
+
+ /* If this fails we need to send an SMBwriteC response,
+ 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,False)) {
+ END_PROFILE(SMBwriteBmpx);
+ return(ERROR_DOS(ERRDOS,ERRlock));
+ }
+
+ nwritten = write_file(fsp,data,startpos,numtowrite);
+
+ if(lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
+
+ if(nwritten < (ssize_t)numtowrite) {
+ END_PROFILE(SMBwriteBmpx);
+ return(UNIXERROR(ERRHRD,ERRdiskfull));
+ }
+
+ /* If the maximum to be written to this file
+ is greater than what we just wrote then set
+ up a secondary struct to be attached to this
+ fd, we will use this to cache error messages etc. */
+
+ if((ssize_t)tcount > nwritten) {
+ write_bmpx_struct *wbms;
+ if(fsp->wbmpx_ptr != NULL)
+ wbms = fsp->wbmpx_ptr; /* Use an existing struct */
+ else
+ wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
+
+ if(!wbms) {
+ DEBUG(0,("Out of memory in reply_readmpx\n"));
+ END_PROFILE(SMBwriteBmpx);
+ return(ERROR_DOS(ERRSRV,ERRnoresource));
+ }
+ wbms->wr_mode = write_through;
+ wbms->wr_discard = False; /* No errors yet */
+ wbms->wr_total_written = nwritten;
+ wbms->wr_errclass = 0;
+ wbms->wr_error = 0;
+ fsp->wbmpx_ptr = wbms;
+ }
+
+ /* We are returning successfully, set the message type back to
+ SMBwritebmpx */
+ SCVAL(outbuf,smb_com,SMBwriteBmpx);
+
+ outsize = set_message(outbuf,1,0,True);
+
+ SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
+
+ DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten ) );
+
+ if (write_through && tcount==nwritten) {
+ /* We need to send both a primary and a secondary response */
+ smb_setlen(outbuf,outsize - 4);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("reply_writebmpx: send_smb failed.");
+
+ /* Now the secondary */
+ outsize = set_message(outbuf,1,0,True);
+ SCVAL(outbuf,smb_com,SMBwritec);
+ SSVAL(outbuf,smb_vwv0,nwritten);
+ }
+
+ END_PROFILE(SMBwriteBmpx);
+ return(outsize);
+}
+
+/****************************************************************************
+ Reply to a SMBwritebs (write block multiplex secondary) request.
+****************************************************************************/
+
+int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+{
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
+ char *data;
+ write_bmpx_struct *wbms;
+ BOOL send_response = False;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBwriteBs);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+
+ tcount = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+ numtowrite = SVAL(inbuf,smb_vwv6);
+ smb_doff = SVAL(inbuf,smb_vwv7);
+
+ data = smb_base(inbuf) + smb_doff;
+
+ /* We need to send an SMBwriteC response, not an SMBwritebs */
+ SCVAL(outbuf,smb_com,SMBwritec);
+
+ /* This fd should have an auxiliary struct attached,
+ check that it does */
+ wbms = fsp->wbmpx_ptr;
+ if(!wbms) {
+ END_PROFILE(SMBwriteBs);
+ return(-1);
+ }
+
+ /* If write through is set we can return errors, else we must cache them */
+ write_through = wbms->wr_mode;
+
+ /* Check for an earlier error */
+ if(wbms->wr_discard) {
+ END_PROFILE(SMBwriteBs);
+ return -1; /* Just discard the packet */
+ }
+
+ nwritten = write_file(fsp,data,startpos,numtowrite);
+
+ if(lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
+
+ if (nwritten < (ssize_t)numtowrite) {
+ if(write_through) {
+ /* We are returning an error - we can delete the aux struct */
+ SAFE_FREE(wbms);
+ fsp->wbmpx_ptr = NULL;
+ END_PROFILE(SMBwriteBs);
+ return(ERROR_DOS(ERRHRD,ERRdiskfull));
+ }
+ END_PROFILE(SMBwriteBs);
+ return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
+ }
+
+ /* Increment the total written, if this matches tcount
+ we can discard the auxiliary struct (hurrah !) and return a writeC */
+ wbms->wr_total_written += nwritten;
+ if(wbms->wr_total_written >= tcount) {
+ if (write_through) {
+ outsize = set_message(outbuf,1,0,True);
+ SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);
+ send_response = True;
+ }
+
+ SAFE_FREE(wbms);
+ fsp->wbmpx_ptr = NULL;
+ }
+
+ if(send_response) {
+ END_PROFILE(SMBwriteBs);
+ return(outsize);
+ }
+
+ END_PROFILE(SMBwriteBs);
+ return(-1);
+}
+
/****************************************************************************
- reply to a SMBgetattrE
+ Reply to a SMBgetattrE.
****************************************************************************/
int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
diff --git a/source/smbd/sec_ctx.c b/source/smbd/sec_ctx.c
index 03f307164d9..9a61a76f6fe 100644
--- a/source/smbd/sec_ctx.c
+++ b/source/smbd/sec_ctx.c
@@ -21,7 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
extern struct current_user current_user;
struct sec_ctx {
@@ -60,10 +59,8 @@ static BOOL become_uid(uid_t uid)
/* Set effective user id */
set_effective_uid(uid);
- current_user.uid = uid;
DO_PROFILE_INC(uid_changes);
-
return True;
}
@@ -89,8 +86,6 @@ static BOOL become_gid(gid_t gid)
/* Set effective group id */
set_effective_gid(gid);
- current_user.gid = gid;
-
return True;
}
@@ -157,14 +152,14 @@ int get_current_groups(int *p_ngroups, gid_t **p_groups)
}
if ((ngroups = sys_getgroups(ngroups,groups)) == -1) {
- safe_free(groups);
+ SAFE_FREE(groups);
return -1;
}
(*p_ngroups) = ngroups;
(*p_groups) = groups;
- DEBUG( 3, ( "get_current_groups: uid %u is in %u groups: ", (unsigned int)getuid() , ngroups ) );
+ DEBUG( 3, ( "get_current_groups: user is in %u groups: ", ngroups ) );
for (i = 0; i < ngroups; i++ ) {
DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
}
@@ -181,11 +176,10 @@ void delete_nt_token(NT_USER_TOKEN **pptoken)
{
if (*pptoken) {
NT_USER_TOKEN *ptoken = *pptoken;
- safe_free( ptoken->user_sids );
+ SAFE_FREE( ptoken->user_sids );
ZERO_STRUCTP(ptoken);
}
- safe_free(*pptoken);
- *pptoken = NULL;
+ SAFE_FREE(*pptoken);
}
/****************************************************************************
@@ -205,7 +199,7 @@ NT_USER_TOKEN *dup_nt_token(NT_USER_TOKEN *ptoken)
ZERO_STRUCTP(token);
if ((token->user_sids = (DOM_SID *)memdup( ptoken->user_sids, sizeof(DOM_SID) * ptoken->num_sids )) == NULL) {
- free(token);
+ SAFE_FREE(token);
return NULL;
}
@@ -248,8 +242,7 @@ BOOL initialise_groups(char *user, uid_t uid, gid_t gid)
prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx - 1];
- safe_free(prev_ctx_p->groups);
- prev_ctx_p->groups = NULL;
+ SAFE_FREE(prev_ctx_p->groups);
prev_ctx_p->ngroups = 0;
get_current_groups(&prev_ctx_p->ngroups, &prev_ctx_p->groups);
@@ -340,7 +333,7 @@ void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN
ctx_p->ngroups = ngroups;
- safe_free(ctx_p->groups);
+ SAFE_FREE(ctx_p->groups);
if (token && (token == ctx_p->token))
smb_panic("DUPLICATE_TOKEN");
@@ -397,7 +390,7 @@ BOOL pop_sec_ctx(void)
ctx_p->uid = (uid_t)-1;
ctx_p->gid = (gid_t)-1;
- safe_free(ctx_p->groups);
+ SAFE_FREE(ctx_p->groups);
ctx_p->ngroups = 0;
delete_nt_token(&ctx_p->token);
diff --git a/source/smbd/server.c b/source/smbd/server.c
index a8bccc548d9..b3b428a9b42 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -22,7 +22,6 @@
#include "includes.h"
pstring servicesf = CONFIGFILE;
-extern pstring debugf;
extern fstring global_myworkgroup;
extern pstring global_myname;
@@ -34,8 +33,6 @@ int last_message = -1;
/* a useful macro to debug the last message processed */
#define LAST_MESSAGE() smb_fn_name(last_message)
-extern int DEBUGLEVEL;
-
extern pstring user_socket_options;
#ifdef WITH_DFS
@@ -104,7 +101,7 @@ static BOOL open_sockets_inetd(void)
/****************************************************************************
open the socket communication
****************************************************************************/
-static BOOL open_sockets(BOOL is_daemon,int port)
+static BOOL open_sockets(BOOL is_daemon,BOOL interactive, int port)
{
int num_interfaces = iface_count();
int fd_listenset[FD_SETSIZE];
@@ -212,14 +209,14 @@ max can be %d\n",
memcpy((char *)&lfds, (char *)&listen_set,
sizeof(listen_set));
- num = sys_select(FD_SETSIZE,&lfds,NULL);
+ num = sys_select(FD_SETSIZE,&lfds,NULL,NULL,NULL);
if (num == -1 && errno == EINTR) {
extern VOLATILE sig_atomic_t reload_after_sighup;
/* check for sighup processing */
if (reload_after_sighup) {
- unbecome_user();
+ change_to_root_user();
DEBUG(1,("Reloading services after SIGHUP\n"));
reload_services(False);
reload_after_sighup = False;
@@ -258,7 +255,10 @@ max can be %d\n",
strerror(errno)));
continue;
}
-
+
+ if (smbd_server_fd() != -1 && interactive)
+ return True;
+
if (smbd_server_fd() != -1 && sys_fork()==0) {
/* Child code ... */
@@ -365,7 +365,7 @@ BOOL reload_services(BOOL test)
reset_stat_cache();
/* this forces service parameters to be flushed */
- become_service(NULL,True);
+ set_current_service(NULL,True);
return(ret);
}
@@ -398,7 +398,7 @@ static BOOL dump_core(void)
{
char *p;
pstring dname;
- pstrcpy(dname,debugf);
+ pstrcpy(dname,lp_logfile());
if ((p=strrchr(dname,'/'))) *p=0;
pstrcat(dname,"/corefiles");
mkdir(dname,0700);
@@ -434,11 +434,11 @@ update the current smbd process count
static void decrement_smbd_process_count(void)
{
- int total_smbds;
+ int32 total_smbds;
if (lp_max_smbd_processes()) {
total_smbds = 0;
- tdb_change_int_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, -1);
+ tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, -1);
}
}
@@ -454,7 +454,7 @@ void exit_server(char *reason)
if (!firsttime) exit(0);
firsttime = 0;
- unbecome_user();
+ change_to_root_user();
DEBUG(2,("Closing connections\n"));
conn_close_all();
@@ -462,9 +462,8 @@ void exit_server(char *reason)
invalidate_all_vuids();
/* delete our entry in the connections database. */
- if (lp_status(-1)) {
- yield_connection(NULL,"",MAXSTATUS);
- }
+ if (lp_status(-1))
+ yield_connection(NULL,"");
respond_to_all_remaining_local_messages();
decrement_smbd_process_count();
@@ -532,10 +531,11 @@ usage on the program
static void usage(char *pname)
{
- printf("Usage: %s [-DaoPh?V] [-d debuglevel] [-l log basename] [-p port]\n", pname);
+ printf("Usage: %s [-DaioPh?V] [-d debuglevel] [-l log basename] [-p port]\n", pname);
printf(" [-O socket options] [-s services file]\n");
- printf("\t-D Become a daemon\n");
+ printf("\t-D Become a daemon (default)\n");
printf("\t-a Append to log file (default)\n");
+ printf("\t-i Run interactive (not a daemon)\n");
printf("\t-o Overwrite log file, don't append\n");
printf("\t-h Print usage\n");
printf("\t-? Print usage\n");
@@ -557,10 +557,12 @@ static void usage(char *pname)
extern BOOL append_log;
/* shall I run as a daemon */
BOOL is_daemon = False;
+ BOOL interactive = False;
BOOL specified_logfile = False;
int port = SMB_PORT;
int opt;
extern char *optarg;
+ pstring logfile;
#ifdef HAVE_SET_AUTH_PARAMETERS
set_auth_parameters(argc,argv);
@@ -572,7 +574,7 @@ static void usage(char *pname)
argc--;
}
- while ( EOF != (opt = getopt(argc, argv, "O:l:s:d:Dp:h?Vaof:")) )
+ while ( EOF != (opt = getopt(argc, argv, "O:l:s:d:Dip:h?Vaof:")) )
switch (opt) {
case 'O':
pstrcpy(user_socket_options,optarg);
@@ -584,7 +586,8 @@ static void usage(char *pname)
case 'l':
specified_logfile = True;
- slprintf(debugf, sizeof(debugf)-1, "%s/log.smbd", optarg);
+ slprintf(logfile, sizeof(logfile)-1, "%s/log.smbd", optarg);
+ lp_set_logfile(logfile);
break;
case 'a':
@@ -599,6 +602,10 @@ static void usage(char *pname)
is_daemon = True;
break;
+ case 'i':
+ interactive = True;
+ break;
+
case 'd':
if (*optarg == 'A')
DEBUGLEVEL = 10000;
@@ -638,12 +645,13 @@ static void usage(char *pname)
TimeInit();
if(!specified_logfile) {
- slprintf(debugf, sizeof(debugf)-1, "%s/log.smbd", LOGFILEBASE);
+ slprintf(logfile, sizeof(logfile)-1, "%s/log.smbd", LOGFILEBASE);
+ lp_set_logfile(logfile);
}
pstrcpy(remote_machine, "smbd");
- setup_logging(argv[0],False);
+ setup_logging(argv[0],interactive);
charset_initialise();
@@ -683,11 +691,12 @@ static void usage(char *pname)
umask(0);
init_sec_ctx();
+ init_conn_ctx();
reopen_logs();
- DEBUG(1,( "smbd version %s started.\n", VERSION));
- DEBUGADD(1,( "Copyright Andrew Tridgell 1992-1998\n"));
+ DEBUG(0,( "smbd version %s started.\n", VERSION));
+ DEBUGADD(0,( "Copyright Andrew Tridgell and the Samba Team 1992-2002\n"));
DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
(int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
@@ -731,59 +740,66 @@ static void usage(char *pname)
DEBUG(3,( "loaded services\n"));
if (!is_daemon && !is_a_socket(0)) {
- DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ if (!interactive)
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+
+ /*
+ * Setting is_daemon here prevents us from eventually calling
+ * the open_sockets_inetd()
+ */
+
is_daemon = True;
}
- if (is_daemon) {
+ if (is_daemon && !interactive) {
DEBUG( 3, ( "Becoming a daemon.\n" ) );
become_daemon();
}
- if (!directory_exist(lp_lockdir(), NULL)) {
+#if HAVE_SETPGID
+ /*
+ * If we're interactive we want to set our own process group for
+ * signal management.
+ */
+ if (interactive)
+ setpgid( (pid_t)0, (pid_t)0);
+#endif
+
+ if (!directory_exist(lp_lockdir(), NULL))
mkdir(lp_lockdir(), 0755);
- }
- if (is_daemon) {
+ if (is_daemon)
pidfile_create("smbd");
- }
- if (!message_init()) {
+ if (!message_init())
exit(1);
- }
/* Setup the main smbd so that we can get messages. */
- if (lp_status(-1)) {
- claim_connection(NULL,"",MAXSTATUS,True);
- }
+ if (lp_status(-1))
+ claim_connection(NULL,"",0,True);
/* Attempt to migrate from an old 2.0.x machine account file. */
- if (!migrate_from_old_password_file(global_myworkgroup)) {
+ if (!migrate_from_old_password_file(global_myworkgroup))
DEBUG(0,("Failed to migrate from old MAC file.\n"));
- }
- if (!open_sockets(is_daemon,port))
+ if (!open_sockets(is_daemon,interactive,port))
exit(1);
/*
- * everything after this point is run after the fork()
+ * Everything after this point is run after the fork().
*/
- if (!locking_init(0)) {
+ if (!locking_init(0))
exit(1);
- }
- if (!print_backend_init()) {
+ if (!print_backend_init())
exit(1);
- }
- if (!share_info_db_init()) {
+ if (!share_info_db_init())
exit(1);
- }
- if(!initialize_password_db(False)) {
+ if(!initialize_password_db(False))
exit(1);
- }
/* possibly reload the services file. */
reload_services(True);
@@ -799,14 +815,12 @@ static void usage(char *pname)
}
/* Setup oplocks */
- if (!init_oplocks()) {
+ if (!init_oplocks())
exit(1);
- }
/* Setup change notify */
- if (!init_change_notify()) {
+ if (!init_change_notify())
exit(1);
- }
smbd_process();
diff --git a/source/smbd/service.c b/source/smbd/service.c
index ffbdefbecb7..515bcc5c792 100644
--- a/source/smbd/service.c
+++ b/source/smbd/service.c
@@ -21,8 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
extern struct timeval smb_last_time;
extern int case_default;
extern BOOL case_preserve;
@@ -36,9 +34,10 @@ extern fstring remote_machine;
/****************************************************************************
-load parameters specific to a connection/service
+ Load parameters specific to a connection/service.
****************************************************************************/
-BOOL become_service(connection_struct *conn,BOOL do_chdir)
+
+BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
{
extern char magic_char;
static connection_struct *last_conn;
@@ -126,7 +125,7 @@ int find_service(char *service)
/* now handle the special case of a home directory */
if (iService < 0)
{
- char *phome_dir = get_user_home_dir(service);
+ char *phome_dir = get_user_service_home_dir(service);
if(!phome_dir)
{
@@ -135,7 +134,7 @@ int find_service(char *service)
* be a Windows to unix mapped user name.
*/
if(map_username(service))
- phome_dir = get_user_home_dir(service);
+ phome_dir = get_user_service_home_dir(service);
}
DEBUG(3,("checking for home directory %s gave %s\n",service,
@@ -214,8 +213,11 @@ int find_service(char *service)
/****************************************************************************
- make a connection to a service
+ Make a connection to a service. This function is designed to be called
+ AS ROOT and will return to being root on exit ! Modified current_user conn
+ and vuid elements.
****************************************************************************/
+
connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode)
{
int snum;
@@ -223,8 +225,16 @@ connection_struct *make_connection(char *service,char *user,char *password, int
BOOL guest = False;
BOOL force = False;
connection_struct *conn;
+ uid_t euid;
int ret;
+ /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
+
+ if (!non_root_mode() && ((euid = geteuid()) != 0)) {
+ DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
+ smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
+ }
+
strlower(service);
snum = find_service(service);
@@ -320,6 +330,8 @@ connection_struct *make_connection(char *service,char *user,char *password, int
return NULL;
}
+ add_session_user(user);
+
conn = conn_new();
if (!conn) {
DEBUG(0,("Couldn't find free connection.\n"));
@@ -339,7 +351,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int
conn->read_only = lp_readonly(snum);
-
{
pstring list;
StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1);
@@ -482,7 +493,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
conn->groups = NULL;
/* Find all the groups this uid is in and
- store them. Used by become_user() */
+ store them. Used by change_to_user() */
initialise_groups(conn->user, conn->uid, conn->gid);
get_current_groups(&conn->ngroups,&conn->groups);
@@ -499,7 +510,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
conn->ngroups, conn->groups,
- guest);
+ guest, NULL);
/*
* New code to check if there's a share security descripter
@@ -516,7 +527,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
*ecode = ERRaccess;
DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
service ));
- yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
+ yield_connection(conn, lp_servicename(SNUM(conn)));
conn_free(conn);
return NULL;
} else {
@@ -528,7 +539,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
if (!vfs_init(conn)) {
DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
- yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
+ yield_connection(conn, lp_servicename(SNUM(conn)));
conn_free(conn);
return NULL;
}
@@ -542,31 +553,42 @@ connection_struct *make_connection(char *service,char *user,char *password, int
ret = smbrun(cmd,NULL);
if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
DEBUG(1,("preexec gave %d - failing connection\n", ret));
- yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
+ yield_connection(conn, lp_servicename(SNUM(conn)));
conn_free(conn);
*ecode = ERRsrverror;
return NULL;
}
}
- if (!become_user(conn, conn->vuid)) {
+ if (!change_to_user(conn, conn->vuid)) {
DEBUG(0,("Can't become connected user!\n"));
- yield_connection(conn,
- lp_servicename(SNUM(conn)),
- lp_max_connections(SNUM(conn)));
+ yield_connection(conn, lp_servicename(SNUM(conn)));
conn_free(conn);
*ecode = ERRbadpw;
return NULL;
}
+ /* execute any "preexec = " line */
+ if (*lp_preexec(SNUM(conn))) {
+ pstring cmd;
+ pstrcpy(cmd,lp_preexec(SNUM(conn)));
+ standard_sub_conn(conn,cmd);
+ ret = smbrun(cmd,NULL);
+ if (ret != 0 && lp_preexec_close(SNUM(conn))) {
+ DEBUG(1,("preexec gave %d - failing connection\n", ret));
+ yield_connection(conn, lp_servicename(SNUM(conn)));
+ conn_free(conn);
+ *ecode = ERRsrverror;
+ return NULL;
+ }
+ }
+
if (vfs_ChDir(conn,conn->connectpath) != 0) {
DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
remote_machine, conn->client_address,
conn->connectpath,strerror(errno)));
- unbecome_user();
- yield_connection(conn,
- lp_servicename(SNUM(conn)),
- lp_max_connections(SNUM(conn)));
+ change_to_root_user();
+ yield_connection(conn, lp_servicename(SNUM(conn)));
conn_free(conn);
*ecode = ERRnosuchshare;
return NULL;
@@ -585,23 +607,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int
}
#endif
- add_session_user(user);
-
- /* execute any "preexec = " line */
- if (*lp_preexec(SNUM(conn))) {
- pstring cmd;
- pstrcpy(cmd,lp_preexec(SNUM(conn)));
- standard_sub_conn(conn,cmd);
- ret = smbrun(cmd,NULL);
- if (ret != 0 && lp_preexec_close(SNUM(conn))) {
- DEBUG(1,("preexec gave %d - failing connection\n", ret));
- yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
- conn_free(conn);
- *ecode = ERRsrverror;
- return NULL;
- }
- }
-
/*
* Print out the 'connected as' stuff here as we need
* to know the effective uid and gid we will be using.
@@ -616,7 +621,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
}
/* we've finished with the sensitive stuff */
- unbecome_user();
+ change_to_root_user();
/* Add veto/hide lists */
if (!IS_IPC(conn) && !IS_PRINT(conn)) {
@@ -635,15 +640,15 @@ connection_struct *make_connection(char *service,char *user,char *password, int
return(conn);
}
-
/****************************************************************************
-close a cnum
+ Close a cnum
****************************************************************************/
+
void close_cnum(connection_struct *conn, uint16 vuid)
{
DirCacheFlush(SNUM(conn));
- unbecome_user();
+ change_to_root_user();
DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
remote_machine,conn->client_address,
@@ -657,24 +662,21 @@ void close_cnum(connection_struct *conn, uint16 vuid)
}
- yield_connection(conn,
- lp_servicename(SNUM(conn)),
- lp_max_connections(SNUM(conn)));
+ yield_connection(conn, lp_servicename(SNUM(conn)));
file_close_conn(conn);
dptr_closecnum(conn);
/* execute any "postexec = " line */
if (*lp_postexec(SNUM(conn)) &&
- become_user(conn, vuid)) {
+ change_to_user(conn, vuid)) {
pstring cmd;
pstrcpy(cmd,lp_postexec(SNUM(conn)));
standard_sub_conn(conn,cmd);
smbrun(cmd,NULL);
- unbecome_user();
}
- unbecome_user();
+ change_to_root_user();
/* execute any "root postexec = " line */
if (*lp_rootpostexec(SNUM(conn))) {
pstring cmd;
diff --git a/source/smbd/session.c b/source/smbd/session.c
index bf21677f566..7f057256cac 100644
--- a/source/smbd/session.c
+++ b/source/smbd/session.c
@@ -89,9 +89,12 @@ BOOL session_claim(uint16 vuid)
return False;
}
- hostname = client_name();
- if (strequal(hostname,"UNKNOWN"))
- hostname = client_addr();
+ /* Don't resolve the hostname in smbd as we can pause for a long
+ time while waiting for DNS timeouts to occur. The correct
+ place to do this is in the code that displays the session
+ information. */
+
+ hostname = client_addr();
fstrcpy(sessionid.username, vuser->user.unix_name);
fstrcpy(sessionid.hostname, hostname);
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 89515f6351e..bfa304605f6 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -2,9 +2,8 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB transaction2 handling
- Copyright (C) Jeremy Allison 1994-1998
-
Extensively modified by Andrew Tridgell, 1995
+ Copyright (C) Jeremy Allison 1994-2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,7 +22,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
extern int Protocol;
extern BOOL case_sensitive;
extern int smb_read_error;
@@ -38,275 +36,390 @@ extern pstring global_myname;
set correctly for the type of call.
HACK ! Always assumes smb_setup field is zero.
****************************************************************************/
-static int send_trans2_replies(char *outbuf, int bufsize, char *params,
- int paramsize, char *pdata, int datasize)
+
+static int send_trans2_replies(char *outbuf, int bufsize, char *params, int paramsize, char *pdata, int datasize)
{
- /* As we are using a protocol > LANMAN1 then the max_send
- variable must have been set in the sessetupX call.
- This takes precedence over the max_xmit field in the
- global struct. These different max_xmit variables should
- be merged as this is now too confusing */
-
- extern int max_send;
- int data_to_send = datasize;
- int params_to_send = paramsize;
- int useable_space;
- char *pp = params;
- char *pd = pdata;
- int params_sent_thistime, data_sent_thistime, total_sent_thistime;
- int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
- int data_alignment_offset = 0;
-
- /* Initially set the wcnt area to be 10 - this is true for all
- trans2 replies */
- set_message(outbuf,10,0,True);
-
- /* If there genuinely are no parameters or data to send just send
- the empty packet */
- if(params_to_send == 0 && data_to_send == 0)
- {
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("send_trans2_replies: send_smb failed.\n");
- return 0;
- }
-
- /* When sending params and data ensure that both are nicely aligned */
- /* Only do this alignment when there is also data to send - else
- can cause NT redirector problems. */
- if (((params_to_send % 4) != 0) && (data_to_send != 0))
- data_alignment_offset = 4 - (params_to_send % 4);
-
- /* Space is bufsize minus Netbios over TCP header minus SMB header */
- /* The alignment_offset is to align the param bytes on an even byte
- boundary. NT 4.0 Beta needs this to work correctly. */
- useable_space = bufsize - ((smb_buf(outbuf)+
- alignment_offset+data_alignment_offset) -
- outbuf);
-
- /* useable_space can never be more than max_send minus the
- alignment offset. */
- useable_space = MIN(useable_space,
- max_send - (alignment_offset+data_alignment_offset));
-
-
- while (params_to_send || data_to_send)
- {
- /* Calculate whether we will totally or partially fill this packet */
- total_sent_thistime = params_to_send + data_to_send +
- alignment_offset + data_alignment_offset;
- /* We can never send more than useable_space */
- /*
- * Note that 'useable_space' does not include the alignment offsets,
- * but we must include the alignment offsets in the calculation of
- * the length of the data we send over the wire, as the alignment offsets
- * are sent here. Fix from Marc_Jacobsen@hp.com.
- */
- total_sent_thistime = MIN(total_sent_thistime, useable_space+
- alignment_offset + data_alignment_offset);
-
- set_message(outbuf, 10, total_sent_thistime, True);
-
- /* Set total params and data to be sent */
- SSVAL(outbuf,smb_tprcnt,paramsize);
- SSVAL(outbuf,smb_tdrcnt,datasize);
-
- /* Calculate how many parameters and data we can fit into
- this packet. Parameters get precedence */
-
- params_sent_thistime = MIN(params_to_send,useable_space);
- data_sent_thistime = useable_space - params_sent_thistime;
- data_sent_thistime = MIN(data_sent_thistime,data_to_send);
-
- SSVAL(outbuf,smb_prcnt, params_sent_thistime);
-
- /* smb_proff is the offset from the start of the SMB header to the
- parameter bytes, however the first 4 bytes of outbuf are
- the Netbios over TCP header. Thus use smb_base() to subtract
- them from the calculation */
-
- SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
-
- if(params_sent_thistime == 0)
- SSVAL(outbuf,smb_prdisp,0);
- else
- /* Absolute displacement of param bytes sent in this packet */
- SSVAL(outbuf,smb_prdisp,pp - params);
-
- SSVAL(outbuf,smb_drcnt, data_sent_thistime);
- if(data_sent_thistime == 0)
- {
- SSVAL(outbuf,smb_droff,0);
- SSVAL(outbuf,smb_drdisp, 0);
- }
- else
- {
- /* The offset of the data bytes is the offset of the
- parameter bytes plus the number of parameters being sent this time */
- SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) -
- smb_base(outbuf)) + params_sent_thistime + data_alignment_offset);
- SSVAL(outbuf,smb_drdisp, pd - pdata);
- }
-
- /* Copy the param bytes into the packet */
- if(params_sent_thistime)
- memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
- /* Copy in the data bytes */
- if(data_sent_thistime)
- memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+
- data_alignment_offset,pd,data_sent_thistime);
-
- DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
- params_sent_thistime, data_sent_thistime, useable_space));
- DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
- params_to_send, data_to_send, paramsize, datasize));
-
- /* Send the packet */
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("send_trans2_replies: send_smb failed.\n");
-
- pp += params_sent_thistime;
- pd += data_sent_thistime;
-
- params_to_send -= params_sent_thistime;
- data_to_send -= data_sent_thistime;
-
- /* Sanity check */
- if(params_to_send < 0 || data_to_send < 0)
- {
- DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
- params_to_send, data_to_send));
- return -1;
- }
- }
-
- return 0;
-}
+ /* As we are using a protocol > LANMAN1 then the max_send
+ variable must have been set in the sessetupX call.
+ This takes precedence over the max_xmit field in the
+ global struct. These different max_xmit variables should
+ be merged as this is now too confusing */
+
+ extern int max_send;
+ int data_to_send = datasize;
+ int params_to_send = paramsize;
+ int useable_space;
+ char *pp = params;
+ char *pd = pdata;
+ int params_sent_thistime, data_sent_thistime, total_sent_thistime;
+ int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
+ int data_alignment_offset = 0;
+
+ /* Initially set the wcnt area to be 10 - this is true for all
+ trans2 replies */
+ set_message(outbuf,10,0,True);
+
+ /* If there genuinely are no parameters or data to send just send
+ the empty packet */
+
+ if(params_to_send == 0 && data_to_send == 0) {
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("send_trans2_replies: send_smb failed.");
+ return 0;
+ }
+
+ /* When sending params and data ensure that both are nicely aligned */
+ /* Only do this alignment when there is also data to send - else
+ can cause NT redirector problems. */
+
+ if (((params_to_send % 4) != 0) && (data_to_send != 0))
+ data_alignment_offset = 4 - (params_to_send % 4);
+
+ /* Space is bufsize minus Netbios over TCP header minus SMB header */
+ /* The alignment_offset is to align the param bytes on an even byte
+ boundary. NT 4.0 Beta needs this to work correctly. */
+
+ useable_space = bufsize - ((smb_buf(outbuf)+ alignment_offset+data_alignment_offset) - outbuf);
+
+ /* useable_space can never be more than max_send minus the alignment offset. */
+
+ useable_space = MIN(useable_space, max_send - (alignment_offset+data_alignment_offset));
+
+
+ while (params_to_send || data_to_send) {
+ /* Calculate whether we will totally or partially fill this packet */
+
+ total_sent_thistime = params_to_send + data_to_send + alignment_offset + data_alignment_offset;
+
+ /* We can never send more than useable_space */
+ /*
+ * Note that 'useable_space' does not include the alignment offsets,
+ * but we must include the alignment offsets in the calculation of
+ * the length of the data we send over the wire, as the alignment offsets
+ * are sent here. Fix from Marc_Jacobsen@hp.com.
+ */
+
+ total_sent_thistime = MIN(total_sent_thistime, useable_space+ alignment_offset + data_alignment_offset);
+
+ set_message(outbuf, 10, total_sent_thistime, True);
+
+ /* Set total params and data to be sent */
+ SSVAL(outbuf,smb_tprcnt,paramsize);
+ SSVAL(outbuf,smb_tdrcnt,datasize);
+
+ /* Calculate how many parameters and data we can fit into
+ this packet. Parameters get precedence */
+
+ params_sent_thistime = MIN(params_to_send,useable_space);
+ data_sent_thistime = useable_space - params_sent_thistime;
+ data_sent_thistime = MIN(data_sent_thistime,data_to_send);
+
+ SSVAL(outbuf,smb_prcnt, params_sent_thistime);
+
+ /* smb_proff is the offset from the start of the SMB header to the
+ parameter bytes, however the first 4 bytes of outbuf are
+ the Netbios over TCP header. Thus use smb_base() to subtract
+ them from the calculation */
+ SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
+
+ if(params_sent_thistime == 0)
+ SSVAL(outbuf,smb_prdisp,0);
+ else
+ /* Absolute displacement of param bytes sent in this packet */
+ SSVAL(outbuf,smb_prdisp,pp - params);
+
+ SSVAL(outbuf,smb_drcnt, data_sent_thistime);
+ if(data_sent_thistime == 0) {
+ SSVAL(outbuf,smb_droff,0);
+ SSVAL(outbuf,smb_drdisp, 0);
+ } else {
+ /* The offset of the data bytes is the offset of the
+ parameter bytes plus the number of parameters being sent this time */
+ SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) -
+ smb_base(outbuf)) + params_sent_thistime + data_alignment_offset);
+ SSVAL(outbuf,smb_drdisp, pd - pdata);
+ }
+
+ /* Copy the param bytes into the packet */
+
+ if(params_sent_thistime)
+ memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
+
+ /* Copy in the data bytes */
+
+ if(data_sent_thistime)
+ memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+
+ data_alignment_offset,pd,data_sent_thistime);
+
+ DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
+ params_sent_thistime, data_sent_thistime, useable_space));
+ DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
+ params_to_send, data_to_send, paramsize, datasize));
+
+ /* Send the packet */
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("send_trans2_replies: send_smb failed.");
+
+ pp += params_sent_thistime;
+ pd += data_sent_thistime;
+
+ params_to_send -= params_sent_thistime;
+ data_to_send -= data_sent_thistime;
+
+ /* Sanity check */
+
+ if(params_to_send < 0 || data_to_send < 0) {
+ DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
+ params_to_send, data_to_send));
+ return -1;
+ }
+ }
+
+ return 0;
+}
/****************************************************************************
- reply to a TRANSACT2_OPEN
+ Reply to a TRANSACT2_OPEN.
****************************************************************************/
-static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
- int bufsize,
- char **pparams, char **ppdata)
+
+static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- char *params = *pparams;
- int16 open_mode = SVAL(params, 2);
- int16 open_attr = SVAL(params,6);
- BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1));
+ char *params = *pparams;
+ int16 open_mode;
+ int16 open_attr;
+ BOOL oplock_request;
#if 0
- BOOL return_additional_info = BITSETW(params,0);
- int16 open_sattr = SVAL(params, 4);
- time_t open_time = make_unix_date3(params+8);
+ BOOL return_additional_info;
+ int16 open_sattr;
+ time_t open_time;
#endif
- int16 open_ofun = SVAL(params,12);
- int32 open_size = IVAL(params,14);
- char *pname = &params[28];
- int16 namelen = strlen(pname)+1;
+ int16 open_ofun;
+ int32 open_size;
+ char *pname;
+ int16 namelen;
- pstring fname;
- mode_t unixmode;
- SMB_OFF_T size=0;
- int fmode=0,mtime=0,rmode;
- SMB_INO_T inode = 0;
- SMB_STRUCT_STAT sbuf;
- int smb_action = 0;
- BOOL bad_path = False;
- files_struct *fsp;
+ pstring fname;
+ mode_t unixmode;
+ SMB_OFF_T size=0;
+ int fmode=0,mtime=0,rmode;
+ SMB_INO_T inode = 0;
+ SMB_STRUCT_STAT sbuf;
+ int smb_action = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
+
+ /*
+ * Ensure we have enough parameters to perform the operation.
+ */
+
+ if (total_params < 29)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ open_mode = SVAL(params, 2);
+ open_attr = SVAL(params,6);
+ oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1));
+#if 0
+ return_additional_info = BITSETW(params,0);
+ open_sattr = SVAL(params, 4);
+ open_time = make_unix_date3(params+8);
+#endif
+ open_ofun = SVAL(params,12);
+ open_size = IVAL(params,14);
+ pname = &params[28];
+ namelen = strlen(pname)+1;
- StrnCpy(fname,pname,namelen);
+ StrnCpy(fname,pname,namelen);
- DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n",
- fname,open_mode, open_attr, open_ofun, open_size));
+ DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n",
+ fname,open_mode, open_attr, open_ofun, open_size));
- if (IS_IPC(conn)) {
- return(ERROR(ERRSRV,ERRaccess));
- }
+ if (IS_IPC(conn))
+ return(ERROR_DOS(ERRSRV,ERRaccess));
- /* XXXX we need to handle passed times, sattr and flags */
+ /* XXXX we need to handle passed times, sattr and flags */
- unix_convert(fname,conn,0,&bad_path,&sbuf);
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
- if (!check_name(fname,conn))
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- unixmode = unix_mode(conn,open_attr | aARCH, fname);
+ if (!check_name(fname,conn)) {
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ unixmode = unix_mode(conn,open_attr | aARCH, fname);
- fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode,
- oplock_request, &rmode,&smb_action);
+ fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode,
+ oplock_request, &rmode,&smb_action);
- if (!fsp)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- size = sbuf.st_size;
- fmode = dos_mode(conn,fname,&sbuf);
- mtime = sbuf.st_mtime;
- inode = sbuf.st_ino;
- if (fmode & aDIR) {
- close_file(fsp,False);
- return(ERROR(ERRDOS,ERRnoaccess));
- }
-
- /* Realloc the size of parameters and data we will return */
- params = Realloc(*pparams, 28);
- if( params == NULL ) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *pparams = params;
-
- memset((char *)params,'\0',28);
- SSVAL(params,0,fsp->fnum);
- SSVAL(params,2,fmode);
- put_dos_date2(params,4, mtime);
- SIVAL(params,8, (uint32)size);
- SSVAL(params,12,rmode);
-
- if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
- smb_action |= EXTENDED_OPLOCK_GRANTED;
- }
-
- SSVAL(params,18,smb_action);
- /*
- * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
- */
- SIVAL(params,20,inode);
+ if (!fsp) {
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ size = sbuf.st_size;
+ fmode = dos_mode(conn,fname,&sbuf);
+ mtime = sbuf.st_mtime;
+ inode = sbuf.st_ino;
+ if (fmode & aDIR) {
+ close_file(fsp,False);
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
+ }
+
+ /* Realloc the size of parameters and data we will return */
+ params = Realloc(*pparams, 28);
+ if( params == NULL )
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ *pparams = params;
+
+ memset((char *)params,'\0',28);
+ SSVAL(params,0,fsp->fnum);
+ SSVAL(params,2,fmode);
+ put_dos_date2(params,4, mtime);
+ SIVAL(params,8, (uint32)size);
+ SSVAL(params,12,rmode);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+
+ SSVAL(params,18,smb_action);
+
+ /*
+ * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
+ */
+ SIVAL(params,20,inode);
- /* Send the required number of replies */
- send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0);
+ /* Send the required number of replies */
+ send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0);
- return -1;
+ return -1;
}
/*********************************************************
-* Routine to check if a given string matches exactly.
-* as a special case a mask of "." does NOT match. That
-* is required for correct wildcard semantics
-* Case can be significant or not.
+ Routine to check if a given string matches exactly.
+ as a special case a mask of "." does NOT match. That
+ is required for correct wildcard semantics
+ Case can be significant or not.
**********************************************************/
+
static BOOL exact_match(char *str,char *mask, BOOL case_sig)
{
- if (mask[0] == '.' && mask[1] == 0) return False;
- if (case_sig) return strcmp(str,mask)==0;
+ if (mask[0] == '.' && mask[1] == 0)
+ return False;
+ if (case_sig)
+ return strcmp(str,mask)==0;
return strcasecmp(str,mask) == 0;
}
/****************************************************************************
- get a level dependent lanman2 dir entry.
+ Return the filetype for UNIX extensions.
****************************************************************************/
+
+static uint32 unix_filetype(mode_t mode)
+{
+ if(S_ISREG(mode))
+ return UNIX_TYPE_FILE;
+ else if(S_ISDIR(mode))
+ return UNIX_TYPE_DIR;
+#ifdef S_ISLNK
+ else if(S_ISLNK(mode))
+ return UNIX_TYPE_SYMLINK;
+#endif
+#ifdef S_ISCHR
+ else if(S_ISCHR(mode))
+ return UNIX_TYPE_CHARDEV;
+#endif
+#ifdef S_ISBLK
+ else if(S_ISBLK(mode))
+ return UNIX_TYPE_BLKDEV;
+#endif
+#ifdef S_ISFIFO
+ else if(S_ISFIFO(mode))
+ return UNIX_TYPE_FIFO;
+#endif
+#ifdef S_ISSOCK
+ else if(S_ISSOCK(mode))
+ return UNIX_TYPE_SOCKET;
+#endif
+
+ DEBUG(0,("unix_filetype: unknown filetype %u", (unsigned)mode));
+ return UNIX_TYPE_UNKNOWN;
+}
+
+/****************************************************************************
+ Return the major devicenumber for UNIX extensions.
+****************************************************************************/
+
+static uint32 unix_dev_major(SMB_DEV_T dev)
+{
+#if defined(HAVE_DEVICE_MAJOR_FN)
+ return (uint32)major(dev);
+#else
+ return (uint32)(dev >> 8);
+#endif
+}
+
+/****************************************************************************
+ Return the minor devicenumber for UNIX extensions.
+****************************************************************************/
+
+static uint32 unix_dev_minor(SMB_DEV_T dev)
+{
+#if defined(HAVE_DEVICE_MINOR_FN)
+ return (uint32)minor(dev);
+#else
+ return (uint32)(dev & 0xff);
+#endif
+}
+
+/****************************************************************************
+ Map wire perms onto standard UNIX permissions. Obey share restrictions.
+****************************************************************************/
+
+static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *pst, uint32 perms)
+{
+ mode_t ret = 0;
+
+ if (perms == SMB_MODE_NO_CHANGE)
+ return pst->st_mode;
+
+ ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0);
+ ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0);
+ ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0);
+ ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0);
+ ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0);
+ ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0);
+ ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0);
+ ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0);
+ ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & UNIX_SET_UID ) ? S_ISVTX : 0);
+#endif
+
+ if (VALID_STAT(*pst) && S_ISDIR(pst->st_mode)) {
+ ret &= lp_dir_mask(SNUM(conn));
+ /* Add in force bits */
+ ret |= lp_force_dir_mode(SNUM(conn));
+ } else {
+ /* Apply mode mask */
+ ret &= lp_create_mask(SNUM(conn));
+ /* Add in force bits */
+ ret |= lp_force_create_mode(SNUM(conn));
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Get a level dependent lanman2 dir entry.
+****************************************************************************/
+
static BOOL get_lanman2_dir_entry(connection_struct *conn,
char *path_mask,int dirtype,int info_level,
int requires_resume_key,
@@ -315,975 +428,1093 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
BOOL *out_of_space, BOOL *got_exact_match,
int *last_name_off)
{
- char *dname;
- BOOL found = False;
- SMB_STRUCT_STAT sbuf;
- pstring mask;
- pstring pathreal;
- pstring fname;
- char *p, *pdata = *ppdata;
- uint32 reskey=0;
- int prev_dirpos=0;
- int mode=0;
- SMB_OFF_T size = 0;
- uint32 len;
- time_t mdate=0, adate=0, cdate=0;
- char *nameptr;
- BOOL was_8_3;
- int nt_extmode; /* Used for NT connections instead of mode */
- BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
-
- *fname = 0;
- *out_of_space = False;
- *got_exact_match = False;
-
- if (!conn->dirptr)
- return(False);
-
- p = strrchr(path_mask,'/');
- if(p != NULL)
- {
- if(p[1] == '\0')
- pstrcpy(mask,"*.*");
- else
- pstrcpy(mask, p+1);
- }
- else
- pstrcpy(mask, path_mask);
-
- while (!found)
- {
- BOOL got_match;
-
- /* Needed if we run out of space */
- prev_dirpos = TellDir(conn->dirptr);
- dname = ReadDirName(conn->dirptr);
-
- /*
- * Due to bugs in NT client redirectors we are not using
- * resume keys any more - set them to zero.
- * Check out the related comments in findfirst/findnext.
- * JRA.
- */
-
- reskey = 0;
-
- DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
- (long)conn->dirptr,TellDir(conn->dirptr)));
+ char *dname;
+ BOOL found = False;
+ SMB_STRUCT_STAT sbuf;
+ pstring mask;
+ pstring pathreal;
+ pstring fname;
+ char *p, *pdata = *ppdata;
+ uint32 reskey=0;
+ int prev_dirpos=0;
+ int mode=0;
+ SMB_OFF_T size = 0;
+ SMB_OFF_T allocation_size = 0;
+ uint32 len;
+ time_t mdate=0, adate=0, cdate=0;
+ char *nameptr;
+ BOOL was_8_3;
+ int nt_extmode; /* Used for NT connections instead of mode */
+ BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+
+ *fname = 0;
+ *out_of_space = False;
+ *got_exact_match = False;
+
+ if (!conn->dirptr)
+ return(False);
+
+ p = strrchr(path_mask,'/');
+ if(p != NULL) {
+ if(p[1] == '\0')
+ pstrcpy(mask,"*.*");
+ else
+ pstrcpy(mask, p+1);
+ } else
+ pstrcpy(mask, path_mask);
+
+ while (!found) {
+ BOOL got_match;
+
+ /* Needed if we run out of space */
+ prev_dirpos = TellDir(conn->dirptr);
+ dname = ReadDirName(conn->dirptr);
+
+ /*
+ * Due to bugs in NT client redirectors we are not using
+ * resume keys any more - set them to zero.
+ * Check out the related comments in findfirst/findnext.
+ * JRA.
+ */
+
+ reskey = 0;
+
+ DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
+ (long)conn->dirptr,TellDir(conn->dirptr)));
- if (!dname)
- return(False);
-
- pstrcpy(fname,dname);
-
- if(!(got_match = *got_exact_match = exact_match(fname, mask, case_sensitive))) {
- got_match = mask_match(fname, mask, case_sensitive);
- }
-
- if(!got_match && !is_8_3(fname, False)) {
-
- /*
- * It turns out that NT matches wildcards against
- * both long *and* short names. This may explain some
- * of the wildcard wierdness from old DOS clients
- * that some people have been seeing.... JRA.
- */
-
- pstring newname;
- pstrcpy( newname, fname);
- name_map_mangle( newname, True, False, SNUM(conn));
- if(!(got_match = *got_exact_match = exact_match(newname, mask, case_sensitive)))
- got_match = mask_match(newname, mask, case_sensitive);
- }
-
- if(got_match)
- {
- BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
- if (dont_descend && !isdots)
- continue;
+ if (!dname)
+ return(False);
+
+ pstrcpy(fname,dname);
+
+ if(!(got_match = *got_exact_match = exact_match(fname, mask, case_sensitive)))
+ got_match = mask_match(fname, mask, case_sensitive);
+
+ if(!got_match && !is_8_3(fname, False)) {
+
+ /*
+ * It turns out that NT matches wildcards against
+ * both long *and* short names. This may explain some
+ * of the wildcard wierdness from old DOS clients
+ * that some people have been seeing.... JRA.
+ */
+
+ pstring newname;
+ pstrcpy( newname, fname);
+ name_map_mangle( newname, True, False, SNUM(conn));
+ if(!(got_match = *got_exact_match = exact_match(newname, mask, case_sensitive)))
+ got_match = mask_match(newname, mask, case_sensitive);
+ }
+
+ if(got_match) {
+ BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
+ if (dont_descend && !isdots)
+ continue;
- pstrcpy(pathreal,conn->dirpath);
- if(needslash)
- pstrcat(pathreal,"/");
- pstrcat(pathreal,dname);
- if (vfs_stat(conn,pathreal,&sbuf) != 0)
- {
- /* Needed to show the msdfs symlinks as directories */
- if(!lp_host_msdfs() || !lp_msdfs_root(SNUM(conn))
- || !is_msdfs_link(conn, pathreal, NULL, NULL))
- {
- DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
- pathreal,strerror(errno)));
- continue;
- }
- else
- {
- DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
- sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
- }
- }
-
- mode = dos_mode(conn,pathreal,&sbuf);
-
- if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
- DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
- continue;
- }
-
- size = sbuf.st_size;
- mdate = sbuf.st_mtime;
- adate = sbuf.st_atime;
- cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
-
- if (lp_dos_filetime_resolution(SNUM(conn))) {
- cdate &= ~1;
- mdate &= ~1;
- adate &= ~1;
- }
-
- if(mode & aDIR)
- size = 0;
-
- DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
+ pstrcpy(pathreal,conn->dirpath);
+ if(needslash)
+ pstrcat(pathreal,"/");
+ pstrcat(pathreal,dname);
+
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ if (vfs_lstat(conn,pathreal,&sbuf) != 0) {
+ DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n",
+ pathreal,strerror(errno)));
+ continue;
+ }
+ } else if (vfs_stat(conn,pathreal,&sbuf) != 0) {
+ /* Needed to show the msdfs symlinks as directories */
+ if(!lp_host_msdfs() || !lp_msdfs_root(SNUM(conn))
+ || !is_msdfs_link(conn, pathreal, NULL, NULL)) {
+ DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
+ pathreal,strerror(errno)));
+ continue;
+ } else {
+ DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
+ sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
+ }
+ }
+
+ mode = dos_mode(conn,pathreal,&sbuf);
+
+ if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+ DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
+ continue;
+ }
+
+ size = sbuf.st_size;
+ allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size);
+ mdate = sbuf.st_mtime;
+ adate = sbuf.st_atime;
+ cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ cdate &= ~1;
+ mdate &= ~1;
+ adate &= ~1;
+ }
+
+ if(mode & aDIR)
+ size = 0;
+
+ DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
- found = True;
- }
- }
-
- name_map_mangle(fname,False,True,SNUM(conn));
-
- p = pdata;
- nameptr = p;
-
- nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
-
- switch (info_level)
- {
- case 1:
- if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
- }
- put_dos_date2(p,l1_fdateCreation,cdate);
- put_dos_date2(p,l1_fdateLastAccess,adate);
- put_dos_date2(p,l1_fdateLastWrite,mdate);
- SIVAL(p,l1_cbFile,(uint32)size);
- SIVAL(p,l1_cbFileAlloc,SMB_ROUNDUP(size,1024));
- SSVAL(p,l1_attrFile,mode);
- SCVAL(p,l1_cchName,strlen(fname));
- pstrcpy(p + l1_achName, fname);
- nameptr = p + l1_achName;
- p += l1_achName + strlen(fname) + 1;
- break;
-
- case 2:
- /* info_level 2 */
- if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
- }
- put_dos_date2(p,l2_fdateCreation,cdate);
- put_dos_date2(p,l2_fdateLastAccess,adate);
- put_dos_date2(p,l2_fdateLastWrite,mdate);
- SIVAL(p,l2_cbFile,(uint32)size);
- SIVAL(p,l2_cbFileAlloc,SMB_ROUNDUP(size,1024));
- SSVAL(p,l2_attrFile,mode);
- SIVAL(p,l2_cbList,0); /* No extended attributes */
- SCVAL(p,l2_cchName,strlen(fname));
- pstrcpy(p + l2_achName, fname);
- nameptr = p + l2_achName;
- p += l2_achName + strlen(fname) + 1;
- break;
-
- case 3:
- SIVAL(p,0,reskey);
- put_dos_date2(p,4,cdate);
- put_dos_date2(p,8,adate);
- put_dos_date2(p,12,mdate);
- SIVAL(p,16,(uint32)size);
- SIVAL(p,20,SMB_ROUNDUP(size,1024));
- SSVAL(p,24,mode);
- SIVAL(p,26,4);
- CVAL(p,30) = strlen(fname);
- pstrcpy(p+31, fname);
- nameptr = p+31;
- p += 31 + strlen(fname) + 1;
- break;
-
- case 4:
- if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
- }
- SIVAL(p,0,33+strlen(fname)+1);
- put_dos_date2(p,4,cdate);
- put_dos_date2(p,8,adate);
- put_dos_date2(p,12,mdate);
- SIVAL(p,16,(uint32)size);
- SIVAL(p,20,SMB_ROUNDUP(size,1024));
- SSVAL(p,24,mode);
- CVAL(p,32) = strlen(fname);
- pstrcpy(p + 33, fname);
- nameptr = p+33;
- p += 33 + strlen(fname) + 1;
- break;
-
- case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- was_8_3 = is_8_3(fname, True);
- len = 94+strlen(fname);
- len = (len + 3) & ~3;
- SIVAL(p,0,len); p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SOFF_T(p,0,size);
- SOFF_T(p,8,size);
- p += 16;
- SIVAL(p,0,nt_extmode); p += 4;
- SIVAL(p,0,strlen(fname)); p += 4;
- SIVAL(p,0,0); p += 4;
- if (!was_8_3) {
- fstrcpy(p+2,fname);
- if(!name_map_mangle(p+2,True,True,SNUM(conn)))
- (p+2)[12] = 0;
- strupper(p+2);
- SSVAL(p, 0, strlen(p+2));
- } else {
- SSVAL(p,0,0);
- *(p+2) = 0;
- }
- p += 2 + 24;
- /* nameptr = p; */
- pstrcpy(p,fname); p += strlen(p);
- p = pdata + len;
- break;
-
- case SMB_FIND_FILE_DIRECTORY_INFO:
- len = 64+strlen(fname);
- len = (len + 3) & ~3;
- SIVAL(p,0,len); p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SOFF_T(p,0,size);
- SOFF_T(p,8,size);
- p += 16;
- SIVAL(p,0,nt_extmode); p += 4;
- SIVAL(p,0,strlen(fname)); p += 4;
- pstrcpy(p,fname);
- p = pdata + len;
- break;
-
+ found = True;
+ }
+ }
+
+ name_map_mangle(fname,False,True,SNUM(conn));
+
+ p = pdata;
+ nameptr = p;
+
+ nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
+
+ switch (info_level) {
+ case 1:
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ put_dos_date2(p,l1_fdateCreation,cdate);
+ put_dos_date2(p,l1_fdateLastAccess,adate);
+ put_dos_date2(p,l1_fdateLastWrite,mdate);
+ SIVAL(p,l1_cbFile,(uint32)size);
+ SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size);
+ SSVAL(p,l1_attrFile,mode);
+ SCVAL(p,l1_cchName,strlen(fname));
+ pstrcpy(p + l1_achName, fname);
+ nameptr = p + l1_achName;
+ p += l1_achName + strlen(fname) + 1;
+ break;
+
+ case 2:
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ put_dos_date2(p,l2_fdateCreation,cdate);
+ put_dos_date2(p,l2_fdateLastAccess,adate);
+ put_dos_date2(p,l2_fdateLastWrite,mdate);
+ SIVAL(p,l2_cbFile,(uint32)size);
+ SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size);
+ SSVAL(p,l2_attrFile,mode);
+ SIVAL(p,l2_cbList,0); /* No extended attributes */
+ SCVAL(p,l2_cchName,strlen(fname));
+ pstrcpy(p + l2_achName, fname);
+ nameptr = p + l2_achName;
+ p += l2_achName + strlen(fname) + 1;
+ break;
+
+ case 3:
+ SIVAL(p,0,reskey);
+ put_dos_date2(p,4,cdate);
+ put_dos_date2(p,8,adate);
+ put_dos_date2(p,12,mdate);
+ SIVAL(p,16,(uint32)size);
+ SIVAL(p,20,(uint32)allocation_size);
+ SSVAL(p,24,mode);
+ SIVAL(p,26,4);
+ SCVAL(p,30,strlen(fname));
+ pstrcpy(p+31, fname);
+ nameptr = p+31;
+ p += 31 + strlen(fname) + 1;
+ break;
+
+ case 4:
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ SIVAL(p,0,33+strlen(fname)+1);
+ put_dos_date2(p,4,cdate);
+ put_dos_date2(p,8,adate);
+ put_dos_date2(p,12,mdate);
+ SIVAL(p,16,(uint32)size);
+ SIVAL(p,20,(uint32)allocation_size);
+ SSVAL(p,24,mode);
+ SCVAL(p,32,strlen(fname));
+ pstrcpy(p + 33, fname);
+ nameptr = p+33;
+ p += 33 + strlen(fname) + 1;
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ was_8_3 = is_8_3(fname, True);
+ len = 94+strlen(fname);
+ len = (len + 3) & ~3;
+ SIVAL(p,0,len); p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,size);
+ SOFF_T(p,8,allocation_size);
+ p += 16;
+ SIVAL(p,0,nt_extmode); p += 4;
+ SIVAL(p,0,strlen(fname)); p += 4;
+ SIVAL(p,0,0); p += 4;
+ if (!was_8_3) {
+ fstrcpy(p+2,fname);
+ if(!name_map_mangle(p+2,True,True,SNUM(conn)))
+ (p+2)[12] = 0;
+ strupper(p+2);
+ SSVAL(p, 0, strlen(p+2));
+ } else {
+ SSVAL(p,0,0);
+ *(p+2) = 0;
+ }
+ p += 2 + 24;
+ /* nameptr = p; */
+ pstrcpy(p,fname); p += strlen(p);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ len = 64+strlen(fname);
+ len = (len + 3) & ~3;
+ SIVAL(p,0,len); p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,size);
+ SOFF_T(p,8,allocation_size);
+ p += 16;
+ SIVAL(p,0,nt_extmode); p += 4;
+ SIVAL(p,0,strlen(fname)); p += 4;
+ pstrcpy(p,fname);
+ p = pdata + len;
+ break;
- case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
- len = 68+strlen(fname);
- len = (len + 3) & ~3;
- SIVAL(p,0,len); p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SOFF_T(p,0,size);
- SOFF_T(p,8,size);
- p += 16;
- SIVAL(p,0,nt_extmode); p += 4;
- SIVAL(p,0,strlen(fname)); p += 4;
- SIVAL(p,0,0); p += 4;
- pstrcpy(p,fname);
- p = pdata + len;
- break;
-
- case SMB_FIND_FILE_NAMES_INFO:
- len = 12+strlen(fname);
- len = (len + 3) & ~3;
- SIVAL(p,0,len); p += 4;
- SIVAL(p,0,reskey); p += 4;
- SIVAL(p,0,strlen(fname)); p += 4;
- pstrcpy(p,fname);
- p = pdata + len;
- break;
-
- default:
- return(False);
- }
-
-
- if (PTR_DIFF(p,pdata) > space_remaining) {
- /* Move the dirptr back to prev_dirpos */
- SeekDir(conn->dirptr, prev_dirpos);
- *out_of_space = True;
- DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
- return False; /* Not finished - just out of space */
- }
-
- /* Setup the last_filename pointer, as an offset from base_data */
- *last_name_off = PTR_DIFF(nameptr,base_data);
- /* Advance the data pointer to the next slot */
- *ppdata = p;
-
- return(found);
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ len = 68+strlen(fname);
+ len = (len + 3) & ~3;
+ SIVAL(p,0,len); p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,size);
+ SOFF_T(p,8,allocation_size);
+ p += 16;
+ SIVAL(p,0,nt_extmode); p += 4;
+ SIVAL(p,0,strlen(fname)); p += 4;
+ SIVAL(p,0,0); p += 4;
+ pstrcpy(p,fname);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ len = 12+strlen(fname);
+ len = (len + 3) & ~3;
+ SIVAL(p,0,len); p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ SIVAL(p,0,strlen(fname)); p += 4;
+ pstrcpy(p,fname);
+ p = pdata + len;
+ break;
+
+ /* CIFS UNIX Extension. */
+
+ case SMB_FIND_FILE_UNIX:
+ len = 108+strlen(fname)+1; /* (length of SMB_QUERY_FILE_UNIX_BASIC = 100)+4+4+strlen(fname)*/
+ /* +1 to be sure to transmit the termination of fname */
+ len = (len + 3) & ~3;
+
+ SIVAL(p,0,len); p+= 4; /* Offset from this structure to the beginning of the next one */
+ SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
+
+ /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
+ SOFF_T(p,0,sbuf.st_size); /* File size 64 Bit */
+ p+= 8;
+
+#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
+ SOFF_T(p,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */
+#else
+ /* Can't get the value - fake it using size. */
+ SOFF_T(p,0,sbuf.st_size); /* Number of bytes used on disk - 64 Bit */
+#endif
+ p+= 8;
+
+ put_long_date(p,sbuf.st_ctime); /* Creation Time 64 Bit */
+ put_long_date(p+8,sbuf.st_atime); /* Last access time 64 Bit */
+ put_long_date(p+16,sbuf.st_mtime); /* Last modification time 64 Bit */
+ p+= 24;
+
+ SIVAL(p,0,sbuf.st_uid); /* user id for the owner */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SIVAL(p,0,sbuf.st_gid); /* group id of owner */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SIVAL(p,0,unix_filetype(sbuf.st_mode));
+ p+= 4;
+
+ SIVAL(p,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SIVAL(p,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SINO_T(p,0,(SMB_INO_T)sbuf.st_ino); /* inode number */
+ p+= 8;
+
+ SIVAL(p,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SIVAL(p,0,sbuf.st_nlink); /* number of hard links */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ /* End of SMB_QUERY_FILE_UNIX_BASIC */
+ pstrcpy(p,fname);
+ p=pdata+len;
+
+ break;
+
+ default:
+ return(False);
+ }
+
+
+ if (PTR_DIFF(p,pdata) > space_remaining) {
+ /* Move the dirptr back to prev_dirpos */
+ SeekDir(conn->dirptr, prev_dirpos);
+ *out_of_space = True;
+ DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
+ return False; /* Not finished - just out of space */
+ }
+
+ /* Setup the last_filename pointer, as an offset from base_data */
+ *last_name_off = PTR_DIFF(nameptr,base_data);
+ /* Advance the data pointer to the next slot */
+ *ppdata = p;
+
+ return(found);
}
-
/****************************************************************************
Reply to a TRANS2_FINDFIRST.
****************************************************************************/
-static int call_trans2findfirst(connection_struct *conn,
- char *inbuf, char *outbuf, int bufsize,
- char **pparams, char **ppdata)
+static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- /* We must be careful here that we don't return more than the
- allowed number of data bytes. If this means returning fewer than
- maxentries then so be it. We assume that the redirector has
- enough room for the fixed number of parameter bytes it has
- requested. */
- uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt);
- char *params = *pparams;
- char *pdata = *ppdata;
- int dirtype = SVAL(params,0);
- int maxentries = SVAL(params,2);
- BOOL close_after_first = BITSETW(params+4,0);
- BOOL close_if_end = BITSETW(params+4,1);
- BOOL requires_resume_key = BITSETW(params+4,2);
- int info_level = SVAL(params,6);
- pstring directory;
- pstring mask;
- char *p, *wcard;
- int last_name_off=0;
- int dptr_num = -1;
- int numentries = 0;
- int i;
- BOOL finished = False;
- BOOL dont_descend = False;
- BOOL out_of_space = False;
- int space_remaining;
- BOOL bad_path = False;
- SMB_STRUCT_STAT sbuf;
-
- *directory = *mask = 0;
-
- DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n",
- dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
- info_level, max_data_bytes));
+ /* We must be careful here that we don't return more than the
+ allowed number of data bytes. If this means returning fewer than
+ maxentries then so be it. We assume that the redirector has
+ enough room for the fixed number of parameter bytes it has
+ requested. */
+ uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt);
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ int dirtype;
+ int maxentries;
+ BOOL close_after_first;
+ BOOL close_if_end;
+ BOOL requires_resume_key;
+ int info_level;
+ pstring directory;
+ pstring mask;
+ char *p, *wcard;
+ int last_name_off=0;
+ int dptr_num = -1;
+ int numentries = 0;
+ int i;
+ BOOL finished = False;
+ BOOL dont_descend = False;
+ BOOL out_of_space = False;
+ int space_remaining;
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT sbuf;
+
+ if (total_params < 12)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ *directory = *mask = 0;
+
+ dirtype = SVAL(params,0);
+ maxentries = SVAL(params,2);
+ close_after_first = BITSETW(params+4,0);
+ close_if_end = BITSETW(params+4,1);
+ requires_resume_key = BITSETW(params+4,2);
+ info_level = SVAL(params,6);
+
+ DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \
+close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n",
+ dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
+ info_level, max_data_bytes));
- switch (info_level)
- {
- case 1:
- case 2:
- case 3:
- case 4:
- case SMB_FIND_FILE_DIRECTORY_INFO:
- case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
- case SMB_FIND_FILE_NAMES_INFO:
- case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- break;
- default:
- return(ERROR(ERRDOS,ERRunknownlevel));
- }
-
- pstrcpy(directory, params + 12); /* Complete directory path with
- wildcard mask appended */
-
- RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf);
-
- DEBUG(5,("path=%s\n",directory));
-
- unix_convert(directory,conn,0,&bad_path,&sbuf);
- if(!check_name(directory,conn)) {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ switch (info_level) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ case SMB_FIND_FILE_NAMES_INFO:
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ break;
+ case SMB_FIND_FILE_UNIX:
+ if (!lp_unix_extensions())
+ return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ break;
+ default:
+ return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ }
+
+ pstrcpy(directory, params + 12); /* Complete directory path with wildcard mask appended */
+
+ RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf);
+
+ DEBUG(5,("path=%s\n",directory));
+
+ unix_convert(directory,conn,0,&bad_path,&sbuf);
+ if(!check_name(directory,conn)) {
+ set_bad_path_error(errno, bad_path);
#if 0
- /* Ugly - NT specific hack - maybe not needed ? (JRA) */
- if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
- (get_remote_arch() == RA_WINNT))
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbaddirectory;
- }
+ /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+ if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && (get_remote_arch() == RA_WINNT)) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbaddirectory;
+ }
#endif
- return(UNIXERROR(ERRDOS,ERRbadpath));
- }
-
- p = strrchr(directory,'/');
- if(p == NULL) {
- pstrcpy(mask,directory);
- pstrcpy(directory,"./");
- } else {
- pstrcpy(mask,p+1);
- *p = 0;
- }
-
- DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
-
- pdata = Realloc(*ppdata, max_data_bytes + 1024);
- if( pdata == NULL ) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *ppdata = pdata;
- memset((char *)pdata,'\0',max_data_bytes + 1024);
-
- /* Realloc the params space */
- params = Realloc(*pparams, 10);
- if( params == NULL ) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *pparams = params;
-
- dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
- if (dptr_num < 0)
- return(UNIXERROR(ERRDOS,ERRbadfile));
-
- /* Save the wildcard match and attribs we are using on this directory -
- needed as lanman2 assumes these are being saved between calls */
-
- if(!(wcard = strdup(mask))) {
- dptr_close(&dptr_num);
- return(ERROR(ERRDOS,ERRnomem));
- }
-
- dptr_set_wcard(dptr_num, wcard);
- dptr_set_attr(dptr_num, dirtype);
-
- DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
-
- /* We don't need to check for VOL here as this is returned by
- a different TRANS2 call. */
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+
+ p = strrchr(directory,'/');
+ if(p == NULL) {
+ pstrcpy(mask,directory);
+ pstrcpy(directory,"./");
+ } else {
+ pstrcpy(mask,p+1);
+ *p = 0;
+ }
+
+ DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
+
+ pdata = Realloc(*ppdata, max_data_bytes + 1024);
+ if( pdata == NULL )
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ *ppdata = pdata;
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
+
+ /* Realloc the params space */
+ params = Realloc(*pparams, 10);
+ if( params == NULL )
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *pparams = params;
+
+ dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
+ if (dptr_num < 0)
+ return(UNIXERROR(ERRDOS,ERRbadfile));
+
+ /* Save the wildcard match and attribs we are using on this directory -
+ needed as lanman2 assumes these are being saved between calls */
+
+ if(!(wcard = strdup(mask))) {
+ dptr_close(&dptr_num);
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+
+ dptr_set_wcard(dptr_num, wcard);
+ dptr_set_attr(dptr_num, dirtype);
+
+ DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
+
+ /* We don't need to check for VOL here as this is returned by
+ a different TRANS2 call. */
- DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
- conn->dirpath,lp_dontdescend(SNUM(conn))));
- if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive))
- dont_descend = True;
+ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn))));
+
+ if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive))
+ dont_descend = True;
- p = pdata;
- space_remaining = max_data_bytes;
- out_of_space = False;
-
- for (i=0;(i<maxentries) && !finished && !out_of_space;i++)
- {
- BOOL got_exact_match = False;
-
- /* this is a heuristic to avoid seeking the dirptr except when
- absolutely necessary. It allows for a filename of about 40 chars */
- if (space_remaining < DIRLEN_GUESS && numentries > 0)
- {
- out_of_space = True;
- finished = False;
- }
- else
- {
- finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
- requires_resume_key,dont_descend,
- &p,pdata,space_remaining, &out_of_space, &got_exact_match,
- &last_name_off);
- }
-
- if (finished && out_of_space)
- finished = False;
-
- if (!finished && !out_of_space)
- numentries++;
-
- /*
- * As an optimisation if we know we aren't looking
- * for a wildcard name (ie. the name matches the wildcard exactly)
- * then we can finish on any (first) match.
- * This speeds up large directory searches. JRA.
- */
-
- if(got_exact_match)
- finished = True;
-
- space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
- }
+ p = pdata;
+ space_remaining = max_data_bytes;
+ out_of_space = False;
+
+ for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
+ BOOL got_exact_match = False;
+
+ /* this is a heuristic to avoid seeking the dirptr except when
+ absolutely necessary. It allows for a filename of about 40 chars */
+
+ if (space_remaining < DIRLEN_GUESS && numentries > 0) {
+ out_of_space = True;
+ finished = False;
+ } else {
+ finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
+ requires_resume_key,dont_descend,
+ &p,pdata,space_remaining, &out_of_space, &got_exact_match,
+ &last_name_off);
+ }
+
+ if (finished && out_of_space)
+ finished = False;
+
+ if (!finished && !out_of_space)
+ numentries++;
+
+ /*
+ * As an optimisation if we know we aren't looking
+ * for a wildcard name (ie. the name matches the wildcard exactly)
+ * then we can finish on any (first) match.
+ * This speeds up large directory searches. JRA.
+ */
+
+ if(got_exact_match)
+ finished = True;
+
+ space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ }
- /* Check if we can close the dirptr */
- if(close_after_first || (finished && close_if_end))
- {
- DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
- dptr_close(&dptr_num);
- }
-
- /*
- * If there are no matching entries we must return ERRDOS/ERRbadfile -
- * from observation of NT.
- */
-
- if(numentries == 0)
- {
- dptr_close(&dptr_num);
- return(ERROR(ERRDOS,ERRbadfile));
- }
-
- /* At this point pdata points to numentries directory entries. */
-
- /* Set up the return parameter block */
- SSVAL(params,0,dptr_num);
- SSVAL(params,2,numentries);
- SSVAL(params,4,finished);
- SSVAL(params,6,0); /* Never an EA error */
- SSVAL(params,8,last_name_off);
-
- send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata));
-
- if ((! *directory) && dptr_path(dptr_num))
- slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
-
- DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
- smb_fn_name(CVAL(inbuf,smb_com)),
- mask, directory, dirtype, numentries ) );
-
- /*
- * Force a name mangle here to ensure that the
- * mask as an 8.3 name is top of the mangled cache.
- * The reasons for this are subtle. Don't remove
- * this code unless you know what you are doing
- * (see PR#13758). JRA.
- */
-
- if(!is_8_3( mask, False))
- name_map_mangle(mask, True, True, SNUM(conn));
-
- return(-1);
-}
+ /* Check if we can close the dirptr */
+
+ if(close_after_first || (finished && close_if_end)) {
+ DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
+ dptr_close(&dptr_num);
+ }
+
+ /*
+ * If there are no matching entries we must return ERRDOS/ERRbadfile -
+ * from observation of NT.
+ */
+
+ if(numentries == 0) {
+ dptr_close(&dptr_num);
+ return ERROR_DOS(ERRDOS,ERRbadfile);
+ }
+
+ /* At this point pdata points to numentries directory entries. */
+
+ /* Set up the return parameter block */
+ SSVAL(params,0,dptr_num);
+ SSVAL(params,2,numentries);
+ SSVAL(params,4,finished);
+ SSVAL(params,6,0); /* Never an EA error */
+ SSVAL(params,8,last_name_off);
+
+ send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata));
+ if ((! *directory) && dptr_path(dptr_num))
+ slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
+
+ DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
+ smb_fn_name(CVAL(inbuf,smb_com)),
+ mask, directory, dirtype, numentries ) );
+
+ /*
+ * Force a name mangle here to ensure that the
+ * mask as an 8.3 name is top of the mangled cache.
+ * The reasons for this are subtle. Don't remove
+ * this code unless you know what you are doing
+ * (see PR#13758). JRA.
+ */
+
+ if(!is_8_3( mask, False))
+ name_map_mangle(mask, True, True, SNUM(conn));
+
+ return(-1);
+}
/****************************************************************************
- reply to a TRANS2_FINDNEXT
+ Reply to a TRANS2_FINDNEXT.
****************************************************************************/
-static int call_trans2findnext(connection_struct *conn,
- char *inbuf, char *outbuf,
- int length, int bufsize,
- char **pparams, char **ppdata)
+
+static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- /* We must be careful here that we don't return more than the
- allowed number of data bytes. If this means returning fewer than
- maxentries then so be it. We assume that the redirector has
- enough room for the fixed number of parameter bytes it has
- requested. */
- int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
- char *params = *pparams;
- char *pdata = *ppdata;
- int dptr_num = SVAL(params,0);
- int maxentries = SVAL(params,2);
- uint16 info_level = SVAL(params,4);
- uint32 resume_key = IVAL(params,6);
- BOOL close_after_request = BITSETW(params+10,0);
- BOOL close_if_end = BITSETW(params+10,1);
- BOOL requires_resume_key = BITSETW(params+10,2);
- BOOL continue_bit = BITSETW(params+10,3);
- pstring resume_name;
- pstring mask;
- pstring directory;
- char *p;
- uint16 dirtype;
- int numentries = 0;
- int i, last_name_off=0;
- BOOL finished = False;
- BOOL dont_descend = False;
- BOOL out_of_space = False;
- int space_remaining;
-
- *mask = *directory = *resume_name = 0;
-
- pstrcpy( resume_name, params+12);
-
- DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
+ /* We must be careful here that we don't return more than the
+ allowed number of data bytes. If this means returning fewer than
+ maxentries then so be it. We assume that the redirector has
+ enough room for the fixed number of parameter bytes it has
+ requested. */
+ int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ int dptr_num;
+ int maxentries;
+ uint16 info_level;
+ uint32 resume_key;
+ BOOL close_after_request;
+ BOOL close_if_end;
+ BOOL requires_resume_key;
+ BOOL continue_bit;
+ pstring resume_name;
+ pstring mask;
+ pstring directory;
+ char *p;
+ uint16 dirtype;
+ int numentries = 0;
+ int i, last_name_off=0;
+ BOOL finished = False;
+ BOOL dont_descend = False;
+ BOOL out_of_space = False;
+ int space_remaining;
+
+ if (total_params < 12)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ dptr_num = SVAL(params,0);
+ maxentries = SVAL(params,2);
+ info_level = SVAL(params,4);
+ resume_key = IVAL(params,6);
+ close_after_request = BITSETW(params+10,0);
+ close_if_end = BITSETW(params+10,1);
+ requires_resume_key = BITSETW(params+10,2);
+ continue_bit = BITSETW(params+10,3);
+
+ *mask = *directory = *resume_name = 0;
+
+ pstrcpy( resume_name, params+12);
+
+ DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
close_after_request=%d, close_if_end = %d requires_resume_key = %d \
resume_key = %d resume name = %s continue=%d level = %d\n",
- dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end,
- requires_resume_key, resume_key, resume_name, continue_bit, info_level));
-
- switch (info_level)
- {
- case 1:
- case 2:
- case 3:
- case 4:
- case SMB_FIND_FILE_DIRECTORY_INFO:
- case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
- case SMB_FIND_FILE_NAMES_INFO:
- case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- break;
- default:
- return(ERROR(ERRDOS,ERRunknownlevel));
- }
-
- pdata = Realloc( *ppdata, max_data_bytes + 1024);
- if(pdata == NULL) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *ppdata = pdata;
- memset((char *)pdata,'\0',max_data_bytes + 1024);
-
- /* Realloc the params space */
- params = Realloc(*pparams, 6*SIZEOFWORD);
- if( params == NULL ) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *pparams = params;
-
- /* Check that the dptr is valid */
- if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num)))
- return(ERROR(ERRDOS,ERRnofiles));
-
- string_set(&conn->dirpath,dptr_path(dptr_num));
-
- /* Get the wildcard mask from the dptr */
- if((p = dptr_wcard(dptr_num))== NULL) {
- DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
- return (ERROR(ERRDOS,ERRnofiles));
- }
- pstrcpy(mask, p);
- pstrcpy(directory,conn->dirpath);
-
- /* Get the attr mask from the dptr */
- dirtype = dptr_attr(dptr_num);
-
- DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n",
- dptr_num, mask, dirtype,
- (long)conn->dirptr,
- TellDir(conn->dirptr)));
-
- /* We don't need to check for VOL here as this is returned by
- a different TRANS2 call. */
-
- DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn))));
- if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive))
- dont_descend = True;
+ dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end,
+ requires_resume_key, resume_key, resume_name, continue_bit, info_level));
+
+ switch (info_level) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ case SMB_FIND_FILE_NAMES_INFO:
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ break;
+ case SMB_FIND_FILE_UNIX:
+ if (!lp_unix_extensions())
+ return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ break;
+ default:
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ }
+
+ pdata = Realloc( *ppdata, max_data_bytes + 1024);
+ if(pdata == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+
+ *ppdata = pdata;
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
+
+ /* Realloc the params space */
+ params = Realloc(*pparams, 6*SIZEOFWORD);
+ if( params == NULL )
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *pparams = params;
+
+ /* Check that the dptr is valid */
+ if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num)))
+ return ERROR_DOS(ERRDOS,ERRnofiles);
+
+ string_set(&conn->dirpath,dptr_path(dptr_num));
+
+ /* Get the wildcard mask from the dptr */
+ if((p = dptr_wcard(dptr_num))== NULL) {
+ DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
+ return ERROR_DOS(ERRDOS,ERRnofiles);
+ }
+ pstrcpy(mask, p);
+ pstrcpy(directory,conn->dirpath);
+
+ /* Get the attr mask from the dptr */
+ dirtype = dptr_attr(dptr_num);
+
+ DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n",
+ dptr_num, mask, dirtype, (long)conn->dirptr, TellDir(conn->dirptr)));
+
+ /* We don't need to check for VOL here as this is returned by
+ a different TRANS2 call. */
+
+ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive))
+ dont_descend = True;
- p = pdata;
- space_remaining = max_data_bytes;
- out_of_space = False;
-
- /*
- * Seek to the correct position. We no longer use the resume key but
- * depend on the last file name instead.
- */
- if(requires_resume_key && *resume_name && !continue_bit)
- {
- /*
- * Fix for NT redirector problem triggered by resume key indexes
- * changing between directory scans. We now return a resume key of 0
- * and instead look for the filename to continue from (also given
- * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
- * findfirst/findnext (as is usual) then the directory pointer
- * should already be at the correct place. Check this by scanning
- * backwards looking for an exact (ie. case sensitive) filename match.
- * If we get to the beginning of the directory and haven't found it then scan
- * forwards again looking for a match. JRA.
- */
-
- int current_pos, start_pos;
- char *dname = NULL;
- void *dirptr = conn->dirptr;
- start_pos = TellDir(dirptr);
- for(current_pos = start_pos; current_pos >= 0; current_pos--)
- {
- DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos));
-
- SeekDir(dirptr, current_pos);
- dname = ReadDirName(dirptr);
-
- /*
- * Remember, name_map_mangle is called by
- * get_lanman2_dir_entry(), so the resume name
- * could be mangled. Ensure we do the same
- * here.
- */
-
- if(dname != NULL)
- name_map_mangle( dname, False, True, SNUM(conn));
-
- if(dname && strcsequal( resume_name, dname))
- {
- SeekDir(dirptr, current_pos+1);
- DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
- break;
- }
- }
-
- /*
- * Scan forward from start if not found going backwards.
- */
-
- if(current_pos < 0)
- {
- DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos));
- SeekDir(dirptr, start_pos);
- for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos))
- {
- /*
- * Remember, name_map_mangle is called by
- * get_lanman2_dir_entry(), so the resume name
- * could be mangled. Ensure we do the same
- * here.
- */
-
- if(dname != NULL)
- name_map_mangle( dname, False, True, SNUM(conn));
-
- if(dname && strcsequal( resume_name, dname))
- {
- SeekDir(dirptr, current_pos+1);
- DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
- break;
- }
- } /* end for */
- } /* end if current_pos */
- } /* end if requires_resume_key && !continue_bit */
-
- for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
- {
- BOOL got_exact_match = False;
-
- /* this is a heuristic to avoid seeking the dirptr except when
- absolutely necessary. It allows for a filename of about 40 chars */
- if (space_remaining < DIRLEN_GUESS && numentries > 0)
- {
- out_of_space = True;
- finished = False;
- }
- else
- {
- finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
- requires_resume_key,dont_descend,
- &p,pdata,space_remaining, &out_of_space, &got_exact_match,
- &last_name_off);
- }
-
- if (finished && out_of_space)
- finished = False;
-
- if (!finished && !out_of_space)
- numentries++;
-
- /*
- * As an optimisation if we know we aren't looking
- * for a wildcard name (ie. the name matches the wildcard exactly)
- * then we can finish on any (first) match.
- * This speeds up large directory searches. JRA.
- */
-
- if(got_exact_match)
- finished = True;
-
- space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
- }
+ p = pdata;
+ space_remaining = max_data_bytes;
+ out_of_space = False;
+
+ /*
+ * Seek to the correct position. We no longer use the resume key but
+ * depend on the last file name instead.
+ */
+
+ if(requires_resume_key && *resume_name && !continue_bit) {
+
+ /*
+ * Fix for NT redirector problem triggered by resume key indexes
+ * changing between directory scans. We now return a resume key of 0
+ * and instead look for the filename to continue from (also given
+ * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
+ * findfirst/findnext (as is usual) then the directory pointer
+ * should already be at the correct place. Check this by scanning
+ * backwards looking for an exact (ie. case sensitive) filename match.
+ * If we get to the beginning of the directory and haven't found it then scan
+ * forwards again looking for a match. JRA.
+ */
+
+ int current_pos, start_pos;
+ char *dname = NULL;
+ void *dirptr = conn->dirptr;
+ start_pos = TellDir(dirptr);
+
+ for(current_pos = start_pos; current_pos >= 0; current_pos--) {
+ DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos));
+
+ SeekDir(dirptr, current_pos);
+ dname = ReadDirName(dirptr);
+
+ /*
+ * Remember, name_map_mangle is called by
+ * get_lanman2_dir_entry(), so the resume name
+ * could be mangled. Ensure we do the same
+ * here.
+ */
+
+ if(dname != NULL)
+ name_map_mangle( dname, False, True, SNUM(conn));
+
+ if(dname && strcsequal( resume_name, dname)) {
+ SeekDir(dirptr, current_pos+1);
+ DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
+ break;
+ }
+ }
+
+ /*
+ * Scan forward from start if not found going backwards.
+ */
+
+ if(current_pos < 0) {
+ DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos));
+ SeekDir(dirptr, start_pos);
+ for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) {
+
+ /*
+ * Remember, name_map_mangle is called by
+ * get_lanman2_dir_entry(), so the resume name
+ * could be mangled. Ensure we do the same
+ * here.
+ */
+
+ if(dname != NULL)
+ name_map_mangle( dname, False, True, SNUM(conn));
+
+ if(dname && strcsequal( resume_name, dname)) {
+ SeekDir(dirptr, current_pos+1);
+ DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
+ break;
+ }
+ } /* end for */
+ } /* end if current_pos */
+ } /* end if requires_resume_key && !continue_bit */
+
+ for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
+ BOOL got_exact_match = False;
+
+ /* this is a heuristic to avoid seeking the dirptr except when
+ absolutely necessary. It allows for a filename of about 40 chars */
+
+ if (space_remaining < DIRLEN_GUESS && numentries > 0) {
+ out_of_space = True;
+ finished = False;
+ } else {
+ finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
+ requires_resume_key,dont_descend,
+ &p,pdata,space_remaining, &out_of_space, &got_exact_match,
+ &last_name_off);
+ }
+
+ if (finished && out_of_space)
+ finished = False;
+
+ if (!finished && !out_of_space)
+ numentries++;
+
+ /*
+ * As an optimisation if we know we aren't looking
+ * for a wildcard name (ie. the name matches the wildcard exactly)
+ * then we can finish on any (first) match.
+ * This speeds up large directory searches. JRA.
+ */
+
+ if(got_exact_match)
+ finished = True;
+
+ space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ }
- /* Check if we can close the dirptr */
- if(close_after_request || (finished && close_if_end))
- {
- DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
- dptr_close(&dptr_num); /* This frees up the saved mask */
- }
+ /* Check if we can close the dirptr */
+ if(close_after_request || (finished && close_if_end)) {
+ DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
+ dptr_close(&dptr_num); /* This frees up the saved mask */
+ }
- /* Set up the return parameter block */
- SSVAL(params,0,numentries);
- SSVAL(params,2,finished);
- SSVAL(params,4,0); /* Never an EA error */
- SSVAL(params,6,last_name_off);
+ /* Set up the return parameter block */
+ SSVAL(params,0,numentries);
+ SSVAL(params,2,finished);
+ SSVAL(params,4,0); /* Never an EA error */
+ SSVAL(params,6,last_name_off);
- send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata));
+ send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata));
- if ((! *directory) && dptr_path(dptr_num))
- slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
+ if ((! *directory) && dptr_path(dptr_num))
+ slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
- DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
- smb_fn_name(CVAL(inbuf,smb_com)),
- mask, directory, dirtype, numentries ) );
+ DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
+ smb_fn_name(CVAL(inbuf,smb_com)),
+ mask, directory, dirtype, numentries ) );
- return(-1);
+ return(-1);
}
/****************************************************************************
- reply to a TRANS2_QFSINFO (query filesystem info)
+ Reply to a TRANS2_QFSINFO (query filesystem info).
****************************************************************************/
-static int call_trans2qfsinfo(connection_struct *conn,
- char *inbuf, char *outbuf,
- int length, int bufsize,
- char **pparams, char **ppdata)
+static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
- char *pdata = *ppdata;
- char *params = *pparams;
- uint16 info_level = SVAL(params,0);
- int data_len;
- SMB_STRUCT_STAT st;
- char *vname = volume_label(SNUM(conn));
- int snum = SNUM(conn);
- char *fstype = lp_fstype(SNUM(conn));
-
- DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
-
- if(vfs_stat(conn,".",&st)!=0) {
- DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
- return (ERROR(ERRSRV,ERRinvdevice));
- }
-
- pdata = Realloc(*ppdata, max_data_bytes + 1024);
- if ( pdata == NULL ) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *ppdata = pdata;
- memset((char *)pdata,'\0',max_data_bytes + 1024);
-
- switch (info_level)
- {
- case 1:
- {
- SMB_BIG_UINT dfree,dsize,bsize;
- data_len = 18;
- conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
- SIVAL(pdata,l1_idFileSystem,st.st_dev);
- SIVAL(pdata,l1_cSectorUnit,bsize/512);
- SIVAL(pdata,l1_cUnit,dsize);
- SIVAL(pdata,l1_cUnitAvail,dfree);
- SSVAL(pdata,l1_cbSector,512);
- DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n",
- (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize,
- (unsigned int)dfree, 512));
- break;
- }
- case 2:
- {
- /* Return volume name */
- int volname_len = MIN(strlen(vname),11);
- data_len = l2_vol_szVolLabel + volname_len + 1;
- /*
- * Add volume serial number - hash of a combination of
- * the called hostname and the service name.
- */
- SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) );
- SCVAL(pdata,l2_vol_cch,volname_len);
- StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len);
- DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",
- (unsigned)st.st_ctime, volname_len,
- pdata+l2_vol_szVolLabel));
- break;
- }
- case SMB_QUERY_FS_ATTRIBUTE_INFO:
- {
- int fstype_len;
- SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
- FILE_DEVICE_IS_MOUNTED|
- (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */
+ int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
+ char *pdata = *ppdata;
+ char *params = *pparams;
+ uint16 info_level;
+ int data_len;
+ SMB_STRUCT_STAT st;
+ char *vname = volume_label(SNUM(conn));
+ int snum = SNUM(conn);
+ char *fstype = lp_fstype(SNUM(conn));
+
+ if (total_params < 2)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ info_level = SVAL(params,0);
+ DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
+
+ if(vfs_stat(conn,".",&st)!=0) {
+ DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
+ return ERROR_DOS(ERRSRV,ERRinvdevice);
+ }
+
+ pdata = Realloc(*ppdata, max_data_bytes + 1024);
+ if ( pdata == NULL )
+ return ERROR_DOS(ERRDOS,ERRnomem);
+
+ *ppdata = pdata;
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
+
+ switch (info_level) {
+ case 1:
+ {
+ SMB_BIG_UINT dfree,dsize,bsize;
+ data_len = 18;
+ conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
+ SIVAL(pdata,l1_idFileSystem,st.st_dev);
+ SIVAL(pdata,l1_cSectorUnit,bsize/512);
+ SIVAL(pdata,l1_cUnit,dsize);
+ SIVAL(pdata,l1_cUnitAvail,dfree);
+ SSVAL(pdata,l1_cbSector,512);
+ DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n",
+ (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize,
+ (unsigned int)dfree, 512));
+ break;
+ }
+
+ case 2:
+ {
+ /* Return volume name */
+ int volname_len = MIN(strlen(vname),11);
+ data_len = l2_vol_szVolLabel + volname_len + 1;
+ /*
+ * Add volume serial number - hash of a combination of
+ * the called hostname and the service name.
+ */
+ SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) );
+ SCVAL(pdata,l2_vol_cch,volname_len);
+ StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len);
+ DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",
+ (unsigned)st.st_ctime, volname_len,
+ pdata+l2_vol_szVolLabel));
+ break;
+ }
+
+ case SMB_QUERY_FS_ATTRIBUTE_INFO:
+ case SMB_FS_ATTRIBUTE_INFORMATION:
+ {
+ int fstype_len;
+ SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
+ (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */
#if 0 /* Old code. JRA. */
- SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */
- SIVAL(pdata,0,0x700FF);
+ SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */
+ SIVAL(pdata,0,0x700FF);
#endif /* Old code. */
- SIVAL(pdata,4,255); /* Max filename component length */
- fstype_len = dos_PutUniCode(pdata+12,unix_to_dos(fstype,False),sizeof(pstring), False);
- SIVAL(pdata,8,fstype_len);
- data_len = 12 + fstype_len;
- SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS);
- break;
- }
- case SMB_QUERY_FS_LABEL_INFO:
- data_len = 4 + strlen(vname);
- SIVAL(pdata,0,strlen(vname));
- pstrcpy(pdata+4,vname);
- break;
- case SMB_QUERY_FS_VOLUME_INFO:
-
- /*
- * Add volume serial number - hash of a combination of
- * the called hostname and the service name.
- */
- SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^
- (str_checksum(local_machine)<<16));
-
- /* NT4 always serves this up as unicode but expects it to be
- * delivered as ascii! (tridge && JRA)
- */
- if ((get_remote_arch() != RA_WIN2K) && (global_client_caps & CAP_NT_SMBS)) {
- data_len = 18 + strlen(vname);
- SIVAL(pdata,12,strlen(vname));
- pstrcpy(pdata+18,vname);
- } else {
- int vnamelen;
-
- vnamelen = dos_PutUniCode(pdata+18, vname, sizeof(pstring), False);
- data_len = 18 + vnamelen;
- SIVAL(pdata,12,vnamelen);
- SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS);
- }
-
- DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n",
- (int)strlen(vname),vname));
- break;
- case SMB_QUERY_FS_SIZE_INFO:
- {
- SMB_BIG_UINT dfree,dsize,bsize;
- data_len = 24;
- conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
- SBIG_UINT(pdata,0,dsize);
- SBIG_UINT(pdata,8,dfree);
- SIVAL(pdata,16,bsize/512);
- SIVAL(pdata,20,512);
- break;
- }
- case SMB_QUERY_FS_DEVICE_INFO:
- data_len = 8;
- SIVAL(pdata,0,0); /* dev type */
- SIVAL(pdata,4,0); /* characteristics */
- break;
- case SMB_MAC_QUERY_FS_INFO:
- /*
- * Thursby MAC extension... ONLY on NTFS filesystems
- * once we do streams then we don't need this
- */
- if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
- data_len = 88;
- SIVAL(pdata,84,0x100); /* Don't support mac... */
- break;
- }
- /* drop through */
- default:
- return(ERROR(ERRDOS,ERRunknownlevel));
- }
-
-
- send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len);
-
- DEBUG( 4, ( "%s info_level = %d\n",
- smb_fn_name(CVAL(inbuf,smb_com)), info_level) );
-
- return -1;
+ SIVAL(pdata,4,255); /* Max filename component length */
+ /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
+ and will think we can't do long filenames */
+ fstype_len = dos_PutUniCode(pdata+12,unix_to_dos(fstype,False),sizeof(pstring), False);
+ SIVAL(pdata,8,fstype_len);
+ data_len = 12 + fstype_len;
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS);
+ break;
+ }
+
+ case SMB_QUERY_FS_LABEL_INFO:
+ case SMB_FS_LABEL_INFORMATION:
+ data_len = 4 + strlen(vname);
+ SIVAL(pdata,0,strlen(vname));
+ pstrcpy(pdata+4,vname);
+ break;
+
+ case SMB_QUERY_FS_VOLUME_INFO:
+ case SMB_FS_VOLUME_INFORMATION:
+ /*
+ * Add volume serial number - hash of a combination of
+ * the called hostname and the service name.
+ */
+ SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^
+ (str_checksum(local_machine)<<16));
+
+ /* NT4 always serves this up as unicode but expects it to be
+ * delivered as ascii! (tridge && JRA)
+ */
+ if ((get_remote_arch() != RA_WIN2K) && (global_client_caps & CAP_NT_SMBS)) {
+ data_len = 18 + strlen(vname);
+ SIVAL(pdata,12,strlen(vname));
+ pstrcpy(pdata+18,vname);
+ } else {
+ int vnamelen;
+
+ vnamelen = dos_PutUniCode(pdata+18, vname, sizeof(pstring), False);
+ data_len = 18 + vnamelen;
+ SIVAL(pdata,12,vnamelen);
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS);
+ }
+
+ DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n",
+ (int)strlen(vname),vname));
+ break;
+
+ case SMB_QUERY_FS_SIZE_INFO:
+ case SMB_FS_SIZE_INFORMATION:
+ {
+ SMB_BIG_UINT dfree,dsize,bsize;
+ data_len = 24;
+ conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
+ SBIG_UINT(pdata,0,dsize);
+ SBIG_UINT(pdata,8,dfree);
+ SIVAL(pdata,16,bsize/512);
+ SIVAL(pdata,20,512);
+ break;
+ }
+
+ case SMB_FS_FULL_SIZE_INFORMATION:
+ {
+ SMB_BIG_UINT dfree,dsize,bsize;
+ data_len = 32;
+ conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
+ SBIG_UINT(pdata,0,dsize);
+ SBIG_UINT(pdata,8,dsize);
+ SBIG_UINT(pdata,16,dfree);
+ SIVAL(pdata,24,bsize/512);
+ SIVAL(pdata,28,512);
+ break;
+ }
+
+ case SMB_QUERY_FS_DEVICE_INFO:
+ case SMB_FS_DEVICE_INFORMATION:
+ data_len = 8;
+ SIVAL(pdata,0,0); /* dev type */
+ SIVAL(pdata,4,0); /* characteristics */
+ break;
+
+ case SMB_FS_OBJECTID_INFORMATION:
+ data_len = 64;
+ break;
+
+ /*
+ * Query the version and capabilities of the CIFS UNIX extensions
+ * in use.
+ */
+
+ case SMB_QUERY_CIFS_UNIX_INFO:
+
+ if (!lp_unix_extensions())
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+
+ data_len = 12;
+ SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
+ SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
+ SBIG_UINT(pdata,4,((SMB_BIG_UINT)0)); /* No capabilities for now... */
+ break;
+
+ case SMB_MAC_QUERY_FS_INFO:
+ /*
+ * Thursby MAC extension... ONLY on NTFS filesystems
+ * once we do streams then we don't need this
+ */
+ if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
+ data_len = 88;
+ SIVAL(pdata,84,0x100); /* Don't support mac... */
+ break;
+ }
+ /* drop through */
+ default:
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ }
+
+ send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len);
+
+ DEBUG( 4, ( "%s info_level = %d\n", smb_fn_name(CVAL(inbuf,smb_com)), info_level) );
+
+ return -1;
}
/****************************************************************************
- reply to a TRANS2_SETFSINFO (set filesystem info)
+ Reply to a TRANS2_SETFSINFO (set filesystem info).
****************************************************************************/
-static int call_trans2setfsinfo(connection_struct *conn,
- char *inbuf, char *outbuf, int length,
- int bufsize,
- char **pparams, char **ppdata)
+
+static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- /* Just say yes we did it - there is nothing that
- can be set here so it doesn't matter. */
- int outsize;
- DEBUG(3,("call_trans2setfsinfo\n"));
+ /* Just say yes we did it - there is nothing that
+ can be set here so it doesn't matter. */
+ int outsize;
+ DEBUG(3,("call_trans2setfsinfo\n"));
+
+ if (!CAN_WRITE(conn))
+ return(ERROR_DOS(ERRSRV,ERRaccess));
- if (!CAN_WRITE(conn))
- return(ERROR(ERRSRV,ERRaccess));
+ outsize = set_message(outbuf,10,0,True);
- outsize = set_message(outbuf,10,0,True);
+ return outsize;
+}
+
+/****************************************************************************
+ Utility function to set bad path error.
+****************************************************************************/
- return outsize;
+void set_bad_path_error(int err, BOOL bad_path)
+{
+ if((err == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
}
/****************************************************************************
@@ -1291,11 +1522,8 @@ static int call_trans2setfsinfo(connection_struct *conn,
file name or file id).
****************************************************************************/
-static int call_trans2qfilepathinfo(connection_struct *conn,
- char *inbuf, char *outbuf, int length,
- int bufsize,
- char **pparams,char **ppdata,
- int total_data)
+static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *params = *pparams;
@@ -1304,10 +1532,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
uint16 info_level;
int mode=0;
SMB_OFF_T size=0;
+ SMB_OFF_T allocation_size=0;
unsigned int data_size;
SMB_STRUCT_STAT sbuf;
pstring fname1;
char *fname;
+ char *fullpathname;
char *p;
int l;
SMB_OFF_T pos = 0;
@@ -1316,7 +1546,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
time_t c_time;
if (tran_call == TRANSACT2_QFILEINFO) {
- files_struct *fsp = file_fsp(params,0);
+ files_struct *fsp;
+
+ if (total_params < 4)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ fsp = file_fsp(params,0);
info_level = SVAL(params,2);
DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
@@ -1329,14 +1564,22 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
*/
fname = fsp->fsp_name;
unix_convert(fname,conn,0,&bad_path,&sbuf);
- if (!check_name(fname,conn) ||
- (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) {
- DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+ if (!check_name(fname,conn)) {
+ DEBUG(3,("call_trans2qfilepathinfo: check_name of %s failed (%s)\n",fname,strerror(errno)));
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ /* Always do lstat for UNIX calls. */
+ if (vfs_lstat(conn,fname,&sbuf)) {
+ DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno)));
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRbadpath));
}
+ } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) {
+ DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno)));
+ set_bad_path_error(errno, bad_path);
return(UNIXERROR(ERRDOS,ERRbadpath));
}
@@ -1361,6 +1604,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
}
} else {
/* qpathinfo */
+ if (total_params < 6)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
info_level = SVAL(params,0);
DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
@@ -1371,16 +1617,29 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
unix_convert(fname,conn,0,&bad_path,&sbuf);
- if (!check_name(fname,conn) || (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) {
- DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
+ if (!check_name(fname,conn)) {
+ DEBUG(3,("call_trans2qfilepathinfo: check_name of %s failed (%s)\n",fname,strerror(errno)));
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ /* Always do lstat for UNIX calls. */
+ if (vfs_lstat(conn,fname,&sbuf)) {
+ DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno)));
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRbadpath));
}
+ } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) {
+ DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno)));
+ set_bad_path_error(errno, bad_path);
return(UNIXERROR(ERRDOS,ERRbadpath));
}
}
+
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+
DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
fname,info_level,tran_call,total_data));
@@ -1391,7 +1650,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
p++;
l = strlen(p);
mode = dos_mode(conn,fname,&sbuf);
+ fullpathname = fname;
size = sbuf.st_size;
+ allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size);
if (mode & aDIR)
size = 0;
@@ -1400,19 +1661,19 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
params = Realloc(*pparams,2);
if ( params == NULL )
- return(ERROR(ERRDOS,ERRnomem));
+ return ERROR_DOS(ERRDOS,ERRnomem);
*pparams = params;
memset((char *)params,'\0',2);
data_size = max_data_bytes + 1024;
pdata = Realloc(*ppdata, data_size);
if ( pdata == NULL )
- return(ERROR(ERRDOS,ERRnomem));
+ return ERROR_DOS(ERRDOS,ERRnomem);
*ppdata = pdata;
if (total_data > 0 && IVAL(pdata,0) == total_data) {
/* uggh, EAs for OS2 */
DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
- return(ERROR(ERRDOS,ERReasnotsupported));
+ return ERROR_DOS(ERRDOS,ERReasnotsupported);
}
memset((char *)pdata,'\0',data_size);
@@ -1434,7 +1695,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
SIVAL(pdata,l1_cbFile,(uint32)size);
- SIVAL(pdata,l1_cbFileAlloc,SMB_ROUNDUP(size,1024));
+ SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
SSVAL(pdata,l1_attrFile,mode);
SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
break;
@@ -1445,7 +1706,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
put_dos_date2(pdata,4,sbuf.st_atime);
put_dos_date2(pdata,8,sbuf.st_mtime);
SIVAL(pdata,12,(uint32)size);
- SIVAL(pdata,16,SMB_ROUNDUP(size,1024));
+ SIVAL(pdata,16,(uint32)allocation_size);
SIVAL(pdata,20,mode);
break;
@@ -1455,7 +1716,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
break;
case 6:
- return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */
+ return ERROR_DOS(ERRDOS,ERRbadfunc); /* os/2 needs this */
case SMB_FILE_BASIC_INFORMATION:
case SMB_QUERY_FILE_BASIC_INFO:
@@ -1489,12 +1750,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
case SMB_FILE_STANDARD_INFORMATION:
case SMB_QUERY_FILE_STANDARD_INFO:
- data_size = 22;
- SOFF_T(pdata,0,size);
+ data_size = 24;
+ /* Fake up allocation size. */
+ SOFF_T(pdata,0,allocation_size);
SOFF_T(pdata,8,size);
SIVAL(pdata,16,sbuf.st_nlink);
- CVAL(pdata,20) = 0;
- CVAL(pdata,21) = (mode&aDIR)?1:0;
+ SCVAL(pdata,20,0);
+ SCVAL(pdata,21,(mode&aDIR)?1:0);
break;
case SMB_FILE_EA_INFORMATION:
@@ -1541,9 +1803,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
break;
case SMB_FILE_ALLOCATION_INFORMATION:
- case SMB_FILE_END_OF_FILE_INFORMATION:
case SMB_QUERY_FILE_ALLOCATION_INFO:
+ data_size = 8;
+ SOFF_T(pdata,0,allocation_size);
+ break;
+
case SMB_QUERY_FILE_END_OF_FILEINFO:
+ case SMB_FILE_END_OF_FILE_INFORMATION:
data_size = 8;
SOFF_T(pdata,0,size);
break;
@@ -1555,11 +1821,11 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
put_long_date(pdata+24,sbuf.st_mtime); /* change time */
SIVAL(pdata,32,mode);
pdata += 40;
- SOFF_T(pdata,0,size);
+ SOFF_T(pdata,0,allocation_size);
SOFF_T(pdata,8,size);
SIVAL(pdata,16,sbuf.st_nlink);
- CVAL(pdata,20) = delete_pending;
- CVAL(pdata,21) = (mode&aDIR)?1:0;
+ SCVAL(pdata,20,delete_pending);
+ SCVAL(pdata,21,(mode&aDIR)?1:0);
pdata += 24;
SINO_T(pdata,0,(SMB_INO_T)sbuf.st_ino);
pdata += 8; /* index number */
@@ -1608,7 +1874,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
case SMB_FILE_DISPOSITION_INFORMATION:
data_size = 1;
- CVAL(pdata,0) = delete_pending;
+ SCVAL(pdata,0,delete_pending);
break;
case SMB_FILE_POSITION_INFORMATION:
@@ -1668,7 +1934,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
SIVAL(pdata,0,0); /* ??? */
SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
SOFF_T(pdata,8,size);
- SIVAL(pdata,16,0x20); /* ??? */
+ SIVAL(pdata,16,allocation_size);
SIVAL(pdata,20,0); /* ??? */
data_size = 24 + byte_len;
}
@@ -1686,7 +1952,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
put_long_date(pdata+8,sbuf.st_atime);
put_long_date(pdata+16,sbuf.st_mtime); /* write time */
put_long_date(pdata+24,sbuf.st_mtime); /* change time */
- SOFF_T(pdata,32,(SMB_OFF_T)0x20); /* Allocation size. */
+ SOFF_T(pdata,32,allocation_size); /* Allocation size. */
SOFF_T(pdata,40,size);
SIVAL(pdata,48,mode);
SIVAL(pdata,52,0); /* ??? */
@@ -1703,20 +1969,112 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
/*
* NT4 server just returns "invalid query" to this - if we try to answer
* it then NTws gets a BSOD! (tridge).
+ * W2K seems to want this. JRA.
*/
case SMB_QUERY_FILE_STREAM_INFO:
+ if (get_remote_arch() != RA_WIN2K)
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
data_size = 24 + l;
SIVAL(pdata,0,pos);
SIVAL(pdata,4,size);
- SIVAL(pdata,12,size);
+ SIVAL(pdata,12,allocation_size);
SIVAL(pdata,20,l);
pstrcpy(pdata+24,fname);
break;
#endif
+ /*
+ * CIFS UNIX Extensions.
+ */
+
+ case SMB_QUERY_FILE_UNIX_BASIC:
+
+ DEBUG(4,("call_trans2qfilepathinfo: st_mode=%o\n",(int)sbuf.st_mode));
+
+ SOFF_T(pdata,0,sbuf.st_size); /* File size 64 Bit */
+ pdata += 8;
+
+#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
+ SOFF_T(pdata,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */
+#else
+ /* Can't get the value - fake it using size. */
+ SOFF_T(pdata,0,sbuf.st_size); /* Number of bytes used on disk - 64 Bit */
+#endif
+ pdata += 8;
+
+ put_long_date(pdata,sbuf.st_ctime); /* Creation Time 64 Bit */
+ put_long_date(pdata+8,sbuf.st_atime); /* Last access time 64 Bit */
+ put_long_date(pdata+16,sbuf.st_mtime); /* Last modification time 64 Bit */
+ pdata += 24;
+
+ SIVAL(pdata,0,sbuf.st_uid); /* user id for the owner */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SIVAL(pdata,0,sbuf.st_gid); /* group id of owner */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SIVAL(pdata,0,unix_filetype(sbuf.st_mode));
+ pdata += 4;
+
+ SIVAL(pdata,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SIVAL(pdata,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SINO_T(pdata,0,(SMB_INO_T)sbuf.st_ino); /* inode number */
+ pdata += 8;
+
+ SIVAL(pdata,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SIVAL(pdata,0,sbuf.st_nlink); /* number of hard links */
+ SIVAL(pdata,4,0);
+ pdata += 8+1;
+ data_size = PTR_DIFF(pdata,(*ppdata));
+
+ {
+ int i;
+ DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC"));
+
+ for (i=0; i<100; i++)
+ DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
+ DEBUG(4,("\n"));
+ }
+
+ break;
+
+ case SMB_QUERY_FILE_UNIX_LINK:
+ {
+ pstring buffer;
+ int len;
+
+#ifdef S_ISLNK
+ if(!S_ISLNK(sbuf.st_mode))
+ return(UNIXERROR(ERRSRV,ERRbadlink));
+#else
+ return(UNIXERROR(ERRDOS,ErrNotALink));
+#endif
+ len = conn->vfs_ops.readlink(conn,dos_to_unix(fullpathname,False), buffer, sizeof(pstring)-1); /* read link */
+ if (len == -1)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ buffer[len] = 0;
+ unix_to_dos(buffer,True);
+ pstrcpy(pdata,buffer); /* write '\0' terminated string */
+ pdata += strlen(buffer)+1;
+ data_size = PTR_DIFF(pdata,(*ppdata));
+
+ break;
+ }
+
default:
- return(ERROR(ERRDOS,ERRunknownlevel));
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
}
send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size);
@@ -1725,619 +2083,906 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
}
/****************************************************************************
- reply to a TRANS2_SETFILEINFO (set file info by fileid)
+ Deal with the internal needs of setting the delete on close flag. Note that
+ as the tdb locking is recursive, it is safe to call this from within
+ open_file_shared. JRA.
****************************************************************************/
-static int call_trans2setfilepathinfo(connection_struct *conn,
- char *inbuf, char *outbuf, int length,
- int bufsize, char **pparams,
- char **ppdata, int total_data)
+
+NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close)
{
- char *params = *pparams;
- char *pdata = *ppdata;
- uint16 tran_call = SVAL(inbuf, smb_setup0);
- uint16 info_level;
- int mode=0;
- SMB_OFF_T size=0;
- struct utimbuf tvs;
- SMB_STRUCT_STAT sbuf;
- pstring fname1;
- char *fname = NULL;
- int fd = -1;
- BOOL bad_path = False;
- files_struct *fsp = NULL;
-
- if (tran_call == TRANSACT2_SETFILEINFO) {
- fsp = file_fsp(params,0);
- info_level = SVAL(params,2);
-
- if(fsp && (fsp->is_directory || fsp->stat_open)) {
- /*
- * This is actually a SETFILEINFO on a directory
- * handle (returned from an NT SMB). NT5.0 seems
- * to do this call. JRA.
- */
- fname = fsp->fsp_name;
- unix_convert(fname,conn,0,&bad_path,&sbuf);
- if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) {
- DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,ERRbadpath));
- }
- } else if (fsp && fsp->print_file) {
- /*
- * Doing a DELETE_ON_CLOSE should cancel a print job.
- */
- if (((info_level == SMB_SET_FILE_DISPOSITION_INFO)||(info_level == SMB_FILE_DISPOSITION_INFORMATION)) &&
- CVAL(pdata,0)) {
- fsp->share_mode = FILE_DELETE_ON_CLOSE;
-
- DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n",
- fsp->fsp_name ));
-
- SSVAL(params,0,0);
- send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
- return(-1);
- }
- } else {
- /*
- * Original code - this is an open file.
- */
- CHECK_FSP(fsp,conn);
-
- fname = fsp->fsp_name;
- fd = fsp->fd;
-
- if (vfs_fstat(fsp,fd,&sbuf) != 0) {
- DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
- return(UNIXERROR(ERRDOS,ERRbadfid));
- }
- }
- } else {
- /* set path info */
- info_level = SVAL(params,0);
- fname = fname1;
- pstrcpy(fname,&params[6]);
- unix_convert(fname,conn,0,&bad_path,&sbuf);
- if(!check_name(fname, conn))
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,ERRbadpath));
- }
-
- if(!VALID_STAT(sbuf)) {
- DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,ERRbadpath));
- }
- }
-
- if (!CAN_WRITE(conn))
- return(ERROR(ERRSRV,ERRaccess));
-
- DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
- tran_call,fname,info_level,total_data));
-
- /* Realloc the parameter and data sizes */
- params = Realloc(*pparams,2);
- if(params == NULL) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *pparams = params;
-
- SSVAL(params,0,0);
-
- size = sbuf.st_size;
- tvs.modtime = sbuf.st_mtime;
- tvs.actime = sbuf.st_atime;
- mode = dos_mode(conn,fname,&sbuf);
-
- if (total_data > 4 && IVAL(pdata,0) == total_data) {
- /* uggh, EAs for OS2 */
- DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
- return(ERROR(ERRDOS,ERReasnotsupported));
- }
-
- switch (info_level)
- {
- case SMB_INFO_STANDARD:
- case SMB_INFO_QUERY_EA_SIZE:
- {
- /* access time */
- tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
-
- /* write time */
- tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
-
- mode = SVAL(pdata,l1_attrFile);
- size = IVAL(pdata,l1_cbFile);
- break;
- }
-
- /* XXXX um, i don't think this is right.
- it's also not in the cifs6.txt spec.
- */
- case SMB_INFO_QUERY_EAS_FROM_LIST:
- tvs.actime = make_unix_date2(pdata+8);
- tvs.modtime = make_unix_date2(pdata+12);
- size = IVAL(pdata,16);
- mode = IVAL(pdata,24);
- break;
-
- /* XXXX nor this. not in cifs6.txt, either. */
- case SMB_INFO_QUERY_ALL_EAS:
- tvs.actime = make_unix_date2(pdata+8);
- tvs.modtime = make_unix_date2(pdata+12);
- size = IVAL(pdata,16);
- mode = IVAL(pdata,24);
- break;
-
- case SMB_SET_FILE_BASIC_INFO:
- case 1004:
- {
- /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
- time_t write_time;
- time_t changed_time;
-
- /* Ignore create time at offset pdata. */
-
- /* access time */
- tvs.actime = interpret_long_date(pdata+8);
-
- write_time = interpret_long_date(pdata+16);
- changed_time = interpret_long_date(pdata+24);
-
- tvs.modtime = MIN(write_time, changed_time);
-
- /* Prefer a defined time to an undefined one. */
- if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
- tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1
- ? changed_time
- : write_time);
-
- /* attributes */
- mode = IVAL(pdata,32);
- break;
- }
+ /*
+ * Only allow delete on close for writable shares.
+ */
- case SMB_FILE_ALLOCATION_INFORMATION:
- case SMB_SET_FILE_ALLOCATION_INFO:
- {
- int ret = -1;
- size = IVAL(pdata,0);
+ if (delete_on_close && !CAN_WRITE(fsp->conn)) {
+ DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but write access denied on share.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ /*
+ * Only allow delete on close for files/directories opened with delete intent.
+ */
+
+ if (delete_on_close && !GET_DELETE_ACCESS_REQUESTED(fsp->share_mode)) {
+ DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but delete access denied.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if(fsp->is_directory) {
+ fsp->directory_delete_on_close = delete_on_close;
+ DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, directory %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+ } else if(fsp->stat_open) {
+
+ DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, stat open %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+
+ } else {
+
+ files_struct *iterate_fsp;
+
+ /*
+ * Modify the share mode entry for all files open
+ * on this device and inode to tell other smbds we have
+ * changed the delete on close flag. This will be noticed
+ * in the close code, the last closer will delete the file
+ * if flag is set.
+ */
+
+ DEBUG(10,("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n",
+ delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name ));
+
+ if (lock_share_entry_fsp(fsp) == False)
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) {
+ DEBUG(0,("set_delete_on_close_internal: failed to change delete on close flag for file %s\n",
+ fsp->fsp_name ));
+ unlock_share_entry_fsp(fsp);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * Release the lock.
+ */
+
+ unlock_share_entry_fsp(fsp);
+
+ /*
+ * Go through all files we have open on the same device and
+ * inode (hanging off the same hash bucket) and set the DELETE_ON_CLOSE_FLAG.
+ * Other smbd's that have this file open will look in the share_mode on close.
+ * take care of this (rare) case in close_file(). See the comment there.
+ * NB. JRA. We don't really need to do this anymore - all should be taken
+ * care of in the share_mode changes in the tdb.
+ */
+
+ for(iterate_fsp = file_find_di_first(fsp->dev, fsp->inode);
+ iterate_fsp; iterate_fsp = file_find_di_next(iterate_fsp))
+ fsp->delete_on_close = delete_on_close;
+
+ /*
+ * Set the delete on close flag in the fsp.
+ */
+ fsp->delete_on_close = delete_on_close;
+
+ DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Returns true if this pathname is within the share, and thus safe.
+****************************************************************************/
+
+static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in, char *link_dest_out)
+{
+#ifdef PATH_MAX
+ char resolved_name[PATH_MAX+1];
+#else
+ pstring resolved_name;
+#endif
+ pstring link_dest;
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT sbuf;
+
+ pstrcpy(link_dest, link_dest_in);
+ unix_convert(link_dest,conn,0,&bad_path,&sbuf);
+
+ if (conn->vfs_ops.realpath(conn,dos_to_unix(link_dest,False),resolved_name) == NULL)
+ return -1;
+
+ pstrcpy(link_dest, unix_to_dos(resolved_name,False));
+
+ if (*link_dest != '/') {
+ /* Relative path. */
+ pstrcpy(link_dest_out, conn->connectpath);
+ pstrcat(link_dest_out, "/");
+ pstrcat(link_dest_out, link_dest);
+ } else {
+ pstrcpy(link_dest_out, link_dest);
+ }
+
+ /*
+ * Check if the link is within the share.
+ */
+
+ if (strncmp(conn->connectpath, link_dest_out, strlen(conn->connectpath))) {
+ errno = EACCES;
+ return -1;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ Reply to a TRANS2_SETFILEINFO (set file info by fileid).
+****************************************************************************/
+
+static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
+{
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ uint16 tran_call = SVAL(inbuf, smb_setup0);
+ uint16 info_level;
+ int dosmode = 0;
+ SMB_OFF_T size=0;
+ struct utimbuf tvs;
+ SMB_STRUCT_STAT sbuf;
+ pstring fname1;
+ char *fname = NULL;
+ int fd = -1;
+ BOOL bad_path = False;
+ files_struct *fsp = NULL;
+ uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
+ gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
+ mode_t unixmode = 0;
+
+ if (tran_call == TRANSACT2_SETFILEINFO) {
+
+ if (total_params < 4)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ fsp = file_fsp(params,0);
+ info_level = SVAL(params,2);
+
+ if(fsp && (fsp->is_directory || fsp->stat_open)) {
+ /*
+ * This is actually a SETFILEINFO on a directory
+ * handle (returned from an NT SMB). NT5.0 seems
+ * to do this call. JRA.
+ */
+ fname = fsp->fsp_name;
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) {
+ DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+ } else if (fsp && fsp->print_file) {
+ /*
+ * Doing a DELETE_ON_CLOSE should cancel a print job.
+ */
+ if (((info_level == SMB_SET_FILE_DISPOSITION_INFO)||(info_level == SMB_FILE_DISPOSITION_INFORMATION)) &&
+ CVAL(pdata,0)) {
+ fsp->share_mode = FILE_DELETE_ON_CLOSE;
+
+ DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n",
+ fsp->fsp_name ));
+
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
+ }
+ } else {
+ /*
+ * Original code - this is an open file.
+ */
+ CHECK_FSP(fsp,conn);
+
+ fname = fsp->fsp_name;
+ fd = fsp->fd;
+
+ if (vfs_fstat(fsp,fd,&sbuf) != 0) {
+ DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
+ return(UNIXERROR(ERRDOS,ERRbadfid));
+ }
+ }
+ } else {
+ /* set path info */
+ if (total_params < 6)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ info_level = SVAL(params,0);
+ fname = fname1;
+ pstrcpy(fname,&params[6]);
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if(!check_name(fname, conn)) {
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+
+ /*
+ * For CIFS UNIX extensions the target name may not exist.
+ */
+
+ if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) {
+
+ DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+ }
+
+ 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 (VALID_STAT(sbuf))
+ unixmode = sbuf.st_mode;
+
+ DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
+ tran_call,fname,info_level,total_data));
+
+ /* Realloc the parameter and data sizes */
+ params = Realloc(*pparams,2);
+ if(params == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *pparams = params;
+
+ SSVAL(params,0,0);
+
+ size = sbuf.st_size;
+ tvs.modtime = sbuf.st_mtime;
+ tvs.actime = sbuf.st_atime;
+ dosmode = dos_mode(conn,fname,&sbuf);
+ unixmode = sbuf.st_mode;
+
+ set_owner = VALID_STAT(sbuf) ? sbuf.st_uid : (uid_t)SMB_UID_NO_CHANGE;
+ set_grp = VALID_STAT(sbuf) ? sbuf.st_gid : (gid_t)SMB_GID_NO_CHANGE;
+
+ if (total_data > 4 && IVAL(pdata,0) == total_data) {
+ /* uggh, EAs for OS2 */
+ DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
+ return ERROR_DOS(ERRDOS,ERReasnotsupported);
+ }
+
+ switch (info_level) {
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
+ {
+ if (total_data < l1_cbFile+4)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ /* access time */
+ tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
+
+ /* write time */
+ tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
+
+ dosmode = SVAL(pdata,l1_attrFile);
+ size = IVAL(pdata,l1_cbFile);
+ break;
+ }
+
+ /* XXXX um, i don't think this is right.
+ it's also not in the cifs6.txt spec.
+ */
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ if (total_data < 28)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ tvs.actime = make_unix_date2(pdata+8);
+ tvs.modtime = make_unix_date2(pdata+12);
+ size = IVAL(pdata,16);
+ dosmode = IVAL(pdata,24);
+ break;
+
+ /* XXXX nor this. not in cifs6.txt, either. */
+ case SMB_INFO_QUERY_ALL_EAS:
+ if (total_data < 28)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ tvs.actime = make_unix_date2(pdata+8);
+ tvs.modtime = make_unix_date2(pdata+12);
+ size = IVAL(pdata,16);
+ dosmode = IVAL(pdata,24);
+ break;
+
+ case SMB_SET_FILE_BASIC_INFO:
+ case SMB_FILE_BASIC_INFORMATION:
+ {
+ /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
+ time_t write_time;
+ time_t changed_time;
+
+ if (total_data < 36)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ /* Ignore create time at offset pdata. */
+
+ /* access time */
+ tvs.actime = interpret_long_date(pdata+8);
+
+ write_time = interpret_long_date(pdata+16);
+ changed_time = interpret_long_date(pdata+24);
+
+ tvs.modtime = MIN(write_time, changed_time);
+
+ /* Prefer a defined time to an undefined one. */
+ if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
+ tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1
+ ? changed_time
+ : write_time);
+
+ /* attributes */
+ dosmode = IVAL(pdata,32);
+ break;
+ }
+
+ case SMB_FILE_ALLOCATION_INFORMATION:
+ case SMB_SET_FILE_ALLOCATION_INFO:
+ {
+ int ret = -1;
+ SMB_OFF_T allocation_size;
+
+ if (total_data < 8)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ allocation_size = IVAL(pdata,0);
#ifdef LARGE_SMB_OFF_T
- size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
+ allocation_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return(ERROR(ERRDOS,ERRunknownlevel));
+ if (IVAL(pdata,4) != 0) /* more than 32 bits? */
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
#endif /* LARGE_SMB_OFF_T */
- DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n",
- fname, (double)size ));
+ DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n",
+ fname, (double)allocation_size ));
- if(size != sbuf.st_size) {
+ if(allocation_size != sbuf.st_size) {
+ SMB_STRUCT_STAT new_sbuf;
- DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n",
- fname, (double)size ));
+ DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new allocation size to %.0f\n",
+ fname, (double)allocation_size ));
- if (fd == -1) {
- files_struct *new_fsp = NULL;
- int access_mode = 0;
- int action = 0;
+ if (fd == -1) {
+ files_struct *new_fsp = NULL;
+ int access_mode = 0;
+ int action = 0;
- if(global_oplock_break) {
- /* Queue this file modify as we are the process of an oplock break. */
+ if(global_oplock_break) {
+ /* Queue this file modify as we are the process of an oplock break. */
- DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being "));
- DEBUGADD(2,( "in oplock break state.\n"));
+ DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being "));
+ DEBUGADD(2,( "in oplock break state.\n"));
- push_oplock_pending_smb_message(inbuf, length);
- return -1;
- }
+ push_oplock_pending_smb_message(inbuf, length);
+ return -1;
+ }
+
+ new_fsp = open_file_shared(conn, fname, &sbuf,
+ SET_OPEN_MODE(DOS_OPEN_RDWR),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ 0, 0, &access_mode, &action);
- new_fsp = open_file_shared(conn, fname, &sbuf,
- SET_OPEN_MODE(DOS_OPEN_RDWR),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- 0, 0, &access_mode, &action);
-
- if (new_fsp == NULL)
- return(UNIXERROR(ERRDOS,ERRbadpath));
- ret = vfs_allocate_file_space(new_fsp, size);
- close_file(new_fsp,True);
- } else {
- ret = vfs_allocate_file_space(fsp, size);
- }
- if (ret == -1)
- return allocate_space_error(inbuf, outbuf, errno);
-
- sbuf.st_size = size;
- }
-
- break;
- }
+ if (new_fsp == NULL)
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ ret = vfs_allocate_file_space(new_fsp, allocation_size);
+ if (vfs_fstat(new_fsp,new_fsp->fd,&new_sbuf) != 0) {
+ DEBUG(3,("fstat of fnum %d failed (%s)\n",new_fsp->fnum, strerror(errno)));
+ ret = -1;
+ }
+ close_file(new_fsp,True);
+ } else {
+ ret = vfs_allocate_file_space(fsp, allocation_size);
+ if (vfs_fstat(fsp,fd,&new_sbuf) != 0) {
+ DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
+ ret = -1;
+ }
+ }
+ if (ret == -1)
+ return ERROR_NT(NT_STATUS_DISK_FULL);
- case SMB_FILE_END_OF_FILE_INFORMATION:
- case SMB_SET_FILE_END_OF_FILE_INFO:
- {
- size = IVAL(pdata,0);
+ /* Allocate can trucate size... */
+ size = new_sbuf.st_size;
+ }
+
+ break;
+ }
+
+ case SMB_FILE_END_OF_FILE_INFORMATION:
+ case SMB_SET_FILE_END_OF_FILE_INFO:
+ {
+ if (total_data < 8)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ size = IVAL(pdata,0);
#ifdef LARGE_SMB_OFF_T
- size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
+ size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return(ERROR(ERRDOS,ERRunknownlevel));
+ if (IVAL(pdata,4) != 0) /* more than 32 bits? */
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
#endif /* LARGE_SMB_OFF_T */
- DEBUG(10,("call_trans2setfilepathinfo: Set end of file info for file %s to %.0f\n", fname, (double)size ));
- break;
- }
+ DEBUG(10,("call_trans2setfilepathinfo: Set end of file info for file %s to %.0f\n", fname, (double)size ));
+ break;
+ }
- case SMB_FILE_DISPOSITION_INFORMATION:
- case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
- {
- BOOL delete_on_close = (CVAL(pdata,0) ? True : False);
+ case SMB_FILE_DISPOSITION_INFORMATION:
+ case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
+ {
+ BOOL delete_on_close;
+ NTSTATUS status;
- if (tran_call != TRANSACT2_SETFILEINFO)
- return(ERROR(ERRDOS,ERRunknownlevel));
+ if (total_data < 1)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
- if (fsp == NULL)
- return(UNIXERROR(ERRDOS,ERRbadfid));
+ delete_on_close = (CVAL(pdata,0) ? True : False);
- /*
- * Only allow delete on close for files/directories opened with delete intent.
- */
+ if (tran_call != TRANSACT2_SETFILEINFO)
+ return(ERROR_DOS(ERRDOS,ERRunknownlevel));
- if (delete_on_close && !GET_DELETE_ACCESS_REQUESTED(fsp->share_mode)) {
- DEBUG(10,("call_trans2setfilepathinfo: file %s delete on close flag set but delete access denied.\n",
- fsp->fsp_name ));
- return(ERROR(ERRDOS,ERRnoaccess));
- }
+ if (fsp == NULL)
+ return(UNIXERROR(ERRDOS,ERRbadfid));
- if(fsp->is_directory) {
- fsp->directory_delete_on_close = delete_on_close;
- DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, directory %s\n",
- delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
- } else if(fsp->stat_open) {
+ status = set_delete_on_close_internal(fsp, delete_on_close);
- DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, stat open %s\n",
- delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+ if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK))
+ return ERROR_NT(status);
- } else {
+ break;
+ }
- files_struct *iterate_fsp;
+ /*
+ * CIFS UNIX extensions.
+ */
- /*
- * Modify the share mode entry for all files open
- * on this device and inode to tell other smbds we have
- * changed the delete on close flag. This will be noticed
- * in the close code, the last closer will delete the file
- * if flag is set.
- */
+ case SMB_SET_FILE_UNIX_BASIC:
+ {
+ uint32 raw_unixmode;
- DEBUG(10,("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
- delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name ));
+ if (total_data < 100)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
- if (lock_share_entry_fsp(fsp) == False)
- return(ERROR(ERRDOS,ERRnoaccess));
+ size=IVAL(pdata,0); /* first 8 Bytes are size */
+#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);
+#endif /* LARGE_SMB_OFF_T */
+ pdata+=24; /* ctime & st_blocks are not changed */
+ tvs.actime = interpret_long_date(pdata); /* access_time */
+ tvs.modtime = interpret_long_date(pdata+8); /* modification_time */
+ pdata+=16;
+ set_owner = (uid_t)IVAL(pdata,0);
+ pdata += 8;
+ set_grp = (gid_t)IVAL(pdata,0);
+ pdata += 8;
+ raw_unixmode = IVAL(pdata,28);
+ unixmode = unix_perms_from_wire(conn, &sbuf, raw_unixmode);
+ dosmode = 0; /* Ensure dos mode change doesn't override this. */
+
+ DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC: name = %s \
+size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
+ fname, (double)size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode));
+
+ if (!VALID_STAT(sbuf)) {
+
+ /*
+ * The only valid use of this is to create character and block
+ * devices, and named pipes. This is deprecated (IMHO) and
+ * a new info level should be used for mknod. JRA.
+ */
+
+#if !defined(HAVE_MAKEDEV_FN)
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
+#else /* HAVE_MAKEDEV_FN */
+ uint32 file_type = IVAL(pdata,0);
+ uint32 dev_major = IVAL(pdata,4);
+ uint32 dev_minor = IVAL(pdata,12);
+
+ uid_t myuid = geteuid();
+ gid_t mygid = getegid();
+ SMB_DEV_T dev;
+
+ if (tran_call == TRANSACT2_SETFILEINFO)
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
+
+ if (raw_unixmode == SMB_MODE_NO_CHANGE)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ dev = makedev(dev_major, dev_minor);
+
+ /* We can only create as the owner/group we are. */
+
+ if ((set_owner != myuid) && (set_owner != (uid_t)SMB_UID_NO_CHANGE))
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
+ if ((set_grp != mygid) && (set_grp != (gid_t)SMB_GID_NO_CHANGE))
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
+
+ if (file_type != UNIX_TYPE_CHARDEV && file_type != UNIX_TYPE_BLKDEV &&
+ file_type != UNIX_TYPE_FIFO)
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
+
+ DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \
+0%o for file %s\n", (double)dev, unixmode, fname ));
+
+ /* Ok - do the mknod. */
+ if (conn->vfs_ops.mknod(conn,dos_to_unix(fname,False), unixmode, dev) != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
+#endif /* HAVE_MAKEDEV_FN */
- if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) {
- DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close flag for file %s\n",
- fsp->fsp_name ));
- unlock_share_entry_fsp(fsp);
- return(ERROR(ERRDOS,ERRnoaccess));
}
/*
- * Release the lock.
+ * Deal with the UNIX specific mode set.
*/
- unlock_share_entry_fsp(fsp);
+ if (raw_unixmode != SMB_MODE_NO_CHANGE) {
+ DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n",
+ unixmode, fname ));
+ if (vfs_chmod(conn,fname,unixmode) != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
/*
- * Go through all files we have open on the same device and
- * inode (hanging off the same hash bucket) and set the DELETE_ON_CLOSE_FLAG.
- * Other smbd's that have this file open will look in the share_mode on close.
- * take care of this (rare) case in close_file(). See the comment there.
- * NB. JRA. We don't really need to do this anymore - all should be taken
- * care of in the share_mode changes in the tdb.
+ * Deal with the UNIX specific uid set.
*/
- for(iterate_fsp = file_find_di_first(fsp->dev, fsp->inode);
- iterate_fsp; iterate_fsp = file_find_di_next(iterate_fsp))
- fsp->delete_on_close = delete_on_close;
+ if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (sbuf.st_uid != set_owner)) {
+ DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing owner %u for file %s\n",
+ (unsigned int)set_owner, fname ));
+ if (vfs_chown(conn,fname,set_owner, (gid_t)-1) != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
/*
- * Set the delete on close flag in the fsp.
+ * Deal with the UNIX specific gid set.
*/
- fsp->delete_on_close = delete_on_close;
- DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
- delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+ if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (sbuf.st_gid != set_grp)) {
+ DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n",
+ (unsigned int)set_owner, fname ));
+ if (vfs_chown(conn,fname,(uid_t)-1, set_grp) != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ break;
+ }
+
+ case SMB_SET_FILE_UNIX_LINK:
+ {
+ pstring link_dest;
+ /* Set a symbolic link. */
+ /* Don't allow this if follow links is false. */
+
+ if (!lp_symlinks(SNUM(conn)))
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
+ /* Disallow if already exists. */
+ if (VALID_STAT(sbuf))
+ return(ERROR_DOS(ERRDOS,ERRbadpath));
+
+ pstrcpy(link_dest, pdata);
+
+ if (ensure_link_is_safe(conn, link_dest, link_dest) != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ dos_to_unix(link_dest, True);
+ dos_to_unix(fname, True);
+
+ DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
+ fname, link_dest ));
+
+ if (conn->vfs_ops.symlink(conn,link_dest,fname) != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
}
- break;
+ case SMB_SET_FILE_UNIX_HLINK:
+ {
+ pstring link_dest;
+
+ /* Set a hard link. */
+
+ /* Disallow if already exists. */
+ if (VALID_STAT(sbuf))
+ return(ERROR_DOS(ERRDOS,ERRbadpath));
+
+ pstrcpy(link_dest, pdata);
+
+ if (ensure_link_is_safe(conn, link_dest, link_dest) != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ dos_to_unix(link_dest, True);
+ dos_to_unix(fname, True);
+
+ DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
+ fname, link_dest ));
+
+ if (conn->vfs_ops.link(conn,link_dest,fname) != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
+ }
+
+ default:
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
}
- default:
- {
- return(ERROR(ERRDOS,ERRunknownlevel));
+ /* get some defaults (no modifications) if any info is zero or -1. */
+ if (tvs.actime == (time_t)0 || tvs.actime == (time_t)-1)
+ tvs.actime = sbuf.st_atime;
+
+ if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
+ tvs.modtime = sbuf.st_mtime;
+
+ DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
+ DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
+ DEBUG(6,("size: %.0f ", (double)size));
+ DEBUG(6,("dosmode: %x\n" , dosmode));
+
+ if(!((info_level == SMB_SET_FILE_END_OF_FILE_INFO) ||
+ (info_level == SMB_SET_FILE_ALLOCATION_INFO) ||
+ (info_level == SMB_FILE_ALLOCATION_INFORMATION) ||
+ (info_level == SMB_FILE_END_OF_FILE_INFORMATION))) {
+ /*
+ * Only do this test if we are not explicitly
+ * changing the size of a file.
+ */
+ if (!size)
+ size = sbuf.st_size;
}
- }
-
- /* get some defaults (no modifications) if any info is zero or -1. */
- if (tvs.actime == (time_t)0 || tvs.actime == (time_t)-1)
- tvs.actime = sbuf.st_atime;
-
- if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
- tvs.modtime = sbuf.st_mtime;
-
- DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
- DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
- DEBUG(6,("size: %.0f ", (double)size));
- DEBUG(6,("mode: %x\n" , mode));
-
- if(!((info_level == SMB_SET_FILE_END_OF_FILE_INFO) ||
- (info_level == SMB_SET_FILE_ALLOCATION_INFO) ||
- (info_level == 1019) ||
- (info_level == 1020))) {
- /*
- * Only do this test if we are not explicitly
- * changing the size of a file.
- */
- if (!size)
- size = sbuf.st_size;
- }
-
- /* Try and set the times, size and mode of this file -
- if they are different from the current values
- */
- if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) {
- if(fsp != NULL) {
- /*
- * This was a setfileinfo on an open file.
- * NT does this a lot. It's actually pointless
- * setting the time here, as it will be overwritten
- * on the next write, so we save the request
- * away and will set it on file code. JRA.
- */
-
- if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
- DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n",
- ctime(&tvs.modtime) ));
- fsp->pending_modtime = tvs.modtime;
- }
-
- } else {
-
- DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
-
- if(file_utime(conn, fname, &tvs)!=0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
- }
-
- /* check the mode isn't different, before changing it */
- if ((mode != 0) && (mode != dos_mode(conn, fname, &sbuf))) {
-
- DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n",
- fname, mode ));
-
- if(file_chmod(conn, fname, mode, NULL)) {
- DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
- }
-
- if(size != sbuf.st_size) {
-
- DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n",
- fname, (double)size ));
-
- if (fd == -1) {
- files_struct *new_fsp = NULL;
- int access_mode = 0;
- int action = 0;
-
- if(global_oplock_break) {
- /* Queue this file modify as we are the process of an oplock break. */
-
- DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being "));
- DEBUGADD(2,( "in oplock break state.\n"));
-
- push_oplock_pending_smb_message(inbuf, length);
- return -1;
- }
-
- new_fsp = open_file_shared(conn, fname, &sbuf,
- SET_OPEN_MODE(DOS_OPEN_RDWR),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- 0, 0, &access_mode, &action);
+
+ /*
+ * Try and set the times, size and mode of this file -
+ * if they are different from the current values
+ */
+
+ if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) {
+ if(fsp != NULL) {
+ /*
+ * This was a setfileinfo on an open file.
+ * NT does this a lot. It's actually pointless
+ * setting the time here, as it will be overwritten
+ * on the next write, so we save the request
+ * away and will set it on file code. JRA.
+ */
+
+ if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
+ DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n",
+ ctime(&tvs.modtime) ));
+ fsp->pending_modtime = tvs.modtime;
+ }
+
+ } else {
+
+ DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
+
+ if(file_utime(conn, fname, &tvs)!=0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
+ /* check the mode isn't different, before changing it */
+ if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, &sbuf))) {
+
+ DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n",
+ fname, dosmode ));
+
+ if(file_chmod(conn, fname, dosmode, NULL)) {
+ DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
+ if(size != sbuf.st_size) {
+
+ DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n",
+ fname, (double)size ));
+
+ if (fd == -1) {
+ files_struct *new_fsp = NULL;
+ int access_mode = 0;
+ int action = 0;
+
+ if(global_oplock_break) {
+ /* Queue this file modify as we are the process of an oplock break. */
+
+ DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being "));
+ DEBUGADD(2,( "in oplock break state.\n"));
+
+ push_oplock_pending_smb_message(inbuf, length);
+ return -1;
+ }
+
+ new_fsp = open_file_shared(conn, fname, &sbuf,
+ SET_OPEN_MODE(DOS_OPEN_RDWR),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ 0, 0, &access_mode, &action);
- if (new_fsp == NULL)
- return(UNIXERROR(ERRDOS,ERRbadpath));
- vfs_set_filelen(new_fsp, size);
- close_file(new_fsp,True);
- } else {
- vfs_set_filelen(fsp, size);
- }
- }
-
- SSVAL(params,0,0);
-
- send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
-
- return(-1);
+ if (new_fsp == NULL)
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ vfs_set_filelen(new_fsp, size);
+ close_file(new_fsp,True);
+ } else {
+ vfs_set_filelen(fsp, size);
+ }
+ }
+
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
}
/****************************************************************************
- reply to a TRANS2_MKDIR (make directory with extended attributes).
+ Reply to a TRANS2_MKDIR (make directory with extended attributes).
****************************************************************************/
-static int call_trans2mkdir(connection_struct *conn,
- char *inbuf, char *outbuf, int length, int bufsize,
- char **pparams, char **ppdata)
+
+static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- char *params = *pparams;
- pstring directory;
- int ret = -1;
- SMB_STRUCT_STAT sbuf;
- BOOL bad_path = False;
+ char *params = *pparams;
+ pstring directory;
+ int ret = -1;
+ SMB_STRUCT_STAT sbuf;
+ BOOL bad_path = False;
+
+ if (!CAN_WRITE(conn))
+ return ERROR_DOS(ERRSRV,ERRaccess);
- if (!CAN_WRITE(conn))
- return(ERROR(ERRSRV,ERRaccess));
+ if (total_params < 4)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
- pstrcpy(directory, &params[4]);
+ pstrcpy(directory, &params[4]);
- DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
+ DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
- unix_convert(directory,conn,0,&bad_path,&sbuf);
- if (check_name(directory,conn))
- ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
+ unix_convert(directory,conn,0,&bad_path,&sbuf);
+ if (check_name(directory,conn))
+ ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
- if(ret < 0)
- {
- DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- /* Realloc the parameter and data sizes */
- params = Realloc(*pparams,2);
- if(params == NULL) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *pparams = params;
-
- SSVAL(params,0,0);
-
- send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ if(ret < 0) {
+ DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
+ set_bad_path_error(errno, bad_path);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ /* Realloc the parameter and data sizes */
+ params = Realloc(*pparams,2);
+ if(params == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *pparams = params;
+
+ SSVAL(params,0,0);
+
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
- return(-1);
+ return(-1);
}
/****************************************************************************
- reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes)
- We don't actually do this - we just send a null response.
+ Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
+ We don't actually do this - we just send a null response.
****************************************************************************/
-static int call_trans2findnotifyfirst(connection_struct *conn,
- char *inbuf, char *outbuf,
- int length, int bufsize,
- char **pparams, char **ppdata)
+
+static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- static uint16 fnf_handle = 257;
- char *params = *pparams;
- uint16 info_level = SVAL(params,4);
-
- DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
-
- switch (info_level)
- {
- case 1:
- case 2:
- break;
- default:
- return(ERROR(ERRDOS,ERRunknownlevel));
- }
-
- /* Realloc the parameter and data sizes */
- params = Realloc(*pparams,6);
- if(params == NULL) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *pparams = params;
-
- SSVAL(params,0,fnf_handle);
- SSVAL(params,2,0); /* No changes */
- SSVAL(params,4,0); /* No EA errors */
-
- fnf_handle++;
-
- if(fnf_handle == 0)
- fnf_handle = 257;
-
- send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0);
+ static uint16 fnf_handle = 257;
+ char *params = *pparams;
+ uint16 info_level;
+
+ if (total_params < 6)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ info_level = SVAL(params,4);
+ DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
+
+ switch (info_level) {
+ case 1:
+ case 2:
+ break;
+ default:
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ }
+
+ /* Realloc the parameter and data sizes */
+ params = Realloc(*pparams,6);
+ if(params == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *pparams = params;
+
+ SSVAL(params,0,fnf_handle);
+ SSVAL(params,2,0); /* No changes */
+ SSVAL(params,4,0); /* No EA errors */
+
+ fnf_handle++;
+
+ if(fnf_handle == 0)
+ fnf_handle = 257;
+
+ send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0);
- return(-1);
+ return(-1);
}
/****************************************************************************
- reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
- changes). Currently this does nothing.
+ Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
+ changes). Currently this does nothing.
****************************************************************************/
-static int call_trans2findnotifynext(connection_struct *conn,
- char *inbuf, char *outbuf,
- int length, int bufsize,
- char **pparams, char **ppdata)
+
+static int call_trans2findnotifynext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- char *params = *pparams;
+ char *params = *pparams;
- DEBUG(3,("call_trans2findnotifynext\n"));
+ DEBUG(3,("call_trans2findnotifynext\n"));
- /* Realloc the parameter and data sizes */
- params = Realloc(*pparams,4);
- if(params == NULL) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *pparams = params;
+ /* Realloc the parameter and data sizes */
+ params = Realloc(*pparams,4);
+ if(params == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *pparams = params;
- SSVAL(params,0,0); /* No changes */
- SSVAL(params,2,0); /* No EA errors */
+ SSVAL(params,0,0); /* No changes */
+ SSVAL(params,2,0); /* No EA errors */
- send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0);
+ send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0);
- return(-1);
+ return(-1);
}
/****************************************************************************
- reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>
+ Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
****************************************************************************/
-static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
- char* outbuf, int length, int bufsize,
- char** pparams, char** ppdata)
+
+static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- char *params = *pparams;
- enum remote_arch_types ra_type = get_remote_arch();
- BOOL NT_arch = ((ra_type == RA_WINNT) || (ra_type == RA_WIN2K));
- pstring pathname;
- int reply_size = 0;
- int max_referral_level = SVAL(params,0);
-
-
- DEBUG(10,("call_trans2getdfsreferral\n"));
-
- if(!lp_host_msdfs())
- return(ERROR(ERRDOS,ERRbadfunc));
-
- /* if pathname is in UNICODE, convert to DOS */
- /* NT always sends in UNICODE, may not set UNICODE flag */
- if(NT_arch || (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS))
- {
- unistr_to_dos(pathname, &params[2], sizeof(pathname));
- DEBUG(10,("UNICODE referral for %s\n",pathname));
- }
- else
- pstrcpy(pathname,&params[2]);
-
- if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0)
- return(ERROR(ERRDOS,ERRbadfile));
+ char *params = *pparams;
+ enum remote_arch_types ra_type = get_remote_arch();
+ BOOL NT_arch = ((ra_type == RA_WINNT) || (ra_type == RA_WIN2K));
+ pstring pathname;
+ int reply_size = 0;
+ int max_referral_level;
+
+ DEBUG(10,("call_trans2getdfsreferral\n"));
+
+ if (total_params < 2)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ max_referral_level = SVAL(params,0);
+
+ if(!lp_host_msdfs())
+ return ERROR_DOS(ERRDOS,ERRbadfunc);
+
+ /* if pathname is in UNICODE, convert to DOS */
+ /* NT always sends in UNICODE, may not set UNICODE flag */
+ if(NT_arch || (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS)) {
+ unistr_to_dos(pathname, &params[2], sizeof(pathname));
+ DEBUG(10,("UNICODE referral for %s\n",pathname));
+ } else
+ pstrcpy(pathname,&params[2]);
+
+ if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0)
+ return ERROR_DOS(ERRDOS,ERRbadfile);
- SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_UNICODE_STRINGS |
- FLAGS2_DFS_PATHNAMES);
- send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size);
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_UNICODE_STRINGS | FLAGS2_DFS_PATHNAMES);
+ send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size);
- return(-1);
+ return(-1);
}
#define LMCAT_SPL 0x53
@@ -2347,38 +2992,35 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
reply to a TRANS2_IOCTL - used for OS/2 printing.
****************************************************************************/
-static int call_trans2ioctl(connection_struct *conn, char* inbuf,
- char* outbuf, int length, int bufsize,
- char** pparams, char** ppdata)
+static int call_trans2ioctl(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data)
{
- char *pdata = *ppdata;
- files_struct *fsp = file_fsp(inbuf,smb_vwv15);
-
- if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
- (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
- pdata = Realloc(*ppdata, 32);
- if(pdata == NULL) {
- return(ERROR(ERRDOS,ERRnomem));
- }
- *ppdata = pdata;
-
- SSVAL(pdata,0,fsp->print_jobid); /* Job number */
- StrnCpy(pdata+2, global_myname, 15); /* Our NetBIOS name */
- StrnCpy(pdata+18, lp_servicename(SNUM(conn)), 13); /* Service name */
- send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32);
- return(-1);
- } else {
- DEBUG(2,("Unknown TRANS2_IOCTL\n"));
- return(ERROR(ERRSRV,ERRerror));
- }
+ char *pdata = *ppdata;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv15);
+
+ if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
+ (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+ pdata = Realloc(*ppdata, 32);
+ if(pdata == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *ppdata = pdata;
+
+ SSVAL(pdata,0,fsp->print_jobid); /* Job number */
+ StrnCpy(pdata+2, global_myname, 15); /* Our NetBIOS name */
+ StrnCpy(pdata+18, lp_servicename(SNUM(conn)), 13); /* Service name */
+ send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32);
+ return(-1);
+ } else {
+ DEBUG(2,("Unknown TRANS2_IOCTL\n"));
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
}
/****************************************************************************
Reply to a SMBfindclose (stop trans2 directory search).
****************************************************************************/
-int reply_findclose(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+int reply_findclose(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
int outsize = 0;
int dptr_num=SVALS(inbuf,smb_vwv0);
@@ -2400,8 +3042,7 @@ int reply_findclose(connection_struct *conn,
Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
****************************************************************************/
-int reply_findnclose(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+int reply_findnclose(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
int outsize = 0;
int dptr_num= -1;
@@ -2427,8 +3068,7 @@ int reply_findnclose(connection_struct *conn,
Reply to a SMBtranss2 - just ignore it!
****************************************************************************/
-int reply_transs2(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+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));
@@ -2437,10 +3077,10 @@ int reply_transs2(connection_struct *conn,
}
/****************************************************************************
- reply to a SMBtrans2
+ Reply to a SMBtrans2.
****************************************************************************/
-int reply_trans2(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+
+int reply_trans2(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
int outsize = 0;
unsigned int total_params = SVAL(inbuf, smb_tpscnt);
@@ -2474,7 +3114,7 @@ int reply_trans2(connection_struct *conn,
if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
&& (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
END_PROFILE(SMBtrans2);
- return(ERROR(ERRSRV,ERRaccess));
+ return ERROR_DOS(ERRSRV,ERRaccess);
}
outsize = set_message(outbuf,0,0,True);
@@ -2498,7 +3138,7 @@ int reply_trans2(connection_struct *conn,
DEBUG(2,("Invalid smb_sucnt in trans2 call(%d)\n",suwcnt));
DEBUG(2,("Transaction is %d\n",tran_call));
END_PROFILE(SMBtrans2);
- return(ERROR(ERRSRV,ERRerror));
+ return ERROR_DOS(ERRSRV,ERRerror);
}
}
@@ -2510,12 +3150,10 @@ int reply_trans2(connection_struct *conn,
if ((total_params && !params) || (total_data && !data)) {
DEBUG(2,("Out of memory in reply_trans2\n"));
- if(params)
- free(params);
- if(data)
- free(data);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
END_PROFILE(SMBtrans2);
- return(ERROR(ERRDOS,ERRnomem));
+ return ERROR_DOS(ERRDOS,ERRnomem);
}
/* Copy the param and data bytes sent with this request into
@@ -2536,7 +3174,7 @@ int reply_trans2(connection_struct *conn,
of the parameter/data bytes */
outsize = set_message(outbuf,0,0,True);
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_trans2: send_smb failed.\n");
+ exit_server("reply_trans2: send_smb failed.");
while (num_data_sofar < total_data ||
num_params_sofar < total_params) {
@@ -2552,12 +3190,10 @@ int reply_trans2(connection_struct *conn,
else
DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n",
(smb_read_error == READ_ERROR) ? "error" : "timeout" ));
- if(params)
- free(params);
- if(data)
- free(data);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
END_PROFILE(SMBtrans2);
- return(ERROR(ERRSRV,ERRerror));
+ return ERROR_DOS(ERRSRV,ERRerror);
}
/* Revise total_params and total_data in case
@@ -2577,112 +3213,100 @@ int reply_trans2(connection_struct *conn,
}
if (Protocol >= PROTOCOL_NT1) {
- uint16 flg2 = SVAL(outbuf,smb_flg2);
- SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
}
/* Now we must call the relevant TRANS2 function */
switch(tran_call) {
case TRANSACT2_OPEN:
START_PROFILE_NESTED(Trans2_open);
- outsize = call_trans2open(conn,
- inbuf, outbuf, bufsize,
- &params, &data);
+ outsize = call_trans2open(conn, inbuf, outbuf, bufsize,
+ &params, total_params, &data, total_data);
END_PROFILE_NESTED(Trans2_open);
break;
case TRANSACT2_FINDFIRST:
START_PROFILE_NESTED(Trans2_findfirst);
- outsize = call_trans2findfirst(conn, inbuf, outbuf,
- bufsize, &params, &data);
+ outsize = call_trans2findfirst(conn, inbuf, outbuf, bufsize,
+ &params, total_params, &data, total_data);
END_PROFILE_NESTED(Trans2_findfirst);
break;
case TRANSACT2_FINDNEXT:
START_PROFILE_NESTED(Trans2_findnext);
- outsize = call_trans2findnext(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data);
+ outsize = call_trans2findnext(conn, inbuf, outbuf, length, bufsize,
+ &params, total_params, &data, total_data);
END_PROFILE_NESTED(Trans2_findnext);
break;
case TRANSACT2_QFSINFO:
START_PROFILE_NESTED(Trans2_qfsinfo);
- outsize = call_trans2qfsinfo(conn, inbuf, outbuf,
- length, bufsize, &params,
- &data);
+ outsize = call_trans2qfsinfo(conn, inbuf, outbuf, length, bufsize,
+ &params, total_params, &data, total_data);
END_PROFILE_NESTED(Trans2_qfsinfo);
break;
case TRANSACT2_SETFSINFO:
START_PROFILE_NESTED(Trans2_setfsinfo);
- outsize = call_trans2setfsinfo(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data);
+ outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize,
+ &params, total_params, &data, total_data);
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,
- &params, &data, total_data);
+ outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize,
+ &params, total_params, &data, total_data);
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,
- &params, &data,
- total_data);
+ outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize,
+ &params, total_params, &data, total_data);
END_PROFILE_NESTED(Trans2_setpathinfo);
break;
case TRANSACT2_FINDNOTIFYFIRST:
START_PROFILE_NESTED(Trans2_findnotifyfirst);
- outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data);
+ outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, length, bufsize,
+ &params, total_params, &data, total_data);
END_PROFILE_NESTED(Trans2_findnotifyfirst);
break;
case TRANSACT2_FINDNOTIFYNEXT:
START_PROFILE_NESTED(Trans2_findnotifynext);
- outsize = call_trans2findnotifynext(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data);
+ outsize = call_trans2findnotifynext(conn, inbuf, outbuf, length, bufsize,
+ &params, total_params, &data, total_data);
END_PROFILE_NESTED(Trans2_findnotifynext);
break;
case TRANSACT2_MKDIR:
START_PROFILE_NESTED(Trans2_mkdir);
- outsize = call_trans2mkdir(conn, inbuf, outbuf, length,
- bufsize, &params, &data);
+ outsize = call_trans2mkdir(conn, inbuf, outbuf, length, bufsize,
+ &params, total_params, &data, total_data);
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, &data);
+ outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, bufsize,
+ &params, total_params, &data, total_data);
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,&data);
+ outsize = call_trans2ioctl(conn,inbuf,outbuf,length, bufsize,
+ &params, total_params, &data, total_data);
END_PROFILE_NESTED(Trans2_ioctl);
break;
default:
/* Error in request */
DEBUG(2,("Unknown request %d in trans2 call\n", tran_call));
- if(params)
- free(params);
- if(data)
- free(data);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
END_PROFILE(SMBtrans2);
- return (ERROR(ERRSRV,ERRerror));
+ return ERROR_DOS(ERRSRV,ERRerror);
}
/* As we do not know how many data packets will need to be
@@ -2692,10 +3316,8 @@ int reply_trans2(connection_struct *conn,
an error packet.
*/
- if(params)
- free(params);
- if(data)
- free(data);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
END_PROFILE(SMBtrans2);
return outsize; /* If a correct response was needed the
call_trans2xxx calls have already sent
diff --git a/source/smbd/uid.c b/source/smbd/uid.c
index 54ced5a8239..5204f36ad6e 100644
--- a/source/smbd/uid.c
+++ b/source/smbd/uid.c
@@ -21,16 +21,14 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
/* what user is current? */
extern struct current_user current_user;
/****************************************************************************
- Become the guest user.
+ Become the guest user without changing the security context stack.
****************************************************************************/
-BOOL become_guest(void)
+BOOL change_to_guest(void)
{
static struct passwd *pass=NULL;
static uid_t guest_uid = (uid_t)-1;
@@ -84,10 +82,11 @@ static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
}
/****************************************************************************
- Become the user of a connection number.
+ Become the user of a connection number without changing the security context
+ stack, but modify the currnet_user entries.
****************************************************************************/
-BOOL become_user(connection_struct *conn, uint16 vuid)
+BOOL change_to_user(connection_struct *conn, uint16 vuid)
{
user_struct *vuser = get_valid_user_struct(vuid);
int snum;
@@ -98,7 +97,7 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
NT_USER_TOKEN *token = NULL;
if (!conn) {
- DEBUG(2,("Connection not open\n"));
+ DEBUG(2,("change_to_user: Connection not open\n"));
return(False);
}
@@ -111,12 +110,12 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
(current_user.uid == conn->uid)) {
- DEBUG(4,("Skipping become_user - already user\n"));
+ DEBUG(4,("change_to_user: Skipping user change - already user\n"));
return(True);
} else if ((current_user.conn == conn) &&
(vuser != 0) && (current_user.vuid == vuid) &&
(current_user.uid == vuser->uid)) {
- DEBUG(4,("Skipping become_user - already user\n"));
+ DEBUG(4,("change_to_user: Skipping user change - already user\n"));
return(True);
}
@@ -135,7 +134,7 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
token = conn->nt_user_token;
} else {
if (!vuser) {
- DEBUG(2,("Invalid vuid used %d\n",vuid));
+ DEBUG(2,("change_to_user: Invalid vuid used %d\n",vuid));
return(False);
}
uid = vuser->uid;
@@ -182,7 +181,7 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
if (vuser && vuser->guest)
is_guest = True;
- token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest);
+ token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest, NULL);
must_free_token = True;
}
@@ -198,21 +197,22 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
current_user.conn = conn;
current_user.vuid = vuid;
- DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d)\n",
+ DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
(int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
return(True);
}
/****************************************************************************
- Unbecome the user of a connection number.
+ Go back to being root without changing the security context stack,
+ but modify the current_user entries.
****************************************************************************/
-BOOL unbecome_user(void )
+BOOL change_to_root_user(void)
{
set_root_sec_ctx();
- DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
+ DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
(int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
current_user.conn = NULL;
@@ -224,16 +224,13 @@ BOOL unbecome_user(void )
/****************************************************************************
Become the user of an authenticated connected named pipe.
When this is called we are currently running as the connection
- user.
+ user. Doesn't modify current_user.
****************************************************************************/
BOOL become_authenticated_pipe_user(pipes_struct *p)
{
- BOOL res = push_sec_ctx();
-
- if (!res) {
+ if (!push_sec_ctx())
return False;
- }
set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid,
p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token);
@@ -244,19 +241,93 @@ BOOL become_authenticated_pipe_user(pipes_struct *p)
/****************************************************************************
Unbecome the user of an authenticated connected named pipe.
When this is called we are running as the authenticated pipe
- user and need to go back to being the connection user.
+ user and need to go back to being the connection user. Doesn't modify
+ current_user.
****************************************************************************/
-BOOL unbecome_authenticated_pipe_user(pipes_struct *p)
+BOOL unbecome_authenticated_pipe_user(void)
{
return pop_sec_ctx();
}
-/* Temporarily become a root user. Must match with unbecome_root(). */
+/****************************************************************************
+ Utility functions used by become_xxx/unbecome_xxx.
+****************************************************************************/
+
+struct conn_ctx {
+ connection_struct *conn;
+ uint16 vuid;
+};
+
+/* A stack of current_user connection contexts. */
+
+static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
+static int conn_ctx_stack_ndx;
+
+static void push_conn_ctx(void)
+{
+ struct conn_ctx *ctx_p;
+
+ /* Check we don't overflow our stack */
+
+ if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
+ DEBUG(0, ("Connection context stack overflow!\n"));
+ smb_panic("Connection context stack overflow!\n");
+ }
+
+ /* Store previous user context */
+ ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
+
+ ctx_p->conn = current_user.conn;
+ ctx_p->vuid = current_user.vuid;
+
+ DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
+ (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
+
+ conn_ctx_stack_ndx++;
+}
+
+static void pop_conn_ctx(void)
+{
+ struct conn_ctx *ctx_p;
+
+ /* Check for stack underflow. */
+
+ if (conn_ctx_stack_ndx == 0) {
+ DEBUG(0, ("Connection context stack underflow!\n"));
+ smb_panic("Connection context stack underflow!\n");
+ }
+
+ conn_ctx_stack_ndx--;
+ ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
+
+ current_user.conn = ctx_p->conn;
+ current_user.vuid = ctx_p->vuid;
+
+ ctx_p->conn = NULL;
+ ctx_p->vuid = UID_FIELD_INVALID;
+}
+
+void init_conn_ctx(void)
+{
+ int i;
+
+ /* Initialise connection context stack */
+ for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
+ conn_ctx_stack[i].conn = NULL;
+ conn_ctx_stack[i].vuid = UID_FIELD_INVALID;
+ }
+}
+
+/****************************************************************************
+ Temporarily become a root user. Must match with unbecome_root(). Saves and
+ restores the connection context.
+****************************************************************************/
void become_root(void)
{
push_sec_ctx();
+ push_conn_ctx();
set_root_sec_ctx();
}
@@ -265,6 +336,104 @@ void become_root(void)
void unbecome_root(void)
{
pop_sec_ctx();
+ pop_conn_ctx();
+}
+
+/****************************************************************************
+ Push the current security context then force a change via change_to_user().
+ Saves and restores the connection context.
+****************************************************************************/
+
+BOOL become_user(connection_struct *conn, uint16 vuid)
+{
+ if (!push_sec_ctx())
+ return False;
+
+ push_conn_ctx();
+
+ if (!change_to_user(conn, vuid)) {
+ pop_sec_ctx();
+ pop_conn_ctx();
+ return False;
+ }
+
+ return True;
+}
+
+BOOL unbecome_user(void)
+{
+ pop_sec_ctx();
+ pop_conn_ctx();
+ return True;
+}
+
+/*****************************************************************
+ Convert the suplimentary SIDs returned in a netlogon into UNIX
+ group gid_t's. Add to the total group array.
+*****************************************************************/
+
+void add_supplementary_nt_login_groups(int *n_groups, gid_t **pp_groups, NT_USER_TOKEN **pptok)
+{
+ int total_groups;
+ int current_n_groups = *n_groups;
+ gid_t *final_groups = NULL;
+ size_t i;
+ NT_USER_TOKEN *ptok = *pptok;
+ NT_USER_TOKEN *new_tok = NULL;
+
+ if (!ptok || (ptok->num_sids == 0))
+ return;
+
+ new_tok = dup_nt_token(ptok);
+ if (!new_tok) {
+ DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new token\n"));
+ return;
+ }
+ /* Leave the allocated space but empty the number of SIDs. */
+ new_tok->num_sids = 0;
+
+ total_groups = current_n_groups + ptok->num_sids;
+
+ final_groups = (gid_t *)malloc(total_groups * sizeof(gid_t));
+ if (!final_groups) {
+ DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new groups.\n"));
+ delete_nt_token(&new_tok);
+ return;
+ }
+
+ memcpy(final_groups, *pp_groups, current_n_groups * sizeof(gid_t));
+ for (i = 0; i < ptok->num_sids; i++) {
+ enum SID_NAME_USE sid_type;
+ gid_t new_grp;
+
+ if (sid_to_gid(&ptok->user_sids[i], &new_grp, &sid_type)) {
+ /*
+ * Don't add the gid_t if it is already in the current group
+ * list. Some UNIXen don't like the same group more than once.
+ */
+ int j;
+
+ for (j = 0; j < current_n_groups; j++)
+ if (final_groups[j] == new_grp)
+ break;
+
+ if ( j == current_n_groups) {
+ /* Group not already present. */
+ final_groups[current_n_groups++] = new_grp;
+ }
+ } else {
+ /* SID didn't map. Copy to the new token to be saved. */
+ sid_copy(&new_tok->user_sids[new_tok->num_sids++], &ptok->user_sids[i]);
+ }
+ }
+
+ SAFE_FREE(*pp_groups);
+ *pp_groups = final_groups;
+ *n_groups = current_n_groups;
+
+ /* Replace the old token with the truncated one. */
+ delete_nt_token(&ptok);
+ *pptok = new_tok;
}
/*****************************************************************
@@ -282,7 +451,7 @@ BOOL lookup_name(const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
*name_type = SID_NAME_UNKNOWN;
if (!winbind_lookup_name(name, psid, name_type) || (*name_type != SID_NAME_USER) ) {
- BOOL ret;
+ BOOL ret = False;
DEBUG(10, ("lookup_name: winbind lookup for %s failed - trying local\n", name));
@@ -382,16 +551,22 @@ BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE
DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
{
+ uid_t low, high;
fstring sid;
- if (!winbind_uid_to_sid(psid, uid)) {
- DEBUG(10,("uid_to_sid: winbind lookup for uid %u failed - trying local.\n", (unsigned int)uid ));
+ if (lp_winbind_uid(&low, &high) && uid >= low && uid <= high) {
+ if (winbind_uid_to_sid(psid, uid)) {
- return local_uid_to_sid(psid, uid);
+ DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
+ (unsigned int)uid, sid_to_string(sid, psid)));
+
+ return psid;
+ }
}
- DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
- (unsigned int)uid, sid_to_string(sid, psid) ));
+ local_uid_to_sid(psid, uid);
+
+ DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
return psid;
}
@@ -404,16 +579,22 @@ DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
{
+ gid_t low, high;
fstring sid;
- if (!winbind_gid_to_sid(psid, gid)) {
- DEBUG(10,("gid_to_sid: winbind lookup for gid %u failed - trying local.\n", (unsigned int)gid ));
+ if (lp_winbind_gid(&low, &high) && gid >= low && gid <= high) {
+ if (winbind_gid_to_sid(psid, gid)) {
- return local_gid_to_sid(psid, gid);
+ DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
+ (unsigned int)gid, sid_to_string(sid, psid)));
+
+ return psid;
+ }
}
- DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
- (unsigned int)gid, sid_to_string(sid,psid) ));
+ local_gid_to_sid(psid, gid);
+
+ DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
return psid;
}
@@ -520,7 +701,7 @@ BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
return False;
}
- DEBUG(10,("gid_to_uid: winbindd %s -> %u\n",
+ DEBUG(10,("sid_to_gid: winbindd %s -> %u\n",
sid_to_string(sid_str, psid),
(unsigned int)*pgid ));
diff --git a/source/smbd/utmp.c b/source/smbd/utmp.c
index f79cd43c5b1..92e001cd036 100644
--- a/source/smbd/utmp.c
+++ b/source/smbd/utmp.c
@@ -127,7 +127,7 @@ Notes:
#endif
/****************************************************************************
-obtain/release a small number (0 upwards) unique within and across smbds
+ Obtain/release a small number (0 upwards) unique within and across smbds.
****************************************************************************/
/*
* Need a "small" number to represent this connection, unique within this
@@ -154,8 +154,9 @@ obtain/release a small number (0 upwards) unique within and across smbds
*/
/****************************************************************************
-Default paths to various {u,w}tmp{,x} files
+ Default paths to various {u,w}tmp{,x} files.
****************************************************************************/
+
#ifdef HAVE_UTMPX_H
static const char *ux_pathname =
@@ -260,9 +261,11 @@ static void uw_pathname(pstring fname, const char *uw_name, const char *uw_defau
}
#ifndef HAVE_PUTUTLINE
+
/****************************************************************************
-Update utmp file directly. No subroutine interface: probably a BSD system.
+ Update utmp file directly. No subroutine interface: probably a BSD system.
****************************************************************************/
+
static void pututline_my(pstring uname, struct utmp *u, BOOL claim)
{
DEBUG(1,("pututline_my: not yet implemented\n"));
@@ -271,10 +274,12 @@ static void pututline_my(pstring uname, struct utmp *u, BOOL claim)
#endif /* HAVE_PUTUTLINE */
#ifndef HAVE_UPDWTMP
+
/****************************************************************************
-Update wtmp file directly. No subroutine interface: probably a BSD system.
-Credit: Michail Vidiassov <master@iaas.msu.ru>
+ Update wtmp file directly. No subroutine interface: probably a BSD system.
+ Credit: Michail Vidiassov <master@iaas.msu.ru>
****************************************************************************/
+
static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim)
{
int fd;
@@ -294,8 +299,8 @@ static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim)
* man page appears not to specify (hints non-NULL)
* A correspondent suggest at least ut_name should be NULL
*/
- memset((char *)&(u->ut_name), '\0', sizeof(u->ut_name));
- memset((char *)&(u->ut_host), '\0', sizeof(u->ut_host));
+ memset((char *)&u->ut_name, '\0', sizeof(u->ut_name));
+ memset((char *)&u->ut_host, '\0', sizeof(u->ut_host));
}
/* Stolen from logwtmp function in libutil.
* May be more locking/blocking is needed?
@@ -311,9 +316,10 @@ static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim)
#endif /* HAVE_UPDWTMP */
/****************************************************************************
-Update via utmp/wtmp (not utmpx/wtmpx)
+ Update via utmp/wtmp (not utmpx/wtmpx).
****************************************************************************/
-static void utmp_nox_update(struct utmp *u, const char *host, BOOL claim)
+
+static void utmp_nox_update(struct utmp *u, BOOL claim)
{
pstring uname, wname;
#if defined(PUTUTLINE_RETURNS_UTMP)
@@ -369,21 +375,41 @@ static void utmp_nox_update(struct utmp *u, const char *host, BOOL claim)
}
/****************************************************************************
-Update via utmpx/wtmpx (preferred) or via utmp/wtmp
+ Copy a string in the utmp structure.
****************************************************************************/
+
+static void utmp_strcpy(char *dest, const char *src, size_t n)
+{
+ size_t len = 0;
+
+ memset(dest, '\0', n);
+ if (src)
+ len = strlen(src);
+ if (len >= n) {
+ memcpy(dest, src, n);
+ } else {
+ if (len)
+ memcpy(dest, src, len);
+ }
+}
+
+/****************************************************************************
+ Update via utmpx/wtmpx (preferred) or via utmp/wtmp.
+****************************************************************************/
+
static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim)
{
#if !defined(HAVE_UTMPX_H)
/* No utmpx stuff. Drop to non-x stuff */
- utmp_nox_update(u, hostname, claim);
+ utmp_nox_update(u, claim);
#elif !defined(HAVE_PUTUTXLINE)
/* Odd. Have utmpx.h but no "pututxline()". Drop to non-x stuff */
DEBUG(1,("utmp_update: have utmpx.h but no pututxline() function\n"));
- utmp_nox_update(u, hostname, claim);
+ utmp_nox_update(u, claim);
#elif !defined(HAVE_GETUTMPX)
/* Odd. Have utmpx.h but no "getutmpx()". Drop to non-x stuff */
DEBUG(1,("utmp_update: have utmpx.h but no getutmpx() function\n"));
- utmp_nox_update(u, hostname, claim);
+ utmp_nox_update(u, claim);
#else
pstring uname, wname;
struct utmpx ux, *uxrc;
@@ -391,10 +417,12 @@ static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim)
getutmpx(u, &ux);
#if defined(HAVE_UX_UT_SYSLEN)
- if (hostname) ux.ut_syslen = strlen(hostname) + 1; /* include end NULL */
- else ux.ut_syslen = 0;
+ if (hostname)
+ ux.ut_syslen = strlen(hostname) + 1; /* include end NULL */
+ else
+ ux.ut_syslen = 0;
#endif
- safe_strcpy(ux.ut_host, hostname, sizeof(ux.ut_host)-1);
+ utmp_strcpy(ux.ut_host, hostname, sizeof(ux.ut_host));
uw_pathname(uname, "utmpx", ux_pathname);
uw_pathname(wname, "wtmpx", wx_pathname);
@@ -407,7 +435,7 @@ static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim)
* Drop to non-x method. (E.g. RH6 has good defaults in "utmp.h".)
*/
if ((strlen(uname) == 0) || (strlen(wname) == 0)) {
- utmp_nox_update(u, hostname, claim);
+ utmp_nox_update(u, claim);
} else {
utmpxname(uname);
setutxent();
@@ -424,8 +452,9 @@ static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim)
#if defined(HAVE_UT_UT_ID)
/****************************************************************************
-encode the unique connection number into "ut_id"
+ Encode the unique connection number into "ut_id".
****************************************************************************/
+
static int ut_id_encode(int i, char *fourbyte)
{
int nbase;
@@ -467,9 +496,9 @@ static BOOL sys_utmp_fill(struct utmp *u,
* rather than to try to detect and optimise.
*/
#if defined(HAVE_UT_UT_USER)
- safe_strcpy(u->ut_user, username, sizeof(u->ut_user)-1);
+ utmp_strcpy(u->ut_user, username, sizeof(u->ut_user));
#elif defined(HAVE_UT_UT_NAME)
- safe_strcpy(u->ut_name, username, sizeof(u->ut_name)-1);
+ utmp_strcpy(u->ut_name, username, sizeof(u->ut_name));
#endif
/*
@@ -485,7 +514,7 @@ static BOOL sys_utmp_fill(struct utmp *u,
id_str, sizeof(u->ut_line)));
return False;
}
- memcpy(u->ut_line, id_str, sizeof(u->ut_line));
+ utmp_strcpy(u->ut_line, id_str, sizeof(u->ut_line));
#if defined(HAVE_UT_UT_PID)
u->ut_pid = sys_getpid();
@@ -508,7 +537,7 @@ static BOOL sys_utmp_fill(struct utmp *u,
#endif
#if defined(HAVE_UT_UT_HOST)
- safe_strcpy(u->ut_host, hostname, sizeof(u->ut_host)-1);
+ utmp_strcpy(u->ut_host, hostname, sizeof(u->ut_host));
#endif
#if defined(HAVE_UT_UT_ADDR)
@@ -529,8 +558,9 @@ static BOOL sys_utmp_fill(struct utmp *u,
}
/****************************************************************************
-close a connection
+ Close a connection.
****************************************************************************/
+
void sys_utmp_yield(const char *username, const char *hostname,
const char *id_str, int id_num)
{
@@ -553,8 +583,9 @@ void sys_utmp_yield(const char *username, const char *hostname,
}
/****************************************************************************
-claim a entry in whatever utmp system the OS uses
+ Claim a entry in whatever utmp system the OS uses.
****************************************************************************/
+
void sys_utmp_claim(const char *username, const char *hostname,
const char *id_str, int id_num)
{
diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c
index 8e579634249..7d84e8756eb 100644
--- a/source/smbd/vfs-wrap.c
+++ b/source/smbd/vfs-wrap.c
@@ -559,6 +559,62 @@ int vfswrap_utime(connection_struct *conn, char *path, struct utimbuf *times)
return result;
}
+/*********************************************************************
+ A version of ftruncate that will write the space on disk if strict
+ allocate is set.
+**********************************************************************/
+
+static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
+{
+ struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
+ SMB_STRUCT_STAT st;
+ SMB_OFF_T currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
+ unsigned char zero_space[4096];
+ SMB_OFF_T space_to_write = len - st.st_size;
+
+ if (currpos == -1)
+ return -1;
+
+ if (vfs_ops->fstat(fsp, fd, &st) == -1)
+ return -1;
+
+#ifdef S_ISFIFO
+ if (S_ISFIFO(st.st_mode))
+ return 0;
+#endif
+
+ if (st.st_size == len)
+ return 0;
+
+ /* Shrink - just ftruncate. */
+ if (st.st_size > len)
+ return sys_ftruncate(fd, len);
+
+ /* Write out the real space on disk. */
+ if (vfs_ops->lseek(fsp, fd, st.st_size, SEEK_SET) != st.st_size)
+ return -1;
+
+ space_to_write = len - st.st_size;
+
+ memset(zero_space, '\0', sizeof(zero_space));
+ while ( space_to_write > 0) {
+ SMB_OFF_T retlen;
+ SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write);
+
+ retlen = vfs_ops->write(fsp,fsp->fd,(char *)zero_space,current_len_to_write);
+ if (retlen <= 0)
+ return -1;
+
+ space_to_write -= retlen;
+ }
+
+ /* Seek to where we were */
+ if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
+ return -1;
+
+ return 0;
+}
+
int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
{
int result = -1;
@@ -569,13 +625,21 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
START_PROFILE(syscall_ftruncate);
+ if (lp_strict_allocate(SNUM(fsp->conn))) {
+ result = strict_allocate_ftruncate(fsp, fd, len);
+ END_PROFILE(syscall_ftruncate);
+ return result;
+ }
+
/* we used to just check HAVE_FTRUNCATE_EXTEND and only use
sys_ftruncate if the system supports it. Then I discovered that
you can have some filesystems that support ftruncate
expansion and some that don't! On Linux fat can't do
ftruncate extend but ext2 can. */
+
result = sys_ftruncate(fd, len);
- if (result == 0) goto done;
+ if (result == 0)
+ goto done;
/* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
extend a file with ftruncate. Provide alternate implementation
@@ -589,7 +653,7 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
size in which case the ftruncate above should have
succeeded or shorter, in which case seek to len - 1 and
write 1 byte of zero */
- if (vfs_ops->fstat(fsp, fd, &st) < 0) {
+ if (vfs_ops->fstat(fsp, fd, &st) == -1) {
goto done;
}
@@ -610,19 +674,17 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
goto done;
}
- if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1) {
+ if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1)
goto done;
- }
- if (vfs_ops->write(fsp, fd, &c, 1)!=1) {
+ if (vfs_ops->write(fsp, fd, &c, 1)!=1)
goto done;
- }
/* Seek to where we were */
- if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos) {
+ if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
goto done;
- }
result = 0;
+
done:
END_PROFILE(syscall_ftruncate);
@@ -672,6 +734,51 @@ int vfswrap_readlink(connection_struct *conn, const char *path, char *buf, size_
return result;
}
+int vfswrap_link(connection_struct *conn, const char *oldpath, const char *newpath)
+{
+ int result;
+
+ START_PROFILE(syscall_link);
+
+#ifdef VFS_CHECK_NULL
+ if ((oldpath == NULL) || (newpath == NULL))
+ smb_panic("NULL pointer passed to vfswrap_link()\n");
+#endif
+ result = sys_link(oldpath, newpath);
+ END_PROFILE(syscall_link);
+ return result;
+}
+
+int vfswrap_mknod(connection_struct *conn, const char *pathname, mode_t mode, SMB_DEV_T dev)
+{
+ int result;
+
+ START_PROFILE(syscall_mknod);
+
+#ifdef VFS_CHECK_NULL
+ if (pathname == NULL)
+ smb_panic("NULL pointer passed to vfswrap_mknod()\n");
+#endif
+ result = sys_mknod(pathname, mode, dev);
+ END_PROFILE(syscall_mknod);
+ return result;
+}
+
+char *vfswrap_realpath(connection_struct *conn, const char *path, char *resolved_path)
+{
+ char *result;
+
+ START_PROFILE(syscall_realpath);
+
+#ifdef VFS_CHECK_NULL
+ if ((path == NULL) || (resolved_path == NULL))
+ smb_panic("NULL pointer passed to vfswrap_realpath()\n");
+#endif
+ result = sys_realpath(path, resolved_path);
+ END_PROFILE(syscall_realpath);
+ return result;
+}
+
size_t vfswrap_fget_nt_acl(files_struct *fsp, int fd, SEC_DESC **ppdesc)
{
size_t result;
diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c
index 8d049b51c4a..229880c9f15 100644
--- a/source/smbd/vfs.c
+++ b/source/smbd/vfs.c
@@ -21,8 +21,6 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
/* Some structures to help us initialise the vfs operations table */
struct vfs_syminfo {
@@ -74,6 +72,9 @@ struct vfs_ops default_vfs_ops = {
vfswrap_lock,
vfswrap_symlink,
vfswrap_readlink,
+ vfswrap_link,
+ vfswrap_mknod,
+ vfswrap_realpath,
vfswrap_fget_nt_acl,
vfswrap_get_nt_acl,
@@ -240,6 +241,12 @@ static BOOL vfs_init_custom(connection_struct *conn)
if (conn->vfs_ops.readlink == NULL)
conn->vfs_ops.readlink = default_vfs_ops.readlink;
+ if (conn->vfs_ops.link == NULL)
+ conn->vfs_ops.link = default_vfs_ops.link;
+
+ if (conn->vfs_ops.mknod == NULL)
+ conn->vfs_ops.mknod = default_vfs_ops.mknod;
+
if (conn->vfs_ops.fget_nt_acl == NULL)
conn->vfs_ops.fget_nt_acl = default_vfs_ops.fget_nt_acl;
@@ -350,10 +357,10 @@ char *vfs_getwd(connection_struct *conn, char *unix_path)
}
/*******************************************************************
- Check if a vfs file exists.
+ Check if an object exists in the vfs.
********************************************************************/
-BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
+BOOL vfs_object_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
{
SMB_STRUCT_STAT st;
@@ -362,9 +369,26 @@ BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
ZERO_STRUCTP(sbuf);
- if (vfs_stat(conn,fname,sbuf) != 0)
+ if (vfs_stat(conn,fname,sbuf) == -1)
return(False);
+ return True;
+}
+/*******************************************************************
+ Check if a file exists in the vfs.
+********************************************************************/
+
+BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
+{
+ SMB_STRUCT_STAT st;
+
+ if (!sbuf)
+ sbuf = &st;
+
+ ZERO_STRUCTP(sbuf);
+
+ if (vfs_stat(conn,fname,sbuf) == -1)
+ return False;
return(S_ISREG(sbuf->st_mode));
}
@@ -399,19 +423,21 @@ ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N)
{
- size_t total=0;
- ssize_t ret;
+ size_t total=0;
+ ssize_t ret;
- while (total < N)
- {
- ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
+ while (total < N) {
+ ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
- if (ret == -1) return -1;
- if (ret == 0) return total;
+ if (ret == -1)
+ return -1;
+ if (ret == 0)
+ return total;
- total += ret;
- }
- return (ssize_t)total;
+ total += ret;
+ }
+
+ return (ssize_t)total;
}
/****************************************************************************
@@ -424,11 +450,11 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
{
int ret;
SMB_STRUCT_STAT st;
- struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
+ connection_struct *conn = fsp->conn;
+ struct vfs_ops *vfs_ops = &conn->vfs_ops;
+ SMB_OFF_T space_avail;
+ SMB_BIG_UINT bsize,dfree,dsize;
- if (!lp_strict_allocate(SNUM(fsp->conn)))
- return vfs_set_filelen(fsp, len);
-
release_level_2_oplocks_on_change(fsp);
/*
@@ -450,47 +476,30 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
fsp->fsp_name, (double)st.st_size ));
+ flush_write_cache(fsp, SIZECHANGE_FLUSH);
if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
set_filelen_write_cache(fsp, len);
}
return ret;
}
- /* Grow - we need to write out the space.... */
- {
- static unsigned char zero_space[65536];
-
- SMB_OFF_T start_pos = st.st_size;
- SMB_OFF_T len_to_write = len - st.st_size;
- SMB_OFF_T retlen;
+ /* Grow - we need to test if we have enough space. */
- DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f\n",
- fsp->fsp_name, (double)st.st_size ));
+ if (!lp_strict_allocate(SNUM(fsp->conn)))
+ return 0;
- if ((retlen = vfs_ops->lseek(fsp, fsp->fd, start_pos, SEEK_SET)) != start_pos)
- return -1;
+ len -= st.st_size;
+ len /= 1024; /* Len is now number of 1k blocks needed. */
+ space_avail = (SMB_OFF_T)conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
- while ( len_to_write > 0) {
- SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),len_to_write);
-
- retlen = vfs_ops->write(fsp,fsp->fd,(char *)zero_space,current_len_to_write);
- if (retlen <= 0) {
- /* Write fail - return to original size. */
- int save_errno = errno;
- fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, st.st_size);
- errno = save_errno;
- DEBUG(10,("vfs_allocate_file_space: file %s, grow. write fail %s\n",
- fsp->fsp_name, strerror(errno) ));
- return -1;
- }
+ DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %lu, space avail = %lu\n",
+ fsp->fsp_name, (double)st.st_size, (unsigned long)len, (unsigned long)space_avail ));
- DEBUG(10,("vfs_allocate_file_space: file %s, grow. wrote %.0f\n",
- fsp->fsp_name, (double)retlen ));
-
- len_to_write -= retlen;
- }
- set_filelen_write_cache(fsp, len);
+ if (len > space_avail) {
+ errno = ENOSPC;
+ return -1;
}
+
return 0;
}
@@ -505,6 +514,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
int ret;
release_level_2_oplocks_on_change(fsp);
+ DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
+ flush_write_cache(fsp, SIZECHANGE_FLUSH);
if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
set_filelen_write_cache(fsp, len);
@@ -696,7 +707,7 @@ static void array_promote(char *array,int elsize,int element)
memcpy(p,array + element * elsize, elsize);
memmove(array + elsize,array,elsize*element);
memcpy(array,p,elsize);
- free(p);
+ SAFE_FREE(p);
}
/*******************************************************************