diff options
-rw-r--r-- | source4/winbind/wb_samba3_protocol.c | 5 | ||||
-rw-r--r-- | source4/winbind/wb_server.c | 51 | ||||
-rw-r--r-- | source4/winbind/wb_server.h | 10 |
3 files changed, 64 insertions, 2 deletions
diff --git a/source4/winbind/wb_samba3_protocol.c b/source4/winbind/wb_samba3_protocol.c index 2846e9ce90..1b78c99c1f 100644 --- a/source4/winbind/wb_samba3_protocol.c +++ b/source4/winbind/wb_samba3_protocol.c @@ -297,6 +297,8 @@ NTSTATUS wbsrv_samba3_send_reply(struct wbsrv_samba3_call *call) struct tevent_req *subreq; NTSTATUS status; + call->wbconn->pending_calls--; + status = wbsrv_samba3_push_reply(call); NT_STATUS_NOT_OK_RETURN(status); @@ -355,9 +357,12 @@ NTSTATUS wbsrv_samba3_process(struct wbsrv_samba3_call *call) return status; } + call->wbconn->pending_calls++; + status = wbsrv_samba3_handle_call(call); if (!NT_STATUS_IS_OK(status)) { + call->wbconn->pending_calls--; talloc_free(call); return status; } diff --git a/source4/winbind/wb_server.c b/source4/winbind/wb_server.c index 983f9f56a0..29ed5a6716 100644 --- a/source4/winbind/wb_server.c +++ b/source4/winbind/wb_server.c @@ -28,19 +28,66 @@ #include "libcli/util/tstream.h" #include "param/param.h" #include "param/secrets.h" +#include "lib/util/dlinklist.h" void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *reason) { - stream_terminate_connection(wbconn->conn, reason); + struct wbsrv_service *service = wbconn->listen_socket->service; + + if (wbconn->pending_calls == 0) { + char *full_reason = talloc_asprintf(wbconn, "wbsrv: %s", reason); + + DLIST_REMOVE(service->broken_connections, wbconn); + stream_terminate_connection(wbconn->conn, full_reason ? full_reason : reason); + return; + } + + if (wbconn->terminate != NULL) { + return; + } + + DEBUG(3,("wbsrv: terminating connection due to '%s' defered due to %d pending calls\n", + reason, wbconn->pending_calls)); + wbconn->terminate = talloc_strdup(wbconn, reason); + if (wbconn->terminate == NULL) { + wbconn->terminate = "wbsrv: defered terminating connection - no memory"; + } + DLIST_ADD_END(service->broken_connections, wbconn, NULL); +} + +static void wbsrv_cleanup_broken_connections(struct wbsrv_service *s) +{ + struct wbsrv_connection *cur, *next; + + next = s->broken_connections; + while (next != NULL) { + cur = next; + next = cur->next; + + wbsrv_terminate_connection(cur, cur->terminate); + } } static void wbsrv_call_loop(struct tevent_req *subreq) { struct wbsrv_connection *wbsrv_conn = tevent_req_callback_data(subreq, struct wbsrv_connection); + struct wbsrv_service *service = wbsrv_conn->listen_socket->service; struct wbsrv_samba3_call *call; NTSTATUS status; + if (wbsrv_conn->terminate) { + /* + * if the current connection is broken + * we need to clean it up before any other connection + */ + wbsrv_terminate_connection(wbsrv_conn, wbsrv_conn->terminate); + wbsrv_cleanup_broken_connections(service); + return; + } + + wbsrv_cleanup_broken_connections(service); + call = talloc_zero(wbsrv_conn, struct wbsrv_samba3_call); if (call == NULL) { wbsrv_terminate_connection(wbsrv_conn, "wbsrv_call_loop: " @@ -112,6 +159,8 @@ static void wbsrv_accept(struct stream_connection *conn) struct tevent_req *subreq; int rc; + wbsrv_cleanup_broken_connections(wbsrv_socket->service); + wbsrv_conn = talloc_zero(conn, struct wbsrv_connection); if (wbsrv_conn == NULL) { stream_terminate_connection(conn, "wbsrv_accept: out of memory"); diff --git a/source4/winbind/wb_server.h b/source4/winbind/wb_server.h index 9b03004b28..26c404d12b 100644 --- a/source4/winbind/wb_server.h +++ b/source4/winbind/wb_server.h @@ -34,6 +34,8 @@ struct wbsrv_service { struct idmap_context *idmap_ctx; const char *priv_pipe_dir; const char *pipe_dir; + + struct wbsrv_connection *broken_connections; }; struct wbsrv_samconn { @@ -85,6 +87,9 @@ struct wbsrv_listen_socket { state of an open winbind connection */ struct wbsrv_connection { + /* for the broken_connections DLIST */ + struct wbsrv_connection *prev, *next; + /* stream connection we belong to */ struct stream_connection *conn; @@ -94,9 +99,12 @@ struct wbsrv_connection { /* storage for protocol specific data */ void *protocol_private_data; - /* how many calls are pending */ + /* how many calls are pending (do not terminate the connection with calls pending a reply) */ uint32_t pending_calls; + /* is this connection pending termination? If so, why? */ + const char *terminate; + struct tstream_context *tstream; struct tevent_queue *send_queue; |