From 2f7b04061e61df7dcc1029b71fe12ca4dfca5f10 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 3 Oct 1997 20:36:06 +0000 Subject: locking.c: Fixed incorrect parameter count in debug statements. May explain solaris crashes. reply.c: Added NT specific error code. Put oplock break code in correct place in reply_lockingX. server.c: Removed unneeded error mapping stuff. Fixed race condition in oplock code. trans2.c: Added NT specific error code. util.c: Added paranoia check in interpret_addr. Some core dumps reported here. Upped fcntl debug levels. Andrew. Please check the NT specific error code handling (search for the string "/* Ugly - NT specific hack - but needed (JRA) */", this makes NT and 95 clients behave correctly here - please check your Visual Basic apps with this code. Jeremy (jallison@whistle.com). (This used to be commit 97ee4a5f69bd9cfbbc8710a1a04d80db0ee40104) --- source3/lib/util.c | 8 +++-- source3/locking/locking.c | 11 ++++--- source3/smbd/reply.c | 34 ++++++++++++++++++---- source3/smbd/server.c | 74 +++++++++++------------------------------------ source3/smbd/trans2.c | 17 +++++++++++ 5 files changed, 74 insertions(+), 70 deletions(-) diff --git a/source3/lib/util.c b/source3/lib/util.c index 3317efb804..01e2dae154 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -3415,6 +3415,10 @@ uint32 interpret_addr(char *str) DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str)); return 0; } + if(hp->h_addr == NULL) { + DEBUG(3,("Get_Hostbyname: host address is invalid for host %s.\n",str)); + return 0; + } putip((char *)&res,(char *)hp->h_addr); } @@ -4033,7 +4037,7 @@ BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type) #endif - DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type)); + DEBUG(8,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type)); lock.l_type = type; lock.l_whence = SEEK_SET; @@ -4081,7 +4085,7 @@ BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type) } /* everything went OK */ - DEBUG(5,("Lock call successful\n")); + DEBUG(8,("Lock call successful\n")); return(True); #else diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 693beb7432..834f3e5658 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -206,7 +206,7 @@ file dev = %d, ino = %d in hash_bucket %d\n", dev, inode, hash_entry)); { DEBUG(0,("ERROR:get_share_modes (FAST_SHARE_MODES): Deleting old share mode \ record due to old locking version %d for file dev = %d, inode = %d in hash \ -bucket %d",file_scanner_p->locking_version, dev, inode, hash_entry)); +bucket %d\n", file_scanner_p->locking_version, dev, inode, hash_entry)); if(file_prev_p == file_scanner_p) mode_array[hash_entry] = file_scanner_p->next_offset; else @@ -270,7 +270,7 @@ for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries DEBUG(0,("get_share_modes (FAST_SHARE_MODES): process %d no longer exists and \ it left a share mode entry with mode 0x%X for file dev = %d, ino = %d in hash \ -bucket (number of entries now = %d)\n", +bucket %d (number of entries now = %d)\n", pid, entry_scanner_p->share_mode, dev, inode, hash_entry, file_scanner_p->num_share_mode_entries)); @@ -316,8 +316,7 @@ hash bucket %d has a share mode record but no entries - deleting\n", } DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \ -hash bucket %d returning %d entries\n", dev, inode, hash_entry, - num_entries_copied)); +hash bucket %d returning %d entries\n", dev, inode, hash_entry, num_entries_copied)); return(num_entries_copied); } @@ -878,8 +877,8 @@ for share file %s (%s)\n", fname, strerror(errno))); if (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION) { DEBUG(0,("ERROR: read_share_file: share file %s has incorrect \ locking version (was %d, should be %d).\n",fname, - IVAL(buf,SMF_VERSION_OFFSET), LOCKING_VERSION)); - if(buf) + IVAL(buf,SMF_VERSION_OFFSET), LOCKING_VERSION)); + if(buf) free(buf); delete_share_file(cnum, fname); return -1; diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index aa3f43a813..a8f674183c 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -640,6 +640,15 @@ int reply_chkpth(char *inbuf,char *outbuf) unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadpath; } + + /* Ugly - NT specific hack - but needed (JRA) */ + if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && + (get_remote_arch() == RA_WINNT)) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbaddirectory; + } + return(UNIXERROR(ERRDOS,ERRbadpath)); } @@ -3390,22 +3399,37 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize) (num_ulocks == 0) && (num_locks == 0) && (CVAL(inbuf,smb_vwv0) == 0xFF)) { + share_lock_token token; + files_struct *fsp = &Files[fnum]; + uint32 dev = fsp->fd_ptr->dev; + uint32 inode = fsp->fd_ptr->inode; + DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n", fnum)); /* * Make sure we have granted an oplock on this file. */ - if(!Files[fnum].granted_oplock) + if(!fsp->granted_oplock) { DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \ -oplock granted on this file.\n", fnum)); +no oplock granted on this file.\n", fnum)); return ERROR(ERRDOS,ERRlock); } - /* Just clear the granted flag and return. oplock_break() - will handle changing the share_mode_entry. */ + /* Remove the oplock flag from the sharemode. */ + lock_share_entry(fsp->cnum, dev, inode, &token); + if(remove_share_oplock( fnum, token)==False) + { + DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \ +dev = %x, inode = %x\n", fnum, dev, inode)); + unlock_share_entry(fsp->cnum, dev, inode, token); + return -1; + } + unlock_share_entry(fsp->cnum, dev, inode, token); + + /* Clear the granted flag and return. */ - Files[fnum].granted_oplock = 0; + fsp->granted_oplock = False; return -1; } #endif /* USE_OPLOCKS */ diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 9af1a88062..52869505c0 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -2137,20 +2137,6 @@ struct {0,0,0} }; -/* Mapping for old clients. */ - -struct -{ - int new_smb_error; - int old_smb_error; - int protocol_level; - enum remote_arch_types valid_ra_type; -} old_client_errmap[] = -{ - {ERRbaddirectory, ERRbadpath, (int)PROTOCOL_NT1, RA_WINNT}, - {0,0,0} -}; - /**************************************************************************** create an error packet from errno ****************************************************************************/ @@ -2181,29 +2167,6 @@ int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int } } - /* Make sure we don't return error codes that old - clients don't understand. */ - - /* JRA - unfortunately, WinNT needs some error codes - for apps to work correctly, Win95 will break if - these error codes are returned. But they both - negotiate the *same* protocol. So we need to use - the revolting 'remote_arch' enum to tie break. - - There must be a better way of doing this... - */ - - for(i = 0; old_client_errmap[i].new_smb_error != 0; i++) - { - if(((Protocol < old_client_errmap[i].protocol_level) || - (old_client_errmap[i].valid_ra_type != get_remote_arch())) && - (old_client_errmap[i].new_smb_error == ecode)) - { - ecode = old_client_errmap[i].old_smb_error; - break; - } - } - return(error_packet(inbuf,outbuf,eclass,ecode,line)); } @@ -2612,7 +2575,6 @@ BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval) static char *outbuf = NULL; files_struct *fsp = NULL; int fnum; - share_lock_token token; time_t start_time; BOOL shutdown_server = False; @@ -2660,16 +2622,19 @@ allowing break to succeed.\n", dev, inode, fnum)); /* Ensure we have an oplock on the file */ - /* Question - can a client asynchronously break an oplock ? Would it - ever do so ? If so this test is invalid for external smbd oplock - breaks and we should return True in these cases (JRA). + /* 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. But this is an unusual case so + we should log a message at low debug priority (1). */ if(!fsp->granted_oplock) { - DEBUG(0,("oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock.\n", - fsp->name, fnum, dev, inode)); - return False; + DEBUG(1,("oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. \ +Allowing break to succeed regardless.\n", fsp->name, fnum, dev, inode)); + return True; } /* Now comes the horrid part. We must send an oplock break to the client, @@ -2729,7 +2694,8 @@ inode = %x).\n", fsp->name, fnum, dev, inode)); process_smb(inbuf, outbuf); /* We only need this in case a readraw crossed on the wire. */ - global_oplock_break = False; + if(global_oplock_break) + global_oplock_break = False; /* * Die if we go over the time limit. @@ -2760,16 +2726,10 @@ inode = %x).\n", fsp->name, fnum, dev, inode)); if(OPEN_FNUM(fnum)) { - /* Remove the oplock flag from the sharemode. */ - lock_share_entry(fsp->cnum, dev, inode, &token); - if(remove_share_oplock( fnum, token)==False) - { - DEBUG(0,("oplock_break: failed to remove share oplock for fnum %d, \ -dev = %x, inode = %x\n", fnum, dev, inode)); - unlock_share_entry(fsp->cnum, dev, inode, token); - return False; - } - unlock_share_entry(fsp->cnum, dev, inode, token); + /* The lockingX reply will have removed the oplock flag + from the sharemode. */ + /* Paranoia.... */ + fsp->granted_oplock = False; } global_oplocks_open--; @@ -2782,8 +2742,8 @@ dev = %x, inode = %x\n", fnum, dev, inode)); abort(); } - DEBUG(5,("oplock_break: returning success for dev = %x, inode = %x. Current \ -global_oplocks_open = %d\n", dev, inode, global_oplocks_open)); + DEBUG(5,("oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \ +global_oplocks_open = %d\n", fnum, dev, inode, global_oplocks_open)); return True; } diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 56f153f12f..7f46604cce 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -607,6 +607,15 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadpath; } + + /* Ugly - NT specific hack - but needed (JRA) */ + if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && + (get_remote_arch() == RA_WINNT)) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbaddirectory; + } + return(ERROR(ERRDOS,ERRbadpath)); } @@ -641,6 +650,14 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadpath; } + + /* Ugly - NT specific hack - but needed (JRA) */ + if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && + (get_remote_arch() == RA_WINNT)) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbaddirectory; + } return (UNIXERROR(ERRDOS,ERRbadpath)); } return(ERROR(ERRDOS,ERRbadpath)); -- cgit