mirror of
https://github.com/samba-team/samba.git
synced 2025-07-31 20:22:15 +03:00
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>
This commit is contained in:
@ -1,4 +1,3 @@
|
|||||||
# the attributes too long test returns the wrong error
|
# the attributes too long test returns the wrong error
|
||||||
^samba4.ldap.python.+test_attribute_ranges_too_long
|
^samba4.ldap.python.+test_attribute_ranges_too_long
|
||||||
samba4.ldap.python\(ad_dc_default\).*__main__.BasicTests.test_ldapSearchNoAttributes
|
samba4.ldap.python\(ad_dc_default\).*__main__.BasicTests.test_ldapSearchNoAttributes
|
||||||
^samba4.ldap.session-expiry.session-expiry\(ad_dc_default\)
|
|
||||||
|
@ -1384,11 +1384,48 @@ static NTSTATUS ldapsrv_AbandonRequest(struct ldapsrv_call *call)
|
|||||||
return NT_STATUS_OK;
|
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)
|
NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct ldap_message *msg = call->request;
|
struct ldap_message *msg = call->request;
|
||||||
|
struct ldapsrv_connection *conn = call->conn;
|
||||||
NTSTATUS status;
|
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 */
|
/* Check for undecoded critical extensions */
|
||||||
for (i=0; msg->controls && msg->controls[i]; i++) {
|
for (i=0; msg->controls && msg->controls[i]; i++) {
|
||||||
|
@ -69,6 +69,7 @@ static void ldapsrv_terminate_connection(struct ldapsrv_connection *conn,
|
|||||||
|
|
||||||
tevent_queue_stop(conn->sockets.send_queue);
|
tevent_queue_stop(conn->sockets.send_queue);
|
||||||
TALLOC_FREE(conn->sockets.read_req);
|
TALLOC_FREE(conn->sockets.read_req);
|
||||||
|
TALLOC_FREE(conn->deferred_expire_disconnect);
|
||||||
if (conn->active_call) {
|
if (conn->active_call) {
|
||||||
tevent_req_cancel(conn->active_call);
|
tevent_req_cancel(conn->active_call);
|
||||||
conn->active_call = NULL;
|
conn->active_call = NULL;
|
||||||
@ -1014,16 +1015,62 @@ static struct tevent_req *ldapsrv_process_call_send(TALLOC_CTX *mem_ctx,
|
|||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ldapsrv_disconnect_ticket_expired(struct tevent_req *subreq);
|
||||||
|
|
||||||
static void ldapsrv_process_call_trigger(struct tevent_req *req,
|
static void ldapsrv_process_call_trigger(struct tevent_req *req,
|
||||||
void *private_data)
|
void *private_data)
|
||||||
{
|
{
|
||||||
struct ldapsrv_process_call_state *state =
|
struct ldapsrv_process_call_state *state =
|
||||||
tevent_req_data(req,
|
tevent_req_data(req,
|
||||||
struct ldapsrv_process_call_state);
|
struct ldapsrv_process_call_state);
|
||||||
|
struct ldapsrv_connection *conn = state->call->conn;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
|
if (conn->deferred_expire_disconnect != NULL) {
|
||||||
|
/*
|
||||||
|
* Just drop this on the floor
|
||||||
|
*/
|
||||||
|
tevent_req_done(req);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* make the call */
|
/* make the call */
|
||||||
status = ldapsrv_do_call(state->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)) {
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
tevent_req_nterror(req, status);
|
tevent_req_nterror(req, status);
|
||||||
return;
|
return;
|
||||||
@ -1032,6 +1079,21 @@ static void ldapsrv_process_call_trigger(struct tevent_req *req,
|
|||||||
tevent_req_done(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)
|
static NTSTATUS ldapsrv_process_call_recv(struct tevent_req *req)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
@ -66,6 +66,7 @@ struct ldapsrv_connection {
|
|||||||
} limits;
|
} limits;
|
||||||
|
|
||||||
struct tevent_req *active_call;
|
struct tevent_req *active_call;
|
||||||
|
struct tevent_req *deferred_expire_disconnect;
|
||||||
|
|
||||||
struct ldapsrv_call *pending_calls;
|
struct ldapsrv_call *pending_calls;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user