r12917: fix decoding of ldap controls
[Samba/aatanasov.git] / source / libcli / ldap / ldap.c
blobb281f62ed017d616bfe954191a88a310b49b7202
1 /*
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 2 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, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "includes.h"
27 #include "system/iconv.h"
28 #include "libcli/util/asn_1.h"
29 #include "libcli/ldap/ldap.h"
32 static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
34 int i;
36 switch (tree->operation) {
37 case LDB_OP_AND:
38 case LDB_OP_OR:
39 asn1_push_tag(data, ASN1_CONTEXT(tree->operation==LDB_OP_AND?0:1));
40 for (i=0; i<tree->u.list.num_elements; i++) {
41 if (!ldap_push_filter(data, tree->u.list.elements[i])) {
42 return False;
45 asn1_pop_tag(data);
46 break;
48 case LDB_OP_NOT:
49 asn1_push_tag(data, ASN1_CONTEXT(2));
50 if (!ldap_push_filter(data, tree->u.isnot.child)) {
51 return False;
53 asn1_pop_tag(data);
54 break;
56 case LDB_OP_EQUALITY:
57 /* equality test */
58 asn1_push_tag(data, ASN1_CONTEXT(3));
59 asn1_write_OctetString(data, tree->u.equality.attr,
60 strlen(tree->u.equality.attr));
61 asn1_write_OctetString(data, tree->u.equality.value.data,
62 tree->u.equality.value.length);
63 asn1_pop_tag(data);
64 break;
66 case LDB_OP_SUBSTRING:
68 SubstringFilter ::= SEQUENCE {
69 type AttributeDescription,
70 -- at least one must be present
71 substrings SEQUENCE OF CHOICE {
72 initial [0] LDAPString,
73 any [1] LDAPString,
74 final [2] LDAPString } }
76 asn1_push_tag(data, ASN1_CONTEXT(4));
77 asn1_write_OctetString(data, tree->u.substring.attr, strlen(tree->u.substring.attr));
78 asn1_push_tag(data, ASN1_SEQUENCE(0));
79 i = 0;
80 if ( ! tree->u.substring.start_with_wildcard) {
81 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
82 asn1_write_LDAPString(data, (char *)tree->u.substring.chunks[i]->data);
83 asn1_pop_tag(data);
84 i++;
86 while (tree->u.substring.chunks[i]) {
87 int ctx;
89 if (( ! tree->u.substring.chunks[i + 1]) &&
90 (tree->u.substring.end_with_wildcard == 0)) {
91 ctx = 2;
92 } else {
93 ctx = 1;
95 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(ctx));
96 asn1_write_LDAPString(data, (char *)tree->u.substring.chunks[i]->data);
97 asn1_pop_tag(data);
98 i++;
100 asn1_pop_tag(data);
101 asn1_pop_tag(data);
102 break;
104 case LDB_OP_GREATER:
105 /* greaterOrEqual test */
106 asn1_push_tag(data, ASN1_CONTEXT(5));
107 asn1_write_OctetString(data, tree->u.comparison.attr,
108 strlen(tree->u.comparison.attr));
109 asn1_write_OctetString(data, tree->u.comparison.value.data,
110 tree->u.comparison.value.length);
111 asn1_pop_tag(data);
112 break;
114 case LDB_OP_LESS:
115 /* lessOrEqual test */
116 asn1_push_tag(data, ASN1_CONTEXT(6));
117 asn1_write_OctetString(data, tree->u.comparison.attr,
118 strlen(tree->u.comparison.attr));
119 asn1_write_OctetString(data, tree->u.comparison.value.data,
120 tree->u.comparison.value.length);
121 asn1_pop_tag(data);
122 break;
124 case LDB_OP_PRESENT:
125 /* present test */
126 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(7));
127 asn1_write_LDAPString(data, tree->u.present.attr);
128 asn1_pop_tag(data);
129 return !data->has_error;
131 case LDB_OP_APPROX:
132 /* approx test */
133 asn1_push_tag(data, ASN1_CONTEXT(8));
134 asn1_write_OctetString(data, tree->u.comparison.attr,
135 strlen(tree->u.comparison.attr));
136 asn1_write_OctetString(data, tree->u.comparison.value.data,
137 tree->u.comparison.value.length);
138 asn1_pop_tag(data);
139 break;
141 case LDB_OP_EXTENDED:
143 MatchingRuleAssertion ::= SEQUENCE {
144 matchingRule [1] MatchingRuleID OPTIONAL,
145 type [2] AttributeDescription OPTIONAL,
146 matchValue [3] AssertionValue,
147 dnAttributes [4] BOOLEAN DEFAULT FALSE
150 asn1_push_tag(data, ASN1_CONTEXT(9));
151 if (tree->u.extended.rule_id) {
152 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1));
153 asn1_write_LDAPString(data, tree->u.extended.rule_id);
154 asn1_pop_tag(data);
156 if (tree->u.extended.attr) {
157 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2));
158 asn1_write_LDAPString(data, tree->u.extended.attr);
159 asn1_pop_tag(data);
161 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3));
162 asn1_write_LDAPString(data, (char *)tree->u.extended.value.data);
163 asn1_pop_tag(data);
164 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4));
165 asn1_write_uint8(data, tree->u.extended.dnAttributes);
166 asn1_pop_tag(data);
167 asn1_pop_tag(data);
168 break;
170 default:
171 return False;
173 return !data->has_error;
176 static void ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
178 asn1_write_enumerated(data, result->resultcode);
179 asn1_write_OctetString(data, result->dn,
180 (result->dn) ? strlen(result->dn) : 0);
181 asn1_write_OctetString(data, result->errormessage,
182 (result->errormessage) ?
183 strlen(result->errormessage) : 0);
184 if (result->referral) {
185 asn1_push_tag(data, ASN1_CONTEXT(3));
186 asn1_write_OctetString(data, result->referral,
187 strlen(result->referral));
188 asn1_pop_tag(data);
192 BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ctx)
194 struct asn1_data data;
195 int i, j;
197 ZERO_STRUCT(data);
198 asn1_push_tag(&data, ASN1_SEQUENCE(0));
199 asn1_write_Integer(&data, msg->messageid);
201 switch (msg->type) {
202 case LDAP_TAG_BindRequest: {
203 struct ldap_BindRequest *r = &msg->r.BindRequest;
204 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
205 asn1_write_Integer(&data, r->version);
206 asn1_write_OctetString(&data, r->dn,
207 (r->dn != NULL) ? strlen(r->dn) : 0);
209 switch (r->mechanism) {
210 case LDAP_AUTH_MECH_SIMPLE:
211 /* context, primitive */
212 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
213 asn1_write(&data, r->creds.password,
214 strlen(r->creds.password));
215 asn1_pop_tag(&data);
216 break;
217 case LDAP_AUTH_MECH_SASL:
218 /* context, constructed */
219 asn1_push_tag(&data, ASN1_CONTEXT(3));
220 asn1_write_OctetString(&data, r->creds.SASL.mechanism,
221 strlen(r->creds.SASL.mechanism));
222 asn1_write_OctetString(&data, r->creds.SASL.secblob.data,
223 r->creds.SASL.secblob.length);
224 asn1_pop_tag(&data);
225 break;
226 default:
227 return False;
230 asn1_pop_tag(&data);
231 break;
233 case LDAP_TAG_BindResponse: {
234 struct ldap_BindResponse *r = &msg->r.BindResponse;
235 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
236 ldap_encode_response(&data, &r->response);
237 asn1_write_ContextSimple(&data, 7, &r->SASL.secblob);
238 asn1_pop_tag(&data);
239 break;
241 case LDAP_TAG_UnbindRequest: {
242 /* struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
243 break;
245 case LDAP_TAG_SearchRequest: {
246 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
247 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
248 asn1_write_OctetString(&data, r->basedn, strlen(r->basedn));
249 asn1_write_enumerated(&data, r->scope);
250 asn1_write_enumerated(&data, r->deref);
251 asn1_write_Integer(&data, r->sizelimit);
252 asn1_write_Integer(&data, r->timelimit);
253 asn1_write_BOOLEAN(&data, r->attributesonly);
255 if (!ldap_push_filter(&data, r->tree)) {
256 return False;
259 asn1_push_tag(&data, ASN1_SEQUENCE(0));
260 for (i=0; i<r->num_attributes; i++) {
261 asn1_write_OctetString(&data, r->attributes[i],
262 strlen(r->attributes[i]));
264 asn1_pop_tag(&data);
265 asn1_pop_tag(&data);
266 break;
268 case LDAP_TAG_SearchResultEntry: {
269 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
270 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
271 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
272 asn1_push_tag(&data, ASN1_SEQUENCE(0));
273 for (i=0; i<r->num_attributes; i++) {
274 struct ldb_message_element *attr = &r->attributes[i];
275 asn1_push_tag(&data, ASN1_SEQUENCE(0));
276 asn1_write_OctetString(&data, attr->name,
277 strlen(attr->name));
278 asn1_push_tag(&data, ASN1_SEQUENCE(1));
279 for (j=0; j<attr->num_values; j++) {
280 asn1_write_OctetString(&data,
281 attr->values[j].data,
282 attr->values[j].length);
284 asn1_pop_tag(&data);
285 asn1_pop_tag(&data);
287 asn1_pop_tag(&data);
288 asn1_pop_tag(&data);
289 break;
291 case LDAP_TAG_SearchResultDone: {
292 struct ldap_Result *r = &msg->r.SearchResultDone;
293 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
294 ldap_encode_response(&data, r);
295 asn1_pop_tag(&data);
296 break;
298 case LDAP_TAG_ModifyRequest: {
299 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
300 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
301 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
302 asn1_push_tag(&data, ASN1_SEQUENCE(0));
304 for (i=0; i<r->num_mods; i++) {
305 struct ldb_message_element *attrib = &r->mods[i].attrib;
306 asn1_push_tag(&data, ASN1_SEQUENCE(0));
307 asn1_write_enumerated(&data, r->mods[i].type);
308 asn1_push_tag(&data, ASN1_SEQUENCE(0));
309 asn1_write_OctetString(&data, attrib->name,
310 strlen(attrib->name));
311 asn1_push_tag(&data, ASN1_SET);
312 for (j=0; j<attrib->num_values; j++) {
313 asn1_write_OctetString(&data,
314 attrib->values[j].data,
315 attrib->values[j].length);
318 asn1_pop_tag(&data);
319 asn1_pop_tag(&data);
320 asn1_pop_tag(&data);
323 asn1_pop_tag(&data);
324 asn1_pop_tag(&data);
325 break;
327 case LDAP_TAG_ModifyResponse: {
328 struct ldap_Result *r = &msg->r.ModifyResponse;
329 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
330 ldap_encode_response(&data, r);
331 asn1_pop_tag(&data);
332 break;
334 case LDAP_TAG_AddRequest: {
335 struct ldap_AddRequest *r = &msg->r.AddRequest;
336 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
337 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
338 asn1_push_tag(&data, ASN1_SEQUENCE(0));
340 for (i=0; i<r->num_attributes; i++) {
341 struct ldb_message_element *attrib = &r->attributes[i];
342 asn1_push_tag(&data, ASN1_SEQUENCE(0));
343 asn1_write_OctetString(&data, attrib->name,
344 strlen(attrib->name));
345 asn1_push_tag(&data, ASN1_SET);
346 for (j=0; j<r->attributes[i].num_values; j++) {
347 asn1_write_OctetString(&data,
348 attrib->values[j].data,
349 attrib->values[j].length);
351 asn1_pop_tag(&data);
352 asn1_pop_tag(&data);
354 asn1_pop_tag(&data);
355 asn1_pop_tag(&data);
356 break;
358 case LDAP_TAG_AddResponse: {
359 struct ldap_Result *r = &msg->r.AddResponse;
360 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
361 ldap_encode_response(&data, r);
362 asn1_pop_tag(&data);
363 break;
365 case LDAP_TAG_DelRequest: {
366 struct ldap_DelRequest *r = &msg->r.DelRequest;
367 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
368 asn1_write(&data, r->dn, strlen(r->dn));
369 asn1_pop_tag(&data);
370 break;
372 case LDAP_TAG_DelResponse: {
373 struct ldap_Result *r = &msg->r.DelResponse;
374 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
375 ldap_encode_response(&data, r);
376 asn1_pop_tag(&data);
377 break;
379 case LDAP_TAG_ModifyDNRequest: {
380 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
381 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
382 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
383 asn1_write_OctetString(&data, r->newrdn, strlen(r->newrdn));
384 asn1_write_BOOLEAN(&data, r->deleteolddn);
385 if (r->newsuperior != NULL) {
386 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
387 asn1_write(&data, r->newsuperior,
388 strlen(r->newsuperior));
389 asn1_pop_tag(&data);
391 asn1_pop_tag(&data);
392 break;
394 case LDAP_TAG_ModifyDNResponse: {
395 struct ldap_Result *r = &msg->r.ModifyDNResponse;
396 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
397 ldap_encode_response(&data, r);
398 asn1_pop_tag(&data);
399 break;
401 case LDAP_TAG_CompareRequest: {
402 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
403 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
404 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
405 asn1_push_tag(&data, ASN1_SEQUENCE(0));
406 asn1_write_OctetString(&data, r->attribute,
407 strlen(r->attribute));
408 asn1_write_OctetString(&data, r->value.data,
409 r->value.length);
410 asn1_pop_tag(&data);
411 asn1_pop_tag(&data);
412 break;
414 case LDAP_TAG_CompareResponse: {
415 struct ldap_Result *r = &msg->r.ModifyDNResponse;
416 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
417 ldap_encode_response(&data, r);
418 asn1_pop_tag(&data);
419 break;
421 case LDAP_TAG_AbandonRequest: {
422 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
423 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
424 asn1_write_implicit_Integer(&data, r->messageid);
425 asn1_pop_tag(&data);
426 break;
428 case LDAP_TAG_SearchResultReference: {
429 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
430 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
431 asn1_write_OctetString(&data, r->referral, strlen(r->referral));
432 asn1_pop_tag(&data);
433 break;
435 case LDAP_TAG_ExtendedRequest: {
436 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
437 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
438 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
439 asn1_write(&data, r->oid, strlen(r->oid));
440 asn1_pop_tag(&data);
441 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(1));
442 asn1_write(&data, r->value.data, r->value.length);
443 asn1_pop_tag(&data);
444 asn1_pop_tag(&data);
445 break;
447 case LDAP_TAG_ExtendedResponse: {
448 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
449 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
450 ldap_encode_response(&data, &r->response);
451 asn1_pop_tag(&data);
452 break;
454 default:
455 return False;
458 if (msg->controls != NULL) {
459 asn1_push_tag(&data, ASN1_CONTEXT(0));
461 for (i = 0; msg->controls[i] != NULL; i++) {
462 if (!ldap_encode_control(mem_ctx, &data, msg->controls[i])) {
463 return False;
467 asn1_pop_tag(&data);
470 asn1_pop_tag(&data);
472 if (data.has_error) {
473 asn1_free(&data);
474 return False;
477 *result = data_blob_talloc(mem_ctx, data.data, data.length);
478 asn1_free(&data);
479 return True;
482 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
483 DATA_BLOB blob)
485 char *result = talloc_size(mem_ctx, blob.length+1);
486 memcpy(result, blob.data, blob.length);
487 result[blob.length] = '\0';
488 return result;
491 static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
492 struct asn1_data *data,
493 const char **result)
495 DATA_BLOB string;
496 if (!asn1_read_OctetString(data, &string))
497 return False;
498 *result = blob2string_talloc(mem_ctx, string);
499 data_blob_free(&string);
500 return True;
503 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
504 struct asn1_data *data,
505 struct ldap_Result *result)
507 asn1_read_enumerated(data, &result->resultcode);
508 asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
509 asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
510 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
511 asn1_start_tag(data, ASN1_CONTEXT(3));
512 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
513 asn1_end_tag(data);
514 } else {
515 result->referral = NULL;
519 static struct ldb_val **ldap_decode_substring(TALLOC_CTX *mem_ctx, struct ldb_val **chunks, int chunk_num, char *value)
522 chunks = talloc_realloc(mem_ctx, chunks, struct ldb_val *, chunk_num + 2);
523 if (chunks == NULL) {
524 return NULL;
527 chunks[chunk_num] = talloc(mem_ctx, struct ldb_val);
528 if (chunks[chunk_num] == NULL) {
529 return NULL;
532 chunks[chunk_num]->data = (uint8_t *)talloc_strdup(mem_ctx, value);
533 if (chunks[chunk_num]->data == NULL) {
534 return NULL;
536 chunks[chunk_num]->length = strlen(value) + 1;
538 chunks[chunk_num + 1] = NULL;
540 return chunks;
545 parse the ASN.1 formatted search string into a ldb_parse_tree
547 static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
548 struct asn1_data *data)
550 uint8_t filter_tag;
551 struct ldb_parse_tree *ret;
553 if (!asn1_peek_uint8(data, &filter_tag)) {
554 return NULL;
557 filter_tag &= 0x1f; /* strip off the asn1 stuff */
559 ret = talloc(mem_ctx, struct ldb_parse_tree);
560 if (ret == NULL) return NULL;
562 switch(filter_tag) {
563 case 0:
564 case 1:
565 /* AND or OR of one or more filters */
566 ret->operation = (filter_tag == 0)?LDB_OP_AND:LDB_OP_OR;
567 ret->u.list.num_elements = 0;
568 ret->u.list.elements = NULL;
570 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
571 goto failed;
574 while (asn1_tag_remaining(data) > 0) {
575 struct ldb_parse_tree *subtree;
576 subtree = ldap_decode_filter_tree(ret, data);
577 if (subtree == NULL) {
578 goto failed;
580 ret->u.list.elements =
581 talloc_realloc(ret, ret->u.list.elements,
582 struct ldb_parse_tree *,
583 ret->u.list.num_elements+1);
584 if (ret->u.list.elements == NULL) {
585 goto failed;
587 talloc_steal(ret->u.list.elements, subtree);
588 ret->u.list.elements[ret->u.list.num_elements] = subtree;
589 ret->u.list.num_elements++;
591 if (!asn1_end_tag(data)) {
592 goto failed;
594 break;
596 case 2:
597 /* 'not' operation */
598 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
599 goto failed;
602 ret->operation = LDB_OP_NOT;
603 ret->u.isnot.child = ldap_decode_filter_tree(ret, data);
604 if (ret->u.isnot.child == NULL) {
605 goto failed;
607 if (!asn1_end_tag(data)) {
608 goto failed;
610 break;
612 case 3: {
613 /* equalityMatch */
614 const char *attrib;
615 DATA_BLOB value;
617 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
618 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
619 asn1_read_OctetString(data, &value);
620 asn1_end_tag(data);
621 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
622 goto failed;
625 ret->operation = LDB_OP_EQUALITY;
626 ret->u.equality.attr = talloc_steal(ret, attrib);
627 ret->u.equality.value.data = talloc_steal(ret, value.data);
628 ret->u.equality.value.length = value.length;
629 break;
631 case 4: {
632 /* substrings */
633 DATA_BLOB attr;
634 uint8_t subs_tag;
635 char *value;
636 int chunk_num = 0;
638 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
639 goto failed;
641 if (!asn1_read_OctetString(data, &attr)) {
642 goto failed;
645 ret->operation = LDB_OP_SUBSTRING;
646 ret->u.substring.attr = talloc_strndup(ret, (char *)attr.data, attr.length);
647 ret->u.substring.chunks = NULL;
648 ret->u.substring.start_with_wildcard = 1;
649 ret->u.substring.end_with_wildcard = 1;
651 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
652 goto failed;
655 while (asn1_tag_remaining(data)) {
656 asn1_peek_uint8(data, &subs_tag);
657 subs_tag &= 0x1f; /* strip off the asn1 stuff */
658 if (subs_tag > 2) goto failed;
660 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(subs_tag));
661 asn1_read_LDAPString(data, &value);
662 asn1_end_tag(data);
664 switch (subs_tag) {
665 case 0:
666 if (ret->u.substring.chunks != NULL) {
667 /* initial value found in the middle */
668 goto failed;
671 ret->u.substring.chunks = ldap_decode_substring(ret, NULL, 0, value);
672 if (ret->u.substring.chunks == NULL) {
673 goto failed;
676 ret->u.substring.start_with_wildcard = 0;
677 chunk_num = 1;
678 break;
680 case 1:
681 if (ret->u.substring.end_with_wildcard == 0) {
682 /* "any" value found after a "final" value */
683 goto failed;
686 ret->u.substring.chunks = ldap_decode_substring(ret,
687 ret->u.substring.chunks,
688 chunk_num,
689 value);
690 if (ret->u.substring.chunks == NULL) {
691 goto failed;
694 chunk_num++;
695 break;
697 case 2:
698 ret->u.substring.chunks = ldap_decode_substring(ret,
699 ret->u.substring.chunks,
700 chunk_num,
701 value);
702 if (ret->u.substring.chunks == NULL) {
703 goto failed;
706 ret->u.substring.end_with_wildcard = 0;
707 break;
709 default:
710 goto failed;
715 if (!asn1_end_tag(data)) { /* SEQUENCE */
716 goto failed;
719 if (!asn1_end_tag(data)) {
720 goto failed;
722 break;
724 case 5: {
725 /* greaterOrEqual */
726 const char *attrib;
727 DATA_BLOB value;
729 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
730 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
731 asn1_read_OctetString(data, &value);
732 asn1_end_tag(data);
733 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
734 goto failed;
737 ret->operation = LDB_OP_GREATER;
738 ret->u.comparison.attr = talloc_steal(ret, attrib);
739 ret->u.comparison.value.data = talloc_steal(ret, value.data);
740 ret->u.comparison.value.length = value.length;
741 break;
743 case 6: {
744 /* lessOrEqual */
745 const char *attrib;
746 DATA_BLOB value;
748 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
749 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
750 asn1_read_OctetString(data, &value);
751 asn1_end_tag(data);
752 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
753 goto failed;
756 ret->operation = LDB_OP_LESS;
757 ret->u.comparison.attr = talloc_steal(ret, attrib);
758 ret->u.comparison.value.data = talloc_steal(ret, value.data);
759 ret->u.comparison.value.length = value.length;
760 break;
762 case 7: {
763 /* Normal presence, "attribute=*" */
764 char *attr;
766 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(filter_tag))) {
767 goto failed;
769 if (!asn1_read_LDAPString(data, &attr)) {
770 goto failed;
773 ret->operation = LDB_OP_PRESENT;
774 ret->u.present.attr = talloc_steal(ret, attr);
776 if (!asn1_end_tag(data)) {
777 goto failed;
779 break;
781 case 8: {
782 /* approx */
783 const char *attrib;
784 DATA_BLOB value;
786 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
787 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
788 asn1_read_OctetString(data, &value);
789 asn1_end_tag(data);
790 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
791 goto failed;
794 ret->operation = LDB_OP_APPROX;
795 ret->u.comparison.attr = talloc_steal(ret, attrib);
796 ret->u.comparison.value.data = talloc_steal(ret, value.data);
797 ret->u.comparison.value.length = value.length;
798 break;
800 case 9: {
801 char *oid = NULL, *attr = NULL, *value;
802 uint8_t dnAttributes;
803 /* an extended search */
804 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
805 goto failed;
808 /* FIXME: read carefully rfc2251.txt there are a number of 'MUST's
809 we need to check we properly implement --SSS */
810 /* either oid or type must be defined */
811 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) { /* optional */
812 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(1));
813 asn1_read_LDAPString(data, &oid);
814 asn1_end_tag(data);
816 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(2))) { /* optional */
817 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(2));
818 asn1_read_LDAPString(data, &attr);
819 asn1_end_tag(data);
821 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(3));
822 asn1_read_LDAPString(data, &value);
823 asn1_end_tag(data);
824 /* dnAttributes is marked as BOOLEAN DEFAULT FALSE
825 it is not marked as OPTIONAL but openldap tools
826 do not set this unless it is to be set as TRUE
827 NOTE: openldap tools do not work with AD as it
828 seems that AD always requires the dnAttributes
829 boolean value to be set */
830 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(4))) {
831 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(4));
832 asn1_read_uint8(data, &dnAttributes);
833 asn1_end_tag(data);
834 } else {
835 dnAttributes = 0;
837 if ((oid == NULL && attr == NULL) || (value == NULL)) {
838 goto failed;
841 if (oid) {
842 ret->operation = LDB_OP_EXTENDED;
844 /* From the RFC2251: If the type field is
845 absent and matchingRule is present, the matchValue is compared
846 against all attributes in an entry which support that matchingRule
848 if (attr) {
849 ret->u.extended.attr = talloc_steal(ret, attr);
850 } else {
851 ret->u.extended.attr = talloc_strdup(ret, "*");
853 ret->u.extended.rule_id = talloc_steal(ret, oid);
854 ret->u.extended.value.data = talloc_steal(ret, value);
855 ret->u.extended.value.length = strlen(value);
856 ret->u.extended.dnAttributes = dnAttributes;
857 } else {
858 ret->operation = LDB_OP_EQUALITY;
859 ret->u.equality.attr = talloc_steal(ret, attr);
860 ret->u.equality.value.data = talloc_steal(ret, value);
861 ret->u.equality.value.length = strlen(value);
863 if (!asn1_end_tag(data)) {
864 goto failed;
866 break;
869 default:
870 DEBUG(0,("Unsupported LDAP filter operation 0x%x\n", filter_tag));
871 goto failed;
874 return ret;
876 failed:
877 talloc_free(ret);
878 return NULL;
882 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
883 struct ldb_message_element *attrib)
885 asn1_start_tag(data, ASN1_SEQUENCE(0));
886 asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
887 asn1_start_tag(data, ASN1_SET);
888 while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
889 DATA_BLOB blob;
890 asn1_read_OctetString(data, &blob);
891 add_value_to_attrib(mem_ctx, &blob, attrib);
893 asn1_end_tag(data);
894 asn1_end_tag(data);
898 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
899 struct ldb_message_element **attributes,
900 int *num_attributes)
902 asn1_start_tag(data, ASN1_SEQUENCE(0));
903 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
904 struct ldb_message_element attrib;
905 ZERO_STRUCT(attrib);
906 ldap_decode_attrib(mem_ctx, data, &attrib);
907 add_attrib_to_array_talloc(mem_ctx, &attrib,
908 attributes, num_attributes);
910 asn1_end_tag(data);
913 BOOL ldap_decode(struct asn1_data *data, struct ldap_message *msg)
915 uint8_t tag;
917 asn1_start_tag(data, ASN1_SEQUENCE(0));
918 asn1_read_Integer(data, &msg->messageid);
920 if (!asn1_peek_uint8(data, &tag))
921 return False;
923 switch(tag) {
925 case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
926 struct ldap_BindRequest *r = &msg->r.BindRequest;
927 msg->type = LDAP_TAG_BindRequest;
928 asn1_start_tag(data, tag);
929 asn1_read_Integer(data, &r->version);
930 asn1_read_OctetString_talloc(msg, data, &r->dn);
931 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
932 int pwlen;
933 r->creds.password = "";
934 r->mechanism = LDAP_AUTH_MECH_SIMPLE;
935 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
936 pwlen = asn1_tag_remaining(data);
937 if (pwlen != 0) {
938 char *pw = talloc_size(msg, pwlen+1);
939 asn1_read(data, pw, pwlen);
940 pw[pwlen] = '\0';
941 r->creds.password = pw;
943 asn1_end_tag(data);
944 } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
945 asn1_start_tag(data, ASN1_CONTEXT(3));
946 r->mechanism = LDAP_AUTH_MECH_SASL;
947 asn1_read_OctetString_talloc(msg, data, &r->creds.SASL.mechanism);
948 if (asn1_peek_tag(data, ASN1_OCTET_STRING)) { /* optional */
949 asn1_read_OctetString(data, &r->creds.SASL.secblob);
950 if (r->creds.SASL.secblob.data) {
951 talloc_steal(msg, r->creds.SASL.secblob.data);
953 } else {
954 r->creds.SASL.secblob = data_blob(NULL, 0);
956 asn1_end_tag(data);
958 asn1_end_tag(data);
959 break;
962 case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
963 struct ldap_BindResponse *r = &msg->r.BindResponse;
964 msg->type = LDAP_TAG_BindResponse;
965 asn1_start_tag(data, tag);
966 ldap_decode_response(msg, data, &r->response);
967 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
968 DATA_BLOB tmp_blob = data_blob(NULL, 0);
969 asn1_read_ContextSimple(data, 7, &tmp_blob);
970 r->SASL.secblob = data_blob_talloc(msg, tmp_blob.data, tmp_blob.length);
971 data_blob_free(&tmp_blob);
972 } else {
973 r->SASL.secblob = data_blob(NULL, 0);
975 asn1_end_tag(data);
976 break;
979 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
980 msg->type = LDAP_TAG_UnbindRequest;
981 asn1_start_tag(data, tag);
982 asn1_end_tag(data);
983 break;
986 case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
987 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
988 msg->type = LDAP_TAG_SearchRequest;
989 asn1_start_tag(data, tag);
990 asn1_read_OctetString_talloc(msg, data, &r->basedn);
991 asn1_read_enumerated(data, (int *)&(r->scope));
992 asn1_read_enumerated(data, (int *)&(r->deref));
993 asn1_read_Integer(data, &r->sizelimit);
994 asn1_read_Integer(data, &r->timelimit);
995 asn1_read_BOOLEAN(data, &r->attributesonly);
997 r->tree = ldap_decode_filter_tree(msg, data);
998 if (r->tree == NULL) {
999 return False;
1002 asn1_start_tag(data, ASN1_SEQUENCE(0));
1004 r->num_attributes = 0;
1005 r->attributes = NULL;
1007 while (asn1_tag_remaining(data) > 0) {
1008 const char *attr;
1009 if (!asn1_read_OctetString_talloc(msg, data,
1010 &attr))
1011 return False;
1012 if (!add_string_to_array(msg, attr,
1013 &r->attributes,
1014 &r->num_attributes))
1015 return False;
1018 asn1_end_tag(data);
1019 asn1_end_tag(data);
1020 break;
1023 case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
1024 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
1025 msg->type = LDAP_TAG_SearchResultEntry;
1026 r->attributes = NULL;
1027 r->num_attributes = 0;
1028 asn1_start_tag(data, tag);
1029 asn1_read_OctetString_talloc(msg, data, &r->dn);
1030 ldap_decode_attribs(msg, data, &r->attributes,
1031 &r->num_attributes);
1032 asn1_end_tag(data);
1033 break;
1036 case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
1037 struct ldap_Result *r = &msg->r.SearchResultDone;
1038 msg->type = LDAP_TAG_SearchResultDone;
1039 asn1_start_tag(data, tag);
1040 ldap_decode_response(msg, data, r);
1041 asn1_end_tag(data);
1042 break;
1045 case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
1046 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
1047 msg->type = LDAP_TAG_SearchResultReference;
1048 asn1_start_tag(data, tag);
1049 asn1_read_OctetString_talloc(msg, data, &r->referral);
1050 asn1_end_tag(data);
1051 break;
1054 case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
1055 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
1056 msg->type = LDAP_TAG_ModifyRequest;
1057 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
1058 asn1_read_OctetString_talloc(msg, data, &r->dn);
1059 asn1_start_tag(data, ASN1_SEQUENCE(0));
1061 r->num_mods = 0;
1062 r->mods = NULL;
1064 while (asn1_tag_remaining(data) > 0) {
1065 struct ldap_mod mod;
1066 int v;
1067 ZERO_STRUCT(mod);
1068 asn1_start_tag(data, ASN1_SEQUENCE(0));
1069 asn1_read_enumerated(data, &v);
1070 mod.type = v;
1071 ldap_decode_attrib(msg, data, &mod.attrib);
1072 asn1_end_tag(data);
1073 if (!add_mod_to_array_talloc(msg, &mod,
1074 &r->mods, &r->num_mods))
1075 break;
1078 asn1_end_tag(data);
1079 asn1_end_tag(data);
1080 break;
1083 case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
1084 struct ldap_Result *r = &msg->r.ModifyResponse;
1085 msg->type = LDAP_TAG_ModifyResponse;
1086 asn1_start_tag(data, tag);
1087 ldap_decode_response(msg, data, r);
1088 asn1_end_tag(data);
1089 break;
1092 case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
1093 struct ldap_AddRequest *r = &msg->r.AddRequest;
1094 msg->type = LDAP_TAG_AddRequest;
1095 asn1_start_tag(data, tag);
1096 asn1_read_OctetString_talloc(msg, data, &r->dn);
1098 r->attributes = NULL;
1099 r->num_attributes = 0;
1100 ldap_decode_attribs(msg, data, &r->attributes,
1101 &r->num_attributes);
1103 asn1_end_tag(data);
1104 break;
1107 case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1108 struct ldap_Result *r = &msg->r.AddResponse;
1109 msg->type = LDAP_TAG_AddResponse;
1110 asn1_start_tag(data, tag);
1111 ldap_decode_response(msg, data, r);
1112 asn1_end_tag(data);
1113 break;
1116 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1117 struct ldap_DelRequest *r = &msg->r.DelRequest;
1118 int len;
1119 char *dn;
1120 msg->type = LDAP_TAG_DelRequest;
1121 asn1_start_tag(data,
1122 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1123 len = asn1_tag_remaining(data);
1124 dn = talloc_size(msg, len+1);
1125 if (dn == NULL)
1126 break;
1127 asn1_read(data, dn, len);
1128 dn[len] = '\0';
1129 r->dn = dn;
1130 asn1_end_tag(data);
1131 break;
1134 case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1135 struct ldap_Result *r = &msg->r.DelResponse;
1136 msg->type = LDAP_TAG_DelResponse;
1137 asn1_start_tag(data, tag);
1138 ldap_decode_response(msg, data, r);
1139 asn1_end_tag(data);
1140 break;
1143 case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1144 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
1145 msg->type = LDAP_TAG_ModifyDNRequest;
1146 asn1_start_tag(data,
1147 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
1148 asn1_read_OctetString_talloc(msg, data, &r->dn);
1149 asn1_read_OctetString_talloc(msg, data, &r->newrdn);
1150 asn1_read_BOOLEAN(data, &r->deleteolddn);
1151 r->newsuperior = NULL;
1152 if (asn1_tag_remaining(data) > 0) {
1153 int len;
1154 char *newsup;
1155 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1156 len = asn1_tag_remaining(data);
1157 newsup = talloc_size(msg, len+1);
1158 if (newsup == NULL)
1159 break;
1160 asn1_read(data, newsup, len);
1161 newsup[len] = '\0';
1162 r->newsuperior = newsup;
1163 asn1_end_tag(data);
1165 asn1_end_tag(data);
1166 break;
1169 case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1170 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1171 msg->type = LDAP_TAG_ModifyDNResponse;
1172 asn1_start_tag(data, tag);
1173 ldap_decode_response(msg, data, r);
1174 asn1_end_tag(data);
1175 break;
1178 case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1179 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
1180 msg->type = LDAP_TAG_CompareRequest;
1181 asn1_start_tag(data,
1182 ASN1_APPLICATION(LDAP_TAG_CompareRequest));
1183 asn1_read_OctetString_talloc(msg, data, &r->dn);
1184 asn1_start_tag(data, ASN1_SEQUENCE(0));
1185 asn1_read_OctetString_talloc(msg, data, &r->attribute);
1186 asn1_read_OctetString(data, &r->value);
1187 if (r->value.data) {
1188 talloc_steal(msg, r->value.data);
1190 asn1_end_tag(data);
1191 asn1_end_tag(data);
1192 break;
1195 case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1196 struct ldap_Result *r = &msg->r.CompareResponse;
1197 msg->type = LDAP_TAG_CompareResponse;
1198 asn1_start_tag(data, tag);
1199 ldap_decode_response(msg, data, r);
1200 asn1_end_tag(data);
1201 break;
1204 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
1205 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
1206 msg->type = LDAP_TAG_AbandonRequest;
1207 asn1_start_tag(data, tag);
1208 asn1_read_implicit_Integer(data, &r->messageid);
1209 asn1_end_tag(data);
1210 break;
1213 case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1214 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1215 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1217 msg->type = LDAP_TAG_ExtendedRequest;
1218 asn1_start_tag(data,tag);
1219 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
1220 return False;
1222 r->oid = blob2string_talloc(msg, tmp_blob);
1223 data_blob_free(&tmp_blob);
1224 if (!r->oid) {
1225 return False;
1228 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
1229 asn1_read_ContextSimple(data, 1, &tmp_blob);
1230 r->value = data_blob_talloc(msg, tmp_blob.data, tmp_blob.length);
1231 data_blob_free(&tmp_blob);
1232 } else {
1233 r->value = data_blob(NULL, 0);
1236 asn1_end_tag(data);
1237 break;
1240 case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1241 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1242 msg->type = LDAP_TAG_ExtendedResponse;
1243 asn1_start_tag(data, tag);
1244 ldap_decode_response(msg, data, &r->response);
1245 /* I have to come across an operation that actually sends
1246 * something back to really see what's going on. The currently
1247 * needed pwdchange does not send anything back. */
1248 r->name = NULL;
1249 r->value.data = NULL;
1250 r->value.length = 0;
1251 asn1_end_tag(data);
1252 break;
1254 default:
1255 return False;
1258 msg->controls = NULL;
1260 if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
1261 int i;
1262 struct ldap_Control **ctrl = NULL;
1264 asn1_start_tag(data, ASN1_CONTEXT(0));
1266 for (i=0; asn1_peek_tag(data, ASN1_SEQUENCE(0)); i++) {
1267 /* asn1_start_tag(data, ASN1_SEQUENCE(0)); */
1269 ctrl = talloc_realloc(msg, ctrl, struct ldap_Control *, i+2);
1270 if (!ctrl) {
1271 return False;
1274 ctrl[i] = talloc(ctrl, struct ldap_Control);
1275 if (!ctrl[i]) {
1276 return False;
1279 if (!ldap_decode_control(ctrl, data, ctrl[i])) {
1280 return False;
1285 ctrl[i] = NULL;
1287 msg->controls = ctrl;
1289 asn1_end_tag(data);
1292 asn1_end_tag(data);
1293 return ((!data->has_error) && (data->nesting == NULL));
1298 return NT_STATUS_OK if a blob has enough bytes in it to be a full
1299 ldap packet. Set packet_size if true.
1301 NTSTATUS ldap_full_packet(void *private, DATA_BLOB blob, size_t *packet_size)
1303 return asn1_full_tag(blob, ASN1_SEQUENCE(0), packet_size);