ctdb-scripts: Move connection tracking to 10.interface
[samba4-gss.git] / source4 / libcli / ldap / ldap_client.c
blob96521518584d79d03a14a1b9382b0e01a3befa1f
1 /*
2 Unix SMB/CIFS implementation.
3 LDAP protocol helper functions for SAMBA
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Stefan Metzmacher 2004
8 Copyright (C) Simo Sorce 2004
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.
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.
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/>.
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 "librpc/gen_ndr/ads.h"
43 static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status);
45 static int ldap_connection_destructor(struct ldap_connection *conn)
48 * NT_STATUS_OK means that callbacks of pending requests are not
49 * triggered
51 ldap_connection_dead(conn, NT_STATUS_OK);
52 return 0;
55 /**
56 create a new ldap_connection structure. The event context is optional
59 _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,
60 struct loadparm_context *lp_ctx,
61 struct tevent_context *ev)
63 struct ldap_connection *conn;
65 if (ev == NULL) {
66 return NULL;
69 if (lp_ctx == NULL) {
70 return NULL;
73 conn = talloc_zero(mem_ctx, struct ldap_connection);
74 if (conn == NULL) {
75 return NULL;
78 conn->next_messageid = 1;
79 conn->event.event_ctx = ev;
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;
88 conn->lp_ctx = lp_ctx;
90 /* set a reasonable request timeout */
91 conn->timeout = 60;
93 /* explicitly avoid reconnections by default */
94 conn->reconnect.max_retries = 0;
96 talloc_set_destructor(conn, ldap_connection_destructor);
97 return conn;
101 the connection is dead
103 static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status)
105 struct ldap_request *req;
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);
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;
123 req->status = status;
124 if (req->async.fn) {
125 req->async.fn(req);
130 static void ldap_reconnect(struct ldap_connection *conn);
133 handle packet errors
135 static void ldap_error_handler(struct ldap_connection *conn, NTSTATUS status)
137 ldap_connection_dead(conn, status);
139 /* but try to reconnect so that the ldb client can go on */
140 ldap_reconnect(conn);
145 match up with a pending message, adding to the replies list
147 static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg)
149 struct ldap_request *req;
150 int i;
152 for (req=conn->pending; req; req=req->next) {
153 if (req->messageid == msg->messageid) break;
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;
160 if (req == NULL) {
161 DEBUG(0,("ldap: no matching message id for %u\n",
162 msg->messageid));
163 TALLOC_FREE(msg);
164 return;
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);
178 return;
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);
193 return;
196 req->replies[req->num_replies] = talloc_steal(req->replies, msg);
197 req->num_replies++;
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);
207 if (req->async.fn) {
208 req->async.fn(req);
212 static void ldap_connection_recv_done(struct tevent_req *subreq);
214 static void ldap_connection_recv_next(struct ldap_connection *conn)
216 struct tevent_req *subreq = NULL;
218 if (conn->sockets.recv_subreq != NULL) {
219 return;
222 if (conn->sockets.active == NULL) {
223 return;
226 if (conn->pending == NULL) {
227 return;
231 * The minimum size of a LDAP pdu is 7 bytes
233 * dumpasn1 -hh ldap-unbind-min.dat
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 * : }
244 * dumpasn1 -hh ldap-unbind-windows.dat
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 * : }
255 * This means using an initial read size
256 * of 7 is ok.
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;
268 tevent_req_set_callback(subreq, ldap_connection_recv_done, conn);
269 conn->sockets.recv_subreq = subreq;
270 return;
274 decode/process LDAP data
276 static void ldap_connection_recv_done(struct tevent_req *subreq)
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};
287 msg = talloc_zero(conn, struct ldap_message);
288 if (msg == NULL) {
289 ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
290 return;
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;
300 conn->sockets.recv_subreq = NULL;
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;
313 asn1_load_nocopy(asn1, blob.data, blob.length);
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;
323 ldap_match_message(conn, msg);
324 ldap_connection_recv_next(conn);
326 return;
329 enum ldap_proto {
330 LDAP_PROTO_NONE,
331 LDAP_PROTO_LDAP,
332 LDAP_PROTO_LDAPS,
333 LDAP_PROTO_LDAPI
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 */
343 enum ldap_proto proto = LDAP_PROTO_NONE;
344 char *host = NULL;
345 int ret, port;
347 if (url == NULL) {
348 return EINVAL;
351 if (strncasecmp_m(url, "ldapi://", strlen("ldapi://")) == 0) {
352 char *path = NULL, *end = NULL;
354 path = talloc_strdup(mem_ctx, url+8);
355 if (path == NULL) {
356 return ENOMEM;
358 end = rfc1738_unescape(path);
359 if (end == NULL) {
360 TALLOC_FREE(path);
361 return EINVAL;
364 *pproto = LDAP_PROTO_LDAPI;
365 *pdest = path;
366 return 0;
369 if (strncasecmp_m(url, "ldap://", strlen("ldap://")) == 0) {
370 url += 7;
371 proto = LDAP_PROTO_LDAP;
372 port = 389;
374 if (strncasecmp_m(url, "ldaps://", strlen("ldaps://")) == 0) {
375 url += 8;
376 port = 636;
377 proto = LDAP_PROTO_LDAPS;
380 if (proto == LDAP_PROTO_NONE) {
381 return EPROTONOSUPPORT;
384 if (url[0] == '[') {
386 * IPv6 with [aa:bb:cc..]:port
388 const char *end = NULL;
390 url +=1;
392 end = strchr(url, ']');
393 if (end == NULL) {
394 return EINVAL;
397 ret = sscanf(end+1, ":%d", &port);
398 if (ret < 0) {
399 return EINVAL;
402 *pdest = talloc_strndup(mem_ctx, url, end-url);
403 if (*pdest == NULL) {
404 return ENOMEM;
406 *pproto = proto;
407 *pport = port;
408 return 0;
411 ret = sscanf(url, "%m[^:/]:%d", &host, &port);
412 if (ret < 1) {
413 return EINVAL;
416 *pdest = talloc_strdup(mem_ctx, host);
417 SAFE_FREE(host);
418 if (*pdest == NULL) {
419 return ENOMEM;
421 *pproto = proto;
422 *pport = port;
424 return 0;
428 connect to a ldap server
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;
440 static void ldap_connect_recv_unix_conn(struct composite_context *ctx);
441 static void ldap_connect_recv_tcp_conn(struct composite_context *ctx);
443 _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
444 const char *url)
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;
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;
459 state = talloc(result, struct ldap_connect_state);
460 if (state == NULL) goto failed;
461 state->ctx = result;
462 result->private_data = state;
464 state->conn = conn;
466 if (conn->reconnect.url == NULL) {
467 conn->reconnect.url = talloc_strdup(conn, url);
468 if (conn->reconnect.url == NULL) goto failed;
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;
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;
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;
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;
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;
506 if ((proto == LDAP_PROTO_LDAP) || (proto == LDAP_PROTO_LDAPS)) {
507 int wrap_flags = lpcfg_client_ldap_sasl_wrapping(conn->lp_ctx);
509 conn->ldaps = (proto == LDAP_PROTO_LDAPS);
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;
523 conn->ldaps = true;
524 } else if (wrap_flags & ADS_AUTH_SASL_STARTTLS) {
525 if (proto == LDAP_PROTO_LDAP) {
526 conn->starttls = true;
528 conn->ldaps = true;
531 conn->host = talloc_move(conn, &dest);
532 conn->port = port;
534 if (conn->ldaps) {
535 NTSTATUS status;
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;
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;
554 ctx->async.fn = ldap_connect_recv_tcp_conn;
555 ctx->async.private_data = state;
556 return result;
558 failed:
559 talloc_free(result);
560 return NULL;
563 static void ldap_connect_starttls_done(struct ldap_request *ldap_req);
564 static void ldap_connect_got_tls(struct tevent_req *subreq);
566 static void ldap_connect_got_sock(struct composite_context *ctx,
567 struct ldap_connection *conn)
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;
576 socket_set_flags(state->sock, SOCKET_FLAG_NOCLOSE);
577 fd = socket_get_fd(state->sock);
578 TALLOC_FREE(state->sock);
580 smb_set_close_on_exec(fd);
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;
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;
596 conn->sockets.raw = talloc_move(conn, &state->raw);
597 conn->sockets.active = conn->sockets.raw;
599 if (!conn->ldaps) {
600 composite_done(state->ctx);
601 return;
604 if (conn->starttls) {
605 struct ldap_message msg = {
606 .type = LDAP_TAG_ExtendedRequest,
607 .r.ExtendedRequest.oid = LDB_EXTENDED_START_TLS_OID,
609 struct ldap_request *ldap_req = NULL;
611 ldap_req = ldap_request_send(conn, &msg);
612 if (composite_nomem(ldap_req, state->ctx)) {
613 return;
615 ldap_req->async.fn = ldap_connect_starttls_done;
616 ldap_req->async.private_data = state;
617 return;
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;
625 tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
628 static void ldap_connect_starttls_done(struct ldap_request *ldap_req)
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;
637 if (!NT_STATUS_IS_OK(status)) {
638 TALLOC_FREE(ldap_req);
639 composite_error(state->ctx, status);
640 return;
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;
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;
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;
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;
670 tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
673 static void ldap_connect_got_tls(struct tevent_req *subreq)
675 struct ldap_connect_state *state =
676 tevent_req_callback_data(subreq,
677 struct ldap_connect_state);
678 int err;
679 int ret;
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;
689 talloc_steal(state->tls, state->tls_params);
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);
697 static void ldap_connect_recv_tcp_conn(struct composite_context *ctx)
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;
711 ldap_connect_got_sock(state->ctx, conn);
714 static void ldap_connect_recv_unix_conn(struct composite_context *ctx)
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;
721 NTSTATUS status = socket_connect_recv(ctx);
723 if (!NT_STATUS_IS_OK(state->ctx->status)) {
724 composite_error(state->ctx, status);
725 return;
728 ldap_connect_got_sock(state->ctx, conn);
731 _PUBLIC_ NTSTATUS ldap_connect_recv(struct composite_context *ctx)
733 NTSTATUS status = composite_wait(ctx);
734 talloc_free(ctx);
735 return status;
738 _PUBLIC_ NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
740 struct composite_context *ctx = ldap_connect_send(conn, url);
741 return ldap_connect_recv(ctx);
744 /* set reconnect parameters */
746 _PUBLIC_ void ldap_set_reconn_params(struct ldap_connection *conn, int max_retries)
748 if (conn) {
749 conn->reconnect.max_retries = max_retries;
750 conn->reconnect.retries = 0;
751 conn->reconnect.previous = time_mono(NULL);
755 /* Actually this function is NOT ASYNC safe, FIXME? */
756 static void ldap_reconnect(struct ldap_connection *conn)
758 NTSTATUS status;
759 time_t now = time_mono(NULL);
761 /* do we have set up reconnect ? */
762 if (conn->reconnect.max_retries == 0) return;
764 /* is the retry time expired ? */
765 if (now > conn->reconnect.previous + 30) {
766 conn->reconnect.retries = 0;
767 conn->reconnect.previous = now;
770 /* are we reconnectind too often and too fast? */
771 if (conn->reconnect.retries > conn->reconnect.max_retries) return;
773 /* keep track of the number of reconnections */
774 conn->reconnect.retries++;
776 /* reconnect */
777 status = ldap_connect(conn, conn->reconnect.url);
778 if ( ! NT_STATUS_IS_OK(status)) {
779 return;
782 /* rebind */
783 status = ldap_rebind(conn);
784 if ( ! NT_STATUS_IS_OK(status)) {
785 ldap_connection_dead(conn, status);
789 static void ldap_request_destructor_abandon(struct ldap_request *abandon)
791 TALLOC_FREE(abandon);
794 /* destroy an open ldap request */
795 static int ldap_request_destructor(struct ldap_request *req)
797 if (req->state == LDAP_REQUEST_PENDING) {
798 struct ldap_message msg = {
799 .type = LDAP_TAG_AbandonRequest,
800 .r.AbandonRequest.messageid = req->messageid,
802 struct ldap_request *abandon = NULL;
804 DLIST_REMOVE(req->conn->pending, req);
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;
811 abandon->async.fn = ldap_request_destructor_abandon;
812 abandon->async.private_data = NULL;
815 return 0;
818 static void ldap_request_timeout_abandon(struct ldap_request *abandon)
820 struct ldap_request *req =
821 talloc_get_type_abort(abandon->async.private_data,
822 struct ldap_request);
824 if (req->state == LDAP_REQUEST_PENDING) {
825 DLIST_REMOVE(req->conn->pending, req);
827 req->state = LDAP_REQUEST_DONE;
828 if (req->async.fn) {
829 req->async.fn(req);
834 called on timeout of a ldap request
836 static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer *te,
837 struct timeval t, void *private_data)
839 struct ldap_request *req =
840 talloc_get_type_abort(private_data,
841 struct ldap_request);
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,
849 struct ldap_request *abandon = NULL;
851 abandon = ldap_request_send(req->conn, &msg);
852 if (abandon == NULL) {
853 ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
854 return;
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;
862 req->state = LDAP_REQUEST_DONE;
863 if (req->async.fn) {
864 req->async.fn(req);
870 called on completion of a failed ldap request
872 static void ldap_request_failed_complete(struct tevent_context *ev, struct tevent_timer *te,
873 struct timeval t, void *private_data)
875 struct ldap_request *req =
876 talloc_get_type_abort(private_data,
877 struct ldap_request);
879 if (req->async.fn) {
880 req->async.fn(req);
884 static void ldap_request_written(struct tevent_req *subreq);
887 send a ldap message - async interface
889 _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
890 struct ldap_message *msg)
892 struct ldap_request *req;
893 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
894 struct tevent_req *subreq = NULL;
896 req = talloc_zero(conn, struct ldap_request);
897 if (req == NULL) return NULL;
899 if (conn->sockets.active == NULL) {
900 status = NT_STATUS_INVALID_CONNECTION;
901 goto failed;
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;
910 req->type = msg->type;
911 if (req->messageid == -1) {
912 goto failed;
915 talloc_set_destructor(req, ldap_request_destructor);
917 msg->messageid = req->messageid;
919 if (!ldap_encode(msg, samba_ldap_control_handlers(), &req->data, req)) {
920 status = NT_STATUS_INTERNAL_ERROR;
921 goto failed;
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;
933 req->write_iov.iov_base = req->data.data;
934 req->write_iov.iov_len = req->data.length;
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;
944 tevent_req_set_callback(subreq, ldap_request_written, req);
946 req->state = LDAP_REQUEST_PENDING;
947 DLIST_ADD(conn->pending, req);
949 return req;
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);
957 return req;
960 static void ldap_request_written(struct tevent_req *subreq)
962 struct ldap_request *req =
963 tevent_req_callback_data(subreq,
964 struct ldap_request);
965 int err;
966 ssize_t ret;
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;
976 if (req->type == LDAP_TAG_AbandonRequest ||
977 req->type == LDAP_TAG_UnbindRequest)
979 if (req->state == LDAP_REQUEST_PENDING) {
980 DLIST_REMOVE(req->conn->pending, req);
982 req->state = LDAP_REQUEST_DONE;
983 if (req->async.fn) {
984 req->async.fn(req);
986 return;
989 ldap_connection_recv_next(req->conn);
994 wait for a request to complete
995 note that this does not destroy the request
997 _PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req)
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;
1006 return req->status;
1011 a mapping of ldap response code to strings
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)
1060 used to setup the status code from a ldap response
1062 _PUBLIC_ NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
1064 size_t i;
1065 const char *codename = "unknown";
1067 if (r->resultcode == LDAP_SUCCESS) {
1068 return NT_STATUS_OK;
1071 if (conn->last_error) {
1072 talloc_free(conn->last_error);
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;
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:"");
1089 return NT_STATUS_LDAP(r->resultcode);
1093 return error string representing the last error
1095 _PUBLIC_ const char *ldap_errstr(struct ldap_connection *conn,
1096 TALLOC_CTX *mem_ctx,
1097 NTSTATUS status)
1099 if (NT_STATUS_IS_LDAP(status) && conn->last_error != NULL) {
1100 return talloc_strdup(mem_ctx, conn->last_error);
1102 return talloc_asprintf(mem_ctx, "LDAP client internal error: %s", nt_errstr(status));
1107 return the Nth result message, waiting if necessary
1109 _PUBLIC_ NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
1111 *msg = NULL;
1113 NT_STATUS_HAVE_NO_MEMORY(req);
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;
1121 if (n < req->num_replies) {
1122 *msg = req->replies[n];
1123 return NT_STATUS_OK;
1126 if (!NT_STATUS_IS_OK(req->status)) {
1127 return req->status;
1130 return NT_STATUS_NO_MORE_ENTRIES;
1135 return a single result message, checking if it is of the expected LDAP type
1137 _PUBLIC_ NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
1139 NTSTATUS status;
1140 status = ldap_result_n(req, 0, msg);
1141 if (!NT_STATUS_IS_OK(status)) {
1142 return status;
1144 if ((*msg) != NULL && (*msg)->type != (enum ldap_request_tag)type) {
1145 *msg = NULL;
1146 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1148 return status;