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