dd689027f9e51ab276dca24f140228e59d20d653
[samba.git] / source / libcli / ldap / ldap.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    
5    Copyright (C) Andrew Tridgell  2004
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Stefan Metzmacher 2004
8    Copyright (C) Simo Sorce 2004
9     
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23    
24 */
25
26 #include "includes.h"
27 #include "system/iconv.h"
28 #include "asn_1.h"
29
30 /****************************************************************************
31  *
32  * LDAP filter parser -- main routine is ldap_parse_filter
33  *
34  * Shamelessly stolen and adapted from ldb.
35  *
36  ***************************************************************************/
37
38 /*
39   return next token element. Caller frees
40 */
41 static char *ldap_parse_lex(TALLOC_CTX *mem_ctx, const char **s,
42                            const char *sep)
43 {
44         const char *p = *s;
45         char *ret;
46
47         while (isspace(*p)) {
48                 p++;
49         }
50         *s = p;
51
52         if (*p == 0) {
53                 return NULL;
54         }
55
56         if (strchr(sep, *p)) {
57                 (*s) = p+1;
58                 ret = talloc_strndup(mem_ctx, p, 1);
59                 if (!ret) {
60                         errno = ENOMEM;
61                 }
62                 return ret;
63         }
64
65         while (*p && (isalnum(*p) || !strchr(sep, *p))) {
66                 p++;
67         }
68
69         if (p == *s) {
70                 return NULL;
71         }
72
73         ret = talloc_strndup(mem_ctx, *s, p - *s);
74         if (!ret) {
75                 errno = ENOMEM;
76         }
77
78         *s = p;
79
80         return ret;
81 }
82
83
84 /*
85   find a matching close brace in a string
86 */
87 static const char *match_brace(const char *s)
88 {
89         unsigned int count = 0;
90         while (*s && (count != 0 || *s != ')')) {
91                 if (*s == '(') {
92                         count++;
93                 }
94                 if (*s == ')') {
95                         count--;
96                 }
97                 s++;
98         }
99         if (! *s) {
100                 return NULL;
101         }
102         return s;
103 }
104
105 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
106                                                const char **s);
107
108 /*
109   <simple> ::= <attributetype> <filtertype> <attributevalue>
110 */
111 static struct ldap_parse_tree *ldap_parse_simple(TALLOC_CTX *mem_ctx,
112                                                const char *s)
113 {
114         char *eq, *val, *l;
115         struct ldap_parse_tree *ret;
116
117         l = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
118         if (!l) {
119                 return NULL;
120         }
121
122         if (strchr("()&|=", *l))
123                 return NULL;
124
125         eq = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
126         if (!eq || strcmp(eq, "=") != 0)
127                 return NULL;
128
129         val = ldap_parse_lex(mem_ctx, &s, ")");
130         if (val && strchr("()&|", *val))
131                 return NULL;
132         
133         ret = talloc(mem_ctx, sizeof(*ret));
134         if (!ret) {
135                 errno = ENOMEM;
136                 return NULL;
137         }
138
139         ret->operation = LDAP_OP_SIMPLE;
140         ret->u.simple.attr = l;
141         ret->u.simple.value.data = val;
142         ret->u.simple.value.length = val?strlen(val):0;
143
144         return ret;
145 }
146
147
148 /*
149   parse a filterlist
150   <and> ::= '&' <filterlist>
151   <or> ::= '|' <filterlist>
152   <filterlist> ::= <filter> | <filter> <filterlist>
153 */
154 static struct ldap_parse_tree *ldap_parse_filterlist(TALLOC_CTX *mem_ctx,
155                                                    enum ldap_parse_op op,
156                                                    const char *s)
157 {
158         struct ldap_parse_tree *ret, *next;
159
160         ret = talloc(mem_ctx, sizeof(*ret));
161
162         if (!ret) {
163                 errno = ENOMEM;
164                 return NULL;
165         }
166
167         ret->operation = op;
168         ret->u.list.num_elements = 1;
169         ret->u.list.elements = talloc(mem_ctx, sizeof(*ret->u.list.elements));
170         if (!ret->u.list.elements) {
171                 errno = ENOMEM;
172                 return NULL;
173         }
174
175         ret->u.list.elements[0] = ldap_parse_filter(mem_ctx, &s);
176         if (!ret->u.list.elements[0]) {
177                 return NULL;
178         }
179
180         while (isspace(*s)) s++;
181
182         while (*s && (next = ldap_parse_filter(mem_ctx, &s))) {
183                 struct ldap_parse_tree **e;
184                 e = talloc_realloc_p(ret,
185                                      ret->u.list.elements,
186                                      struct ldap_parse_tree *,
187                                      ret->u.list.num_elements+1);
188                 if (!e) {
189                         errno = ENOMEM;
190                         return NULL;
191                 }
192                 ret->u.list.elements = e;
193                 ret->u.list.elements[ret->u.list.num_elements] = next;
194                 ret->u.list.num_elements++;
195                 while (isspace(*s)) s++;
196         }
197
198         return ret;
199 }
200
201
202 /*
203   <not> ::= '!' <filter>
204 */
205 static struct ldap_parse_tree *ldap_parse_not(TALLOC_CTX *mem_ctx, const char *s)
206 {
207         struct ldap_parse_tree *ret;
208
209         ret = talloc(mem_ctx, sizeof(*ret));
210         if (!ret) {
211                 errno = ENOMEM;
212                 return NULL;
213         }
214
215         ret->operation = LDAP_OP_NOT;
216         ret->u.not.child = ldap_parse_filter(mem_ctx, &s);
217         if (!ret->u.not.child)
218                 return NULL;
219
220         return ret;
221 }
222
223 /*
224   parse a filtercomp
225   <filtercomp> ::= <and> | <or> | <not> | <simple>
226 */
227 static struct ldap_parse_tree *ldap_parse_filtercomp(TALLOC_CTX *mem_ctx,
228                                                    const char *s)
229 {
230         while (isspace(*s)) s++;
231
232         switch (*s) {
233         case '&':
234                 return ldap_parse_filterlist(mem_ctx, LDAP_OP_AND, s+1);
235
236         case '|':
237                 return ldap_parse_filterlist(mem_ctx, LDAP_OP_OR, s+1);
238
239         case '!':
240                 return ldap_parse_not(mem_ctx, s+1);
241
242         case '(':
243         case ')':
244                 return NULL;
245         }
246
247         return ldap_parse_simple(mem_ctx, s);
248 }
249
250
251 /*
252   <filter> ::= '(' <filtercomp> ')'
253 */
254 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
255                                                const char **s)
256 {
257         char *l, *s2;
258         const char *p, *p2;
259         struct ldap_parse_tree *ret;
260
261         l = ldap_parse_lex(mem_ctx, s, LDAP_ALL_SEP);
262         if (!l) {
263                 return NULL;
264         }
265
266         if (strcmp(l, "(") != 0) {
267                 return NULL;
268         }
269
270         p = match_brace(*s);
271         if (!p) {
272                 return NULL;
273         }
274         p2 = p + 1;
275
276         s2 = talloc_strndup(mem_ctx, *s, p - *s);
277         if (!s2) {
278                 errno = ENOMEM;
279                 return NULL;
280         }
281
282         ret = ldap_parse_filtercomp(mem_ctx, s2);
283
284         *s = p2;
285
286         return ret;
287 }
288
289 /*
290   main parser entry point. Takes a search string and returns a parse tree
291
292   expression ::= <simple> | <filter>
293 */
294 static struct ldap_parse_tree *ldap_parse_tree(TALLOC_CTX *mem_ctx, const char *s)
295 {
296         while (isspace(*s)) s++;
297
298         if (*s == '(') {
299                 return ldap_parse_filter(mem_ctx, &s);
300         }
301
302         return ldap_parse_simple(mem_ctx, s);
303 }
304
305 static BOOL ldap_push_filter(struct asn1_data *data, struct ldap_parse_tree *tree)
306 {
307         switch (tree->operation) {
308         case LDAP_OP_SIMPLE: {
309                 if ((tree->u.simple.value.length == 1) &&
310                     (((char *)(tree->u.simple.value.data))[0] == '*')) {
311                         /* Just a presence test */
312                         asn1_push_tag(data, 0x87);
313                         asn1_write(data, tree->u.simple.attr,
314                                    strlen(tree->u.simple.attr));
315                         asn1_pop_tag(data);
316                         return !data->has_error;
317                 }
318
319                 /* Equality is all we currently do... */
320                 asn1_push_tag(data, 0xa3);
321                 asn1_write_OctetString(data, tree->u.simple.attr,
322                                       strlen(tree->u.simple.attr));
323                 asn1_write_OctetString(data, tree->u.simple.value.data,
324                                       tree->u.simple.value.length);
325                 asn1_pop_tag(data);
326                 break;
327         }
328
329         case LDAP_OP_AND: {
330                 int i;
331
332                 asn1_push_tag(data, 0xa0);
333                 for (i=0; i<tree->u.list.num_elements; i++) {
334                         ldap_push_filter(data, tree->u.list.elements[i]);
335                 }
336                 asn1_pop_tag(data);
337                 break;
338         }
339
340         case LDAP_OP_OR: {
341                 int i;
342
343                 asn1_push_tag(data, 0xa1);
344                 for (i=0; i<tree->u.list.num_elements; i++) {
345                         ldap_push_filter(data, tree->u.list.elements[i]);
346                 }
347                 asn1_pop_tag(data);
348                 break;
349         }
350         default:
351                 return False;
352         }
353         return !data->has_error;
354 }
355
356 static void ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
357 {
358         asn1_write_enumerated(data, result->resultcode);
359         asn1_write_OctetString(data, result->dn,
360                                (result->dn) ? strlen(result->dn) : 0);
361         asn1_write_OctetString(data, result->errormessage,
362                                (result->errormessage) ?
363                                strlen(result->errormessage) : 0);
364         if (result->referral) {
365                 asn1_push_tag(data, ASN1_CONTEXT(3));
366                 asn1_write_OctetString(data, result->referral,
367                                        strlen(result->referral));
368                 asn1_pop_tag(data);
369         }
370 }
371
372 BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result)
373 {
374         struct asn1_data data;
375         int i, j;
376
377         ZERO_STRUCT(data);
378         asn1_push_tag(&data, ASN1_SEQUENCE(0));
379         asn1_write_Integer(&data, msg->messageid);
380
381         switch (msg->type) {
382         case LDAP_TAG_BindRequest: {
383                 struct ldap_BindRequest *r = &msg->r.BindRequest;
384                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
385                 asn1_write_Integer(&data, r->version);
386                 asn1_write_OctetString(&data, r->dn,
387                                        (r->dn != NULL) ? strlen(r->dn) : 0);
388
389                 switch (r->mechanism) {
390                 case LDAP_AUTH_MECH_SIMPLE:
391                         /* context, primitive */
392                         asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
393                         asn1_write(&data, r->creds.password,
394                                    strlen(r->creds.password));
395                         asn1_pop_tag(&data);
396                         break;
397                 case LDAP_AUTH_MECH_SASL:
398                         /* context, constructed */
399                         asn1_push_tag(&data, ASN1_CONTEXT(3));
400                         asn1_write_OctetString(&data, r->creds.SASL.mechanism,
401                                                strlen(r->creds.SASL.mechanism));
402                         asn1_write_OctetString(&data, r->creds.SASL.secblob.data,
403                                                r->creds.SASL.secblob.length);
404                         asn1_pop_tag(&data);
405                         break;
406                 default:
407                         return False;
408                 }
409
410                 asn1_pop_tag(&data);
411                 asn1_pop_tag(&data);
412                 break;
413         }
414         case LDAP_TAG_BindResponse: {
415                 struct ldap_BindResponse *r = &msg->r.BindResponse;
416                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
417                 ldap_encode_response(&data, &r->response);
418                 if (r->SASL.secblob.length > 0) {
419                         asn1_write_ContextSimple(&data, 7, &r->SASL.secblob);
420                 }
421                 asn1_pop_tag(&data);
422                 break;
423         }
424         case LDAP_TAG_UnbindRequest: {
425 /*              struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
426                 break;
427         }
428         case LDAP_TAG_SearchRequest: {
429                 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
430                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
431                 asn1_write_OctetString(&data, r->basedn, strlen(r->basedn));
432                 asn1_write_enumerated(&data, r->scope);
433                 asn1_write_enumerated(&data, r->deref);
434                 asn1_write_Integer(&data, r->sizelimit);
435                 asn1_write_Integer(&data, r->timelimit);
436                 asn1_write_BOOLEAN(&data, r->attributesonly);
437
438                 {
439                         TALLOC_CTX *mem_ctx = talloc_init("ldap_parse_tree");
440                         struct ldap_parse_tree *tree;
441
442                         if (mem_ctx == NULL)
443                                 return False;
444
445                         tree = ldap_parse_tree(mem_ctx, r->filter);
446
447                         if (tree == NULL)
448                                 return False;
449
450                         ldap_push_filter(&data, tree);
451
452                         talloc_destroy(mem_ctx);
453                 }
454
455                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
456                 for (i=0; i<r->num_attributes; i++) {
457                         asn1_write_OctetString(&data, r->attributes[i],
458                                                strlen(r->attributes[i]));
459                 }
460                 asn1_pop_tag(&data);
461
462                 asn1_pop_tag(&data);
463                 break;
464         }
465         case LDAP_TAG_SearchResultEntry: {
466                 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
467                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
468                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
469                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
470                 for (i=0; i<r->num_attributes; i++) {
471                         struct ldap_attribute *attr = &r->attributes[i];
472                         asn1_push_tag(&data, ASN1_SEQUENCE(0));
473                         asn1_write_OctetString(&data, attr->name,
474                                                strlen(attr->name));
475                         asn1_push_tag(&data, ASN1_SEQUENCE(1));
476                         for (j=0; j<attr->num_values; j++) {
477                                 asn1_write_OctetString(&data,
478                                                        attr->values[j].data,
479                                                        attr->values[j].length);
480                         }
481                         asn1_pop_tag(&data);
482                         asn1_pop_tag(&data);
483                 }
484                 asn1_pop_tag(&data);
485                 asn1_pop_tag(&data);
486                 break;
487         }
488         case LDAP_TAG_SearchResultDone: {
489                 struct ldap_Result *r = &msg->r.SearchResultDone;
490                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
491                 ldap_encode_response(&data, r);
492                 asn1_pop_tag(&data);
493                 break;
494         }
495         case LDAP_TAG_ModifyRequest: {
496                 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
497                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
498                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
499                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
500
501                 for (i=0; i<r->num_mods; i++) {
502                         struct ldap_attribute *attrib = &r->mods[i].attrib;
503                         asn1_push_tag(&data, ASN1_SEQUENCE(0));
504                         asn1_write_enumerated(&data, r->mods[i].type);
505                         asn1_push_tag(&data, ASN1_SEQUENCE(0));
506                         asn1_write_OctetString(&data, attrib->name,
507                                                strlen(attrib->name));
508                         asn1_push_tag(&data, ASN1_SET);
509                         for (j=0; j<attrib->num_values; j++) {
510                                 asn1_write_OctetString(&data,
511                                                        attrib->values[j].data,
512                                                        attrib->values[j].length);
513         
514                         }
515                         asn1_pop_tag(&data);
516                         asn1_pop_tag(&data);
517                         asn1_pop_tag(&data);
518                 }
519                 
520                 asn1_pop_tag(&data);
521                 asn1_pop_tag(&data);
522                 break;
523         }
524         case LDAP_TAG_ModifyResponse: {
525                 struct ldap_Result *r = &msg->r.ModifyResponse;
526                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
527                 ldap_encode_response(&data, r);
528                 asn1_pop_tag(&data);
529                 break;
530         }
531         case LDAP_TAG_AddRequest: {
532                 struct ldap_AddRequest *r = &msg->r.AddRequest;
533                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
534                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
535                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
536
537                 for (i=0; i<r->num_attributes; i++) {
538                         struct ldap_attribute *attrib = &r->attributes[i];
539                         asn1_push_tag(&data, ASN1_SEQUENCE(0));
540                         asn1_write_OctetString(&data, attrib->name,
541                                                strlen(attrib->name));
542                         asn1_push_tag(&data, ASN1_SET);
543                         for (j=0; j<r->attributes[i].num_values; j++) {
544                                 asn1_write_OctetString(&data,
545                                                        attrib->values[j].data,
546                                                        attrib->values[j].length);
547                         }
548                         asn1_pop_tag(&data);
549                         asn1_pop_tag(&data);
550                 }
551                 asn1_pop_tag(&data);
552                 asn1_pop_tag(&data);
553                 break;
554         }
555         case LDAP_TAG_AddResponse: {
556                 struct ldap_Result *r = &msg->r.AddResponse;
557                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
558                 ldap_encode_response(&data, r);
559                 asn1_pop_tag(&data);
560                 break;
561         }
562         case LDAP_TAG_DelRequest: {
563                 struct ldap_DelRequest *r = &msg->r.DelRequest;
564                 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
565                 asn1_write(&data, r->dn, strlen(r->dn));
566                 asn1_pop_tag(&data);
567                 break;
568         }
569         case LDAP_TAG_DelResponse: {
570                 struct ldap_Result *r = &msg->r.DelResponse;
571                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
572                 ldap_encode_response(&data, r);
573                 asn1_pop_tag(&data);
574                 break;
575         }
576         case LDAP_TAG_ModifyDNRequest: {
577                 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
578                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
579                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
580                 asn1_write_OctetString(&data, r->newrdn, strlen(r->newrdn));
581                 asn1_write_BOOLEAN(&data, r->deleteolddn);
582                 if (r->newsuperior != NULL) {
583                         asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
584                         asn1_write(&data, r->newsuperior,
585                                    strlen(r->newsuperior));
586                         asn1_pop_tag(&data);
587                 }
588                 asn1_pop_tag(&data);
589                 break;
590         }
591         case LDAP_TAG_ModifyDNResponse: {
592                 struct ldap_Result *r = &msg->r.ModifyDNResponse;
593                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
594                 ldap_encode_response(&data, r);
595                 asn1_pop_tag(&data);
596                 break;
597         }
598         case LDAP_TAG_CompareRequest: {
599                 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
600                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
601                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
602                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
603                 asn1_write_OctetString(&data, r->attribute,
604                                        strlen(r->attribute));
605                 asn1_write_OctetString(&data, r->value.data,
606                                        r->value.length);
607                 asn1_pop_tag(&data);
608                 asn1_pop_tag(&data);
609                 break;
610         }
611         case LDAP_TAG_CompareResponse: {
612                 struct ldap_Result *r = &msg->r.ModifyDNResponse;
613                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
614                 ldap_encode_response(&data, r);
615                 asn1_pop_tag(&data);
616                 break;
617         }
618         case LDAP_TAG_AbandonRequest: {
619                 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
620                 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
621                 asn1_write_implicit_Integer(&data, r->messageid);
622                 asn1_pop_tag(&data);
623                 break;
624         }
625         case LDAP_TAG_SearchResultReference: {
626                 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
627                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
628                 asn1_write_OctetString(&data, r->referral, strlen(r->referral));
629                 asn1_pop_tag(&data);
630                 break;
631         }
632         case LDAP_TAG_ExtendedRequest: {
633                 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
634                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
635                 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
636                 asn1_write(&data, r->oid, strlen(r->oid));
637                 asn1_pop_tag(&data);
638                 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(1));
639                 asn1_write(&data, r->value.data, r->value.length);
640                 asn1_pop_tag(&data);
641                 asn1_pop_tag(&data);
642                 break;
643         }
644         case LDAP_TAG_ExtendedResponse: {
645                 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
646                 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
647                 ldap_encode_response(&data, &r->response);
648                 asn1_pop_tag(&data);
649                 break;
650         }
651         default:
652                 return False;
653         }
654
655         asn1_pop_tag(&data);
656         *result = data_blob(data.data, data.length);
657         asn1_free(&data);
658         return True;
659 }
660
661 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
662                                       DATA_BLOB blob)
663 {
664         char *result = talloc(mem_ctx, blob.length+1);
665         memcpy(result, blob.data, blob.length);
666         result[blob.length] = '\0';
667         return result;
668 }
669
670 static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
671                                          struct asn1_data *data,
672                                          const char **result)
673 {
674         DATA_BLOB string;
675         if (!asn1_read_OctetString(data, &string))
676                 return False;
677         *result = blob2string_talloc(mem_ctx, string);
678         data_blob_free(&string);
679         return True;
680 }
681
682 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
683                                  struct asn1_data *data,
684                                  struct ldap_Result *result)
685 {
686         asn1_read_enumerated(data, &result->resultcode);
687         asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
688         asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
689         if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
690                 asn1_start_tag(data, ASN1_CONTEXT(3));
691                 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
692                 asn1_end_tag(data);
693         } else {
694                 result->referral = NULL;
695         }
696 }
697
698 static BOOL ldap_decode_filter(TALLOC_CTX *mem_ctx, struct asn1_data *data,
699                                char **filter)
700 {
701         uint8 filter_tag, tag_desc;
702
703         if (!asn1_peek_uint8(data, &filter_tag))
704                 return False;
705
706         tag_desc = filter_tag;
707         filter_tag &= 0x1f;     /* strip off the asn1 stuff */
708         tag_desc &= 0xe0;
709
710         switch(filter_tag) {
711         case 0: {
712                 /* AND of one or more filters */
713                 if (tag_desc != 0xa0) /* context compount */
714                         return False;
715
716                 asn1_start_tag(data, ASN1_CONTEXT(0));
717
718                 *filter = talloc_strdup(mem_ctx, "(&");
719                 if (*filter == NULL)
720                         return False;
721
722                 while (asn1_tag_remaining(data) > 0) {
723                         char *subfilter;
724                         if (!ldap_decode_filter(mem_ctx, data, &subfilter))
725                                 return False;
726                         *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
727                                                   subfilter);
728                         if (*filter == NULL)
729                                 return False;
730                 }
731                 asn1_end_tag(data);
732
733                 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
734                 break;
735         }
736         case 1: {
737                 /* OR of one or more filters */
738                 if (tag_desc != 0xa0) /* context compount */
739                         return False;
740
741                 asn1_start_tag(data, ASN1_CONTEXT(1));
742
743                 *filter = talloc_strdup(mem_ctx, "(|");
744                 if (*filter == NULL)
745                         return False;
746
747                 while (asn1_tag_remaining(data) > 0) {
748                         char *subfilter;
749                         if (!ldap_decode_filter(mem_ctx, data, &subfilter))
750                                 return False;
751                         *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
752                                                   subfilter);
753                         if (*filter == NULL)
754                                 return False;
755                 }
756
757                 asn1_end_tag(data);
758
759                 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
760                 break;
761         }
762         case 3: {
763                 /* equalityMatch */
764                 const char *attrib, *value;
765                 if (tag_desc != 0xa0) /* context compound */
766                         return False;
767                 asn1_start_tag(data, ASN1_CONTEXT(3));
768                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
769                 asn1_read_OctetString_talloc(mem_ctx, data, &value);
770                 asn1_end_tag(data);
771                 if ((data->has_error) || (attrib == NULL) || (value == NULL))
772                         return False;
773                 *filter = talloc_asprintf(mem_ctx, "(%s=%s)", attrib, value);
774                 break;
775         }
776         case 7: {
777                 /* Normal presence, "attribute=*" */
778                 int attr_len;
779                 char *attr_name;
780                 if (tag_desc != 0x80) /* context simple */
781                         return False;
782                 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(7)))
783                         return False;
784                 attr_len = asn1_tag_remaining(data);
785                 attr_name = malloc(attr_len+1);
786                 if (attr_name == NULL)
787                         return False;
788                 asn1_read(data, attr_name, attr_len);
789                 attr_name[attr_len] = '\0';
790                 *filter = talloc_asprintf(mem_ctx, "(%s=*)", attr_name);
791                 SAFE_FREE(attr_name);
792                 asn1_end_tag(data);
793                 break;
794         }
795         default:
796                 return False;
797         }
798         if (*filter == NULL)
799                 return False;
800         return True;
801 }
802
803 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
804                                struct ldap_attribute *attrib)
805 {
806         asn1_start_tag(data, ASN1_SEQUENCE(0));
807         asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
808         asn1_start_tag(data, ASN1_SET);
809         while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
810                 DATA_BLOB blob;
811                 struct ldap_val value;
812                 asn1_read_OctetString(data, &blob);
813                 value.data = blob.data;
814                 value.length = blob.length;
815                 add_value_to_attrib(mem_ctx, &value, attrib);
816                 data_blob_free(&blob);
817         }
818         asn1_end_tag(data);
819         asn1_end_tag(data);
820         
821 }
822
823 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
824                                 struct ldap_attribute **attributes,
825                                 int *num_attributes)
826 {
827         asn1_start_tag(data, ASN1_SEQUENCE(0));
828         while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
829                 struct ldap_attribute attrib;
830                 ZERO_STRUCT(attrib);
831                 ldap_decode_attrib(mem_ctx, data, &attrib);
832                 add_attrib_to_array_talloc(mem_ctx, &attrib,
833                                            attributes, num_attributes);
834         }
835         asn1_end_tag(data);
836 }
837
838 BOOL ldap_decode(struct asn1_data *data, struct ldap_message *msg)
839 {
840         uint8 tag;
841
842         asn1_start_tag(data, ASN1_SEQUENCE(0));
843         asn1_read_Integer(data, &msg->messageid);
844
845         if (!asn1_peek_uint8(data, &tag))
846                 return False;
847
848         switch(tag) {
849
850         case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
851                 struct ldap_BindRequest *r = &msg->r.BindRequest;
852                 msg->type = LDAP_TAG_BindRequest;
853                 asn1_start_tag(data, tag);
854                 asn1_read_Integer(data, &r->version);
855                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
856                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
857                         int pwlen;
858                         r->creds.password = "";
859                         r->mechanism = LDAP_AUTH_MECH_SIMPLE;
860                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
861                         pwlen = asn1_tag_remaining(data);
862                         if (pwlen != 0) {
863                                 char *pw = talloc(msg->mem_ctx, pwlen+1);
864                                 asn1_read(data, pw, pwlen);
865                                 pw[pwlen] = '\0';
866                                 r->creds.password = pw;
867                         }
868                         asn1_end_tag(data);
869                 } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
870                         asn1_start_tag(data, ASN1_CONTEXT(3));
871                         r->mechanism = LDAP_AUTH_MECH_SASL;
872                         asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->creds.SASL.mechanism);
873                         asn1_read_OctetString(data, &r->creds.SASL.secblob);
874                         if (r->creds.SASL.secblob.data) {
875                                 talloc_steal(msg->mem_ctx, r->creds.SASL.secblob.data);
876                         }
877                         asn1_end_tag(data);
878                 }
879                 asn1_end_tag(data);
880                 break;
881         }
882
883         case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
884                 struct ldap_BindResponse *r = &msg->r.BindResponse;
885                 msg->type = LDAP_TAG_BindResponse;
886                 asn1_start_tag(data, tag);
887                 ldap_decode_response(msg->mem_ctx, data, &r->response);
888                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
889                         DATA_BLOB tmp_blob = data_blob(NULL, 0);
890                         asn1_read_ContextSimple(data, 7, &tmp_blob);
891                         r->SASL.secblob = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
892                         data_blob_free(&tmp_blob);
893                 } else {
894                         r->SASL.secblob = data_blob(NULL, 0);
895                 }
896                 asn1_end_tag(data);
897                 break;
898         }
899
900         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
901                 msg->type = LDAP_TAG_UnbindRequest;
902                 asn1_start_tag(data, tag);
903                 asn1_end_tag(data);
904                 break;
905         }
906
907         case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
908                 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
909                 msg->type = LDAP_TAG_SearchRequest;
910                 asn1_start_tag(data, tag);
911                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->basedn);
912                 asn1_read_enumerated(data, (int *)&(r->scope));
913                 asn1_read_enumerated(data, (int *)&(r->deref));
914                 asn1_read_Integer(data, &r->sizelimit);
915                 asn1_read_Integer(data, &r->timelimit);
916                 asn1_read_BOOLEAN(data, &r->attributesonly);
917
918                 /* Maybe create a TALLOC_CTX for the filter? This can waste
919                  * quite a bit of memory recursing down. */
920                 ldap_decode_filter(msg->mem_ctx, data, &r->filter);
921
922                 asn1_start_tag(data, ASN1_SEQUENCE(0));
923
924                 r->num_attributes = 0;
925                 r->attributes = NULL;
926
927                 while (asn1_tag_remaining(data) > 0) {
928                         const char *attr;
929                         if (!asn1_read_OctetString_talloc(msg->mem_ctx, data,
930                                                           &attr))
931                                 return False;
932                         if (!add_string_to_array(msg->mem_ctx, attr,
933                                                  &r->attributes,
934                                                  &r->num_attributes))
935                                 return False;
936                 }
937
938                 asn1_end_tag(data);
939                 asn1_end_tag(data);
940                 break;
941         }
942
943         case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
944                 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
945                 msg->type = LDAP_TAG_SearchResultEntry;
946                 r->attributes = NULL;
947                 r->num_attributes = 0;
948                 asn1_start_tag(data, tag);
949                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
950                 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
951                                     &r->num_attributes);
952                 asn1_end_tag(data);
953                 break;
954         }
955
956         case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
957                 struct ldap_Result *r = &msg->r.SearchResultDone;
958                 msg->type = LDAP_TAG_SearchResultDone;
959                 asn1_start_tag(data, tag);
960                 ldap_decode_response(msg->mem_ctx, data, r);
961                 asn1_end_tag(data);
962                 break;
963         }
964
965         case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
966                 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
967                 msg->type = LDAP_TAG_SearchResultReference;
968                 asn1_start_tag(data, tag);
969                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->referral);
970                 asn1_end_tag(data);
971                 break;
972         }
973
974         case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
975                 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
976                 msg->type = LDAP_TAG_ModifyRequest;
977                 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
978                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
979                 asn1_start_tag(data, ASN1_SEQUENCE(0));
980
981                 r->num_mods = 0;
982                 r->mods = NULL;
983
984                 while (asn1_tag_remaining(data) > 0) {
985                         struct ldap_mod mod;
986                         int v;
987                         ZERO_STRUCT(mod);
988                         asn1_start_tag(data, ASN1_SEQUENCE(0));
989                         asn1_read_enumerated(data, &v);
990                         mod.type = v;
991                         ldap_decode_attrib(msg->mem_ctx, data, &mod.attrib);
992                         asn1_end_tag(data);
993                         if (!add_mod_to_array_talloc(msg->mem_ctx, &mod,
994                                                      &r->mods, &r->num_mods))
995                                 break;
996                 }
997
998                 asn1_end_tag(data);
999                 asn1_end_tag(data);
1000                 break;
1001         }
1002
1003         case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
1004                 struct ldap_Result *r = &msg->r.ModifyResponse;
1005                 msg->type = LDAP_TAG_ModifyResponse;
1006                 asn1_start_tag(data, tag);
1007                 ldap_decode_response(msg->mem_ctx, data, r);
1008                 asn1_end_tag(data);
1009                 break;
1010         }
1011
1012         case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
1013                 struct ldap_AddRequest *r = &msg->r.AddRequest;
1014                 msg->type = LDAP_TAG_AddRequest;
1015                 asn1_start_tag(data, tag);
1016                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1017
1018                 r->attributes = NULL;
1019                 r->num_attributes = 0;
1020                 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
1021                                     &r->num_attributes);
1022
1023                 asn1_end_tag(data);
1024                 break;
1025         }
1026
1027         case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1028                 struct ldap_Result *r = &msg->r.AddResponse;
1029                 msg->type = LDAP_TAG_AddResponse;
1030                 asn1_start_tag(data, tag);
1031                 ldap_decode_response(msg->mem_ctx, data, r);
1032                 asn1_end_tag(data);
1033                 break;
1034         }
1035
1036         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1037                 struct ldap_DelRequest *r = &msg->r.DelRequest;
1038                 int len;
1039                 char *dn;
1040                 msg->type = LDAP_TAG_DelRequest;
1041                 asn1_start_tag(data,
1042                                ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1043                 len = asn1_tag_remaining(data);
1044                 dn = talloc(msg->mem_ctx, len+1);
1045                 if (dn == NULL)
1046                         break;
1047                 asn1_read(data, dn, len);
1048                 dn[len] = '\0';
1049                 r->dn = dn;
1050                 asn1_end_tag(data);
1051                 break;
1052         }
1053
1054         case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1055                 struct ldap_Result *r = &msg->r.DelResponse;
1056                 msg->type = LDAP_TAG_DelResponse;
1057                 asn1_start_tag(data, tag);
1058                 ldap_decode_response(msg->mem_ctx, data, r);
1059                 asn1_end_tag(data);
1060                 break;
1061         }
1062
1063         case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1064                 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
1065                 msg->type = LDAP_TAG_ModifyDNRequest;
1066                 asn1_start_tag(data,
1067                                ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
1068                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1069                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->newrdn);
1070                 asn1_read_BOOLEAN(data, &r->deleteolddn);
1071                 r->newsuperior = NULL;
1072                 if (asn1_tag_remaining(data) > 0) {
1073                         int len;
1074                         char *newsup;
1075                         asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1076                         len = asn1_tag_remaining(data);
1077                         newsup = talloc(msg->mem_ctx, len+1);
1078                         if (newsup == NULL)
1079                                 break;
1080                         asn1_read(data, newsup, len);
1081                         newsup[len] = '\0';
1082                         r->newsuperior = newsup;
1083                         asn1_end_tag(data);
1084                 }
1085                 asn1_end_tag(data);
1086                 break;
1087         }
1088
1089         case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1090                 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1091                 msg->type = LDAP_TAG_ModifyDNResponse;
1092                 asn1_start_tag(data, tag);
1093                 ldap_decode_response(msg->mem_ctx, data, r);
1094                 asn1_end_tag(data);
1095                 break;
1096         }
1097
1098         case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1099                 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
1100                 msg->type = LDAP_TAG_CompareRequest;
1101                 asn1_start_tag(data,
1102                                ASN1_APPLICATION(LDAP_TAG_CompareRequest));
1103                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1104                 asn1_start_tag(data, ASN1_SEQUENCE(0));
1105                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->attribute);
1106                 asn1_read_OctetString(data, &r->value);
1107                 if (r->value.data) {
1108                         talloc_steal(msg->mem_ctx, r->value.data);
1109                 }
1110                 asn1_end_tag(data);
1111                 asn1_end_tag(data);
1112                 break;
1113         }
1114
1115         case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1116                 struct ldap_Result *r = &msg->r.CompareResponse;
1117                 msg->type = LDAP_TAG_CompareResponse;
1118                 asn1_start_tag(data, tag);
1119                 ldap_decode_response(msg->mem_ctx, data, r);
1120                 asn1_end_tag(data);
1121                 break;
1122         }
1123
1124         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
1125                 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
1126                 msg->type = LDAP_TAG_AbandonRequest;
1127                 asn1_start_tag(data, tag);
1128                 asn1_read_implicit_Integer(data, &r->messageid);
1129                 asn1_end_tag(data);
1130                 break;
1131         }
1132
1133         case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1134                 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1135                 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1136
1137                 msg->type = LDAP_TAG_ExtendedRequest;
1138                 asn1_start_tag(data,tag);
1139                 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
1140                         return False;
1141                 }
1142                 r->oid = blob2string_talloc(msg->mem_ctx, tmp_blob);
1143                 data_blob_free(&tmp_blob);
1144                 if (!r->oid) {
1145                         return False;
1146                 }
1147
1148                 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
1149                         asn1_read_ContextSimple(data, 1, &tmp_blob);
1150                         r->value = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
1151                         data_blob_free(&tmp_blob);
1152                 } else {
1153                         r->value = data_blob(NULL, 0);
1154                 }
1155
1156                 asn1_end_tag(data);
1157                 break;
1158         }
1159
1160         case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1161                 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1162                 msg->type = LDAP_TAG_ExtendedResponse;
1163                 asn1_start_tag(data, tag);              
1164                 ldap_decode_response(msg->mem_ctx, data, &r->response);
1165                 /* I have to come across an operation that actually sends
1166                  * something back to really see what's going on. The currently
1167                  * needed pwdchange does not send anything back. */
1168                 r->name = NULL;
1169                 r->value.data = NULL;
1170                 r->value.length = 0;
1171                 asn1_end_tag(data);
1172                 break;
1173         }
1174         default: 
1175                 return False;
1176         }
1177
1178         msg->num_controls = 0;
1179         msg->controls = NULL;
1180
1181         if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
1182                 int i;
1183                 struct ldap_Control *ctrl = NULL;
1184
1185                 asn1_start_tag(data, ASN1_CONTEXT(0));
1186
1187                 for (i=0; asn1_peek_tag(data, ASN1_SEQUENCE(0)); i++) {
1188                         asn1_start_tag(data, ASN1_SEQUENCE(0));
1189
1190                         ctrl = talloc_realloc_p(msg->mem_ctx, ctrl, struct ldap_Control, i+1);
1191                         if (!ctrl) {
1192                                 return False;
1193                         }
1194                         ctrl[i].oid = NULL;
1195                         ctrl[i].critical = False;
1196                         ctrl[i].value = data_blob(NULL, 0);
1197
1198                         asn1_read_OctetString_talloc(ctrl, data, &ctrl[i].oid);
1199
1200                         if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
1201                                 asn1_read_BOOLEAN(data, &ctrl[i].critical);
1202                         }
1203
1204                         if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
1205                                 asn1_read_OctetString(data, &ctrl[i].value);
1206                                 if (ctrl[i].value.data) {
1207                                         talloc_steal(msg->mem_ctx, ctrl[i].value.data);
1208                                 }
1209                         }
1210
1211                         asn1_end_tag(data);
1212                 }
1213                 msg->num_controls = i;
1214                 msg->controls = ctrl;
1215
1216                 asn1_end_tag(data);
1217         }
1218
1219         asn1_end_tag(data);
1220         return ((!data->has_error) && (data->nesting == NULL));
1221 }
1222
1223 BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
1224                           char **host, uint16 *port, BOOL *ldaps)
1225 {
1226         int tmp_port = 0;
1227         char protocol[11];
1228         char tmp_host[255];
1229         const char *p = url;
1230         int ret;
1231
1232         /* skip leading "URL:" (if any) */
1233         if (strncasecmp( p, "URL:", 4) == 0) {
1234                 p += 4;
1235         }
1236
1237         /* Paranoia check */
1238         SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
1239                 
1240         ret = sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
1241         if (ret < 2) {
1242                 return False;
1243         }
1244
1245         if (strequal(protocol, "ldap")) {
1246                 *port = 389;
1247                 *ldaps = False;
1248         } else if (strequal(protocol, "ldaps")) {
1249                 *port = 636;
1250                 *ldaps = True;
1251         } else {
1252                 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
1253                 return False;
1254         }
1255
1256         if (tmp_port != 0)
1257                 *port = tmp_port;
1258
1259         *host = talloc_strdup(mem_ctx, tmp_host);
1260
1261         return (*host != NULL);
1262 }