summaryrefslogtreecommitdiff
path: root/source4/libcli/ldap
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli/ldap')
-rw-r--r--source4/libcli/ldap/config.mk3
-rw-r--r--source4/libcli/ldap/ldap.c39
-rw-r--r--source4/libcli/ldap/ldap.h7
-rw-r--r--source4/libcli/ldap/ldap_bind.c5
-rw-r--r--source4/libcli/ldap/ldap_client.c1
-rw-r--r--source4/libcli/ldap/ldap_controls.c470
-rw-r--r--source4/libcli/ldap/ldap_ildap.c14
-rw-r--r--source4/libcli/ldap/ldap_msg.c3
-rw-r--r--source4/libcli/ldap/ldap_ndr.c1
9 files changed, 518 insertions, 25 deletions
diff --git a/source4/libcli/ldap/config.mk b/source4/libcli/ldap/config.mk
index 912cb133bf..59d2d1ea30 100644
--- a/source4/libcli/ldap/config.mk
+++ b/source4/libcli/ldap/config.mk
@@ -7,7 +7,8 @@ OBJ_FILES = ldap.o \
ldap_bind.o \
ldap_msg.o \
ldap_ndr.o \
- ldap_ildap.o
+ ldap_ildap.o \
+ ldap_controls.o
REQUIRED_SUBSYSTEMS = LIBCLI_UTILS LIBEVENTS GENSEC SOCKET NDR_SAMR LIBTLS \
LIBPACKET
# End SUBSYSTEM LIBCLI_LDAP
diff --git a/source4/libcli/ldap/ldap.c b/source4/libcli/ldap/ldap.c
index c699820cea..d021fc3bd6 100644
--- a/source4/libcli/ldap/ldap.c
+++ b/source4/libcli/ldap/ldap.c
@@ -455,6 +455,18 @@ BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ct
return False;
}
+ if (msg->controls != NULL) {
+ 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])) {
+ return False;
+ }
+ }
+
+ asn1_pop_tag(&data);
+ }
+
asn1_pop_tag(&data);
if (data.has_error) {
@@ -1243,42 +1255,35 @@ BOOL ldap_decode(struct asn1_data *data, struct ldap_message *msg)
return False;
}
- msg->num_controls = 0;
msg->controls = NULL;
if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
int i;
- struct ldap_Control *ctrl = NULL;
+ struct ldap_Control **ctrl = NULL;
asn1_start_tag(data, ASN1_CONTEXT(0));
for (i=0; asn1_peek_tag(data, ASN1_SEQUENCE(0)); i++) {
asn1_start_tag(data, ASN1_SEQUENCE(0));
- ctrl = talloc_realloc(msg, ctrl, struct ldap_Control, i+1);
+ ctrl = talloc_realloc(msg, ctrl, struct ldap_Control *, i+2);
if (!ctrl) {
return False;
}
- ctrl[i].oid = NULL;
- ctrl[i].critical = False;
- ctrl[i].value = data_blob(NULL, 0);
- asn1_read_OctetString_talloc(ctrl, data, &ctrl[i].oid);
-
- if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
- asn1_read_BOOLEAN(data, &ctrl[i].critical);
+ ctrl[i] = talloc(ctrl, struct ldap_Control);
+ if (!ctrl[i]) {
+ return False;
}
- if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
- asn1_read_OctetString(data, &ctrl[i].value);
- if (ctrl[i].value.data) {
- talloc_steal(msg, ctrl[i].value.data);
- }
+ if (!ldap_decode_control(ctrl, data, ctrl[i])) {
+ return False;
}
- asn1_end_tag(data);
}
- msg->num_controls = i;
+
+ ctrl[i] = NULL;
+
msg->controls = ctrl;
asn1_end_tag(data);
diff --git a/source4/libcli/ldap/ldap.h b/source4/libcli/ldap/ldap.h
index b6e69ff8e6..5283553f13 100644
--- a/source4/libcli/ldap/ldap.h
+++ b/source4/libcli/ldap/ldap.h
@@ -243,15 +243,14 @@ union ldap_Request {
struct ldap_Control {
const char *oid;
BOOL critical;
- DATA_BLOB value;
+ void *value;
};
struct ldap_message {
- uint32_t messageid;
+ int messageid;
enum ldap_request_tag type;
union ldap_Request r;
- int num_controls;
- struct ldap_Control *controls;
+ struct ldap_Control **controls;
};
#include "libcli/ldap/ldap_proto.h"
diff --git a/source4/libcli/ldap/ldap_bind.c b/source4/libcli/ldap/ldap_bind.c
index 6b1c321d49..1f6ef77631 100644
--- a/source4/libcli/ldap/ldap_bind.c
+++ b/source4/libcli/ldap/ldap_bind.c
@@ -23,6 +23,7 @@
*/
#include "includes.h"
+#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
#include "auth/auth.h"
@@ -41,6 +42,7 @@ static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *con
res->r.BindRequest.dn = talloc_strdup(res, dn);
res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
res->r.BindRequest.creds.password = talloc_strdup(res, pw);
+ res->controls = NULL;
return res;
}
@@ -128,6 +130,7 @@ static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn,
res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res, sasl_mechanism);
res->r.BindRequest.creds.SASL.secblob = *secblob;
+ res->controls = NULL;
return res;
}
@@ -186,7 +189,7 @@ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *cr
}
status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs,
- False, &sasl_mechs_msgs);
+ False, NULL, NULL, &sasl_mechs_msgs);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n",
nt_errstr(status)));
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
index 9b1a4ef9d5..9103e939e7 100644
--- a/source4/libcli/ldap/ldap_client.c
+++ b/source4/libcli/ldap/ldap_client.c
@@ -28,6 +28,7 @@
#include "dlinklist.h"
#include "lib/events/events.h"
#include "lib/socket/socket.h"
+#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
#include "libcli/composite/composite.h"
#include "lib/stream/packet.h"
diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c
new file mode 100644
index 0000000000..55e7a94aa7
--- /dev/null
+++ b/source4/libcli/ldap/ldap_controls.c
@@ -0,0 +1,470 @@
+/*
+ Unix SMB/CIFS mplementation.
+ LDAP protocol helper functions for SAMBA
+
+ Copyright (C) Simo Sorce 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+#include "system/iconv.h"
+#include "libcli/util/asn_1.h"
+#include "libcli/ldap/ldap.h"
+#include "lib/ldb/include/ldb.h"
+
+struct 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);
+};
+
+static BOOL decode_server_sort_response(void *mem_ctx, DATA_BLOB in, void **out)
+{
+ DATA_BLOB attr;
+ struct asn1_data data;
+ struct ldb_sort_resp_control *lsrc;
+
+ if (!asn1_load(&data, in)) {
+ return False;
+ }
+
+ lsrc = talloc(mem_ctx, struct ldb_sort_resp_control);
+ if (!lsrc) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_enumerated(&data, &(lsrc->result))) {
+ return False;
+ }
+
+ lsrc->attr_desc = NULL;
+ if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
+ if (!asn1_read_OctetString(&data, &attr)) {
+ return False;
+ }
+ lsrc->attr_desc = talloc_strndup(lsrc, attr.data, attr.length);
+ if (!lsrc->attr_desc) {
+ return False;
+ }
+ }
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+
+ *out = lsrc;
+
+ return True;
+}
+
+static BOOL decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void **out)
+{
+ DATA_BLOB attr;
+ DATA_BLOB rule;
+ struct asn1_data data;
+ struct ldb_server_sort_control **lssc;
+ int num;
+
+ if (!asn1_load(&data, in)) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ lssc = NULL;
+
+ for (num = 0; asn1_peek_tag(&data, ASN1_SEQUENCE(0)); num++) {
+ lssc = talloc_realloc(mem_ctx, lssc, struct ldb_server_sort_control *, num + 2);
+ if (!lssc) {
+ return False;
+ }
+ lssc[num] = talloc(lssc, struct ldb_server_sort_control);
+ if (!lssc[num]) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_OctetString(&data, &attr)) {
+ return False;
+ }
+
+ lssc[num]->attributeName = talloc_strndup(lssc[num], attr.data, attr.length);
+ if (!lssc [num]->attributeName) {
+ return False;
+ }
+
+ if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
+ if (!asn1_read_OctetString(&data, &rule)) {
+ return False;
+ }
+ lssc[num]->orderingRule = talloc_strndup(lssc[num], rule.data, rule.length);
+ if (!lssc[num]->orderingRule) {
+ return False;
+ }
+ }
+
+ if (asn1_peek_tag(&data, ASN1_BOOLEAN)) {
+ if (!asn1_read_BOOLEAN(&data, &(lssc[num]->reverse))) {
+ return False;
+ }
+ }
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+ }
+
+ lssc[num] = NULL;
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+
+ *out = lssc;
+
+ return True;
+}
+
+static BOOL decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void **out)
+{
+ struct asn1_data data;
+ struct ldb_extended_dn_control *ledc;
+
+ if (!asn1_load(&data, in)) {
+ return False;
+ }
+
+ ledc = talloc(mem_ctx, struct ldb_extended_dn_control);
+ if (!ledc) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_Integer(&data, &(ledc->type))) {
+ return False;
+ }
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+
+ *out = ledc;
+
+ return True;
+}
+
+static BOOL decode_paged_results_request(void *mem_ctx, DATA_BLOB in, void **out)
+{
+ DATA_BLOB cookie;
+ struct asn1_data data;
+ struct ldb_paged_control *lprc;
+
+ if (!asn1_load(&data, in)) {
+ return False;
+ }
+
+ lprc = talloc(mem_ctx, struct ldb_paged_control);
+ if (!lprc) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_Integer(&data, &(lprc->size))) {
+ return False;
+ }
+
+ if (!asn1_read_OctetString(&data, &cookie)) {
+ return False;
+ }
+ lprc->cookie_len = cookie.length;
+ if (lprc->cookie_len) {
+ lprc->cookie = talloc_memdup(lprc, cookie.data, cookie.length);
+
+ if (!(lprc->cookie)) {
+ return False;
+ }
+ } else {
+ lprc->cookie = NULL;
+ }
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+
+ *out = lprc;
+
+ return True;
+}
+
+static BOOL encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
+{
+ struct ldb_sort_resp_control *lsrc = talloc_get_type(in, struct ldb_sort_resp_control);
+ struct asn1_data data;
+
+ ZERO_STRUCT(data);
+
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_write_enumerated(&data, lsrc->result)) {
+ return False;
+ }
+
+ if (lsrc->attr_desc) {
+ if (!asn1_write_OctetString(&data, lsrc->attr_desc, strlen(lsrc->attr_desc))) {
+ return False;
+ }
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+
+ *out = data_blob_talloc(mem_ctx, data.data, data.length);
+ if (out->data == NULL) {
+ return False;
+ }
+
+ return True;
+}
+
+static BOOL encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
+{
+ struct ldb_server_sort_control **lssc = talloc_get_type(in, struct ldb_server_sort_control *);
+ struct asn1_data data;
+ int num;
+
+ ZERO_STRUCT(data);
+
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ for (num = 0; lssc[num]; num++) {
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_write_OctetString(&data, lssc[num]->attributeName, strlen(lssc[num]->attributeName))) {
+ return False;
+ }
+
+ if (lssc[num]->orderingRule) {
+ if (!asn1_write_OctetString(&data, lssc[num]->orderingRule, strlen(lssc[num]->orderingRule))) {
+ return False;
+ }
+ }
+
+ if (lssc[num]->reverse) {
+ if (!asn1_write_BOOLEAN(&data, lssc[num]->reverse)) {
+ return False;
+ }
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+
+ *out = data_blob_talloc(mem_ctx, data.data, data.length);
+ if (out->data == NULL) {
+ return False;
+ }
+
+ return True;
+}
+
+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;
+
+ ZERO_STRUCT(data);
+
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_write_Integer(&data, ledc->type)) {
+ return False;
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+
+ *out = data_blob_talloc(mem_ctx, data.data, data.length);
+ if (out->data == NULL) {
+ return False;
+ }
+
+ return True;
+}
+
+static BOOL encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out)
+{
+ struct ldb_paged_control *lprc = talloc_get_type(in, struct ldb_paged_control);
+ struct asn1_data data;
+
+ ZERO_STRUCT(data);
+
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_write_Integer(&data, lprc->size)) {
+ return False;
+ }
+
+ if (!asn1_write_OctetString(&data, lprc->cookie, lprc->cookie_len)) {
+ return False;
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+
+ *out = data_blob_talloc(mem_ctx, data.data, data.length);
+ if (out->data == NULL) {
+ return False;
+ }
+
+ return True;
+}
+
+struct control_handler ldap_known_controls[] = {
+ { "1.2.840.113556.1.4.319", decode_paged_results_request, encode_paged_results_request },
+ { "1.2.840.113556.1.4.529", decode_extended_dn_request, encode_extended_dn_request },
+ { "1.2.840.113556.1.4.473", decode_server_sort_request, encode_server_sort_request },
+ { "1.2.840.113556.1.4.474", decode_server_sort_response, encode_server_sort_response },
+ { NULL, NULL, NULL }
+};
+
+BOOL ldap_decode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
+{
+ int i;
+ DATA_BLOB oid;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_OctetString(data, &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)) {
+ if (!asn1_read_BOOLEAN(data, &(ctrl->critical))) {
+ return False;
+ }
+ } else {
+ ctrl->critical = False;
+ }
+
+ ctrl->value = NULL;
+
+ for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
+ if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
+
+ if (!asn1_read_OctetString(data, &value)) {
+ return False;
+ }
+ if (!ldap_known_controls[i].decode(mem_ctx, value, &(ctrl->value))) {
+ return False;
+ }
+ break;
+ }
+ }
+ if (ldap_known_controls[i].oid == NULL) {
+ return False;
+ }
+
+ if (!asn1_end_tag(data)) {
+ return False;
+ }
+
+ return True;
+}
+
+BOOL ldap_encode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
+{
+ DATA_BLOB value;
+ int i;
+
+ 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;
+ }
+ }
+
+ for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
+ if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
+ if (!ldap_known_controls[i].encode(mem_ctx, ctrl->value, &value)) {
+ return False;
+ }
+ break;
+ }
+ }
+ if (ldap_known_controls[i].oid == NULL) {
+ return False;
+ }
+
+ if (value.length != 0) {
+ if (!asn1_write_OctetString(data, value.data, value.length)) {
+ return False;
+ }
+ }
+
+ if (!asn1_pop_tag(data)) {
+ return False;
+ }
+
+ return True;
+}
diff --git a/source4/libcli/ldap/ldap_ildap.c b/source4/libcli/ldap/ldap_ildap.c
index f29685a67c..a5227ec37f 100644
--- a/source4/libcli/ldap/ldap_ildap.c
+++ b/source4/libcli/ldap/ldap_ildap.c
@@ -22,6 +22,7 @@
*/
#include "includes.h"
+#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
/*
@@ -156,6 +157,8 @@ int ildap_count_entries(struct ldap_connection *conn, struct ldap_message **res)
NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
int scope, struct ldb_parse_tree *tree,
const char * const *attrs, BOOL attributesonly,
+ struct ldap_Control **control_req,
+ struct ldap_Control ***control_res,
struct ldap_message ***results)
{
struct ldap_message *msg;
@@ -163,6 +166,8 @@ NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
NTSTATUS status;
struct ldap_request *req;
+ if (control_res)
+ *control_res = NULL;
*results = NULL;
msg = new_ldap_message(conn);
@@ -180,6 +185,7 @@ NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
msg->r.SearchRequest.tree = tree;
msg->r.SearchRequest.num_attributes = n;
msg->r.SearchRequest.attributes = discard_const(attrs);
+ msg->controls = control_req;
req = ldap_request_send(conn, msg);
talloc_steal(msg, req);
@@ -191,6 +197,9 @@ NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
if (res->type == LDAP_TAG_SearchResultDone) {
status = ldap_check_response(conn, &res->r.GeneralResult);
+ if (control_res) {
+ *control_res = talloc_steal(conn, res->controls);
+ }
break;
}
@@ -219,12 +228,15 @@ NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
NTSTATUS ildap_search(struct ldap_connection *conn, const char *basedn,
int scope, const char *expression,
const char * const *attrs, BOOL attributesonly,
+ struct ldap_Control **control_req,
+ struct ldap_Control ***control_res,
struct ldap_message ***results)
{
struct ldb_parse_tree *tree = ldb_parse_tree(conn, expression);
NTSTATUS status;
status = ildap_search_bytree(conn, basedn, scope, tree, attrs,
- attributesonly, results);
+ attributesonly, control_req,
+ control_res, results);
talloc_free(tree);
return status;
}
diff --git a/source4/libcli/ldap/ldap_msg.c b/source4/libcli/ldap/ldap_msg.c
index c77d9eb356..d74aa500ca 100644
--- a/source4/libcli/ldap/ldap_msg.c
+++ b/source4/libcli/ldap/ldap_msg.c
@@ -23,12 +23,13 @@
*/
#include "includes.h"
+#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
{
- return talloc(mem_ctx, struct ldap_message);
+ return talloc_zero(mem_ctx, struct ldap_message);
}
diff --git a/source4/libcli/ldap/ldap_ndr.c b/source4/libcli/ldap/ldap_ndr.c
index 1d5e4ccf20..0cccdbe971 100644
--- a/source4/libcli/ldap/ldap_ndr.c
+++ b/source4/libcli/ldap/ldap_ndr.c
@@ -23,6 +23,7 @@
#include "includes.h"
#include "libcli/ldap/ldap.h"
+#include "librpc/gen_ndr/ndr_security.h"
#include "librpc/gen_ndr/ndr_misc.h"
/*