summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h2
-rw-r--r--source3/lib/util.c53
-rw-r--r--source3/printing/printing.c7
-rw-r--r--source3/smbd/server.c106
4 files changed, 110 insertions, 58 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index d6027e3716..3d478b9246 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1443,7 +1443,7 @@ int read_smb_length(int fd,char *inbuf,int timeout);
BOOL receive_smb(int fd,char *buffer, int timeout);
BOOL client_receive_smb(int fd,char *buffer, int timeout);
BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout);
-BOOL push_local_message(char *buf, int msg_len);
+BOOL push_smb_message(char *buf, int msg_len);
BOOL receive_message_or_smb(int smbfd, int oplock_fd,
char *buffer, int buffer_len,
int timeout, BOOL *got_smb);
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 1aa88c0708..12d7adcb56 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -2485,29 +2485,31 @@ BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout)
}
/****************************************************************************
- structure to hold a linked list of local udp messages.
+ structure to hold a linked list of local messages.
for processing.
****************************************************************************/
-typedef struct _udp_message_list {
- struct _udp_message_list *msg_next;
+typedef struct _message_list {
+ struct _message_list *msg_next;
char *msg_buf;
int msg_len;
-} udp_message_list;
+} pending_message_list;
-static udp_message_list *udp_msg_head = NULL;
+static pending_message_list *smb_msg_head = NULL;
/****************************************************************************
- Function to push a linked list of local udp messages ready
+ Function to push a linked list of local messages ready
for processing.
****************************************************************************/
-BOOL push_local_message(char *buf, int msg_len)
+
+static BOOL push_local_message(pending_message_list **pml, char *buf, int msg_len)
{
- udp_message_list *msg = (udp_message_list *)malloc(sizeof(udp_message_list));
+ pending_message_list *msg = (pending_message_list *)
+ malloc(sizeof(pending_message_list));
if(msg == NULL)
{
- DEBUG(0,("push_local_message: malloc fail (1)\n"));
+ DEBUG(0,("push_message: malloc fail (1)\n"));
return False;
}
@@ -2522,19 +2524,33 @@ BOOL push_local_message(char *buf, int msg_len)
memcpy(msg->msg_buf, buf, msg_len);
msg->msg_len = msg_len;
- msg->msg_next = udp_msg_head;
- udp_msg_head = msg;
+ msg->msg_next = *pml;
+ *pml = msg;
return True;
}
/****************************************************************************
+ Function to push a linked list of local smb messages ready
+ for processing.
+****************************************************************************/
+
+BOOL push_smb_message(char *buf, int msg_len)
+{
+ return push_local_message(&smb_msg_head, buf, msg_len);
+}
+
+/****************************************************************************
Do a select on an two fd's - with timeout.
If a local udp message has been pushed onto the
queue (this can only happen during oplock break
processing) return this first.
+ If a pending smb message has been pushed onto the
+ queue (this can only happen during oplock break
+ processing) return this next.
+
If the first smbfd is ready then read an smb from it.
if the second (loopback UDP) fd is ready then read a message
from it and setup the buffer header to identify the length
@@ -2555,19 +2571,22 @@ BOOL receive_message_or_smb(int smbfd, int oplock_fd,
*got_smb = False;
/*
- * Check to see if we already have a message on the udp queue.
+ * Check to see if we already have a message on the smb queue.
* If so - copy and return it.
*/
-
- if(udp_msg_head)
+
+ if(smb_msg_head)
{
- udp_message_list *msg = udp_msg_head;
+ pending_message_list *msg = smb_msg_head;
memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
- udp_msg_head = msg->msg_next;
-
+ smb_msg_head = msg->msg_next;
+
/* Free the message we just copied. */
free((char *)msg->msg_buf);
free((char *)msg);
+ *got_smb = True;
+
+ DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
return True;
}
diff --git a/source3/printing/printing.c b/source3/printing/printing.c
index 76b962606b..629b3ad496 100644
--- a/source3/printing/printing.c
+++ b/source3/printing/printing.c
@@ -436,7 +436,12 @@ A long spool-path will just waste significant chars of the file name.
buf->job = atoi(tok[LPRNG_JOBTOK]);
buf->size = atoi(tok[LPRNG_TOTALTOK]);
- buf->status = strequal(tok[LPRNG_RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ if (strequal(tok[LPRNG_RANKTOK],"active"))
+ buf->status = LPQ_PRINTING;
+ else if (strequal(tok[LPRNG_RANKTOK],"hold"))
+ buf->status = LPQ_PAUSED;
+ else
+ buf->status = LPQ_QUEUED;
/* buf->time = time(NULL); */
buf->time = LPRng_time(tok,LPRNG_TIMETOK);
DEBUG(3,("Time reported for job %d is %s", buf->job, ctime(&buf->time)));
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 751039070f..b5408a2903 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -2963,6 +2963,16 @@ inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
shutdown_server = True;
break;
}
+
+ /*
+ * There are certain SMB requests that we shouldn't allow
+ * to recurse. opens, renames and deletes are the obvious
+ * ones. This is handled in the switch_message() function.
+ * If global_oplock_break is set they will push the packet onto
+ * the pending smb queue and return -1 (no reply).
+ * JRA.
+ */
+
process_smb(inbuf, outbuf);
/*
@@ -3036,6 +3046,8 @@ BOOL request_oplock_break(share_mode_entry *share_entry,
char op_break_msg[OPLOCK_BREAK_MSG_LEN];
struct sockaddr_in addr_out;
int pid = getpid();
+ time_t start_time;
+ int time_left;
if(pid == share_entry->pid)
{
@@ -3089,7 +3101,10 @@ to pid %d on port %d for dev = %x, inode = %x. Error was %s\n",
* While we get messages that aren't ours, loop.
*/
- while(1)
+ start_time = time(NULL);
+ time_left = OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR;
+
+ while(time_left >= 0)
{
char op_break_reply[UDP_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
int32 reply_msg_len;
@@ -3097,7 +3112,7 @@ to pid %d on port %d for dev = %x, inode = %x. Error was %s\n",
char *reply_msg_start;
if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply),
- (OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) * 1000) == False)
+ time_left ? time_left * 1000 : 1) == False)
{
if(smb_read_error == READ_TIMEOUT)
{
@@ -3120,23 +3135,6 @@ pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", timestring, shar
return False;
}
- /*
- * If the response we got was not an answer to our message, but
- * was a completely different request, push it onto the pending
- * udp message stack so that we can deal with it in the main loop.
- * It may be another oplock break request to us.
- */
-
- /*
- * Local note from JRA. There exists the possibility of a denial
- * of service attack here by allowing non-root processes running
- * on a local machine sending many of these pending messages to
- * a smbd port. Currently I'm not sure how to restrict the messages
- * I will queue (although I could add a limit to the queue) to
- * those received by root processes only. There should be a
- * way to make this bulletproof....
- */
-
reply_msg_len = IVAL(op_break_reply,UDP_CMD_LEN_OFFSET);
reply_from_port = SVAL(op_break_reply,UDP_CMD_PORT_OFFSET);
@@ -3150,21 +3148,37 @@ pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", timestring, shar
continue;
}
- if(((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) == 0) ||
- (reply_from_port != share_entry->op_port) ||
+ /*
+ * Test to see if this is the reply we are awaiting.
+ */
+
+ if((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) &&
+ (reply_from_port == share_entry->op_port) &&
(memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET],
&op_break_msg[OPLOCK_BREAK_PID_OFFSET],
- OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) != 0))
+ OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) == 0))
{
- 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",
- 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;
+ /*
+ * This is the reply we've been waiting for.
+ */
+ break;
}
+ else
+ {
+ /*
+ * This is another message - probably a break request.
+ * Process it to prevent potential deadlock.
+ * Note that the code in switch_message() prevents
+ * us from recursing into here as any SMB requests
+ * we might process that would cause another oplock
+ * break request to be made will be queued.
+ * JRA.
+ */
- break;
+ process_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply));
+ }
+
+ time_left -= (time(NULL) - start_time);
}
DEBUG(3,("%s request_oplock_break: broke oplock.\n", timestring()));
@@ -4522,7 +4536,7 @@ force write permissions on print services.
#define TIME_INIT (1<<2)
#define CAN_IPC (1<<3)
#define AS_GUEST (1<<5)
-
+#define QUEUE_IN_OPLOCK (1<<6)
/*
define a list of possible SMB messages and their corresponding
@@ -4556,20 +4570,20 @@ struct smb_message_struct
{SMBsetatr,"SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
{SMBchkpth,"SMBchkpth",reply_chkpth,AS_USER},
{SMBsearch,"SMBsearch",reply_search,AS_USER},
- {SMBopen,"SMBopen",reply_open,AS_USER},
+ {SMBopen,"SMBopen",reply_open,AS_USER | QUEUE_IN_OPLOCK },
/* note that SMBmknew and SMBcreate are deliberately overloaded */
{SMBcreate,"SMBcreate",reply_mknew,AS_USER},
{SMBmknew,"SMBmknew",reply_mknew,AS_USER},
- {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE},
+ {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
{SMBread,"SMBread",reply_read,AS_USER},
{SMBwrite,"SMBwrite",reply_write,AS_USER},
{SMBclose,"SMBclose",reply_close,AS_USER | CAN_IPC},
{SMBmkdir,"SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
{SMBrmdir,"SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
{SMBdskattr,"SMBdskattr",reply_dskattr,AS_USER},
- {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE},
+ {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
/* this is a Pathworks specific call, allowing the
changing of the root path */
@@ -4577,8 +4591,8 @@ struct smb_message_struct
{SMBlseek,"SMBlseek",reply_lseek,AS_USER},
{SMBflush,"SMBflush",reply_flush,AS_USER},
- {SMBctemp,"SMBctemp",reply_ctemp,AS_USER},
- {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER},
+ {SMBctemp,"SMBctemp",reply_ctemp,AS_USER | QUEUE_IN_OPLOCK },
+ {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER | QUEUE_IN_OPLOCK },
{SMBsplclose,"SMBsplclose",reply_printclose,AS_USER},
{SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER|AS_GUEST},
{SMBsplwr,"SMBsplwr",reply_printwrite,AS_USER},
@@ -4605,10 +4619,10 @@ struct smb_message_struct
{SMBtrans,"SMBtrans",reply_trans,AS_USER | CAN_IPC},
{SMBtranss,"SMBtranss",NULL,AS_USER | CAN_IPC},
{SMBioctls,"SMBioctls",NULL,AS_USER},
- {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE},
- {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE},
+ {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
+ {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
- {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER | CAN_IPC},
+ {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
{SMBreadX,"SMBreadX",reply_read_and_X,AS_USER},
{SMBwriteX,"SMBwriteX",reply_write_and_X,AS_USER},
{SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER},
@@ -4620,7 +4634,7 @@ struct smb_message_struct
/* LANMAN2.0 PROTOCOL FOLLOWS */
{SMBfindnclose, "SMBfindnclose", reply_findnclose, AS_USER},
{SMBfindclose, "SMBfindclose", reply_findclose,AS_USER},
- {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER},
+ {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER | QUEUE_IN_OPLOCK },
{SMBtranss2, "SMBtranss2", reply_transs2, AS_USER},
/* messaging routines */
@@ -4702,6 +4716,20 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
else
{
DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
+
+ if(global_oplock_break && (smb_messages[match].flags & QUEUE_IN_OPLOCK))
+ {
+ /*
+ * Queue this message as we are the process of an oplock break.
+ */
+
+ DEBUG(2,("%s: switch_message: queueing message due to being in oplock break state.\n",
+ timestring() ));
+
+ push_smb_message( inbuf, size);
+ return -1;
+ }
+
if (smb_messages[match].fn)
{
int cnum = SVAL(inbuf,smb_tid);