summaryrefslogtreecommitdiff
path: root/source4/ldap_server/ldap_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/ldap_server/ldap_server.c')
-rw-r--r--source4/ldap_server/ldap_server.c108
1 files changed, 104 insertions, 4 deletions
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
index 90d32c6833a..25c3b624abc 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -441,6 +441,10 @@ static void ldapsrv_accept_tls_done(struct tevent_req *subreq)
}
static void ldapsrv_call_read_done(struct tevent_req *subreq);
+static NTSTATUS ldapsrv_packet_check(
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size);
static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
{
@@ -494,7 +498,7 @@ static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
conn->connection->event.ctx,
conn->sockets.active,
7, /* initial_read_size */
- ldap_full_packet,
+ ldapsrv_packet_check,
conn);
if (subreq == NULL) {
ldapsrv_terminate_connection(conn, "ldapsrv_call_read_next: "
@@ -520,6 +524,9 @@ static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
}
static void ldapsrv_call_process_done(struct tevent_req *subreq);
+static int ldapsrv_check_packet_size(
+ struct ldapsrv_connection *conn,
+ size_t size);
static void ldapsrv_call_read_done(struct tevent_req *subreq)
{
@@ -530,6 +537,8 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
struct ldapsrv_call *call;
struct asn1_data *asn1;
DATA_BLOB blob;
+ int ret = LDAP_SUCCESS;
+ struct ldap_request_limits limits = {0};
conn->sockets.read_req = NULL;
@@ -560,7 +569,15 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
return;
}
- asn1 = asn1_init(call);
+ ret = ldapsrv_check_packet_size(conn, blob.length);
+ if (ret != LDAP_SUCCESS) {
+ ldapsrv_terminate_connection(
+ conn,
+ "Request packet too large");
+ return;
+ }
+
+ asn1 = asn1_init(call, ASN1_MAX_TREE_DEPTH);
if (asn1 == NULL) {
ldapsrv_terminate_connection(conn, "no memory");
return;
@@ -577,8 +594,13 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
return;
}
- status = ldap_decode(asn1, samba_ldap_control_handlers(),
- call->request);
+ limits.max_search_size =
+ lpcfg_ldap_max_search_request_size(conn->lp_ctx);
+ status = ldap_decode(
+ asn1,
+ &limits,
+ samba_ldap_control_handlers(),
+ call->request);
if (!NT_STATUS_IS_OK(status)) {
ldapsrv_terminate_connection(conn, nt_errstr(status));
return;
@@ -1292,6 +1314,84 @@ failed:
}
+/*
+ * Check the size of an ldap request packet.
+ *
+ * For authenticated connections the maximum packet size is controlled by
+ * the smb.conf parameter "ldap max authenticated request size"
+ *
+ * For anonymous connections the maximum packet size is controlled by
+ * the smb.conf parameter "ldap max anonymous request size"
+ */
+static int ldapsrv_check_packet_size(
+ struct ldapsrv_connection *conn,
+ size_t size)
+{
+ bool is_anonymous = false;
+ size_t max_size = 0;
+
+ max_size = lpcfg_ldap_max_anonymous_request_size(conn->lp_ctx);
+ if (size <= max_size) {
+ return LDAP_SUCCESS;
+ }
+
+ /*
+ * Request is larger than the maximum unauthenticated request size.
+ * As this code is called frequently we avoid calling
+ * security_token_is_anonymous if possible
+ */
+ if (conn->session_info != NULL &&
+ conn->session_info->security_token != NULL) {
+ is_anonymous = security_token_is_anonymous(
+ conn->session_info->security_token);
+ }
+
+ if (is_anonymous) {
+ DBG_WARNING(
+ "LDAP request size (%zu) exceeds (%zu)\n",
+ size,
+ max_size);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ max_size = lpcfg_ldap_max_authenticated_request_size(conn->lp_ctx);
+ if (size > max_size) {
+ DBG_WARNING(
+ "LDAP request size (%zu) exceeds (%zu)\n",
+ size,
+ max_size);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ return LDAP_SUCCESS;
+
+}
+
+/*
+ * Check that the blob contains enough data to be a valid packet
+ * If there is a packet header check the size to ensure that it does not
+ * exceed the maximum sizes.
+ *
+ */
+static NTSTATUS ldapsrv_packet_check(
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size)
+{
+ NTSTATUS ret;
+ struct ldapsrv_connection *conn = private_data;
+ int result = LDB_SUCCESS;
+
+ ret = ldap_full_packet(private_data, blob, packet_size);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ result = ldapsrv_check_packet_size(conn, *packet_size);
+ if (result != LDAP_SUCCESS) {
+ return NT_STATUS_LDAP(result);
+ }
+ return NT_STATUS_OK;
+}
+
NTSTATUS server_service_ldap_init(TALLOC_CTX *ctx)
{
static const struct service_details details = {