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)) {
943 DEBUG(0,("Unsupported LDAP filter operation 0x%x\n", filter_tag));
954 /* Decode a single LDAP attribute, possibly containing multiple values */
955 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
956 struct ldb_message_element *attrib)
958 asn1_start_tag(data, ASN1_SEQUENCE(0));
959 asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
960 asn1_start_tag(data, ASN1_SET);
961 while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
963 asn1_read_OctetString(data, mem_ctx, &blob);
964 add_value_to_attrib(mem_ctx, &blob, attrib);
971 /* Decode a set of LDAP attributes, as found in the dereference control */
972 void ldap_decode_attribs_bare(TALLOC_CTX *mem_ctx, struct asn1_data *data,
973 struct ldb_message_element **attributes,
976 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
977 struct ldb_message_element attrib;
979 ldap_decode_attrib(mem_ctx, data, &attrib);
980 add_attrib_to_array_talloc(mem_ctx, &attrib,
981 attributes, num_attributes);
985 /* Decode a set of LDAP attributes, as found in a search entry */
986 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
987 struct ldb_message_element **attributes,
990 asn1_start_tag(data, ASN1_SEQUENCE(0));
991 ldap_decode_attribs_bare(mem_ctx, data,
992 attributes, num_attributes);
996 /* This routine returns LDAP status codes */
998 _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
1002 asn1_start_tag(data, ASN1_SEQUENCE(0));
1003 asn1_read_Integer(data, &msg->messageid);
1005 if (!asn1_peek_uint8(data, &tag))
1006 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1010 case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
1011 struct ldap_BindRequest *r = &msg->r.BindRequest;
1012 msg->type = LDAP_TAG_BindRequest;
1013 asn1_start_tag(data, tag);
1014 asn1_read_Integer(data, &r->version);
1015 asn1_read_OctetString_talloc(msg, data, &r->dn);
1016 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
1018 r->creds.password = "";
1019 r->mechanism = LDAP_AUTH_MECH_SIMPLE;
1020 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1021 pwlen = asn1_tag_remaining(data);
1023 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1026 char *pw = talloc_array(msg, char, pwlen+1);
1028 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1030 asn1_read(data, pw, pwlen);
1032 r->creds.password = pw;
1035 } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
1036 asn1_start_tag(data, ASN1_CONTEXT(3));
1037 r->mechanism = LDAP_AUTH_MECH_SASL;
1038 asn1_read_OctetString_talloc(msg, data, &r->creds.SASL.mechanism);
1039 if (asn1_peek_tag(data, ASN1_OCTET_STRING)) { /* optional */
1040 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1041 asn1_read_OctetString(data, msg, &tmp_blob);
1042 r->creds.SASL.secblob = talloc(msg, DATA_BLOB);
1043 if (!r->creds.SASL.secblob) {
1044 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1046 *r->creds.SASL.secblob = data_blob_talloc(r->creds.SASL.secblob,
1047 tmp_blob.data, tmp_blob.length);
1048 data_blob_free(&tmp_blob);
1050 r->creds.SASL.secblob = NULL;
1054 /* Neither Simple nor SASL bind */
1055 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1061 case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
1062 struct ldap_BindResponse *r = &msg->r.BindResponse;
1063 msg->type = LDAP_TAG_BindResponse;
1064 asn1_start_tag(data, tag);
1065 ldap_decode_response(msg, data, &r->response);
1066 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
1067 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1068 asn1_read_ContextSimple(data, 7, &tmp_blob);
1069 r->SASL.secblob = talloc(msg, DATA_BLOB);
1070 if (!r->SASL.secblob) {
1071 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1073 *r->SASL.secblob = data_blob_talloc(r->SASL.secblob,
1074 tmp_blob.data, tmp_blob.length);
1075 data_blob_free(&tmp_blob);
1077 r->SASL.secblob = NULL;
1083 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
1084 msg->type = LDAP_TAG_UnbindRequest;
1085 asn1_start_tag(data, tag);
1090 case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
1091 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
1092 msg->type = LDAP_TAG_SearchRequest;
1093 asn1_start_tag(data, tag);
1094 asn1_read_OctetString_talloc(msg, data, &r->basedn);
1095 asn1_read_enumerated(data, (int *)&(r->scope));
1096 asn1_read_enumerated(data, (int *)&(r->deref));
1097 asn1_read_Integer(data, &r->sizelimit);
1098 asn1_read_Integer(data, &r->timelimit);
1099 asn1_read_BOOLEAN(data, &r->attributesonly);
1101 r->tree = ldap_decode_filter_tree(msg, data);
1102 if (r->tree == NULL) {
1103 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1106 asn1_start_tag(data, ASN1_SEQUENCE(0));
1108 r->num_attributes = 0;
1109 r->attributes = NULL;
1111 while (asn1_tag_remaining(data) > 0) {
1114 if (!asn1_read_OctetString_talloc(msg, data,
1116 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1117 if (!add_string_to_array(msg, attr,
1119 &r->num_attributes))
1120 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1128 case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
1129 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
1130 msg->type = LDAP_TAG_SearchResultEntry;
1131 r->attributes = NULL;
1132 r->num_attributes = 0;
1133 asn1_start_tag(data, tag);
1134 asn1_read_OctetString_talloc(msg, data, &r->dn);
1135 ldap_decode_attribs(msg, data, &r->attributes,
1136 &r->num_attributes);
1141 case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
1142 struct ldap_Result *r = &msg->r.SearchResultDone;
1143 msg->type = LDAP_TAG_SearchResultDone;
1144 asn1_start_tag(data, tag);
1145 ldap_decode_response(msg, data, r);
1150 case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
1151 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
1152 msg->type = LDAP_TAG_SearchResultReference;
1153 asn1_start_tag(data, tag);
1154 asn1_read_OctetString_talloc(msg, data, &r->referral);
1159 case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
1160 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
1161 msg->type = LDAP_TAG_ModifyRequest;
1162 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
1163 asn1_read_OctetString_talloc(msg, data, &r->dn);
1164 asn1_start_tag(data, ASN1_SEQUENCE(0));
1169 while (asn1_tag_remaining(data) > 0) {
1170 struct ldap_mod mod;
1173 asn1_start_tag(data, ASN1_SEQUENCE(0));
1174 asn1_read_enumerated(data, &v);
1176 ldap_decode_attrib(msg, data, &mod.attrib);
1178 if (!add_mod_to_array_talloc(msg, &mod,
1179 &r->mods, &r->num_mods)) {
1180 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1189 case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
1190 struct ldap_Result *r = &msg->r.ModifyResponse;
1191 msg->type = LDAP_TAG_ModifyResponse;
1192 asn1_start_tag(data, tag);
1193 ldap_decode_response(msg, data, r);
1198 case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
1199 struct ldap_AddRequest *r = &msg->r.AddRequest;
1200 msg->type = LDAP_TAG_AddRequest;
1201 asn1_start_tag(data, tag);
1202 asn1_read_OctetString_talloc(msg, data, &r->dn);
1204 r->attributes = NULL;
1205 r->num_attributes = 0;
1206 ldap_decode_attribs(msg, data, &r->attributes,
1207 &r->num_attributes);
1213 case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1214 struct ldap_Result *r = &msg->r.AddResponse;
1215 msg->type = LDAP_TAG_AddResponse;
1216 asn1_start_tag(data, tag);
1217 ldap_decode_response(msg, data, r);
1222 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1223 struct ldap_DelRequest *r = &msg->r.DelRequest;
1226 msg->type = LDAP_TAG_DelRequest;
1227 asn1_start_tag(data,
1228 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1229 len = asn1_tag_remaining(data);
1231 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1233 dn = talloc_array(msg, char, len+1);
1236 asn1_read(data, dn, len);
1243 case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1244 struct ldap_Result *r = &msg->r.DelResponse;
1245 msg->type = LDAP_TAG_DelResponse;
1246 asn1_start_tag(data, tag);
1247 ldap_decode_response(msg, data, r);
1252 case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1253 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
1254 msg->type = LDAP_TAG_ModifyDNRequest;
1255 asn1_start_tag(data,
1256 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
1257 asn1_read_OctetString_talloc(msg, data, &r->dn);
1258 asn1_read_OctetString_talloc(msg, data, &r->newrdn);
1259 asn1_read_BOOLEAN(data, &r->deleteolddn);
1260 r->newsuperior = NULL;
1261 if (asn1_tag_remaining(data) > 0) {
1264 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1265 len = asn1_tag_remaining(data);
1267 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1269 newsup = talloc_array(msg, char, len+1);
1270 if (newsup == NULL) {
1271 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1273 asn1_read(data, newsup, len);
1275 r->newsuperior = newsup;
1282 case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1283 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1284 msg->type = LDAP_TAG_ModifyDNResponse;
1285 asn1_start_tag(data, tag);
1286 ldap_decode_response(msg, data, r);
1291 case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1292 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
1293 msg->type = LDAP_TAG_CompareRequest;
1294 asn1_start_tag(data,
1295 ASN1_APPLICATION(LDAP_TAG_CompareRequest));
1296 asn1_read_OctetString_talloc(msg, data, &r->dn);
1297 asn1_start_tag(data, ASN1_SEQUENCE(0));
1298 asn1_read_OctetString_talloc(msg, data, &r->attribute);
1299 asn1_read_OctetString(data, msg, &r->value);
1300 if (r->value.data) {
1301 talloc_steal(msg, r->value.data);
1308 case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1309 struct ldap_Result *r = &msg->r.CompareResponse;
1310 msg->type = LDAP_TAG_CompareResponse;
1311 asn1_start_tag(data, tag);
1312 ldap_decode_response(msg, data, r);
1317 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
1318 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
1319 msg->type = LDAP_TAG_AbandonRequest;
1320 asn1_start_tag(data, tag);
1321 asn1_read_implicit_Integer(data, &r->messageid);
1326 case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1327 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1328 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1330 msg->type = LDAP_TAG_ExtendedRequest;
1331 asn1_start_tag(data,tag);
1332 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
1333 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1335 r->oid = blob2string_talloc(msg, tmp_blob);
1336 data_blob_free(&tmp_blob);
1338 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1341 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
1342 asn1_read_ContextSimple(data, 1, &tmp_blob);
1343 r->value = talloc(msg, DATA_BLOB);
1345 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1347 *r->value = data_blob_talloc(r->value, tmp_blob.data, tmp_blob.length);
1348 data_blob_free(&tmp_blob);
1357 case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1358 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1359 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1361 msg->type = LDAP_TAG_ExtendedResponse;
1362 asn1_start_tag(data, tag);
1363 ldap_decode_response(msg, data, &r->response);
1365 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(10))) {
1366 asn1_read_ContextSimple(data, 1, &tmp_blob);
1367 r->oid = blob2string_talloc(msg, tmp_blob);
1368 data_blob_free(&tmp_blob);
1370 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1376 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(11))) {
1377 asn1_read_ContextSimple(data, 1, &tmp_blob);
1378 r->value = talloc(msg, DATA_BLOB);
1380 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1382 *r->value = data_blob_talloc(r->value, tmp_blob.data, tmp_blob.length);
1383 data_blob_free(&tmp_blob);
1392 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1395 msg->controls = NULL;
1396 msg->controls_decoded = NULL;
1398 if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
1400 struct ldb_control **ctrl = NULL;
1401 bool *decoded = NULL;
1403 asn1_start_tag(data, ASN1_CONTEXT(0));
1405 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
1407 /* asn1_start_tag(data, ASN1_SEQUENCE(0)); */
1409 ctrl = talloc_realloc(msg, ctrl, struct ldb_control *, i+2);
1411 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1414 decoded = talloc_realloc(msg, decoded, bool, i+1);
1416 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1419 ctrl[i] = talloc(ctrl, struct ldb_control);
1421 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1424 if (!ldap_decode_control_wrapper(ctrl, data, ctrl[i], &value)) {
1425 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1428 if (!ldap_decode_control_value(ctrl, value, ctrl[i])) {
1429 if (ctrl[i]->critical) {
1430 ctrl[i]->data = NULL;
1434 talloc_free(ctrl[i]);
1447 msg->controls = ctrl;
1448 msg->controls_decoded = decoded;
1454 if ((data->has_error) || (data->nesting != NULL)) {
1455 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1457 return NT_STATUS_OK;
1462 return NT_STATUS_OK if a blob has enough bytes in it to be a full
1463 ldap packet. Set packet_size if true.
1465 NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_size)
1467 return asn1_full_tag(blob, ASN1_SEQUENCE(0), packet_size);