d8bbf426342c5c857152cf81a80ede565f756638
[jra/samba/.git] / source4 / libcli / ldap / ldap_message.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 3 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, see <http://www.gnu.org/licenses/>.
22    
23 */
24
25 #include "includes.h"
26 #include "../lib/util/asn1.h"
27 #include "libcli/ldap/ldap.h"
28 #include "libcli/ldap/ldap_proto.h"
29
30 _PUBLIC_ struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
31 {
32         return talloc_zero(mem_ctx, struct ldap_message);
33 }
34
35
36 static bool add_value_to_attrib(TALLOC_CTX *mem_ctx, struct ldb_val *value,
37                                 struct ldb_message_element *attrib)
38 {
39         attrib->values = talloc_realloc(mem_ctx,
40                                         attrib->values,
41                                         DATA_BLOB,
42                                         attrib->num_values+1);
43         if (attrib->values == NULL)
44                 return false;
45
46         attrib->values[attrib->num_values].data = talloc_steal(attrib->values,
47                                                                value->data);
48         attrib->values[attrib->num_values].length = value->length;
49         attrib->num_values += 1;
50         return true;
51 }
52
53 static bool add_attrib_to_array_talloc(TALLOC_CTX *mem_ctx,
54                                        const struct ldb_message_element *attrib,
55                                        struct ldb_message_element **attribs,
56                                        int *num_attribs)
57 {
58         *attribs = talloc_realloc(mem_ctx,
59                                   *attribs,
60                                   struct ldb_message_element,
61                                   *num_attribs+1);
62
63         if (*attribs == NULL)
64                 return false;
65
66         (*attribs)[*num_attribs] = *attrib;
67         talloc_steal(*attribs, attrib->values);
68         talloc_steal(*attribs, attrib->name);
69         *num_attribs += 1;
70         return true;
71 }
72
73 static bool add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
74                                     struct ldap_mod *mod,
75                                     struct ldap_mod **mods,
76                                     int *num_mods)
77 {
78         *mods = talloc_realloc(mem_ctx, *mods, struct ldap_mod, (*num_mods)+1);
79
80         if (*mods == NULL)
81                 return false;
82
83         (*mods)[*num_mods] = *mod;
84         *num_mods += 1;
85         return true;
86 }
87
88 static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
89 {
90         int i;
91
92         switch (tree->operation) {
93         case LDB_OP_AND:
94         case LDB_OP_OR:
95                 asn1_push_tag(data, ASN1_CONTEXT(tree->operation==LDB_OP_AND?0:1));
96                 for (i=0; i<tree->u.list.num_elements; i++) {
97                         if (!ldap_push_filter(data, tree->u.list.elements[i])) {
98                                 return false;
99                         }
100                 }
101                 asn1_pop_tag(data);
102                 break;
103
104         case LDB_OP_NOT:
105                 asn1_push_tag(data, ASN1_CONTEXT(2));
106                 if (!ldap_push_filter(data, tree->u.isnot.child)) {
107                         return false;
108                 }
109                 asn1_pop_tag(data);
110                 break;
111
112         case LDB_OP_EQUALITY:
113                 /* equality test */
114                 asn1_push_tag(data, ASN1_CONTEXT(3));
115                 asn1_write_OctetString(data, tree->u.equality.attr,
116                                       strlen(tree->u.equality.attr));
117                 asn1_write_OctetString(data, tree->u.equality.value.data,
118                                       tree->u.equality.value.length);
119                 asn1_pop_tag(data);
120                 break;
121
122         case LDB_OP_SUBSTRING:
123                 /*
124                   SubstringFilter ::= SEQUENCE {
125                           type            AttributeDescription,
126                           -- at least one must be present
127                           substrings      SEQUENCE OF CHOICE {
128                                   initial [0] LDAPString,
129                                   any     [1] LDAPString,
130                                   final   [2] LDAPString } }
131                 */
132                 asn1_push_tag(data, ASN1_CONTEXT(4));
133                 asn1_write_OctetString(data, tree->u.substring.attr, strlen(tree->u.substring.attr));
134                 asn1_push_tag(data, ASN1_SEQUENCE(0));
135                 i = 0;
136                 if ( ! tree->u.substring.start_with_wildcard) {
137                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
138                         asn1_write_DATA_BLOB_LDAPString(data, tree->u.substring.chunks[i]);
139                         asn1_pop_tag(data);
140                         i++;
141                 }
142                 while (tree->u.substring.chunks[i]) {
143                         int ctx;
144
145                         if (( ! tree->u.substring.chunks[i + 1]) &&
146                             (tree->u.substring.end_with_wildcard == 0)) {
147                                 ctx = 2;
148                         } else {
149                                 ctx = 1;
150                         }
151                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(ctx));
152                         asn1_write_DATA_BLOB_LDAPString(data, tree->u.substring.chunks[i]);
153                         asn1_pop_tag(data);
154                         i++;
155                 }
156                 asn1_pop_tag(data);
157                 asn1_pop_tag(data);
158                 break;
159
160         case LDB_OP_GREATER:
161                 /* greaterOrEqual test */
162                 asn1_push_tag(data, ASN1_CONTEXT(5));
163                 asn1_write_OctetString(data, tree->u.comparison.attr,
164                                       strlen(tree->u.comparison.attr));
165                 asn1_write_OctetString(data, tree->u.comparison.value.data,
166                                       tree->u.comparison.value.length);
167                 asn1_pop_tag(data);
168                 break;
169
170         case LDB_OP_LESS:
171                 /* lessOrEqual test */
172                 asn1_push_tag(data, ASN1_CONTEXT(6));
173                 asn1_write_OctetString(data, tree->u.comparison.attr,
174                                       strlen(tree->u.comparison.attr));
175                 asn1_write_OctetString(data, tree->u.comparison.value.data,
176                                       tree->u.comparison.value.length);
177                 asn1_pop_tag(data);
178                 break;
179
180         case LDB_OP_PRESENT:
181                 /* present test */
182                 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(7));
183                 asn1_write_LDAPString(data, tree->u.present.attr);
184                 asn1_pop_tag(data);
185                 return !data->has_error;
186
187         case LDB_OP_APPROX:
188                 /* approx test */
189                 asn1_push_tag(data, ASN1_CONTEXT(8));
190                 asn1_write_OctetString(data, tree->u.comparison.attr,
191                                       strlen(tree->u.comparison.attr));
192                 asn1_write_OctetString(data, tree->u.comparison.value.data,
193                                       tree->u.comparison.value.length);
194                 asn1_pop_tag(data);
195                 break;
196
197         case LDB_OP_EXTENDED:
198                 /*
199                   MatchingRuleAssertion ::= SEQUENCE {
200                   matchingRule    [1] MatchingRuleID OPTIONAL,
201                   type            [2] AttributeDescription OPTIONAL,
202                   matchValue      [3] AssertionValue,
203                   dnAttributes    [4] BOOLEAN DEFAULT FALSE
204                   }
205                 */
206                 asn1_push_tag(data, ASN1_CONTEXT(9));
207                 if (tree->u.extended.rule_id) {
208                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1));
209                         asn1_write_LDAPString(data, tree->u.extended.rule_id);
210                         asn1_pop_tag(data);
211                 }
212                 if (tree->u.extended.attr) {
213                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2));
214                         asn1_write_LDAPString(data, tree->u.extended.attr);
215                         asn1_pop_tag(data);
216                 }
217                 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3));
218                 asn1_write_DATA_BLOB_LDAPString(data, &tree->u.extended.value);
219                 asn1_pop_tag(data);
220                 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4));
221                 asn1_write_uint8(data, tree->u.extended.dnAttributes);
222                 asn1_pop_tag(data);
223                 asn1_pop_tag(data);
224                 break;
225
226         default:
227                 return false;
228         }
229         return !data->has_error;
230 }
231
232 static void ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
233 {
234         asn1_write_enumerated(data, result->resultcode);
235         asn1_write_OctetString(data, result->dn,
236                                (result->dn) ? strlen(result->dn) : 0);
237         asn1_write_OctetString(data, result->errormessage,
238                                (result->errormessage) ?
239                                strlen(result->errormessage) : 0);
240         if (result->referral) {
241                 asn1_push_tag(data, ASN1_CONTEXT(3));
242                 asn1_write_OctetString(data, result->referral,
243                                        strlen(result->referral));
244                 asn1_pop_tag(data);
245         }
246 }
247
248 _PUBLIC_ bool ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ctx)
249 {
250         struct asn1_data *data = asn1_init(mem_ctx);
251         int i, j;
252
253         if (!data) return false;
254
255         asn1_push_tag(data, ASN1_SEQUENCE(0));
256         asn1_write_Integer(data, msg->messageid);
257
258         switch (msg->type) {
259         case LDAP_TAG_BindRequest: {
260                 struct ldap_BindRequest *r = &msg->r.BindRequest;
261                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
262                 asn1_write_Integer(data, r->version);
263                 asn1_write_OctetString(data, r->dn,
264                                        (r->dn != NULL) ? strlen(r->dn) : 0);
265
266                 switch (r->mechanism) {
267                 case LDAP_AUTH_MECH_SIMPLE:
268                         /* context, primitive */
269                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
270                         asn1_write(data, r->creds.password,
271                                    strlen(r->creds.password));
272                         asn1_pop_tag(data);
273                         break;
274                 case LDAP_AUTH_MECH_SASL:
275                         /* context, constructed */
276                         asn1_push_tag(data, ASN1_CONTEXT(3));
277                         asn1_write_OctetString(data, r->creds.SASL.mechanism,
278                                                strlen(r->creds.SASL.mechanism));
279                         if (r->creds.SASL.secblob) {
280                                 asn1_write_OctetString(data, r->creds.SASL.secblob->data,
281                                                        r->creds.SASL.secblob->length);
282                         }
283                         asn1_pop_tag(data);
284                         break;
285                 default:
286                         return false;
287                 }
288
289                 asn1_pop_tag(data);
290                 break;
291         }
292         case LDAP_TAG_BindResponse: {
293                 struct ldap_BindResponse *r = &msg->r.BindResponse;
294                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
295                 ldap_encode_response(data, &r->response);
296                 if (r->SASL.secblob) {
297                         asn1_write_ContextSimple(data, 7, r->SASL.secblob);
298                 }
299                 asn1_pop_tag(data);
300                 break;
301         }
302         case LDAP_TAG_UnbindRequest: {
303 /*              struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
304                 break;
305         }
306         case LDAP_TAG_SearchRequest: {
307                 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
308                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
309                 asn1_write_OctetString(data, r->basedn, strlen(r->basedn));
310                 asn1_write_enumerated(data, r->scope);
311                 asn1_write_enumerated(data, r->deref);
312                 asn1_write_Integer(data, r->sizelimit);
313                 asn1_write_Integer(data, r->timelimit);
314                 asn1_write_BOOLEAN(data, r->attributesonly);
315
316                 if (!ldap_push_filter(data, r->tree)) {
317                         return false;
318                 }
319
320                 asn1_push_tag(data, ASN1_SEQUENCE(0));
321                 for (i=0; i<r->num_attributes; i++) {
322                         asn1_write_OctetString(data, r->attributes[i],
323                                                strlen(r->attributes[i]));
324                 }
325                 asn1_pop_tag(data);
326                 asn1_pop_tag(data);
327                 break;
328         }
329         case LDAP_TAG_SearchResultEntry: {
330                 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
331                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
332                 asn1_write_OctetString(data, r->dn, strlen(r->dn));
333                 asn1_push_tag(data, ASN1_SEQUENCE(0));
334                 for (i=0; i<r->num_attributes; i++) {
335                         struct ldb_message_element *attr = &r->attributes[i];
336                         asn1_push_tag(data, ASN1_SEQUENCE(0));
337                         asn1_write_OctetString(data, attr->name,
338                                                strlen(attr->name));
339                         asn1_push_tag(data, ASN1_SEQUENCE(1));
340                         for (j=0; j<attr->num_values; j++) {
341                                 asn1_write_OctetString(data,
342                                                        attr->values[j].data,
343                                                        attr->values[j].length);
344                         }
345                         asn1_pop_tag(data);
346                         asn1_pop_tag(data);
347                 }
348                 asn1_pop_tag(data);
349                 asn1_pop_tag(data);
350                 break;
351         }
352         case LDAP_TAG_SearchResultDone: {
353                 struct ldap_Result *r = &msg->r.SearchResultDone;
354                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
355                 ldap_encode_response(data, r);
356                 asn1_pop_tag(data);
357                 break;
358         }
359         case LDAP_TAG_ModifyRequest: {
360                 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
361                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
362                 asn1_write_OctetString(data, r->dn, strlen(r->dn));
363                 asn1_push_tag(data, ASN1_SEQUENCE(0));
364
365                 for (i=0; i<r->num_mods; i++) {
366                         struct ldb_message_element *attrib = &r->mods[i].attrib;
367                         asn1_push_tag(data, ASN1_SEQUENCE(0));
368                         asn1_write_enumerated(data, r->mods[i].type);
369                         asn1_push_tag(data, ASN1_SEQUENCE(0));
370                         asn1_write_OctetString(data, attrib->name,
371                                                strlen(attrib->name));
372                         asn1_push_tag(data, ASN1_SET);
373                         for (j=0; j<attrib->num_values; j++) {
374                                 asn1_write_OctetString(data,
375                                                        attrib->values[j].data,
376                                                        attrib->values[j].length);
377         
378                         }
379                         asn1_pop_tag(data);
380                         asn1_pop_tag(data);
381                         asn1_pop_tag(data);
382                 }
383                 
384                 asn1_pop_tag(data);
385                 asn1_pop_tag(data);
386                 break;
387         }
388         case LDAP_TAG_ModifyResponse: {
389                 struct ldap_Result *r = &msg->r.ModifyResponse;
390                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
391                 ldap_encode_response(data, r);
392                 asn1_pop_tag(data);
393                 break;
394         }
395         case LDAP_TAG_AddRequest: {
396                 struct ldap_AddRequest *r = &msg->r.AddRequest;
397                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
398                 asn1_write_OctetString(data, r->dn, strlen(r->dn));
399                 asn1_push_tag(data, ASN1_SEQUENCE(0));
400
401                 for (i=0; i<r->num_attributes; i++) {
402                         struct ldb_message_element *attrib = &r->attributes[i];
403                         asn1_push_tag(data, ASN1_SEQUENCE(0));
404                         asn1_write_OctetString(data, attrib->name,
405                                                strlen(attrib->name));
406                         asn1_push_tag(data, ASN1_SET);
407                         for (j=0; j<r->attributes[i].num_values; j++) {
408                                 asn1_write_OctetString(data,
409                                                        attrib->values[j].data,
410                                                        attrib->values[j].length);
411                         }
412                         asn1_pop_tag(data);
413                         asn1_pop_tag(data);
414                 }
415                 asn1_pop_tag(data);
416                 asn1_pop_tag(data);
417                 break;
418         }
419         case LDAP_TAG_AddResponse: {
420                 struct ldap_Result *r = &msg->r.AddResponse;
421                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
422                 ldap_encode_response(data, r);
423                 asn1_pop_tag(data);
424                 break;
425         }
426         case LDAP_TAG_DelRequest: {
427                 struct ldap_DelRequest *r = &msg->r.DelRequest;
428                 asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type));
429                 asn1_write(data, r->dn, strlen(r->dn));
430                 asn1_pop_tag(data);
431                 break;
432         }
433         case LDAP_TAG_DelResponse: {
434                 struct ldap_Result *r = &msg->r.DelResponse;
435                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
436                 ldap_encode_response(data, r);
437                 asn1_pop_tag(data);
438                 break;
439         }
440         case LDAP_TAG_ModifyDNRequest: {
441                 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
442                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
443                 asn1_write_OctetString(data, r->dn, strlen(r->dn));
444                 asn1_write_OctetString(data, r->newrdn, strlen(r->newrdn));
445                 asn1_write_BOOLEAN(data, r->deleteolddn);
446                 if (r->newsuperior) {
447                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
448                         asn1_write(data, r->newsuperior,
449                                    strlen(r->newsuperior));
450                         asn1_pop_tag(data);
451                 }
452                 asn1_pop_tag(data);
453                 break;
454         }
455         case LDAP_TAG_ModifyDNResponse: {
456                 struct ldap_Result *r = &msg->r.ModifyDNResponse;
457                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
458                 ldap_encode_response(data, r);
459                 asn1_pop_tag(data);
460                 break;
461         }
462         case LDAP_TAG_CompareRequest: {
463                 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
464                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
465                 asn1_write_OctetString(data, r->dn, strlen(r->dn));
466                 asn1_push_tag(data, ASN1_SEQUENCE(0));
467                 asn1_write_OctetString(data, r->attribute,
468                                        strlen(r->attribute));
469                 asn1_write_OctetString(data, r->value.data,
470                                        r->value.length);
471                 asn1_pop_tag(data);
472                 asn1_pop_tag(data);
473                 break;
474         }
475         case LDAP_TAG_CompareResponse: {
476                 struct ldap_Result *r = &msg->r.ModifyDNResponse;
477                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
478                 ldap_encode_response(data, r);
479                 asn1_pop_tag(data);
480                 break;
481         }
482         case LDAP_TAG_AbandonRequest: {
483                 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
484                 asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type));
485                 asn1_write_implicit_Integer(data, r->messageid);
486                 asn1_pop_tag(data);
487                 break;
488         }
489         case LDAP_TAG_SearchResultReference: {
490                 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
491                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
492                 asn1_write_OctetString(data, r->referral, strlen(r->referral));
493                 asn1_pop_tag(data);
494                 break;
495         }
496         case LDAP_TAG_ExtendedRequest: {
497                 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
498                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
499                 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
500                 asn1_write(data, r->oid, strlen(r->oid));
501                 asn1_pop_tag(data);
502                 if (r->value) {
503                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1));
504                         asn1_write(data, r->value->data, r->value->length);
505                         asn1_pop_tag(data);
506                 }
507                 asn1_pop_tag(data);
508                 break;
509         }
510         case LDAP_TAG_ExtendedResponse: {
511                 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
512                 asn1_push_tag(data, ASN1_APPLICATION(msg->type));
513                 ldap_encode_response(data, &r->response);
514                 if (r->oid) {
515                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(10));
516                         asn1_write(data, r->oid, strlen(r->oid));
517                         asn1_pop_tag(data);
518                 }
519                 if (r->value) {
520                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(11));
521                         asn1_write(data, r->value->data, r->value->length);
522                         asn1_pop_tag(data);
523                 }
524                 asn1_pop_tag(data);
525                 break;
526         }
527         default:
528                 return false;
529         }
530
531         if (msg->controls != NULL) {
532                 asn1_push_tag(data, ASN1_CONTEXT(0));
533                 
534                 for (i = 0; msg->controls[i] != NULL; i++) {
535                         if (!ldap_encode_control(mem_ctx, data, msg->controls[i])) {
536                                 return false;
537                         }
538                 }
539
540                 asn1_pop_tag(data);
541         }
542
543         asn1_pop_tag(data);
544
545         if (data->has_error) {
546                 asn1_free(data);
547                 return false;
548         }
549
550         *result = data_blob_talloc(mem_ctx, data->data, data->length);
551         asn1_free(data);
552         return true;
553 }
554
555 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
556                                       DATA_BLOB blob)
557 {
558         char *result = talloc_array(mem_ctx, char, blob.length+1);
559         memcpy(result, blob.data, blob.length);
560         result[blob.length] = '\0';
561         return result;
562 }
563
564 bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
565                                   struct asn1_data *data,
566                                   const char **result)
567 {
568         DATA_BLOB string;
569         if (!asn1_read_OctetString(data, mem_ctx, &string))
570                 return false;
571         *result = blob2string_talloc(mem_ctx, string);
572         data_blob_free(&string);
573         return true;
574 }
575
576 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
577                                  struct asn1_data *data,
578                                  struct ldap_Result *result)
579 {
580         asn1_read_enumerated(data, &result->resultcode);
581         asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
582         asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
583         if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
584                 asn1_start_tag(data, ASN1_CONTEXT(3));
585                 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
586                 asn1_end_tag(data);
587         } else {
588                 result->referral = NULL;
589         }
590 }
591
592 static struct ldb_val **ldap_decode_substring(TALLOC_CTX *mem_ctx, struct ldb_val **chunks, int chunk_num, char *value)
593 {
594
595         chunks = talloc_realloc(mem_ctx, chunks, struct ldb_val *, chunk_num + 2);
596         if (chunks == NULL) {
597                 return NULL;
598         }
599
600         chunks[chunk_num] = talloc(mem_ctx, struct ldb_val);
601         if (chunks[chunk_num] == NULL) {
602                 return NULL;
603         }
604
605         chunks[chunk_num]->data = (uint8_t *)talloc_strdup(mem_ctx, value);
606         if (chunks[chunk_num]->data == NULL) {
607                 return NULL;
608         }
609         chunks[chunk_num]->length = strlen(value);
610
611         chunks[chunk_num + 1] = '\0';
612
613         return chunks;
614 }
615
616
617 /*
618   parse the ASN.1 formatted search string into a ldb_parse_tree
619 */
620 static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx, 
621                                                       struct asn1_data *data)
622 {
623         uint8_t filter_tag;
624         struct ldb_parse_tree *ret;
625
626         if (!asn1_peek_uint8(data, &filter_tag)) {
627                 return NULL;
628         }
629
630         filter_tag &= 0x1f;     /* strip off the asn1 stuff */
631
632         ret = talloc(mem_ctx, struct ldb_parse_tree);
633         if (ret == NULL) return NULL;
634
635         switch(filter_tag) {
636         case 0:
637         case 1:
638                 /* AND or OR of one or more filters */
639                 ret->operation = (filter_tag == 0)?LDB_OP_AND:LDB_OP_OR;
640                 ret->u.list.num_elements = 0;
641                 ret->u.list.elements = NULL;
642
643                 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
644                         goto failed;
645                 }
646
647                 while (asn1_tag_remaining(data) > 0) {
648                         struct ldb_parse_tree *subtree;
649                         subtree = ldap_decode_filter_tree(ret, data);
650                         if (subtree == NULL) {
651                                 goto failed;
652                         }
653                         ret->u.list.elements = 
654                                 talloc_realloc(ret, ret->u.list.elements, 
655                                                struct ldb_parse_tree *, 
656                                                ret->u.list.num_elements+1);
657                         if (ret->u.list.elements == NULL) {
658                                 goto failed;
659                         }
660                         talloc_steal(ret->u.list.elements, subtree);
661                         ret->u.list.elements[ret->u.list.num_elements] = subtree;
662                         ret->u.list.num_elements++;
663                 }
664                 if (!asn1_end_tag(data)) {
665                         goto failed;
666                 }
667                 break;
668
669         case 2:
670                 /* 'not' operation */
671                 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
672                         goto failed;
673                 }
674
675                 ret->operation = LDB_OP_NOT;
676                 ret->u.isnot.child = ldap_decode_filter_tree(ret, data);
677                 if (ret->u.isnot.child == NULL) {
678                         goto failed;
679                 }
680                 if (!asn1_end_tag(data)) {
681                         goto failed;
682                 }
683                 break;
684
685         case 3: {
686                 /* equalityMatch */
687                 const char *attrib;
688                 DATA_BLOB value;
689
690                 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
691                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
692                 asn1_read_OctetString(data, mem_ctx, &value);
693                 asn1_end_tag(data);
694                 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
695                         goto failed;
696                 }
697
698                 ret->operation = LDB_OP_EQUALITY;
699                 ret->u.equality.attr = talloc_steal(ret, attrib);
700                 ret->u.equality.value.data = talloc_steal(ret, value.data);
701                 ret->u.equality.value.length = value.length;
702                 break;
703         }
704         case 4: {
705                 /* substrings */
706                 DATA_BLOB attr;
707                 uint8_t subs_tag;
708                 char *value;
709                 int chunk_num = 0;
710
711                 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
712                         goto failed;
713                 }
714                 if (!asn1_read_OctetString(data, mem_ctx, &attr)) {
715                         goto failed;
716                 }
717
718                 ret->operation = LDB_OP_SUBSTRING;
719                 ret->u.substring.attr = talloc_strndup(ret, (char *)attr.data, attr.length);
720                 ret->u.substring.chunks = NULL;
721                 ret->u.substring.start_with_wildcard = 1;
722                 ret->u.substring.end_with_wildcard = 1;
723
724                 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
725                         goto failed;
726                 }
727
728                 while (asn1_tag_remaining(data)) {
729                         asn1_peek_uint8(data, &subs_tag);
730                         subs_tag &= 0x1f;       /* strip off the asn1 stuff */
731                         if (subs_tag > 2) goto failed;
732
733                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(subs_tag));
734                         asn1_read_LDAPString(data, mem_ctx, &value);
735                         asn1_end_tag(data);
736
737                         switch (subs_tag) {
738                         case 0:
739                                 if (ret->u.substring.chunks != NULL) {
740                                         /* initial value found in the middle */
741                                         goto failed;
742                                 }
743
744                                 ret->u.substring.chunks = ldap_decode_substring(ret, NULL, 0, value);
745                                 if (ret->u.substring.chunks == NULL) {
746                                         goto failed;
747                                 }
748
749                                 ret->u.substring.start_with_wildcard = 0;
750                                 chunk_num = 1;
751                                 break;
752
753                         case 1:
754                                 if (ret->u.substring.end_with_wildcard == 0) {
755                                         /* "any" value found after a "final" value */
756                                         goto failed;
757                                 }
758
759                                 ret->u.substring.chunks = ldap_decode_substring(ret,
760                                                                                 ret->u.substring.chunks,
761                                                                                 chunk_num,
762                                                                                 value);
763                                 if (ret->u.substring.chunks == NULL) {
764                                         goto failed;
765                                 }
766
767                                 chunk_num++;
768                                 break;
769
770                         case 2:
771                                 ret->u.substring.chunks = ldap_decode_substring(ret,
772                                                                                 ret->u.substring.chunks,
773                                                                                 chunk_num,
774                                                                                 value);
775                                 if (ret->u.substring.chunks == NULL) {
776                                         goto failed;
777                                 }
778
779                                 ret->u.substring.end_with_wildcard = 0;
780                                 break;
781
782                         default:
783                                 goto failed;
784                         }
785
786                 }
787
788                 if (!asn1_end_tag(data)) { /* SEQUENCE */
789                         goto failed;
790                 }
791
792                 if (!asn1_end_tag(data)) {
793                         goto failed;
794                 }
795                 break;
796         }
797         case 5: {
798                 /* greaterOrEqual */
799                 const char *attrib;
800                 DATA_BLOB value;
801
802                 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
803                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
804                 asn1_read_OctetString(data, mem_ctx, &value);
805                 asn1_end_tag(data);
806                 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
807                         goto failed;
808                 }
809
810                 ret->operation = LDB_OP_GREATER;
811                 ret->u.comparison.attr = talloc_steal(ret, attrib);
812                 ret->u.comparison.value.data = talloc_steal(ret, value.data);
813                 ret->u.comparison.value.length = value.length;
814                 break;
815         }
816         case 6: {
817                 /* lessOrEqual */
818                 const char *attrib;
819                 DATA_BLOB value;
820
821                 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
822                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
823                 asn1_read_OctetString(data, mem_ctx, &value);
824                 asn1_end_tag(data);
825                 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
826                         goto failed;
827                 }
828
829                 ret->operation = LDB_OP_LESS;
830                 ret->u.comparison.attr = talloc_steal(ret, attrib);
831                 ret->u.comparison.value.data = talloc_steal(ret, value.data);
832                 ret->u.comparison.value.length = value.length;
833                 break;
834         }
835         case 7: {
836                 /* Normal presence, "attribute=*" */
837                 char *attr;
838
839                 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(filter_tag))) {
840                         goto failed;
841                 }
842                 if (!asn1_read_LDAPString(data, ret, &attr)) {
843                         goto failed;
844                 }
845
846                 ret->operation = LDB_OP_PRESENT;
847                 ret->u.present.attr = talloc_steal(ret, attr);
848
849                 if (!asn1_end_tag(data)) {
850                         goto failed;
851                 }
852                 break;
853         }
854         case 8: {
855                 /* approx */
856                 const char *attrib;
857                 DATA_BLOB value;
858
859                 asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
860                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
861                 asn1_read_OctetString(data, mem_ctx, &value);
862                 asn1_end_tag(data);
863                 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
864                         goto failed;
865                 }
866
867                 ret->operation = LDB_OP_APPROX;
868                 ret->u.comparison.attr = talloc_steal(ret, attrib);
869                 ret->u.comparison.value.data = talloc_steal(ret, value.data);
870                 ret->u.comparison.value.length = value.length;
871                 break;
872         }
873         case 9: {
874                 char *oid = NULL, *attr = NULL, *value;
875                 uint8_t dnAttributes;
876                 /* an extended search */
877                 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
878                         goto failed;
879                 }
880
881                 /* FIXME: read carefully rfc2251.txt there are a number of 'MUST's
882                    we need to check we properly implement --SSS */ 
883                 /* either oid or type must be defined */
884                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) { /* optional */
885                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(1));
886                         asn1_read_LDAPString(data, ret, &oid);
887                         asn1_end_tag(data);
888                 }
889                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(2))) {      /* optional  */
890                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(2));
891                         asn1_read_LDAPString(data, ret, &attr);
892                         asn1_end_tag(data);
893                 }
894                 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(3));
895                 asn1_read_LDAPString(data, ret, &value);
896                 asn1_end_tag(data);
897                 /* dnAttributes is marked as BOOLEAN DEFAULT FALSE
898                    it is not marked as OPTIONAL but openldap tools
899                    do not set this unless it is to be set as TRUE
900                    NOTE: openldap tools do not work with AD as it
901                    seems that AD always requires the dnAttributes
902                    boolean value to be set */
903                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(4))) {
904                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(4));
905                         asn1_read_uint8(data, &dnAttributes);
906                         asn1_end_tag(data);
907                 } else {
908                         dnAttributes = 0;
909                 }
910                 if ((oid == NULL && attr == NULL) || (value == NULL)) {
911                         goto failed;
912                 }
913
914                 if (oid) {
915                         ret->operation               = LDB_OP_EXTENDED;
916
917                         /* From the RFC2251: If the type field is
918                            absent and matchingRule is present, the matchValue is compared
919                            against all attributes in an entry which support that matchingRule
920                         */
921                         if (attr) {
922                                 ret->u.extended.attr = talloc_steal(ret, attr);
923                         } else {
924                                 ret->u.extended.attr = talloc_strdup(ret, "*");
925                         }
926                         ret->u.extended.rule_id      = talloc_steal(ret, oid);
927                         ret->u.extended.value.data   = talloc_steal(ret, value);
928                         ret->u.extended.value.length = strlen(value);
929                         ret->u.extended.dnAttributes = dnAttributes;
930                 } else {
931                         ret->operation               = LDB_OP_EQUALITY;
932                         ret->u.equality.attr         = talloc_steal(ret, attr);
933                         ret->u.equality.value.data   = talloc_steal(ret, value);
934                         ret->u.equality.value.length = strlen(value);
935                 }
936                 if (!asn1_end_tag(data)) {
937                         goto failed;
938                 }
939                 break;
940         }
941
942         default:
943                 goto failed;
944         }
945         
946         return ret;
947
948 failed:
949         talloc_free(ret);
950         return NULL;    
951 }
952
953 /* Decode a single LDAP attribute, possibly containing multiple values */
954 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
955                                struct ldb_message_element *attrib)
956 {
957         asn1_start_tag(data, ASN1_SEQUENCE(0));
958         asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
959         asn1_start_tag(data, ASN1_SET);
960         while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
961                 DATA_BLOB blob;
962                 asn1_read_OctetString(data, mem_ctx, &blob);
963                 add_value_to_attrib(mem_ctx, &blob, attrib);
964         }
965         asn1_end_tag(data);
966         asn1_end_tag(data);
967         
968 }
969
970 /* Decode a set of LDAP attributes, as found in the dereference control */
971 void ldap_decode_attribs_bare(TALLOC_CTX *mem_ctx, struct asn1_data *data,
972                               struct ldb_message_element **attributes,
973                               int *num_attributes)
974 {
975         while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
976                 struct ldb_message_element attrib;
977                 ZERO_STRUCT(attrib);
978                 ldap_decode_attrib(mem_ctx, data, &attrib);
979                 add_attrib_to_array_talloc(mem_ctx, &attrib,
980                                            attributes, num_attributes);
981         }
982 }
983
984 /* Decode a set of LDAP attributes, as found in a search entry */
985 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
986                                 struct ldb_message_element **attributes,
987                                 int *num_attributes)
988 {
989         asn1_start_tag(data, ASN1_SEQUENCE(0));
990         ldap_decode_attribs_bare(mem_ctx, data, 
991                                  attributes, num_attributes);
992         asn1_end_tag(data);
993 }
994
995 /* This routine returns LDAP status codes */
996
997 _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
998 {
999         uint8_t tag;
1000
1001         asn1_start_tag(data, ASN1_SEQUENCE(0));
1002         asn1_read_Integer(data, &msg->messageid);
1003
1004         if (!asn1_peek_uint8(data, &tag))
1005                 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1006
1007         switch(tag) {
1008
1009         case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
1010                 struct ldap_BindRequest *r = &msg->r.BindRequest;
1011                 msg->type = LDAP_TAG_BindRequest;
1012                 asn1_start_tag(data, tag);
1013                 asn1_read_Integer(data, &r->version);
1014                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1015                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
1016                         int pwlen;
1017                         r->creds.password = "";
1018                         r->mechanism = LDAP_AUTH_MECH_SIMPLE;
1019                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1020                         pwlen = asn1_tag_remaining(data);
1021                         if (pwlen == -1) {
1022                                 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1023                         }
1024                         if (pwlen != 0) {
1025                                 char *pw = talloc_array(msg, char, pwlen+1);
1026                                 if (!pw) {
1027                                         return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1028                                 }
1029                                 asn1_read(data, pw, pwlen);
1030                                 pw[pwlen] = '\0';
1031                                 r->creds.password = pw;
1032                         }
1033                         asn1_end_tag(data);
1034                 } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
1035                         asn1_start_tag(data, ASN1_CONTEXT(3));
1036                         r->mechanism = LDAP_AUTH_MECH_SASL;
1037                         asn1_read_OctetString_talloc(msg, data, &r->creds.SASL.mechanism);
1038                         if (asn1_peek_tag(data, ASN1_OCTET_STRING)) { /* optional */
1039                                 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1040                                 asn1_read_OctetString(data, msg, &tmp_blob);
1041                                 r->creds.SASL.secblob = talloc(msg, DATA_BLOB);
1042                                 if (!r->creds.SASL.secblob) {
1043                                         return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1044                                 }
1045                                 *r->creds.SASL.secblob = data_blob_talloc(r->creds.SASL.secblob,
1046                                                                           tmp_blob.data, tmp_blob.length);
1047                                 data_blob_free(&tmp_blob);
1048                         } else {
1049                                 r->creds.SASL.secblob = NULL;
1050                         }
1051                         asn1_end_tag(data);
1052                 } else {
1053                         /* Neither Simple nor SASL bind */
1054                         return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1055                 }
1056                 asn1_end_tag(data);
1057                 break;
1058         }
1059
1060         case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
1061                 struct ldap_BindResponse *r = &msg->r.BindResponse;
1062                 msg->type = LDAP_TAG_BindResponse;
1063                 asn1_start_tag(data, tag);
1064                 ldap_decode_response(msg, data, &r->response);
1065                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
1066                         DATA_BLOB tmp_blob = data_blob(NULL, 0);
1067                         asn1_read_ContextSimple(data, 7, &tmp_blob);
1068                         r->SASL.secblob = talloc(msg, DATA_BLOB);
1069                         if (!r->SASL.secblob) {
1070                                 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1071                         }
1072                         *r->SASL.secblob = data_blob_talloc(r->SASL.secblob,
1073                                                             tmp_blob.data, tmp_blob.length);
1074                         data_blob_free(&tmp_blob);
1075                 } else {
1076                         r->SASL.secblob = NULL;
1077                 }
1078                 asn1_end_tag(data);
1079                 break;
1080         }
1081
1082         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
1083                 msg->type = LDAP_TAG_UnbindRequest;
1084                 asn1_start_tag(data, tag);
1085                 asn1_end_tag(data);
1086                 break;
1087         }
1088
1089         case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
1090                 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
1091                 msg->type = LDAP_TAG_SearchRequest;
1092                 asn1_start_tag(data, tag);
1093                 asn1_read_OctetString_talloc(msg, data, &r->basedn);
1094                 asn1_read_enumerated(data, (int *)&(r->scope));
1095                 asn1_read_enumerated(data, (int *)&(r->deref));
1096                 asn1_read_Integer(data, &r->sizelimit);
1097                 asn1_read_Integer(data, &r->timelimit);
1098                 asn1_read_BOOLEAN(data, &r->attributesonly);
1099
1100                 r->tree = ldap_decode_filter_tree(msg, data);
1101                 if (r->tree == NULL) {
1102                         return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1103                 }
1104
1105                 asn1_start_tag(data, ASN1_SEQUENCE(0));
1106
1107                 r->num_attributes = 0;
1108                 r->attributes = NULL;
1109
1110                 while (asn1_tag_remaining(data) > 0) {                                  
1111
1112                         const char *attr;
1113                         if (!asn1_read_OctetString_talloc(msg, data,
1114                                                           &attr))
1115                                 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1116                         if (!add_string_to_array(msg, attr,
1117                                                  &r->attributes,
1118                                                  &r->num_attributes))
1119                                 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1120                 }
1121
1122                 asn1_end_tag(data);
1123                 asn1_end_tag(data);
1124                 break;
1125         }
1126
1127         case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
1128                 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
1129                 msg->type = LDAP_TAG_SearchResultEntry;
1130                 r->attributes = NULL;
1131                 r->num_attributes = 0;
1132                 asn1_start_tag(data, tag);
1133                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1134                 ldap_decode_attribs(msg, data, &r->attributes,
1135                                     &r->num_attributes);
1136                 asn1_end_tag(data);
1137                 break;
1138         }
1139
1140         case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
1141                 struct ldap_Result *r = &msg->r.SearchResultDone;
1142                 msg->type = LDAP_TAG_SearchResultDone;
1143                 asn1_start_tag(data, tag);
1144                 ldap_decode_response(msg, data, r);
1145                 asn1_end_tag(data);
1146                 break;
1147         }
1148
1149         case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
1150                 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
1151                 msg->type = LDAP_TAG_SearchResultReference;
1152                 asn1_start_tag(data, tag);
1153                 asn1_read_OctetString_talloc(msg, data, &r->referral);
1154                 asn1_end_tag(data);
1155                 break;
1156         }
1157
1158         case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
1159                 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
1160                 msg->type = LDAP_TAG_ModifyRequest;
1161                 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
1162                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1163                 asn1_start_tag(data, ASN1_SEQUENCE(0));
1164
1165                 r->num_mods = 0;
1166                 r->mods = NULL;
1167
1168                 while (asn1_tag_remaining(data) > 0) {
1169                         struct ldap_mod mod;
1170                         int v;
1171                         ZERO_STRUCT(mod);
1172                         asn1_start_tag(data, ASN1_SEQUENCE(0));
1173                         asn1_read_enumerated(data, &v);
1174                         mod.type = v;
1175                         ldap_decode_attrib(msg, data, &mod.attrib);
1176                         asn1_end_tag(data);
1177                         if (!add_mod_to_array_talloc(msg, &mod,
1178                                                      &r->mods, &r->num_mods)) {
1179                                 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1180                         }
1181                 }
1182
1183                 asn1_end_tag(data);
1184                 asn1_end_tag(data);
1185                 break;
1186         }
1187
1188         case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
1189                 struct ldap_Result *r = &msg->r.ModifyResponse;
1190                 msg->type = LDAP_TAG_ModifyResponse;
1191                 asn1_start_tag(data, tag);
1192                 ldap_decode_response(msg, data, r);
1193                 asn1_end_tag(data);
1194                 break;
1195         }
1196
1197         case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
1198                 struct ldap_AddRequest *r = &msg->r.AddRequest;
1199                 msg->type = LDAP_TAG_AddRequest;
1200                 asn1_start_tag(data, tag);
1201                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1202
1203                 r->attributes = NULL;
1204                 r->num_attributes = 0;
1205                 ldap_decode_attribs(msg, data, &r->attributes,
1206                                     &r->num_attributes);
1207
1208                 asn1_end_tag(data);
1209                 break;
1210         }
1211
1212         case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1213                 struct ldap_Result *r = &msg->r.AddResponse;
1214                 msg->type = LDAP_TAG_AddResponse;
1215                 asn1_start_tag(data, tag);
1216                 ldap_decode_response(msg, data, r);
1217                 asn1_end_tag(data);
1218                 break;
1219         }
1220
1221         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1222                 struct ldap_DelRequest *r = &msg->r.DelRequest;
1223                 int len;
1224                 char *dn;
1225                 msg->type = LDAP_TAG_DelRequest;
1226                 asn1_start_tag(data,
1227                                ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1228                 len = asn1_tag_remaining(data);
1229                 if (len == -1) {
1230                         return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1231                 }
1232                 dn = talloc_array(msg, char, len+1);
1233                 if (dn == NULL)
1234                         break;
1235                 asn1_read(data, dn, len);
1236                 dn[len] = '\0';
1237                 r->dn = dn;
1238                 asn1_end_tag(data);
1239                 break;
1240         }
1241
1242         case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1243                 struct ldap_Result *r = &msg->r.DelResponse;
1244                 msg->type = LDAP_TAG_DelResponse;
1245                 asn1_start_tag(data, tag);
1246                 ldap_decode_response(msg, data, r);
1247                 asn1_end_tag(data);
1248                 break;
1249         }
1250
1251         case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1252                 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
1253                 msg->type = LDAP_TAG_ModifyDNRequest;
1254                 asn1_start_tag(data,
1255                                ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
1256                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1257                 asn1_read_OctetString_talloc(msg, data, &r->newrdn);
1258                 asn1_read_BOOLEAN(data, &r->deleteolddn);
1259                 r->newsuperior = NULL;
1260                 if (asn1_tag_remaining(data) > 0) {
1261                         int len;
1262                         char *newsup;
1263                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1264                         len = asn1_tag_remaining(data);
1265                         if (len == -1) {
1266                                 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1267                         }
1268                         newsup = talloc_array(msg, char, len+1);
1269                         if (newsup == NULL) {
1270                                 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1271                         }
1272                         asn1_read(data, newsup, len);
1273                         newsup[len] = '\0';
1274                         r->newsuperior = newsup;
1275                         asn1_end_tag(data);
1276                 }
1277                 asn1_end_tag(data);
1278                 break;
1279         }
1280
1281         case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1282                 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1283                 msg->type = LDAP_TAG_ModifyDNResponse;
1284                 asn1_start_tag(data, tag);
1285                 ldap_decode_response(msg, data, r);
1286                 asn1_end_tag(data);
1287                 break;
1288         }
1289
1290         case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1291                 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
1292                 msg->type = LDAP_TAG_CompareRequest;
1293                 asn1_start_tag(data,
1294                                ASN1_APPLICATION(LDAP_TAG_CompareRequest));
1295                 asn1_read_OctetString_talloc(msg, data, &r->dn);
1296                 asn1_start_tag(data, ASN1_SEQUENCE(0));
1297                 asn1_read_OctetString_talloc(msg, data, &r->attribute);
1298                 asn1_read_OctetString(data, msg, &r->value);
1299                 if (r->value.data) {
1300                         talloc_steal(msg, r->value.data);
1301                 }
1302                 asn1_end_tag(data);
1303                 asn1_end_tag(data);
1304                 break;
1305         }
1306
1307         case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1308                 struct ldap_Result *r = &msg->r.CompareResponse;
1309                 msg->type = LDAP_TAG_CompareResponse;
1310                 asn1_start_tag(data, tag);
1311                 ldap_decode_response(msg, data, r);
1312                 asn1_end_tag(data);
1313                 break;
1314         }
1315
1316         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
1317                 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
1318                 msg->type = LDAP_TAG_AbandonRequest;
1319                 asn1_start_tag(data, tag);
1320                 asn1_read_implicit_Integer(data, &r->messageid);
1321                 asn1_end_tag(data);
1322                 break;
1323         }
1324
1325         case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1326                 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1327                 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1328
1329                 msg->type = LDAP_TAG_ExtendedRequest;
1330                 asn1_start_tag(data,tag);
1331                 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
1332                         return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1333                 }
1334                 r->oid = blob2string_talloc(msg, tmp_blob);
1335                 data_blob_free(&tmp_blob);
1336                 if (!r->oid) {
1337                         return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1338                 }
1339
1340                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
1341                         asn1_read_ContextSimple(data, 1, &tmp_blob);
1342                         r->value = talloc(msg, DATA_BLOB);
1343                         if (!r->value) {
1344                                 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1345                         }
1346                         *r->value = data_blob_talloc(r->value, tmp_blob.data, tmp_blob.length);
1347                         data_blob_free(&tmp_blob);
1348                 } else {
1349                         r->value = NULL;
1350                 }
1351
1352                 asn1_end_tag(data);
1353                 break;
1354         }
1355
1356         case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1357                 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1358                 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1359
1360                 msg->type = LDAP_TAG_ExtendedResponse;
1361                 asn1_start_tag(data, tag);              
1362                 ldap_decode_response(msg, data, &r->response);
1363
1364                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(10))) {
1365                         asn1_read_ContextSimple(data, 1, &tmp_blob);
1366                         r->oid = blob2string_talloc(msg, tmp_blob);
1367                         data_blob_free(&tmp_blob);
1368                         if (!r->oid) {
1369                                 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1370                         }
1371                 } else {
1372                         r->oid = NULL;
1373                 }
1374
1375                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(11))) {
1376                         asn1_read_ContextSimple(data, 1, &tmp_blob);
1377                         r->value = talloc(msg, DATA_BLOB);
1378                         if (!r->value) {
1379                                 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1380                         }
1381                         *r->value = data_blob_talloc(r->value, tmp_blob.data, tmp_blob.length);
1382                         data_blob_free(&tmp_blob);
1383                 } else {
1384                         r->value = NULL;
1385                 }
1386
1387                 asn1_end_tag(data);
1388                 break;
1389         }
1390         default: 
1391                 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1392         }
1393
1394         msg->controls = NULL;
1395         msg->controls_decoded = NULL;
1396
1397         if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
1398                 int i = 0;
1399                 struct ldb_control **ctrl = NULL;
1400                 bool *decoded = NULL;
1401
1402                 asn1_start_tag(data, ASN1_CONTEXT(0));
1403
1404                 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
1405                         DATA_BLOB value;
1406                         /* asn1_start_tag(data, ASN1_SEQUENCE(0)); */
1407
1408                         ctrl = talloc_realloc(msg, ctrl, struct ldb_control *, i+2);
1409                         if (!ctrl) {
1410                                 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1411                         }
1412
1413                         decoded = talloc_realloc(msg, decoded, bool, i+1);
1414                         if (!decoded) {
1415                                 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1416                         }
1417
1418                         ctrl[i] = talloc(ctrl, struct ldb_control);
1419                         if (!ctrl[i]) {
1420                                 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
1421                         }
1422
1423                         if (!ldap_decode_control_wrapper(ctrl, data, ctrl[i], &value)) {
1424                                 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1425                         }
1426                         
1427                         if (!ldap_decode_control_value(ctrl, value, ctrl[i])) {
1428                                 if (ctrl[i]->critical) {
1429                                         ctrl[i]->data = NULL;
1430                                         decoded[i] = false;
1431                                         i++;
1432                                 } else {
1433                                         talloc_free(ctrl[i]);
1434                                         ctrl[i] = NULL;
1435                                 }
1436                         } else {
1437                                 decoded[i] = true;
1438                                 i++;
1439                         }
1440                 }
1441
1442                 if (ctrl != NULL) {
1443                         ctrl[i] = NULL;
1444                 }
1445
1446                 msg->controls = ctrl;
1447                 msg->controls_decoded = decoded;
1448
1449                 asn1_end_tag(data);
1450         }
1451
1452         asn1_end_tag(data);
1453         if ((data->has_error) || (data->nesting != NULL)) {
1454                 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
1455         }
1456         return NT_STATUS_OK;
1457 }
1458
1459
1460 /*
1461   return NT_STATUS_OK if a blob has enough bytes in it to be a full
1462   ldap packet. Set packet_size if true.
1463 */
1464 NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_size)
1465 {
1466         return asn1_full_tag(blob, ASN1_SEQUENCE(0), packet_size);
1467 }