r1802: start to support SASL in our ldap libraries
[kai/samba.git] / source4 / libcli / ldap / ldap.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    
5    Copyright (C) Andrew Tridgell  2004
6    Copyright (C) Volker Lendecke 2004
7     
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21    
22 */
23
24 #include "includes.h"
25
26 /****************************************************************************
27  *
28  * LDAP filter parser -- main routine is ldap_parse_filter
29  *
30  * Shamelessly stolen and adapted from ldb.
31  *
32  ***************************************************************************/
33
34 /* Hmm. A blob might be more appropriate here :-) */
35
36 struct ldap_val {
37         unsigned int length;
38         void *data;
39 };
40
41 enum ldap_parse_op {LDAP_OP_SIMPLE, LDAP_OP_AND, LDAP_OP_OR, LDAP_OP_NOT};
42
43 struct ldap_parse_tree {
44         enum ldap_parse_op operation;
45         union {
46                 struct {
47                         char *attr;
48                         struct ldap_val value;
49                 } simple;
50                 struct {
51                         unsigned int num_elements;
52                         struct ldap_parse_tree **elements;
53                 } list;
54                 struct {
55                         struct ldap_parse_tree *child;
56                 } not;
57         } u;
58 };
59
60 #define LDAP_ALL_SEP "()&|=!"
61 #define LDAP_CONNECTION_TIMEOUT 10000
62
63 /*
64   return next token element. Caller frees
65 */
66 static char *ldap_parse_lex(TALLOC_CTX *mem_ctx, const char **s,
67                            const char *sep)
68 {
69         const char *p = *s;
70         char *ret;
71
72         while (isspace(*p)) {
73                 p++;
74         }
75         *s = p;
76
77         if (*p == 0) {
78                 return NULL;
79         }
80
81         if (strchr(sep, *p)) {
82                 (*s) = p+1;
83                 ret = talloc_strndup(mem_ctx, p, 1);
84                 if (!ret) {
85                         errno = ENOMEM;
86                 }
87                 return ret;
88         }
89
90         while (*p && (isalnum(*p) || !strchr(sep, *p))) {
91                 p++;
92         }
93
94         if (p == *s) {
95                 return NULL;
96         }
97
98         ret = talloc_strndup(mem_ctx, *s, p - *s);
99         if (!ret) {
100                 errno = ENOMEM;
101         }
102
103         *s = p;
104
105         return ret;
106 }
107
108
109 /*
110   find a matching close brace in a string
111 */
112 static const char *match_brace(const char *s)
113 {
114         unsigned int count = 0;
115         while (*s && (count != 0 || *s != ')')) {
116                 if (*s == '(') {
117                         count++;
118                 }
119                 if (*s == ')') {
120                         count--;
121                 }
122                 s++;
123         }
124         if (! *s) {
125                 return NULL;
126         }
127         return s;
128 }
129
130 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
131                                                const char **s);
132
133 /*
134   <simple> ::= <attributetype> <filtertype> <attributevalue>
135 */
136 static struct ldap_parse_tree *ldap_parse_simple(TALLOC_CTX *mem_ctx,
137                                                const char *s)
138 {
139         char *eq, *val, *l;
140         struct ldap_parse_tree *ret;
141
142         l = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
143         if (!l) {
144                 return NULL;
145         }
146
147         if (strchr("()&|=", *l))
148                 return NULL;
149
150         eq = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
151         if (!eq || strcmp(eq, "=") != 0)
152                 return NULL;
153
154         val = ldap_parse_lex(mem_ctx, &s, ")");
155         if (val && strchr("()&|", *val))
156                 return NULL;
157         
158         ret = talloc(mem_ctx, sizeof(*ret));
159         if (!ret) {
160                 errno = ENOMEM;
161                 return NULL;
162         }
163
164         ret->operation = LDAP_OP_SIMPLE;
165         ret->u.simple.attr = l;
166         ret->u.simple.value.data = val;
167         ret->u.simple.value.length = val?strlen(val):0;
168
169         return ret;
170 }
171
172
173 /*
174   parse a filterlist
175   <and> ::= '&' <filterlist>
176   <or> ::= '|' <filterlist>
177   <filterlist> ::= <filter> | <filter> <filterlist>
178 */
179 static struct ldap_parse_tree *ldap_parse_filterlist(TALLOC_CTX *mem_ctx,
180                                                    enum ldap_parse_op op,
181                                                    const char *s)
182 {
183         struct ldap_parse_tree *ret, *next;
184
185         ret = talloc(mem_ctx, sizeof(*ret));
186
187         if (!ret) {
188                 errno = ENOMEM;
189                 return NULL;
190         }
191
192         ret->operation = op;
193         ret->u.list.num_elements = 1;
194         ret->u.list.elements = talloc(mem_ctx, sizeof(*ret->u.list.elements));
195         if (!ret->u.list.elements) {
196                 errno = ENOMEM;
197                 return NULL;
198         }
199
200         ret->u.list.elements[0] = ldap_parse_filter(mem_ctx, &s);
201         if (!ret->u.list.elements[0]) {
202                 return NULL;
203         }
204
205         while (isspace(*s)) s++;
206
207         while (*s && (next = ldap_parse_filter(mem_ctx, &s))) {
208                 struct ldap_parse_tree **e;
209                 e = talloc_realloc(mem_ctx, ret->u.list.elements,
210                                    sizeof(struct ldap_parse_tree) *
211                                    (ret->u.list.num_elements+1));
212                 if (!e) {
213                         errno = ENOMEM;
214                         return NULL;
215                 }
216                 ret->u.list.elements = e;
217                 ret->u.list.elements[ret->u.list.num_elements] = next;
218                 ret->u.list.num_elements++;
219                 while (isspace(*s)) s++;
220         }
221
222         return ret;
223 }
224
225
226 /*
227   <not> ::= '!' <filter>
228 */
229 static struct ldap_parse_tree *ldap_parse_not(TALLOC_CTX *mem_ctx, const char *s)
230 {
231         struct ldap_parse_tree *ret;
232
233         ret = talloc(mem_ctx, sizeof(*ret));
234         if (!ret) {
235                 errno = ENOMEM;
236                 return NULL;
237         }
238
239         ret->operation = LDAP_OP_NOT;
240         ret->u.not.child = ldap_parse_filter(mem_ctx, &s);
241         if (!ret->u.not.child)
242                 return NULL;
243
244         return ret;
245 }
246
247 /*
248   parse a filtercomp
249   <filtercomp> ::= <and> | <or> | <not> | <simple>
250 */
251 static struct ldap_parse_tree *ldap_parse_filtercomp(TALLOC_CTX *mem_ctx,
252                                                    const char *s)
253 {
254         while (isspace(*s)) s++;
255
256         switch (*s) {
257         case '&':
258                 return ldap_parse_filterlist(mem_ctx, LDAP_OP_AND, s+1);
259
260         case '|':
261                 return ldap_parse_filterlist(mem_ctx, LDAP_OP_OR, s+1);
262
263         case '!':
264                 return ldap_parse_not(mem_ctx, s+1);
265
266         case '(':
267         case ')':
268                 return NULL;
269         }
270
271         return ldap_parse_simple(mem_ctx, s);
272 }
273
274
275 /*
276   <filter> ::= '(' <filtercomp> ')'
277 */
278 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
279                                                const char **s)
280 {
281         char *l, *s2;
282         const char *p, *p2;
283         struct ldap_parse_tree *ret;
284
285         l = ldap_parse_lex(mem_ctx, s, LDAP_ALL_SEP);
286         if (!l) {
287                 return NULL;
288         }
289
290         if (strcmp(l, "(") != 0) {
291                 return NULL;
292         }
293
294         p = match_brace(*s);
295         if (!p) {
296                 return NULL;
297         }
298         p2 = p + 1;
299
300         s2 = talloc_strndup(mem_ctx, *s, p - *s);
301         if (!s2) {
302                 errno = ENOMEM;
303                 return NULL;
304         }
305
306         ret = ldap_parse_filtercomp(mem_ctx, s2);
307
308         *s = p2;
309
310         return ret;
311 }
312
313 /*
314   main parser entry point. Takes a search string and returns a parse tree
315
316   expression ::= <simple> | <filter>
317 */
318 static struct ldap_parse_tree *ldap_parse_tree(TALLOC_CTX *mem_ctx, const char *s)
319 {
320         while (isspace(*s)) s++;
321
322         if (*s == '(') {
323                 return ldap_parse_filter(mem_ctx, &s);
324         }
325
326         return ldap_parse_simple(mem_ctx, s);
327 }
328
329 static BOOL ldap_push_filter(ASN1_DATA *data, struct ldap_parse_tree *tree)
330 {
331         switch (tree->operation) {
332         case LDAP_OP_SIMPLE: {
333                 if ((tree->u.simple.value.length == 1) &&
334                     (((char *)(tree->u.simple.value.data))[0] == '*')) {
335                         /* Just a presence test */
336                         asn1_push_tag(data, 0x87);
337                         asn1_write(data, tree->u.simple.attr,
338                                    strlen(tree->u.simple.attr));
339                         asn1_pop_tag(data);
340                         return !data->has_error;
341                 }
342
343                 /* Equality is all we currently do... */
344                 asn1_push_tag(data, 0xa3);
345                 asn1_write_OctetString(data, tree->u.simple.attr,
346                                       strlen(tree->u.simple.attr));
347                 asn1_write_OctetString(data, tree->u.simple.value.data,
348                                       tree->u.simple.value.length);
349                 asn1_pop_tag(data);
350                 break;
351         }
352
353         case LDAP_OP_AND: {
354                 int i;
355
356                 asn1_push_tag(data, 0xa0);
357                 for (i=0; i<tree->u.list.num_elements; i++) {
358                         ldap_push_filter(data, tree->u.list.elements[i]);
359                 }
360                 asn1_pop_tag(data);
361                 break;
362         }
363
364         case LDAP_OP_OR: {
365                 int i;
366
367                 asn1_push_tag(data, 0xa1);
368                 for (i=0; i<tree->u.list.num_elements; i++) {
369                         ldap_push_filter(data, tree->u.list.elements[i]);
370                 }
371                 asn1_pop_tag(data);
372                 break;
373         }
374         default:
375                 return False;
376         }
377         return !data->has_error;
378 }
379
380 /****************************************************************************
381  *
382  * LDIF parser
383  *
384  * Shamelessly stolen and adapted from Samba 4.
385  *
386  ***************************************************************************/
387
388 /*
389   pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
390   this routine removes any RFC2849 continuations and comments
391
392   caller frees
393 */
394 static char *next_chunk(TALLOC_CTX *mem_ctx,
395                         int (*fgetc_fn)(void *), void *private_data)
396 {
397         size_t alloc_size=0, chunk_size = 0;
398         char *chunk = NULL;
399         int c;
400         int in_comment = 0;
401
402         while ((c = fgetc_fn(private_data)) != EOF) {
403                 if (chunk_size+1 >= alloc_size) {
404                         char *c2;
405                         alloc_size += 1024;
406                         c2 = talloc_realloc(mem_ctx, chunk, alloc_size);
407                         if (!c2) {
408                                 errno = ENOMEM;
409                                 return NULL;
410                         }
411                         chunk = c2;
412                 }
413
414                 if (in_comment) {
415                         if (c == '\n') {
416                                 in_comment = 0;
417                         }
418                         continue;                       
419                 }
420                 
421                 /* handle continuation lines - see RFC2849 */
422                 if (c == ' ' && chunk_size > 1 &&
423                     chunk[chunk_size-1] == '\n') {
424                         chunk_size--;
425                         continue;
426                 }
427                 
428                 /* chunks are terminated by a double line-feed */
429                 if (c == '\n' && chunk_size > 0 &&
430                     chunk[chunk_size-1] == '\n') {
431                         chunk[chunk_size-1] = 0;
432                         return chunk;
433                 }
434
435                 if (c == '#' &&
436                     (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
437                         in_comment = 1;
438                         continue;
439                 }
440
441                 /* ignore leading blank lines */
442                 if (chunk_size == 0 && c == '\n') {
443                         continue;
444                 }
445
446                 chunk[chunk_size++] = c;
447         }
448
449         if (chunk) {
450                 chunk[chunk_size] = 0;
451         }
452
453         return chunk;
454 }
455
456 /* simple ldif attribute parser */
457 static int next_attr(char **s, const char **attr, struct ldap_val *value)
458 {
459         char *p;
460         int base64_encoded = 0;
461
462         if (strncmp(*s, "-\n", 2) == 0) {
463                 value->length = 0;
464                 *attr = "-";
465                 *s += 2;
466                 return 0;
467         }
468
469         p = strchr(*s, ':');
470         if (!p) {
471                 return -1;
472         }
473
474         *p++ = 0;
475
476         if (*p == ':') {
477                 base64_encoded = 1;
478                 p++;
479         }
480
481         *attr = *s;
482
483         while (isspace(*p)) {
484                 p++;
485         }
486
487         value->data = p;
488
489         p = strchr(p, '\n');
490
491         if (!p) {
492                 value->length = strlen((char *)value->data);
493                 *s = ((char *)value->data) + value->length;
494         } else {
495                 value->length = p - (char *)value->data;
496                 *s = p+1;
497                 *p = 0;
498         }
499
500         if (base64_encoded) {
501                 DATA_BLOB blob = base64_decode_data_blob(value->data);
502                 memcpy(value->data, blob.data, blob.length);
503                 value->length = blob.length;
504                 ((char *)value->data)[value->length] = '\0';
505         }
506
507         return 0;
508 }
509
510 static BOOL add_value_to_attrib(TALLOC_CTX *mem_ctx, struct ldap_val *value,
511                                 struct ldap_attribute *attrib)
512 {
513         attrib->values = talloc_realloc(mem_ctx, attrib->values,
514                                         sizeof(*attrib->values) *
515                                         (attrib->num_values+1));
516         if (attrib->values == NULL)
517                 return False;
518
519         attrib->values[attrib->num_values] =
520                 data_blob_talloc(mem_ctx, value->data, value->length);
521         attrib->num_values += 1;
522         return True;
523 }
524
525 static BOOL fill_add_attributes(struct ldap_message *msg, char **chunk)
526 {
527         struct ldap_AddRequest *r = &msg->r.AddRequest;
528         const char *attr_name;
529         struct ldap_val value;
530
531         r->num_attributes = 0;
532         r->attributes = NULL;
533
534         while (next_attr(chunk, &attr_name, &value) == 0) {
535                 int i;
536                 struct ldap_attribute *attrib = NULL;
537                 
538                 for (i=0; i<r->num_attributes; i++) {
539                         if (strequal(r->attributes[i].name, attr_name)) {
540                                 attrib = &r->attributes[i];
541                                 break;
542                         }
543                 }
544
545                 if (attrib == NULL) {
546                         r->attributes = talloc_realloc(msg->mem_ctx,
547                                                        r->attributes,
548                                                        sizeof(*r->attributes) *
549                                                        (r->num_attributes+1));
550                         if (r->attributes == NULL)
551                                 return False;
552
553                         attrib = &(r->attributes[r->num_attributes]);
554                         r->num_attributes += 1;
555                         ZERO_STRUCTP(attrib);
556                         attrib->name = talloc_strdup(msg->mem_ctx,
557                                                      attr_name);
558                 }
559
560                 if (!add_value_to_attrib(msg->mem_ctx, &value, attrib))
561                         return False;
562         }
563         return True;
564 }
565
566 static BOOL add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
567                                     struct ldap_mod *mod,
568                                     struct ldap_mod **mods,
569                                     int *num_mods)
570 {
571         *mods = talloc_realloc(mem_ctx, *mods,
572                                sizeof(**mods) * ((*num_mods)+1));
573
574         if (*mods == NULL)
575                 return False;
576
577         (*mods)[*num_mods] = *mod;
578         *num_mods += 1;
579         return True;
580 }
581
582 static BOOL fill_mods(struct ldap_message *msg, char **chunk)
583 {
584         struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
585         const char *attr_name;
586         struct ldap_val value;
587
588         r->num_mods = 0;
589         r->mods = NULL;
590
591         while (next_attr(chunk, &attr_name, &value) == 0) {
592
593                 struct ldap_mod mod;
594                 mod.type = LDAP_MODIFY_NONE;
595
596                 mod.attrib.name = talloc_strdup(msg->mem_ctx, value.data);
597
598                 if (strequal(attr_name, "add"))
599                         mod.type = LDAP_MODIFY_ADD;
600
601                 if (strequal(attr_name, "delete"))
602                         mod.type = LDAP_MODIFY_DELETE;
603
604                 if (strequal(attr_name, "replace"))
605                         mod.type = LDAP_MODIFY_REPLACE;
606
607                 if (mod.type == LDAP_MODIFY_NONE) {
608                         DEBUG(2, ("ldif modification type %s unsupported\n",
609                                   attr_name));
610                         return False;
611                 }
612
613                 mod.attrib.num_values = 0;
614                 mod.attrib.values = NULL;
615
616                 while (next_attr(chunk, &attr_name, &value) == 0) {
617                         if (strequal(attr_name, "-"))
618                                 break;
619                         if (!strequal(attr_name, mod.attrib.name)) {
620                                 DEBUG(3, ("attrib name %s does not "
621                                           "match %s\n", attr_name,
622                                           mod.attrib.name));
623                                 return False;
624                         }
625                         if (!add_value_to_attrib(msg->mem_ctx, &value,
626                                                  &mod.attrib)) {
627                                 DEBUG(3, ("Could not add value\n"));
628                                 return False;
629                         }
630                 }
631
632                 if (!add_mod_to_array_talloc(msg->mem_ctx, &mod, &r->mods,
633                                              &r->num_mods))
634                         return False;
635         }
636
637         return True;
638 }
639
640 /*
641  read from a LDIF source, creating a ldap_message
642 */
643 static struct ldap_message *ldif_read(int (*fgetc_fn)(void *),
644                                       void *private_data)
645 {
646         struct ldap_message *msg;
647         const char *attr=NULL;
648         const char *dn;
649         char *chunk=NULL, *s;
650         struct ldap_val value;
651
652         value.data = NULL;
653
654         msg = new_ldap_message();
655         if (msg == NULL)
656                 return NULL;
657
658         chunk = next_chunk(msg->mem_ctx, fgetc_fn, private_data);
659         if (!chunk) {
660                 goto failed;
661         }
662
663         s = chunk;
664
665         if (next_attr(&s, &attr, &value) != 0) {
666                 goto failed;
667         }
668         
669         /* first line must be a dn */
670         if (!strequal(attr, "dn")) {
671                 DEBUG(5, ("Error: First line of ldif must be a dn not '%s'\n",
672                           attr));
673                 goto failed;
674         }
675
676         dn = talloc_strdup(msg->mem_ctx, value.data);
677
678         if (next_attr(&s, &attr, &value) != 0) {
679                 goto failed;
680         }
681
682         if (!strequal(attr, "changetype")) {
683                 DEBUG(5, ("Error: Second line of ldif must be a changetype "
684                           "not '%s'\n",  attr));
685                 goto failed;
686         }
687
688         if (strequal(value.data, "delete")) {
689                 msg->type = LDAP_TAG_DelRequest;
690                 msg->r.DelRequest.dn = dn;
691                 return msg;
692         }
693
694         if (strequal(value.data, "add")) {
695                 msg->type = LDAP_TAG_AddRequest;
696
697                 msg->r.AddRequest.dn = dn;
698
699                 if (!fill_add_attributes(msg, &s))
700                         goto failed;
701
702                 return msg;
703         }
704
705         if (strequal(value.data, "modify")) {
706                 msg->type = LDAP_TAG_ModifyRequest;
707
708                 msg->r.ModifyRequest.dn = dn;
709
710                 if (!fill_mods(msg, &s))
711                         goto failed;
712
713                 return msg;
714         }
715
716         DEBUG(3, ("changetype %s not supported\n", (char *)value.data));
717
718 failed:
719         destroy_ldap_message(msg);
720         return NULL;
721 }
722
723 /*
724   a wrapper around ldif_read() for reading from const char*
725 */
726 struct ldif_read_string_state {
727         const char *s;
728 };
729
730 static int fgetc_string(void *private_data)
731 {
732         struct ldif_read_string_state *state = private_data;
733         if (state->s[0] != 0) {
734                 return *state->s++;
735         }
736         return EOF;
737 }
738
739 struct ldap_message *ldap_ldif2msg(const char *s)
740 {
741         struct ldif_read_string_state state;
742         state.s = s;
743         return ldif_read(fgetc_string, &state);
744 }
745
746 static void ldap_encode_response(enum ldap_request_tag tag,
747                                  struct ldap_Result *result,
748                                  ASN1_DATA *data)
749 {
750         asn1_push_tag(data, ASN1_APPLICATION(tag));
751         asn1_write_enumerated(data, result->resultcode);
752         asn1_write_OctetString(data, result->dn,
753                                (result->dn) ? strlen(result->dn) : 0);
754         asn1_write_OctetString(data, result->errormessage,
755                                (result->errormessage) ?
756                                strlen(result->errormessage) : 0);
757         if (result->referral != NULL)
758                 asn1_write_OctetString(data, result->referral,
759                                        strlen(result->referral));
760         asn1_pop_tag(data);
761 }
762
763 BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result)
764 {
765         ASN1_DATA data;
766         int i, j;
767
768         ZERO_STRUCT(data);
769         asn1_push_tag(&data, ASN1_SEQUENCE(0));
770         asn1_write_Integer(&data, msg->messageid);
771
772         switch (msg->type) {
773         case LDAP_TAG_BindRequest: {
774                 struct ldap_BindRequest *r = &msg->r.BindRequest;
775                 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_BindRequest));
776                 asn1_write_Integer(&data, r->version);
777                 asn1_write_OctetString(&data, r->dn,
778                                        (r->dn != NULL) ? strlen(r->dn) : 0);
779
780                 switch (r->mechanism) {
781                 case LDAP_AUTH_MECH_SIMPLE:
782                         /* context, primitive */
783                         asn1_push_tag(&data, r->mechanism | 0x80);
784                         asn1_write(&data, r->creds.password,
785                                    strlen(r->creds.password));
786                         asn1_pop_tag(&data);
787                         break;
788                 case LDAP_AUTH_MECH_SASL:
789                         /* context, constructed */
790                         asn1_push_tag(&data, r->mechanism | 0xa0);
791                         asn1_write_OctetString(&data, r->creds.SASL.mechanism,
792                                                strlen(r->creds.SASL.mechanism));
793                         asn1_write_OctetString(&data, r->creds.SASL.secblob.data,
794                                                r->creds.SASL.secblob.length);
795                         asn1_pop_tag(&data);
796                         break;
797                 default:
798                         return False;
799                 }
800
801                 asn1_pop_tag(&data);
802                 asn1_pop_tag(&data);
803                 break;
804         }
805         case LDAP_TAG_BindResponse: {
806                 struct ldap_BindResponse *r = &msg->r.BindResponse;
807                 ldap_encode_response(msg->type, &r->response, &data);
808                 break;
809         }
810         case LDAP_TAG_UnbindRequest: {
811 /*              struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
812                 break;
813         }
814         case LDAP_TAG_SearchRequest: {
815                 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
816                 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_SearchRequest));
817                 asn1_write_OctetString(&data, r->basedn, strlen(r->basedn));
818                 asn1_write_enumerated(&data, r->scope);
819                 asn1_write_enumerated(&data, r->deref);
820                 asn1_write_Integer(&data, r->sizelimit);
821                 asn1_write_Integer(&data, r->timelimit);
822                 asn1_write_BOOLEAN2(&data, r->attributesonly);
823
824                 {
825                         TALLOC_CTX *mem_ctx = talloc_init("ldap_parse_tree");
826                         struct ldap_parse_tree *tree;
827
828                         if (mem_ctx == NULL)
829                                 return False;
830
831                         tree = ldap_parse_tree(mem_ctx, r->filter);
832
833                         if (tree == NULL)
834                                 return False;
835
836                         ldap_push_filter(&data, tree);
837
838                         talloc_destroy(mem_ctx);
839                 }
840
841                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
842                 for (i=0; i<r->num_attributes; i++) {
843                         asn1_write_OctetString(&data, r->attributes[i],
844                                                strlen(r->attributes[i]));
845                 }
846                 asn1_pop_tag(&data);
847
848                 asn1_pop_tag(&data);
849                 break;
850         }
851         case LDAP_TAG_SearchResultEntry: {
852                 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
853                 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_SearchResultEntry));
854                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
855                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
856                 for (i=0; i<r->num_attributes; i++) {
857                         struct ldap_attribute *attr = &r->attributes[i];
858                         asn1_push_tag(&data, ASN1_SEQUENCE(0));
859                         asn1_write_OctetString(&data, attr->name,
860                                                strlen(attr->name));
861                         asn1_push_tag(&data, ASN1_SEQUENCE(1));
862                         for (j=0; j<attr->num_values; j++) {
863                                 asn1_write_OctetString(&data,
864                                                        attr->values[j].data,
865                                                        attr->values[j].length);
866                         }
867                         asn1_pop_tag(&data);
868                         asn1_pop_tag(&data);
869                 }
870                 asn1_pop_tag(&data);
871                 asn1_pop_tag(&data);
872                 break;
873         }
874         case LDAP_TAG_SearchResultDone: {
875                 struct ldap_Result *r = &msg->r.SearchResultDone;
876                 ldap_encode_response(msg->type, r, &data);
877                 break;
878         }
879         case LDAP_TAG_ModifyRequest: {
880                 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
881                 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
882                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
883                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
884
885                 for (i=0; i<r->num_mods; i++) {
886                         struct ldap_attribute *attrib = &r->mods[i].attrib;
887                         asn1_push_tag(&data, ASN1_SEQUENCE(0));
888                         asn1_write_enumerated(&data, r->mods[i].type);
889                         asn1_push_tag(&data, ASN1_SEQUENCE(0));
890                         asn1_write_OctetString(&data, attrib->name,
891                                                strlen(attrib->name));
892                         asn1_push_tag(&data, ASN1_SET);
893                         for (j=0; j<attrib->num_values; j++) {
894                                 asn1_write_OctetString(&data,
895                                                        attrib->values[j].data,
896                                                        attrib->values[j].length);
897         
898                         }
899                         asn1_pop_tag(&data);
900                         asn1_pop_tag(&data);
901                         asn1_pop_tag(&data);
902                 }
903                 
904                 asn1_pop_tag(&data);
905                 asn1_pop_tag(&data);
906                 break;
907         }
908         case LDAP_TAG_ModifyResponse: {
909                 struct ldap_Result *r = &msg->r.ModifyResponse;
910                 ldap_encode_response(msg->type, r, &data);
911                 break;
912         }
913         case LDAP_TAG_AddRequest: {
914                 struct ldap_AddRequest *r = &msg->r.AddRequest;
915                 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_AddRequest));
916                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
917                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
918
919                 for (i=0; i<r->num_attributes; i++) {
920                         struct ldap_attribute *attrib = &r->attributes[i];
921                         asn1_push_tag(&data, ASN1_SEQUENCE(0));
922                         asn1_write_OctetString(&data, attrib->name,
923                                                strlen(attrib->name));
924                         asn1_push_tag(&data, ASN1_SET);
925                         for (j=0; j<r->attributes[i].num_values; j++) {
926                                 asn1_write_OctetString(&data,
927                                                        attrib->values[j].data,
928                                                        attrib->values[j].length);
929                         }
930                         asn1_pop_tag(&data);
931                         asn1_pop_tag(&data);
932                 }
933                 asn1_pop_tag(&data);
934                 asn1_pop_tag(&data);
935                 break;
936         }
937         case LDAP_TAG_AddResponse: {
938                 struct ldap_Result *r = &msg->r.AddResponse;
939                 ldap_encode_response(msg->type, r, &data);
940                 break;
941         }
942         case LDAP_TAG_DelRequest: {
943                 struct ldap_DelRequest *r = &msg->r.DelRequest;
944                 asn1_push_tag(&data,
945                               ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
946                 asn1_write(&data, r->dn, strlen(r->dn));
947                 asn1_pop_tag(&data);
948                 break;
949         }
950         case LDAP_TAG_DelResponse: {
951                 struct ldap_Result *r = &msg->r.DelResponse;
952                 ldap_encode_response(msg->type, r, &data);
953                 break;
954         }
955         case LDAP_TAG_ModifyDNRequest: {
956                 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
957                 asn1_push_tag(&data,
958                               ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
959                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
960                 asn1_write_OctetString(&data, r->newrdn, strlen(r->newrdn));
961                 asn1_write_BOOLEAN2(&data, r->deleteolddn);
962                 if (r->newsuperior != NULL) {
963                         asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
964                         asn1_write(&data, r->newsuperior,
965                                    strlen(r->newsuperior));
966                         asn1_pop_tag(&data);
967                 }
968                 asn1_pop_tag(&data);
969                 break;
970         }
971         case LDAP_TAG_ModifyDNResponse: {
972 /*              struct ldap_Result *r = &msg->r.ModifyDNResponse; */
973                 break;
974         }
975         case LDAP_TAG_CompareRequest: {
976                 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
977                 asn1_push_tag(&data,
978                               ASN1_APPLICATION(LDAP_TAG_CompareRequest));
979                 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
980                 asn1_push_tag(&data, ASN1_SEQUENCE(0));
981                 asn1_write_OctetString(&data, r->attribute,
982                                        strlen(r->attribute));
983                 asn1_write_OctetString(&data, r->value,
984                                        strlen(r->value));
985                 asn1_pop_tag(&data);
986                 asn1_pop_tag(&data);
987                 break;
988         }
989         case LDAP_TAG_CompareResponse: {
990 /*              struct ldap_Result *r = &msg->r.CompareResponse; */
991                 break;
992         }
993         case LDAP_TAG_AbandonRequest: {
994                 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
995                 asn1_push_tag(&data,
996                               ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest));
997                 asn1_write_Integer(&data, r->messageid);
998                 asn1_pop_tag(&data);
999                 break;
1000         }
1001         case LDAP_TAG_SearchResultReference: {
1002 /*              struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
1003                 break;
1004         }
1005         case LDAP_TAG_ExtendedRequest: {
1006                 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1007                 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_ExtendedRequest));
1008                 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
1009                 asn1_write(&data, r->oid, strlen(r->oid));
1010                 asn1_pop_tag(&data);
1011                 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(1));
1012                 asn1_write(&data, r->value.data, r->value.length);
1013                 asn1_pop_tag(&data);
1014                 asn1_pop_tag(&data);
1015                 break;
1016         }
1017         case LDAP_TAG_ExtendedResponse: {
1018                 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1019                 ldap_encode_response(msg->type, &r->response, &data);
1020                 break;
1021         }
1022         default:
1023                 return False;
1024         }
1025
1026         asn1_pop_tag(&data);
1027         *result = data_blob(data.data, data.length);
1028         asn1_free(&data);
1029         return True;
1030 }
1031
1032 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
1033                                       DATA_BLOB blob)
1034 {
1035         char *result = talloc(mem_ctx, blob.length+1);
1036         memcpy(result, blob.data, blob.length);
1037         result[blob.length] = '\0';
1038         return result;
1039 }
1040
1041 static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
1042                                          ASN1_DATA *data,
1043                                          const char **result)
1044 {
1045         DATA_BLOB string;
1046         if (!asn1_read_OctetString(data, &string))
1047                 return False;
1048         *result = blob2string_talloc(mem_ctx, string);
1049         data_blob_free(&string);
1050         return True;
1051 }
1052
1053 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
1054                                  ASN1_DATA *data,
1055                                  enum ldap_request_tag tag,
1056                                  struct ldap_Result *result)
1057 {
1058         asn1_start_tag(data, ASN1_APPLICATION(tag));
1059         asn1_read_enumerated(data, &result->resultcode);
1060         asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
1061         asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
1062         if (asn1_peek_tag(data, ASN1_OCTET_STRING))
1063                 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
1064         else
1065                 result->referral = NULL;
1066         asn1_end_tag(data);
1067 }
1068
1069 static BOOL add_attrib_to_array_talloc(TALLOC_CTX *mem_ctx,
1070                                        const struct ldap_attribute *attrib,
1071                                        struct ldap_attribute **attribs,
1072                                        int *num_attribs)
1073 {
1074         *attribs = talloc_realloc(mem_ctx, *attribs,
1075                                   sizeof(**attribs) * (*num_attribs+1));
1076
1077         if (*attribs == NULL)
1078                 return False;
1079
1080         (*attribs)[*num_attribs] = *attrib;
1081         *num_attribs += 1;
1082         return True;
1083 }
1084                                        
1085 static BOOL ldap_decode_filter(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
1086                                char **filter)
1087 {
1088         uint8 filter_tag, tag_desc;
1089
1090         if (!asn1_peek_uint8(data, &filter_tag))
1091                 return False;
1092
1093         tag_desc = filter_tag;
1094         filter_tag &= 0x1f;     /* strip off the asn1 stuff */
1095         tag_desc &= 0xe0;
1096
1097         switch(filter_tag) {
1098         case 0: {
1099                 /* AND of one or more filters */
1100                 if (tag_desc != 0xa0) /* context compount */
1101                         return False;
1102
1103                 asn1_start_tag(data, ASN1_CONTEXT(0));
1104
1105                 *filter = talloc_strdup(mem_ctx, "(&");
1106                 if (*filter == NULL)
1107                         return False;
1108
1109                 while (asn1_tag_remaining(data) > 0) {
1110                         char *subfilter;
1111                         if (!ldap_decode_filter(mem_ctx, data, &subfilter))
1112                                 return False;
1113                         *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
1114                                                   subfilter);
1115                         if (*filter == NULL)
1116                                 return False;
1117                 }
1118                 asn1_end_tag(data);
1119
1120                 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
1121                 break;
1122         }
1123         case 1: {
1124                 /* OR of one or more filters */
1125                 if (tag_desc != 0xa0) /* context compount */
1126                         return False;
1127
1128                 asn1_start_tag(data, ASN1_CONTEXT(1));
1129
1130                 *filter = talloc_strdup(mem_ctx, "(|");
1131                 if (*filter == NULL)
1132                         return False;
1133
1134                 while (asn1_tag_remaining(data) > 0) {
1135                         char *subfilter;
1136                         if (!ldap_decode_filter(mem_ctx, data, &subfilter))
1137                                 return False;
1138                         *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
1139                                                   subfilter);
1140                         if (*filter == NULL)
1141                                 return False;
1142                 }
1143
1144                 asn1_end_tag(data);
1145
1146                 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
1147                 break;
1148         }
1149         case 3: {
1150                 /* equalityMatch */
1151                 const char *attrib, *value;
1152                 if (tag_desc != 0xa0) /* context compound */
1153                         return False;
1154                 asn1_start_tag(data, ASN1_CONTEXT(3));
1155                 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
1156                 asn1_read_OctetString_talloc(mem_ctx, data, &value);
1157                 asn1_end_tag(data);
1158                 if ((data->has_error) || (attrib == NULL) || (value == NULL))
1159                         return False;
1160                 *filter = talloc_asprintf(mem_ctx, "(%s=%s)", attrib, value);
1161                 break;
1162         }
1163         case 7: {
1164                 /* Normal presence, "attribute=*" */
1165                 int attr_len;
1166                 char *attr_name;
1167                 if (tag_desc != 0x80) /* context simple */
1168                         return False;
1169                 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(7)))
1170                         return False;
1171                 attr_len = asn1_tag_remaining(data);
1172                 attr_name = malloc(attr_len+1);
1173                 if (attr_name == NULL)
1174                         return False;
1175                 asn1_read(data, attr_name, attr_len);
1176                 attr_name[attr_len] = '\0';
1177                 *filter = talloc_asprintf(mem_ctx, "(%s=*)", attr_name);
1178                 SAFE_FREE(attr_name);
1179                 asn1_end_tag(data);
1180                 break;
1181         }
1182         default:
1183                 return False;
1184         }
1185         if (*filter == NULL)
1186                 return False;
1187         return True;
1188 }
1189
1190 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
1191                                struct ldap_attribute *attrib)
1192 {
1193         asn1_start_tag(data, ASN1_SEQUENCE(0));
1194         asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
1195         asn1_start_tag(data, ASN1_SET);
1196         while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
1197                 DATA_BLOB blob;
1198                 struct ldap_val value;
1199                 asn1_read_OctetString(data, &blob);
1200                 value.data = blob.data;
1201                 value.length = blob.length;
1202                 add_value_to_attrib(mem_ctx, &value, attrib);
1203                 data_blob_free(&blob);
1204         }
1205         asn1_end_tag(data);
1206         asn1_end_tag(data);
1207         
1208 }
1209
1210 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
1211                                 struct ldap_attribute **attributes,
1212                                 int *num_attributes)
1213 {
1214         asn1_start_tag(data, ASN1_SEQUENCE(0));
1215         while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
1216                 struct ldap_attribute attrib;
1217                 ZERO_STRUCT(attrib);
1218                 ldap_decode_attrib(mem_ctx, data, &attrib);
1219                 add_attrib_to_array_talloc(mem_ctx, &attrib,
1220                                            attributes, num_attributes);
1221         }
1222         asn1_end_tag(data);
1223 }
1224
1225 BOOL ldap_decode(ASN1_DATA *data, struct ldap_message *msg)
1226 {
1227         uint8 tag;
1228
1229         asn1_start_tag(data, ASN1_SEQUENCE(0));
1230         asn1_read_Integer(data, &msg->messageid);
1231
1232         if (!asn1_peek_uint8(data, &tag))
1233                 return False;
1234
1235         switch(tag) {
1236
1237         case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
1238                 struct ldap_BindRequest *r = &msg->r.BindRequest;
1239                 msg->type = LDAP_TAG_BindRequest;
1240                 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_BindRequest));
1241                 asn1_read_Integer(data, &r->version);
1242                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1243                 if (asn1_peek_tag(data, 0x80)) {
1244                         int pwlen;
1245                         r->creds.password = "";
1246                         /* Mechanism 0 (SIMPLE) */
1247                         asn1_start_tag(data, 0x80);
1248                         pwlen = asn1_tag_remaining(data);
1249                         if (pwlen != 0) {
1250                                 char *pw = talloc(msg->mem_ctx, pwlen+1);
1251                                 asn1_read(data, pw, pwlen);
1252                                 pw[pwlen] = '\0';
1253                                 r->creds.password = pw;
1254                         }
1255                         asn1_end_tag(data);
1256                 }
1257                 asn1_end_tag(data);
1258                 break;
1259         }
1260
1261         case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
1262                 struct ldap_BindResponse *r = &msg->r.BindResponse;
1263                 msg->type = LDAP_TAG_BindResponse;
1264                 ldap_decode_response(msg->mem_ctx,
1265                                      data, LDAP_TAG_BindResponse,
1266                                      &r->response);
1267                 break;
1268         }
1269
1270         case ASN1_APPLICATION(LDAP_TAG_UnbindRequest): {
1271                 msg->type = LDAP_TAG_UnbindRequest;
1272                 break;
1273         }
1274
1275         case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
1276                 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
1277                 msg->type = LDAP_TAG_SearchRequest;
1278                 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_SearchRequest));
1279                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->basedn);
1280                 asn1_read_enumerated(data, (int *)&(r->scope));
1281                 asn1_read_enumerated(data, (int *)&(r->deref));
1282                 asn1_read_Integer(data, &r->sizelimit);
1283                 asn1_read_Integer(data, &r->timelimit);
1284                 asn1_read_BOOLEAN2(data, &r->attributesonly);
1285
1286                 /* Maybe create a TALLOC_CTX for the filter? This can waste
1287                  * quite a bit of memory recursing down. */
1288                 ldap_decode_filter(msg->mem_ctx, data, &r->filter);
1289
1290                 asn1_start_tag(data, ASN1_SEQUENCE(0));
1291
1292                 r->num_attributes = 0;
1293                 r->attributes = NULL;
1294
1295                 while (asn1_tag_remaining(data) > 0) {
1296                         const char *attr;
1297                         if (!asn1_read_OctetString_talloc(msg->mem_ctx, data,
1298                                                           &attr))
1299                                 return False;
1300                         if (!add_string_to_array(msg->mem_ctx, attr,
1301                                                  &r->attributes,
1302                                                  &r->num_attributes))
1303                                 return False;
1304                 }
1305
1306                 asn1_end_tag(data);
1307                 asn1_end_tag(data);
1308                 break;
1309         }
1310
1311         case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
1312                 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
1313                 msg->type = LDAP_TAG_SearchResultEntry;
1314                 r->attributes = NULL;
1315                 r->num_attributes = 0;
1316                 asn1_start_tag(data,
1317                                ASN1_APPLICATION(LDAP_TAG_SearchResultEntry));
1318                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1319                 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
1320                                     &r->num_attributes);
1321                 asn1_end_tag(data);
1322                 break;
1323         }
1324
1325         case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
1326                 struct ldap_Result *r = &msg->r.SearchResultDone;
1327                 msg->type = LDAP_TAG_SearchResultDone;
1328                 ldap_decode_response(msg->mem_ctx, data,
1329                                      LDAP_TAG_SearchResultDone, r);
1330                 break;
1331         }
1332
1333         case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
1334 /*              struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
1335                 msg->type = LDAP_TAG_SearchResultReference;
1336                 break;
1337         }
1338
1339         case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
1340                 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
1341                 msg->type = LDAP_TAG_ModifyRequest;
1342                 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
1343                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1344                 asn1_start_tag(data, ASN1_SEQUENCE(0));
1345
1346                 r->num_mods = 0;
1347                 r->mods = NULL;
1348
1349                 while (asn1_tag_remaining(data) > 0) {
1350                         struct ldap_mod mod;
1351                         ZERO_STRUCT(mod);
1352                         asn1_start_tag(data, ASN1_SEQUENCE(0));
1353                         asn1_read_enumerated(data, &mod.type);
1354                         ldap_decode_attrib(msg->mem_ctx, data, &mod.attrib);
1355                         asn1_end_tag(data);
1356                         if (!add_mod_to_array_talloc(msg->mem_ctx, &mod,
1357                                                      &r->mods, &r->num_mods))
1358                                 break;
1359                 }
1360
1361                 asn1_end_tag(data);
1362                 asn1_end_tag(data);
1363                 break;
1364         }
1365
1366         case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
1367                 struct ldap_Result *r = &msg->r.ModifyResponse;
1368                 msg->type = LDAP_TAG_ModifyResponse;
1369                 ldap_decode_response(msg->mem_ctx, data,
1370                                      LDAP_TAG_ModifyResponse, r);
1371                 break;
1372         }
1373
1374         case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
1375                 struct ldap_AddRequest *r = &msg->r.AddRequest;
1376                 msg->type = LDAP_TAG_AddRequest;
1377                 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_AddRequest));
1378                 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1379
1380                 r->attributes = NULL;
1381                 r->num_attributes = 0;
1382                 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
1383                                     &r->num_attributes);
1384
1385                 asn1_end_tag(data);
1386                 break;
1387         }
1388
1389         case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1390                 struct ldap_Result *r = &msg->r.AddResponse;
1391                 msg->type = LDAP_TAG_AddResponse;
1392                 ldap_decode_response(msg->mem_ctx, data,
1393                                      LDAP_TAG_AddResponse, r);
1394                 break;
1395         }
1396
1397         case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1398                 struct ldap_DelRequest *r = &msg->r.DelRequest;
1399                 int len;
1400                 char *dn;
1401                 msg->type = LDAP_TAG_DelRequest;
1402                 asn1_start_tag(data,
1403                                ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1404                 len = asn1_tag_remaining(data);
1405                 dn = talloc(msg->mem_ctx, len+1);
1406                 if (dn == NULL)
1407                         break;
1408                 asn1_read(data, dn, len);
1409                 dn[len] = '\0';
1410                 r->dn = dn;
1411                 asn1_end_tag(data);
1412                 break;
1413         }
1414
1415         case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1416                 struct ldap_Result *r = &msg->r.DelResponse;
1417                 msg->type = LDAP_TAG_DelResponse;
1418                 ldap_decode_response(msg->mem_ctx, data,
1419                                      LDAP_TAG_DelResponse, r);
1420                 break;
1421         }
1422
1423         case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1424 /*              struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest; */
1425                 msg->type = LDAP_TAG_ModifyDNRequest;
1426                 break;
1427         }
1428
1429         case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1430                 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1431                 msg->type = LDAP_TAG_ModifyDNResponse;
1432                 ldap_decode_response(msg->mem_ctx, data,
1433                                      LDAP_TAG_ModifyDNResponse, r);
1434                 break;
1435         }
1436
1437         case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1438 /*              struct ldap_CompareRequest *r = &msg->r.CompareRequest; */
1439                 msg->type = LDAP_TAG_CompareRequest;
1440                 break;
1441         }
1442
1443         case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1444                 struct ldap_Result *r = &msg->r.CompareResponse;
1445                 msg->type = LDAP_TAG_CompareResponse;
1446                 ldap_decode_response(msg->mem_ctx, data,
1447                                      LDAP_TAG_CompareResponse, r);
1448                 break;
1449         }
1450
1451         case ASN1_APPLICATION(LDAP_TAG_AbandonRequest): {
1452 /*              struct ldap_AbandonRequest *r = &msg->r.AbandonRequest; */
1453                 msg->type = LDAP_TAG_AbandonRequest;
1454                 break;
1455         }
1456
1457         case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1458 /*              struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest; */
1459                 msg->type = LDAP_TAG_ExtendedRequest;
1460                 break;
1461         }
1462
1463         case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1464                 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1465                 msg->type = LDAP_TAG_ExtendedResponse;
1466                 ldap_decode_response(msg->mem_ctx, data,
1467                                      LDAP_TAG_ExtendedResponse, &r->response);
1468                 /* I have to come across an operation that actually sends
1469                  * something back to really see what's going on. The currently
1470                  * needed pwdchange does not send anything back. */
1471                 r->name = NULL;
1472                 r->value.data = NULL;
1473                 r->value.length = 0;
1474                 break;
1475         }
1476
1477         }
1478
1479         asn1_end_tag(data);
1480         return ((!data->has_error) && (data->nesting == NULL));
1481 }
1482
1483 BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
1484                           char **host, uint16 *port, BOOL *ldaps)
1485 {
1486         int tmp_port = 0;
1487         fstring protocol;
1488         fstring tmp_host;
1489         const char *p = url;
1490
1491         /* skip leading "URL:" (if any) */
1492         if ( strnequal( p, "URL:", 4 ) ) {
1493                 p += 4;
1494         }
1495
1496         /* Paranoia check */
1497         SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
1498                 
1499         sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
1500
1501         if (strequal(protocol, "ldap")) {
1502                 *port = 389;
1503                 *ldaps = False;
1504         } else if (strequal(protocol, "ldaps")) {
1505                 *port = 636;
1506                 *ldaps = True;
1507         } else {
1508                 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
1509                 return False;
1510         }
1511
1512         if (tmp_port != 0)
1513                 *port = tmp_port;
1514         
1515         *host = talloc_strdup(mem_ctx, tmp_host);
1516
1517         return (*host != NULL);
1518 }
1519
1520 struct ldap_connection *new_ldap_connection(void)
1521 {
1522         TALLOC_CTX *mem_ctx = talloc_init("ldap_connection");
1523         struct ldap_connection *result;
1524
1525         if (mem_ctx == NULL)
1526                 return NULL;
1527
1528         result = talloc(mem_ctx, sizeof(*result));
1529
1530         if (result == NULL)
1531                 return NULL;
1532
1533         result->mem_ctx = mem_ctx;
1534         result->next_msgid = 1;
1535         result->outstanding = NULL;
1536         result->searchid = 0;
1537         result->search_entries = NULL;
1538         result->auth_dn = NULL;
1539         result->simple_pw = NULL;
1540         result->gensec = NULL;
1541
1542         return result;
1543 }
1544
1545 BOOL ldap_connect(struct ldap_connection *conn, const char *url)
1546 {
1547         struct hostent *hp;
1548         struct in_addr ip;
1549
1550         if (!ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
1551                                   &conn->port, &conn->ldaps))
1552                 return False;
1553
1554         hp = sys_gethostbyname(conn->host);
1555
1556         if ((hp == NULL) || (hp->h_addr == NULL))
1557                 return False;
1558
1559         putip((char *)&ip, (char *)hp->h_addr);
1560
1561         conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
1562
1563         return (conn->sock >= 0);
1564 }
1565
1566 BOOL ldap_set_simple_creds(struct ldap_connection *conn,
1567                            const char *dn, const char *password)
1568 {
1569         conn->auth_dn = talloc_strdup(conn->mem_ctx, dn);
1570         conn->simple_pw = talloc_strdup(conn->mem_ctx, password);
1571
1572         return ((conn->auth_dn != NULL) && (conn->simple_pw != NULL));
1573 }
1574
1575 struct ldap_message *new_ldap_message(void)
1576 {
1577         TALLOC_CTX *mem_ctx = talloc_init("ldap_message");
1578         struct ldap_message *result;
1579
1580         if (mem_ctx == NULL)
1581                 return NULL;
1582
1583         result = talloc(mem_ctx, sizeof(*result));
1584
1585         if (result == NULL)
1586                 return NULL;
1587
1588         result->mem_ctx = mem_ctx;
1589         return result;
1590 }
1591
1592 void destroy_ldap_message(struct ldap_message *msg)
1593 {
1594         if (msg != NULL)
1595                 talloc_destroy(msg->mem_ctx);
1596 }
1597
1598 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
1599                    const struct timeval *endtime)
1600 {
1601         DATA_BLOB request;
1602         BOOL result;
1603         struct ldap_queue_entry *entry;
1604
1605         msg->messageid = conn->next_msgid++;
1606
1607         if (!ldap_encode(msg, &request))
1608                 return False;
1609
1610         result = (write_data_until(conn->sock, request.data, request.length,
1611                                    endtime) == request.length);
1612
1613         data_blob_free(&request);
1614
1615         if (!result)
1616                 return result;
1617
1618         /* abandon and unbind don't expect results */
1619
1620         if ((msg->type == LDAP_TAG_AbandonRequest) ||
1621             (msg->type == LDAP_TAG_UnbindRequest))
1622                 return True;
1623
1624         entry = malloc(sizeof(*entry)); 
1625
1626         if (entry == NULL)
1627                 return False;
1628
1629         entry->msgid = msg->messageid;
1630         entry->msg = NULL;
1631         DLIST_ADD(conn->outstanding, entry);
1632
1633         return True;
1634 }
1635
1636 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
1637                       const struct timeval *endtime)
1638 {
1639         struct asn1_data data;
1640         BOOL result;
1641
1642         if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1643                 return False;
1644
1645         result = ldap_decode(&data, msg);
1646
1647         asn1_free(&data);
1648         return result;
1649 }
1650
1651 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
1652                                             int msgid)
1653 {
1654         struct ldap_queue_entry *e;
1655
1656         for (e = conn->outstanding; e != NULL; e = e->next) {
1657
1658                 if (e->msgid == msgid) {
1659                         struct ldap_message *result = e->msg;
1660                         DLIST_REMOVE(conn->outstanding, e);
1661                         SAFE_FREE(e);
1662                         return result;
1663                 }
1664         }
1665
1666         return NULL;
1667 }
1668
1669 static void add_search_entry(struct ldap_connection *conn,
1670                              struct ldap_message *msg)
1671 {
1672         struct ldap_queue_entry *e = malloc(sizeof *e);
1673
1674         if (e == NULL)
1675                 return;
1676
1677         e->msg = msg;
1678         DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
1679         return;
1680 }
1681
1682 static void fill_outstanding_request(struct ldap_connection *conn,
1683                                      struct ldap_message *msg)
1684 {
1685         struct ldap_queue_entry *e;
1686
1687         for (e = conn->outstanding; e != NULL; e = e->next) {
1688                 if (e->msgid == msg->messageid) {
1689                         e->msg = msg;
1690                         return;
1691                 }
1692         }
1693
1694         /* This reply has not been expected, destroy the incoming msg */
1695         destroy_ldap_message(msg);
1696         return;
1697 }
1698
1699 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
1700                                   const struct timeval *endtime)
1701 {
1702         struct ldap_message *result = recv_from_queue(conn, msgid);
1703
1704         if (result != NULL)
1705                 return result;
1706
1707         while (True) {
1708                 struct asn1_data data;
1709                 BOOL res;
1710
1711                 result = new_ldap_message();
1712
1713                 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1714                         return NULL;
1715
1716                 res = ldap_decode(&data, result);
1717                 asn1_free(&data);
1718
1719                 if (!res)
1720                         return NULL;
1721
1722                 if (result->messageid == msgid)
1723                         return result;
1724
1725                 if (result->type == LDAP_TAG_SearchResultEntry) {
1726                         add_search_entry(conn, result);
1727                 } else {
1728                         fill_outstanding_request(conn, result);
1729                 }
1730         }
1731
1732         return NULL;
1733 }
1734
1735 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
1736                                       struct ldap_message *request)
1737 {
1738         if (!ldap_send_msg(conn, request, NULL))
1739                 return False;
1740
1741         return ldap_receive(conn, request->messageid, NULL);
1742 }
1743
1744 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
1745 {
1746         struct ldap_message *response;
1747         struct ldap_message *msg;
1748         const char *dn, *pw;
1749         int result = LDAP_OTHER;
1750
1751         if (conn == NULL)
1752                 return result;
1753
1754         if (userdn) {
1755                 dn = userdn;
1756         } else {
1757                 if (conn->auth_dn) {
1758                         dn = conn->auth_dn;
1759                 } else {
1760                         dn = "";
1761                 }
1762         }
1763
1764         if (password) {
1765                 pw = password;
1766         } else {
1767                 if (conn->simple_pw) {
1768                         pw = conn->simple_pw;
1769                 } else {
1770                         pw = "";
1771                 }
1772         }
1773
1774         msg =  new_ldap_simple_bind_msg(dn, pw);
1775         if (!msg)
1776                 return result;
1777
1778         response = ldap_transaction(conn, msg);
1779         if (!response) {
1780                 destroy_ldap_message(msg);
1781                 return result;
1782         }
1783                 
1784         result = response->r.BindResponse.response.resultcode;
1785
1786         destroy_ldap_message(msg);
1787         destroy_ldap_message(response);
1788
1789         return result;
1790 }
1791
1792 int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
1793 {
1794         NTSTATUS status;
1795         TALLOC_CTX *mem_ctx = NULL;
1796         struct ldap_message *response;
1797         struct ldap_message *msg;
1798         DATA_BLOB input = data_blob(NULL, 0);
1799         DATA_BLOB output = data_blob(NULL, 0);
1800         int result = LDAP_OTHER;
1801
1802         if (conn == NULL)
1803                 return result;
1804
1805         status = gensec_client_start(&conn->gensec);
1806         if (!NT_STATUS_IS_OK(status)) {
1807                 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
1808                 return result;
1809         }
1810
1811         status = gensec_set_domain(conn->gensec, domain);
1812         if (!NT_STATUS_IS_OK(status)) {
1813                 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", 
1814                           domain, nt_errstr(status)));
1815                 goto done;
1816         }
1817
1818         status = gensec_set_username(conn->gensec, username);
1819         if (!NT_STATUS_IS_OK(status)) {
1820                 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", 
1821                           username, nt_errstr(status)));
1822                 goto done;
1823         }
1824
1825         status = gensec_set_password(conn->gensec, password);
1826         if (!NT_STATUS_IS_OK(status)) {
1827                 DEBUG(1, ("Failed to start set GENSEC client password: %s\n", 
1828                           nt_errstr(status)));
1829                 goto done;
1830         }
1831
1832         status = gensec_set_target_hostname(conn->gensec, conn->host);
1833         if (!NT_STATUS_IS_OK(status)) {
1834                 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
1835                           nt_errstr(status)));
1836                 goto done;
1837         }
1838
1839         status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
1840         if (!NT_STATUS_IS_OK(status)) {
1841                 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
1842                           nt_errstr(status)));
1843                 goto done;
1844         }
1845
1846         mem_ctx = talloc_init("ldap_bind_sasl");
1847         if (!mem_ctx)
1848                 goto done;
1849
1850         status = gensec_update(conn->gensec, mem_ctx,
1851                                input,
1852                                &output);
1853
1854         while(1) {
1855                 if (NT_STATUS_IS_OK(status) && output.length == 0) {
1856                         break;
1857                 }
1858                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
1859                         break;
1860                 }
1861
1862                 msg =  new_ldap_sasl_bind_msg("GSS-SPNEGO", &output);
1863                 if (!msg)
1864                         goto done;
1865
1866                 response = ldap_transaction(conn, msg);
1867                 destroy_ldap_message(msg);
1868
1869                 result = response->r.BindResponse.response.resultcode;
1870
1871                 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
1872                         break;
1873                 }
1874
1875                 status = gensec_update(conn->gensec, mem_ctx,
1876                                        response->r.BindResponse.SASL.creds,
1877                                        &output);
1878
1879                 destroy_ldap_message(response);
1880         }
1881
1882 done:
1883         if (conn->gensec)
1884                 gensec_end(&conn->gensec);
1885         if (mem_ctx)
1886                 talloc_destroy(mem_ctx);
1887
1888         return result;
1889 }
1890
1891 BOOL ldap_setup_connection(struct ldap_connection *conn,
1892                            const char *url, const char *userdn, const char *password)
1893 {
1894         int result;
1895
1896         if (!ldap_connect(conn, url)) {
1897                 return False;
1898         }
1899
1900         result = ldap_bind_simple(conn, userdn, password);
1901         if (result == LDAP_SUCCESS) {
1902                 return True;
1903         }
1904
1905         return False;
1906 }
1907
1908 BOOL ldap_setup_connection_with_sasl(struct ldap_connection *conn, const char *url, const char *username, const char *domain, const char *password)
1909 {
1910         int result;
1911
1912         if (!ldap_connect(conn, url)) {
1913                 return False;
1914         }
1915
1916         result = ldap_bind_sasl(conn, username, domain, password);
1917         if (result == LDAP_SUCCESS) {
1918                 return True;
1919         }
1920
1921         return False;
1922 }
1923
1924 static BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
1925                                  const struct timeval *endtime)
1926 {
1927         struct ldap_message *msg = new_ldap_message();
1928         BOOL result;
1929
1930         if (msg == NULL)
1931                 return False;
1932
1933         msg->type = LDAP_TAG_AbandonRequest;
1934         msg->r.AbandonRequest.messageid = msgid;
1935
1936         result = ldap_send_msg(conn, msg, endtime);
1937         destroy_ldap_message(msg);
1938         return result;
1939 }
1940
1941 struct ldap_message *new_ldap_search_message(const char *base,
1942                                              enum ldap_scope scope,
1943                                              char *filter,
1944                                              int num_attributes,
1945                                              const char **attributes)
1946 {
1947         struct ldap_message *res = new_ldap_message();
1948
1949         if (res == NULL)
1950                 return NULL;
1951
1952         res->type = LDAP_TAG_SearchRequest;
1953         res->r.SearchRequest.basedn = base;
1954         res->r.SearchRequest.scope = scope;
1955         res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
1956         res->r.SearchRequest.timelimit = 0;
1957         res->r.SearchRequest.sizelimit = 0;
1958         res->r.SearchRequest.attributesonly = False;
1959         res->r.SearchRequest.filter = filter;
1960         res->r.SearchRequest.num_attributes = num_attributes;
1961         res->r.SearchRequest.attributes = attributes;
1962         return res;
1963 }
1964
1965 struct ldap_message *new_ldap_simple_bind_msg(const char *dn, const char *pw)
1966 {
1967         struct ldap_message *res = new_ldap_message();
1968
1969         if (res == NULL)
1970                 return NULL;
1971
1972         res->type = LDAP_TAG_BindRequest;
1973         res->r.BindRequest.version = 3;
1974         res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
1975         res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
1976         res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
1977         return res;
1978 }
1979
1980 struct ldap_message *new_ldap_sasl_bind_msg(const char *sasl_mechanism, DATA_BLOB *secblob)
1981 {
1982         struct ldap_message *res = new_ldap_message();
1983
1984         if (res == NULL)
1985                 return NULL;
1986
1987         res->type = LDAP_TAG_BindRequest;
1988         res->r.BindRequest.version = 3;
1989         res->r.BindRequest.dn = "";
1990         res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
1991         res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
1992         res->r.BindRequest.creds.SASL.secblob = *secblob;
1993         return res;
1994 }
1995
1996 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
1997                        const struct timeval *endtime)
1998 {
1999         if ((conn->searchid != 0) &&
2000             (!ldap_abandon_message(conn, conn->searchid, endtime)))
2001                 return False;
2002
2003         conn->searchid = conn->next_msgid;
2004         return ldap_send_msg(conn, msg, endtime);
2005 }
2006
2007 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
2008                                        const struct timeval *endtime)
2009 {
2010         struct ldap_message *result;
2011
2012         if (conn->search_entries != NULL) {
2013                 struct ldap_queue_entry *e = conn->search_entries;
2014
2015                 result = e->msg;
2016                 DLIST_REMOVE(conn->search_entries, e);
2017                 SAFE_FREE(e);
2018                 return result;
2019         }
2020
2021         result = ldap_receive(conn, conn->searchid, endtime);
2022
2023         if (result->type == LDAP_TAG_SearchResultEntry)
2024                 return result;
2025
2026         if (result->type == LDAP_TAG_SearchResultDone) {
2027                 /* TODO: Handle Paged Results */
2028                 destroy_ldap_message(result);
2029                 return NULL;
2030         }
2031
2032         /* TODO: Handle Search References here */
2033         return NULL;
2034 }
2035
2036 void ldap_endsearchent(struct ldap_connection *conn,
2037                        const struct timeval *endtime)
2038 {
2039         struct ldap_queue_entry *e;
2040
2041         e = conn->search_entries;
2042
2043         while (e != NULL) {
2044                 struct ldap_queue_entry *next = e->next;
2045                 DLIST_REMOVE(conn->search_entries, e);
2046                 SAFE_FREE(e);
2047                 e = next;
2048         }
2049 }
2050
2051 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
2052                                     struct ldap_message *msg,
2053                                     const struct timeval *endtime)
2054 {
2055         struct ldap_message *res1, *res2 = NULL;
2056         if (!ldap_setsearchent(conn, msg, endtime))
2057                 return NULL;
2058
2059         res1 = ldap_getsearchent(conn, endtime);
2060
2061         if (res1 != NULL)
2062                 res2 = ldap_getsearchent(conn, endtime);
2063
2064         ldap_endsearchent(conn, endtime);
2065
2066         if (res1 == NULL)
2067                 return NULL;
2068
2069         if (res2 != NULL) {
2070                 /* More than one entry */
2071                 destroy_ldap_message(res1);
2072                 destroy_ldap_message(res2);
2073                 return NULL;
2074         }
2075
2076         return res1;
2077 }
2078
2079 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
2080                             DATA_BLOB *value)
2081 {
2082         int i;
2083         struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
2084
2085         if (msg->type != LDAP_TAG_SearchResultEntry)
2086                 return False;
2087
2088         for (i=0; i<r->num_attributes; i++) {
2089                 if (strequal(attr, r->attributes[i].name)) {
2090                         if (r->attributes[i].num_values != 1)
2091                                 return False;
2092
2093                         *value = r->attributes[i].values[0];
2094                         return True;
2095                 }
2096         }
2097         return False;
2098 }
2099
2100 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
2101                              TALLOC_CTX *mem_ctx, char **value)
2102 {
2103         DATA_BLOB blob;
2104
2105         if (!ldap_find_single_value(msg, attr, &blob))
2106                 return False;
2107
2108         *value = talloc(mem_ctx, blob.length+1);
2109
2110         if (*value == NULL)
2111                 return False;
2112
2113         memcpy(*value, blob.data, blob.length);
2114         (*value)[blob.length] = '\0';
2115         return True;
2116 }
2117
2118 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
2119                           int *value)
2120 {
2121         DATA_BLOB blob;
2122         char *val;
2123         int errno_save;
2124         BOOL res;
2125
2126         if (!ldap_find_single_value(msg, attr, &blob))
2127                 return False;
2128
2129         val = malloc(blob.length+1);
2130         if (val == NULL)
2131                 return False;
2132
2133         memcpy(val, blob.data, blob.length);
2134         val[blob.length] = '\0';
2135
2136         errno_save = errno;
2137         errno = 0;
2138
2139         *value = strtol(val, NULL, 10);
2140
2141         res = (errno == 0);
2142
2143         free(val);
2144         errno = errno_save;
2145
2146         return res;
2147 }
2148
2149 int ldap_error(struct ldap_connection *conn)
2150 {
2151         return 0;
2152 }
2153
2154 NTSTATUS ldap2nterror(int ldaperror)
2155 {
2156         return NT_STATUS_OK;
2157 }