From 364266e22a08e730f2442cf87ec385620cff2700 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 29 Nov 2007 08:00:04 +0100 Subject: r26192: Handle, test and implement the style of extended_dn requiest that MMC uses. It appears that the control value is optional, implying type 0 responses. Failing to parse this was causing LDAP disconnects with 'unavailable critical extension'. Andrew Bartlett (This used to be commit 833dfc2f2af84c45f954e428c9ea6babf100ba92) --- source4/libcli/ldap/ldap.c | 13 ++++++++++++- source4/libcli/ldap/ldap.h | 2 ++ source4/libcli/ldap/ldap_client.c | 15 +++++++++++++++ source4/libcli/ldap/ldap_controls.c | 18 ++++++++++++++++-- 4 files changed, 45 insertions(+), 3 deletions(-) (limited to 'source4/libcli/ldap') diff --git a/source4/libcli/ldap/ldap.c b/source4/libcli/ldap/ldap.c index 11689fbd79..34d715e3e5 100644 --- a/source4/libcli/ldap/ldap.c +++ b/source4/libcli/ldap/ldap.c @@ -1325,10 +1325,12 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg) } msg->controls = NULL; + msg->controls_decoded = NULL; if (asn1_peek_tag(data, ASN1_CONTEXT(0))) { int i = 0; struct ldb_control **ctrl = NULL; + bool *decoded = NULL; asn1_start_tag(data, ASN1_CONTEXT(0)); @@ -1341,6 +1343,11 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg) return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR); } + decoded = talloc_realloc(msg, decoded, bool, i+1); + if (!decoded) { + return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR); + } + ctrl[i] = talloc(ctrl, struct ldb_control); if (!ctrl[i]) { return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR); @@ -1352,12 +1359,15 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg) if (!ldap_decode_control_value(ctrl, value, ctrl[i])) { if (ctrl[i]->critical) { - return NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION); + ctrl[i]->data = NULL; + decoded[i] = false; + i++; } else { talloc_free(ctrl[i]); ctrl[i] = NULL; } } else { + decoded[i] = true; i++; } } @@ -1367,6 +1377,7 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg) } msg->controls = ctrl; + msg->controls_decoded = decoded; asn1_end_tag(data); } diff --git a/source4/libcli/ldap/ldap.h b/source4/libcli/ldap/ldap.h index e89322213a..6f5e86744e 100644 --- a/source4/libcli/ldap/ldap.h +++ b/source4/libcli/ldap/ldap.h @@ -240,11 +240,13 @@ union ldap_Request { struct ldap_ExtendedResponse ExtendedResponse; }; + struct ldap_message { int messageid; enum ldap_request_tag type; union ldap_Request r; struct ldb_control **controls; + bool *controls_decoded; }; struct event_context; diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c index fcb2d92214..41e9c37196 100644 --- a/source4/libcli/ldap/ldap_client.c +++ b/source4/libcli/ldap/ldap_client.c @@ -116,6 +116,7 @@ static void ldap_error_handler(void *private_data, NTSTATUS status) static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg) { struct ldap_request *req; + int i; for (req=conn->pending; req; req=req->next) { if (req->messageid == msg->messageid) break; @@ -132,6 +133,20 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message return; } + /* Check for undecoded critical extensions */ + for (i=0; msg->controls && msg->controls[i]; i++) { + if (!msg->controls_decoded[i] && + msg->controls[i]->critical) { + req->status = NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION); + req->state = LDAP_REQUEST_DONE; + DLIST_REMOVE(conn->pending, req); + if (req->async.fn) { + req->async.fn(req); + } + return; + } + } + /* add to the list of replies received */ talloc_steal(req, msg); req->replies = talloc_realloc(req, req->replies, diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c index b7fd1ce178..34e5cccf75 100644 --- a/source4/libcli/ldap/ldap_controls.c +++ b/source4/libcli/ldap/ldap_controls.c @@ -156,9 +156,16 @@ static bool decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void **out) static bool decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void **out) { - struct asn1_data *data = asn1_init(mem_ctx); + struct asn1_data *data; struct ldb_extended_dn_control *ledc; + /* The content of this control is optional */ + if (in.length == 0) { + *out = NULL; + return true; + } + + data = asn1_init(mem_ctx); if (!data) return false; if (!asn1_load(data, in)) { @@ -717,7 +724,14 @@ static bool encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out) static bool encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out) { struct ldb_extended_dn_control *ledc = talloc_get_type(in, struct ldb_extended_dn_control); - struct asn1_data *data = asn1_init(mem_ctx); + struct asn1_data *data; + + if (!in) { + *out = data_blob(NULL, 0); + return true; + } + + data = asn1_init(mem_ctx); if (!data) return false; -- cgit