summaryrefslogtreecommitdiff
path: root/source4/winbind
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2013-06-27 11:28:03 +1000
committerStefan Metzmacher <metze@samba.org>2013-07-10 06:57:06 +0200
commit2505d48e4fbcd8a805a88ad0b05fb1a16a588197 (patch)
treef396d19aceddb99a195d9f23142e6afbe36af57e /source4/winbind
parentdf929d6feb857668ad9da277213e9fae1480ff63 (diff)
downloadsamba-2505d48e4fbcd8a805a88ad0b05fb1a16a588197.tar.gz
s4-winbindd: Do not terminate a connection that is still pending (bug #9820)
Instead, wait until the call attempts to reply, and let it terminate then (often this happens in the attempt to then write to the broken pipe). Andrew Bartlett Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> Signed-off-by: Andrew Bartlett <abartlet@samba.org> Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'source4/winbind')
-rw-r--r--source4/winbind/wb_samba3_protocol.c5
-rw-r--r--source4/winbind/wb_server.c51
-rw-r--r--source4/winbind/wb_server.h10
3 files changed, 64 insertions, 2 deletions
diff --git a/source4/winbind/wb_samba3_protocol.c b/source4/winbind/wb_samba3_protocol.c
index 2846e9ce90d..1b78c99c1f9 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 983f9f56a0d..29ed5a67161 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 9b03004b285..26c404d12bd 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;