mirror of
https://github.com/samba-team/samba.git
synced 2025-01-12 09:18:10 +03:00
printing.c: Bug fix for lpng reporting.
server.c: Large fix for oplock deadlock bug.
util.c: Fix for oplock deadlock bug.
Jeremy.
(This used to be commit 4cae830ab3
)
This commit is contained in:
parent
a7a312a32d
commit
118213c059
@ -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);
|
||||
|
@ -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,12 +2524,22 @@ 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.
|
||||
|
||||
@ -2535,6 +2547,10 @@ BOOL push_local_message(char *buf, int msg_len)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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)));
|
||||
|
@ -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.
|
||||
*/
|
||||
|
||||
process_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply));
|
||||
}
|
||||
|
||||
break;
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user