summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2020-08-10 16:24:04 +0200
committerKarolin Seeger <kseeger@samba.org>2020-08-31 09:26:35 +0000
commita8dfc1ad59f662ff1f01192c91a8a7d169e0938b (patch)
tree068f86c159ca3fe14bd2f5dab52965f47f5b73b9
parent6026130628ea63eade45409360e434f4813f4ebe (diff)
downloadsamba-a8dfc1ad59f662ff1f01192c91a8a7d169e0938b.tar.gz
ldap_server: Terminate LDAP connections on krb ticket expiry
See RFC4511 section 4.4.1 and https://lists.samba.org/archive/cifs-protocol/2020-August/003515.html for details: Windows terminates LDAP connections when the krb5 ticket expires, Samba should do the same. This patch slightly deviates from Windows behaviour by sending a LDAP exop response with msgid 0 that is ASN1-encoded conforming to RFC4511. Bug: https://bugzilla.samba.org/show_bug.cgi?id=14465 Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org> (cherry picked from commit eb72f887b0bf91c050fd5d911f58a1b3ff9b8bcc)
-rw-r--r--selftest/knownfail.d/ldap1
-rw-r--r--source4/ldap_server/ldap_backend.c37
-rw-r--r--source4/ldap_server/ldap_server.c62
-rw-r--r--source4/ldap_server/ldap_server.h1
4 files changed, 100 insertions, 1 deletions
diff --git a/selftest/knownfail.d/ldap b/selftest/knownfail.d/ldap
index 21c1aca7e6e..0331d3687d4 100644
--- a/selftest/knownfail.d/ldap
+++ b/selftest/knownfail.d/ldap
@@ -1,4 +1,3 @@
# the attributes too long test returns the wrong error
^samba4.ldap.python.+test_attribute_ranges_too_long
samba4.ldap.python\(ad_dc_default\).*__main__.BasicTests.test_ldapSearchNoAttributes
-^samba4.ldap.session-expiry.session-expiry\(ad_dc_default\)
diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c
index bf724335a25..2839082daef 100644
--- a/source4/ldap_server/ldap_backend.c
+++ b/source4/ldap_server/ldap_backend.c
@@ -1384,11 +1384,48 @@ static NTSTATUS ldapsrv_AbandonRequest(struct ldapsrv_call *call)
return NT_STATUS_OK;
}
+static NTSTATUS ldapsrv_expired(struct ldapsrv_call *call)
+{
+ struct ldapsrv_reply *reply = NULL;
+ struct ldap_ExtendedResponse *r = NULL;
+
+ DBG_DEBUG("Sending connection expired message\n");
+
+ reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
+ if (reply == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * According to RFC4511 section 4.4.1 this has a msgid of 0
+ */
+ reply->msg->messageid = 0;
+
+ r = &reply->msg->r.ExtendedResponse;
+ r->response.resultcode = LDB_ERR_UNAVAILABLE;
+ r->response.errormessage = "The server has timed out this connection";
+ r->oid = "1.3.6.1.4.1.1466.20036"; /* see rfc4511 section 4.4.1 */
+
+ ldapsrv_queue_reply(call, reply);
+ return NT_STATUS_OK;
+}
+
NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call)
{
unsigned int i;
struct ldap_message *msg = call->request;
+ struct ldapsrv_connection *conn = call->conn;
NTSTATUS status;
+ bool expired;
+
+ expired = timeval_expired(&conn->limits.expire_time);
+ if (expired) {
+ status = ldapsrv_expired(call);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return NT_STATUS_NETWORK_SESSION_EXPIRED;
+ }
/* Check for undecoded critical extensions */
for (i=0; msg->controls && msg->controls[i]; i++) {
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
index 3a37ddbcaf9..fd2309b7ce3 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -69,6 +69,7 @@ static void ldapsrv_terminate_connection(struct ldapsrv_connection *conn,
tevent_queue_stop(conn->sockets.send_queue);
TALLOC_FREE(conn->sockets.read_req);
+ TALLOC_FREE(conn->deferred_expire_disconnect);
if (conn->active_call) {
tevent_req_cancel(conn->active_call);
conn->active_call = NULL;
@@ -1016,16 +1017,62 @@ static struct tevent_req *ldapsrv_process_call_send(TALLOC_CTX *mem_ctx,
return req;
}
+static void ldapsrv_disconnect_ticket_expired(struct tevent_req *subreq);
+
static void ldapsrv_process_call_trigger(struct tevent_req *req,
void *private_data)
{
struct ldapsrv_process_call_state *state =
tevent_req_data(req,
struct ldapsrv_process_call_state);
+ struct ldapsrv_connection *conn = state->call->conn;
NTSTATUS status;
+ if (conn->deferred_expire_disconnect != NULL) {
+ /*
+ * Just drop this on the floor
+ */
+ tevent_req_done(req);
+ return;
+ }
+
/* make the call */
status = ldapsrv_do_call(state->call);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
+ /*
+ * For testing purposes, defer the TCP disconnect
+ * after having sent the msgid 0
+ * 1.3.6.1.4.1.1466.20036 exop response. LDAP clients
+ * should not wait for the TCP connection to close but
+ * handle this packet equivalent to a TCP
+ * disconnect. This delay enables testing both cases
+ * in LDAP client libraries.
+ */
+
+ int defer_msec = lpcfg_parm_int(
+ conn->lp_ctx,
+ NULL,
+ "ldap_server",
+ "delay_expire_disconnect",
+ 0);
+
+ conn->deferred_expire_disconnect = tevent_wakeup_send(
+ conn,
+ conn->connection->event.ctx,
+ timeval_current_ofs_msec(defer_msec));
+ if (tevent_req_nomem(conn->deferred_expire_disconnect, req)) {
+ return;
+ }
+ tevent_req_set_callback(
+ conn->deferred_expire_disconnect,
+ ldapsrv_disconnect_ticket_expired,
+ conn);
+
+ tevent_req_done(req);
+ return;
+ }
+
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return;
@@ -1034,6 +1081,21 @@ static void ldapsrv_process_call_trigger(struct tevent_req *req,
tevent_req_done(req);
}
+static void ldapsrv_disconnect_ticket_expired(struct tevent_req *subreq)
+{
+ struct ldapsrv_connection *conn = tevent_req_callback_data(
+ subreq, struct ldapsrv_connection);
+ bool ok;
+
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ DBG_WARNING("tevent_wakeup_recv failed\n");
+ }
+ conn->deferred_expire_disconnect = NULL;
+ ldapsrv_terminate_connection(conn, "network session expired");
+}
+
static NTSTATUS ldapsrv_process_call_recv(struct tevent_req *req)
{
NTSTATUS status;
diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h
index 74c19fd2fbc..c94bd914b9b 100644
--- a/source4/ldap_server/ldap_server.h
+++ b/source4/ldap_server/ldap_server.h
@@ -66,6 +66,7 @@ struct ldapsrv_connection {
} limits;
struct tevent_req *active_call;
+ struct tevent_req *deferred_expire_disconnect;
struct ldapsrv_call *pending_calls;
};