diff options
Diffstat (limited to 'source/smbd/process.c')
-rw-r--r-- | source/smbd/process.c | 233 |
1 files changed, 74 insertions, 159 deletions
diff --git a/source/smbd/process.c b/source/smbd/process.c index 38d6e4d7cf1..aaf98203a25 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -26,8 +26,6 @@ extern int keepalive; extern struct auth_context *negprot_global_auth_context; extern int smb_echo_count; -struct timeval smb_last_time; - static char *InBuffer = NULL; static char *OutBuffer = NULL; static char *current_inbuf = NULL; @@ -91,7 +89,7 @@ static BOOL push_queued_message(char *buf, int msg_len, msg->buf = data_blob_talloc(msg, buf, msg_len); if(msg->buf.data == NULL) { DEBUG(0,("push_message: malloc fail (2)\n")); - talloc_free(msg); + TALLOC_FREE(msg); return False; } @@ -103,7 +101,7 @@ static BOOL push_queued_message(char *buf, int msg_len, private_len); if (msg->private_data.data == NULL) { DEBUG(0,("push_message: malloc fail (3)\n")); - talloc_free(msg); + TALLOC_FREE(msg); return False; } } @@ -131,7 +129,7 @@ void remove_deferred_open_smb_message(uint16 mid) (unsigned int)mid, (unsigned int)pml->buf.length )); DLIST_REMOVE(deferred_open_queue, pml); - talloc_free(pml); + TALLOC_FREE(pml); return; } } @@ -223,115 +221,6 @@ BOOL push_deferred_smb_message(uint16 mid, private_data, priv_len); } -static struct timed_event *timed_events; - -struct timed_event { - struct timed_event *next, *prev; - struct timeval when; - const char *event_name; - void (*handler)(struct timed_event *te, - const struct timeval *now, - void *private_data); - void *private_data; -}; - -static int timed_event_destructor(void *p) -{ - struct timed_event *te = talloc_get_type_abort(p, struct timed_event); - DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te, - te->event_name)); - DLIST_REMOVE(timed_events, te); - return 0; -} - -/**************************************************************************** - Schedule a function for future calling, cancel with talloc_free(). - It's the responsibility of the handler to call talloc_free() on the event - handed to it. -****************************************************************************/ - -struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx, - struct timeval when, - const char *event_name, - void (*handler)(struct timed_event *te, - const struct timeval *now, - void *private_data), - void *private_data) -{ - struct timed_event *te, *last_te, *cur_te; - - te = TALLOC_P(mem_ctx, struct timed_event); - if (te == NULL) { - DEBUG(0, ("talloc failed\n")); - return NULL; - } - - te->when = when; - te->event_name = event_name; - te->handler = handler; - te->private_data = private_data; - - /* keep the list ordered */ - last_te = NULL; - for (cur_te = timed_events; cur_te; cur_te = cur_te->next) { - /* if the new event comes before the current one break */ - if (!timeval_is_zero(&cur_te->when) && - timeval_compare(&te->when, &cur_te->when) < 0) { - break; - } - last_te = cur_te; - } - - DLIST_ADD_AFTER(timed_events, te, last_te); - talloc_set_destructor(te, timed_event_destructor); - - DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name, - (unsigned long)te)); - return te; -} - -static void run_events(void) -{ - struct timeval now; - - if (timed_events == NULL) { - /* No syscall if there are no events */ - DEBUG(10, ("run_events: No events\n")); - return; - } - - GetTimeOfDay(&now); - - if (timeval_compare(&now, &timed_events->when) < 0) { - /* Nothing to do yet */ - DEBUG(10, ("run_events: Nothing to do\n")); - return; - } - - DEBUG(10, ("Running event \"%s\" %lx\n", timed_events->event_name, - (unsigned long)timed_events)); - - timed_events->handler(timed_events, &now, timed_events->private_data); - return; -} - -struct timeval timed_events_timeout(void) -{ - struct timeval now, timeout; - - if (timed_events == NULL) { - return timeval_set(SMBD_SELECT_TIMEOUT, 0); - } - - now = timeval_current(); - timeout = timeval_until(&now, &timed_events->when); - - DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)timeout.tv_sec, - (int)timeout.tv_usec)); - - return timeout; -} - struct idle_event { struct timed_event *te; struct timeval interval; @@ -346,11 +235,11 @@ static void idle_event_handler(struct timed_event *te, struct idle_event *event = talloc_get_type_abort(private_data, struct idle_event); - talloc_free(event->te); + TALLOC_FREE(event->te); if (!event->handler(now, event->private_data)) { /* Don't repeat, delete ourselves */ - talloc_free(event); + TALLOC_FREE(event); return; } @@ -386,13 +275,13 @@ struct idle_event *add_idle_event(TALLOC_CTX *mem_ctx, idle_event_handler, result); if (result->te == NULL) { DEBUG(0, ("add_timed_event failed\n")); - talloc_free(result); + TALLOC_FREE(result); return NULL; } return result; } - + /**************************************************************************** Do all async processing in here. This includes kernel oplock messages, change notify events etc. @@ -412,7 +301,7 @@ static void async_processing(fd_set *pfds) process_aio_queue(); if (got_sig_term) { - exit_server("Caught TERM signal"); + exit_server_cleanly("termination signal"); } /* check for async change notify events */ @@ -428,6 +317,20 @@ static void async_processing(fd_set *pfds) } /**************************************************************************** + Add a fd to the set we will be select(2)ing on. +****************************************************************************/ + +static int select_on_fd(int fd, int maxfd, fd_set *fds) +{ + if (fd != -1) { + FD_SET(fd, fds); + maxfd = MAX(maxfd, fd); + } + + return maxfd; +} + +/**************************************************************************** Do a select on an two fd's - with timeout. If a local udp message has been pushed onto the @@ -452,8 +355,8 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) { fd_set fds; int selrtn; - struct timeval to = timeval_set(SMBD_SELECT_TIMEOUT, 0); - int maxfd; + struct timeval to; + int maxfd = 0; smb_read_error = 0; @@ -462,6 +365,9 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) if (timeout >= 0) { to.tv_sec = timeout / 1000; to.tv_usec = (timeout % 1000) * 1000; + } else { + to.tv_sec = SMBD_SELECT_TIMEOUT; + to.tv_usec = 0; } /* @@ -536,18 +442,29 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) goto again; } + /* + * Are there any timed events waiting ? If so, ensure we don't + * select for longer than it would take to wait for them. + */ + { - struct timeval tmp = timed_events_timeout(); - to = timeval_min(&to, &tmp); - if (timeval_is_zero(&to)) { - return True; + struct timeval tmp; + struct timeval *tp = get_timed_events_timeout(&tmp); + + if (tp) { + to = timeval_min(&to, tp); + if (timeval_is_zero(&to)) { + /* Process a timed event now... */ + run_events(); + } } } - FD_SET(smbd_server_fd(),&fds); - maxfd = setup_oplock_select_set(&fds); + maxfd = select_on_fd(smbd_server_fd(), maxfd, &fds); + maxfd = select_on_fd(change_notify_fd(), maxfd, &fds); + maxfd = select_on_fd(oplock_notify_fd(), maxfd, &fds); - selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,&to); + selrtn = sys_select(maxfd+1,&fds,NULL,NULL,&to); /* if we get EINTR then maybe we have received an oplock signal - treat this as select returning 1. This is ugly, but @@ -595,22 +512,27 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) return receive_smb(smbd_server_fd(), buffer, 0); } -/**************************************************************************** -Get the next SMB packet, doing the local message processing automatically. -****************************************************************************/ +/* + * Only allow 5 outstanding trans requests. We're allocating memory, so + * prevent a DoS. + */ -BOOL receive_next_smb(char *inbuf, int bufsize, int timeout) +NTSTATUS allow_new_trans(struct trans_state *list, int mid) { - BOOL got_keepalive; - BOOL ret; + int count = 0; + for (; list != NULL; list = list->next) { - do { - ret = receive_message_or_smb(inbuf,bufsize,timeout); - - got_keepalive = (ret && (CVAL(inbuf,0) == SMBkeepalive)); - } while (ret && got_keepalive); + if (list->mid == mid) { + return NT_STATUS_INVALID_PARAMETER; + } + + count += 1; + } + if (count > 5) { + return NT_STATUS_INSUFFICIENT_RESOURCES; + } - return ret; + return NT_STATUS_OK; } /**************************************************************************** @@ -701,7 +623,7 @@ static const struct smb_message_struct { /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER }, /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER }, /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC }, -/* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC}, +/* 0x26 */ { "SMBtranss",reply_transs,AS_USER | CAN_IPC}, /* 0x27 */ { "SMBioctl",reply_ioctl,0}, /* 0x28 */ { "SMBioctls",NULL,AS_USER}, /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE }, @@ -971,7 +893,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize /* Make sure this is an SMB packet. smb_size contains NetBIOS header so subtract 4 from it. */ if ((strncmp(smb_base(inbuf),"\377SMB",4) != 0) || (size < (smb_size - 4))) { DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",smb_len(inbuf))); - exit_server("Non-SMB packet"); + exit_server_cleanly("Non-SMB packet"); return(-1); } @@ -1087,8 +1009,6 @@ static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize) int outsize = 0; int msg_type = CVAL(inbuf,0); - GetTimeOfDay(&smb_last_time); - chain_size = 0; file_chain_reset(); reset_chain_p(); @@ -1162,11 +1082,10 @@ set. Ignoring max smbd restriction.\n")); } /**************************************************************************** - Process an smb from the client - split out from the smbd_process() code so - it can be used by the oplock break code. + Process an smb from the client ****************************************************************************/ -void process_smb(char *inbuf, char *outbuf) +static void process_smb(char *inbuf, char *outbuf) { static int trans_num; int msg_type = CVAL(inbuf,0); @@ -1186,7 +1105,7 @@ void process_smb(char *inbuf, char *outbuf) static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81}; DEBUG( 1, ( "Connection denied from %s\n", client_addr() ) ); (void)send_smb(smbd_server_fd(),(char *)buf); - exit_server("connection denied"); + exit_server_cleanly("connection denied"); } } @@ -1208,7 +1127,7 @@ void process_smb(char *inbuf, char *outbuf) DEBUG(0,("ERROR: Invalid message response size! %d %d\n", nread, smb_len(outbuf))); } else if (!send_smb(smbd_server_fd(),outbuf)) { - exit_server("process_smb: send_smb failed."); + exit_server_cleanly("process_smb: send_smb failed."); } } trans_num++; @@ -1246,20 +1165,16 @@ void remove_from_common_flags2(uint32 v) void construct_reply_common(char *inbuf,char *outbuf) { - memset(outbuf,'\0',smb_size); - - set_message(outbuf,0,0,True); - SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com)); + set_message(outbuf,0,0,False); - memcpy(outbuf+4,inbuf+4,4); - SCVAL(outbuf,smb_rcls,SMB_SUCCESS); - SCVAL(outbuf,smb_reh,0); + SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com)); + SIVAL(outbuf,smb_rcls,0); SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); SSVAL(outbuf,smb_flg2, (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) | common_flags2); + memset(outbuf+smb_pidhigh,'\0',(smb_tid-smb_pidhigh)); - SSVAL(outbuf,smb_err,SMB_SUCCESS); SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid)); SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid)); SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid)); @@ -1715,8 +1630,8 @@ void smbd_process(void) errno = 0; /* free up temporary memory */ - lp_talloc_free(); - main_loop_talloc_free(); + lp_TALLOC_FREE(); + main_loop_TALLOC_FREE(); /* Did someone ask for immediate checks on things like blocking locks ? */ if (select_timeout == 0) { |