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"
42 static void ldap_connection_dead(struct ldap_connection
*conn
, NTSTATUS status
);
44 static int ldap_connection_destructor(struct ldap_connection
*conn
)
47 * NT_STATUS_OK means that callbacks of pending requests are not
50 ldap_connection_dead(conn
, NT_STATUS_OK
);
55 create a new ldap_connection stucture. The event context is optional
58 _PUBLIC_
struct ldap_connection
*ldap4_new_connection(TALLOC_CTX
*mem_ctx
,
59 struct loadparm_context
*lp_ctx
,
60 struct tevent_context
*ev
)
62 struct ldap_connection
*conn
;
68 conn
= talloc_zero(mem_ctx
, struct ldap_connection
);
73 conn
->next_messageid
= 1;
74 conn
->event
.event_ctx
= ev
;
76 conn
->sockets
.send_queue
= tevent_queue_create(conn
,
77 "ldap_connection send_queue");
78 if (conn
->sockets
.send_queue
== NULL
) {
83 conn
->lp_ctx
= lp_ctx
;
85 /* set a reasonable request timeout */
88 /* explicitly avoid reconnections by default */
89 conn
->reconnect
.max_retries
= 0;
91 talloc_set_destructor(conn
, ldap_connection_destructor
);
96 the connection is dead
98 static void ldap_connection_dead(struct ldap_connection
*conn
, NTSTATUS status
)
100 struct ldap_request
*req
;
102 tevent_queue_stop(conn
->sockets
.send_queue
);
103 TALLOC_FREE(conn
->sockets
.recv_subreq
);
104 conn
->sockets
.active
= NULL
;
105 TALLOC_FREE(conn
->sockets
.sasl
);
106 TALLOC_FREE(conn
->sockets
.tls
);
107 TALLOC_FREE(conn
->sockets
.raw
);
109 /* return an error for any pending request ... */
110 while (conn
->pending
) {
112 DLIST_REMOVE(req
->conn
->pending
, req
);
114 req
->state
= LDAP_REQUEST_DONE
;
115 if (NT_STATUS_IS_OK(status
)) {
118 req
->status
= status
;
125 static void ldap_reconnect(struct ldap_connection
*conn
);
130 static void ldap_error_handler(struct ldap_connection
*conn
, NTSTATUS status
)
132 ldap_connection_dead(conn
, status
);
134 /* but try to reconnect so that the ldb client can go on */
135 ldap_reconnect(conn
);
140 match up with a pending message, adding to the replies list
142 static void ldap_match_message(struct ldap_connection
*conn
, struct ldap_message
*msg
)
144 struct ldap_request
*req
;
147 for (req
=conn
->pending
; req
; req
=req
->next
) {
148 if (req
->messageid
== msg
->messageid
) break;
150 /* match a zero message id to the last request sent.
151 It seems that servers send 0 if unable to parse */
152 if (req
== NULL
&& msg
->messageid
== 0) {
156 DEBUG(0,("ldap: no matching message id for %u\n",
162 /* Check for undecoded critical extensions */
163 for (i
=0; msg
->controls
&& msg
->controls
[i
]; i
++) {
164 if (!msg
->controls_decoded
[i
] &&
165 msg
->controls
[i
]->critical
) {
167 req
->status
= NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION
);
168 req
->state
= LDAP_REQUEST_DONE
;
169 DLIST_REMOVE(conn
->pending
, req
);
177 /* add to the list of replies received */
178 req
->replies
= talloc_realloc(req
, req
->replies
,
179 struct ldap_message
*, req
->num_replies
+1);
180 if (req
->replies
== NULL
) {
182 req
->status
= NT_STATUS_NO_MEMORY
;
183 req
->state
= LDAP_REQUEST_DONE
;
184 DLIST_REMOVE(conn
->pending
, req
);
191 req
->replies
[req
->num_replies
] = talloc_steal(req
->replies
, msg
);
194 if (msg
->type
!= LDAP_TAG_SearchResultEntry
&&
195 msg
->type
!= LDAP_TAG_SearchResultReference
) {
196 /* currently only search results expect multiple
198 req
->state
= LDAP_REQUEST_DONE
;
199 DLIST_REMOVE(conn
->pending
, req
);
207 static void ldap_connection_recv_done(struct tevent_req
*subreq
);
209 static void ldap_connection_recv_next(struct ldap_connection
*conn
)
211 struct tevent_req
*subreq
= NULL
;
213 if (conn
->sockets
.recv_subreq
!= NULL
) {
217 if (conn
->sockets
.active
== NULL
) {
221 if (conn
->pending
== NULL
) {
226 * The minimum size of a LDAP pdu is 7 bytes
228 * dumpasn1 -hh ldap-unbind-min.dat
230 * <30 05 02 01 09 42 00>
235 * 5 0: [APPLICATION 2]
236 * : Error: Object has zero length.
239 * dumpasn1 -hh ldap-unbind-windows.dat
241 * <30 84 00 00 00 05 02 01 09 42 00>
246 * 9 0: [APPLICATION 2]
247 * : Error: Object has zero length.
250 * This means using an initial read size
253 subreq
= tstream_read_pdu_blob_send(conn
,
254 conn
->event
.event_ctx
,
255 conn
->sockets
.active
,
256 7, /* initial_read_size */
259 if (subreq
== NULL
) {
260 ldap_error_handler(conn
, NT_STATUS_NO_MEMORY
);
263 tevent_req_set_callback(subreq
, ldap_connection_recv_done
, conn
);
264 conn
->sockets
.recv_subreq
= subreq
;
269 decode/process LDAP data
271 static void ldap_connection_recv_done(struct tevent_req
*subreq
)
274 struct ldap_connection
*conn
=
275 tevent_req_callback_data(subreq
,
276 struct ldap_connection
);
277 struct ldap_message
*msg
;
278 struct asn1_data
*asn1
;
281 msg
= talloc_zero(conn
, struct ldap_message
);
283 ldap_error_handler(conn
, NT_STATUS_NO_MEMORY
);
287 asn1
= asn1_init(conn
);
290 ldap_error_handler(conn
, NT_STATUS_NO_MEMORY
);
294 conn
->sockets
.recv_subreq
= NULL
;
296 status
= tstream_read_pdu_blob_recv(subreq
,
300 if (!NT_STATUS_IS_OK(status
)) {
303 ldap_error_handler(conn
, status
);
307 asn1_load_nocopy(asn1
, blob
.data
, blob
.length
);
309 status
= ldap_decode(asn1
, samba_ldap_control_handlers(), msg
);
311 if (!NT_STATUS_IS_OK(status
)) {
313 ldap_error_handler(conn
, status
);
317 ldap_match_message(conn
, msg
);
318 ldap_connection_recv_next(conn
);
326 static NTSTATUS
ldap_parse_basic_url(TALLOC_CTX
*mem_ctx
, const char *url
,
327 char **host
, uint16_t *port
, bool *ldaps
)
335 SMB_ASSERT(sizeof(protocol
)>10 && sizeof(tmp_host
)>254);
337 ret
= sscanf(url
, "%10[^:]://%254[^:/]:%d", protocol
, tmp_host
, &tmp_port
);
339 return NT_STATUS_INVALID_PARAMETER
;
342 if (strequal(protocol
, "ldap")) {
345 } else if (strequal(protocol
, "ldaps")) {
349 DEBUG(0, ("unrecognised ldap protocol (%s)!\n", protocol
));
350 return NT_STATUS_PROTOCOL_UNREACHABLE
;
356 *host
= talloc_strdup(mem_ctx
, tmp_host
);
357 NT_STATUS_HAVE_NO_MEMORY(*host
);
363 connect to a ldap server
366 struct ldap_connect_state
{
367 struct composite_context
*ctx
;
368 struct ldap_connection
*conn
;
369 struct socket_context
*sock
;
370 struct tstream_context
*raw
;
371 struct tstream_tls_params
*tls_params
;
372 struct tstream_context
*tls
;
375 static void ldap_connect_recv_unix_conn(struct composite_context
*ctx
);
376 static void ldap_connect_recv_tcp_conn(struct composite_context
*ctx
);
378 _PUBLIC_
struct composite_context
*ldap_connect_send(struct ldap_connection
*conn
,
381 struct composite_context
*result
, *ctx
;
382 struct ldap_connect_state
*state
;
386 result
= talloc_zero(conn
, struct composite_context
);
387 if (result
== NULL
) goto failed
;
388 result
->state
= COMPOSITE_STATE_IN_PROGRESS
;
389 result
->async
.fn
= NULL
;
390 result
->event_ctx
= conn
->event
.event_ctx
;
392 state
= talloc(result
, struct ldap_connect_state
);
393 if (state
== NULL
) goto failed
;
395 result
->private_data
= state
;
399 if (conn
->reconnect
.url
== NULL
) {
400 conn
->reconnect
.url
= talloc_strdup(conn
, url
);
401 if (conn
->reconnect
.url
== NULL
) goto failed
;
405 SMB_ASSERT(sizeof(protocol
)>10);
407 ret
= sscanf(url
, "%10[^:]://", protocol
);
412 if (strequal(protocol
, "ldapi")) {
413 struct socket_address
*unix_addr
;
416 NTSTATUS status
= socket_create("unix", SOCKET_TYPE_STREAM
, &state
->sock
, 0);
417 if (!NT_STATUS_IS_OK(status
)) {
420 talloc_steal(state
, state
->sock
);
421 SMB_ASSERT(sizeof(protocol
)>10);
422 SMB_ASSERT(sizeof(path
)>1024);
424 /* LDAPI connections are to localhost, so give the
425 * local host name as the target for gensec's
426 * DIGEST-MD5 mechanism */
427 conn
->host
= talloc_asprintf(conn
, "%s.%s",
428 lpcfg_netbios_name(conn
->lp_ctx
),
429 lpcfg_dnsdomain(conn
->lp_ctx
));
430 if (composite_nomem(conn
->host
, state
->ctx
)) {
434 /* The %c specifier doesn't null terminate :-( */
436 ret
= sscanf(url
, "%10[^:]://%1025c", protocol
, path
);
438 composite_error(state
->ctx
, NT_STATUS_INVALID_PARAMETER
);
442 rfc1738_unescape(path
);
444 unix_addr
= socket_address_from_strings(state
, state
->sock
->backend_name
,
446 if (composite_nomem(unix_addr
, result
)) {
451 ctx
= socket_connect_send(state
->sock
, NULL
, unix_addr
,
452 0, result
->event_ctx
);
453 ctx
->async
.fn
= ldap_connect_recv_unix_conn
;
454 ctx
->async
.private_data
= state
;
457 NTSTATUS status
= ldap_parse_basic_url(conn
, url
, &conn
->host
,
458 &conn
->port
, &conn
->ldaps
);
459 if (!NT_STATUS_IS_OK(status
)) {
460 composite_error(result
, status
);
465 char *ca_file
= lpcfg_tls_cafile(state
, conn
->lp_ctx
);
466 char *crl_file
= lpcfg_tls_crlfile(state
, conn
->lp_ctx
);
467 const char *tls_priority
= lpcfg_tls_priority(conn
->lp_ctx
);
468 enum tls_verify_peer_state verify_peer
=
469 lpcfg_tls_verify_peer(conn
->lp_ctx
);
471 status
= tstream_tls_params_client(state
,
478 if (!NT_STATUS_IS_OK(status
)) {
479 composite_error(result
, status
);
484 ctx
= socket_connect_multi_send(state
, conn
->host
, 1, &conn
->port
,
485 lpcfg_resolve_context(conn
->lp_ctx
),
487 if (composite_nomem(ctx
, result
)) {
491 ctx
->async
.fn
= ldap_connect_recv_tcp_conn
;
492 ctx
->async
.private_data
= state
;
500 static void ldap_connect_got_tls(struct tevent_req
*subreq
);
502 static void ldap_connect_got_sock(struct composite_context
*ctx
,
503 struct ldap_connection
*conn
)
505 struct ldap_connect_state
*state
=
506 talloc_get_type_abort(ctx
->private_data
,
507 struct ldap_connect_state
);
508 struct tevent_req
*subreq
= NULL
;
512 socket_set_flags(state
->sock
, SOCKET_FLAG_NOCLOSE
);
513 fd
= socket_get_fd(state
->sock
);
514 TALLOC_FREE(state
->sock
);
516 smb_set_close_on_exec(fd
);
518 ret
= set_blocking(fd
, false);
520 NTSTATUS status
= map_nt_error_from_unix_common(errno
);
521 composite_error(state
->ctx
, status
);
525 ret
= tstream_bsd_existing_socket(state
, fd
, &state
->raw
);
527 NTSTATUS status
= map_nt_error_from_unix_common(errno
);
528 composite_error(state
->ctx
, status
);
533 conn
->sockets
.raw
= talloc_move(conn
, &state
->raw
);
534 conn
->sockets
.active
= conn
->sockets
.raw
;
535 composite_done(state
->ctx
);
539 subreq
= tstream_tls_connect_send(state
, state
->ctx
->event_ctx
,
540 state
->raw
, state
->tls_params
);
541 if (composite_nomem(subreq
, state
->ctx
)) {
544 tevent_req_set_callback(subreq
, ldap_connect_got_tls
, state
);
547 static void ldap_connect_got_tls(struct tevent_req
*subreq
)
549 struct ldap_connect_state
*state
=
550 tevent_req_callback_data(subreq
,
551 struct ldap_connect_state
);
555 ret
= tstream_tls_connect_recv(subreq
, &err
, state
, &state
->tls
);
558 NTSTATUS status
= map_nt_error_from_unix_common(err
);
559 composite_error(state
->ctx
, status
);
563 talloc_steal(state
->tls
, state
->tls_params
);
565 state
->conn
->sockets
.raw
= talloc_move(state
->conn
, &state
->raw
);
566 state
->conn
->sockets
.tls
= talloc_move(state
->conn
->sockets
.raw
,
568 state
->conn
->sockets
.active
= state
->conn
->sockets
.tls
;
569 composite_done(state
->ctx
);
572 static void ldap_connect_recv_tcp_conn(struct composite_context
*ctx
)
574 struct ldap_connect_state
*state
=
575 talloc_get_type_abort(ctx
->async
.private_data
,
576 struct ldap_connect_state
);
577 struct ldap_connection
*conn
= state
->conn
;
579 NTSTATUS status
= socket_connect_multi_recv(ctx
, state
, &state
->sock
,
581 if (!NT_STATUS_IS_OK(status
)) {
582 composite_error(state
->ctx
, status
);
586 ldap_connect_got_sock(state
->ctx
, conn
);
589 static void ldap_connect_recv_unix_conn(struct composite_context
*ctx
)
591 struct ldap_connect_state
*state
=
592 talloc_get_type_abort(ctx
->async
.private_data
,
593 struct ldap_connect_state
);
594 struct ldap_connection
*conn
= state
->conn
;
596 NTSTATUS status
= socket_connect_recv(ctx
);
598 if (!NT_STATUS_IS_OK(state
->ctx
->status
)) {
599 composite_error(state
->ctx
, status
);
603 ldap_connect_got_sock(state
->ctx
, conn
);
606 _PUBLIC_ NTSTATUS
ldap_connect_recv(struct composite_context
*ctx
)
608 NTSTATUS status
= composite_wait(ctx
);
613 _PUBLIC_ NTSTATUS
ldap_connect(struct ldap_connection
*conn
, const char *url
)
615 struct composite_context
*ctx
= ldap_connect_send(conn
, url
);
616 return ldap_connect_recv(ctx
);
619 /* set reconnect parameters */
621 _PUBLIC_
void ldap_set_reconn_params(struct ldap_connection
*conn
, int max_retries
)
624 conn
->reconnect
.max_retries
= max_retries
;
625 conn
->reconnect
.retries
= 0;
626 conn
->reconnect
.previous
= time_mono(NULL
);
630 /* Actually this function is NOT ASYNC safe, FIXME? */
631 static void ldap_reconnect(struct ldap_connection
*conn
)
634 time_t now
= time_mono(NULL
);
636 /* do we have set up reconnect ? */
637 if (conn
->reconnect
.max_retries
== 0) return;
639 /* is the retry time expired ? */
640 if (now
> conn
->reconnect
.previous
+ 30) {
641 conn
->reconnect
.retries
= 0;
642 conn
->reconnect
.previous
= now
;
645 /* are we reconnectind too often and too fast? */
646 if (conn
->reconnect
.retries
> conn
->reconnect
.max_retries
) return;
648 /* keep track of the number of reconnections */
649 conn
->reconnect
.retries
++;
652 status
= ldap_connect(conn
, conn
->reconnect
.url
);
653 if ( ! NT_STATUS_IS_OK(status
)) {
658 status
= ldap_rebind(conn
);
659 if ( ! NT_STATUS_IS_OK(status
)) {
660 ldap_connection_dead(conn
, status
);
664 static void ldap_request_destructor_abandon(struct ldap_request
*abandon
)
666 TALLOC_FREE(abandon
);
669 /* destroy an open ldap request */
670 static int ldap_request_destructor(struct ldap_request
*req
)
672 if (req
->state
== LDAP_REQUEST_PENDING
) {
673 struct ldap_message msg
= {
674 .type
= LDAP_TAG_AbandonRequest
,
675 .r
.AbandonRequest
.messageid
= req
->messageid
,
677 struct ldap_request
*abandon
= NULL
;
679 DLIST_REMOVE(req
->conn
->pending
, req
);
681 abandon
= ldap_request_send(req
->conn
, &msg
);
682 if (abandon
== NULL
) {
683 ldap_error_handler(req
->conn
, NT_STATUS_NO_MEMORY
);
686 abandon
->async
.fn
= ldap_request_destructor_abandon
;
687 abandon
->async
.private_data
= NULL
;
693 static void ldap_request_timeout_abandon(struct ldap_request
*abandon
)
695 struct ldap_request
*req
=
696 talloc_get_type_abort(abandon
->async
.private_data
,
697 struct ldap_request
);
699 if (req
->state
== LDAP_REQUEST_PENDING
) {
700 DLIST_REMOVE(req
->conn
->pending
, req
);
702 req
->state
= LDAP_REQUEST_DONE
;
709 called on timeout of a ldap request
711 static void ldap_request_timeout(struct tevent_context
*ev
, struct tevent_timer
*te
,
712 struct timeval t
, void *private_data
)
714 struct ldap_request
*req
=
715 talloc_get_type_abort(private_data
,
716 struct ldap_request
);
718 req
->status
= NT_STATUS_IO_TIMEOUT
;
719 if (req
->state
== LDAP_REQUEST_PENDING
) {
720 struct ldap_message msg
= {
721 .type
= LDAP_TAG_AbandonRequest
,
722 .r
.AbandonRequest
.messageid
= req
->messageid
,
724 struct ldap_request
*abandon
= NULL
;
726 abandon
= ldap_request_send(req
->conn
, &msg
);
727 if (abandon
== NULL
) {
728 ldap_error_handler(req
->conn
, NT_STATUS_NO_MEMORY
);
731 talloc_reparent(req
->conn
, req
, abandon
);
732 abandon
->async
.fn
= ldap_request_timeout_abandon
;
733 abandon
->async
.private_data
= req
;
734 DLIST_REMOVE(req
->conn
->pending
, req
);
737 req
->state
= LDAP_REQUEST_DONE
;
745 called on completion of a failed ldap request
747 static void ldap_request_failed_complete(struct tevent_context
*ev
, struct tevent_timer
*te
,
748 struct timeval t
, void *private_data
)
750 struct ldap_request
*req
=
751 talloc_get_type_abort(private_data
,
752 struct ldap_request
);
759 static void ldap_request_written(struct tevent_req
*subreq
);
762 send a ldap message - async interface
764 _PUBLIC_
struct ldap_request
*ldap_request_send(struct ldap_connection
*conn
,
765 struct ldap_message
*msg
)
767 struct ldap_request
*req
;
768 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
769 struct tevent_req
*subreq
= NULL
;
771 req
= talloc_zero(conn
, struct ldap_request
);
772 if (req
== NULL
) return NULL
;
774 if (conn
->sockets
.active
== NULL
) {
775 status
= NT_STATUS_INVALID_CONNECTION
;
779 req
->state
= LDAP_REQUEST_SEND
;
781 req
->messageid
= conn
->next_messageid
++;
782 if (conn
->next_messageid
== 0) {
783 conn
->next_messageid
= 1;
785 req
->type
= msg
->type
;
786 if (req
->messageid
== -1) {
790 talloc_set_destructor(req
, ldap_request_destructor
);
792 msg
->messageid
= req
->messageid
;
794 if (!ldap_encode(msg
, samba_ldap_control_handlers(), &req
->data
, req
)) {
795 status
= NT_STATUS_INTERNAL_ERROR
;
799 /* put a timeout on the request */
800 req
->time_event
= tevent_add_timer(conn
->event
.event_ctx
, req
,
801 timeval_current_ofs(conn
->timeout
, 0),
802 ldap_request_timeout
, req
);
803 if (req
->time_event
== NULL
) {
804 status
= NT_STATUS_NO_MEMORY
;
808 req
->write_iov
.iov_base
= req
->data
.data
;
809 req
->write_iov
.iov_len
= req
->data
.length
;
811 subreq
= tstream_writev_queue_send(req
, conn
->event
.event_ctx
,
812 conn
->sockets
.active
,
813 conn
->sockets
.send_queue
,
815 if (subreq
== NULL
) {
816 status
= NT_STATUS_NO_MEMORY
;
819 tevent_req_set_callback(subreq
, ldap_request_written
, req
);
821 req
->state
= LDAP_REQUEST_PENDING
;
822 DLIST_ADD(conn
->pending
, req
);
827 req
->status
= status
;
828 req
->state
= LDAP_REQUEST_ERROR
;
829 tevent_add_timer(conn
->event
.event_ctx
, req
, timeval_zero(),
830 ldap_request_failed_complete
, req
);
835 static void ldap_request_written(struct tevent_req
*subreq
)
837 struct ldap_request
*req
=
838 tevent_req_callback_data(subreq
,
839 struct ldap_request
);
843 ret
= tstream_writev_queue_recv(subreq
, &err
);
846 NTSTATUS error
= map_nt_error_from_unix_common(err
);
847 ldap_error_handler(req
->conn
, error
);
851 if (req
->type
== LDAP_TAG_AbandonRequest
||
852 req
->type
== LDAP_TAG_UnbindRequest
)
854 if (req
->state
== LDAP_REQUEST_PENDING
) {
855 DLIST_REMOVE(req
->conn
->pending
, req
);
857 req
->state
= LDAP_REQUEST_DONE
;
864 ldap_connection_recv_next(req
->conn
);
869 wait for a request to complete
870 note that this does not destroy the request
872 _PUBLIC_ NTSTATUS
ldap_request_wait(struct ldap_request
*req
)
874 while (req
->state
< LDAP_REQUEST_DONE
) {
875 if (tevent_loop_once(req
->conn
->event
.event_ctx
) != 0) {
876 req
->state
= LDAP_REQUEST_ERROR
;
877 req
->status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
886 a mapping of ldap response code to strings
888 static const struct {
889 enum ldap_result_code code
;
891 } ldap_code_map
[] = {
892 #define _LDAP_MAP_CODE(c) { c, #c }
893 _LDAP_MAP_CODE(LDAP_SUCCESS
),
894 _LDAP_MAP_CODE(LDAP_OPERATIONS_ERROR
),
895 _LDAP_MAP_CODE(LDAP_PROTOCOL_ERROR
),
896 _LDAP_MAP_CODE(LDAP_TIME_LIMIT_EXCEEDED
),
897 _LDAP_MAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED
),
898 _LDAP_MAP_CODE(LDAP_COMPARE_FALSE
),
899 _LDAP_MAP_CODE(LDAP_COMPARE_TRUE
),
900 _LDAP_MAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED
),
901 _LDAP_MAP_CODE(LDAP_STRONG_AUTH_REQUIRED
),
902 _LDAP_MAP_CODE(LDAP_REFERRAL
),
903 _LDAP_MAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED
),
904 _LDAP_MAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION
),
905 _LDAP_MAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED
),
906 _LDAP_MAP_CODE(LDAP_SASL_BIND_IN_PROGRESS
),
907 _LDAP_MAP_CODE(LDAP_NO_SUCH_ATTRIBUTE
),
908 _LDAP_MAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE
),
909 _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_MATCHING
),
910 _LDAP_MAP_CODE(LDAP_CONSTRAINT_VIOLATION
),
911 _LDAP_MAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS
),
912 _LDAP_MAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX
),
913 _LDAP_MAP_CODE(LDAP_NO_SUCH_OBJECT
),
914 _LDAP_MAP_CODE(LDAP_ALIAS_PROBLEM
),
915 _LDAP_MAP_CODE(LDAP_INVALID_DN_SYNTAX
),
916 _LDAP_MAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM
),
917 _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION
),
918 _LDAP_MAP_CODE(LDAP_INVALID_CREDENTIALS
),
919 _LDAP_MAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTS
),
920 _LDAP_MAP_CODE(LDAP_BUSY
),
921 _LDAP_MAP_CODE(LDAP_UNAVAILABLE
),
922 _LDAP_MAP_CODE(LDAP_UNWILLING_TO_PERFORM
),
923 _LDAP_MAP_CODE(LDAP_LOOP_DETECT
),
924 _LDAP_MAP_CODE(LDAP_NAMING_VIOLATION
),
925 _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_VIOLATION
),
926 _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF
),
927 _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_RDN
),
928 _LDAP_MAP_CODE(LDAP_ENTRY_ALREADY_EXISTS
),
929 _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED
),
930 _LDAP_MAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS
),
931 _LDAP_MAP_CODE(LDAP_OTHER
)
935 used to setup the status code from a ldap response
937 _PUBLIC_ NTSTATUS
ldap_check_response(struct ldap_connection
*conn
, struct ldap_Result
*r
)
940 const char *codename
= "unknown";
942 if (r
->resultcode
== LDAP_SUCCESS
) {
946 if (conn
->last_error
) {
947 talloc_free(conn
->last_error
);
950 for (i
=0;i
<ARRAY_SIZE(ldap_code_map
);i
++) {
951 if (r
->resultcode
== ldap_code_map
[i
].code
) {
952 codename
= ldap_code_map
[i
].str
;
957 conn
->last_error
= talloc_asprintf(conn
, "LDAP error %u %s - %s <%s> <%s>",
960 r
->dn
?r
->dn
:"(NULL)",
961 r
->errormessage
?r
->errormessage
:"",
962 r
->referral
?r
->referral
:"");
964 return NT_STATUS_LDAP(r
->resultcode
);
968 return error string representing the last error
970 _PUBLIC_
const char *ldap_errstr(struct ldap_connection
*conn
,
974 if (NT_STATUS_IS_LDAP(status
) && conn
->last_error
!= NULL
) {
975 return talloc_strdup(mem_ctx
, conn
->last_error
);
977 return talloc_asprintf(mem_ctx
, "LDAP client internal error: %s", nt_errstr(status
));
982 return the Nth result message, waiting if necessary
984 _PUBLIC_ NTSTATUS
ldap_result_n(struct ldap_request
*req
, int n
, struct ldap_message
**msg
)
988 NT_STATUS_HAVE_NO_MEMORY(req
);
990 while (req
->state
< LDAP_REQUEST_DONE
&& n
>= req
->num_replies
) {
991 if (tevent_loop_once(req
->conn
->event
.event_ctx
) != 0) {
992 return NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
996 if (n
< req
->num_replies
) {
997 *msg
= req
->replies
[n
];
1001 if (!NT_STATUS_IS_OK(req
->status
)) {
1005 return NT_STATUS_NO_MORE_ENTRIES
;
1010 return a single result message, checking if it is of the expected LDAP type
1012 _PUBLIC_ NTSTATUS
ldap_result_one(struct ldap_request
*req
, struct ldap_message
**msg
, int type
)
1015 status
= ldap_result_n(req
, 0, msg
);
1016 if (!NT_STATUS_IS_OK(status
)) {
1019 if ((*msg
)->type
!= type
) {
1021 return NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
1027 a simple ldap transaction, for single result requests that only need a status code
1028 this relies on single valued requests having the response type == request type + 1
1030 _PUBLIC_ NTSTATUS
ldap_transaction(struct ldap_connection
*conn
, struct ldap_message
*msg
)
1032 struct ldap_request
*req
= ldap_request_send(conn
, msg
);
1033 struct ldap_message
*res
;
1035 status
= ldap_result_n(req
, 0, &res
);
1036 if (!NT_STATUS_IS_OK(status
)) {
1040 if (res
->type
!= msg
->type
+ 1) {
1042 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
1044 status
= ldap_check_response(conn
, &res
->r
.GeneralResult
);