2 Unix SMB/CIFS mplementation.
3 LDAP protocol helper functions for SAMBA
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Stefan Metzmacher 2004
8 Copyright (C) Simo Sorce 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "../lib/util/asn1.h"
27 #include "libcli/ldap/ldap.h"
28 #include "libcli/ldap/ldap_proto.h"
30 _PUBLIC_
struct ldap_message
*new_ldap_message(TALLOC_CTX
*mem_ctx
)
32 return talloc_zero(mem_ctx
, struct ldap_message
);
36 static bool add_value_to_attrib(TALLOC_CTX
*mem_ctx
, struct ldb_val
*value
,
37 struct ldb_message_element
*attrib
)
39 attrib
->values
= talloc_realloc(mem_ctx
,
42 attrib
->num_values
+1);
43 if (attrib
->values
== NULL
)
46 attrib
->values
[attrib
->num_values
].data
= talloc_steal(attrib
->values
,
48 attrib
->values
[attrib
->num_values
].length
= value
->length
;
49 attrib
->num_values
+= 1;
53 static bool add_attrib_to_array_talloc(TALLOC_CTX
*mem_ctx
,
54 const struct ldb_message_element
*attrib
,
55 struct ldb_message_element
**attribs
,
58 *attribs
= talloc_realloc(mem_ctx
,
60 struct ldb_message_element
,
66 (*attribs
)[*num_attribs
] = *attrib
;
67 talloc_steal(*attribs
, attrib
->values
);
68 talloc_steal(*attribs
, attrib
->name
);
73 static bool add_mod_to_array_talloc(TALLOC_CTX
*mem_ctx
,
75 struct ldap_mod
**mods
,
78 *mods
= talloc_realloc(mem_ctx
, *mods
, struct ldap_mod
, (*num_mods
)+1);
83 (*mods
)[*num_mods
] = *mod
;
88 static bool ldap_push_filter(struct asn1_data
*data
, struct ldb_parse_tree
*tree
)
92 switch (tree
->operation
) {
95 asn1_push_tag(data
, ASN1_CONTEXT(tree
->operation
==LDB_OP_AND
?0:1));
96 for (i
=0; i
<tree
->u
.list
.num_elements
; i
++) {
97 if (!ldap_push_filter(data
, tree
->u
.list
.elements
[i
])) {
105 asn1_push_tag(data
, ASN1_CONTEXT(2));
106 if (!ldap_push_filter(data
, tree
->u
.isnot
.child
)) {
112 case LDB_OP_EQUALITY
:
114 asn1_push_tag(data
, ASN1_CONTEXT(3));
115 asn1_write_OctetString(data
, tree
->u
.equality
.attr
,
116 strlen(tree
->u
.equality
.attr
));
117 asn1_write_OctetString(data
, tree
->u
.equality
.value
.data
,
118 tree
->u
.equality
.value
.length
);
122 case LDB_OP_SUBSTRING
:
124 SubstringFilter ::= SEQUENCE {
125 type AttributeDescription,
126 -- at least one must be present
127 substrings SEQUENCE OF CHOICE {
128 initial [0] LDAPString,
130 final [2] LDAPString } }
132 asn1_push_tag(data
, ASN1_CONTEXT(4));
133 asn1_write_OctetString(data
, tree
->u
.substring
.attr
, strlen(tree
->u
.substring
.attr
));
134 asn1_push_tag(data
, ASN1_SEQUENCE(0));
136 if ( ! tree
->u
.substring
.start_with_wildcard
) {
137 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(0));
138 asn1_write_DATA_BLOB_LDAPString(data
, tree
->u
.substring
.chunks
[i
]);
142 while (tree
->u
.substring
.chunks
[i
]) {
145 if (( ! tree
->u
.substring
.chunks
[i
+ 1]) &&
146 (tree
->u
.substring
.end_with_wildcard
== 0)) {
151 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(ctx
));
152 asn1_write_DATA_BLOB_LDAPString(data
, tree
->u
.substring
.chunks
[i
]);
161 /* greaterOrEqual test */
162 asn1_push_tag(data
, ASN1_CONTEXT(5));
163 asn1_write_OctetString(data
, tree
->u
.comparison
.attr
,
164 strlen(tree
->u
.comparison
.attr
));
165 asn1_write_OctetString(data
, tree
->u
.comparison
.value
.data
,
166 tree
->u
.comparison
.value
.length
);
171 /* lessOrEqual test */
172 asn1_push_tag(data
, ASN1_CONTEXT(6));
173 asn1_write_OctetString(data
, tree
->u
.comparison
.attr
,
174 strlen(tree
->u
.comparison
.attr
));
175 asn1_write_OctetString(data
, tree
->u
.comparison
.value
.data
,
176 tree
->u
.comparison
.value
.length
);
182 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(7));
183 asn1_write_LDAPString(data
, tree
->u
.present
.attr
);
185 return !data
->has_error
;
189 asn1_push_tag(data
, ASN1_CONTEXT(8));
190 asn1_write_OctetString(data
, tree
->u
.comparison
.attr
,
191 strlen(tree
->u
.comparison
.attr
));
192 asn1_write_OctetString(data
, tree
->u
.comparison
.value
.data
,
193 tree
->u
.comparison
.value
.length
);
197 case LDB_OP_EXTENDED
:
199 MatchingRuleAssertion ::= SEQUENCE {
200 matchingRule [1] MatchingRuleID OPTIONAL,
201 type [2] AttributeDescription OPTIONAL,
202 matchValue [3] AssertionValue,
203 dnAttributes [4] BOOLEAN DEFAULT FALSE
206 asn1_push_tag(data
, ASN1_CONTEXT(9));
207 if (tree
->u
.extended
.rule_id
) {
208 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(1));
209 asn1_write_LDAPString(data
, tree
->u
.extended
.rule_id
);
212 if (tree
->u
.extended
.attr
) {
213 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(2));
214 asn1_write_LDAPString(data
, tree
->u
.extended
.attr
);
217 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(3));
218 asn1_write_DATA_BLOB_LDAPString(data
, &tree
->u
.extended
.value
);
220 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(4));
221 asn1_write_uint8(data
, tree
->u
.extended
.dnAttributes
);
229 return !data
->has_error
;
232 static void ldap_encode_response(struct asn1_data
*data
, struct ldap_Result
*result
)
234 asn1_write_enumerated(data
, result
->resultcode
);
235 asn1_write_OctetString(data
, result
->dn
,
236 (result
->dn
) ? strlen(result
->dn
) : 0);
237 asn1_write_OctetString(data
, result
->errormessage
,
238 (result
->errormessage
) ?
239 strlen(result
->errormessage
) : 0);
240 if (result
->referral
) {
241 asn1_push_tag(data
, ASN1_CONTEXT(3));
242 asn1_write_OctetString(data
, result
->referral
,
243 strlen(result
->referral
));
248 _PUBLIC_
bool ldap_encode(struct ldap_message
*msg
, DATA_BLOB
*result
, TALLOC_CTX
*mem_ctx
)
250 struct asn1_data
*data
= asn1_init(mem_ctx
);
253 if (!data
) return false;
255 asn1_push_tag(data
, ASN1_SEQUENCE(0));
256 asn1_write_Integer(data
, msg
->messageid
);
259 case LDAP_TAG_BindRequest
: {
260 struct ldap_BindRequest
*r
= &msg
->r
.BindRequest
;
261 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
262 asn1_write_Integer(data
, r
->version
);
263 asn1_write_OctetString(data
, r
->dn
,
264 (r
->dn
!= NULL
) ? strlen(r
->dn
) : 0);
266 switch (r
->mechanism
) {
267 case LDAP_AUTH_MECH_SIMPLE
:
268 /* context, primitive */
269 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(0));
270 asn1_write(data
, r
->creds
.password
,
271 strlen(r
->creds
.password
));
274 case LDAP_AUTH_MECH_SASL
:
275 /* context, constructed */
276 asn1_push_tag(data
, ASN1_CONTEXT(3));
277 asn1_write_OctetString(data
, r
->creds
.SASL
.mechanism
,
278 strlen(r
->creds
.SASL
.mechanism
));
279 if (r
->creds
.SASL
.secblob
) {
280 asn1_write_OctetString(data
, r
->creds
.SASL
.secblob
->data
,
281 r
->creds
.SASL
.secblob
->length
);
292 case LDAP_TAG_BindResponse
: {
293 struct ldap_BindResponse
*r
= &msg
->r
.BindResponse
;
294 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
295 ldap_encode_response(data
, &r
->response
);
296 if (r
->SASL
.secblob
) {
297 asn1_write_ContextSimple(data
, 7, r
->SASL
.secblob
);
302 case LDAP_TAG_UnbindRequest
: {
303 /* struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
306 case LDAP_TAG_SearchRequest
: {
307 struct ldap_SearchRequest
*r
= &msg
->r
.SearchRequest
;
308 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
309 asn1_write_OctetString(data
, r
->basedn
, strlen(r
->basedn
));
310 asn1_write_enumerated(data
, r
->scope
);
311 asn1_write_enumerated(data
, r
->deref
);
312 asn1_write_Integer(data
, r
->sizelimit
);
313 asn1_write_Integer(data
, r
->timelimit
);
314 asn1_write_BOOLEAN(data
, r
->attributesonly
);
316 if (!ldap_push_filter(data
, r
->tree
)) {
320 asn1_push_tag(data
, ASN1_SEQUENCE(0));
321 for (i
=0; i
<r
->num_attributes
; i
++) {
322 asn1_write_OctetString(data
, r
->attributes
[i
],
323 strlen(r
->attributes
[i
]));
329 case LDAP_TAG_SearchResultEntry
: {
330 struct ldap_SearchResEntry
*r
= &msg
->r
.SearchResultEntry
;
331 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
332 asn1_write_OctetString(data
, r
->dn
, strlen(r
->dn
));
333 asn1_push_tag(data
, ASN1_SEQUENCE(0));
334 for (i
=0; i
<r
->num_attributes
; i
++) {
335 struct ldb_message_element
*attr
= &r
->attributes
[i
];
336 asn1_push_tag(data
, ASN1_SEQUENCE(0));
337 asn1_write_OctetString(data
, attr
->name
,
339 asn1_push_tag(data
, ASN1_SEQUENCE(1));
340 for (j
=0; j
<attr
->num_values
; j
++) {
341 asn1_write_OctetString(data
,
342 attr
->values
[j
].data
,
343 attr
->values
[j
].length
);
352 case LDAP_TAG_SearchResultDone
: {
353 struct ldap_Result
*r
= &msg
->r
.SearchResultDone
;
354 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
355 ldap_encode_response(data
, r
);
359 case LDAP_TAG_ModifyRequest
: {
360 struct ldap_ModifyRequest
*r
= &msg
->r
.ModifyRequest
;
361 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
362 asn1_write_OctetString(data
, r
->dn
, strlen(r
->dn
));
363 asn1_push_tag(data
, ASN1_SEQUENCE(0));
365 for (i
=0; i
<r
->num_mods
; i
++) {
366 struct ldb_message_element
*attrib
= &r
->mods
[i
].attrib
;
367 asn1_push_tag(data
, ASN1_SEQUENCE(0));
368 asn1_write_enumerated(data
, r
->mods
[i
].type
);
369 asn1_push_tag(data
, ASN1_SEQUENCE(0));
370 asn1_write_OctetString(data
, attrib
->name
,
371 strlen(attrib
->name
));
372 asn1_push_tag(data
, ASN1_SET
);
373 for (j
=0; j
<attrib
->num_values
; j
++) {
374 asn1_write_OctetString(data
,
375 attrib
->values
[j
].data
,
376 attrib
->values
[j
].length
);
388 case LDAP_TAG_ModifyResponse
: {
389 struct ldap_Result
*r
= &msg
->r
.ModifyResponse
;
390 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
391 ldap_encode_response(data
, r
);
395 case LDAP_TAG_AddRequest
: {
396 struct ldap_AddRequest
*r
= &msg
->r
.AddRequest
;
397 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
398 asn1_write_OctetString(data
, r
->dn
, strlen(r
->dn
));
399 asn1_push_tag(data
, ASN1_SEQUENCE(0));
401 for (i
=0; i
<r
->num_attributes
; i
++) {
402 struct ldb_message_element
*attrib
= &r
->attributes
[i
];
403 asn1_push_tag(data
, ASN1_SEQUENCE(0));
404 asn1_write_OctetString(data
, attrib
->name
,
405 strlen(attrib
->name
));
406 asn1_push_tag(data
, ASN1_SET
);
407 for (j
=0; j
<r
->attributes
[i
].num_values
; j
++) {
408 asn1_write_OctetString(data
,
409 attrib
->values
[j
].data
,
410 attrib
->values
[j
].length
);
419 case LDAP_TAG_AddResponse
: {
420 struct ldap_Result
*r
= &msg
->r
.AddResponse
;
421 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
422 ldap_encode_response(data
, r
);
426 case LDAP_TAG_DelRequest
: {
427 struct ldap_DelRequest
*r
= &msg
->r
.DelRequest
;
428 asn1_push_tag(data
, ASN1_APPLICATION_SIMPLE(msg
->type
));
429 asn1_write(data
, r
->dn
, strlen(r
->dn
));
433 case LDAP_TAG_DelResponse
: {
434 struct ldap_Result
*r
= &msg
->r
.DelResponse
;
435 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
436 ldap_encode_response(data
, r
);
440 case LDAP_TAG_ModifyDNRequest
: {
441 struct ldap_ModifyDNRequest
*r
= &msg
->r
.ModifyDNRequest
;
442 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
443 asn1_write_OctetString(data
, r
->dn
, strlen(r
->dn
));
444 asn1_write_OctetString(data
, r
->newrdn
, strlen(r
->newrdn
));
445 asn1_write_BOOLEAN(data
, r
->deleteolddn
);
446 if (r
->newsuperior
) {
447 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(0));
448 asn1_write(data
, r
->newsuperior
,
449 strlen(r
->newsuperior
));
455 case LDAP_TAG_ModifyDNResponse
: {
456 struct ldap_Result
*r
= &msg
->r
.ModifyDNResponse
;
457 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
458 ldap_encode_response(data
, r
);
462 case LDAP_TAG_CompareRequest
: {
463 struct ldap_CompareRequest
*r
= &msg
->r
.CompareRequest
;
464 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
465 asn1_write_OctetString(data
, r
->dn
, strlen(r
->dn
));
466 asn1_push_tag(data
, ASN1_SEQUENCE(0));
467 asn1_write_OctetString(data
, r
->attribute
,
468 strlen(r
->attribute
));
469 asn1_write_OctetString(data
, r
->value
.data
,
475 case LDAP_TAG_CompareResponse
: {
476 struct ldap_Result
*r
= &msg
->r
.ModifyDNResponse
;
477 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
478 ldap_encode_response(data
, r
);
482 case LDAP_TAG_AbandonRequest
: {
483 struct ldap_AbandonRequest
*r
= &msg
->r
.AbandonRequest
;
484 asn1_push_tag(data
, ASN1_APPLICATION_SIMPLE(msg
->type
));
485 asn1_write_implicit_Integer(data
, r
->messageid
);
489 case LDAP_TAG_SearchResultReference
: {
490 struct ldap_SearchResRef
*r
= &msg
->r
.SearchResultReference
;
491 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
492 asn1_write_OctetString(data
, r
->referral
, strlen(r
->referral
));
496 case LDAP_TAG_ExtendedRequest
: {
497 struct ldap_ExtendedRequest
*r
= &msg
->r
.ExtendedRequest
;
498 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
499 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(0));
500 asn1_write(data
, r
->oid
, strlen(r
->oid
));
503 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(1));
504 asn1_write(data
, r
->value
->data
, r
->value
->length
);
510 case LDAP_TAG_ExtendedResponse
: {
511 struct ldap_ExtendedResponse
*r
= &msg
->r
.ExtendedResponse
;
512 asn1_push_tag(data
, ASN1_APPLICATION(msg
->type
));
513 ldap_encode_response(data
, &r
->response
);
515 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(10));
516 asn1_write(data
, r
->oid
, strlen(r
->oid
));
520 asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(11));
521 asn1_write(data
, r
->value
->data
, r
->value
->length
);
531 if (msg
->controls
!= NULL
) {
532 asn1_push_tag(data
, ASN1_CONTEXT(0));
534 for (i
= 0; msg
->controls
[i
] != NULL
; i
++) {
535 if (!ldap_encode_control(mem_ctx
, data
, msg
->controls
[i
])) {
545 if (data
->has_error
) {
550 *result
= data_blob_talloc(mem_ctx
, data
->data
, data
->length
);
555 static const char *blob2string_talloc(TALLOC_CTX
*mem_ctx
,
558 char *result
= talloc_array(mem_ctx
, char, blob
.length
+1);
559 memcpy(result
, blob
.data
, blob
.length
);
560 result
[blob
.length
] = '\0';
564 bool asn1_read_OctetString_talloc(TALLOC_CTX
*mem_ctx
,
565 struct asn1_data
*data
,
569 if (!asn1_read_OctetString(data
, mem_ctx
, &string
))
571 *result
= blob2string_talloc(mem_ctx
, string
);
572 data_blob_free(&string
);
576 static void ldap_decode_response(TALLOC_CTX
*mem_ctx
,
577 struct asn1_data
*data
,
578 struct ldap_Result
*result
)
580 asn1_read_enumerated(data
, &result
->resultcode
);
581 asn1_read_OctetString_talloc(mem_ctx
, data
, &result
->dn
);
582 asn1_read_OctetString_talloc(mem_ctx
, data
, &result
->errormessage
);
583 if (asn1_peek_tag(data
, ASN1_CONTEXT(3))) {
584 asn1_start_tag(data
, ASN1_CONTEXT(3));
585 asn1_read_OctetString_talloc(mem_ctx
, data
, &result
->referral
);
588 result
->referral
= NULL
;
592 static struct ldb_val
**ldap_decode_substring(TALLOC_CTX
*mem_ctx
, struct ldb_val
**chunks
, int chunk_num
, char *value
)
595 chunks
= talloc_realloc(mem_ctx
, chunks
, struct ldb_val
*, chunk_num
+ 2);
596 if (chunks
== NULL
) {
600 chunks
[chunk_num
] = talloc(mem_ctx
, struct ldb_val
);
601 if (chunks
[chunk_num
] == NULL
) {
605 chunks
[chunk_num
]->data
= (uint8_t *)talloc_strdup(mem_ctx
, value
);
606 if (chunks
[chunk_num
]->data
== NULL
) {
609 chunks
[chunk_num
]->length
= strlen(value
);
611 chunks
[chunk_num
+ 1] = '\0';
618 parse the ASN.1 formatted search string into a ldb_parse_tree
620 static struct ldb_parse_tree
*ldap_decode_filter_tree(TALLOC_CTX
*mem_ctx
,
621 struct asn1_data
*data
)
624 struct ldb_parse_tree
*ret
;
626 if (!asn1_peek_uint8(data
, &filter_tag
)) {
630 filter_tag
&= 0x1f; /* strip off the asn1 stuff */
632 ret
= talloc(mem_ctx
, struct ldb_parse_tree
);
633 if (ret
== NULL
) return NULL
;
638 /* AND or OR of one or more filters */
639 ret
->operation
= (filter_tag
== 0)?LDB_OP_AND
:LDB_OP_OR
;
640 ret
->u
.list
.num_elements
= 0;
641 ret
->u
.list
.elements
= NULL
;
643 if (!asn1_start_tag(data
, ASN1_CONTEXT(filter_tag
))) {
647 while (asn1_tag_remaining(data
) > 0) {
648 struct ldb_parse_tree
*subtree
;
649 subtree
= ldap_decode_filter_tree(ret
, data
);
650 if (subtree
== NULL
) {
653 ret
->u
.list
.elements
=
654 talloc_realloc(ret
, ret
->u
.list
.elements
,
655 struct ldb_parse_tree
*,
656 ret
->u
.list
.num_elements
+1);
657 if (ret
->u
.list
.elements
== NULL
) {
660 talloc_steal(ret
->u
.list
.elements
, subtree
);
661 ret
->u
.list
.elements
[ret
->u
.list
.num_elements
] = subtree
;
662 ret
->u
.list
.num_elements
++;
664 if (!asn1_end_tag(data
)) {
670 /* 'not' operation */
671 if (!asn1_start_tag(data
, ASN1_CONTEXT(filter_tag
))) {
675 ret
->operation
= LDB_OP_NOT
;
676 ret
->u
.isnot
.child
= ldap_decode_filter_tree(ret
, data
);
677 if (ret
->u
.isnot
.child
== NULL
) {
680 if (!asn1_end_tag(data
)) {
690 asn1_start_tag(data
, ASN1_CONTEXT(filter_tag
));
691 asn1_read_OctetString_talloc(mem_ctx
, data
, &attrib
);
692 asn1_read_OctetString(data
, mem_ctx
, &value
);
694 if ((data
->has_error
) || (attrib
== NULL
) || (value
.data
== NULL
)) {
698 ret
->operation
= LDB_OP_EQUALITY
;
699 ret
->u
.equality
.attr
= talloc_steal(ret
, attrib
);
700 ret
->u
.equality
.value
.data
= talloc_steal(ret
, value
.data
);
701 ret
->u
.equality
.value
.length
= value
.length
;
711 if (!asn1_start_tag(data
, ASN1_CONTEXT(filter_tag
))) {
714 if (!asn1_read_OctetString(data
, mem_ctx
, &attr
)) {
718 ret
->operation
= LDB_OP_SUBSTRING
;
719 ret
->u
.substring
.attr
= talloc_strndup(ret
, (char *)attr
.data
, attr
.length
);
720 ret
->u
.substring
.chunks
= NULL
;
721 ret
->u
.substring
.start_with_wildcard
= 1;
722 ret
->u
.substring
.end_with_wildcard
= 1;
724 if (!asn1_start_tag(data
, ASN1_SEQUENCE(0))) {
728 while (asn1_tag_remaining(data
)) {
729 asn1_peek_uint8(data
, &subs_tag
);
730 subs_tag
&= 0x1f; /* strip off the asn1 stuff */
731 if (subs_tag
> 2) goto failed
;
733 asn1_start_tag(data
, ASN1_CONTEXT_SIMPLE(subs_tag
));
734 asn1_read_LDAPString(data
, mem_ctx
, &value
);
739 if (ret
->u
.substring
.chunks
!= NULL
) {
740 /* initial value found in the middle */
744 ret
->u
.substring
.chunks
= ldap_decode_substring(ret
, NULL
, 0, value
);
745 if (ret
->u
.substring
.chunks
== NULL
) {
749 ret
->u
.substring
.start_with_wildcard
= 0;
754 if (ret
->u
.substring
.end_with_wildcard
== 0) {
755 /* "any" value found after a "final" value */
759 ret
->u
.substring
.chunks
= ldap_decode_substring(ret
,
760 ret
->u
.substring
.chunks
,
763 if (ret
->u
.substring
.chunks
== NULL
) {
771 ret
->u
.substring
.chunks
= ldap_decode_substring(ret
,
772 ret
->u
.substring
.chunks
,
775 if (ret
->u
.substring
.chunks
== NULL
) {
779 ret
->u
.substring
.end_with_wildcard
= 0;
788 if (!asn1_end_tag(data
)) { /* SEQUENCE */
792 if (!asn1_end_tag(data
)) {
802 asn1_start_tag(data
, ASN1_CONTEXT(filter_tag
));
803 asn1_read_OctetString_talloc(mem_ctx
, data
, &attrib
);
804 asn1_read_OctetString(data
, mem_ctx
, &value
);
806 if ((data
->has_error
) || (attrib
== NULL
) || (value
.data
== NULL
)) {
810 ret
->operation
= LDB_OP_GREATER
;
811 ret
->u
.comparison
.attr
= talloc_steal(ret
, attrib
);
812 ret
->u
.comparison
.value
.data
= talloc_steal(ret
, value
.data
);
813 ret
->u
.comparison
.value
.length
= value
.length
;
821 asn1_start_tag(data
, ASN1_CONTEXT(filter_tag
));
822 asn1_read_OctetString_talloc(mem_ctx
, data
, &attrib
);
823 asn1_read_OctetString(data
, mem_ctx
, &value
);
825 if ((data
->has_error
) || (attrib
== NULL
) || (value
.data
== NULL
)) {
829 ret
->operation
= LDB_OP_LESS
;
830 ret
->u
.comparison
.attr
= talloc_steal(ret
, attrib
);
831 ret
->u
.comparison
.value
.data
= talloc_steal(ret
, value
.data
);
832 ret
->u
.comparison
.value
.length
= value
.length
;
836 /* Normal presence, "attribute=*" */
839 if (!asn1_start_tag(data
, ASN1_CONTEXT_SIMPLE(filter_tag
))) {
842 if (!asn1_read_LDAPString(data
, ret
, &attr
)) {
846 ret
->operation
= LDB_OP_PRESENT
;
847 ret
->u
.present
.attr
= talloc_steal(ret
, attr
);
849 if (!asn1_end_tag(data
)) {
859 asn1_start_tag(data
, ASN1_CONTEXT(filter_tag
));
860 asn1_read_OctetString_talloc(mem_ctx
, data
, &attrib
);
861 asn1_read_OctetString(data
, mem_ctx
, &value
);
863 if ((data
->has_error
) || (attrib
== NULL
) || (value
.data
== NULL
)) {
867 ret
->operation
= LDB_OP_APPROX
;
868 ret
->u
.comparison
.attr
= talloc_steal(ret
, attrib
);
869 ret
->u
.comparison
.value
.data
= talloc_steal(ret
, value
.data
);
870 ret
->u
.comparison
.value
.length
= value
.length
;
874 char *oid
= NULL
, *attr
= NULL
, *value
;
875 uint8_t dnAttributes
;
876 /* an extended search */
877 if (!asn1_start_tag(data
, ASN1_CONTEXT(filter_tag
))) {
881 /* FIXME: read carefully rfc2251.txt there are a number of 'MUST's
882 we need to check we properly implement --SSS */
883 /* either oid or type must be defined */
884 if (asn1_peek_tag(data
, ASN1_CONTEXT_SIMPLE(1))) { /* optional */
885 asn1_start_tag(data
, ASN1_CONTEXT_SIMPLE(1));
886 asn1_read_LDAPString(data
, ret
, &oid
);
889 if (asn1_peek_tag(data
, ASN1_CONTEXT_SIMPLE(2))) { /* optional */
890 asn1_start_tag(data
, ASN1_CONTEXT_SIMPLE(2));
891 asn1_read_LDAPString(data
, ret
, &attr
);
894 asn1_start_tag(data
, ASN1_CONTEXT_SIMPLE(3));
895 asn1_read_LDAPString(data
, ret
, &value
);
897 /* dnAttributes is marked as BOOLEAN DEFAULT FALSE
898 it is not marked as OPTIONAL but openldap tools
899 do not set this unless it is to be set as TRUE
900 NOTE: openldap tools do not work with AD as it
901 seems that AD always requires the dnAttributes
902 boolean value to be set */
903 if (asn1_peek_tag(data
, ASN1_CONTEXT_SIMPLE(4))) {
904 asn1_start_tag(data
, ASN1_CONTEXT_SIMPLE(4));
905 asn1_read_uint8(data
, &dnAttributes
);
910 if ((oid
== NULL
&& attr
== NULL
) || (value
== NULL
)) {
915 ret
->operation
= LDB_OP_EXTENDED
;
917 /* From the RFC2251: If the type field is
918 absent and matchingRule is present, the matchValue is compared
919 against all attributes in an entry which support that matchingRule
922 ret
->u
.extended
.attr
= talloc_steal(ret
, attr
);
924 ret
->u
.extended
.attr
= talloc_strdup(ret
, "*");
926 ret
->u
.extended
.rule_id
= talloc_steal(ret
, oid
);
927 ret
->u
.extended
.value
.data
= talloc_steal(ret
, value
);
928 ret
->u
.extended
.value
.length
= strlen(value
);
929 ret
->u
.extended
.dnAttributes
= dnAttributes
;
931 ret
->operation
= LDB_OP_EQUALITY
;
932 ret
->u
.equality
.attr
= talloc_steal(ret
, attr
);
933 ret
->u
.equality
.value
.data
= talloc_steal(ret
, value
);
934 ret
->u
.equality
.value
.length
= strlen(value
);
936 if (!asn1_end_tag(data
)) {
953 /* Decode a single LDAP attribute, possibly containing multiple values */
954 static void ldap_decode_attrib(TALLOC_CTX
*mem_ctx
, struct asn1_data
*data
,
955 struct ldb_message_element
*attrib
)
957 asn1_start_tag(data
, ASN1_SEQUENCE(0));
958 asn1_read_OctetString_talloc(mem_ctx
, data
, &attrib
->name
);
959 asn1_start_tag(data
, ASN1_SET
);
960 while (asn1_peek_tag(data
, ASN1_OCTET_STRING
)) {
962 asn1_read_OctetString(data
, mem_ctx
, &blob
);
963 add_value_to_attrib(mem_ctx
, &blob
, attrib
);
970 /* Decode a set of LDAP attributes, as found in the dereference control */
971 void ldap_decode_attribs_bare(TALLOC_CTX
*mem_ctx
, struct asn1_data
*data
,
972 struct ldb_message_element
**attributes
,
975 while (asn1_peek_tag(data
, ASN1_SEQUENCE(0))) {
976 struct ldb_message_element attrib
;
978 ldap_decode_attrib(mem_ctx
, data
, &attrib
);
979 add_attrib_to_array_talloc(mem_ctx
, &attrib
,
980 attributes
, num_attributes
);
984 /* Decode a set of LDAP attributes, as found in a search entry */
985 static void ldap_decode_attribs(TALLOC_CTX
*mem_ctx
, struct asn1_data
*data
,
986 struct ldb_message_element
**attributes
,
989 asn1_start_tag(data
, ASN1_SEQUENCE(0));
990 ldap_decode_attribs_bare(mem_ctx
, data
,
991 attributes
, num_attributes
);
995 /* This routine returns LDAP status codes */
997 _PUBLIC_ NTSTATUS
ldap_decode(struct asn1_data
*data
, struct ldap_message
*msg
)
1001 asn1_start_tag(data
, ASN1_SEQUENCE(0));
1002 asn1_read_Integer(data
, &msg
->messageid
);
1004 if (!asn1_peek_uint8(data
, &tag
))
1005 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1009 case ASN1_APPLICATION(LDAP_TAG_BindRequest
): {
1010 struct ldap_BindRequest
*r
= &msg
->r
.BindRequest
;
1011 msg
->type
= LDAP_TAG_BindRequest
;
1012 asn1_start_tag(data
, tag
);
1013 asn1_read_Integer(data
, &r
->version
);
1014 asn1_read_OctetString_talloc(msg
, data
, &r
->dn
);
1015 if (asn1_peek_tag(data
, ASN1_CONTEXT_SIMPLE(0))) {
1017 r
->creds
.password
= "";
1018 r
->mechanism
= LDAP_AUTH_MECH_SIMPLE
;
1019 asn1_start_tag(data
, ASN1_CONTEXT_SIMPLE(0));
1020 pwlen
= asn1_tag_remaining(data
);
1022 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1025 char *pw
= talloc_array(msg
, char, pwlen
+1);
1027 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1029 asn1_read(data
, pw
, pwlen
);
1031 r
->creds
.password
= pw
;
1034 } else if (asn1_peek_tag(data
, ASN1_CONTEXT(3))){
1035 asn1_start_tag(data
, ASN1_CONTEXT(3));
1036 r
->mechanism
= LDAP_AUTH_MECH_SASL
;
1037 asn1_read_OctetString_talloc(msg
, data
, &r
->creds
.SASL
.mechanism
);
1038 if (asn1_peek_tag(data
, ASN1_OCTET_STRING
)) { /* optional */
1039 DATA_BLOB tmp_blob
= data_blob(NULL
, 0);
1040 asn1_read_OctetString(data
, msg
, &tmp_blob
);
1041 r
->creds
.SASL
.secblob
= talloc(msg
, DATA_BLOB
);
1042 if (!r
->creds
.SASL
.secblob
) {
1043 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1045 *r
->creds
.SASL
.secblob
= data_blob_talloc(r
->creds
.SASL
.secblob
,
1046 tmp_blob
.data
, tmp_blob
.length
);
1047 data_blob_free(&tmp_blob
);
1049 r
->creds
.SASL
.secblob
= NULL
;
1053 /* Neither Simple nor SASL bind */
1054 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1060 case ASN1_APPLICATION(LDAP_TAG_BindResponse
): {
1061 struct ldap_BindResponse
*r
= &msg
->r
.BindResponse
;
1062 msg
->type
= LDAP_TAG_BindResponse
;
1063 asn1_start_tag(data
, tag
);
1064 ldap_decode_response(msg
, data
, &r
->response
);
1065 if (asn1_peek_tag(data
, ASN1_CONTEXT_SIMPLE(7))) {
1066 DATA_BLOB tmp_blob
= data_blob(NULL
, 0);
1067 asn1_read_ContextSimple(data
, 7, &tmp_blob
);
1068 r
->SASL
.secblob
= talloc(msg
, DATA_BLOB
);
1069 if (!r
->SASL
.secblob
) {
1070 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1072 *r
->SASL
.secblob
= data_blob_talloc(r
->SASL
.secblob
,
1073 tmp_blob
.data
, tmp_blob
.length
);
1074 data_blob_free(&tmp_blob
);
1076 r
->SASL
.secblob
= NULL
;
1082 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest
): {
1083 msg
->type
= LDAP_TAG_UnbindRequest
;
1084 asn1_start_tag(data
, tag
);
1089 case ASN1_APPLICATION(LDAP_TAG_SearchRequest
): {
1090 struct ldap_SearchRequest
*r
= &msg
->r
.SearchRequest
;
1091 msg
->type
= LDAP_TAG_SearchRequest
;
1092 asn1_start_tag(data
, tag
);
1093 asn1_read_OctetString_talloc(msg
, data
, &r
->basedn
);
1094 asn1_read_enumerated(data
, (int *)&(r
->scope
));
1095 asn1_read_enumerated(data
, (int *)&(r
->deref
));
1096 asn1_read_Integer(data
, &r
->sizelimit
);
1097 asn1_read_Integer(data
, &r
->timelimit
);
1098 asn1_read_BOOLEAN(data
, &r
->attributesonly
);
1100 r
->tree
= ldap_decode_filter_tree(msg
, data
);
1101 if (r
->tree
== NULL
) {
1102 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1105 asn1_start_tag(data
, ASN1_SEQUENCE(0));
1107 r
->num_attributes
= 0;
1108 r
->attributes
= NULL
;
1110 while (asn1_tag_remaining(data
) > 0) {
1113 if (!asn1_read_OctetString_talloc(msg
, data
,
1115 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1116 if (!add_string_to_array(msg
, attr
,
1118 &r
->num_attributes
))
1119 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1127 case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry
): {
1128 struct ldap_SearchResEntry
*r
= &msg
->r
.SearchResultEntry
;
1129 msg
->type
= LDAP_TAG_SearchResultEntry
;
1130 r
->attributes
= NULL
;
1131 r
->num_attributes
= 0;
1132 asn1_start_tag(data
, tag
);
1133 asn1_read_OctetString_talloc(msg
, data
, &r
->dn
);
1134 ldap_decode_attribs(msg
, data
, &r
->attributes
,
1135 &r
->num_attributes
);
1140 case ASN1_APPLICATION(LDAP_TAG_SearchResultDone
): {
1141 struct ldap_Result
*r
= &msg
->r
.SearchResultDone
;
1142 msg
->type
= LDAP_TAG_SearchResultDone
;
1143 asn1_start_tag(data
, tag
);
1144 ldap_decode_response(msg
, data
, r
);
1149 case ASN1_APPLICATION(LDAP_TAG_SearchResultReference
): {
1150 struct ldap_SearchResRef
*r
= &msg
->r
.SearchResultReference
;
1151 msg
->type
= LDAP_TAG_SearchResultReference
;
1152 asn1_start_tag(data
, tag
);
1153 asn1_read_OctetString_talloc(msg
, data
, &r
->referral
);
1158 case ASN1_APPLICATION(LDAP_TAG_ModifyRequest
): {
1159 struct ldap_ModifyRequest
*r
= &msg
->r
.ModifyRequest
;
1160 msg
->type
= LDAP_TAG_ModifyRequest
;
1161 asn1_start_tag(data
, ASN1_APPLICATION(LDAP_TAG_ModifyRequest
));
1162 asn1_read_OctetString_talloc(msg
, data
, &r
->dn
);
1163 asn1_start_tag(data
, ASN1_SEQUENCE(0));
1168 while (asn1_tag_remaining(data
) > 0) {
1169 struct ldap_mod mod
;
1172 asn1_start_tag(data
, ASN1_SEQUENCE(0));
1173 asn1_read_enumerated(data
, &v
);
1175 ldap_decode_attrib(msg
, data
, &mod
.attrib
);
1177 if (!add_mod_to_array_talloc(msg
, &mod
,
1178 &r
->mods
, &r
->num_mods
)) {
1179 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1188 case ASN1_APPLICATION(LDAP_TAG_ModifyResponse
): {
1189 struct ldap_Result
*r
= &msg
->r
.ModifyResponse
;
1190 msg
->type
= LDAP_TAG_ModifyResponse
;
1191 asn1_start_tag(data
, tag
);
1192 ldap_decode_response(msg
, data
, r
);
1197 case ASN1_APPLICATION(LDAP_TAG_AddRequest
): {
1198 struct ldap_AddRequest
*r
= &msg
->r
.AddRequest
;
1199 msg
->type
= LDAP_TAG_AddRequest
;
1200 asn1_start_tag(data
, tag
);
1201 asn1_read_OctetString_talloc(msg
, data
, &r
->dn
);
1203 r
->attributes
= NULL
;
1204 r
->num_attributes
= 0;
1205 ldap_decode_attribs(msg
, data
, &r
->attributes
,
1206 &r
->num_attributes
);
1212 case ASN1_APPLICATION(LDAP_TAG_AddResponse
): {
1213 struct ldap_Result
*r
= &msg
->r
.AddResponse
;
1214 msg
->type
= LDAP_TAG_AddResponse
;
1215 asn1_start_tag(data
, tag
);
1216 ldap_decode_response(msg
, data
, r
);
1221 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest
): {
1222 struct ldap_DelRequest
*r
= &msg
->r
.DelRequest
;
1225 msg
->type
= LDAP_TAG_DelRequest
;
1226 asn1_start_tag(data
,
1227 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest
));
1228 len
= asn1_tag_remaining(data
);
1230 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1232 dn
= talloc_array(msg
, char, len
+1);
1235 asn1_read(data
, dn
, len
);
1242 case ASN1_APPLICATION(LDAP_TAG_DelResponse
): {
1243 struct ldap_Result
*r
= &msg
->r
.DelResponse
;
1244 msg
->type
= LDAP_TAG_DelResponse
;
1245 asn1_start_tag(data
, tag
);
1246 ldap_decode_response(msg
, data
, r
);
1251 case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest
): {
1252 struct ldap_ModifyDNRequest
*r
= &msg
->r
.ModifyDNRequest
;
1253 msg
->type
= LDAP_TAG_ModifyDNRequest
;
1254 asn1_start_tag(data
,
1255 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest
));
1256 asn1_read_OctetString_talloc(msg
, data
, &r
->dn
);
1257 asn1_read_OctetString_talloc(msg
, data
, &r
->newrdn
);
1258 asn1_read_BOOLEAN(data
, &r
->deleteolddn
);
1259 r
->newsuperior
= NULL
;
1260 if (asn1_tag_remaining(data
) > 0) {
1263 asn1_start_tag(data
, ASN1_CONTEXT_SIMPLE(0));
1264 len
= asn1_tag_remaining(data
);
1266 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1268 newsup
= talloc_array(msg
, char, len
+1);
1269 if (newsup
== NULL
) {
1270 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1272 asn1_read(data
, newsup
, len
);
1274 r
->newsuperior
= newsup
;
1281 case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse
): {
1282 struct ldap_Result
*r
= &msg
->r
.ModifyDNResponse
;
1283 msg
->type
= LDAP_TAG_ModifyDNResponse
;
1284 asn1_start_tag(data
, tag
);
1285 ldap_decode_response(msg
, data
, r
);
1290 case ASN1_APPLICATION(LDAP_TAG_CompareRequest
): {
1291 struct ldap_CompareRequest
*r
= &msg
->r
.CompareRequest
;
1292 msg
->type
= LDAP_TAG_CompareRequest
;
1293 asn1_start_tag(data
,
1294 ASN1_APPLICATION(LDAP_TAG_CompareRequest
));
1295 asn1_read_OctetString_talloc(msg
, data
, &r
->dn
);
1296 asn1_start_tag(data
, ASN1_SEQUENCE(0));
1297 asn1_read_OctetString_talloc(msg
, data
, &r
->attribute
);
1298 asn1_read_OctetString(data
, msg
, &r
->value
);
1299 if (r
->value
.data
) {
1300 talloc_steal(msg
, r
->value
.data
);
1307 case ASN1_APPLICATION(LDAP_TAG_CompareResponse
): {
1308 struct ldap_Result
*r
= &msg
->r
.CompareResponse
;
1309 msg
->type
= LDAP_TAG_CompareResponse
;
1310 asn1_start_tag(data
, tag
);
1311 ldap_decode_response(msg
, data
, r
);
1316 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest
): {
1317 struct ldap_AbandonRequest
*r
= &msg
->r
.AbandonRequest
;
1318 msg
->type
= LDAP_TAG_AbandonRequest
;
1319 asn1_start_tag(data
, tag
);
1320 asn1_read_implicit_Integer(data
, &r
->messageid
);
1325 case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest
): {
1326 struct ldap_ExtendedRequest
*r
= &msg
->r
.ExtendedRequest
;
1327 DATA_BLOB tmp_blob
= data_blob(NULL
, 0);
1329 msg
->type
= LDAP_TAG_ExtendedRequest
;
1330 asn1_start_tag(data
,tag
);
1331 if (!asn1_read_ContextSimple(data
, 0, &tmp_blob
)) {
1332 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1334 r
->oid
= blob2string_talloc(msg
, tmp_blob
);
1335 data_blob_free(&tmp_blob
);
1337 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1340 if (asn1_peek_tag(data
, ASN1_CONTEXT_SIMPLE(1))) {
1341 asn1_read_ContextSimple(data
, 1, &tmp_blob
);
1342 r
->value
= talloc(msg
, DATA_BLOB
);
1344 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1346 *r
->value
= data_blob_talloc(r
->value
, tmp_blob
.data
, tmp_blob
.length
);
1347 data_blob_free(&tmp_blob
);
1356 case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse
): {
1357 struct ldap_ExtendedResponse
*r
= &msg
->r
.ExtendedResponse
;
1358 DATA_BLOB tmp_blob
= data_blob(NULL
, 0);
1360 msg
->type
= LDAP_TAG_ExtendedResponse
;
1361 asn1_start_tag(data
, tag
);
1362 ldap_decode_response(msg
, data
, &r
->response
);
1364 if (asn1_peek_tag(data
, ASN1_CONTEXT_SIMPLE(10))) {
1365 asn1_read_ContextSimple(data
, 1, &tmp_blob
);
1366 r
->oid
= blob2string_talloc(msg
, tmp_blob
);
1367 data_blob_free(&tmp_blob
);
1369 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1375 if (asn1_peek_tag(data
, ASN1_CONTEXT_SIMPLE(11))) {
1376 asn1_read_ContextSimple(data
, 1, &tmp_blob
);
1377 r
->value
= talloc(msg
, DATA_BLOB
);
1379 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1381 *r
->value
= data_blob_talloc(r
->value
, tmp_blob
.data
, tmp_blob
.length
);
1382 data_blob_free(&tmp_blob
);
1391 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1394 msg
->controls
= NULL
;
1395 msg
->controls_decoded
= NULL
;
1397 if (asn1_peek_tag(data
, ASN1_CONTEXT(0))) {
1399 struct ldb_control
**ctrl
= NULL
;
1400 bool *decoded
= NULL
;
1402 asn1_start_tag(data
, ASN1_CONTEXT(0));
1404 while (asn1_peek_tag(data
, ASN1_SEQUENCE(0))) {
1406 /* asn1_start_tag(data, ASN1_SEQUENCE(0)); */
1408 ctrl
= talloc_realloc(msg
, ctrl
, struct ldb_control
*, i
+2);
1410 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1413 decoded
= talloc_realloc(msg
, decoded
, bool, i
+1);
1415 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1418 ctrl
[i
] = talloc(ctrl
, struct ldb_control
);
1420 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
1423 if (!ldap_decode_control_wrapper(ctrl
, data
, ctrl
[i
], &value
)) {
1424 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1427 if (!ldap_decode_control_value(ctrl
, value
, ctrl
[i
])) {
1428 if (ctrl
[i
]->critical
) {
1429 ctrl
[i
]->data
= NULL
;
1433 talloc_free(ctrl
[i
]);
1446 msg
->controls
= ctrl
;
1447 msg
->controls_decoded
= decoded
;
1453 if ((data
->has_error
) || (data
->nesting
!= NULL
)) {
1454 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1456 return NT_STATUS_OK
;
1461 return NT_STATUS_OK if a blob has enough bytes in it to be a full
1462 ldap packet. Set packet_size if true.
1464 NTSTATUS
ldap_full_packet(void *private_data
, DATA_BLOB blob
, size_t *packet_size
)
1466 return asn1_full_tag(blob
, ASN1_SEQUENCE(0), packet_size
);