From f85f08419cd267f6d20c3ea6d072ddef49ca82c0 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 6 Jan 1999 23:32:13 +0000 Subject: Fixed the blocking locks and change notify code that got broken in beta5. The problem was that I had increased the select timeout so much that the client was sending echo requests as a sort of keepalive. As smbd only did timeout processing on select timeout then not much timeout processing was being done :-). I've fixed this by moving the timeout code to a function and calling it every time we get an SMBecho request (we must have been idle at that point). Jeremy. --- source/include/local.h | 2 +- source/include/proto.h | 13 +- source/smbd/process.c | 320 +++++++++++++++++++++++++++---------------------- source/smbd/reply.c | 4 +- 4 files changed, 184 insertions(+), 155 deletions(-) diff --git a/source/include/local.h b/source/include/local.h index 6aef7f0b8dd..cdff63aa8e5 100644 --- a/source/include/local.h +++ b/source/include/local.h @@ -126,7 +126,7 @@ /* the following control timings of various actions. Don't change them unless you know what you are doing. These are all in seconds */ #define DEFAULT_SMBD_TIMEOUT (60*60*24*7) -#define SMBD_RELOAD_CHECK (120) +#define SMBD_RELOAD_CHECK (180) #define IDLE_CLOSED_TIMEOUT (60) #define DPTR_IDLE_TIMEOUT (120) #define SMBD_SELECT_LOOP (60) diff --git a/source/include/proto.h b/source/include/proto.h index 72baf1c77ec..1f4f522ac77 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -2412,6 +2412,10 @@ int reply_negprot(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize); +/*The following definitions come from smbd/noquotas.c */ + +BOOL disk_quotas(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize); + /*The following definitions come from smbd/nttrans.c */ void fail_next_srvsvc_open(void); @@ -2506,15 +2510,6 @@ void construct_reply_common(char *inbuf,char *outbuf); int chain_reply(char *inbuf,char *outbuf,int size,int bufsize); void smbd_process(void); -/*The following definitions come from smbd/quotas.c */ - -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize); -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize); -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize); -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize); -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize); -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize); - /*The following definitions come from smbd/reply.c */ int reply_special(char *inbuf,char *outbuf); diff --git a/source/smbd/process.c b/source/smbd/process.c index f3d755f1060..1e263249f38 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -736,12 +736,168 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) return outsize2; } +/**************************************************************************** + Process any timeout housekeeping. Return False if the caler should exit. +****************************************************************************/ + +static BOOL timeout_processing(int *counter, int deadtime, + int *last_keepalive, int *service_load_counter) +{ + extern int Client; + + time_t t; + BOOL allidle = True; + extern int keepalive; + + if (*counter > 365 * 3600) /* big number of seconds. */ + { + *counter = 0; + *service_load_counter = 0; + } + + if (smb_read_error == READ_EOF) + { + DEBUG(3,("end of file from client\n")); + return False; + } + + if (smb_read_error == READ_ERROR) + { + DEBUG(3,("receive_smb error (%s) exiting\n", + strerror(errno))); + return False; + } + + t = time(NULL); + + /* become root again if waiting */ + unbecome_user(); + + /* check for smb.conf reload */ + if (*counter >= *service_load_counter + SMBD_RELOAD_CHECK) + { + *service_load_counter = *counter; + + /* reload services, if files have changed. */ + reload_services(True); + } + + /* + * If reload_after_sighup == True then we got a SIGHUP + * and are being asked to reload. Fix from + */ + + if (reload_after_sighup) + { + DEBUG(0,("Reloading services after SIGHUP\n")); + reload_services(False); + reload_after_sighup = False; + /* + * Use this as an excuse to print some stats. + */ + print_stat_cache_statistics(); + } + + /* automatic timeout if all connections are closed */ + if (conn_num_open()==0 && *counter >= IDLE_CLOSED_TIMEOUT) + { + DEBUG( 2, ( "Closing idle connection\n" ) ); + return False; + } + + if (keepalive && (*counter-*last_keepalive)>keepalive) + { + struct cli_state *cli = server_client(); + if (!send_keepalive(Client)) { + DEBUG( 2, ( "Keepalive failed - exiting.\n" ) ); + return False; + } + /* also send a keepalive to the password server if its still + connected */ + if (cli && cli->initialised) + send_keepalive(cli->fd); + *last_keepalive = *counter; + } + + /* check for connection timeouts */ + allidle = conn_idle_all(t, deadtime); + + if (allidle && conn_num_open()>0) { + DEBUG(2,("Closing idle connection 2.\n")); + return False; + } + + if(global_machine_password_needs_changing) + { + unsigned char trust_passwd_hash[16]; + time_t lct; + pstring remote_machine_list; + + /* + * We're in domain level security, and the code that + * read the machine password flagged that the machine + * password needs changing. + */ + + /* + * First, open the machine password file with an exclusive lock. + */ + + if(!trust_password_lock( global_myworkgroup, global_myname, True)) { + DEBUG(0,("process: unable to open the machine account password file for \ +machine %s in domain %s.\n", global_myname, global_myworkgroup )); + return True; + } + + if(!get_trust_account_password( trust_passwd_hash, &lct)) { + DEBUG(0,("process: unable to read the machine account password for \ +machine %s in domain %s.\n", global_myname, global_myworkgroup )); + trust_password_unlock(); + return True; + } + + /* + * Make sure someone else hasn't already done this. + */ + + if(t < lct + lp_machine_password_timeout()) { + trust_password_unlock(); + global_machine_password_needs_changing = False; + return True; + } + + pstrcpy(remote_machine_list, lp_passwordserver()); + + change_trust_account_password( global_myworkgroup, remote_machine_list); + trust_password_unlock(); + global_machine_password_needs_changing = False; + } + + /* + * Check to see if we have any blocking locks + * outstanding on the queue. + */ + process_blocking_lock_queue(t); + + /* + * Check to see if we have any change notifies + * outstanding on the queue. + */ + process_pending_change_notify_queue(t); + + return True; +} + /**************************************************************************** process commands from the client ****************************************************************************/ + void smbd_process(void) { - extern int Client; + extern int smb_echo_count; + int counter = SMBD_SELECT_LOOP; + int service_load_counter = 0; + int last_keepalive=0; InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); @@ -771,9 +927,6 @@ void smbd_process(void) while (True) { int deadtime = lp_deadtime()*60; - int counter; - int last_keepalive=0; - int service_load_counter = 0; BOOL got_smb = False; if (deadtime <= 0) @@ -786,154 +939,33 @@ void smbd_process(void) errno = 0; - for (counter=SMBD_SELECT_LOOP; - !receive_message_or_smb(InBuffer,BUFFER_SIZE, - SMBD_SELECT_LOOP*1000,&got_smb); - counter += SMBD_SELECT_LOOP) + while(!receive_message_or_smb(InBuffer,BUFFER_SIZE,SMBD_SELECT_LOOP*1000,&got_smb)) { - time_t t; - BOOL allidle = True; - extern int keepalive; - - if (counter > 365 * 3600) /* big number of seconds. */ - { - counter = 0; - service_load_counter = 0; - } - - if (smb_read_error == READ_EOF) - { - DEBUG(3,("end of file from client\n")); + if(!timeout_processing(&counter, deadtime, &last_keepalive, &service_load_counter)) return; - } - - if (smb_read_error == READ_ERROR) - { - DEBUG(3,("receive_smb error (%s) exiting\n", - strerror(errno))); - return; - } - - t = time(NULL); - - /* become root again if waiting */ - unbecome_user(); - - /* check for smb.conf reload */ - if (counter >= service_load_counter + SMBD_RELOAD_CHECK) - { - service_load_counter = counter; - - /* reload services, if files have changed. */ - reload_services(True); - } + counter += SMBD_SELECT_LOOP; + } + if(got_smb) { /* - * If reload_after_sighup == True then we got a SIGHUP - * and are being asked to reload. Fix from - */ - - if (reload_after_sighup) - { - DEBUG(0,("Reloading services after SIGHUP\n")); - reload_services(False); - reload_after_sighup = False; - /* - * Use this as an excuse to print some stats. - */ - print_stat_cache_statistics(); - } - - /* automatic timeout if all connections are closed */ - if (conn_num_open()==0 && counter >= IDLE_CLOSED_TIMEOUT) - { - DEBUG( 2, ( "Closing idle connection\n" ) ); - return; - } - - if (keepalive && (counter-last_keepalive)>keepalive) - { - struct cli_state *cli = server_client(); - if (!send_keepalive(Client)) { - DEBUG( 2, ( "Keepalive failed - exiting.\n" ) ); - return; - } - /* also send a keepalive to the password server if its still - connected */ - if (cli && cli->initialised) - send_keepalive(cli->fd); - last_keepalive = counter; - } - - /* check for connection timeouts */ - allidle = conn_idle_all(t, deadtime); - - if (allidle && conn_num_open()>0) { - DEBUG(2,("Closing idle connection 2.\n")); - return; - } - - if(global_machine_password_needs_changing) - { - unsigned char trust_passwd_hash[16]; - time_t lct; - pstring remote_machine_list; + * Ensure we do timeout processing if the SMB we just got was + * only an echo request. This allows us to set the select + * timeout in 'receive_message_or_smb()' to any value we like + * without worrying that the client will send echo requests + * faster than the select timeout, thus starving out the + * essential processing (change notify, blocking locks) that + * the timeout code does. JRA. + */ + int num_echos = smb_echo_count; - /* - * We're in domain level security, and the code that - * read the machine password flagged that the machine - * password needs changing. - */ - - /* - * First, open the machine password file with an exclusive lock. - */ - - if(!trust_password_lock( global_myworkgroup, global_myname, True)) { - DEBUG(0,("process: unable to open the machine account password file for \ -machine %s in domain %s.\n", global_myname, global_myworkgroup )); - continue; - } - - if(!get_trust_account_password( trust_passwd_hash, &lct)) { - DEBUG(0,("process: unable to read the machine account password for \ -machine %s in domain %s.\n", global_myname, global_myworkgroup )); - trust_password_unlock(); - continue; - } - - /* - * Make sure someone else hasn't already done this. - */ - - if(t < lct + lp_machine_password_timeout()) { - trust_password_unlock(); - global_machine_password_needs_changing = False; - continue; - } - - pstrcpy(remote_machine_list, lp_passwordserver()); + process_smb(InBuffer, OutBuffer); - change_trust_account_password( global_myworkgroup, remote_machine_list); - trust_password_unlock(); - global_machine_password_needs_changing = False; + if(smb_echo_count != num_echos) { + if(!timeout_processing(&counter, deadtime, &last_keepalive, &service_load_counter)) + return; + counter += SMBD_SELECT_LOOP; } - - /* - * Check to see if we have any blocking locks - * outstanding on the queue. - */ - process_blocking_lock_queue(t); - - /* - * Check to see if we have any change notifies - * outstanding on the queue. - */ - process_pending_change_notify_queue(t); } - - if(got_smb) - process_smb(InBuffer, OutBuffer); else process_local_message(InBuffer, BUFFER_SIZE); } diff --git a/source/smbd/reply.c b/source/smbd/reply.c index c6ebd70c423..b13563182c9 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -42,7 +42,7 @@ extern fstring global_myworkgroup; extern int Client; extern int global_oplock_break; uint32 global_client_caps = 0; - +unsigned int smb_echo_count = 0; /**************************************************************************** report a possible attack via the password buffer overflow bug @@ -2833,6 +2833,8 @@ int reply_echo(connection_struct *conn, DEBUG(3,("echo %d times\n", smb_reverb)); + smb_echo_count++; + return -1; } -- cgit