summaryrefslogtreecommitdiff
path: root/libcli/ldap
diff options
context:
space:
mode:
Diffstat (limited to 'libcli/ldap')
-rw-r--r--libcli/ldap/ldap_message.c148
-rw-r--r--libcli/ldap/ldap_message.h14
2 files changed, 156 insertions, 6 deletions
diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c
index 06052a936a..9b00d0188d 100644
--- a/libcli/ldap/ldap_message.c
+++ b/libcli/ldap/ldap_message.c
@@ -84,6 +84,138 @@ static bool add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
return true;
}
+static bool ldap_decode_control_value(void *mem_ctx, DATA_BLOB value,
+ const struct ldap_control_handler *handlers,
+ struct ldb_control *ctrl)
+{
+ int i;
+
+ if (!handlers) {
+ return true;
+ }
+
+ for (i = 0; handlers[i].oid != NULL; i++) {
+ if (strcmp(handlers[i].oid, ctrl->oid) == 0) {
+ if (!handlers[i].decode || !handlers[i].decode(mem_ctx, value, &ctrl->data)) {
+ return false;
+ }
+ break;
+ }
+ }
+ if (handlers[i].oid == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool ldap_decode_control_wrapper(void *mem_ctx, struct asn1_data *data,
+ struct ldb_control *ctrl, DATA_BLOB *value)
+{
+ DATA_BLOB oid;
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+ return false;
+ }
+
+ if (!asn1_read_OctetString(data, mem_ctx, &oid)) {
+ return false;
+ }
+ ctrl->oid = talloc_strndup(mem_ctx, (char *)oid.data, oid.length);
+ if (!ctrl->oid) {
+ return false;
+ }
+
+ if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
+ bool critical;
+ if (!asn1_read_BOOLEAN(data, &critical)) {
+ return false;
+ }
+ ctrl->critical = critical;
+ } else {
+ ctrl->critical = false;
+ }
+
+ ctrl->data = NULL;
+
+ if (!asn1_peek_tag(data, ASN1_OCTET_STRING)) {
+ *value = data_blob(NULL, 0);
+ goto end_tag;
+ }
+
+ if (!asn1_read_OctetString(data, mem_ctx, value)) {
+ return false;
+ }
+
+end_tag:
+ if (!asn1_end_tag(data)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool ldap_encode_control(void *mem_ctx, struct asn1_data *data,
+ const struct ldap_control_handler *handlers,
+ struct ldb_control *ctrl)
+{
+ DATA_BLOB value;
+ int i;
+
+ if (!handlers) {
+ return false;
+ }
+
+ for (i = 0; handlers[i].oid != NULL; i++) {
+ if (strcmp(handlers[i].oid, ctrl->oid) == 0) {
+ if (!handlers[i].encode) {
+ if (ctrl->critical) {
+ return false;
+ } else {
+ /* not encoding this control */
+ return true;
+ }
+ }
+ if (!handlers[i].encode(mem_ctx, ctrl->data, &value)) {
+ return false;
+ }
+ break;
+ }
+ }
+ if (handlers[i].oid == NULL) {
+ return false;
+ }
+
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+ return false;
+ }
+
+ if (!asn1_write_OctetString(data, ctrl->oid, strlen(ctrl->oid))) {
+ return false;
+ }
+
+ if (ctrl->critical) {
+ if (!asn1_write_BOOLEAN(data, ctrl->critical)) {
+ return false;
+ }
+ }
+
+ if (!ctrl->data) {
+ goto pop_tag;
+ }
+
+ if (!asn1_write_OctetString(data, value.data, value.length)) {
+ return false;
+ }
+
+pop_tag:
+ if (!asn1_pop_tag(data)) {
+ return false;
+ }
+
+ return true;
+}
+
static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
{
int i;
@@ -244,7 +376,9 @@ static void ldap_encode_response(struct asn1_data *data, struct ldap_Result *res
}
}
-_PUBLIC_ bool ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ctx)
+_PUBLIC_ bool ldap_encode(struct ldap_message *msg,
+ const struct ldap_control_handler *control_handlers,
+ DATA_BLOB *result, TALLOC_CTX *mem_ctx)
{
struct asn1_data *data = asn1_init(mem_ctx);
int i, j;
@@ -531,7 +665,9 @@ _PUBLIC_ bool ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CT
asn1_push_tag(data, ASN1_CONTEXT(0));
for (i = 0; msg->controls[i] != NULL; i++) {
- if (!ldap_encode_control(mem_ctx, data, msg->controls[i])) {
+ if (!ldap_encode_control(mem_ctx, data,
+ control_handlers,
+ msg->controls[i])) {
return false;
}
}
@@ -993,7 +1129,9 @@ static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
/* This routine returns LDAP status codes */
-_PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
+_PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
+ const struct ldap_control_handler *control_handlers,
+ struct ldap_message *msg)
{
uint8_t tag;
@@ -1428,7 +1566,9 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
}
- if (!ldap_decode_control_value(ctrl, value, ctrl[i])) {
+ if (!ldap_decode_control_value(ctrl, value,
+ control_handlers,
+ ctrl[i])) {
if (ctrl[i]->critical) {
ctrl[i]->data = NULL;
decoded[i] = false;
diff --git a/libcli/ldap/ldap_message.h b/libcli/ldap/ldap_message.h
index d2ce14445d..c50018465c 100644
--- a/libcli/ldap/ldap_message.h
+++ b/libcli/ldap/ldap_message.h
@@ -207,11 +207,21 @@ struct ldap_message {
bool *controls_decoded;
};
+struct ldap_control_handler {
+ const char *oid;
+ bool (*decode)(void *mem_ctx, DATA_BLOB in, void *_out);
+ bool (*encode)(void *mem_ctx, void *in, DATA_BLOB *out);
+};
+
struct asn1_data;
struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx);
-NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg);
-bool ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ctx);
+NTSTATUS ldap_decode(struct asn1_data *data,
+ const struct ldap_control_handler *control_handlers,
+ struct ldap_message *msg);
+bool ldap_encode(struct ldap_message *msg,
+ const struct ldap_control_handler *control_handlers,
+ DATA_BLOB *result, TALLOC_CTX *mem_ctx);
NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_size);
bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,