diff options
author | Volker Lendecke <vl@samba.org> | 2020-08-10 16:24:04 +0200 |
---|---|---|
committer | Volker Lendecke <vl@samba.org> | 2020-08-21 19:14:32 +0000 |
commit | eb72f887b0bf91c050fd5d911f58a1b3ff9b8bcc (patch) | |
tree | 2f7da1f741368f2ccaff558e23e75ec02b8ed14f /source4 | |
parent | 77f72fb01faba45babfe6080f805361492ce49e5 (diff) | |
download | samba-eb72f887b0bf91c050fd5d911f58a1b3ff9b8bcc.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>
Diffstat (limited to 'source4')
-rw-r--r-- | source4/ldap_server/ldap_backend.c | 37 | ||||
-rw-r--r-- | source4/ldap_server/ldap_server.c | 62 | ||||
-rw-r--r-- | source4/ldap_server/ldap_server.h | 1 |
3 files changed, 100 insertions, 0 deletions
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 036dfaab5ae..5cd72d3e258 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; @@ -1014,16 +1015,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; @@ -1032,6 +1079,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; }; |