return(True);
}
+#if 0
+ /*
+ * This code I believe is incorrect - and commenting it out
+ * is the correct fix for the bug mentioned below in the
+ * comment 'name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra)'.
+ * The incoming name can be mangled, and if we de-mangle it
+ * here it will not compare correctly against the filename (name2)
+ * read from the directory and then mangled by the name_map_mangle()
+ * call. We need to mangle both names or neither.
+ * (JRA).
+ */
if (mangled)
check_mangled_stack(name);
+#endif
/* open the directory */
if (!(cur_dir = OpenDir(cnum, path, True)))
struct stat statbuf;
file_fd_struct *fd_ptr;
files_struct *fsp = &Files[fnum];
+ int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
fsp->open = False;
fsp->fd_ptr = 0;
pstrcpy(fname,fname1);
/* check permissions */
- if ((flags != O_RDONLY) && !CAN_WRITE(cnum) && !Connections[cnum].printer)
- {
+
+ /*
+ * This code was changed after seeing a client open request
+ * containing the open mode of (DENY_WRITE/read-only) with
+ * the 'create if not exist' bit set. The previous code
+ * would fail to open the file read only on a read-only share
+ * as it was checking the flags parameter directly against O_RDONLY,
+ * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.
+ * JRA.
+ */
+
+ if (!CAN_WRITE(cnum) && !Connections[cnum].printer) {
+ /* It's a read-only share - fail if we wanted to write. */
+ if(accmode != O_RDONLY) {
DEBUG(3,("Permission denied opening %s\n",fname));
check_for_pipe(fname);
return;
}
+ else if(flags & O_CREAT) {
+ /* We don't want to write - but we must make sure that O_CREAT
+ doesn't create the file if we have write access into the
+ directory.
+ */
+ flags &= ~O_CREAT;
+ }
+ }
/* this handles a bug in Win95 - it doesn't say to create the file when it
should */
*/
if((fd_ptr = fd_get_already_open(sbuf))!= 0) {
- int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
-
/* File was already open. */
if((flags & O_CREAT) && (flags & O_EXCL)) {
fd_ptr->ref_count--;
fsp->print_file = Connections[cnum].printer;
fsp->modified = False;
fsp->granted_oplock = False;
+ fsp->sent_oplock_break = False;
fsp->cnum = cnum;
string_set(&fsp->name,dos_to_unix(fname,False));
fsp->wbmpx_ptr = NULL;
if (normal_close)
check_magic(fnum,cnum);
+ if(fs_p->granted_oplock == True)
+ global_oplocks_open--;
+
+ fs_p->sent_oplock_break = False;
+
DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
timestring(),Connections[cnum].user,fs_p->name,
Connections[cnum].num_files_open));
(access_allowed == AREAD && *flags == O_WRONLY) ||
(access_allowed == AWRITE && *flags == O_RDONLY))
{
- DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
+ DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d\n",
deny_mode,old_deny_mode,old_open_mode,
- share->pid,fname, access_allowed));
+ share->pid,fname, fcbopen, *flags, access_allowed));
return False;
}
be extended to level II oplocks (multiple reader
oplocks). */
- if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum)))
+ if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum)) &&
+ !IS_VETO_OPLOCK_PATH(cnum,fname))
{
fs_p->granted_oplock = True;
+ fs_p->sent_oplock_break = False;
global_oplocks_open++;
port = oplock_port;
return True;
}
close(Client); /* The parent doesn't need this socket */
-#endif /NO_FORK_DEBUG */
+#endif /* NO_FORK_DEBUG */
} /* end for num */
} /* end while 1 */
} /* end if is_daemon */
if (msg_type == 0)
show_msg(inbuf);
+ else if(msg_type == 0x85)
+ return; /* Keepalive packet. */
nread = construct_reply(inbuf,outbuf,nread,max_send);
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(inbuf == NULL) {
- DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
- return False;
- }
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- if(outbuf == NULL) {
- DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
- free(inbuf);
- inbuf = NULL;
- return False;
- }
- }
+ DEBUG(3,("%s oplock_break: called for dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", timestring(), dev, inode, global_oplocks_open));
/* We need to search the file open table for the
entry containing this dev and inode, and ensure
{
if(OPEN_FNUM(fnum))
{
- fsp = &Files[fnum];
- 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;
+ if((Files[fnum].fd_ptr->dev == dev) && (Files[fnum].fd_ptr->inode == inode) &&
+ (Files[fnum].open_time.tv_sec == tval->tv_sec) &&
+ (Files[fnum].open_time.tv_usec == tval->tv_usec)) {
+ fsp = &Files[fnum];
+ break;
+ }
}
}
if(fsp == NULL)
{
/* The file could have been closed in the meantime - return success. */
- DEBUG(3,("oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
-allowing break to succeed.\n", dev, inode, fnum));
+ DEBUG(0,("%s oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
+allowing break to succeed.\n", timestring(), dev, inode, fnum));
return True;
}
if(!fsp->granted_oplock)
{
- 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));
+ DEBUG(0,("%s oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. Allowing break to succeed regardless.\n", timestring(), fsp->name, fnum, dev, inode));
return True;
}
+ /* mark the oplock break as sent - we don't want to send twice! */
+ if (fsp->sent_oplock_break)
+ {
+ DEBUG(0,("%s oplock_break: ERROR: oplock_break already sent for file %s (fnum = %d, dev = %x, inode = %x)\n", timestring(), fsp->name, fnum, dev, 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;
+ }
+
/* 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 + SAFETY_MARGIN))==NULL)
+ {
+ DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+ return False;
+ }
+
+ if((outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL)
+ {
+ DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+ free(inbuf);
+ inbuf = NULL;
+ return False;
+ }
+
/* Prepare the SMBlockingX message. */
bzero(outbuf,smb_size);
set_message(outbuf,8,0,True);
send_smb(Client, outbuf);
+ /* Remember we just sent an oplock break on this file. */
+ fsp->sent_oplock_break = True;
+
+ /* We need this in case a readraw crosses on the wire. */
global_oplock_break = True;
/* Process incoming messages. */
*/
if (smb_read_error == READ_EOF)
- DEBUG(0,("oplock_break: end of file from client\n"));
+ DEBUG(0,("%s oplock_break: end of file from client\n", timestring()));
if (smb_read_error == READ_ERROR)
- DEBUG(0,("oplock_break: receive_smb error (%s)\n",
- strerror(errno)));
+ DEBUG(0,("%s oplock_break: receive_smb error (%s)\n",
+ timestring(), strerror(errno)));
if (smb_read_error == READ_TIMEOUT)
- DEBUG(0,("oplock_break: receive_smb timed out after %d seconds.\n",
- OPLOCK_BREAK_TIMEOUT));
+ DEBUG(0,("%s oplock_break: receive_smb timed out after %d seconds.\n",
+ timestring(), OPLOCK_BREAK_TIMEOUT));
- DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
-inode = %x).\n", fsp->name, fnum, dev, inode));
+ DEBUG(0,("%s oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
shutdown_server = True;
break;
}
process_smb(inbuf, outbuf);
- /* We only need this in case a readraw crossed on the wire. */
- if(global_oplock_break)
- global_oplock_break = False;
-
/*
* Die if we go over the time limit.
*/
if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
{
- DEBUG(0,("oplock_break: no break received from client within \
-%d seconds.\n", OPLOCK_BREAK_TIMEOUT));
- DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
-inode = %x).\n", fsp->name, fnum, dev, inode));
+ DEBUG(0,("%s oplock_break: no break received from client within \
+%d seconds.\n", timestring(), OPLOCK_BREAK_TIMEOUT));
+ DEBUG(0,("%s oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
shutdown_server = True;
break;
}
}
+ /* 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 did not respond we must die.
*/
if(shutdown_server)
{
- DEBUG(0,("oplock_break: client failure in break - shutting down this smbd.\n"));
+ DEBUG(0,("%s oplock_break: client failure in break - shutting down this smbd.\n",
+ timestring()));
close_sockets();
close(oplock_sock);
exit_server("oplock break failure");
from the sharemode. */
/* Paranoia.... */
fsp->granted_oplock = False;
+ fsp->sent_oplock_break = False;
+ global_oplocks_open--;
}
- global_oplocks_open--;
-
/* Santity check - remove this later. JRA */
if(global_oplocks_open < 0)
{
exit_server("oplock_break: global_oplocks_open < 0");
}
- 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));
+ DEBUG(3,("%s oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", timestring(), fnum, dev, inode, global_oplocks_open));
return True;
}
addr_out.sin_port = htons( share_entry->op_port );
addr_out.sin_family = AF_INET;
- DEBUG(3,("request_oplock_break: sending a oplock break message to pid %d on port %d \
-for dev = %x, inode = %x\n", share_entry->pid, share_entry->op_port, dev, inode));
+ DEBUG(3,("%s request_oplock_break: sending a oplock break message to pid %d on port %d \
+for dev = %x, inode = %x\n", timestring(), share_entry->pid, share_entry->op_port, dev, inode));
if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
(struct sockaddr *)&addr_out,sizeof(addr_out)) < 0)
{
- DEBUG(0,("request_oplock_break: failed when sending a oplock break message \
+ DEBUG(0,("%s request_oplock_break: failed when sending a oplock break message \
to pid %d on port %d for dev = %x, inode = %x. Error was %s\n",
- share_entry->pid, share_entry->op_port, dev, inode,
+ timestring(), share_entry->pid, share_entry->op_port, dev, inode,
strerror(errno)));
return False;
}
/*
* 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 seconds.
+ * return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds.
* While we get messages that aren't ours, loop.
*/
char *reply_msg_start;
if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply),
- OPLOCK_BREAK_TIMEOUT * 1000) == False)
+ (OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) * 1000) == False)
{
if(smb_read_error == READ_TIMEOUT)
- DEBUG(0,("request_oplock_break: no response received to oplock break request to \
-pid %d on port %d for dev = %x, inode = %x\n", share_entry->pid,
+ {
+ DEBUG(0,("%s request_oplock_break: no response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x\n", timestring(), share_entry->pid,
share_entry->op_port, dev, inode));
+ /*
+ * 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
- DEBUG(0,("request_oplock_break: error in response received to oplock break request to \
-pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", share_entry->pid,
+ DEBUG(0,("%s request_oplock_break: error in response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", timestring, share_entry->pid,
share_entry->op_port, dev, inode, strerror(errno)));
return False;
}
if(reply_msg_len != OPLOCK_BREAK_MSG_LEN)
{
/* Ignore it. */
- DEBUG(0,("request_oplock_break: invalid message length received. Ignoring\n"));
+ DEBUG(0,("%s request_oplock_break: invalid message length received. Ignoring\n",
+ timestring()));
continue;
}
&op_break_msg[OPLOCK_BREAK_PID_OFFSET],
OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) != 0))
{
- DEBUG(3,("request_oplock_break: received other message whilst awaiting \
+ DEBUG(3,("%s request_oplock_break: received other message whilst awaiting \
oplock break response from pid %d on port %d for dev = %x, inode = %x.\n",
- share_entry->pid, share_entry->op_port, dev, inode));
+ timestring(), share_entry->pid, share_entry->op_port, dev, inode));
if(push_local_message(op_break_reply, sizeof(op_break_reply)) == False)
return False;
continue;
break;
}
- DEBUG(3,("request_oplock_break: broke oplock.\n"));
+ DEBUG(3,("%s request_oplock_break: broke oplock.\n", timestring()));
return True;
}
+/****************************************************************************
+Get the next SMB packet, doing the local message processing automatically.
+****************************************************************************/
+
+BOOL receive_next_smb(int smbfd, int oplockfd, char *inbuf, int bufsize, int timeout)
+{
+ BOOL got_smb = False;
+ BOOL ret;
+
+ do
+ {
+ ret = receive_message_or_smb(smbfd,oplockfd,inbuf,bufsize,
+ timeout,&got_smb);
+
+ if(ret && !got_smb)
+ {
+ /* Deal with oplock break requests from other smbd's. */
+ process_local_message(oplock_sock, inbuf, bufsize);
+ continue;
+ }
+
+ if(ret && (CVAL(inbuf,0) == 0x85))
+ {
+ /* Keepalive packet. */
+ got_smb = False;
+ }
+
+ }
+ while(ret && !got_smb);
+
+ return ret;
+}
+
/****************************************************************************
check if a snum is in use
****************************************************************************/
}
}
- create_mangled_stack(lp_mangledstack());
+ reset_mangled_stack( lp_mangledstack() );
/* this forces service parameters to be flushed */
become_service(-1,True);
pcon->dirptr = NULL;
pcon->veto_list = NULL;
pcon->hide_list = NULL;
+ pcon->veto_oplock_list = NULL;
string_set(&pcon->dirpath,"");
string_set(&pcon->user,user);
{
set_namearray( &pcon->veto_list, lp_veto_files(SNUM(cnum)));
set_namearray( &pcon->hide_list, lp_hide_files(SNUM(cnum)));
+ set_namearray( &pcon->veto_oplock_list, lp_veto_oplocks(SNUM(cnum)));
}
{
****************************************************************************/
int find_free_file(void )
{
- int i;
- /* we start at 1 here for an obscure reason I can't now remember,
- but I think is important :-) */
- for (i=1;i<MAX_OPEN_FILES;i++)
- if (!Files[i].open)
- return(i);
- DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
- return(-1);
+ int i;
+ static int first_file;
+
+ /* we want to give out file handles differently on each new
+ connection because of a common bug in MS clients where they try to
+ reuse a file descriptor from an earlier smb connection. This code
+ increases the chance that the errant client will get an error rather
+ than causing corruption */
+ if (first_file == 0) {
+ first_file = (getpid() ^ (int)time(NULL)) % MAX_OPEN_FILES;
+ if (first_file == 0) first_file = 1;
+ }
+
+ for (i=first_file;i<MAX_OPEN_FILES;i++)
+ if (!Files[i].open) {
+ memset(&Files[i], 0, sizeof(Files[i]));
+ return(i);
+ }
+
+ /* returning a file handle of 0 is a bad idea - so we start at 1 */
+ for (i=1;i<first_file;i++)
+ if (!Files[i].open) {
+ memset(&Files[i], 0, sizeof(Files[i]));
+ return(i);
+ }
+
+
+ DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
+ return(-1);
}
/****************************************************************************
free_namearray(Connections[cnum].veto_list);
free_namearray(Connections[cnum].hide_list);
+ free_namearray(Connections[cnum].veto_oplock_list);
string_set(&Connections[cnum].user,"");
string_set(&Connections[cnum].dirpath,"");
{
int cnum = SVAL(inbuf,smb_tid);
int flags = smb_messages[match].flags;
- uint16 session_tag = SVAL(inbuf,smb_uid);
+ /* In share mode security we must ignore the vuid. */
+ uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
/* does this protocol need to be run as root? */
if (!(flags & AS_USER))
chain_size = 0;
chain_fnum = -1;
+ reset_chain_pnum();
bzero(outbuf,smb_size);
}
#endif
+ /* re-initialise the timezone */
+ TimeInit();
+
while (True)
{
int deadtime = lp_deadtime()*60;
fd_ptr->real_open_flags = -1;
}
+ /* for RPC pipes */
+ init_rpc_pipe_hnd();
+
+#ifdef NTDOMAIN
+ /* for LSA handles */
+ init_lsa_policy_hnd();
+#endif
+
init_dptrs();
}
int port = SMB_PORT;
int opt;
extern char *optarg;
- char pidFile[100] = { 0 };
+ char pidFile[100];
+
+ *pidFile = '\0';
#ifdef NEED_AUTH_PARAMETERS
set_auth_parameters(argc,argv);
#ifndef NO_SIGNAL_TEST
signal(SIGHUP,SIGNAL_CAST sig_hup);
#endif
-
+
+ /* Setup the signals that allow the debug log level
+ to by dynamically changed. */
+
+#if defined(SIGUSR1)
+ signal( SIGUSR1, SIGNAL_CAST sig_usr1 );
+#endif /* SIGUSR1 */
+
+#if defined(SIGUSR2)
+ signal( SIGUSR2, SIGNAL_CAST sig_usr2 );
+#endif /* SIGUSR2 */
+
DEBUG(3,("%s loaded services\n",timestring()));
if (!is_daemon && !is_a_socket(0))
become_daemon();
}
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+
if (*pidFile)
{
int fd;