diff options
author | Jeremy Allison <jra@samba.org> | 1998-07-17 22:21:24 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 1998-07-17 22:21:24 +0000 |
commit | 471087c9d28a4058efc16f98784cb179ffc1e4c4 (patch) | |
tree | accca93b43b77c8a46b2b78891d64a822ec3a403 /source3/smbd | |
parent | 18067a7f0c7153d5298ab1e6530ace4f25f926e7 (diff) | |
download | samba-471087c9d28a4058efc16f98784cb179ffc1e4c4.tar.gz samba-471087c9d28a4058efc16f98784cb179ffc1e4c4.tar.bz2 samba-471087c9d28a4058efc16f98784cb179ffc1e4c4.zip |
Code added to fix the renaming of a directory under NT SMB calls.
local.h: Changed MAXDIR to MAX_OPEN_DIRECTORIES - shmem size also tuned by this.
dir.c: Use MAX_OPEN_DIRECTORIES.
nttrans.c: Allow opening of a directory to succeed. Doesn't actually open
a file descriptor but takes a files_struct slot marked as an
fd.
reply.c: Changed to close any outstanding is_directory files.
reply_close changed to understand directory files.
server.c: Added open_directory(), close_directory() calls.
smb.h: Added is_directory to files_struct.
Changed OPEN_FNUM to check that target is !is_directory (this
prevents the normal file calls from processing a directory
files_struct.
Jeremy.
(This used to be commit e01ce693f47e75e277f3440d46e32b0bd866b550)
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/dir.c | 4 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 81 | ||||
-rw-r--r-- | source3/smbd/reply.c | 55 | ||||
-rw-r--r-- | source3/smbd/server.c | 125 |
4 files changed, 204 insertions, 61 deletions
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); } } |