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/>.
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
51 ldap_connection_dead(conn
, NT_STATUS_OK
);
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
;
73 conn
= talloc_zero(mem_ctx
, struct ldap_connection
);
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
) {
88 conn
->lp_ctx
= lp_ctx
;
90 /* set a reasonable request timeout */
93 /* explicitly avoid reconnections by default */
94 conn
->reconnect
.max_retries
= 0;
96 talloc_set_destructor(conn
, ldap_connection_destructor
);
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
) {
117 DLIST_REMOVE(req
->conn
->pending
, req
);
119 req
->state
= LDAP_REQUEST_DONE
;
120 if (NT_STATUS_IS_OK(status
)) {
123 req
->status
= status
;
130 static void ldap_reconnect(struct ldap_connection
*conn
);
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
;
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) {
161 DEBUG(0,("ldap: no matching message id for %u\n",
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
) {
172 req
->status
= NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION
);
173 req
->state
= LDAP_REQUEST_DONE
;
174 DLIST_REMOVE(conn
->pending
, req
);
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
) {
187 req
->status
= NT_STATUS_NO_MEMORY
;
188 req
->state
= LDAP_REQUEST_DONE
;
189 DLIST_REMOVE(conn
->pending
, req
);
196 req
->replies
[req
->num_replies
] = talloc_steal(req
->replies
, msg
);
199 if (msg
->type
!= LDAP_TAG_SearchResultEntry
&&
200 msg
->type
!= LDAP_TAG_SearchResultReference
) {
201 /* currently only search results expect multiple
203 req
->state
= LDAP_REQUEST_DONE
;
204 DLIST_REMOVE(conn
->pending
, 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
) {
222 if (conn
->sockets
.active
== NULL
) {
226 if (conn
->pending
== NULL
) {
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>
240 * 5 0: [APPLICATION 2]
241 * : Error: Object has zero length.
244 * dumpasn1 -hh ldap-unbind-windows.dat
246 * <30 84 00 00 00 05 02 01 09 42 00>
251 * 9 0: [APPLICATION 2]
252 * : Error: Object has zero length.
255 * This means using an initial read size
258 subreq
= tstream_read_pdu_blob_send(conn
,
259 conn
->event
.event_ctx
,
260 conn
->sockets
.active
,
261 7, /* initial_read_size */
264 if (subreq
== NULL
) {
265 ldap_error_handler(conn
, NT_STATUS_NO_MEMORY
);
268 tevent_req_set_callback(subreq
, ldap_connection_recv_done
, conn
);
269 conn
->sockets
.recv_subreq
= subreq
;
274 decode/process LDAP data
276 static void ldap_connection_recv_done(struct tevent_req
*subreq
)
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
;
285 struct ldap_request_limits limits
= {0};
287 msg
= talloc_zero(conn
, struct ldap_message
);
289 ldap_error_handler(conn
, NT_STATUS_NO_MEMORY
);
293 asn1
= asn1_init(conn
, ASN1_MAX_TREE_DEPTH
);
296 ldap_error_handler(conn
, NT_STATUS_NO_MEMORY
);
300 conn
->sockets
.recv_subreq
= NULL
;
302 status
= tstream_read_pdu_blob_recv(subreq
,
306 if (!NT_STATUS_IS_OK(status
)) {
309 ldap_error_handler(conn
, status
);
313 asn1_load_nocopy(asn1
, blob
.data
, blob
.length
);
315 status
= ldap_decode(asn1
, &limits
, samba_ldap_control_handlers(), msg
);
317 if (!NT_STATUS_IS_OK(status
)) {
319 ldap_error_handler(conn
, status
);
323 ldap_match_message(conn
, msg
);
324 ldap_connection_recv_next(conn
);
336 static int ldap_parse_basic_url(
338 enum ldap_proto
*pproto
,
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
;
351 if (strncasecmp_m(url
, "ldapi://", strlen("ldapi://")) == 0) {
352 char *path
= NULL
, *end
= NULL
;
354 path
= talloc_strdup(mem_ctx
, url
+8);
358 end
= rfc1738_unescape(path
);
364 *pproto
= LDAP_PROTO_LDAPI
;
369 if (strncasecmp_m(url
, "ldap://", strlen("ldap://")) == 0) {
371 proto
= LDAP_PROTO_LDAP
;
374 if (strncasecmp_m(url
, "ldaps://", strlen("ldaps://")) == 0) {
377 proto
= LDAP_PROTO_LDAPS
;
380 if (proto
== LDAP_PROTO_NONE
) {
381 return EPROTONOSUPPORT
;
386 * IPv6 with [aa:bb:cc..]:port
388 const char *end
= NULL
;
392 end
= strchr(url
, ']');
397 ret
= sscanf(end
+1, ":%d", &port
);
402 *pdest
= talloc_strndup(mem_ctx
, url
, end
-url
);
403 if (*pdest
== NULL
) {
411 ret
= sscanf(url
, "%m[^:/]:%d", &host
, &port
);
416 *pdest
= talloc_strdup(mem_ctx
, host
);
418 if (*pdest
== NULL
) {
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
,
446 struct composite_context
*result
, *ctx
;
447 struct ldap_connect_state
*state
;
448 enum ldap_proto proto
;
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
;
462 result
->private_data
= state
;
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
);
473 composite_error(result
, map_nt_error_from_unix_common(ret
));
477 if (proto
== LDAP_PROTO_LDAPI
) {
478 struct socket_address
*unix_addr
;
479 NTSTATUS status
= socket_create(state
, "unix",
482 if (!NT_STATUS_IS_OK(status
)) {
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
)) {
493 unix_addr
= socket_address_from_strings(state
, state
->sock
->backend_name
,
495 if (composite_nomem(unix_addr
, 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
;
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
) {
515 proto
= LDAP_PROTO_LDAPS
;
516 } else if (port
== 3268) {
518 proto
= LDAP_PROTO_LDAPS
;
520 conn
->starttls
= true;
524 } else if (wrap_flags
& ADS_AUTH_SASL_STARTTLS
) {
525 if (proto
== LDAP_PROTO_LDAP
) {
526 conn
->starttls
= true;
531 conn
->host
= talloc_move(conn
, &dest
);
537 status
= tstream_tls_params_client_lpcfg(state
,
541 if (!NT_STATUS_IS_OK(status
)) {
542 composite_error(result
, status
);
547 ctx
= socket_connect_multi_send(state
, conn
->host
, 1, &conn
->port
,
548 lpcfg_resolve_context(conn
->lp_ctx
),
550 if (composite_nomem(ctx
, result
)) {
554 ctx
->async
.fn
= ldap_connect_recv_tcp_conn
;
555 ctx
->async
.private_data
= state
;
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
;
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);
584 NTSTATUS status
= map_nt_error_from_unix_common(errno
);
585 composite_error(state
->ctx
, status
);
589 ret
= tstream_bsd_existing_socket(state
, fd
, &state
->raw
);
591 NTSTATUS status
= map_nt_error_from_unix_common(errno
);
592 composite_error(state
->ctx
, status
);
596 conn
->sockets
.raw
= talloc_move(conn
, &state
->raw
);
597 conn
->sockets
.active
= conn
->sockets
.raw
;
600 composite_done(state
->ctx
);
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
)) {
615 ldap_req
->async
.fn
= ldap_connect_starttls_done
;
616 ldap_req
->async
.private_data
= state
;
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
)) {
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
);
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
);
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
);
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
);
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
)) {
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
);
681 ret
= tstream_tls_connect_recv(subreq
, &err
, state
, &state
->tls
);
684 NTSTATUS status
= map_nt_error_from_unix_common(err
);
685 composite_error(state
->ctx
, status
);
689 talloc_steal(state
->tls
, state
->tls_params
);
691 state
->conn
->sockets
.tls
= talloc_move(state
->conn
->sockets
.raw
,
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
;
704 NTSTATUS status
= socket_connect_multi_recv(ctx
, state
, &state
->sock
,
706 if (!NT_STATUS_IS_OK(status
)) {
707 composite_error(state
->ctx
, status
);
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
);
728 ldap_connect_got_sock(state
->ctx
, conn
);
731 _PUBLIC_ NTSTATUS
ldap_connect_recv(struct composite_context
*ctx
)
733 NTSTATUS status
= composite_wait(ctx
);
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
)
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
)
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
++;
777 status
= ldap_connect(conn
, conn
->reconnect
.url
);
778 if ( ! NT_STATUS_IS_OK(status
)) {
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
);
811 abandon
->async
.fn
= ldap_request_destructor_abandon
;
812 abandon
->async
.private_data
= NULL
;
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
;
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
);
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
);
862 req
->state
= LDAP_REQUEST_DONE
;
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
);
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
;
904 req
->state
= LDAP_REQUEST_SEND
;
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) {
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
;
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
;
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
,
940 if (subreq
== NULL
) {
941 status
= NT_STATUS_NO_MEMORY
;
944 tevent_req_set_callback(subreq
, ldap_request_written
, req
);
946 req
->state
= LDAP_REQUEST_PENDING
;
947 DLIST_ADD(conn
->pending
, req
);
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
);
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
);
968 ret
= tstream_writev_queue_recv(subreq
, &err
);
971 NTSTATUS error
= map_nt_error_from_unix_common(err
);
972 ldap_error_handler(req
->conn
, error
);
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
;
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
;
1011 a mapping of ldap response code to strings
1013 static const struct {
1014 enum ldap_result_code code
;
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
)
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
;
1082 conn
->last_error
= talloc_asprintf(conn
, "LDAP error %u %s - %s <%s> <%s>",
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
,
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
)
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
)) {
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
)
1140 status
= ldap_result_n(req
, 0, msg
);
1141 if (!NT_STATUS_IS_OK(status
)) {
1144 if ((*msg
) != NULL
&& (*msg
)->type
!= (enum ldap_request_tag
)type
) {
1146 return NT_STATUS_UNEXPECTED_NETWORK_ERROR
;