From 9f0ae6fad2d0099a58fec389ddd430c0448ec02e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 28 Feb 2003 00:26:20 +0000 Subject: [PATCH] *Excellent* patch from Michael Steffens to limit the unix domain sockets used by winbindd (also solves FD_SETSIZE problem in winbindd to boot !). Adds a "last_access" field to winbindd connections, and will close the oldest idle connection once the number of open connections goes over WINBINDD_MAX_SIMULTANEOUS_CLIENTS (defined in local.h as 200 currently). Jeremy. (This used to be commit a82caefda49396641e8650db8a7ef51752ba6c41) --- source3/include/local.h | 2 ++ source3/nsswitch/winbindd.c | 53 +++++++++++++++++++++++++++++++++---- source3/nsswitch/winbindd.h | 21 ++++++++------- 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/source3/include/local.h b/source3/include/local.h index e16cdbbc5dc..29b0641119d 100644 --- a/source3/include/local.h +++ b/source3/include/local.h @@ -221,4 +221,6 @@ /* Number in seconds for winbindd to wait for the mutex. Make this 2 * smbd wait time. */ #define WINBIND_SERVER_MUTEX_WAIT_TIME (( ((NUM_CLI_AUTH_CONNECT_RETRIES) * ((CLI_AUTH_TIMEOUT)/1000)) + 5)*2) +/* Max number of simultaneous winbindd socket connections. */ +#define WINBINDD_MAX_SIMULTANEOUS_CLIENTS 200 #endif diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index 09b89462ecd..ad37768c090 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -339,7 +339,9 @@ static void new_connection(int listen_sock) ZERO_STRUCTP(state); state->sock = sock; - + + state->last_access = time(NULL); + /* Add to connection list */ winbindd_add_client(state); @@ -375,6 +377,35 @@ static void remove_client(struct winbindd_cli_state *state) } +/* Shutdown client connection which has been idle for the longest time */ + +static BOOL remove_idle_client(void) +{ + struct winbindd_cli_state *state, *remove_state = NULL; + time_t last_access = 0; + int nidle = 0; + + for (state = winbindd_client_list(); state; state = state->next) { + if (state->read_buf_len == 0 && state->write_buf_len == 0 && + !state->getpwent_state && !state->getgrent_state) { + nidle++; + if (!last_access || state->last_access < last_access) { + last_access = state->last_access; + remove_state = state; + } + } + } + + if (remove_state) { + DEBUG(5,("Found %d idle client connections, shutting down sock %d, pid %u\n", + nidle, remove_state->sock, (unsigned int)remove_state->pid)); + remove_client(remove_state); + return True; + } + + return False; +} + /* Process a complete received packet from a client */ void winbind_process_packet(struct winbindd_cli_state *state) @@ -427,6 +458,7 @@ void winbind_client_read(struct winbindd_cli_state *state) /* Update client state */ state->read_buf_len += n; + state->last_access = time(NULL); } /* Write some data to a client connection */ @@ -477,7 +509,8 @@ static void client_write(struct winbindd_cli_state *state) /* Update client state */ state->write_buf_len -= num_written; - + state->last_access = time(NULL); + /* Have we written all data? */ if (state->write_buf_len == 0) { @@ -508,7 +541,7 @@ static void client_write(struct winbindd_cli_state *state) } } -/* Process incoming clients on accept_sock. We use a tricky non-blocking, +/* Process incoming clients on listen_sock. We use a tricky non-blocking, non-forking, non-threaded model which allows us to handle many simultaneous connections while remaining impervious to many denial of service attacks. */ @@ -608,7 +641,7 @@ static void process_loop(void) exit(1); } - /* Create a new connection if accept_sock readable */ + /* Create a new connection if listen_sock readable */ if (selret > 0) { @@ -616,8 +649,18 @@ static void process_loop(void) dual_select(&w_fds); } - if (FD_ISSET(listen_sock, &r_fds)) + if (FD_ISSET(listen_sock, &r_fds)) { + while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) { + DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n", + WINBINDD_MAX_SIMULTANEOUS_CLIENTS)); + if (!remove_idle_client()) { + DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n", + WINBINDD_MAX_SIMULTANEOUS_CLIENTS)); + break; + } + } new_connection(listen_sock); + } /* Process activity on client connections */ diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 8bd8a837481..42ef209fafa 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -36,16 +36,17 @@ /* Client state structure */ struct winbindd_cli_state { - struct winbindd_cli_state *prev, *next; /* Linked list pointers */ - int sock; /* Open socket from client */ - pid_t pid; /* pid of client */ - int read_buf_len, write_buf_len; /* Indexes in request/response */ - BOOL finished; /* Can delete from list */ - BOOL write_extra_data; /* Write extra_data field */ - struct winbindd_request request; /* Request from client */ - struct winbindd_response response; /* Respose to client */ - struct getent_state *getpwent_state; /* State for getpwent() */ - struct getent_state *getgrent_state; /* State for getgrent() */ + struct winbindd_cli_state *prev, *next; /* Linked list pointers */ + int sock; /* Open socket from client */ + pid_t pid; /* pid of client */ + int read_buf_len, write_buf_len; /* Indexes in request/response */ + BOOL finished; /* Can delete from list */ + BOOL write_extra_data; /* Write extra_data field */ + time_t last_access; /* Time of last access (read or write) */ + struct winbindd_request request; /* Request from client */ + struct winbindd_response response; /* Respose to client */ + struct getent_state *getpwent_state; /* State for getpwent() */ + struct getent_state *getgrent_state; /* State for getgrent() */ }; /* State between get{pw,gr}ent() calls */ -- 2.34.1