10766fe34f522ff6d7cf605ab984e9e821fb8182
[ira/wip.git] / source3 / lib / tldap.c
1 /*
2    Unix SMB/CIFS implementation.
3    Infrastructure for async ldap client requests
4    Copyright (C) Volker Lendecke 2009
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21
22 static bool tevent_req_is_ldap_error(struct tevent_req *req, int *perr)
23 {
24         enum tevent_req_state state;
25         uint64_t err;
26
27         if (!tevent_req_is_error(req, &state, &err)) {
28                 return false;
29         }
30         switch (state) {
31         case TEVENT_REQ_TIMED_OUT:
32                 *perr = TLDAP_TIMEOUT;
33                 break;
34         case TEVENT_REQ_NO_MEMORY:
35                 *perr = TLDAP_NO_MEMORY;
36                 break;
37         case TEVENT_REQ_USER_ERROR:
38                 *perr = err;
39                 break;
40         default:
41                 *perr = TLDAP_OPERATIONS_ERROR;
42                 break;
43         }
44         return true;
45 }
46
47 struct tldap_ctx_attribute {
48         char *name;
49         void *ptr;
50 };
51
52 struct tldap_context {
53         int ld_version;
54         int ld_deref;
55         int ld_sizelimit;
56         int ld_timelimit;
57         int fd;
58         int msgid;
59         struct tevent_queue *outgoing;
60         struct tevent_req **pending;
61
62         /* For the sync wrappers we need something like get_last_error... */
63         int lderr;
64         char *res_matcheddn;
65         char *res_diagnosticmessage;
66         char *res_referral;
67
68         /* debug */
69         void (*log_fn)(void *context, enum tldap_debug_level level,
70                        const char *fmt, va_list ap);
71         void *log_private;
72
73         struct tldap_ctx_attribute *ctx_attrs;
74 };
75
76 struct tldap_message {
77         struct asn1_data *data;
78         uint8_t *inbuf;
79         int type;
80         int id;
81
82         /* RESULT_ENTRY */
83         char *dn;
84         struct tldap_attribute *attribs;
85 };
86
87 void tldap_set_debug(struct tldap_context *ld,
88                      void (*log_fn)(void *log_private,
89                                     enum tldap_debug_level level,
90                                     const char *fmt,
91                                     va_list ap) PRINTF_ATTRIBUTE(3,0),
92                      void *log_private)
93 {
94         ld->log_fn = log_fn;
95         ld->log_private = log_private;
96 }
97
98 static void tldap_debug(struct tldap_context *ld,
99                          enum tldap_debug_level level,
100                          const char *fmt, ...)
101 {
102         va_list ap;
103         if (!ld) {
104                 return;
105         }
106         if (ld->log_fn == NULL) {
107                 return;
108         }
109         va_start(ap, fmt);
110         ld->log_fn(ld->log_private, level, fmt, ap);
111         va_end(ap);
112 }
113
114 static int tldap_next_msgid(struct tldap_context *ld)
115 {
116         int result;
117
118         result = ld->msgid++;
119         if (ld->msgid == 2147483647) {
120                 ld->msgid = 1;
121         }
122         return result;
123 }
124
125 struct tldap_context *tldap_context_create(TALLOC_CTX *mem_ctx, int fd)
126 {
127         struct tldap_context *ctx;
128
129         ctx = talloc_zero(mem_ctx, struct tldap_context);
130         if (ctx == NULL) {
131                 return NULL;
132         }
133         ctx->fd = fd;
134         ctx->msgid = 1;
135         ctx->ld_version = 3;
136         ctx->outgoing = tevent_queue_create(ctx, "tldap_outgoing");
137         if (ctx->outgoing == NULL) {
138                 TALLOC_FREE(ctx);
139                 return NULL;
140         }
141         return ctx;
142 }
143
144 static struct tldap_ctx_attribute *tldap_context_findattr(
145         struct tldap_context *ld, const char *name)
146 {
147         int i, num_attrs;
148
149         num_attrs = talloc_array_length(ld->ctx_attrs);
150
151         for (i=0; i<num_attrs; i++) {
152                 if (strcmp(ld->ctx_attrs[i].name, name) == 0) {
153                         return &ld->ctx_attrs[i];
154                 }
155         }
156         return NULL;
157 }
158
159 bool tldap_context_setattr(struct tldap_context *ld,
160                            const char *name, const void *_pptr)
161 {
162         struct tldap_ctx_attribute *tmp, *attr;
163         char *tmpname;
164         int num_attrs;
165         void **pptr = (void **)_pptr;
166
167         attr = tldap_context_findattr(ld, name);
168         if (attr != NULL) {
169                 /*
170                  * We don't actually delete attrs, we don't expect tons of
171                  * attributes being shuffled around.
172                  */
173                 TALLOC_FREE(attr->ptr);
174                 if (*pptr != NULL) {
175                         attr->ptr = talloc_move(ld->ctx_attrs, pptr);
176                         *pptr = NULL;
177                 }
178                 return true;
179         }
180
181         tmpname = talloc_strdup(ld, name);
182         if (tmpname == NULL) {
183                 return false;
184         }
185
186         num_attrs = talloc_array_length(ld->ctx_attrs);
187
188         tmp = talloc_realloc(ld, ld->ctx_attrs, struct tldap_ctx_attribute,
189                              num_attrs+1);
190         if (tmp == NULL) {
191                 TALLOC_FREE(tmpname);
192                 return false;
193         }
194         tmp[num_attrs].name = talloc_move(tmp, &tmpname);
195         if (*pptr != NULL) {
196                 tmp[num_attrs].ptr = talloc_move(tmp, pptr);
197         } else {
198                 tmp[num_attrs].ptr = NULL;
199         }
200         *pptr = NULL;
201         ld->ctx_attrs = tmp;
202         return true;
203 }
204
205 void *tldap_context_getattr(struct tldap_context *ld, const char *name)
206 {
207         struct tldap_ctx_attribute *attr = tldap_context_findattr(ld, name);
208
209         if (attr == NULL) {
210                 return NULL;
211         }
212         return attr->ptr;
213 }
214
215 struct read_ldap_state {
216         uint8_t *buf;
217         bool done;
218 };
219
220 static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data)
221 {
222         struct read_ldap_state *state = talloc_get_type_abort(
223                 private_data, struct read_ldap_state);
224         size_t len;
225         int i, lensize;
226
227         if (state->done) {
228                 /* We've been here, we're done */
229                 return 0;
230         }
231
232         /*
233          * From ldap.h: LDAP_TAG_MESSAGE is 0x30
234          */
235         if (buf[0] != 0x30) {
236                 return -1;
237         }
238
239         len = buf[1];
240         if ((len & 0x80) == 0) {
241                 state->done = true;
242                 return len;
243         }
244
245         lensize = (len & 0x7f);
246         len = 0;
247
248         if (buflen == 2) {
249                 /* Please get us the full length */
250                 return lensize;
251         }
252         if (buflen > 2 + lensize) {
253                 state->done = true;
254                 return 0;
255         }
256         if (buflen != 2 + lensize) {
257                 return -1;
258         }
259
260         for (i=0; i<lensize; i++) {
261                 len = (len << 8) | buf[2+i];
262         }
263         return len;
264 }
265
266 static void read_ldap_done(struct tevent_req *subreq);
267
268 static struct tevent_req *read_ldap_send(TALLOC_CTX *mem_ctx,
269                                          struct tevent_context *ev,
270                                          int fd)
271 {
272         struct tevent_req *req, *subreq;
273         struct read_ldap_state *state;
274
275         req = tevent_req_create(mem_ctx, &state, struct read_ldap_state);
276         if (req == NULL) {
277                 return NULL;
278         }
279         state->done = false;
280
281         subreq = read_packet_send(state, ev, fd, 2, read_ldap_more, state);
282         if (tevent_req_nomem(subreq, req)) {
283                 return tevent_req_post(req, ev);
284         }
285         tevent_req_set_callback(subreq, read_ldap_done, req);
286         return req;
287 }
288
289 static void read_ldap_done(struct tevent_req *subreq)
290 {
291         struct tevent_req *req = tevent_req_callback_data(
292                 subreq, struct tevent_req);
293         struct read_ldap_state *state = tevent_req_data(
294                 req, struct read_ldap_state);
295         ssize_t nread;
296         int err;
297
298         nread = read_packet_recv(subreq, state, &state->buf, &err);
299         TALLOC_FREE(subreq);
300         if (nread == -1) {
301                 tevent_req_error(req, err);
302                 return;
303         }
304         tevent_req_done(req);
305 }
306
307 static ssize_t read_ldap_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
308                               uint8_t **pbuf, int *perrno)
309 {
310         struct read_ldap_state *state = tevent_req_data(
311                 req, struct read_ldap_state);
312
313         if (tevent_req_is_unix_error(req, perrno)) {
314                 return -1;
315         }
316         *pbuf = talloc_move(mem_ctx, &state->buf);
317         return talloc_get_size(*pbuf);
318 }
319
320 static bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob)
321 {
322         if (asn1->has_error) {
323                 return false;
324         }
325         if (asn1->nesting != NULL) {
326                 return false;
327         }
328         blob->data = asn1->data;
329         blob->length = asn1->length;
330         return true;
331 }
332
333 static void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len)
334 {
335         ZERO_STRUCTP(data);
336         data->data = buf;
337         data->length = len;
338 }
339
340 struct tldap_msg_state {
341         struct tldap_context *ld;
342         struct tevent_context *ev;
343         int id;
344         struct iovec iov;
345
346         struct asn1_data *data;
347         uint8_t *inbuf;
348 };
349
350 static void tldap_msg_sent(struct tevent_req *subreq);
351 static void tldap_msg_received(struct tevent_req *subreq);
352
353 static struct tevent_req *tldap_msg_send(TALLOC_CTX *mem_ctx,
354                                          struct tevent_context *ev,
355                                          struct tldap_context *ld,
356                                          int id, struct asn1_data *data)
357 {
358         struct tevent_req *req, *subreq;
359         struct tldap_msg_state *state;
360         DATA_BLOB blob;
361
362         tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_send: sending msg %d\n",
363                     id);
364
365         req = tevent_req_create(mem_ctx, &state, struct tldap_msg_state);
366         if (req == NULL) {
367                 return NULL;
368         }
369         state->ld = ld;
370         state->ev = ev;
371         state->id = id;
372
373         asn1_pop_tag(data);
374
375         if (!asn1_blob(data, &blob)) {
376                 tevent_req_error(req, TLDAP_ENCODING_ERROR);
377                 return tevent_req_post(req, ev);
378         }
379
380         state->iov.iov_base = blob.data;
381         state->iov.iov_len = blob.length;
382
383         subreq = writev_send(state, ev, ld->outgoing, ld->fd, false,
384                              &state->iov, 1);
385         if (tevent_req_nomem(subreq, req)) {
386                 return tevent_req_post(req, ev);
387         }
388         tevent_req_set_callback(subreq, tldap_msg_sent, req);
389         return req;
390 }
391
392 static void tldap_msg_unset_pending(struct tevent_req *req)
393 {
394         struct tldap_msg_state *state = tevent_req_data(
395                 req, struct tldap_msg_state);
396         struct tldap_context *ld = state->ld;
397         int num_pending = talloc_array_length(ld->pending);
398         int i;
399
400         if (num_pending == 1) {
401                 TALLOC_FREE(ld->pending);
402                 return;
403         }
404
405         for (i=0; i<num_pending; i++) {
406                 if (req == ld->pending[i]) {
407                         break;
408                 }
409         }
410         if (i == num_pending) {
411                 /*
412                  * Something's seriously broken. Just returning here is the
413                  * right thing nevertheless, the point of this routine is to
414                  * remove ourselves from cli->pending.
415                  */
416                 return;
417         }
418
419         /*
420          * Remove ourselves from the cli->pending array
421          */
422         if (num_pending > 1) {
423                 ld->pending[i] = ld->pending[num_pending-1];
424         }
425
426         /*
427          * No NULL check here, we're shrinking by sizeof(void *), and
428          * talloc_realloc just adjusts the size for this.
429          */
430         ld->pending = talloc_realloc(NULL, ld->pending, struct tevent_req *,
431                                      num_pending - 1);
432         return;
433 }
434
435 static int tldap_msg_destructor(struct tevent_req *req)
436 {
437         tldap_msg_unset_pending(req);
438         return 0;
439 }
440
441 static bool tldap_msg_set_pending(struct tevent_req *req)
442 {
443         struct tldap_msg_state *state = tevent_req_data(
444                 req, struct tldap_msg_state);
445         struct tldap_context *ld;
446         struct tevent_req **pending;
447         int num_pending;
448         struct tevent_req *subreq;
449
450         ld = state->ld;
451         num_pending = talloc_array_length(ld->pending);
452
453         pending = talloc_realloc(ld, ld->pending, struct tevent_req *,
454                                  num_pending+1);
455         if (pending == NULL) {
456                 return false;
457         }
458         pending[num_pending] = req;
459         ld->pending = pending;
460         talloc_set_destructor(req, tldap_msg_destructor);
461
462         if (num_pending > 0) {
463                 return true;
464         }
465
466         /*
467          * We're the first ones, add the read_ldap request that waits for the
468          * answer from the server
469          */
470         subreq = read_ldap_send(ld->pending, state->ev, ld->fd);
471         if (subreq == NULL) {
472                 tldap_msg_unset_pending(req);
473                 return false;
474         }
475         tevent_req_set_callback(subreq, tldap_msg_received, ld);
476         return true;
477 }
478
479 static void tldap_msg_sent(struct tevent_req *subreq)
480 {
481         struct tevent_req *req = tevent_req_callback_data(
482                 subreq, struct tevent_req);
483         ssize_t nwritten;
484         int err;
485
486         nwritten = writev_recv(subreq, &err);
487         TALLOC_FREE(subreq);
488         if (nwritten == -1) {
489                 tevent_req_error(req, TLDAP_SERVER_DOWN);
490                 return;
491         }
492
493         if (!tldap_msg_set_pending(req)) {
494                 tevent_req_nomem(NULL, req);
495                 return;
496         }
497 }
498
499 static int tldap_msg_msgid(struct tevent_req *req)
500 {
501         struct tldap_msg_state *state = tevent_req_data(
502                 req, struct tldap_msg_state);
503
504         return state->id;
505 }
506
507 static void tldap_msg_received(struct tevent_req *subreq)
508 {
509         struct tldap_context *ld = tevent_req_callback_data(
510                 subreq, struct tldap_context);
511         struct tevent_req *req;
512         struct tldap_msg_state *state;
513         struct tevent_context *ev;
514         struct asn1_data *data;
515         uint8_t *inbuf;
516         ssize_t received;
517         size_t num_pending;
518         int i, err, status;
519         int id;
520         uint8_t type;
521         bool ok;
522
523         received = read_ldap_recv(subreq, talloc_tos(), &inbuf, &err);
524         TALLOC_FREE(subreq);
525         if (received == -1) {
526                 status = TLDAP_SERVER_DOWN;
527                 goto fail;
528         }
529
530         data = asn1_init(talloc_tos());
531         if (data == NULL) {
532                 status = TLDAP_NO_MEMORY;
533                 goto fail;
534         }
535         asn1_load_nocopy(data, inbuf, received);
536
537         ok = true;
538         ok &= asn1_start_tag(data, ASN1_SEQUENCE(0));
539         ok &= asn1_read_Integer(data, &id);
540         ok &= asn1_peek_uint8(data, &type);
541
542         if (!ok) {
543                 status = TLDAP_PROTOCOL_ERROR;
544                 goto fail;
545         }
546
547         tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_received: got msg %d "
548                     "type %d\n", id, (int)type);
549
550         num_pending = talloc_array_length(ld->pending);
551
552         for (i=0; i<num_pending; i++) {
553                 if (id == tldap_msg_msgid(ld->pending[i])) {
554                         break;
555                 }
556         }
557         if (i == num_pending) {
558                 /* Dump unexpected reply */
559                 tldap_debug(ld, TLDAP_DEBUG_WARNING, "tldap_msg_received: "
560                             "No request pending for msg %d\n", id);
561                 TALLOC_FREE(inbuf);
562                 goto done;
563         }
564
565         req = ld->pending[i];
566         state = tevent_req_data(req, struct tldap_msg_state);
567
568         state->inbuf = talloc_move(state, &inbuf);
569         state->data = talloc_move(state, &data);
570
571         ev = state->ev;
572
573         talloc_set_destructor(req, NULL);
574         tldap_msg_destructor(req);
575         tevent_req_done(req);
576
577  done:
578         if (talloc_array_length(ld->pending) > 0) {
579                 state = tevent_req_data(ld->pending[0],
580                                         struct tldap_msg_state);
581                 subreq = read_ldap_send(ld->pending, state->ev, ld->fd);
582                 if (subreq == NULL) {
583                         status = TLDAP_NO_MEMORY;
584                         goto fail;
585                 }
586                 tevent_req_set_callback(subreq, tldap_msg_received, ld);
587         }
588         return;
589
590  fail:
591         while (talloc_array_length(ld->pending) > 0) {
592                 req = ld->pending[0];
593                 talloc_set_destructor(req, NULL);
594                 tldap_msg_destructor(req);
595                 tevent_req_error(req, status);
596         }
597 }
598
599 static int tldap_msg_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
600                           struct tldap_message **pmsg)
601 {
602         struct tldap_msg_state *state = tevent_req_data(
603                 req, struct tldap_msg_state);
604         struct tldap_message *msg;
605         int err;
606         uint8_t msgtype;
607
608         if (tevent_req_is_ldap_error(req, &err)) {
609                 return err;
610         }
611
612         if (!asn1_peek_uint8(state->data, &msgtype)) {
613                 return TLDAP_PROTOCOL_ERROR;
614         }
615
616         if (pmsg == NULL) {
617                 return TLDAP_SUCCESS;
618         }
619
620         msg = talloc_zero(mem_ctx, struct tldap_message);
621         if (msg == NULL) {
622                 return TLDAP_NO_MEMORY;
623         }
624         msg->id = state->id;
625
626         msg->inbuf = talloc_move(msg, &state->inbuf);
627         msg->data = talloc_move(msg, &state->data);
628         msg->type = msgtype;
629
630         *pmsg = msg;
631         return TLDAP_SUCCESS;
632 }
633
634 struct tldap_req_state {
635         int id;
636         struct asn1_data *out;
637         struct tldap_message *result;
638
639         int lderr;
640         char *res_matcheddn;
641         char *res_diagnosticmessage;
642         char *res_referral;
643 };
644
645 static struct tevent_req *tldap_req_create(TALLOC_CTX *mem_ctx,
646                                            struct tldap_context *ld,
647                                            struct tldap_req_state **pstate)
648 {
649         struct tevent_req *req;
650         struct tldap_req_state *state;
651
652         req = tevent_req_create(mem_ctx, &state, struct tldap_req_state);
653         if (req == NULL) {
654                 return NULL;
655         }
656         ZERO_STRUCTP(state);
657         state->out = asn1_init(state);
658         if (state->out == NULL) {
659                 TALLOC_FREE(req);
660                 return NULL;
661         }
662         state->result = NULL;
663         state->id = tldap_next_msgid(ld);
664
665         asn1_push_tag(state->out, ASN1_SEQUENCE(0));
666         asn1_write_Integer(state->out, state->id);
667
668         *pstate = state;
669         return req;
670 }
671
672 static void tldap_save_errors(struct tldap_context *ctx,
673                               struct tevent_req *req)
674 {
675         struct tldap_req_state *state = tevent_req_data(
676                 req, struct tldap_req_state);
677
678         TALLOC_FREE(ctx->res_matcheddn);
679         TALLOC_FREE(ctx->res_diagnosticmessage);
680         TALLOC_FREE(ctx->res_referral);
681
682         ctx->lderr = state->lderr;
683         ctx->res_matcheddn = talloc_move(ctx, &state->res_matcheddn);
684         ctx->res_diagnosticmessage = talloc_move(
685                 ctx, &state->res_diagnosticmessage);
686         ctx->res_referral = talloc_move(ctx, &state->res_referral);
687 }
688
689 static char *blob2string_talloc(TALLOC_CTX *mem_ctx, DATA_BLOB blob)
690 {
691         char *result = talloc_array(mem_ctx, char, blob.length+1);
692         memcpy(result, blob.data, blob.length);
693         result[blob.length] = '\0';
694         return result;
695 }
696
697 static bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
698                                          struct asn1_data *data,
699                                          char **result)
700 {
701         DATA_BLOB string;
702         if (!asn1_read_OctetString(data, mem_ctx, &string))
703                 return false;
704         *result = blob2string_talloc(mem_ctx, string);
705         data_blob_free(&string);
706         return true;
707 }
708
709 static bool tldap_decode_response(struct tldap_req_state *state)
710 {
711         struct asn1_data *data = state->result->data;
712         bool ok = true;
713
714         ok &= asn1_read_enumerated(data, &state->lderr);
715         ok &= asn1_read_OctetString_talloc(state, data, &state->res_matcheddn);
716         ok &= asn1_read_OctetString_talloc(state, data,
717                                            &state->res_diagnosticmessage);
718         if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
719                 ok &= asn1_start_tag(data, ASN1_CONTEXT(3));
720                 ok &= asn1_read_OctetString_talloc(
721                         state, data, &state->res_referral);
722                 ok &= asn1_end_tag(data);
723         } else {
724                 state->res_referral = NULL;
725         }
726
727         return ok;
728 }
729
730 static void tldap_sasl_bind_done(struct tevent_req *subreq);
731
732 struct tevent_req *tldap_sasl_bind_send(TALLOC_CTX *mem_ctx,
733                                         struct tevent_context *ev,
734                                         struct tldap_context *ld,
735                                         const char *dn,
736                                         const char *mechanism,
737                                         DATA_BLOB *creds,
738                                         struct tldap_control **sctrls,
739                                         struct tldap_control **cctrls)
740 {
741         struct tevent_req *req, *subreq;
742         struct tldap_req_state *state;
743
744         req = tldap_req_create(mem_ctx, ld, &state);
745         if (req == NULL) {
746                 return NULL;
747         }
748
749         if (dn == NULL) {
750                 dn = "";
751         }
752
753         asn1_push_tag(state->out, TLDAP_REQ_BIND);
754         asn1_write_Integer(state->out, ld->ld_version);
755         asn1_write_OctetString(state->out, dn, (dn != NULL) ? strlen(dn) : 0);
756
757         if (mechanism == NULL) {
758                 asn1_push_tag(state->out, ASN1_CONTEXT_SIMPLE(0));
759                 asn1_write(state->out, creds->data, creds->length);
760                 asn1_pop_tag(state->out);
761         } else {
762                 asn1_push_tag(state->out, ASN1_CONTEXT(3));
763                 asn1_write_OctetString(state->out, mechanism,
764                                        strlen(mechanism));
765                 if ((creds != NULL) && (creds->data != NULL)) {
766                         asn1_write_OctetString(state->out, creds->data,
767                                                creds->length);
768                 }
769                 asn1_pop_tag(state->out);
770         }
771
772         if (!asn1_pop_tag(state->out)) {
773                 tevent_req_error(req, TLDAP_ENCODING_ERROR);
774                 return tevent_req_post(req, ev);
775         }
776
777         subreq = tldap_msg_send(state, ev, ld, state->id, state->out);
778         if (tevent_req_nomem(subreq, req)) {
779                 return tevent_req_post(req, ev);
780         }
781         tevent_req_set_callback(subreq, tldap_sasl_bind_done, req);
782         return req;
783 }
784
785 static void tldap_sasl_bind_done(struct tevent_req *subreq)
786 {
787         struct tevent_req *req = tevent_req_callback_data(
788                 subreq, struct tevent_req);
789         struct tldap_req_state *state = tevent_req_data(
790                 req, struct tldap_req_state);
791         int err;
792
793         err = tldap_msg_recv(subreq, state, &state->result);
794         TALLOC_FREE(subreq);
795         if (err != TLDAP_SUCCESS) {
796                 tevent_req_error(req, err);
797                 return;
798         }
799         if (state->result->type != TLDAP_RES_BIND) {
800                 tevent_req_error(req, TLDAP_PROTOCOL_ERROR);
801                 return;
802         }
803         if (!asn1_start_tag(state->result->data, state->result->type) ||
804             !tldap_decode_response(state) ||
805             !asn1_end_tag(state->result->data)) {
806                 tevent_req_error(req, TLDAP_DECODING_ERROR);
807                 return;
808         }
809         /*
810          * TODO: pull the reply blob
811          */
812         if (state->lderr != TLDAP_SUCCESS) {
813                 tevent_req_error(req, state->lderr);
814                 return;
815         }
816         tevent_req_done(req);
817 }
818
819 int tldap_sasl_bind_recv(struct tevent_req *req)
820 {
821         int err;
822
823         if (tevent_req_is_ldap_error(req, &err)) {
824                 return err;
825         }
826         return TLDAP_SUCCESS;
827 }
828
829 int tldap_sasl_bind(struct tldap_context *ld,
830                     const char *dn,
831                     const char *mechanism,
832                     DATA_BLOB *creds,
833                     struct tldap_control **sctrls,
834                     struct tldap_control **cctrls)
835 {
836         TALLOC_CTX *frame = talloc_stackframe();
837         struct tevent_context *ev;
838         struct tevent_req *req;
839         int result;
840
841         ev = event_context_init(frame);
842         if (ev == NULL) {
843                 result = TLDAP_NO_MEMORY;
844                 goto fail;
845         }
846
847         req = tldap_sasl_bind_send(frame, ev, ld, dn, mechanism, creds,
848                                    sctrls, cctrls);
849         if (req == NULL) {
850                 result = TLDAP_NO_MEMORY;
851                 goto fail;
852         }
853
854         if (!tevent_req_poll(req, ev)) {
855                 result = TLDAP_OPERATIONS_ERROR;
856                 goto fail;
857         }
858
859         result = tldap_sasl_bind_recv(req);
860         tldap_save_errors(ld, req);
861  fail:
862         TALLOC_FREE(frame);
863         return result;
864 }
865
866 struct tevent_req *tldap_simple_bind_send(TALLOC_CTX *mem_ctx,
867                                           struct tevent_context *ev,
868                                           struct tldap_context *ld,
869                                           const char *dn,
870                                           const char *passwd)
871 {
872         DATA_BLOB cred;
873
874         if (passwd != NULL) {
875                 cred.data = (uint8_t *)passwd;
876                 cred.length = strlen(passwd);
877         } else {
878                 cred.data = (uint8_t *)"";
879                 cred.length = 0;
880         }
881         return tldap_sasl_bind_send(mem_ctx, ev, ld, dn, NULL, &cred, NULL,
882                                     NULL);
883 }
884
885 int tldap_simple_bind_recv(struct tevent_req *req)
886 {
887         return tldap_sasl_bind_recv(req);
888 }
889
890 int tldap_simple_bind(struct tldap_context *ld, const char *dn,
891                       const char *passwd)
892 {
893         DATA_BLOB cred;
894
895         if (passwd != NULL) {
896                 cred.data = (uint8_t *)passwd;
897                 cred.length = strlen(passwd);
898         } else {
899                 cred.data = (uint8_t *)"";
900                 cred.length = 0;
901         }
902         return tldap_sasl_bind(ld, dn, NULL, &cred, NULL, NULL);
903 }
904
905 /*****************************************************************************/
906
907 /*
908  * This piece has a dependency on ldb, the ldb_parse_tree() function is used.
909  * In case we want to separate out tldap, we need to copy or rewrite it.
910  */
911
912 #include "lib/ldb/include/ldb.h"
913 #include "lib/ldb/include/ldb_errors.h"
914
915 static bool ldap_push_filter(struct asn1_data *data,
916                              struct ldb_parse_tree *tree)
917 {
918         int i;
919
920         switch (tree->operation) {
921         case LDB_OP_AND:
922         case LDB_OP_OR:
923                 asn1_push_tag(data,
924                               ASN1_CONTEXT(tree->operation==LDB_OP_AND?0:1));
925                 for (i=0; i<tree->u.list.num_elements; i++) {
926                         if (!ldap_push_filter(data,
927                                               tree->u.list.elements[i])) {
928                                 return false;
929                         }
930                 }
931                 asn1_pop_tag(data);
932                 break;
933
934         case LDB_OP_NOT:
935                 asn1_push_tag(data, ASN1_CONTEXT(2));
936                 if (!ldap_push_filter(data, tree->u.isnot.child)) {
937                         return false;
938                 }
939                 asn1_pop_tag(data);
940                 break;
941
942         case LDB_OP_EQUALITY:
943                 /* equality test */
944                 asn1_push_tag(data, ASN1_CONTEXT(3));
945                 asn1_write_OctetString(data, tree->u.equality.attr,
946                                       strlen(tree->u.equality.attr));
947                 asn1_write_OctetString(data, tree->u.equality.value.data,
948                                       tree->u.equality.value.length);
949                 asn1_pop_tag(data);
950                 break;
951
952         case LDB_OP_SUBSTRING:
953                 /*
954                   SubstringFilter ::= SEQUENCE {
955                           type            AttributeDescription,
956                           -- at least one must be present
957                           substrings      SEQUENCE OF CHOICE {
958                                   initial [0] LDAPString,
959                                   any     [1] LDAPString,
960                                   final   [2] LDAPString } }
961                 */
962                 asn1_push_tag(data, ASN1_CONTEXT(4));
963                 asn1_write_OctetString(data, tree->u.substring.attr,
964                                        strlen(tree->u.substring.attr));
965                 asn1_push_tag(data, ASN1_SEQUENCE(0));
966                 i = 0;
967                 if (!tree->u.substring.start_with_wildcard) {
968                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
969                         asn1_write_DATA_BLOB_LDAPString(
970                                 data, tree->u.substring.chunks[i]);
971                         asn1_pop_tag(data);
972                         i++;
973                 }
974                 while (tree->u.substring.chunks[i]) {
975                         int ctx;
976
977                         if ((!tree->u.substring.chunks[i + 1]) &&
978                             (tree->u.substring.end_with_wildcard == 0)) {
979                                 ctx = 2;
980                         } else {
981                                 ctx = 1;
982                         }
983                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(ctx));
984                         asn1_write_DATA_BLOB_LDAPString(
985                                 data, tree->u.substring.chunks[i]);
986                         asn1_pop_tag(data);
987                         i++;
988                 }
989                 asn1_pop_tag(data);
990                 asn1_pop_tag(data);
991                 break;
992
993         case LDB_OP_GREATER:
994                 /* greaterOrEqual test */
995                 asn1_push_tag(data, ASN1_CONTEXT(5));
996                 asn1_write_OctetString(data, tree->u.comparison.attr,
997                                       strlen(tree->u.comparison.attr));
998                 asn1_write_OctetString(data, tree->u.comparison.value.data,
999                                       tree->u.comparison.value.length);
1000                 asn1_pop_tag(data);
1001                 break;
1002
1003         case LDB_OP_LESS:
1004                 /* lessOrEqual test */
1005                 asn1_push_tag(data, ASN1_CONTEXT(6));
1006                 asn1_write_OctetString(data, tree->u.comparison.attr,
1007                                       strlen(tree->u.comparison.attr));
1008                 asn1_write_OctetString(data, tree->u.comparison.value.data,
1009                                       tree->u.comparison.value.length);
1010                 asn1_pop_tag(data);
1011                 break;
1012
1013         case LDB_OP_PRESENT:
1014                 /* present test */
1015                 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(7));
1016                 asn1_write_LDAPString(data, tree->u.present.attr);
1017                 asn1_pop_tag(data);
1018                 return !data->has_error;
1019
1020         case LDB_OP_APPROX:
1021                 /* approx test */
1022                 asn1_push_tag(data, ASN1_CONTEXT(8));
1023                 asn1_write_OctetString(data, tree->u.comparison.attr,
1024                                       strlen(tree->u.comparison.attr));
1025                 asn1_write_OctetString(data, tree->u.comparison.value.data,
1026                                       tree->u.comparison.value.length);
1027                 asn1_pop_tag(data);
1028                 break;
1029
1030         case LDB_OP_EXTENDED:
1031                 /*
1032                   MatchingRuleAssertion ::= SEQUENCE {
1033                   matchingRule    [1] MatchingRuleID OPTIONAL,
1034                   type            [2] AttributeDescription OPTIONAL,
1035                   matchValue      [3] AssertionValue,
1036                   dnAttributes    [4] BOOLEAN DEFAULT FALSE
1037                   }
1038                 */
1039                 asn1_push_tag(data, ASN1_CONTEXT(9));
1040                 if (tree->u.extended.rule_id) {
1041                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1));
1042                         asn1_write_LDAPString(data, tree->u.extended.rule_id);
1043                         asn1_pop_tag(data);
1044                 }
1045                 if (tree->u.extended.attr) {
1046                         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2));
1047                         asn1_write_LDAPString(data, tree->u.extended.attr);
1048                         asn1_pop_tag(data);
1049                 }
1050                 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3));
1051                 asn1_write_DATA_BLOB_LDAPString(data, &tree->u.extended.value);
1052                 asn1_pop_tag(data);
1053                 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4));
1054                 asn1_write_uint8(data, tree->u.extended.dnAttributes);
1055                 asn1_pop_tag(data);
1056                 asn1_pop_tag(data);
1057                 break;
1058
1059         default:
1060                 return false;
1061         }
1062         return !data->has_error;
1063 }
1064
1065 static bool tldap_push_filter(struct asn1_data *data, const char *filter)
1066 {
1067         struct ldb_parse_tree *tree;
1068         bool ret;
1069
1070         tree = ldb_parse_tree(talloc_tos(), filter);
1071         if (tree == NULL) {
1072                 return false;
1073         }
1074         ret = ldap_push_filter(data, tree);
1075         TALLOC_FREE(tree);
1076         return ret;
1077 }
1078
1079 /*****************************************************************************/
1080
1081 static void tldap_search_done(struct tevent_req *subreq);
1082
1083 struct tevent_req *tldap_search_send(TALLOC_CTX *mem_ctx,
1084                                      struct tevent_context *ev,
1085                                      struct tldap_context *ld,
1086                                      const char *base, int scope,
1087                                      const char *filter,
1088                                      const char **attrs,
1089                                      int num_attrs,
1090                                      int attrsonly,
1091                                      struct tldap_control **sctrls,
1092                                      struct tldap_control **cctrls,
1093                                      int timelimit,
1094                                      int sizelimit,
1095                                      int deref)
1096 {
1097         struct tevent_req *req, *subreq;
1098         struct tldap_req_state *state;
1099         int i;
1100
1101         req = tldap_req_create(mem_ctx, ld, &state);
1102         if (req == NULL) {
1103                 return NULL;
1104         }
1105
1106         asn1_push_tag(state->out, TLDAP_REQ_SEARCH);
1107         asn1_write_OctetString(state->out, base, strlen(base));
1108         asn1_write_enumerated(state->out, scope);
1109         asn1_write_enumerated(state->out, deref);
1110         asn1_write_Integer(state->out, sizelimit);
1111         asn1_write_Integer(state->out, timelimit);
1112         asn1_write_BOOLEAN(state->out, attrsonly);
1113
1114         if (!tldap_push_filter(state->out, filter)) {
1115                 goto encoding_error;
1116         }
1117
1118         asn1_push_tag(state->out, ASN1_SEQUENCE(0));
1119         for (i=0; i<num_attrs; i++) {
1120                 asn1_write_OctetString(state->out, attrs[i], strlen(attrs[i]));
1121         }
1122         asn1_pop_tag(state->out);
1123         asn1_pop_tag(state->out);
1124
1125         subreq = tldap_msg_send(state, ev, ld, state->id, state->out);
1126         if (tevent_req_nomem(subreq, req)) {
1127                 return tevent_req_post(req, ev);
1128         }
1129         tevent_req_set_callback(subreq, tldap_search_done, req);
1130         return req;
1131
1132  encoding_error:
1133         tevent_req_error(req, TLDAP_ENCODING_ERROR);
1134         return tevent_req_post(req, ev);
1135 }
1136
1137 static void tldap_search_done(struct tevent_req *subreq)
1138 {
1139         struct tevent_req *req = tevent_req_callback_data(
1140                 subreq, struct tevent_req);
1141         struct tldap_req_state *state = tevent_req_data(
1142                 req, struct tldap_req_state);
1143         int err;
1144
1145         err = tldap_msg_recv(subreq, state, &state->result);
1146         if (err != TLDAP_SUCCESS) {
1147                 tevent_req_error(req, err);
1148                 return;
1149         }
1150         switch (state->result->type) {
1151         case TLDAP_RES_SEARCH_ENTRY:
1152         case TLDAP_RES_SEARCH_REFERENCE:
1153                 tevent_req_notify_callback(req);
1154                 if (!tldap_msg_set_pending(subreq)) {
1155                         tevent_req_nomem(NULL, req);
1156                         return;
1157                 }
1158                 break;
1159         case TLDAP_RES_SEARCH_RESULT:
1160                 TALLOC_FREE(subreq);
1161                 if (!asn1_start_tag(state->result->data,
1162                                     state->result->type) ||
1163                     !tldap_decode_response(state) ||
1164                     !asn1_end_tag(state->result->data)) {
1165                         tevent_req_error(req, TLDAP_DECODING_ERROR);
1166                         return;
1167                 }
1168                 tevent_req_done(req);
1169                 break;
1170         default:
1171                 tevent_req_error(req, TLDAP_PROTOCOL_ERROR);
1172                 return;
1173         }
1174 }
1175
1176 int tldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1177                       struct tldap_message **pmsg)
1178 {
1179         struct tldap_req_state *state = tevent_req_data(
1180                 req, struct tldap_req_state);
1181         int err;
1182
1183         if (!tevent_req_is_in_progress(req)
1184             && tevent_req_is_ldap_error(req, &err)) {
1185                 return err;
1186         }
1187
1188         if (tevent_req_is_in_progress(req)) {
1189                 switch (state->result->type) {
1190                 case TLDAP_RES_SEARCH_ENTRY:
1191                 case TLDAP_RES_SEARCH_REFERENCE:
1192                         break;
1193                 default:
1194                         return TLDAP_OPERATIONS_ERROR;
1195                 }
1196         }
1197
1198         *pmsg = state->result;
1199         return TLDAP_SUCCESS;
1200 }
1201
1202 struct tldap_sync_search_state {
1203         TALLOC_CTX *mem_ctx;
1204         struct tldap_message **entries;
1205         struct tldap_message **refs;
1206         int rc;
1207 };
1208
1209 static void tldap_search_cb(struct tevent_req *req)
1210 {
1211         struct tldap_sync_search_state *state =
1212                 (struct tldap_sync_search_state *)
1213                 tevent_req_callback_data_void(req);
1214         struct tldap_message *msg, **tmp;
1215         int rc, num_entries, num_refs;
1216
1217         rc = tldap_search_recv(req, talloc_tos(), &msg);
1218         if (rc != TLDAP_SUCCESS) {
1219                 state->rc = rc;
1220                 return;
1221         }
1222
1223         switch (tldap_msg_type(msg)) {
1224         case TLDAP_RES_SEARCH_ENTRY:
1225                 num_entries = talloc_array_length(state->entries);
1226                 tmp = talloc_realloc(state->mem_ctx, state->entries,
1227                                      struct tldap_message *, num_entries + 1);
1228                 if (tmp == NULL) {
1229                         state->rc = TLDAP_NO_MEMORY;
1230                         return;
1231                 }
1232                 state->entries = tmp;
1233                 state->entries[num_entries] = talloc_move(state->entries,
1234                                                           &msg);
1235                 break;
1236         case TLDAP_RES_SEARCH_REFERENCE:
1237                 num_refs = talloc_array_length(state->refs);
1238                 tmp = talloc_realloc(state->mem_ctx, state->refs,
1239                                      struct tldap_message *, num_refs + 1);
1240                 if (tmp == NULL) {
1241                         state->rc = TLDAP_NO_MEMORY;
1242                         return;
1243                 }
1244                 state->refs = tmp;
1245                 state->refs[num_refs] = talloc_move(state->refs, &msg);
1246                 break;
1247         case TLDAP_RES_SEARCH_RESULT:
1248                 state->rc = TLDAP_SUCCESS;
1249                 break;
1250         default:
1251                 state->rc = TLDAP_PROTOCOL_ERROR;
1252                 break;
1253         }
1254 }
1255
1256 int tldap_search(struct tldap_context *ld,
1257                  const char *base, int scope, const char *filter,
1258                  const char **attrs, int num_attrs, int attrsonly,
1259                  struct tldap_control **sctrls, struct tldap_control **cctrls,
1260                  int timelimit, int sizelimit, int deref,
1261                  TALLOC_CTX *mem_ctx, struct tldap_message ***entries,
1262                  struct tldap_message ***refs)
1263 {
1264         TALLOC_CTX *frame = talloc_stackframe();
1265         struct tevent_context *ev;
1266         struct tevent_req *req;
1267         struct tldap_sync_search_state state;
1268
1269         ZERO_STRUCT(state);
1270         state.mem_ctx = mem_ctx;
1271         state.rc = TLDAP_SUCCESS;
1272
1273         ev = event_context_init(frame);
1274         if (ev == NULL) {
1275                 state.rc = TLDAP_NO_MEMORY;
1276                 goto fail;
1277         }
1278
1279         req = tldap_search_send(frame, ev, ld, base, scope, filter,
1280                                 attrs, num_attrs, attrsonly,
1281                                 sctrls, cctrls, timelimit,
1282                                 sizelimit, deref);
1283         if (req == NULL) {
1284                 state.rc = TLDAP_NO_MEMORY;
1285                 goto fail;
1286         }
1287
1288         tevent_req_set_callback(req, tldap_search_cb, &state);
1289
1290         while (tevent_req_is_in_progress(req)
1291                && (state.rc == TLDAP_SUCCESS)) {
1292                 if (tevent_loop_once(ev) == -1) {
1293                         return TLDAP_OPERATIONS_ERROR;
1294                 }
1295         }
1296
1297         if (state.rc != TLDAP_SUCCESS) {
1298                 return state.rc;
1299         }
1300
1301         if (entries != NULL) {
1302                 *entries = state.entries;
1303         } else {
1304                 TALLOC_FREE(state.entries);
1305         }
1306         if (refs != NULL) {
1307                 *refs = state.refs;
1308         } else {
1309                 TALLOC_FREE(state.refs);
1310         }
1311         tldap_save_errors(ld, req);
1312 fail:
1313         TALLOC_FREE(frame);
1314         return state.rc;
1315 }
1316
1317 static bool tldap_parse_search_entry(struct tldap_message *msg)
1318 {
1319         int num_attribs = 0;
1320
1321         asn1_start_tag(msg->data, msg->type);
1322
1323         /* dn */
1324
1325         asn1_read_OctetString_talloc(msg, msg->data, &msg->dn);
1326         if (msg->dn == NULL) {
1327                 return false;
1328         }
1329
1330         /*
1331          * Attributes: We overallocate msg->attribs by one, so that while
1332          * looping over the attributes we can directly parse into the last
1333          * array element. Same for the values in the inner loop.
1334          */
1335
1336         msg->attribs = talloc_array(msg, struct tldap_attribute, 1);
1337         if (msg->attribs == NULL) {
1338                 return false;
1339         }
1340
1341         asn1_start_tag(msg->data, ASN1_SEQUENCE(0));
1342         while (asn1_peek_tag(msg->data, ASN1_SEQUENCE(0))) {
1343                 struct tldap_attribute *attrib;
1344                 int num_values = 0;
1345
1346                 attrib = &msg->attribs[num_attribs];
1347                 attrib->values = talloc_array(msg->attribs, DATA_BLOB, 1);
1348                 if (attrib->values == NULL) {
1349                         return false;
1350                 }
1351                 asn1_start_tag(msg->data, ASN1_SEQUENCE(0));
1352                 asn1_read_OctetString_talloc(msg->attribs, msg->data,
1353                                              &attrib->name);
1354                 asn1_start_tag(msg->data, ASN1_SET);
1355
1356                 while (asn1_peek_tag(msg->data, ASN1_OCTET_STRING)) {
1357                         asn1_read_OctetString(msg->data, msg,
1358                                               &attrib->values[num_values]);
1359
1360                         attrib->values = talloc_realloc(
1361                                 msg->attribs, attrib->values, DATA_BLOB,
1362                                 num_values + 2);
1363                         if (attrib->values == NULL) {
1364                                 return false;
1365                         }
1366                         num_values += 1;
1367                 }
1368                 attrib->values = talloc_realloc(msg->attribs, attrib->values,
1369                                                 DATA_BLOB, num_values);
1370                 attrib->num_values = num_values;
1371
1372                 asn1_end_tag(msg->data); /* ASN1_SET */
1373                 asn1_end_tag(msg->data); /* ASN1_SEQUENCE(0) */
1374                 msg->attribs = talloc_realloc(
1375                         msg, msg->attribs, struct tldap_attribute,
1376                         num_attribs + 2);
1377                 if (msg->attribs == NULL) {
1378                         return false;
1379                 }
1380                 num_attribs += 1;
1381         }
1382         msg->attribs = talloc_realloc(
1383                 msg, msg->attribs, struct tldap_attribute, num_attribs);
1384         asn1_end_tag(msg->data);
1385         if (msg->data->has_error) {
1386                 return false;
1387         }
1388         return true;
1389 }
1390
1391 bool tldap_entry_dn(struct tldap_message *msg, char **dn)
1392 {
1393         if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
1394                 return false;
1395         }
1396         *dn = msg->dn;
1397         return true;
1398 }
1399
1400 bool tldap_entry_attributes(struct tldap_message *msg, int *num_attributes,
1401                             struct tldap_attribute **attributes)
1402 {
1403         if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
1404                 return false;
1405         }
1406         *attributes = msg->attribs;
1407         *num_attributes = talloc_array_length(msg->attribs);
1408         return true;
1409 }
1410
1411 static void tldap_simple_done(struct tevent_req *subreq, int type)
1412 {
1413         struct tevent_req *req = tevent_req_callback_data(
1414                 subreq, struct tevent_req);
1415         struct tldap_req_state *state = tevent_req_data(
1416                 req, struct tldap_req_state);
1417         int err;
1418
1419         err = tldap_msg_recv(subreq, state, &state->result);
1420         TALLOC_FREE(subreq);
1421         if (err != TLDAP_SUCCESS) {
1422                 tevent_req_error(req, err);
1423                 return;
1424         }
1425         if (state->result->type != type) {
1426                 tevent_req_error(req, TLDAP_PROTOCOL_ERROR);
1427                 return;
1428         }
1429         if (!asn1_start_tag(state->result->data, state->result->type) ||
1430             !tldap_decode_response(state) ||
1431             !asn1_end_tag(state->result->data)) {
1432                 tevent_req_error(req, TLDAP_DECODING_ERROR);
1433                 return;
1434         }
1435         if (state->lderr != TLDAP_SUCCESS) {
1436                 tevent_req_error(req, state->lderr);
1437                 return;
1438         }
1439         tevent_req_done(req);
1440 }
1441
1442 static int tldap_simple_recv(struct tevent_req *req)
1443 {
1444         int err;
1445         if (tevent_req_is_ldap_error(req, &err)) {
1446                 return err;
1447         }
1448         return TLDAP_SUCCESS;
1449 }
1450
1451 static void tldap_add_done(struct tevent_req *subreq);
1452
1453 struct tevent_req *tldap_add_send(TALLOC_CTX *mem_ctx,
1454                                   struct tevent_context *ev,
1455                                   struct tldap_context *ld,
1456                                   const char *dn,
1457                                   int num_attributes,
1458                                   struct tldap_mod *attributes,
1459                                   struct tldap_control **sctrls,
1460                                   struct tldap_control **cctrls)
1461 {
1462         struct tevent_req *req, *subreq;
1463         struct tldap_req_state *state;
1464         int i, j;
1465
1466         req = tldap_req_create(mem_ctx, ld, &state);
1467         if (req == NULL) {
1468                 return NULL;
1469         }
1470
1471         asn1_push_tag(state->out, TLDAP_REQ_ADD);
1472         asn1_write_OctetString(state->out, dn, strlen(dn));
1473         asn1_push_tag(state->out, ASN1_SEQUENCE(0));
1474
1475         for (i=0; i<num_attributes; i++) {
1476                 struct tldap_mod *attrib = &attributes[i];
1477                 asn1_push_tag(state->out, ASN1_SEQUENCE(0));
1478                 asn1_write_OctetString(state->out, attrib->attribute,
1479                                        strlen(attrib->attribute));
1480                 asn1_push_tag(state->out, ASN1_SET);
1481                 for (j=0; j<attrib->num_values; j++) {
1482                         asn1_write_OctetString(state->out,
1483                                                attrib->values[j].data,
1484                                                attrib->values[j].length);
1485                 }
1486                 asn1_pop_tag(state->out);
1487                 asn1_pop_tag(state->out);
1488         }
1489
1490         asn1_pop_tag(state->out);
1491         asn1_pop_tag(state->out);
1492
1493         subreq = tldap_msg_send(state, ev, ld, state->id, state->out);
1494         if (tevent_req_nomem(subreq, req)) {
1495                 return tevent_req_post(req, ev);
1496         }
1497         tevent_req_set_callback(subreq, tldap_add_done, req);
1498         return req;
1499
1500 }
1501
1502 static void tldap_add_done(struct tevent_req *subreq)
1503 {
1504         return tldap_simple_done(subreq, TLDAP_RES_ADD);
1505 }
1506
1507 int tldap_add_recv(struct tevent_req *req)
1508 {
1509         return tldap_simple_recv(req);
1510 }
1511
1512 int tldap_add(struct tldap_context *ld, const char *dn,
1513               int num_attributes, struct tldap_mod *attributes,
1514               struct tldap_control **sctrls, struct tldap_control **cctrls)
1515 {
1516         TALLOC_CTX *frame = talloc_stackframe();
1517         struct tevent_context *ev;
1518         struct tevent_req *req;
1519         int result;
1520
1521         ev = event_context_init(frame);
1522         if (ev == NULL) {
1523                 result = TLDAP_NO_MEMORY;
1524                 goto fail;
1525         }
1526
1527         req = tldap_add_send(frame, ev, ld, dn, num_attributes, attributes,
1528                              sctrls, cctrls);
1529         if (req == NULL) {
1530                 result = TLDAP_NO_MEMORY;
1531                 goto fail;
1532         }
1533
1534         if (!tevent_req_poll(req, ev)) {
1535                 result = TLDAP_OPERATIONS_ERROR;
1536                 goto fail;
1537         }
1538
1539         result = tldap_add_recv(req);
1540         tldap_save_errors(ld, req);
1541  fail:
1542         TALLOC_FREE(frame);
1543         return result;
1544 }
1545
1546 static void tldap_modify_done(struct tevent_req *subreq);
1547
1548 struct tevent_req *tldap_modify_send(TALLOC_CTX *mem_ctx,
1549                                      struct tevent_context *ev,
1550                                      struct tldap_context *ld,
1551                                      const char *dn,
1552                                      int num_mods, struct tldap_mod *mods,
1553                                      struct tldap_control **sctrls,
1554                                      struct tldap_control **cctrls)
1555 {
1556         struct tevent_req *req, *subreq;
1557         struct tldap_req_state *state;
1558         int i, j;
1559
1560         req = tldap_req_create(mem_ctx, ld, &state);
1561         if (req == NULL) {
1562                 return NULL;
1563         }
1564
1565         asn1_push_tag(state->out, TLDAP_REQ_MODIFY);
1566         asn1_write_OctetString(state->out, dn, strlen(dn));
1567         asn1_push_tag(state->out, ASN1_SEQUENCE(0));
1568
1569         for (i=0; i<num_mods; i++) {
1570                 struct tldap_mod *mod = &mods[i];
1571                 asn1_push_tag(state->out, ASN1_SEQUENCE(0));
1572                 asn1_write_enumerated(state->out, mod->mod_op),
1573                 asn1_push_tag(state->out, ASN1_SEQUENCE(0));
1574                 asn1_write_OctetString(state->out, mod->attribute,
1575                                        strlen(mod->attribute));
1576                 asn1_push_tag(state->out, ASN1_SET);
1577                 for (j=0; j<mod->num_values; j++) {
1578                         asn1_write_OctetString(state->out,
1579                                                mod->values[j].data,
1580                                                mod->values[j].length);
1581                 }
1582                 asn1_pop_tag(state->out);
1583                 asn1_pop_tag(state->out);
1584                 asn1_pop_tag(state->out);
1585         }
1586
1587         asn1_pop_tag(state->out);
1588         asn1_pop_tag(state->out);
1589
1590         subreq = tldap_msg_send(state, ev, ld, state->id, state->out);
1591         if (tevent_req_nomem(subreq, req)) {
1592                 return tevent_req_post(req, ev);
1593         }
1594         tevent_req_set_callback(subreq, tldap_modify_done, req);
1595         return req;
1596
1597 }
1598
1599 static void tldap_modify_done(struct tevent_req *subreq)
1600 {
1601         return tldap_simple_done(subreq, TLDAP_RES_MODIFY);
1602 }
1603
1604 int tldap_modify_recv(struct tevent_req *req)
1605 {
1606         return tldap_simple_recv(req);
1607 }
1608
1609 int tldap_modify(struct tldap_context *ld, const char *dn,
1610                  int num_mods, struct tldap_mod *mods,
1611                  struct tldap_control **sctrls, struct tldap_control **cctrls)
1612  {
1613         TALLOC_CTX *frame = talloc_stackframe();
1614         struct tevent_context *ev;
1615         struct tevent_req *req;
1616         int result;
1617
1618         ev = event_context_init(frame);
1619         if (ev == NULL) {
1620                 result = TLDAP_NO_MEMORY;
1621                 goto fail;
1622         }
1623
1624         req = tldap_modify_send(frame, ev, ld, dn, num_mods, mods,
1625                                 sctrls, cctrls);
1626         if (req == NULL) {
1627                 result = TLDAP_NO_MEMORY;
1628                 goto fail;
1629         }
1630
1631         if (!tevent_req_poll(req, ev)) {
1632                 result = TLDAP_OPERATIONS_ERROR;
1633                 goto fail;
1634         }
1635
1636         result = tldap_modify_recv(req);
1637         tldap_save_errors(ld, req);
1638  fail:
1639         TALLOC_FREE(frame);
1640         return result;
1641 }
1642
1643 static void tldap_delete_done(struct tevent_req *subreq);
1644
1645 struct tevent_req *tldap_delete_send(TALLOC_CTX *mem_ctx,
1646                                      struct tevent_context *ev,
1647                                      struct tldap_context *ld,
1648                                      const char *dn,
1649                                      struct tldap_control **sctrls,
1650                                      struct tldap_control **cctrls)
1651 {
1652         struct tevent_req *req, *subreq;
1653         struct tldap_req_state *state;
1654
1655         req = tldap_req_create(mem_ctx, ld, &state);
1656         if (req == NULL) {
1657                 return NULL;
1658         }
1659
1660         asn1_push_tag(state->out, TLDAP_REQ_DELETE);
1661         asn1_write(state->out, dn, strlen(dn));
1662         asn1_pop_tag(state->out);
1663
1664         subreq = tldap_msg_send(state, ev, ld, state->id, state->out);
1665         if (tevent_req_nomem(subreq, req)) {
1666                 return tevent_req_post(req, ev);
1667         }
1668         tevent_req_set_callback(subreq, tldap_delete_done, req);
1669         return req;
1670
1671 }
1672
1673 static void tldap_delete_done(struct tevent_req *subreq)
1674 {
1675         return tldap_simple_done(subreq, TLDAP_RES_DELETE);
1676 }
1677
1678 int tldap_delete_recv(struct tevent_req *req)
1679 {
1680         return tldap_simple_recv(req);
1681 }
1682
1683 int tldap_delete(struct tldap_context *ld, const char *dn,
1684                  struct tldap_control **sctrls, struct tldap_control **cctrls)
1685 {
1686         TALLOC_CTX *frame = talloc_stackframe();
1687         struct tevent_context *ev;
1688         struct tevent_req *req;
1689         int result;
1690
1691         ev = event_context_init(frame);
1692         if (ev == NULL) {
1693                 result = TLDAP_NO_MEMORY;
1694                 goto fail;
1695         }
1696
1697         req = tldap_delete_send(frame, ev, ld, dn, sctrls, cctrls);
1698         if (req == NULL) {
1699                 result = TLDAP_NO_MEMORY;
1700                 goto fail;
1701         }
1702
1703         if (!tevent_req_poll(req, ev)) {
1704                 result = TLDAP_OPERATIONS_ERROR;
1705                 goto fail;
1706         }
1707
1708         result = tldap_delete_recv(req);
1709         tldap_save_errors(ld, req);
1710  fail:
1711         TALLOC_FREE(frame);
1712         return result;
1713 }
1714
1715 int tldap_msg_id(const struct tldap_message *msg)
1716 {
1717         return msg->id;
1718 }
1719
1720 int tldap_msg_type(const struct tldap_message *msg)
1721 {
1722         return msg->type;
1723 }
1724
1725 const char *tldap_req_matcheddn(struct tevent_req *req)
1726 {
1727         struct tldap_req_state *state = tevent_req_data(
1728                 req, struct tldap_req_state);
1729         return state->res_matcheddn;
1730 }
1731
1732 const char *tldap_req_diagnosticmessage(struct tevent_req *req)
1733 {
1734         struct tldap_req_state *state = tevent_req_data(
1735                 req, struct tldap_req_state);
1736         return state->res_diagnosticmessage;
1737 }
1738
1739 const char *tldap_req_referral(struct tevent_req *req)
1740 {
1741         struct tldap_req_state *state = tevent_req_data(
1742                 req, struct tldap_req_state);
1743         return state->res_referral;
1744 }
1745
1746 const char *tldap_ctx_matcheddn(struct tldap_context *ctx)
1747 {
1748         return ctx->res_matcheddn;
1749 }
1750
1751 const char *tldap_ctx_diagnosticmessage(struct tldap_context *ctx)
1752 {
1753         return ctx->res_diagnosticmessage;
1754 }
1755
1756 const char *tldap_ctx_referral(struct tldap_context *ctx)
1757 {
1758         return ctx->res_referral;
1759 }
1760
1761 const char *tldap_err2string(int rc)
1762 {
1763         const char *res = NULL;
1764
1765         /*
1766          * This would normally be a table, but the error codes are not fully
1767          * sequential. Let the compiler figure out the optimum implementation
1768          * :-)
1769          */
1770
1771         switch (rc) {
1772         case TLDAP_SUCCESS:
1773                 res = "TLDAP_SUCCESS";
1774                 break;
1775         case TLDAP_OPERATIONS_ERROR:
1776                 res = "TLDAP_OPERATIONS_ERROR";
1777                 break;
1778         case TLDAP_PROTOCOL_ERROR:
1779                 res = "TLDAP_PROTOCOL_ERROR";
1780                 break;
1781         case TLDAP_TIMELIMIT_EXCEEDED:
1782                 res = "TLDAP_TIMELIMIT_EXCEEDED";
1783                 break;
1784         case TLDAP_SIZELIMIT_EXCEEDED:
1785                 res = "TLDAP_SIZELIMIT_EXCEEDED";
1786                 break;
1787         case TLDAP_COMPARE_FALSE:
1788                 res = "TLDAP_COMPARE_FALSE";
1789                 break;
1790         case TLDAP_COMPARE_TRUE:
1791                 res = "TLDAP_COMPARE_TRUE";
1792                 break;
1793         case TLDAP_STRONG_AUTH_NOT_SUPPORTED:
1794                 res = "TLDAP_STRONG_AUTH_NOT_SUPPORTED";
1795                 break;
1796         case TLDAP_STRONG_AUTH_REQUIRED:
1797                 res = "TLDAP_STRONG_AUTH_REQUIRED";
1798                 break;
1799         case TLDAP_REFERRAL:
1800                 res = "TLDAP_REFERRAL";
1801                 break;
1802         case TLDAP_ADMINLIMIT_EXCEEDED:
1803                 res = "TLDAP_ADMINLIMIT_EXCEEDED";
1804                 break;
1805         case TLDAP_UNAVAILABLE_CRITICAL_EXTENSION:
1806                 res = "TLDAP_UNAVAILABLE_CRITICAL_EXTENSION";
1807                 break;
1808         case TLDAP_CONFIDENTIALITY_REQUIRED:
1809                 res = "TLDAP_CONFIDENTIALITY_REQUIRED";
1810                 break;
1811         case TLDAP_SASL_BIND_IN_PROGRESS:
1812                 res = "TLDAP_SASL_BIND_IN_PROGRESS";
1813                 break;
1814         case TLDAP_NO_SUCH_ATTRIBUTE:
1815                 res = "TLDAP_NO_SUCH_ATTRIBUTE";
1816                 break;
1817         case TLDAP_UNDEFINED_TYPE:
1818                 res = "TLDAP_UNDEFINED_TYPE";
1819                 break;
1820         case TLDAP_INAPPROPRIATE_MATCHING:
1821                 res = "TLDAP_INAPPROPRIATE_MATCHING";
1822                 break;
1823         case TLDAP_CONSTRAINT_VIOLATION:
1824                 res = "TLDAP_CONSTRAINT_VIOLATION";
1825                 break;
1826         case TLDAP_TYPE_OR_VALUE_EXISTS:
1827                 res = "TLDAP_TYPE_OR_VALUE_EXISTS";
1828                 break;
1829         case TLDAP_INVALID_SYNTAX:
1830                 res = "TLDAP_INVALID_SYNTAX";
1831                 break;
1832         case TLDAP_NO_SUCH_OBJECT:
1833                 res = "TLDAP_NO_SUCH_OBJECT";
1834                 break;
1835         case TLDAP_ALIAS_PROBLEM:
1836                 res = "TLDAP_ALIAS_PROBLEM";
1837                 break;
1838         case TLDAP_INVALID_DN_SYNTAX:
1839                 res = "TLDAP_INVALID_DN_SYNTAX";
1840                 break;
1841         case TLDAP_IS_LEAF:
1842                 res = "TLDAP_IS_LEAF";
1843                 break;
1844         case TLDAP_ALIAS_DEREF_PROBLEM:
1845                 res = "TLDAP_ALIAS_DEREF_PROBLEM";
1846                 break;
1847         case TLDAP_INAPPROPRIATE_AUTH:
1848                 res = "TLDAP_INAPPROPRIATE_AUTH";
1849                 break;
1850         case TLDAP_INVALID_CREDENTIALS:
1851                 res = "TLDAP_INVALID_CREDENTIALS";
1852                 break;
1853         case TLDAP_INSUFFICIENT_ACCESS:
1854                 res = "TLDAP_INSUFFICIENT_ACCESS";
1855                 break;
1856         case TLDAP_BUSY:
1857                 res = "TLDAP_BUSY";
1858                 break;
1859         case TLDAP_UNAVAILABLE:
1860                 res = "TLDAP_UNAVAILABLE";
1861                 break;
1862         case TLDAP_UNWILLING_TO_PERFORM:
1863                 res = "TLDAP_UNWILLING_TO_PERFORM";
1864                 break;
1865         case TLDAP_LOOP_DETECT:
1866                 res = "TLDAP_LOOP_DETECT";
1867                 break;
1868         case TLDAP_NAMING_VIOLATION:
1869                 res = "TLDAP_NAMING_VIOLATION";
1870                 break;
1871         case TLDAP_OBJECT_CLASS_VIOLATION:
1872                 res = "TLDAP_OBJECT_CLASS_VIOLATION";
1873                 break;
1874         case TLDAP_NOT_ALLOWED_ON_NONLEAF:
1875                 res = "TLDAP_NOT_ALLOWED_ON_NONLEAF";
1876                 break;
1877         case TLDAP_NOT_ALLOWED_ON_RDN:
1878                 res = "TLDAP_NOT_ALLOWED_ON_RDN";
1879                 break;
1880         case TLDAP_ALREADY_EXISTS:
1881                 res = "TLDAP_ALREADY_EXISTS";
1882                 break;
1883         case TLDAP_NO_OBJECT_CLASS_MODS:
1884                 res = "TLDAP_NO_OBJECT_CLASS_MODS";
1885                 break;
1886         case TLDAP_RESULTS_TOO_LARGE:
1887                 res = "TLDAP_RESULTS_TOO_LARGE";
1888                 break;
1889         case TLDAP_AFFECTS_MULTIPLE_DSAS:
1890                 res = "TLDAP_AFFECTS_MULTIPLE_DSAS";
1891                 break;
1892         case TLDAP_OTHER:
1893                 res = "TLDAP_OTHER";
1894                 break;
1895         case TLDAP_SERVER_DOWN:
1896                 res = "TLDAP_SERVER_DOWN";
1897                 break;
1898         case TLDAP_LOCAL_ERROR:
1899                 res = "TLDAP_LOCAL_ERROR";
1900                 break;
1901         case TLDAP_ENCODING_ERROR:
1902                 res = "TLDAP_ENCODING_ERROR";
1903                 break;
1904         case TLDAP_DECODING_ERROR:
1905                 res = "TLDAP_DECODING_ERROR";
1906                 break;
1907         case TLDAP_TIMEOUT:
1908                 res = "TLDAP_TIMEOUT";
1909                 break;
1910         case TLDAP_AUTH_UNKNOWN:
1911                 res = "TLDAP_AUTH_UNKNOWN";
1912                 break;
1913         case TLDAP_FILTER_ERROR:
1914                 res = "TLDAP_FILTER_ERROR";
1915                 break;
1916         case TLDAP_USER_CANCELLED:
1917                 res = "TLDAP_USER_CANCELLED";
1918                 break;
1919         case TLDAP_PARAM_ERROR:
1920                 res = "TLDAP_PARAM_ERROR";
1921                 break;
1922         case TLDAP_NO_MEMORY:
1923                 res = "TLDAP_NO_MEMORY";
1924                 break;
1925         case TLDAP_CONNECT_ERROR:
1926                 res = "TLDAP_CONNECT_ERROR";
1927                 break;
1928         case TLDAP_NOT_SUPPORTED:
1929                 res = "TLDAP_NOT_SUPPORTED";
1930                 break;
1931         case TLDAP_CONTROL_NOT_FOUND:
1932                 res = "TLDAP_CONTROL_NOT_FOUND";
1933                 break;
1934         case TLDAP_NO_RESULTS_RETURNED:
1935                 res = "TLDAP_NO_RESULTS_RETURNED";
1936                 break;
1937         case TLDAP_MORE_RESULTS_TO_RETURN:
1938                 res = "TLDAP_MORE_RESULTS_TO_RETURN";
1939                 break;
1940         case TLDAP_CLIENT_LOOP:
1941                 res = "TLDAP_CLIENT_LOOP";
1942                 break;
1943         case TLDAP_REFERRAL_LIMIT_EXCEEDED:
1944                 res = "TLDAP_REFERRAL_LIMIT_EXCEEDED";
1945                 break;
1946         default:
1947                 res = talloc_asprintf(talloc_tos(), "Unknown LDAP Error (%d)",
1948                                       rc);
1949                 break;
1950         }
1951         if (res == NULL) {
1952                 res = "Unknown LDAP Error";
1953         }
1954         return res;
1955 }