summaryrefslogtreecommitdiff
path: root/source3/nsswitch
diff options
context:
space:
mode:
Diffstat (limited to 'source3/nsswitch')
-rw-r--r--source3/nsswitch/winbindd.c53
-rw-r--r--source3/nsswitch/winbindd.h21
2 files changed, 59 insertions, 15 deletions
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index 8338b34822..35fef6e361 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 164b7ffda7..cc7cdc5297 100644
--- a/source3/nsswitch/winbindd.h
+++ b/source3/nsswitch/winbindd.h
@@ -35,16 +35,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 */