summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/local.h12
-rw-r--r--source3/include/proto.h2
-rw-r--r--source3/include/smb.h19
-rw-r--r--source3/smbd/dir.c4
-rw-r--r--source3/smbd/nttrans.c81
-rw-r--r--source3/smbd/reply.c55
-rw-r--r--source3/smbd/server.c125
7 files changed, 222 insertions, 76 deletions
diff --git a/source3/include/local.h b/source3/include/local.h
index f32700c0eb..4a69325b77 100644
--- a/source3/include/local.h
+++ b/source3/include/local.h
@@ -37,19 +37,19 @@
#define MAX_CONNECTIONS 127
#define MAX_OPEN_FILES 100
+/* max number of directories open at once */
+/* note that with the new directory code this no longer requires a
+ file handle per directory, but large numbers do use more memory */
+#define MAX_OPEN_DIRECTORIES 64
+
/* Default size of shared memory used for share mode locking */
#ifndef SHMEM_SIZE
-#define SHMEM_SIZE (1024*MAX_OPEN_FILES)
+#define SHMEM_SIZE (1024*(MAX_OPEN_FILES+MAX_OPEN_DIRECTORIES))
#endif
/* the max number of simultanous connections to the server by all clients */
#define MAXSTATUS 100000
-/* max number of directories open at once */
-/* note that with the new directory code this no longer requires a
- file handle per directory, but large numbers do use more memory */
-#define MAXDIR 64
-
#define WORDMAX 0xFFFF
/* the maximum password length before we declare a likely attack */
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 3acfb0cf5e..b390cb60d9 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1815,6 +1815,8 @@ int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize);
BOOL check_name(char *name,int cnum);
void sync_file(int fnum);
void close_file(int fnum, BOOL normal_close);
+void close_directory(int fnum);
+void open_directory(int fnum,int cnum,char *fname, int *action);
BOOL check_file_sharing(int cnum,char *fname, BOOL rename_op);
int check_share_mode( share_mode_entry *share, int deny_mode, char *fname,
BOOL fcbopen, int *flags);
diff --git a/source3/include/smb.h b/source3/include/smb.h
index ca295f3b42..921cb4284d 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -418,14 +418,14 @@ typedef struct
/* Structure used when SMBwritebmpx is active */
typedef struct
- {
- int wr_total_written; /* So we know when to discard this */
- int32 wr_timeout;
- int32 wr_errclass;
- int32 wr_error; /* Cached errors */
- BOOL wr_mode; /* write through mode) */
- BOOL wr_discard; /* discard all further data */
- } write_bmpx_struct;
+{
+ int wr_total_written; /* So we know when to discard this */
+ int32 wr_timeout;
+ int32 wr_errclass;
+ int32 wr_error; /* Cached errors */
+ BOOL wr_mode; /* write through mode) */
+ BOOL wr_discard; /* discard all further data */
+} write_bmpx_struct;
/*
* Structure used to indirect fd's from the files_struct.
@@ -467,6 +467,7 @@ typedef struct
BOOL modified;
BOOL granted_oplock;
BOOL sent_oplock_break;
+ BOOL is_directory;
BOOL reserved;
char *name;
} files_struct;
@@ -781,7 +782,7 @@ struct parm_struct
/* these are useful macros for checking validity of handles */
#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < MAX_OPEN_FILES))
-#define OPEN_FNUM(fnum) (VALID_FNUM(fnum) && Files[fnum].open)
+#define OPEN_FNUM(fnum) (VALID_FNUM(fnum) && Files[fnum].open && !Files[fnum].is_directory)
#define VALID_CNUM(cnum) (((cnum) >= 0) && ((cnum) < MAX_CONNECTIONS))
#define OPEN_CNUM(cnum) (VALID_CNUM(cnum) && Connections[cnum].open)
#define IS_IPC(cnum) (VALID_CNUM(cnum) && Connections[cnum].ipc)
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index 37fcd05743..8296a90fa1 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -115,7 +115,7 @@ static void *dptr_get(int key,uint32 lastused)
if (dp->valid) {
if (lastused) dp->lastused = lastused;
if (!dp->ptr) {
- if (dptrs_open >= MAXDIR)
+ if (dptrs_open >= MAX_OPEN_DIRECTORIES)
dptr_idleoldest();
DEBUG(4,("Reopening dptr key %d\n",key));
if ((dp->ptr = OpenDir(dp->cnum, dp->path, True)))
@@ -284,7 +284,7 @@ int dptr_create(int cnum,char *path, BOOL expect_close,int pid)
if (!start_dir(cnum,path))
return(-2); /* Code to say use a unix error return code. */
- if (dptrs_open >= MAXDIR)
+ if (dptrs_open >= MAX_OPEN_DIRECTORIES)
dptr_idleoldest();
for (i=0;i<NUMDIRPTRS;i++)
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 8f7f40b4f9..672e2c0802 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -476,12 +476,14 @@ int reply_ntcreate_and_X(char *inbuf,char *outbuf,int length,int bufsize)
return(ERROR(ERRSRV,ERRnofids));
}
+ fsp = &Files[fnum];
+
if (!check_name(fname,cnum)) {
if((errno == ENOENT) && bad_path) {
unix_ERR_class = ERRDOS;
unix_ERR_code = ERRbadpath;
}
- Files[fnum].reserved = False;
+ fsp->reserved = False;
restore_case_semantics(file_attributes);
@@ -493,39 +495,72 @@ int reply_ntcreate_and_X(char *inbuf,char *outbuf,int length,int bufsize)
oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+ /*
+ * NB. We have a potential bug here. If we cause an oplock
+ * break to ourselves, then we could end up processing filename
+ * related SMB requests whilst we await the oplock break
+ * response. As we may have changed the filename case
+ * semantics to be POSIX-like, this could mean a filename
+ * request could fail when it should succeed. This is a
+ * rare condition, but eventually we must arrange to restore
+ * the correct case semantics before issuing an oplock break
+ * request to our client. JRA.
+ */
+
open_file_shared(fnum,cnum,fname,smb_open_mode,smb_ofun,unixmode,
oplock_request,&rmode,&smb_action);
- fsp = &Files[fnum];
-
- if (!fsp->open) {
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- Files[fnum].reserved = False;
+ restore_case_semantics(file_attributes);
- restore_case_semantics(file_attributes);
+ if (!fsp->open) {
+ /*
+ * We cheat here. The only case we care about is a directory
+ * rename, where the NT client will attempt to open the source
+ * directory for DELETE access. Note that when the NT client
+ * does this it does *not* set the directory bit in the
+ * request packet. This is translated into a read/write open
+ * request. POSIX states that any open for write request on a directory
+ * will generate an EISDIR error, so we can catch this here and open
+ * a pseudo handle that is flagged as a directory. JRA.
+ */
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if(errno == EISDIR) {
+ oplock_request = 0;
+ open_directory(fnum, cnum, fname, &smb_action);
+
+ if(!fsp->open) {
+ fsp->reserved = False;
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+ fsp->reserved = False;
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
}
- if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
- close_file(fnum,False);
-
- restore_case_semantics(file_attributes);
-
- return(ERROR(ERRDOS,ERRnoaccess));
- }
+ if(fsp->is_directory) {
+ if(stat(fsp->name, &sbuf) != 0) {
+ close_directory(fnum);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+ if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ close_file(fnum,False);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+ }
- restore_case_semantics(file_attributes);
-
file_len = sbuf.st_size;
fmode = dos_mode(cnum,fname,&sbuf);
if(fmode == 0)
fmode = FILE_ATTRIBUTE_NORMAL;
mtime = sbuf.st_mtime;
- if (fmode & aDIR) {
+ if (!fsp->is_directory && (fmode & aDIR)) {
close_file(fnum,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
@@ -591,10 +626,12 @@ int reply_ntcreate_and_X(char *inbuf,char *outbuf,int length,int bufsize)
} else {
SIVAL(p,0,file_len);
}
+ p += 12;
+ SCVAL(p,0,fsp->is_directory ? 1 : 0);
}
chain_fnum = fnum;
-
+
return chain_reply(inbuf,outbuf,length,bufsize);
}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 07b72738c5..a0d1775b21 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1490,10 +1490,15 @@ int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize)
open by this user */
if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
int i;
- for (i=0;i<MAX_OPEN_FILES;i++)
- if ((Files[i].vuid == vuid) && Files[i].open) {
- close_file(i,False);
+ for (i=0;i<MAX_OPEN_FILES;i++) {
+ files_struct *fsp = &Files[i];
+ if ((fsp->vuid == vuid) && fsp->open) {
+ if(!fsp->is_directory)
+ close_file(i,False);
+ else
+ close_directory(i);
}
+ }
}
invalidate_vuid(vuid);
@@ -2416,14 +2421,16 @@ int reply_exit(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
/****************************************************************************
- reply to a close
+ Reply to a close - has to deal with closing a directory opened by NT SMB's.
****************************************************************************/
+
int reply_close(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int fnum,cnum;
int outsize = 0;
time_t mtime;
int32 eclass = 0, err = 0;
+ files_struct *fsp = NULL;
outsize = set_message(outbuf,0,0,True);
@@ -2435,23 +2442,43 @@ int reply_close(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
fnum = GETFNUM(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
+ /*
+ * We can only use CHECK_FNUM if we know it's not a directory.
+ */
+
+ if(!(VALID_FNUM(fnum) && Files[fnum].open && Files[fnum].is_directory))
+ CHECK_FNUM(fnum,cnum);
+
+ fsp = &Files[fnum];
if(HAS_CACHED_ERROR(fnum)) {
- eclass = Files[fnum].wbmpx_ptr->wr_errclass;
- err = Files[fnum].wbmpx_ptr->wr_error;
+ eclass = fsp->wbmpx_ptr->wr_errclass;
+ err = fsp->wbmpx_ptr->wr_error;
}
- mtime = make_unix_date3(inbuf+smb_vwv1);
+ if(fsp->is_directory) {
+ /*
+ * Special case - close NT SMB directory
+ * handle.
+ */
+ DEBUG(3,("%s close directory fnum=%d cnum=%d\n",
+ timestring(), fnum, cnum ));
+ close_directory(fnum);
+ } else {
+ /*
+ * Close ordinary file.
+ */
+ mtime = make_unix_date3(inbuf+smb_vwv1);
- /* try and set the date */
- set_filetime(cnum, Files[fnum].name,mtime);
+ /* try and set the date */
+ set_filetime(cnum, fsp->name,mtime);
- DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n",
- timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,
- Connections[cnum].num_files_open));
+ DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n",
+ timestring(),fsp->fd_ptr->fd,fnum,cnum,
+ Connections[cnum].num_files_open));
- close_file(fnum,True);
+ close_file(fnum,True);
+ }
/* We have a cached error */
if(eclass || err)
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index a236e2e6ec..cabf2d44b1 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -1511,6 +1511,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
fsp->modified = False;
fsp->granted_oplock = False;
fsp->sent_oplock_break = False;
+ fsp->is_directory = False;
fsp->cnum = cnum;
/*
* Note that the file name here is the *untranslated* name
@@ -1609,15 +1610,43 @@ static void check_magic(int fnum,int cnum)
}
}
+/****************************************************************************
+ Common code to close a file or a directory.
+****************************************************************************/
+
+static void close_filestruct(files_struct *fs_p)
+{
+ int cnum = fs_p->cnum;
+
+ fs_p->reserved = False;
+ fs_p->open = False;
+ fs_p->is_directory = False;
+
+ Connections[cnum].num_files_open--;
+ if(fs_p->wbmpx_ptr)
+ {
+ free((char *)fs_p->wbmpx_ptr);
+ fs_p->wbmpx_ptr = NULL;
+ }
+
+#if USE_MMAP
+ if(fs_p->mmap_ptr)
+ {
+ munmap(fs_p->mmap_ptr,fs_p->mmap_size);
+ fs_p->mmap_ptr = NULL;
+ }
+#endif
+}
/****************************************************************************
-close a file - possibly invalidating the read prediction
+ Close a file - possibly invalidating the read prediction.
-If normal_close is 1 then this came from a normal SMBclose (or equivalent)
-operation otherwise it came as the result of some other operation such as
-the closing of the connection. In the latter case printing and
-magic scripts are not run
+ If normal_close is 1 then this came from a normal SMBclose (or equivalent)
+ operation otherwise it came as the result of some other operation such as
+ the closing of the connection. In the latter case printing and
+ magic scripts are not run.
****************************************************************************/
+
void close_file(int fnum, BOOL normal_close)
{
files_struct *fs_p = &Files[fnum];
@@ -1626,28 +1655,12 @@ void close_file(int fnum, BOOL normal_close)
uint32 inode = fs_p->fd_ptr->inode;
int token;
- Files[fnum].reserved = False;
+ close_filestruct(fs_p);
#if USE_READ_PREDICTION
invalidate_read_prediction(fs_p->fd_ptr->fd);
#endif
- fs_p->open = False;
- Connections[cnum].num_files_open--;
- if(fs_p->wbmpx_ptr)
- {
- free((char *)fs_p->wbmpx_ptr);
- fs_p->wbmpx_ptr = NULL;
- }
-
-#if USE_MMAP
- if(fs_p->mmap_ptr)
- {
- munmap(fs_p->mmap_ptr,fs_p->mmap_size);
- fs_p->mmap_ptr = NULL;
- }
-#endif
-
if (lp_share_modes(SNUM(cnum)))
{
lock_share_entry( cnum, dev, inode, &token);
@@ -1684,6 +1697,69 @@ void close_file(int fnum, BOOL normal_close)
memset(fs_p, 0, sizeof(*fs_p));
}
+/****************************************************************************
+ Close a directory opened by an NT SMB call.
+****************************************************************************/
+
+void close_directory(int fnum)
+{
+ files_struct *fs_p = &Files[fnum];
+
+ /*
+ * Do the code common to files and directories.
+ */
+ close_filestruct(fs_p);
+
+ if (fs_p->name) {
+ string_free(&fs_p->name);
+ }
+
+ /* we will catch bugs faster by zeroing this structure */
+ memset(fs_p, 0, sizeof(*fs_p));
+}
+
+/****************************************************************************
+ Open a directory from an NT SMB call.
+****************************************************************************/
+
+void open_directory(int fnum,int cnum,char *fname, int *action)
+{
+ extern struct current_user current_user;
+ files_struct *fsp = &Files[fnum];
+
+ fsp->fd_ptr = NULL;
+ Connections[cnum].num_files_open++;
+ fsp->mode = 0;
+ GetTimeOfDay(&fsp->open_time);
+ fsp->vuid = current_user.vuid;
+ fsp->size = 0;
+ fsp->pos = -1;
+ fsp->open = True;
+ fsp->mmap_ptr = NULL;
+ fsp->mmap_size = 0;
+ fsp->can_lock = True;
+ fsp->can_read = False;
+ fsp->can_write = False;
+ fsp->share_mode = 0;
+ fsp->print_file = False;
+ fsp->modified = False;
+ fsp->granted_oplock = False;
+ fsp->sent_oplock_break = False;
+ fsp->is_directory = True;
+ fsp->cnum = cnum;
+ /*
+ * Note that the file name here is the *untranslated* name
+ * ie. it is still in the DOS codepage sent from the client.
+ * All use of this filename will pass though the sys_xxxx
+ * functions which will do the dos_to_unix translation before
+ * mapping into a UNIX filename. JRA.
+ */
+ string_set(&fsp->name,fname);
+ fsp->wbmpx_ptr = NULL;
+
+ *action = FILE_WAS_OPENED;
+}
+
enum {AFAIL,AREAD,AWRITE,AALL};
/*******************************************************************
@@ -4413,7 +4489,10 @@ static void close_open_files(int cnum)
int i;
for (i=0;i<MAX_OPEN_FILES;i++)
if( Files[i].cnum == cnum && Files[i].open) {
- close_file(i,False);
+ if(Files[i].is_directory)
+ close_directory(i);
+ else
+ close_file(i,False);
}
}