int oplock_sock = -1;
uint16 oplock_port = 0;
/* Current number of oplocks we have outstanding. */
-uint32 global_oplocks_open = 0;
+int32 global_oplocks_open = 0;
#endif /* USE_OPLOCKS */
BOOL global_oplock_break = False;
int result = 0;
extern struct current_user current_user;
- DEBUG(5,("dos_mode: %d %s\n", cnum, path));
+ DEBUG(8,("dos_mode: %d %s\n", cnum, path));
if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) {
if (!((sbuf->st_mode & S_IWOTH) ||
result |= aHIDDEN;
}
- DEBUG(5,("dos_mode returning "));
+ DEBUG(8,("dos_mode returning "));
- if (result & aHIDDEN) DEBUG(5, ("h"));
- if (result & aRONLY ) DEBUG(5, ("r"));
- if (result & aSYSTEM) DEBUG(5, ("s"));
- if (result & aDIR ) DEBUG(5, ("d"));
- if (result & aARCH ) DEBUG(5, ("a"));
+ if (result & aHIDDEN) DEBUG(8, ("h"));
+ if (result & aRONLY ) DEBUG(8, ("r"));
+ if (result & aSYSTEM) DEBUG(8, ("s"));
+ if (result & aDIR ) DEBUG(8, ("d"));
+ if (result & aARCH ) DEBUG(8, ("a"));
- DEBUG(5,("\n"));
+ DEBUG(8,("\n"));
return(result);
}
/****************************************************************************
fd support routines - attempt to do a sys_open
****************************************************************************/
-
-int fd_attempt_open(char *fname, int flags, int mode)
+static int fd_attempt_open(char *fname, int flags, int mode)
{
int fd = sys_open(fname,flags,mode);
fd support routines - attempt to find an already open file by dev
and inode - increments the ref_count of the returned file_fd_struct *.
****************************************************************************/
-file_fd_struct *fd_get_already_open(struct stat *sbuf)
+static file_fd_struct *fd_get_already_open(struct stat *sbuf)
{
int i;
file_fd_struct *fd_ptr;
fd support routines - attempt to find a empty slot in the FileFd array.
Increments the ref_count of the returned entry.
****************************************************************************/
-file_fd_struct *fd_get_new()
+static file_fd_struct *fd_get_new()
{
int i;
file_fd_struct *fd_ptr;
fd support routines - attempt to re-open an already open fd as O_RDWR.
Save the already open fd (we cannot close due to POSIX file locking braindamage.
****************************************************************************/
-
-void fd_attempt_reopen(char *fname, int mode, file_fd_struct *fd_ptr)
+static void fd_attempt_reopen(char *fname, int mode, file_fd_struct *fd_ptr)
{
int fd = sys_open( fname, O_RDWR, mode);
fd support routines - attempt to close the file referenced by this fd.
Decrements the ref_count and returns it.
****************************************************************************/
-int fd_attempt_close(file_fd_struct *fd_ptr)
+static int fd_attempt_close(file_fd_struct *fd_ptr)
{
DEBUG(3,("fd_attempt_close on file_fd_struct %d, fd = %d, dev = %x, inode = %x, open_flags = %d, ref_count = %d.\n",
fd_ptr - &FileFd[0],
fsp->open = False;
fsp->fd_ptr = 0;
+ fsp->granted_oplock = False;
errno = EPERM;
pstrcpy(fname,fname1);
if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
if (new_deny == DENY_DOS || old_deny == DENY_DOS) {
- if (old_deny == new_deny && share_pid == getpid())
+ int pid = getpid();
+ if (old_deny == new_deny && share_pid == pid)
return(AALL);
if (old_mode == 0) return(AREAD);
{
min_share_mode_entry *share_entry = &old_shares[i];
- /* someone else has a share lock on it, check to see
- if we can too */
- if ((share_entry->share_mode != DENY_DOS) || (share_entry->pid != pid))
- goto free_and_exit;
-
#ifdef USE_OPLOCKS
/*
- * The share modes would give us access. Check if someone
- * has an oplock on this file. If so we must break it before
- * continuing.
+ * Break oplocks before checking share modes. See comment in
+ * open_file_shared for details.
+ * Check if someone has an oplock on this file. If so we must
+ * break it before continuing.
*/
if(share_entry->op_type & BATCH_OPLOCK)
{
break;
}
#endif /* USE_OPLOCKS */
+
+ /* someone else has a share lock on it, check to see
+ if we can too */
+ if ((share_entry->share_mode != DENY_DOS) || (share_entry->pid != pid))
+ goto free_and_exit;
+
} /* end for */
if(broke_oplock)
{
min_share_mode_entry *share_entry = &old_shares[i];
- /* someone else has a share lock on it, check to see
- if we can too */
- if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False)
- {
- free((char *)old_shares);
- unlock_share_entry(cnum, dev, inode, token);
- errno = EACCES;
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadshare;
- return;
- }
#ifdef USE_OPLOCKS
/*
- * The share modes would give us access. Check if someone
- * has an oplock on this file. If so we must break it before
- * continuing.
+ * By observation of NetBench, oplocks are broken *before* share
+ * modes are checked. This allows a file to be closed by the client
+ * if the share mode would deny access and the client has an oplock.
+ * Check if someone has an oplock on this file. If so we must break
+ * it before continuing.
*/
if(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
{
break;
}
#endif /* USE_OPLOCKS */
+
+ /* someone else has a share lock on it, check to see
+ if we can too */
+ if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False)
+ {
+ free((char *)old_shares);
+ unlock_share_entry(cnum, dev, inode, token);
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ return;
+ }
+
} /* end for */
if(broke_oplock)
be extended to level II oplocks (multiple reader
oplocks). */
- if(oplock_request && (num_share_modes == 0))
+ if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum)))
{
fs_p->granted_oplock = True;
global_oplocks_open++;
DEBUG(5,("open_file_shared: granted oplock (%x) on file %s, \
dev = %x, inode = %x\n", oplock_request, fname, dev, inode));
- }
+ }
+ else
+ {
+ port = 0;
+ oplock_request = 0;
+ }
+#else /* USE_OPLOCKS */
+ oplock_request = 0;
+ port = 0;
#endif /* USE_OPLOCKS */
set_share_mode(token, fnum, port, oplock_request);
}
{EPERM,ERRDOS,ERRnoaccess},
{EACCES,ERRDOS,ERRnoaccess},
{ENOENT,ERRDOS,ERRbadfile},
- {ENOTDIR,ERRDOS,ERRbaddirectory},
+ {ENOTDIR,ERRDOS,ERRbadpath},
{EIO,ERRHRD,ERRgeneral},
{EBADF,ERRSRV,ERRsrverror},
{EINVAL,ERRSRV,ERRsrverror},
{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
****************************************************************************/
}
}
- /* 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));
}
static void process_smb(char *inbuf, char *outbuf)
{
extern int Client;
- static int trans_num = 0;
-
+ static int trans_num;
int msg_type = CVAL(inbuf,0);
- int32 len = smb_len(outbuf);
+ int32 len = smb_len(inbuf);
int nread = len + 4;
+ if (trans_num == 0) {
+ /* on the first packet, check the global hosts allow/ hosts
+ deny parameters before doing any parsing of the packet
+ passed to us by the client. This prevents attacks on our
+ parsing code from hosts not in the hosts allow list */
+ if (!check_access(-1)) {
+ /* send a negative session response "not listining on calling
+ name" */
+ static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+ DEBUG(1,("%s Connection denied from %s\n",
+ timestring(),client_addr()));
+ send_smb(Client,(char *)buf);
+ exit_server("connection denied");
+ }
+ }
+
DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
uint32 remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
uint32 dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
uint32 inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+ struct timeval tval;
struct sockaddr_in toaddr;
+ tval.tv_sec = IVAL(msg_start, OPLOCK_BREAK_SEC_OFFSET);
+ tval.tv_usec = IVAL(msg_start, OPLOCK_BREAK_USEC_OFFSET);
+
DEBUG(5,("process_local_message: oplock break request from \
pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
if(global_oplocks_open != 0)
{
- if(oplock_break(dev, inode) == False)
+ if(oplock_break(dev, inode, &tval) == False)
{
DEBUG(0,("process_local_message: oplock break failed - \
not returning udp message.\n"));
/****************************************************************************
Process an oplock break directly.
****************************************************************************/
-BOOL oplock_break(uint32 dev, uint32 inode)
+BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
{
extern int Client;
static char *inbuf = NULL;
static char *outbuf = NULL;
files_struct *fsp = NULL;
int fnum;
- share_lock_token token;
time_t start_time;
BOOL shutdown_server = False;
+ DEBUG(5,("oplock_break: called for dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", dev, inode, global_oplocks_open));
+
if(inbuf == NULL)
{
inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
if(OPEN_FNUM(fnum))
{
fsp = &Files[fnum];
- if((fsp->fd_ptr->dev == dev) && (fsp->fd_ptr->inode == inode))
+ if((fsp->fd_ptr->dev == dev) && (fsp->fd_ptr->inode == inode) &&
+ (fsp->open_time.tv_sec == tval->tv_sec) &&
+ (fsp->open_time.tv_usec == tval->tv_usec))
break;
}
}
/* 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.
*/
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(3,("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,
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.
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--;
abort();
}
+ 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;
}
/* We are breaking our own oplock, make sure it's us. */
if(share_entry->op_port != oplock_port)
{
- DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %x, port = %d \
+ DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \
should be %d\n", pid, share_entry->op_port, oplock_port));
return False;
}
+
+ DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
+
/* Call oplock break direct. */
- return oplock_break(dev, inode);
+ return oplock_break(dev, inode, &share_entry->time);
}
/* We need to send a OPLOCK_BREAK_CMD message to the
SIVAL(op_break_msg,OPLOCK_BREAK_PID_OFFSET,pid);
SIVAL(op_break_msg,OPLOCK_BREAK_DEV_OFFSET,dev);
SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,inode);
+ SIVAL(op_break_msg,OPLOCK_BREAK_SEC_OFFSET,(uint32)share_entry->time.tv_sec);
+ SIVAL(op_break_msg,OPLOCK_BREAK_USEC_OFFSET,(uint32)share_entry->time.tv_usec);
/* set the address and port */
bzero((char *)&addr_out,sizeof(addr_out));