s4:libcli/ldap: ldap4_new_connection() requires a valid lp_ctx
[metze/samba/wip.git] / source4 / libcli / ldap / ldap_client.c
1 /* 
2    Unix SMB/CIFS implementation.
3    LDAP protocol helper functions for SAMBA
4    
5    Copyright (C) Andrew Tridgell  2004
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Stefan Metzmacher 2004
8    Copyright (C) Simo Sorce 2004
9     
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22    
23 */
24
25 #include "includes.h"
26 #include <tevent.h>
27 #include "lib/socket/socket.h"
28 #include "lib/tsocket/tsocket.h"
29 #include "libcli/util/tstream.h"
30 #include "../lib/util/asn1.h"
31 #include "../lib/util/dlinklist.h"
32 #include "libcli/ldap/libcli_ldap.h"
33 #include "libcli/ldap/ldap_proto.h"
34 #include "libcli/ldap/ldap_client.h"
35 #include "libcli/composite/composite.h"
36 #include "lib/tls/tls.h"
37 #include "auth/gensec/gensec.h"
38 #include "system/time.h"
39 #include "param/param.h"
40 #include "libcli/resolve/resolve.h"
41 #include "lib/param/loadparm.h"
42
43 static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status);
44
45 static int ldap_connection_destructor(struct ldap_connection *conn)
46 {
47         /*
48          * NT_STATUS_OK means that callbacks of pending requests are not
49          * triggered
50          */
51         ldap_connection_dead(conn, NT_STATUS_OK);
52         return 0;
53 }
54
55 /**
56   create a new ldap_connection stucture. The event context is optional
57 */
58
59 _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx, 
60                                              struct loadparm_context *lp_ctx,
61                                              struct tevent_context *ev)
62 {
63         struct ldap_connection *conn;
64
65         if (ev == NULL) {
66                 return NULL;
67         }
68
69         if (lp_ctx == NULL) {
70                 return NULL;
71         }
72
73         conn = talloc_zero(mem_ctx, struct ldap_connection);
74         if (conn == NULL) {
75                 return NULL;
76         }
77
78         conn->next_messageid  = 1;
79         conn->event.event_ctx = ev;
80
81         conn->sockets.send_queue = tevent_queue_create(conn,
82                                         "ldap_connection send_queue");
83         if (conn->sockets.send_queue == NULL) {
84                 TALLOC_FREE(conn);
85                 return NULL;
86         }
87
88         conn->lp_ctx = lp_ctx;
89
90         /* set a reasonable request timeout */
91         conn->timeout = 60;
92
93         /* explicitly avoid reconnections by default */
94         conn->reconnect.max_retries = 0;
95
96         talloc_set_destructor(conn, ldap_connection_destructor);
97         return conn;
98 }
99
100 /*
101   the connection is dead
102 */
103 static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status)
104 {
105         struct ldap_request *req;
106
107         tevent_queue_stop(conn->sockets.send_queue);
108         TALLOC_FREE(conn->sockets.recv_subreq);
109         conn->sockets.active = NULL;
110         TALLOC_FREE(conn->sockets.sasl);
111         TALLOC_FREE(conn->sockets.tls);
112         TALLOC_FREE(conn->sockets.raw);
113
114         /* return an error for any pending request ... */
115         while (conn->pending) {
116                 req = conn->pending;
117                 DLIST_REMOVE(req->conn->pending, req);
118                 req->conn = NULL;
119                 req->state = LDAP_REQUEST_DONE;
120                 if (NT_STATUS_IS_OK(status)) {
121                         continue;
122                 }
123                 req->status = status;
124                 if (req->async.fn) {
125                         req->async.fn(req);
126                 }
127         }
128 }
129
130 static void ldap_reconnect(struct ldap_connection *conn);
131
132 /*
133   handle packet errors
134 */
135 static void ldap_error_handler(struct ldap_connection *conn, NTSTATUS status)
136 {
137         ldap_connection_dead(conn, status);
138
139         /* but try to reconnect so that the ldb client can go on */
140         ldap_reconnect(conn);
141 }
142
143
144 /*
145   match up with a pending message, adding to the replies list
146 */
147 static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg)
148 {
149         struct ldap_request *req;
150         int i;
151
152         for (req=conn->pending; req; req=req->next) {
153                 if (req->messageid == msg->messageid) break;
154         }
155         /* match a zero message id to the last request sent.
156            It seems that servers send 0 if unable to parse */
157         if (req == NULL && msg->messageid == 0) {
158                 req = conn->pending;
159         }
160         if (req == NULL) {
161                 DEBUG(0,("ldap: no matching message id for %u\n",
162                          msg->messageid));
163                 TALLOC_FREE(msg);
164                 return;
165         }
166
167         /* Check for undecoded critical extensions */
168         for (i=0; msg->controls && msg->controls[i]; i++) {
169                 if (!msg->controls_decoded[i] && 
170                     msg->controls[i]->critical) {
171                         TALLOC_FREE(msg);
172                         req->status = NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION);
173                         req->state = LDAP_REQUEST_DONE;
174                         DLIST_REMOVE(conn->pending, req);
175                         if (req->async.fn) {
176                                 req->async.fn(req);
177                         }
178                         return;
179                 }
180         }
181
182         /* add to the list of replies received */
183         req->replies = talloc_realloc(req, req->replies, 
184                                       struct ldap_message *, req->num_replies+1);
185         if (req->replies == NULL) {
186                 TALLOC_FREE(msg);
187                 req->status = NT_STATUS_NO_MEMORY;
188                 req->state = LDAP_REQUEST_DONE;
189                 DLIST_REMOVE(conn->pending, req);
190                 if (req->async.fn) {
191                         req->async.fn(req);
192                 }
193                 return;
194         }
195
196         req->replies[req->num_replies] = talloc_steal(req->replies, msg);
197         req->num_replies++;
198
199         if (msg->type != LDAP_TAG_SearchResultEntry &&
200             msg->type != LDAP_TAG_SearchResultReference) {
201                 /* currently only search results expect multiple
202                    replies */
203                 req->state = LDAP_REQUEST_DONE;
204                 DLIST_REMOVE(conn->pending, req);
205         }
206
207         if (req->async.fn) {
208                 req->async.fn(req);
209         }
210 }
211
212 static void ldap_connection_recv_done(struct tevent_req *subreq);
213
214 static void ldap_connection_recv_next(struct ldap_connection *conn)
215 {
216         struct tevent_req *subreq = NULL;
217
218         if (conn->sockets.recv_subreq != NULL) {
219                 return;
220         }
221
222         if (conn->sockets.active == NULL) {
223                 return;
224         }
225
226         if (conn->pending == NULL) {
227                 return;
228         }
229
230         /*
231          * The minimum size of a LDAP pdu is 7 bytes
232          *
233          * dumpasn1 -hh ldap-unbind-min.dat
234          *
235          *     <30 05 02 01 09 42 00>
236          *    0    5: SEQUENCE {
237          *     <02 01 09>
238          *    2    1:   INTEGER 9
239          *     <42 00>
240          *    5    0:   [APPLICATION 2]
241          *          :     Error: Object has zero length.
242          *          :   }
243          *
244          * dumpasn1 -hh ldap-unbind-windows.dat
245          *
246          *     <30 84 00 00 00 05 02 01 09 42 00>
247          *    0    5: SEQUENCE {
248          *     <02 01 09>
249          *    6    1:   INTEGER 9
250          *     <42 00>
251          *    9    0:   [APPLICATION 2]
252          *          :     Error: Object has zero length.
253          *          :   }
254          *
255          * This means using an initial read size
256          * of 7 is ok.
257          */
258         subreq = tstream_read_pdu_blob_send(conn,
259                                             conn->event.event_ctx,
260                                             conn->sockets.active,
261                                             7, /* initial_read_size */
262                                             ldap_full_packet,
263                                             conn);
264         if (subreq == NULL) {
265                 ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
266                 return;
267         }
268         tevent_req_set_callback(subreq, ldap_connection_recv_done, conn);
269         conn->sockets.recv_subreq = subreq;
270         return;
271 }
272
273 /*
274   decode/process LDAP data
275 */
276 static void ldap_connection_recv_done(struct tevent_req *subreq)
277 {
278         NTSTATUS status;
279         struct ldap_connection *conn =
280                 tevent_req_callback_data(subreq,
281                 struct ldap_connection);
282         struct ldap_message *msg;
283         struct asn1_data *asn1;
284         DATA_BLOB blob;
285         struct ldap_request_limits limits = {0};
286
287         msg = talloc_zero(conn, struct ldap_message);
288         if (msg == NULL) {
289                 ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
290                 return;
291         }
292
293         asn1 = asn1_init(conn, ASN1_MAX_TREE_DEPTH);
294         if (asn1 == NULL) {
295                 TALLOC_FREE(msg);
296                 ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
297                 return;
298         }
299
300         conn->sockets.recv_subreq = NULL;
301
302         status = tstream_read_pdu_blob_recv(subreq,
303                                             asn1,
304                                             &blob);
305         TALLOC_FREE(subreq);
306         if (!NT_STATUS_IS_OK(status)) {
307                 TALLOC_FREE(msg);
308                 asn1_free(asn1);
309                 ldap_error_handler(conn, status);
310                 return;
311         }
312
313         asn1_load_nocopy(asn1, blob.data, blob.length);
314
315         status = ldap_decode(asn1, &limits, samba_ldap_control_handlers(), msg);
316         asn1_free(asn1);
317         if (!NT_STATUS_IS_OK(status)) {
318                 TALLOC_FREE(msg);
319                 ldap_error_handler(conn, status);
320                 return;
321         }
322
323         ldap_match_message(conn, msg);
324         ldap_connection_recv_next(conn);
325
326         return;
327 }
328
329 enum ldap_proto {
330         LDAP_PROTO_NONE,
331         LDAP_PROTO_LDAP,
332         LDAP_PROTO_LDAPS,
333         LDAP_PROTO_LDAPI
334 };
335
336 static int ldap_parse_basic_url(
337         const char *url,
338         enum ldap_proto *pproto,
339         TALLOC_CTX *mem_ctx,
340         char **pdest,           /* path for ldapi, host for ldap[s] */
341         uint16_t *pport)        /* Not set for ldapi */
342 {
343         enum ldap_proto proto = LDAP_PROTO_NONE;
344         char *host = NULL;
345         int ret, port;
346
347         if (url == NULL) {
348                 return EINVAL;
349         }
350
351         if (strncasecmp_m(url, "ldapi://", strlen("ldapi://")) == 0) {
352                 char *path = NULL, *end = NULL;
353
354                 path = talloc_strdup(mem_ctx, url+8);
355                 if (path == NULL) {
356                         return ENOMEM;
357                 }
358                 end = rfc1738_unescape(path);
359                 if (end == NULL) {
360                         TALLOC_FREE(path);
361                         return EINVAL;
362                 }
363
364                 *pproto = LDAP_PROTO_LDAPI;
365                 *pdest = path;
366                 return 0;
367         }
368
369         if (strncasecmp_m(url, "ldap://", strlen("ldap://")) == 0) {
370                 url += 7;
371                 proto = LDAP_PROTO_LDAP;
372                 port = 389;
373         }
374         if (strncasecmp_m(url, "ldaps://", strlen("ldaps://")) == 0) {
375                 url += 8;
376                 port = 636;
377                 proto = LDAP_PROTO_LDAPS;
378         }
379
380         if (proto == LDAP_PROTO_NONE) {
381                 return EPROTONOSUPPORT;
382         }
383
384         if (url[0] == '[') {
385                 /*
386                  * IPv6 with [aa:bb:cc..]:port
387                  */
388                 const char *end = NULL;
389
390                 url +=1;
391
392                 end = strchr(url, ']');
393                 if (end == NULL) {
394                         return EINVAL;
395                 }
396
397                 ret = sscanf(end+1, ":%d", &port);
398                 if (ret < 0) {
399                         return EINVAL;
400                 }
401
402                 *pdest = talloc_strndup(mem_ctx, url, end-url);
403                 if (*pdest == NULL) {
404                         return ENOMEM;
405                 }
406                 *pproto = proto;
407                 *pport = port;
408                 return 0;
409         }
410
411         ret = sscanf(url, "%m[^:/]:%d", &host, &port);
412         if (ret < 1) {
413                 return EINVAL;
414         }
415
416         *pdest = talloc_strdup(mem_ctx, host);
417         SAFE_FREE(host);
418         if (*pdest == NULL) {
419                 return ENOMEM;
420         }
421         *pproto = proto;
422         *pport = port;
423
424         return 0;
425 }
426
427 /*
428   connect to a ldap server
429 */
430
431 struct ldap_connect_state {
432         struct composite_context *ctx;
433         struct ldap_connection *conn;
434         struct socket_context *sock;
435         struct tstream_context *raw;
436         struct tstream_tls_params *tls_params;
437         struct tstream_context *tls;
438 };
439
440 static void ldap_connect_recv_unix_conn(struct composite_context *ctx);
441 static void ldap_connect_recv_tcp_conn(struct composite_context *ctx);
442
443 _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
444                                             const char *url)
445 {
446         struct composite_context *result, *ctx;
447         struct ldap_connect_state *state;
448         enum ldap_proto proto;
449         char *dest = NULL;
450         uint16_t port;
451         int ret;
452
453         result = talloc_zero(conn, struct composite_context);
454         if (result == NULL) goto failed;
455         result->state = COMPOSITE_STATE_IN_PROGRESS;
456         result->async.fn = NULL;
457         result->event_ctx = conn->event.event_ctx;
458
459         state = talloc(result, struct ldap_connect_state);
460         if (state == NULL) goto failed;
461         state->ctx = result;
462         result->private_data = state;
463
464         state->conn = conn;
465
466         if (conn->reconnect.url == NULL) {
467                 conn->reconnect.url = talloc_strdup(conn, url);
468                 if (conn->reconnect.url == NULL) goto failed;
469         }
470
471         ret = ldap_parse_basic_url(url, &proto, conn, &dest, &port);
472         if (ret != 0) {
473                 composite_error(result, map_nt_error_from_unix_common(ret));
474                 return result;
475         }
476
477         if (proto == LDAP_PROTO_LDAPI) {
478                 struct socket_address *unix_addr;
479                 NTSTATUS status = socket_create(state, "unix",
480                                                 SOCKET_TYPE_STREAM,
481                                                 &state->sock, 0);
482                 if (!NT_STATUS_IS_OK(status)) {
483                         return NULL;
484                 }
485
486                 conn->host = talloc_asprintf(conn, "%s.%s",
487                                              lpcfg_netbios_name(conn->lp_ctx),
488                                              lpcfg_dnsdomain(conn->lp_ctx));
489                 if (composite_nomem(conn->host, state->ctx)) {
490                         return result;
491                 }
492
493                 unix_addr = socket_address_from_strings(state, state->sock->backend_name,
494                                                         dest, 0);
495                 if (composite_nomem(unix_addr, result)) {
496                         return result;
497                 }
498
499                 ctx = socket_connect_send(state->sock, NULL, unix_addr,
500                                           0, result->event_ctx);
501                 ctx->async.fn = ldap_connect_recv_unix_conn;
502                 ctx->async.private_data = state;
503                 return result;
504         }
505
506         if ((proto == LDAP_PROTO_LDAP) || (proto == LDAP_PROTO_LDAPS)) {
507                 int wrap_flags = lpcfg_client_ldap_sasl_wrapping(conn->lp_ctx);
508
509                 conn->ldaps = (proto == LDAP_PROTO_LDAPS);
510
511                 if (wrap_flags & ADS_AUTH_SASL_LDAPS) {
512                         if (proto == LDAP_PROTO_LDAP) {
513                                 if (port == 389) {
514                                         port = 636;
515                                         proto = LDAP_PROTO_LDAPS;
516                                 } else if (port == 3268) {
517                                         port = 3269;
518                                         proto = LDAP_PROTO_LDAPS;
519                                 } else {
520                                         conn->starttls = true;
521                                 }
522                         }
523                         conn->ldaps = true;
524                 } else if (wrap_flags & ADS_AUTH_SASL_STARTTLS) {
525                         if (proto == LDAP_PROTO_LDAP) {
526                                 conn->starttls = true;
527                         }
528                         conn->ldaps = true;
529                 }
530
531                 conn->host = talloc_move(conn, &dest);
532                 conn->port = port;
533
534                 if (conn->ldaps) {
535                         NTSTATUS status;
536
537                         status = tstream_tls_params_client_lpcfg(state,
538                                                                  conn->lp_ctx,
539                                                                  conn->host,
540                                                                  &state->tls_params);
541                         if (!NT_STATUS_IS_OK(status)) {
542                                 composite_error(result, status);
543                                 return result;
544                         }
545                 }
546
547                 ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
548                                                 lpcfg_resolve_context(conn->lp_ctx),
549                                                 result->event_ctx);
550                 if (composite_nomem(ctx, result)) {
551                         return result;
552                 }
553
554                 ctx->async.fn = ldap_connect_recv_tcp_conn;
555                 ctx->async.private_data = state;
556                 return result;
557         }
558  failed:
559         talloc_free(result);
560         return NULL;
561 }
562
563 static void ldap_connect_starttls_done(struct ldap_request *ldap_req);
564 static void ldap_connect_got_tls(struct tevent_req *subreq);
565
566 static void ldap_connect_got_sock(struct composite_context *ctx, 
567                                   struct ldap_connection *conn)
568 {
569         struct ldap_connect_state *state =
570                 talloc_get_type_abort(ctx->private_data,
571                 struct ldap_connect_state);
572         struct tevent_req *subreq = NULL;
573         int fd;
574         int ret;
575
576         socket_set_flags(state->sock, SOCKET_FLAG_NOCLOSE);
577         fd = socket_get_fd(state->sock);
578         TALLOC_FREE(state->sock);
579
580         smb_set_close_on_exec(fd);
581
582         ret = set_blocking(fd, false);
583         if (ret == -1) {
584                 NTSTATUS status = map_nt_error_from_unix_common(errno);
585                 composite_error(state->ctx, status);
586                 return;
587         }
588
589         ret = tstream_bsd_existing_socket(state, fd, &state->raw);
590         if (ret == -1) {
591                 NTSTATUS status = map_nt_error_from_unix_common(errno);
592                 composite_error(state->ctx, status);
593                 return;
594         }
595
596         conn->sockets.raw = talloc_move(conn, &state->raw);
597         conn->sockets.active = conn->sockets.raw;
598
599         if (!conn->ldaps) {
600                 composite_done(state->ctx);
601                 return;
602         }
603
604         if (conn->starttls) {
605                 struct ldap_message msg = {
606                         .type = LDAP_TAG_ExtendedRequest,
607                         .r.ExtendedRequest.oid = LDB_EXTENDED_START_TLS_OID,
608                 };
609                 struct ldap_request *ldap_req = NULL;
610
611                 ldap_req = ldap_request_send(conn, &msg);
612                 if (composite_nomem(ldap_req, state->ctx)) {
613                         return;
614                 }
615                 ldap_req->async.fn = ldap_connect_starttls_done;
616                 ldap_req->async.private_data = state;
617                 return;
618         }
619
620         subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
621                                           conn->sockets.raw, state->tls_params);
622         if (composite_nomem(subreq, state->ctx)) {
623                 return;
624         }
625         tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
626 }
627
628 static void ldap_connect_starttls_done(struct ldap_request *ldap_req)
629 {
630         struct ldap_connect_state *state =
631                 talloc_get_type_abort(ldap_req->async.private_data,
632                 struct ldap_connect_state);
633         struct ldap_connection *conn = state->conn;
634         NTSTATUS status = ldap_req->status;
635         struct tevent_req *subreq = NULL;
636
637         if (!NT_STATUS_IS_OK(status)) {
638                 TALLOC_FREE(ldap_req);
639                 composite_error(state->ctx, status);
640                 return;
641         }
642
643         if (ldap_req->num_replies != 1) {
644                 TALLOC_FREE(ldap_req);
645                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
646                 composite_error(state->ctx, status);
647                 return;
648         }
649
650         if (ldap_req->replies[0]->type != LDAP_TAG_ExtendedResponse) {
651                 TALLOC_FREE(ldap_req);
652                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
653                 composite_error(state->ctx, status);
654                 return;
655         }
656
657         status = ldap_check_response(conn,
658                                      &ldap_req->replies[0]->r.GeneralResult);
659         if (!NT_STATUS_IS_OK(status)) {
660                 TALLOC_FREE(ldap_req);
661                 composite_error(state->ctx, status);
662                 return;
663         }
664
665         subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
666                                           conn->sockets.raw, state->tls_params);
667         if (composite_nomem(subreq, state->ctx)) {
668                 return;
669         }
670         tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
671 }
672
673 static void ldap_connect_got_tls(struct tevent_req *subreq)
674 {
675         struct ldap_connect_state *state =
676                 tevent_req_callback_data(subreq,
677                 struct ldap_connect_state);
678         int err;
679         int ret;
680
681         ret = tstream_tls_connect_recv(subreq, &err, state, &state->tls);
682         TALLOC_FREE(subreq);
683         if (ret == -1) {
684                 NTSTATUS status = map_nt_error_from_unix_common(err);
685                 composite_error(state->ctx, status);
686                 return;
687         }
688
689         talloc_steal(state->tls, state->tls_params);
690
691         state->conn->sockets.tls = talloc_move(state->conn->sockets.raw,
692                                                &state->tls);
693         state->conn->sockets.active = state->conn->sockets.tls;
694         composite_done(state->ctx);
695 }
696
697 static void ldap_connect_recv_tcp_conn(struct composite_context *ctx)
698 {
699         struct ldap_connect_state *state =
700                 talloc_get_type_abort(ctx->async.private_data,
701                 struct ldap_connect_state);
702         struct ldap_connection *conn = state->conn;
703         uint16_t port;
704         NTSTATUS status = socket_connect_multi_recv(ctx, state, &state->sock,
705                                                        &port);
706         if (!NT_STATUS_IS_OK(status)) {
707                 composite_error(state->ctx, status);
708                 return;
709         }
710
711         ldap_connect_got_sock(state->ctx, conn);
712 }
713
714 static void ldap_connect_recv_unix_conn(struct composite_context *ctx)
715 {
716         struct ldap_connect_state *state =
717                 talloc_get_type_abort(ctx->async.private_data,
718                 struct ldap_connect_state);
719         struct ldap_connection *conn = state->conn;
720
721         NTSTATUS status = socket_connect_recv(ctx);
722
723         if (!NT_STATUS_IS_OK(state->ctx->status)) {
724                 composite_error(state->ctx, status);
725                 return;
726         }
727
728         ldap_connect_got_sock(state->ctx, conn);
729 }
730
731 _PUBLIC_ NTSTATUS ldap_connect_recv(struct composite_context *ctx)
732 {
733         NTSTATUS status = composite_wait(ctx);
734         talloc_free(ctx);
735         return status;
736 }
737
738 _PUBLIC_ NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
739 {
740         struct composite_context *ctx = ldap_connect_send(conn, url);
741         return ldap_connect_recv(ctx);
742 }
743
744 /* set reconnect parameters */
745
746 _PUBLIC_ void ldap_set_reconn_params(struct ldap_connection *conn, int max_retries)
747 {
748         if (conn) {
749                 conn->reconnect.max_retries = max_retries;
750                 conn->reconnect.retries = 0;
751                 conn->reconnect.previous = time_mono(NULL);
752         }
753 }
754
755 /* Actually this function is NOT ASYNC safe, FIXME? */
756 static void ldap_reconnect(struct ldap_connection *conn)
757 {
758         NTSTATUS status;
759         time_t now = time_mono(NULL);
760
761         /* do we have set up reconnect ? */
762         if (conn->reconnect.max_retries == 0) return;
763
764         /* is the retry time expired ? */
765         if (now > conn->reconnect.previous + 30) {
766                 conn->reconnect.retries = 0;
767                 conn->reconnect.previous = now;
768         }
769
770         /* are we reconnectind too often and too fast? */
771         if (conn->reconnect.retries > conn->reconnect.max_retries) return;
772
773         /* keep track of the number of reconnections */
774         conn->reconnect.retries++;
775
776         /* reconnect */
777         status = ldap_connect(conn, conn->reconnect.url);
778         if ( ! NT_STATUS_IS_OK(status)) {
779                 return;
780         }
781
782         /* rebind */
783         status = ldap_rebind(conn);
784         if ( ! NT_STATUS_IS_OK(status)) {
785                 ldap_connection_dead(conn, status);
786         }
787 }
788
789 static void ldap_request_destructor_abandon(struct ldap_request *abandon)
790 {
791         TALLOC_FREE(abandon);
792 }
793
794 /* destroy an open ldap request */
795 static int ldap_request_destructor(struct ldap_request *req)
796 {
797         if (req->state == LDAP_REQUEST_PENDING) {
798                 struct ldap_message msg = {
799                         .type = LDAP_TAG_AbandonRequest,
800                         .r.AbandonRequest.messageid = req->messageid,
801                 };
802                 struct ldap_request *abandon = NULL;
803
804                 DLIST_REMOVE(req->conn->pending, req);
805
806                 abandon = ldap_request_send(req->conn, &msg);
807                 if (abandon == NULL) {
808                         ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
809                         return 0;
810                 }
811                 abandon->async.fn = ldap_request_destructor_abandon;
812                 abandon->async.private_data = NULL;
813         }
814
815         return 0;
816 }
817
818 static void ldap_request_timeout_abandon(struct ldap_request *abandon)
819 {
820         struct ldap_request *req =
821                 talloc_get_type_abort(abandon->async.private_data,
822                 struct ldap_request);
823
824         if (req->state == LDAP_REQUEST_PENDING) {
825                 DLIST_REMOVE(req->conn->pending, req);
826         }
827         req->state = LDAP_REQUEST_DONE;
828         if (req->async.fn) {
829                 req->async.fn(req);
830         }
831 }
832
833 /*
834   called on timeout of a ldap request
835 */
836 static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer *te, 
837                                       struct timeval t, void *private_data)
838 {
839         struct ldap_request *req =
840                 talloc_get_type_abort(private_data,
841                 struct ldap_request);
842
843         req->status = NT_STATUS_IO_TIMEOUT;
844         if (req->state == LDAP_REQUEST_PENDING) {
845                 struct ldap_message msg = {
846                         .type = LDAP_TAG_AbandonRequest,
847                         .r.AbandonRequest.messageid = req->messageid,
848                 };
849                 struct ldap_request *abandon = NULL;
850
851                 abandon = ldap_request_send(req->conn, &msg);
852                 if (abandon == NULL) {
853                         ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
854                         return;
855                 }
856                 talloc_reparent(req->conn, req, abandon);
857                 abandon->async.fn = ldap_request_timeout_abandon;
858                 abandon->async.private_data = req;
859                 DLIST_REMOVE(req->conn->pending, req);
860                 return;
861         }
862         req->state = LDAP_REQUEST_DONE;
863         if (req->async.fn) {
864                 req->async.fn(req);
865         }
866 }
867
868
869 /*
870   called on completion of a failed ldap request
871 */
872 static void ldap_request_failed_complete(struct tevent_context *ev, struct tevent_timer *te,
873                                       struct timeval t, void *private_data)
874 {
875         struct ldap_request *req =
876                 talloc_get_type_abort(private_data,
877                 struct ldap_request);
878
879         if (req->async.fn) {
880                 req->async.fn(req);
881         }
882 }
883
884 static void ldap_request_written(struct tevent_req *subreq);
885
886 /*
887   send a ldap message - async interface
888 */
889 _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
890                                        struct ldap_message *msg)
891 {
892         struct ldap_request *req;
893         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
894         struct tevent_req *subreq = NULL;
895
896         req = talloc_zero(conn, struct ldap_request);
897         if (req == NULL) return NULL;
898
899         if (conn->sockets.active == NULL) {
900                 status = NT_STATUS_INVALID_CONNECTION;
901                 goto failed;
902         }
903
904         req->state       = LDAP_REQUEST_SEND;
905         req->conn        = conn;
906         req->messageid   = conn->next_messageid++;
907         if (conn->next_messageid == 0) {
908                 conn->next_messageid = 1;
909         }
910         req->type        = msg->type;
911         if (req->messageid == -1) {
912                 goto failed;
913         }
914
915         talloc_set_destructor(req, ldap_request_destructor);
916
917         msg->messageid = req->messageid;
918
919         if (!ldap_encode(msg, samba_ldap_control_handlers(), &req->data, req)) {
920                 status = NT_STATUS_INTERNAL_ERROR;
921                 goto failed;            
922         }
923
924         /* put a timeout on the request */
925         req->time_event = tevent_add_timer(conn->event.event_ctx, req,
926                                            timeval_current_ofs(conn->timeout, 0),
927                                            ldap_request_timeout, req);
928         if (req->time_event == NULL) {
929                 status = NT_STATUS_NO_MEMORY;
930                 goto failed;
931         }
932
933         req->write_iov.iov_base = req->data.data;
934         req->write_iov.iov_len = req->data.length;
935
936         subreq = tstream_writev_queue_send(req, conn->event.event_ctx,
937                                            conn->sockets.active,
938                                            conn->sockets.send_queue,
939                                            &req->write_iov, 1);
940         if (subreq == NULL) {
941                 status = NT_STATUS_NO_MEMORY;
942                 goto failed;
943         }
944         tevent_req_set_callback(subreq, ldap_request_written, req);
945
946         req->state = LDAP_REQUEST_PENDING;
947         DLIST_ADD(conn->pending, req);
948
949         return req;
950
951 failed:
952         req->status = status;
953         req->state = LDAP_REQUEST_ERROR;
954         tevent_add_timer(conn->event.event_ctx, req, timeval_zero(),
955                          ldap_request_failed_complete, req);
956
957         return req;
958 }
959
960 static void ldap_request_written(struct tevent_req *subreq)
961 {
962         struct ldap_request *req =
963                 tevent_req_callback_data(subreq,
964                 struct ldap_request);
965         int err;
966         ssize_t ret;
967
968         ret = tstream_writev_queue_recv(subreq, &err);
969         TALLOC_FREE(subreq);
970         if (ret == -1) {
971                 NTSTATUS error = map_nt_error_from_unix_common(err);
972                 ldap_error_handler(req->conn, error);
973                 return;
974         }
975
976         if (req->type == LDAP_TAG_AbandonRequest ||
977             req->type == LDAP_TAG_UnbindRequest)
978         {
979                 if (req->state == LDAP_REQUEST_PENDING) {
980                         DLIST_REMOVE(req->conn->pending, req);
981                 }
982                 req->state = LDAP_REQUEST_DONE;
983                 if (req->async.fn) {
984                         req->async.fn(req);
985                 }
986                 return;
987         }
988
989         ldap_connection_recv_next(req->conn);
990 }
991
992
993 /*
994   wait for a request to complete
995   note that this does not destroy the request
996 */
997 _PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req)
998 {
999         while (req->state < LDAP_REQUEST_DONE) {
1000                 if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
1001                         req->state = LDAP_REQUEST_ERROR;
1002                         req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1003                         break;
1004                 }
1005         }
1006         return req->status;
1007 }
1008
1009
1010 /*
1011   a mapping of ldap response code to strings
1012 */
1013 static const struct {
1014         enum ldap_result_code code;
1015         const char *str;
1016 } ldap_code_map[] = {
1017 #define _LDAP_MAP_CODE(c) { c, #c }
1018         _LDAP_MAP_CODE(LDAP_SUCCESS),
1019         _LDAP_MAP_CODE(LDAP_OPERATIONS_ERROR),
1020         _LDAP_MAP_CODE(LDAP_PROTOCOL_ERROR),
1021         _LDAP_MAP_CODE(LDAP_TIME_LIMIT_EXCEEDED),
1022         _LDAP_MAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED),
1023         _LDAP_MAP_CODE(LDAP_COMPARE_FALSE),
1024         _LDAP_MAP_CODE(LDAP_COMPARE_TRUE),
1025         _LDAP_MAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED),
1026         _LDAP_MAP_CODE(LDAP_STRONG_AUTH_REQUIRED),
1027         _LDAP_MAP_CODE(LDAP_REFERRAL),
1028         _LDAP_MAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED),
1029         _LDAP_MAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION),
1030         _LDAP_MAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED),
1031         _LDAP_MAP_CODE(LDAP_SASL_BIND_IN_PROGRESS),
1032         _LDAP_MAP_CODE(LDAP_NO_SUCH_ATTRIBUTE),
1033         _LDAP_MAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE),
1034         _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_MATCHING),
1035         _LDAP_MAP_CODE(LDAP_CONSTRAINT_VIOLATION),
1036         _LDAP_MAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS),
1037         _LDAP_MAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX),
1038         _LDAP_MAP_CODE(LDAP_NO_SUCH_OBJECT),
1039         _LDAP_MAP_CODE(LDAP_ALIAS_PROBLEM),
1040         _LDAP_MAP_CODE(LDAP_INVALID_DN_SYNTAX),
1041         _LDAP_MAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM),
1042         _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION),
1043         _LDAP_MAP_CODE(LDAP_INVALID_CREDENTIALS),
1044         _LDAP_MAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTS),
1045         _LDAP_MAP_CODE(LDAP_BUSY),
1046         _LDAP_MAP_CODE(LDAP_UNAVAILABLE),
1047         _LDAP_MAP_CODE(LDAP_UNWILLING_TO_PERFORM),
1048         _LDAP_MAP_CODE(LDAP_LOOP_DETECT),
1049         _LDAP_MAP_CODE(LDAP_NAMING_VIOLATION),
1050         _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_VIOLATION),
1051         _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF),
1052         _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_RDN),
1053         _LDAP_MAP_CODE(LDAP_ENTRY_ALREADY_EXISTS),
1054         _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED),
1055         _LDAP_MAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS),
1056         _LDAP_MAP_CODE(LDAP_OTHER)
1057 };
1058
1059 /*
1060   used to setup the status code from a ldap response
1061 */
1062 _PUBLIC_ NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
1063 {
1064         size_t i;
1065         const char *codename = "unknown";
1066
1067         if (r->resultcode == LDAP_SUCCESS) {
1068                 return NT_STATUS_OK;
1069         }
1070
1071         if (conn->last_error) {
1072                 talloc_free(conn->last_error);
1073         }
1074
1075         for (i=0;i<ARRAY_SIZE(ldap_code_map);i++) {
1076                 if ((enum ldap_result_code)r->resultcode == ldap_code_map[i].code) {
1077                         codename = ldap_code_map[i].str;
1078                         break;
1079                 }
1080         }
1081
1082         conn->last_error = talloc_asprintf(conn, "LDAP error %u %s - %s <%s> <%s>", 
1083                                            r->resultcode,
1084                                            codename,
1085                                            r->dn?r->dn:"(NULL)", 
1086                                            r->errormessage?r->errormessage:"", 
1087                                            r->referral?r->referral:"");
1088         
1089         return NT_STATUS_LDAP(r->resultcode);
1090 }
1091
1092 /*
1093   return error string representing the last error
1094 */
1095 _PUBLIC_ const char *ldap_errstr(struct ldap_connection *conn, 
1096                         TALLOC_CTX *mem_ctx, 
1097                         NTSTATUS status)
1098 {
1099         if (NT_STATUS_IS_LDAP(status) && conn->last_error != NULL) {
1100                 return talloc_strdup(mem_ctx, conn->last_error);
1101         }
1102         return talloc_asprintf(mem_ctx, "LDAP client internal error: %s", nt_errstr(status));
1103 }
1104
1105
1106 /*
1107   return the Nth result message, waiting if necessary
1108 */
1109 _PUBLIC_ NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
1110 {
1111         *msg = NULL;
1112
1113         NT_STATUS_HAVE_NO_MEMORY(req);
1114
1115         while (req->state < LDAP_REQUEST_DONE && n >= req->num_replies) {
1116                 if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
1117                         return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1118                 }
1119         }
1120
1121         if (n < req->num_replies) {
1122                 *msg = req->replies[n];
1123                 return NT_STATUS_OK;
1124         }
1125
1126         if (!NT_STATUS_IS_OK(req->status)) {
1127                 return req->status;
1128         }
1129
1130         return NT_STATUS_NO_MORE_ENTRIES;
1131 }
1132
1133
1134 /*
1135   return a single result message, checking if it is of the expected LDAP type
1136 */
1137 _PUBLIC_ NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
1138 {
1139         NTSTATUS status;
1140         status = ldap_result_n(req, 0, msg);
1141         if (!NT_STATUS_IS_OK(status)) {
1142                 return status;
1143         }
1144         if ((*msg) != NULL && (*msg)->type != (enum ldap_request_tag)type) {
1145                 *msg = NULL;
1146                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1147         }
1148         return status;
1149 }