r8917: Better support for extended ldap search operations
[samba.git] / source4 / libcli / ldap / ldap.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    
5    Copyright (C) Andrew Tridgell  2004
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Stefan Metzmacher 2004
8    Copyright (C) Simo Sorce 2004
9     
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.
14    
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.
19    
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.
23    
24 */
25
26 #include "includes.h"
27 #include "system/iconv.h"
28 #include "asn_1.h"
29 #include "libcli/ldap/ldap.h"
30
31
32 static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
33 {
34         int i;
35
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;
43                         }
44                 }
45                 asn1_pop_tag(data);
46                 break;
47
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;
52                 }
53                 asn1_pop_tag(data);
54                 break;
55
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;
65
66         case LDB_OP_SUBSTRING:
67                 /*
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 } }
75                 */
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, tree->u.substring.chunks[i]->data);
83                         asn1_pop_tag(data);
84                         i++;
85                 }
86                 while (tree->u.substring.chunks[i]) {
87                         int ctx;
88
89                         if (( ! tree->u.substring.chunks[i + 1]) &&
90                             (tree->u.substring.end_with_wildcard == 0)) {
91                                 ctx = 2;
92                         } else {
93                                 ctx = 1;
94                         }
95                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(ctx));
96                         asn1_write_LDAPString(data, tree->u.substring.chunks[i]->data);
97                         asn1_pop_tag(data);
98                         i++;
99                 }
100                 asn1_pop_tag(data);
101                 asn1_pop_tag(data);
102                 break;
103
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;
113
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;
123
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;
130
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;
140
141         case LDB_OP_EXTENDED:
142                 /*
143                   MatchingRuleAssertion ::= SEQUENCE {
144                   matchingRule    [1] MatchingRuleID OPTIONAL,
145                   type            [2] AttributeDescription OPTIONAL,
146                   matchValue      [3] AssertionValue,
147                   dnAttributes    [4] BOOLEAN DEFAULT FALSE
148                   }
149                 */
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);
155                 }
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);
160                 }
161                 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3));
162                 asn1_write_LDAPString(data, 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;
169
170         default:
171                 return False;
172         }
173         return !data->has_error;
174 }
175
176 static void ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
177 {
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);
189         }
190 }
191
192 BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result)
193 {
194         struct asn1_data data;
195         int i, j;
196
197         ZERO_STRUCT(data);
198         asn1_push_tag(&data, ASN1_SEQUENCE(0));
199         asn1_write_Integer(&data, msg->messageid);
200
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);
208
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;
228                 }
229
230                 asn1_pop_tag(&data);
231                 break;
232         }
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;
240         }
241         case LDAP_TAG_UnbindRequest: {
242 /*              struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
243                 break;
244         }
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);
254
255                 if (!ldap_push_filter(&data, r->tree)) {
256                         return False;
257                 }
258
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]));
263                 }
264                 asn1_pop_tag(&data);
265                 asn1_pop_tag(&data);
266                 break;
267         }
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);
283                         }
284                         asn1_pop_tag(&data);
285                         asn1_pop_tag(&data);
286                 }
287                 asn1_pop_tag(&data);
288                 asn1_pop_tag(&data);
289                 break;
290         }
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;
297         }
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));
303
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);
316         
317                         }
318                         asn1_pop_tag(&data);
319                         asn1_pop_tag(&data);
320                         asn1_pop_tag(&data);
321                 }
322                 
323                 asn1_pop_tag(&data);
324                 asn1_pop_tag(&data);
325                 break;
326         }
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;
333         }
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));
339
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);
350                         }
351                         asn1_pop_tag(&data);
352                         asn1_pop_tag(&data);
353                 }
354                 asn1_pop_tag(&data);
355                 asn1_pop_tag(&data);
356                 break;
357         }
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;
364         }
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;
371         }
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;
378         }
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);
390                 }
391                 asn1_pop_tag(&data);
392                 break;
393         }
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;
400         }
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;
413         }
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;
420         }
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;
427         }
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;
434         }
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;
446         }
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;
453         }
454         default:
455                 return False;
456         }
457
458         asn1_pop_tag(&data);
459
460         if (data.has_error) {
461                 asn1_free(&data);
462                 return False;
463         }
464
465         *result = data_blob(data.data, data.length);
466         asn1_free(&data);
467         return True;
468 }
469
470 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
471                                       DATA_BLOB blob)
472 {
473         char *result = talloc_size(mem_ctx, blob.length+1);
474         memcpy(result, blob.data, blob.length);
475         result[blob.length] = '\0';
476         return result;
477 }
478
479 static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
480                                          struct asn1_data *data,
481                                          const char **result)
482 {
483         DATA_BLOB string;
484         if (!asn1_read_OctetString(data, &string))
485                 return False;
486         *result = blob2string_talloc(mem_ctx, string);
487         data_blob_free(&string);
488         return True;
489 }
490
491 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
492                                  struct asn1_data *data,
493                                  struct ldap_Result *result)
494 {
495         asn1_read_enumerated(data, &result->resultcode);
496         asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
497         asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
498         if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
499                 asn1_start_tag(data, ASN1_CONTEXT(3));
500                 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
501                 asn1_end_tag(data);
502         } else {
503                 result->referral = NULL;
504         }
505 }
506
507 static struct ldb_val **ldap_decode_substring(TALLOC_CTX *mem_ctx, struct ldb_val **chunks, int chunk_num, char *value)
508 {
509
510         chunks = talloc_realloc(mem_ctx, chunks, struct ldb_val *, chunk_num + 2);
511         if (chunks == NULL) {
512                 return NULL;
513         }
514
515         chunks[chunk_num] = talloc(mem_ctx, struct ldb_val);
516         if (chunks[chunk_num] == NULL) {
517                 return NULL;
518         }
519
520         chunks[chunk_num]->data = talloc_strdup(mem_ctx, value);
521         if (chunks[chunk_num]->data == NULL) {
522                 return NULL;
523         }
524         chunks[chunk_num]->length = strlen(value) + 1;
525
526         chunks[chunk_num + 1] = NULL;
527
528         return chunks;
529 }
530
531
532 /*
533   parse the ASN.1 formatted search string into a ldb_parse_tree
534 */
535 static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx, 
536                                                       struct asn1_data *data)
537 {
538         uint8_t filter_tag;
539         struct ldb_parse_tree *ret;
540
541         if (!asn1_peek_uint8(data, &filter_tag)) {
542                 return NULL;
543         }
544
545         filter_tag &= 0x1f;     /* strip off the asn1 stuff */
546
547         ret = talloc(mem_ctx, struct ldb_parse_tree);
548         if (ret == NULL) return NULL;
549
550         switch(filter_tag) {
551         case 0:
552         case 1:
553                 /* AND or OR of one or more filters */
554                 ret->operation = (filter_tag == 0)?LDB_OP_AND:LDB_OP_OR;
555                 ret->u.list.num_elements = 0;
556                 ret->u.list.elements = NULL;
557
558                 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
559                         goto failed;
560                 }
561
562                 while (asn1_tag_remaining(data) > 0) {
563                         struct ldb_parse_tree *subtree;
564                         subtree = ldap_decode_filter_tree(ret, data);
565                         if (subtree == NULL) {
566                                 goto failed;
567                         }
568                         ret->u.list.elements = 
569                                 talloc_realloc(ret, ret->u.list.elements, 
570                                                struct ldb_parse_tree *, 
571                                                ret->u.list.num_elements+1);
572                         if (ret->u.list.elements == NULL) {
573                                 goto failed;
574                         }
575                         talloc_steal(ret->u.list.elements, subtree);
576                         ret->u.list.elements[ret->u.list.num_elements] = subtree;
577                         ret->u.list.num_elements++;
578                 }
579                 if (!asn1_end_tag(data)) {
580                         goto failed;
581                 }
582                 break;
583
584         case 2:
585                 /* 'not' operation */
586                 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
587                         goto failed;
588                 }
589
590                 ret->operation = LDB_OP_NOT;
591                 ret->u.isnot.child = ldap_decode_filter_tree(ret, data);
592                 if (ret->u.isnot.child == NULL) {
593                         goto failed;
594                 }
595                 if (!asn1_end_tag(data)) {
596                         goto failed;
597                 }
598                 break;
599
600         case 3: {
601                 /* equalityMatch */
602                 const char *attrib;
603                 DATA_BLOB value;
604
605                 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
606                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
607                 asn1_read_OctetString(data, &value);
608                 asn1_end_tag(data);
609                 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
610                         goto failed;
611                 }
612
613                 ret->operation = LDB_OP_EQUALITY;
614                 ret->u.equality.attr = talloc_steal(ret, attrib);
615                 ret->u.equality.value.data = talloc_steal(ret, value.data);
616                 ret->u.equality.value.length = value.length;
617                 break;
618         }
619         case 4: {
620                 /* substrings */
621                 DATA_BLOB attr;
622                 uint8_t subs_tag;
623                 char *value;
624                 int chunk_num = 0;
625
626                 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
627                         goto failed;
628                 }
629                 if (!asn1_read_OctetString(data, &attr)) {
630                         goto failed;
631                 }
632
633                 ret->operation = LDB_OP_SUBSTRING;
634                 ret->u.substring.attr = talloc_memdup(ret, attr.data, attr.length + 1);
635                 ret->u.substring.attr[attr.length] = '\0';
636                 ret->u.substring.chunks = NULL;
637                 ret->u.substring.start_with_wildcard = 1;
638                 ret->u.substring.end_with_wildcard = 1;
639
640                 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
641                         goto failed;
642                 }
643
644                 while (asn1_tag_remaining(data)) {
645                         asn1_peek_uint8(data, &subs_tag);
646                         subs_tag &= 0x1f;       /* strip off the asn1 stuff */
647                         if (subs_tag > 2) goto failed;
648
649                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(subs_tag));
650                         asn1_read_LDAPString(data, &value);
651                         asn1_end_tag(data);
652
653                         switch (subs_tag) {
654                         case 0:
655                                 if (ret->u.substring.chunks != NULL) {
656                                         /* initial value found in the middle */
657                                         goto failed;
658                                 }
659
660                                 ret->u.substring.chunks = ldap_decode_substring(ret, NULL, 0, value);
661                                 if (ret->u.substring.chunks == NULL) {
662                                         goto failed;
663                                 }
664
665                                 ret->u.substring.start_with_wildcard = 0;
666                                 chunk_num = 1;
667                                 break;
668
669                         case 1:
670                                 if (ret->u.substring.end_with_wildcard == 0) {
671                                         /* "any" value found after a "final" value */
672                                         goto failed;
673                                 }
674
675                                 ret->u.substring.chunks = ldap_decode_substring(ret,
676                                                                                 ret->u.substring.chunks,
677                                                                                 chunk_num,
678                                                                                 value);
679                                 if (ret->u.substring.chunks == NULL) {
680                                         goto failed;
681                                 }
682
683                                 chunk_num++;
684                                 break;
685
686                         case 2:
687                                 ret->u.substring.chunks = ldap_decode_substring(ret,
688                                                                                 ret->u.substring.chunks,
689                                                                                 chunk_num,
690                                                                                 value);
691                                 if (ret->u.substring.chunks == NULL) {
692                                         goto failed;
693                                 }
694
695                                 ret->u.substring.end_with_wildcard = 0;
696                                 break;
697
698                         default:
699                                 goto failed;
700                         }
701
702                 }
703
704                 if (!asn1_end_tag(data)) { /* SEQUENCE */
705                         goto failed;
706                 }
707
708                 if (!asn1_end_tag(data)) {
709                         goto failed;
710                 }
711                 break;
712         }
713         case 5: {
714                 /* greaterOrEqual */
715                 const char *attrib;
716                 DATA_BLOB value;
717
718                 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
719                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
720                 asn1_read_OctetString(data, &value);
721                 asn1_end_tag(data);
722                 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
723                         goto failed;
724                 }
725
726                 ret->operation = LDB_OP_GREATER;
727                 ret->u.comparison.attr = talloc_steal(ret, attrib);
728                 ret->u.comparison.value.data = talloc_steal(ret, value.data);
729                 ret->u.comparison.value.length = value.length;
730                 break;
731         }
732         case 6: {
733                 /* lessOrEqual */
734                 const char *attrib;
735                 DATA_BLOB value;
736
737                 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
738                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
739                 asn1_read_OctetString(data, &value);
740                 asn1_end_tag(data);
741                 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
742                         goto failed;
743                 }
744
745                 ret->operation = LDB_OP_LESS;
746                 ret->u.comparison.attr = talloc_steal(ret, attrib);
747                 ret->u.comparison.value.data = talloc_steal(ret, value.data);
748                 ret->u.comparison.value.length = value.length;
749                 break;
750         }
751         case 7: {
752                 /* Normal presence, "attribute=*" */
753                 char *attr;
754
755                 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(filter_tag))) {
756                         goto failed;
757                 }
758                 if (!asn1_read_LDAPString(data, &attr)) {
759                         goto failed;
760                 }
761
762                 ret->operation = LDB_OP_PRESENT;
763                 ret->u.present.attr = talloc_steal(ret, attr);
764
765                 if (!asn1_end_tag(data)) {
766                         goto failed;
767                 }
768                 break;
769         }
770         case 8: {
771                 /* approx */
772                 const char *attrib;
773                 DATA_BLOB value;
774
775                 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
776                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
777                 asn1_read_OctetString(data, &value);
778                 asn1_end_tag(data);
779                 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
780                         goto failed;
781                 }
782
783                 ret->operation = LDB_OP_APPROX;
784                 ret->u.comparison.attr = talloc_steal(ret, attrib);
785                 ret->u.comparison.value.data = talloc_steal(ret, value.data);
786                 ret->u.comparison.value.length = value.length;
787                 break;
788         }
789         case 9: {
790                 char *oid = NULL, *attr = NULL, *value;
791                 uint8_t dnAttributes;
792                 /* an extended search */
793                 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
794                         goto failed;
795                 }
796
797                 /* FIXME: read carefully rfc2251.txt there are a number of 'MUST's
798                    we need to check we properly implement --SSS */ 
799                 /* either oid or type must be defined */
800                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) { /* optional */
801                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(1));
802                         asn1_read_LDAPString(data, &oid);
803                         asn1_end_tag(data);
804                 }
805                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(2))) {      /* optional  */
806                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(2));
807                         asn1_read_LDAPString(data, &attr);
808                         asn1_end_tag(data);
809                 }
810                 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(3));
811                 asn1_read_LDAPString(data, &value);
812                 asn1_end_tag(data);
813                 /* dnAttributes is marked as BOOLEAN DEFAULT FALSE
814                    it is not marked as OPTIONAL but openldap tools
815                    do not set this unless it is to be set as TRUE
816                    NOTE: openldap tools do not work with AD as it
817                    seems that AD always requires the dnAttributes
818                    boolean value to be set */
819                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(4))) {
820                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(4));
821                         asn1_read_uint8(data, &dnAttributes);
822                         asn1_end_tag(data);
823                 } else {
824                         dnAttributes = 0;
825                 }
826                 if ((oid == NULL && attr == NULL) || (value == NULL)) {
827                         goto failed;
828                 }
829
830                 if (oid) {
831                         ret->operation               = LDB_OP_EXTENDED;
832
833                         /* From the RFC2251: If the type field is
834                            absent and matchingRule is present, the matchValue is compared
835                            against all attributes in an entry which support that matchingRule
836                         */
837                         if (attr) {
838                                 ret->u.extended.attr = talloc_steal(ret, attr);
839                         } else {
840                                 ret->u.extended.attr = talloc_strdup(ret, "*");
841                         }
842                         ret->u.extended.rule_id      = talloc_steal(ret, oid);
843                         ret->u.extended.value.data   = talloc_steal(ret, value);
844                         ret->u.extended.value.length = strlen(value);
845                         ret->u.extended.dnAttributes = dnAttributes;
846                 } else {
847                         ret->operation               = LDB_OP_EQUALITY;
848                         ret->u.equality.attr         = talloc_steal(ret, attr);
849                         ret->u.equality.value.data   = talloc_steal(ret, value);
850                         ret->u.equality.value.length = strlen(value);
851                 }
852                 if (!asn1_end_tag(data)) {
853                         goto failed;
854                 }
855                 break;
856         }
857
858         default:
859                 DEBUG(0,("Unsupported LDAP filter operation 0x%x\n", filter_tag));
860                 goto failed;
861         }
862         
863         return ret;
864
865 failed:
866         talloc_free(ret);
867         return NULL;    
868 }
869
870
871 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
872                                struct ldb_message_element *attrib)
873 {
874         asn1_start_tag(data, ASN1_SEQUENCE(0));
875         asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
876         asn1_start_tag(data, ASN1_SET);
877         while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
878                 DATA_BLOB blob;
879                 asn1_read_OctetString(data, &blob);
880                 add_value_to_attrib(mem_ctx, &blob, attrib);
881         }
882         asn1_end_tag(data);
883         asn1_end_tag(data);
884         
885 }
886
887 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
888                                 struct ldb_message_element **attributes,
889                                 int *num_attributes)
890 {
891         asn1_start_tag(data, ASN1_SEQUENCE(0));
892         while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
893                 struct ldb_message_element attrib;
894                 ZERO_STRUCT(attrib);
895                 ldap_decode_attrib(mem_ctx, data, &attrib);
896                 add_attrib_to_array_talloc(mem_ctx, &attrib,
897                                            attributes, num_attributes);
898         }
899         asn1_end_tag(data);
900 }
901
902 BOOL ldap_decode(struct asn1_data *data, struct ldap_message *msg)
903 {
904         uint8_t tag;
905
906         asn1_start_tag(data, ASN1_SEQUENCE(0));
907         asn1_read_Integer(data, &msg->messageid);
908
909         if (!asn1_peek_uint8(data, &tag))
910                 return False;
911
912         switch(tag) {
913
914         case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
915                 struct ldap_BindRequest *r = &msg->r.BindRequest;
916                 msg->type = LDAP_TAG_BindRequest;
917                 asn1_start_tag(data, tag);
918                 asn1_read_Integer(data, &r->version);
919                 asn1_read_OctetString_talloc(msg, data, &r->dn);
920                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
921                         int pwlen;
922                         r->creds.password = "";
923                         r->mechanism = LDAP_AUTH_MECH_SIMPLE;
924                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
925                         pwlen = asn1_tag_remaining(data);
926                         if (pwlen != 0) {
927                                 char *pw = talloc_size(msg, pwlen+1);
928                                 asn1_read(data, pw, pwlen);
929                                 pw[pwlen] = '\0';
930                                 r->creds.password = pw;
931                         }
932                         asn1_end_tag(data);
933                 } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
934                         asn1_start_tag(data, ASN1_CONTEXT(3));
935                         r->mechanism = LDAP_AUTH_MECH_SASL;
936                         asn1_read_OctetString_talloc(msg, data, &r->creds.SASL.mechanism);
937                         asn1_read_OctetString(data, &r->creds.SASL.secblob);
938                         if (r->creds.SASL.secblob.data) {
939                                 talloc_steal(msg, r->creds.SASL.secblob.data);
940                         }
941                         asn1_end_tag(data);
942                 }
943                 asn1_end_tag(data);
944                 break;
945         }
946
947         case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
948                 struct ldap_BindResponse *r = &msg->r.BindResponse;
949                 msg->type = LDAP_TAG_BindResponse;
950                 asn1_start_tag(data, tag);
951                 ldap_decode_response(msg, data, &r->response);
952                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
953                         DATA_BLOB tmp_blob = data_blob(NULL, 0);
954                         asn1_read_ContextSimple(data, 7, &tmp_blob);
955                         r->SASL.secblob = data_blob_talloc(msg, tmp_blob.data, tmp_blob.length);
956                         data_blob_free(&tmp_blob);
957                 } else {
958                         r->SASL.secblob = data_blob(NULL, 0);
959                 }
960                 asn1_end_tag(data);
961                 break;
962         }
963
964         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
965                 msg->type = LDAP_TAG_UnbindRequest;
966                 asn1_start_tag(data, tag);
967                 asn1_end_tag(data);
968                 break;
969         }
970
971         case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
972                 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
973                 msg->type = LDAP_TAG_SearchRequest;
974                 asn1_start_tag(data, tag);
975                 asn1_read_OctetString_talloc(msg, data, &r->basedn);
976                 asn1_read_enumerated(data, (int *)&(r->scope));
977                 asn1_read_enumerated(data, (int *)&(r->deref));
978                 asn1_read_Integer(data, &r->sizelimit);
979                 asn1_read_Integer(data, &r->timelimit);
980                 asn1_read_BOOLEAN(data, &r->attributesonly);
981
982                 r->tree = ldap_decode_filter_tree(msg, data);
983                 if (r->tree == NULL) {
984                         return False;
985                 }
986
987                 asn1_start_tag(data, ASN1_SEQUENCE(0));
988
989                 r->num_attributes = 0;
990                 r->attributes = NULL;
991
992                 while (asn1_tag_remaining(data) > 0) {
993                         const char *attr;
994                         if (!asn1_read_OctetString_talloc(msg, data,
995                                                           &attr))
996                                 return False;
997                         if (!add_string_to_array(msg, attr,
998                                                  &r->attributes,
999                                                  &r->num_attributes))
1000                                 return False;
1001                 }
1002
1003                 asn1_end_tag(data);
1004                 asn1_end_tag(data);
1005                 break;
1006         }
1007
1008         case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
1009                 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
1010                 msg->type = LDAP_TAG_SearchResultEntry;
1011                 r->attributes = NULL;
1012                 r->num_attributes = 0;
1013                 asn1_start_tag(data, tag);
1014                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1015                 ldap_decode_attribs(msg, data, &r->attributes,
1016                                     &r->num_attributes);
1017                 asn1_end_tag(data);
1018                 break;
1019         }
1020
1021         case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
1022                 struct ldap_Result *r = &msg->r.SearchResultDone;
1023                 msg->type = LDAP_TAG_SearchResultDone;
1024                 asn1_start_tag(data, tag);
1025                 ldap_decode_response(msg, data, r);
1026                 asn1_end_tag(data);
1027                 break;
1028         }
1029
1030         case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
1031                 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
1032                 msg->type = LDAP_TAG_SearchResultReference;
1033                 asn1_start_tag(data, tag);
1034                 asn1_read_OctetString_talloc(msg, data, &r->referral);
1035                 asn1_end_tag(data);
1036                 break;
1037         }
1038
1039         case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
1040                 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
1041                 msg->type = LDAP_TAG_ModifyRequest;
1042                 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
1043                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1044                 asn1_start_tag(data, ASN1_SEQUENCE(0));
1045
1046                 r->num_mods = 0;
1047                 r->mods = NULL;
1048
1049                 while (asn1_tag_remaining(data) > 0) {
1050                         struct ldap_mod mod;
1051                         int v;
1052                         ZERO_STRUCT(mod);
1053                         asn1_start_tag(data, ASN1_SEQUENCE(0));
1054                         asn1_read_enumerated(data, &v);
1055                         mod.type = v;
1056                         ldap_decode_attrib(msg, data, &mod.attrib);
1057                         asn1_end_tag(data);
1058                         if (!add_mod_to_array_talloc(msg, &mod,
1059                                                      &r->mods, &r->num_mods))
1060                                 break;
1061                 }
1062
1063                 asn1_end_tag(data);
1064                 asn1_end_tag(data);
1065                 break;
1066         }
1067
1068         case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
1069                 struct ldap_Result *r = &msg->r.ModifyResponse;
1070                 msg->type = LDAP_TAG_ModifyResponse;
1071                 asn1_start_tag(data, tag);
1072                 ldap_decode_response(msg, data, r);
1073                 asn1_end_tag(data);
1074                 break;
1075         }
1076
1077         case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
1078                 struct ldap_AddRequest *r = &msg->r.AddRequest;
1079                 msg->type = LDAP_TAG_AddRequest;
1080                 asn1_start_tag(data, tag);
1081                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1082
1083                 r->attributes = NULL;
1084                 r->num_attributes = 0;
1085                 ldap_decode_attribs(msg, data, &r->attributes,
1086                                     &r->num_attributes);
1087
1088                 asn1_end_tag(data);
1089                 break;
1090         }
1091
1092         case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1093                 struct ldap_Result *r = &msg->r.AddResponse;
1094                 msg->type = LDAP_TAG_AddResponse;
1095                 asn1_start_tag(data, tag);
1096                 ldap_decode_response(msg, data, r);
1097                 asn1_end_tag(data);
1098                 break;
1099         }
1100
1101         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1102                 struct ldap_DelRequest *r = &msg->r.DelRequest;
1103                 int len;
1104                 char *dn;
1105                 msg->type = LDAP_TAG_DelRequest;
1106                 asn1_start_tag(data,
1107                                ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1108                 len = asn1_tag_remaining(data);
1109                 dn = talloc_size(msg, len+1);
1110                 if (dn == NULL)
1111                         break;
1112                 asn1_read(data, dn, len);
1113                 dn[len] = '\0';
1114                 r->dn = dn;
1115                 asn1_end_tag(data);
1116                 break;
1117         }
1118
1119         case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1120                 struct ldap_Result *r = &msg->r.DelResponse;
1121                 msg->type = LDAP_TAG_DelResponse;
1122                 asn1_start_tag(data, tag);
1123                 ldap_decode_response(msg, data, r);
1124                 asn1_end_tag(data);
1125                 break;
1126         }
1127
1128         case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1129                 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
1130                 msg->type = LDAP_TAG_ModifyDNRequest;
1131                 asn1_start_tag(data,
1132                                ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
1133                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1134                 asn1_read_OctetString_talloc(msg, data, &r->newrdn);
1135                 asn1_read_BOOLEAN(data, &r->deleteolddn);
1136                 r->newsuperior = NULL;
1137                 if (asn1_tag_remaining(data) > 0) {
1138                         int len;
1139                         char *newsup;
1140                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1141                         len = asn1_tag_remaining(data);
1142                         newsup = talloc_size(msg, len+1);
1143                         if (newsup == NULL)
1144                                 break;
1145                         asn1_read(data, newsup, len);
1146                         newsup[len] = '\0';
1147                         r->newsuperior = newsup;
1148                         asn1_end_tag(data);
1149                 }
1150                 asn1_end_tag(data);
1151                 break;
1152         }
1153
1154         case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1155                 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1156                 msg->type = LDAP_TAG_ModifyDNResponse;
1157                 asn1_start_tag(data, tag);
1158                 ldap_decode_response(msg, data, r);
1159                 asn1_end_tag(data);
1160                 break;
1161         }
1162
1163         case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1164                 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
1165                 msg->type = LDAP_TAG_CompareRequest;
1166                 asn1_start_tag(data,
1167                                ASN1_APPLICATION(LDAP_TAG_CompareRequest));
1168                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1169                 asn1_start_tag(data, ASN1_SEQUENCE(0));
1170                 asn1_read_OctetString_talloc(msg, data, &r->attribute);
1171                 asn1_read_OctetString(data, &r->value);
1172                 if (r->value.data) {
1173                         talloc_steal(msg, r->value.data);
1174                 }
1175                 asn1_end_tag(data);
1176                 asn1_end_tag(data);
1177                 break;
1178         }
1179
1180         case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1181                 struct ldap_Result *r = &msg->r.CompareResponse;
1182                 msg->type = LDAP_TAG_CompareResponse;
1183                 asn1_start_tag(data, tag);
1184                 ldap_decode_response(msg, data, r);
1185                 asn1_end_tag(data);
1186                 break;
1187         }
1188
1189         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
1190                 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
1191                 msg->type = LDAP_TAG_AbandonRequest;
1192                 asn1_start_tag(data, tag);
1193                 asn1_read_implicit_Integer(data, &r->messageid);
1194                 asn1_end_tag(data);
1195                 break;
1196         }
1197
1198         case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1199                 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1200                 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1201
1202                 msg->type = LDAP_TAG_ExtendedRequest;
1203                 asn1_start_tag(data,tag);
1204                 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
1205                         return False;
1206                 }
1207                 r->oid = blob2string_talloc(msg, tmp_blob);
1208                 data_blob_free(&tmp_blob);
1209                 if (!r->oid) {
1210                         return False;
1211                 }
1212
1213                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
1214                         asn1_read_ContextSimple(data, 1, &tmp_blob);
1215                         r->value = data_blob_talloc(msg, tmp_blob.data, tmp_blob.length);
1216                         data_blob_free(&tmp_blob);
1217                 } else {
1218                         r->value = data_blob(NULL, 0);
1219                 }
1220
1221                 asn1_end_tag(data);
1222                 break;
1223         }
1224
1225         case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1226                 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1227                 msg->type = LDAP_TAG_ExtendedResponse;
1228                 asn1_start_tag(data, tag);              
1229                 ldap_decode_response(msg, data, &r->response);
1230                 /* I have to come across an operation that actually sends
1231                  * something back to really see what's going on. The currently
1232                  * needed pwdchange does not send anything back. */
1233                 r->name = NULL;
1234                 r->value.data = NULL;
1235                 r->value.length = 0;
1236                 asn1_end_tag(data);
1237                 break;
1238         }
1239         default: 
1240                 return False;
1241         }
1242
1243         msg->num_controls = 0;
1244         msg->controls = NULL;
1245
1246         if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
1247                 int i;
1248                 struct ldap_Control *ctrl = NULL;
1249
1250                 asn1_start_tag(data, ASN1_CONTEXT(0));
1251
1252                 for (i=0; asn1_peek_tag(data, ASN1_SEQUENCE(0)); i++) {
1253                         asn1_start_tag(data, ASN1_SEQUENCE(0));
1254
1255                         ctrl = talloc_realloc(msg, ctrl, struct ldap_Control, i+1);
1256                         if (!ctrl) {
1257                                 return False;
1258                         }
1259                         ctrl[i].oid = NULL;
1260                         ctrl[i].critical = False;
1261                         ctrl[i].value = data_blob(NULL, 0);
1262
1263                         asn1_read_OctetString_talloc(ctrl, data, &ctrl[i].oid);
1264
1265                         if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
1266                                 asn1_read_BOOLEAN(data, &ctrl[i].critical);
1267                         }
1268
1269                         if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
1270                                 asn1_read_OctetString(data, &ctrl[i].value);
1271                                 if (ctrl[i].value.data) {
1272                                         talloc_steal(msg, ctrl[i].value.data);
1273                                 }
1274                         }
1275
1276                         asn1_end_tag(data);
1277                 }
1278                 msg->num_controls = i;
1279                 msg->controls = ctrl;
1280
1281                 asn1_end_tag(data);
1282         }
1283
1284         asn1_end_tag(data);
1285         return ((!data->has_error) && (data->nesting == NULL));
1286 }
1287
1288