2 Unix SMB/CIFS implementation.
3 Infrastructure for async ldap client requests
4 Copyright (C) Volker Lendecke 2009
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/network.h"
23 #include "system/locale.h"
24 #include "lib/util/talloc_stack.h"
25 #include "lib/util/samba_util.h"
26 #include "lib/util_tsock.h"
27 #include "../lib/util/asn1.h"
28 #include "../lib/tsocket/tsocket.h"
29 #include "../lib/util/tevent_unix.h"
31 static TLDAPRC
tldap_simple_recv(struct tevent_req
*req
);
32 static bool tldap_msg_set_pending(struct tevent_req
*req
);
34 #define TEVENT_TLDAP_RC_MAGIC (0x87bcd26e)
36 bool tevent_req_ldap_error(struct tevent_req
*req
, TLDAPRC rc
)
40 if (TLDAP_RC_IS_SUCCESS(rc
)) {
44 err
= TEVENT_TLDAP_RC_MAGIC
;
46 err
|= TLDAP_RC_V(rc
);
48 return tevent_req_error(req
, err
);
51 bool tevent_req_is_ldap_error(struct tevent_req
*req
, TLDAPRC
*perr
)
53 enum tevent_req_state state
;
56 if (!tevent_req_is_error(req
, &state
, &err
)) {
60 case TEVENT_REQ_TIMED_OUT
:
61 *perr
= TLDAP_TIMEOUT
;
63 case TEVENT_REQ_NO_MEMORY
:
64 *perr
= TLDAP_NO_MEMORY
;
66 case TEVENT_REQ_USER_ERROR
:
67 if ((err
>> 32) != TEVENT_TLDAP_RC_MAGIC
) {
70 *perr
= TLDAP_RC(err
& 0xffffffff);
73 *perr
= TLDAP_OPERATIONS_ERROR
;
79 struct tldap_ctx_attribute
{
84 struct tldap_context
{
86 struct tstream_context
*conn
;
88 struct tevent_queue
*outgoing
;
89 struct tevent_req
**pending
;
90 struct tevent_req
*read_req
;
92 /* For the sync wrappers we need something like get_last_error... */
93 struct tldap_message
*last_msg
;
96 void (*log_fn
)(void *context
, enum tldap_debug_level level
,
97 const char *fmt
, va_list ap
);
100 struct tldap_ctx_attribute
*ctx_attrs
;
103 struct tldap_message
{
104 struct asn1_data
*data
;
111 struct tldap_attribute
*attribs
;
113 /* Error data sent by the server */
116 char *res_diagnosticmessage
;
118 DATA_BLOB res_serverSaslCreds
;
119 struct tldap_control
*res_sctrls
;
121 /* Controls sent by the server */
122 struct tldap_control
*ctrls
;
125 void tldap_set_debug(struct tldap_context
*ld
,
126 void (*log_fn
)(void *log_private
,
127 enum tldap_debug_level level
,
129 va_list ap
) PRINTF_ATTRIBUTE(3,0),
133 ld
->log_private
= log_private
;
136 static void tldap_debug(
137 struct tldap_context
*ld
,
138 enum tldap_debug_level level
,
139 const char *fmt
, ...) PRINTF_ATTRIBUTE(3,4);
141 static void tldap_debug(struct tldap_context
*ld
,
142 enum tldap_debug_level level
,
143 const char *fmt
, ...)
149 if (ld
->log_fn
== NULL
) {
153 ld
->log_fn(ld
->log_private
, level
, fmt
, ap
);
157 static int tldap_next_msgid(struct tldap_context
*ld
)
161 result
= ld
->msgid
++;
162 if (ld
->msgid
== 2147483647) {
168 struct tldap_context
*tldap_context_create(TALLOC_CTX
*mem_ctx
, int fd
)
170 struct tldap_context
*ctx
;
173 ctx
= talloc_zero(mem_ctx
, struct tldap_context
);
177 ret
= tstream_bsd_existing_socket(ctx
, fd
, &ctx
->conn
);
184 ctx
->outgoing
= tevent_queue_create(ctx
, "tldap_outgoing");
185 if (ctx
->outgoing
== NULL
) {
192 bool tldap_connection_ok(struct tldap_context
*ld
)
200 if (ld
->conn
== NULL
) {
204 ret
= tstream_pending_bytes(ld
->conn
);
212 static size_t tldap_pending_reqs(struct tldap_context
*ld
)
214 return talloc_array_length(ld
->pending
);
217 struct tstream_context
*tldap_get_tstream(struct tldap_context
*ld
)
222 void tldap_set_tstream(struct tldap_context
*ld
,
223 struct tstream_context
*stream
)
228 static struct tldap_ctx_attribute
*tldap_context_findattr(
229 struct tldap_context
*ld
, const char *name
)
233 num_attrs
= talloc_array_length(ld
->ctx_attrs
);
235 for (i
=0; i
<num_attrs
; i
++) {
236 if (strcmp(ld
->ctx_attrs
[i
].name
, name
) == 0) {
237 return &ld
->ctx_attrs
[i
];
243 bool tldap_context_setattr(struct tldap_context
*ld
,
244 const char *name
, const void *_pptr
)
246 struct tldap_ctx_attribute
*tmp
, *attr
;
249 void **pptr
= (void **)discard_const_p(void,_pptr
);
251 attr
= tldap_context_findattr(ld
, name
);
254 * We don't actually delete attrs, we don't expect tons of
255 * attributes being shuffled around.
257 TALLOC_FREE(attr
->ptr
);
259 attr
->ptr
= talloc_move(ld
->ctx_attrs
, pptr
);
265 tmpname
= talloc_strdup(ld
, name
);
266 if (tmpname
== NULL
) {
270 num_attrs
= talloc_array_length(ld
->ctx_attrs
);
272 tmp
= talloc_realloc(ld
, ld
->ctx_attrs
, struct tldap_ctx_attribute
,
275 TALLOC_FREE(tmpname
);
278 tmp
[num_attrs
].name
= talloc_move(tmp
, &tmpname
);
280 tmp
[num_attrs
].ptr
= talloc_move(tmp
, pptr
);
282 tmp
[num_attrs
].ptr
= NULL
;
289 void *tldap_context_getattr(struct tldap_context
*ld
, const char *name
)
291 struct tldap_ctx_attribute
*attr
= tldap_context_findattr(ld
, name
);
299 struct read_ldap_state
{
304 static ssize_t
read_ldap_more(uint8_t *buf
, size_t buflen
, void *private_data
);
305 static void read_ldap_done(struct tevent_req
*subreq
);
307 static struct tevent_req
*read_ldap_send(TALLOC_CTX
*mem_ctx
,
308 struct tevent_context
*ev
,
309 struct tstream_context
*conn
)
311 struct tevent_req
*req
, *subreq
;
312 struct read_ldap_state
*state
;
314 req
= tevent_req_create(mem_ctx
, &state
, struct read_ldap_state
);
320 subreq
= tstream_read_packet_send(state
, ev
, conn
, 2, read_ldap_more
,
322 if (tevent_req_nomem(subreq
, req
)) {
323 return tevent_req_post(req
, ev
);
325 tevent_req_set_callback(subreq
, read_ldap_done
, req
);
329 static ssize_t
read_ldap_more(uint8_t *buf
, size_t buflen
, void *private_data
)
331 struct read_ldap_state
*state
= talloc_get_type_abort(
332 private_data
, struct read_ldap_state
);
337 /* We've been here, we're done */
342 * From ldap.h: LDAP_TAG_MESSAGE is 0x30
344 if (buf
[0] != 0x30) {
349 if ((len
& 0x80) == 0) {
354 lensize
= (len
& 0x7f);
358 /* Please get us the full length */
361 if (buflen
> 2 + lensize
) {
365 if (buflen
!= 2 + lensize
) {
369 for (i
=0; i
<lensize
; i
++) {
370 len
= (len
<< 8) | buf
[2+i
];
375 static void read_ldap_done(struct tevent_req
*subreq
)
377 struct tevent_req
*req
= tevent_req_callback_data(
378 subreq
, struct tevent_req
);
379 struct read_ldap_state
*state
= tevent_req_data(
380 req
, struct read_ldap_state
);
384 nread
= tstream_read_packet_recv(subreq
, state
, &state
->buf
, &err
);
387 tevent_req_error(req
, err
);
390 tevent_req_done(req
);
393 static ssize_t
read_ldap_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
394 uint8_t **pbuf
, int *perrno
)
396 struct read_ldap_state
*state
= tevent_req_data(
397 req
, struct read_ldap_state
);
399 if (tevent_req_is_unix_error(req
, perrno
)) {
402 *pbuf
= talloc_move(mem_ctx
, &state
->buf
);
403 return talloc_get_size(*pbuf
);
406 struct tldap_msg_state
{
407 struct tldap_context
*ld
;
408 struct tevent_context
*ev
;
412 struct asn1_data
*data
;
416 static bool tldap_push_controls(struct asn1_data
*data
,
417 struct tldap_control
*sctrls
,
422 if ((sctrls
== NULL
) || (num_sctrls
== 0)) {
426 if (!asn1_push_tag(data
, ASN1_CONTEXT(0))) return false;
428 for (i
=0; i
<num_sctrls
; i
++) {
429 struct tldap_control
*c
= &sctrls
[i
];
430 if (!asn1_push_tag(data
, ASN1_SEQUENCE(0))) return false;
431 if (!asn1_write_OctetString(data
, c
->oid
, strlen(c
->oid
))) return false;
433 if (!asn1_write_BOOLEAN(data
, true)) return false;
435 if (c
->value
.data
!= NULL
) {
436 if (!asn1_write_OctetString(data
, c
->value
.data
,
437 c
->value
.length
)) return false;
439 if (!asn1_pop_tag(data
)) return false; /* ASN1_SEQUENCE(0) */
442 return asn1_pop_tag(data
); /* ASN1_CONTEXT(0) */
445 #define tldap_context_disconnect(ld, status) \
446 _tldap_context_disconnect(ld, status, __location__)
448 static void _tldap_context_disconnect(struct tldap_context
*ld
,
450 const char *location
)
452 if (ld
->conn
== NULL
) {
454 * We don't need to tldap_debug() on
455 * a potential 2nd run.
457 * The rest of the function would just
458 * be a noop for the 2nd run anyway.
463 tldap_debug(ld
, TLDAP_DEBUG_WARNING
,
464 "tldap_context_disconnect: %s at %s\n",
465 tldap_rc2string(status
),
467 tevent_queue_stop(ld
->outgoing
);
468 TALLOC_FREE(ld
->read_req
);
469 TALLOC_FREE(ld
->conn
);
471 while (talloc_array_length(ld
->pending
) > 0) {
472 struct tevent_req
*req
= NULL
;
473 struct tldap_msg_state
*state
= NULL
;
475 req
= ld
->pending
[0];
476 state
= tevent_req_data(req
, struct tldap_msg_state
);
477 tevent_req_defer_callback(req
, state
->ev
);
478 tevent_req_ldap_error(req
, status
);
482 static void tldap_msg_sent(struct tevent_req
*subreq
);
483 static void tldap_msg_received(struct tevent_req
*subreq
);
485 static struct tevent_req
*tldap_msg_send(TALLOC_CTX
*mem_ctx
,
486 struct tevent_context
*ev
,
487 struct tldap_context
*ld
,
488 int id
, struct asn1_data
*data
,
489 struct tldap_control
*sctrls
,
492 struct tevent_req
*req
, *subreq
;
493 struct tldap_msg_state
*state
;
497 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "tldap_msg_send: sending msg %d\n",
500 req
= tevent_req_create(mem_ctx
, &state
, struct tldap_msg_state
);
508 ok
= tldap_connection_ok(ld
);
510 tevent_req_ldap_error(req
, TLDAP_SERVER_DOWN
);
511 return tevent_req_post(req
, ev
);
514 if (!tldap_push_controls(data
, sctrls
, num_sctrls
)) {
515 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
516 return tevent_req_post(req
, ev
);
520 if (!asn1_pop_tag(data
)) {
521 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
522 return tevent_req_post(req
, ev
);
525 if (!asn1_blob(data
, &blob
)) {
526 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
527 return tevent_req_post(req
, ev
);
530 if (!tldap_msg_set_pending(req
)) {
532 return tevent_req_post(req
, ev
);;
535 state
->iov
.iov_base
= (void *)blob
.data
;
536 state
->iov
.iov_len
= blob
.length
;
538 subreq
= tstream_writev_queue_send(state
, ev
, ld
->conn
, ld
->outgoing
,
540 if (tevent_req_nomem(subreq
, req
)) {
541 return tevent_req_post(req
, ev
);
543 tevent_req_set_callback(subreq
, tldap_msg_sent
, req
);
547 static void tldap_msg_unset_pending(struct tevent_req
*req
)
549 struct tldap_msg_state
*state
= tevent_req_data(
550 req
, struct tldap_msg_state
);
551 struct tldap_context
*ld
= state
->ld
;
552 int num_pending
= tldap_pending_reqs(ld
);
555 tevent_req_set_cleanup_fn(req
, NULL
);
557 for (i
=0; i
<num_pending
; i
++) {
558 if (req
== ld
->pending
[i
]) {
562 if (i
== num_pending
) {
564 * Something's seriously broken. Just returning here is the
565 * right thing nevertheless, the point of this routine is to
566 * remove ourselves from cli->pending.
571 if (num_pending
== 1) {
572 TALLOC_FREE(ld
->pending
);
577 * Remove ourselves from the cli->pending array
579 if (num_pending
> 1) {
580 ld
->pending
[i
] = ld
->pending
[num_pending
-1];
584 * No NULL check here, we're shrinking by sizeof(void *), and
585 * talloc_realloc just adjusts the size for this.
587 ld
->pending
= talloc_realloc(NULL
, ld
->pending
, struct tevent_req
*,
591 static void tldap_msg_cleanup(struct tevent_req
*req
,
592 enum tevent_req_state req_state
)
594 tldap_msg_unset_pending(req
);
597 static bool tldap_msg_set_pending(struct tevent_req
*req
)
599 struct tldap_msg_state
*state
= tevent_req_data(
600 req
, struct tldap_msg_state
);
601 struct tldap_context
*ld
;
602 struct tevent_req
**pending
;
606 num_pending
= tldap_pending_reqs(ld
);
608 pending
= talloc_realloc(ld
, ld
->pending
, struct tevent_req
*,
610 if (pending
== NULL
) {
613 pending
[num_pending
] = req
;
614 ld
->pending
= pending
;
615 tevent_req_set_cleanup_fn(req
, tldap_msg_cleanup
);
617 if (ld
->read_req
!= NULL
) {
622 * We're the first one, add the read_ldap request that waits for the
623 * answer from the server
625 ld
->read_req
= read_ldap_send(ld
->pending
, state
->ev
, ld
->conn
);
626 if (ld
->read_req
== NULL
) {
627 tldap_msg_unset_pending(req
);
630 tevent_req_set_callback(ld
->read_req
, tldap_msg_received
, ld
);
634 static void tldap_msg_sent(struct tevent_req
*subreq
)
636 struct tevent_req
*req
= tevent_req_callback_data(
637 subreq
, struct tevent_req
);
638 struct tldap_msg_state
*state
= tevent_req_data(
639 req
, struct tldap_msg_state
);
643 nwritten
= tstream_writev_queue_recv(subreq
, &err
);
645 if (nwritten
== -1) {
646 tldap_context_disconnect(state
->ld
, TLDAP_SERVER_DOWN
);
651 static int tldap_msg_msgid(struct tevent_req
*req
)
653 struct tldap_msg_state
*state
= tevent_req_data(
654 req
, struct tldap_msg_state
);
659 static void tldap_msg_received(struct tevent_req
*subreq
)
661 struct tldap_context
*ld
= tevent_req_callback_data(
662 subreq
, struct tldap_context
);
663 struct tevent_req
*req
;
664 struct tldap_msg_state
*state
;
665 struct asn1_data
*data
;
670 TLDAPRC status
= TLDAP_PROTOCOL_ERROR
;
675 received
= read_ldap_recv(subreq
, talloc_tos(), &inbuf
, &err
);
678 if (received
== -1) {
679 status
= TLDAP_SERVER_DOWN
;
683 data
= asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH
);
686 * We have to disconnect all, we can't tell which of
687 * the requests this reply is for.
689 status
= TLDAP_NO_MEMORY
;
692 asn1_load_nocopy(data
, inbuf
, received
);
695 ok
&= asn1_start_tag(data
, ASN1_SEQUENCE(0));
696 ok
&= asn1_read_Integer(data
, &id
);
697 ok
&= asn1_peek_uint8(data
, &type
);
700 status
= TLDAP_PROTOCOL_ERROR
;
704 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "tldap_msg_received: got msg %d "
705 "type %d\n", id
, (int)type
);
711 "tldap_msg_received: got msgid 0 of "
712 "type %"PRIu8
", disconnecting\n",
714 tldap_context_disconnect(ld
, TLDAP_SERVER_DOWN
);
718 num_pending
= talloc_array_length(ld
->pending
);
720 for (i
=0; i
<num_pending
; i
++) {
721 if (id
== tldap_msg_msgid(ld
->pending
[i
])) {
725 if (i
== num_pending
) {
726 /* Dump unexpected reply */
727 tldap_debug(ld
, TLDAP_DEBUG_WARNING
, "tldap_msg_received: "
728 "No request pending for msg %d\n", id
);
734 req
= ld
->pending
[i
];
735 state
= tevent_req_data(req
, struct tldap_msg_state
);
737 state
->inbuf
= talloc_move(state
, &inbuf
);
738 state
->data
= talloc_move(state
, &data
);
740 tldap_msg_unset_pending(req
);
741 num_pending
= talloc_array_length(ld
->pending
);
743 tevent_req_defer_callback(req
, state
->ev
);
744 tevent_req_done(req
);
747 if (num_pending
== 0) {
751 state
= tevent_req_data(ld
->pending
[0], struct tldap_msg_state
);
752 ld
->read_req
= read_ldap_send(ld
->pending
, state
->ev
, ld
->conn
);
753 if (ld
->read_req
== NULL
) {
754 status
= TLDAP_NO_MEMORY
;
757 tevent_req_set_callback(ld
->read_req
, tldap_msg_received
, ld
);
761 tldap_context_disconnect(ld
, status
);
764 static TLDAPRC
tldap_msg_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
765 struct tldap_message
**pmsg
)
767 struct tldap_msg_state
*state
= tevent_req_data(
768 req
, struct tldap_msg_state
);
769 struct tldap_message
*msg
;
773 if (tevent_req_is_ldap_error(req
, &err
)) {
777 if (!asn1_peek_uint8(state
->data
, &msgtype
)) {
778 return TLDAP_PROTOCOL_ERROR
;
782 return TLDAP_SUCCESS
;
785 msg
= talloc_zero(mem_ctx
, struct tldap_message
);
787 return TLDAP_NO_MEMORY
;
791 msg
->inbuf
= talloc_move(msg
, &state
->inbuf
);
792 msg
->data
= talloc_move(msg
, &state
->data
);
796 return TLDAP_SUCCESS
;
799 struct tldap_req_state
{
801 struct asn1_data
*out
;
802 struct tldap_message
*result
;
805 static struct tevent_req
*tldap_req_create(TALLOC_CTX
*mem_ctx
,
806 struct tldap_context
*ld
,
807 struct tldap_req_state
**pstate
)
809 struct tevent_req
*req
;
810 struct tldap_req_state
*state
;
812 req
= tevent_req_create(mem_ctx
, &state
, struct tldap_req_state
);
816 state
->out
= asn1_init(state
, ASN1_MAX_TREE_DEPTH
);
817 if (state
->out
== NULL
) {
820 state
->id
= tldap_next_msgid(ld
);
822 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
823 if (!asn1_write_Integer(state
->out
, state
->id
)) goto err
;
834 static void tldap_save_msg(struct tldap_context
*ld
, struct tevent_req
*req
)
836 struct tldap_req_state
*state
= tevent_req_data(
837 req
, struct tldap_req_state
);
839 TALLOC_FREE(ld
->last_msg
);
840 ld
->last_msg
= talloc_move(ld
, &state
->result
);
843 static char *blob2string_talloc(TALLOC_CTX
*mem_ctx
, DATA_BLOB blob
)
845 char *result
= talloc_array(mem_ctx
, char, blob
.length
+1);
847 if (result
== NULL
) {
851 memcpy(result
, blob
.data
, blob
.length
);
852 result
[blob
.length
] = '\0';
856 static bool asn1_read_OctetString_talloc(TALLOC_CTX
*mem_ctx
,
857 struct asn1_data
*data
,
862 if (!asn1_read_OctetString(data
, mem_ctx
, &string
))
865 result
= blob2string_talloc(mem_ctx
, string
);
867 data_blob_free(&string
);
869 if (result
== NULL
) {
876 static bool tldap_decode_controls(struct tldap_req_state
*state
);
878 static bool tldap_decode_response(struct tldap_req_state
*state
)
880 struct asn1_data
*data
= state
->result
->data
;
881 struct tldap_message
*msg
= state
->result
;
885 ok
&= asn1_read_enumerated(data
, &rc
);
887 msg
->lderr
= TLDAP_RC(rc
);
890 ok
&= asn1_read_OctetString_talloc(msg
, data
, &msg
->res_matcheddn
);
891 ok
&= asn1_read_OctetString_talloc(msg
, data
,
892 &msg
->res_diagnosticmessage
);
894 if (asn1_peek_tag(data
, ASN1_CONTEXT(3))) {
895 ok
&= asn1_start_tag(data
, ASN1_CONTEXT(3));
896 ok
&= asn1_read_OctetString_talloc(msg
, data
,
898 ok
&= asn1_end_tag(data
);
900 msg
->res_referral
= NULL
;
906 static void tldap_sasl_bind_done(struct tevent_req
*subreq
);
908 struct tevent_req
*tldap_sasl_bind_send(TALLOC_CTX
*mem_ctx
,
909 struct tevent_context
*ev
,
910 struct tldap_context
*ld
,
912 const char *mechanism
,
914 struct tldap_control
*sctrls
,
916 struct tldap_control
*cctrls
,
919 struct tevent_req
*req
, *subreq
;
920 struct tldap_req_state
*state
;
922 req
= tldap_req_create(mem_ctx
, ld
, &state
);
931 if (!asn1_push_tag(state
->out
, TLDAP_REQ_BIND
)) goto err
;
932 if (!asn1_write_Integer(state
->out
, ld
->ld_version
)) goto err
;
933 if (!asn1_write_OctetString(state
->out
, dn
, strlen(dn
))) goto err
;
935 if (mechanism
== NULL
) {
936 if (!asn1_push_tag(state
->out
, ASN1_CONTEXT_SIMPLE(0))) goto err
;
937 if (!asn1_write(state
->out
, creds
->data
, creds
->length
)) goto err
;
938 if (!asn1_pop_tag(state
->out
)) goto err
;
940 if (!asn1_push_tag(state
->out
, ASN1_CONTEXT(3))) goto err
;
941 if (!asn1_write_OctetString(state
->out
, mechanism
,
942 strlen(mechanism
))) goto err
;
943 if ((creds
!= NULL
) && (creds
->data
!= NULL
)) {
944 if (!asn1_write_OctetString(state
->out
, creds
->data
,
945 creds
->length
)) goto err
;
947 if (!asn1_pop_tag(state
->out
)) goto err
;
950 if (!asn1_pop_tag(state
->out
)) goto err
;
952 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
954 if (tevent_req_nomem(subreq
, req
)) {
955 return tevent_req_post(req
, ev
);
957 tevent_req_set_callback(subreq
, tldap_sasl_bind_done
, req
);
962 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
963 return tevent_req_post(req
, ev
);
966 static void tldap_sasl_bind_done(struct tevent_req
*subreq
)
968 struct tevent_req
*req
= tevent_req_callback_data(
969 subreq
, struct tevent_req
);
970 struct tldap_req_state
*state
= tevent_req_data(
971 req
, struct tldap_req_state
);
975 rc
= tldap_msg_recv(subreq
, state
, &state
->result
);
977 if (tevent_req_ldap_error(req
, rc
)) {
980 if (state
->result
->type
!= TLDAP_RES_BIND
) {
981 tevent_req_ldap_error(req
, TLDAP_PROTOCOL_ERROR
);
985 ok
= asn1_start_tag(state
->result
->data
, TLDAP_RES_BIND
);
986 ok
&= tldap_decode_response(state
);
988 if (asn1_peek_tag(state
->result
->data
, ASN1_CONTEXT_SIMPLE(7))) {
991 ok
&= asn1_start_tag(state
->result
->data
,
992 ASN1_CONTEXT_SIMPLE(7));
997 len
= asn1_tag_remaining(state
->result
->data
);
1002 state
->result
->res_serverSaslCreds
=
1003 data_blob_talloc(state
->result
, NULL
, len
);
1004 if (state
->result
->res_serverSaslCreds
.data
== NULL
) {
1008 ok
= asn1_read(state
->result
->data
,
1009 state
->result
->res_serverSaslCreds
.data
,
1010 state
->result
->res_serverSaslCreds
.length
);
1012 ok
&= asn1_end_tag(state
->result
->data
);
1015 ok
&= asn1_end_tag(state
->result
->data
);
1021 if (!TLDAP_RC_IS_SUCCESS(state
->result
->lderr
) &&
1022 !TLDAP_RC_EQUAL(state
->result
->lderr
,
1023 TLDAP_SASL_BIND_IN_PROGRESS
)) {
1024 tevent_req_ldap_error(req
, state
->result
->lderr
);
1027 tevent_req_done(req
);
1031 tevent_req_ldap_error(req
, TLDAP_DECODING_ERROR
);
1035 TLDAPRC
tldap_sasl_bind_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
1036 DATA_BLOB
*serverSaslCreds
)
1038 struct tldap_req_state
*state
= tevent_req_data(
1039 req
, struct tldap_req_state
);
1042 if (tevent_req_is_ldap_error(req
, &rc
)) {
1046 if (serverSaslCreds
!= NULL
) {
1047 serverSaslCreds
->data
= talloc_move(
1048 mem_ctx
, &state
->result
->res_serverSaslCreds
.data
);
1049 serverSaslCreds
->length
=
1050 state
->result
->res_serverSaslCreds
.length
;
1053 return state
->result
->lderr
;
1056 TLDAPRC
tldap_sasl_bind(struct tldap_context
*ld
,
1058 const char *mechanism
,
1060 struct tldap_control
*sctrls
,
1062 struct tldap_control
*cctrls
,
1064 TALLOC_CTX
*mem_ctx
,
1065 DATA_BLOB
*serverSaslCreds
)
1067 TALLOC_CTX
*frame
= talloc_stackframe();
1068 struct tevent_context
*ev
;
1069 struct tevent_req
*req
;
1070 TLDAPRC rc
= TLDAP_NO_MEMORY
;
1072 ev
= samba_tevent_context_init(frame
);
1076 req
= tldap_sasl_bind_send(frame
, ev
, ld
, dn
, mechanism
, creds
,
1077 sctrls
, num_sctrls
, cctrls
, num_cctrls
);
1081 if (!tevent_req_poll(req
, ev
)) {
1082 rc
= TLDAP_OPERATIONS_ERROR
;
1085 rc
= tldap_sasl_bind_recv(req
, mem_ctx
, serverSaslCreds
);
1086 tldap_save_msg(ld
, req
);
1092 struct tevent_req
*tldap_simple_bind_send(TALLOC_CTX
*mem_ctx
,
1093 struct tevent_context
*ev
,
1094 struct tldap_context
*ld
,
1100 if (passwd
!= NULL
) {
1101 cred
.data
= discard_const_p(uint8_t, passwd
);
1102 cred
.length
= strlen(passwd
);
1104 cred
.data
= discard_const_p(uint8_t, "");
1107 return tldap_sasl_bind_send(mem_ctx
, ev
, ld
, dn
, NULL
, &cred
, NULL
, 0,
1111 TLDAPRC
tldap_simple_bind_recv(struct tevent_req
*req
)
1113 return tldap_sasl_bind_recv(req
, NULL
, NULL
);
1116 TLDAPRC
tldap_simple_bind(struct tldap_context
*ld
, const char *dn
,
1121 if (passwd
!= NULL
) {
1122 cred
.data
= discard_const_p(uint8_t, passwd
);
1123 cred
.length
= strlen(passwd
);
1125 cred
.data
= discard_const_p(uint8_t, "");
1128 return tldap_sasl_bind(ld
, dn
, NULL
, &cred
, NULL
, 0, NULL
, 0,
1132 /*****************************************************************************/
1134 /* can't use isalpha() as only a strict set is valid for LDAP */
1136 static bool tldap_is_alpha(char c
)
1138 return (((c
>= 'a') && (c
<= 'z')) || \
1139 ((c
>= 'A') && (c
<= 'Z')));
1142 static bool tldap_is_adh(char c
)
1144 return tldap_is_alpha(c
) || isdigit(c
) || (c
== '-');
1147 #define TLDAP_FILTER_AND ASN1_CONTEXT(0)
1148 #define TLDAP_FILTER_OR ASN1_CONTEXT(1)
1149 #define TLDAP_FILTER_NOT ASN1_CONTEXT(2)
1150 #define TLDAP_FILTER_EQ ASN1_CONTEXT(3)
1151 #define TLDAP_FILTER_SUB ASN1_CONTEXT(4)
1152 #define TLDAP_FILTER_LE ASN1_CONTEXT(5)
1153 #define TLDAP_FILTER_GE ASN1_CONTEXT(6)
1154 #define TLDAP_FILTER_PRES ASN1_CONTEXT_SIMPLE(7)
1155 #define TLDAP_FILTER_APX ASN1_CONTEXT(8)
1156 #define TLDAP_FILTER_EXT ASN1_CONTEXT(9)
1158 #define TLDAP_SUB_INI ASN1_CONTEXT_SIMPLE(0)
1159 #define TLDAP_SUB_ANY ASN1_CONTEXT_SIMPLE(1)
1160 #define TLDAP_SUB_FIN ASN1_CONTEXT_SIMPLE(2)
1163 /* oid's should be numerical only in theory,
1164 * but apparently some broken servers may have alphanum aliases instead.
1165 * Do like openldap libraries and allow alphanum aliases for oids, but
1166 * do not allow Tagging options in that case.
1168 static bool tldap_is_attrdesc(const char *s
, int len
, bool no_tagopts
)
1170 bool is_oid
= false;
1174 /* first char has stricter rules */
1177 } else if (!tldap_is_alpha(*s
)) {
1178 /* bad first char */
1182 for (i
= 1; i
< len
; i
++) {
1185 if (isdigit(s
[i
])) {
1198 if (tldap_is_adh(s
[i
])) {
1205 /* no tagging options */
1212 if ((i
+ 1) == len
) {
1230 /* this function copies the value until the closing parenthesis is found. */
1231 static char *tldap_get_val(TALLOC_CTX
*memctx
,
1232 const char *value
, const char **_s
)
1234 const char *s
= value
;
1236 /* find terminator */
1239 if (s
&& (*(s
- 1) == '\\')) {
1244 if (!s
|| !(*s
== ')')) {
1245 /* malformed filter */
1251 return talloc_strndup(memctx
, value
, s
- value
);
1254 static int tldap_hex2char(const char *x
)
1256 if (isxdigit(x
[0]) && isxdigit(x
[1])) {
1257 const char h1
= x
[0], h2
= x
[1];
1260 if (h1
>= 'a') c
= h1
- (int)'a' + 10;
1261 else if (h1
>= 'A') c
= h1
- (int)'A' + 10;
1262 else if (h1
>= '0') c
= h1
- (int)'0';
1264 if (h2
>= 'a') c
+= h2
- (int)'a' + 10;
1265 else if (h2
>= 'A') c
+= h2
- (int)'A' + 10;
1266 else if (h2
>= '0') c
+= h2
- (int)'0';
1274 static bool tldap_find_first_star(const char *val
, const char **star
)
1278 for (s
= val
; *s
; s
++) {
1281 if (isxdigit(s
[1]) && isxdigit(s
[2])) {
1285 /* not hex based escape, check older syntax */
1294 /* invalid escape sequence */
1299 /* end of val, nothing found */
1309 /* string ended without closing parenthesis, filter is malformed */
1313 static bool tldap_unescape_inplace(char *value
, size_t *val_len
)
1318 for (i
= 0,p
= 0; i
< *val_len
; i
++) {
1324 /* these must be escaped */
1328 if (!value
[i
+ 1]) {
1334 /* LDAPv3 escaped */
1335 c
= tldap_hex2char(&value
[i
]);
1336 if (c
>= 0 && c
< 256) {
1343 /* LDAPv2 escaped */
1349 value
[p
] = value
[i
];
1360 value
[p
] = value
[i
];
1369 static bool tldap_push_filter_basic(struct tldap_context
*ld
,
1370 struct asn1_data
*data
,
1372 static bool tldap_push_filter_substring(struct tldap_context
*ld
,
1373 struct asn1_data
*data
,
1376 static bool tldap_push_filter_int(struct tldap_context
*ld
,
1377 struct asn1_data
*data
,
1380 const char *s
= *_s
;
1384 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1385 "Incomplete or malformed filter\n");
1390 /* we are right after a parenthesis,
1391 * find out what op we have at hand */
1394 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "Filter op: AND\n");
1395 if (!asn1_push_tag(data
, TLDAP_FILTER_AND
)) return false;
1400 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "Filter op: OR\n");
1401 if (!asn1_push_tag(data
, TLDAP_FILTER_OR
)) return false;
1406 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "Filter op: NOT\n");
1407 if (!asn1_push_tag(data
, TLDAP_FILTER_NOT
)) return false;
1409 ret
= tldap_push_filter_int(ld
, data
, &s
);
1413 if (!asn1_pop_tag(data
)) return false;
1418 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1419 "Invalid parenthesis '%c'\n", *s
);
1423 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1424 "Invalid filter termination\n");
1428 ret
= tldap_push_filter_basic(ld
, data
, &s
);
1435 /* only and/or filters get here.
1436 * go through the list of filters */
1439 /* RFC 4526: empty and/or */
1440 if (!asn1_pop_tag(data
)) return false;
1445 ret
= tldap_push_filter_int(ld
, data
, &s
);
1451 /* end of list, return */
1452 if (!asn1_pop_tag(data
)) return false;
1459 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1460 "Incomplete or malformed filter\n");
1465 if (asn1_has_error(data
)) {
1474 static bool tldap_push_filter_basic(struct tldap_context
*ld
,
1475 struct asn1_data
*data
,
1478 TALLOC_CTX
*tmpctx
= talloc_tos();
1479 const char *s
= *_s
;
1487 size_t type_len
= 0;
1490 bool write_octect
= true;
1493 eq
= strchr(s
, '=');
1495 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1496 "Invalid filter, missing equal sign\n");
1505 if (!asn1_push_tag(data
, TLDAP_FILTER_LE
)) return false;
1509 if (!asn1_push_tag(data
, TLDAP_FILTER_GE
)) return false;
1513 if (!asn1_push_tag(data
, TLDAP_FILTER_APX
)) return false;
1517 if (!asn1_push_tag(data
, TLDAP_FILTER_EXT
)) return false;
1518 write_octect
= false;
1524 if (*s
== ':') { /* [:dn]:rule:= value */
1526 /* malformed filter */
1530 } else { /* type[:dn][:rule]:= value */
1532 dn
= strchr(s
, ':');
1533 type_len
= dn
- type
;
1534 if (dn
== e
) { /* type:= value */
1541 rule
= strchr(dn
, ':');
1545 if ((rule
== dn
+ 1) || rule
+ 1 == e
) {
1546 /* malformed filter, contains "::" */
1550 if (strncasecmp_m(dn
, "dn:", 3) != 0) {
1555 /* malformed filter. With two
1556 * optionals, the first must be "dn"
1569 if (!type
&& !dn
&& !rule
) {
1570 /* malformed filter, there must be at least one */
1575 MatchingRuleAssertion ::= SEQUENCE {
1576 matchingRule [1] MatchingRuleID OPTIONAL,
1577 type [2] AttributeDescription OPTIONAL,
1578 matchValue [3] AssertionValue,
1579 dnAttributes [4] BOOLEAN DEFAULT FALSE
1583 /* check and add rule */
1585 ret
= tldap_is_attrdesc(rule
, e
- rule
, true);
1589 if (!asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(1))) return false;
1590 if (!asn1_write(data
, rule
, e
- rule
)) return false;
1591 if (!asn1_pop_tag(data
)) return false;
1594 /* check and add type */
1596 ret
= tldap_is_attrdesc(type
, type_len
, false);
1600 if (!asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(2))) return false;
1601 if (!asn1_write(data
, type
, type_len
)) return false;
1602 if (!asn1_pop_tag(data
)) return false;
1605 uval
= tldap_get_val(tmpctx
, val
, _s
);
1609 uval_len
= *_s
- val
;
1610 ret
= tldap_unescape_inplace(uval
, &uval_len
);
1615 if (!asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(3))) return false;
1616 if (!asn1_write(data
, uval
, uval_len
)) return false;
1617 if (!asn1_pop_tag(data
)) return false;
1619 if (!asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(4))) return false;
1620 if (!asn1_write_uint8(data
, dn
?1:0)) return false;
1621 if (!asn1_pop_tag(data
)) return false;
1627 ret
= tldap_is_attrdesc(s
, e
- s
, false);
1632 if (strncmp(val
, "*)", 2) == 0) {
1634 if (!asn1_push_tag(data
, TLDAP_FILTER_PRES
)) return false;
1635 if (!asn1_write(data
, s
, e
- s
)) return false;
1637 write_octect
= false;
1641 ret
= tldap_find_first_star(val
, &star
);
1647 if (!asn1_push_tag(data
, TLDAP_FILTER_SUB
)) return false;
1648 if (!asn1_write_OctetString(data
, s
, e
- s
)) return false;
1649 ret
= tldap_push_filter_substring(ld
, data
, val
, &s
);
1654 write_octect
= false;
1658 /* if nothing else, then it is just equality */
1659 if (!asn1_push_tag(data
, TLDAP_FILTER_EQ
)) return false;
1660 write_octect
= true;
1665 uval
= tldap_get_val(tmpctx
, val
, _s
);
1669 uval_len
= *_s
- val
;
1670 ret
= tldap_unescape_inplace(uval
, &uval_len
);
1675 if (!asn1_write_OctetString(data
, s
, e
- s
)) return false;
1676 if (!asn1_write_OctetString(data
, uval
, uval_len
)) return false;
1679 if (asn1_has_error(data
)) {
1682 return asn1_pop_tag(data
);
1685 static bool tldap_push_filter_substring(struct tldap_context
*ld
,
1686 struct asn1_data
*data
,
1690 TALLOC_CTX
*tmpctx
= talloc_tos();
1691 bool initial
= true;
1698 SubstringFilter ::= SEQUENCE {
1699 type AttributeDescription,
1700 -- at least one must be present
1701 substrings SEQUENCE OF CHOICE {
1702 initial [0] LDAPString,
1704 final [2] LDAPString } }
1706 if (!asn1_push_tag(data
, ASN1_SEQUENCE(0))) return false;
1709 ret
= tldap_find_first_star(val
, &star
);
1713 chunk_len
= star
- val
;
1717 if (!initial
&& chunk_len
== 0) {
1718 /* found '**', which is illegal */
1734 if (initial
&& chunk_len
== 0) {
1740 chunk
= talloc_strndup(tmpctx
, val
, chunk_len
);
1744 ret
= tldap_unescape_inplace(chunk
, &chunk_len
);
1751 if (!asn1_push_tag(data
, TLDAP_SUB_INI
)) return false;
1754 if (!asn1_push_tag(data
, TLDAP_SUB_ANY
)) return false;
1758 if (!asn1_push_tag(data
, TLDAP_SUB_FIN
)) return false;
1764 if (!asn1_write(data
, chunk
, chunk_len
)) return false;
1765 if (!asn1_pop_tag(data
)) return false;
1769 } while (*star
== '*');
1773 /* end of sequence */
1774 return asn1_pop_tag(data
);
1777 /* NOTE: although openldap libraries allow for spaces in some places, mosly
1778 * around parenthesis, we do not allow any spaces (except in values of
1779 * course) as I couldn't fine any place in RFC 4512 or RFC 4515 where
1780 * leading or trailing spaces where allowed.
1782 static bool tldap_push_filter(struct tldap_context
*ld
,
1783 struct asn1_data
*data
,
1786 const char *s
= filter
;
1789 ret
= tldap_push_filter_int(ld
, data
, &s
);
1791 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1792 "Incomplete or malformed filter\n");
1798 /*****************************************************************************/
1800 static void tldap_search_done(struct tevent_req
*subreq
);
1802 struct tevent_req
*tldap_search_send(TALLOC_CTX
*mem_ctx
,
1803 struct tevent_context
*ev
,
1804 struct tldap_context
*ld
,
1805 const char *base
, int scope
,
1810 struct tldap_control
*sctrls
,
1812 struct tldap_control
*cctrls
,
1818 struct tevent_req
*req
, *subreq
;
1819 struct tldap_req_state
*state
;
1822 req
= tldap_req_create(mem_ctx
, ld
, &state
);
1827 if (!asn1_push_tag(state
->out
, TLDAP_REQ_SEARCH
)) goto encoding_error
;
1828 if (!asn1_write_OctetString(state
->out
, base
, strlen(base
))) goto encoding_error
;
1829 if (!asn1_write_enumerated(state
->out
, scope
)) goto encoding_error
;
1830 if (!asn1_write_enumerated(state
->out
, deref
)) goto encoding_error
;
1831 if (!asn1_write_Integer(state
->out
, sizelimit
)) goto encoding_error
;
1832 if (!asn1_write_Integer(state
->out
, timelimit
)) goto encoding_error
;
1833 if (!asn1_write_BOOLEAN(state
->out
, attrsonly
)) goto encoding_error
;
1835 if (!tldap_push_filter(ld
, state
->out
, filter
)) {
1836 goto encoding_error
;
1839 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto encoding_error
;
1840 for (i
=0; i
<num_attrs
; i
++) {
1841 if (!asn1_write_OctetString(state
->out
, attrs
[i
], strlen(attrs
[i
]))) goto encoding_error
;
1843 if (!asn1_pop_tag(state
->out
)) goto encoding_error
;
1844 if (!asn1_pop_tag(state
->out
)) goto encoding_error
;
1846 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
1847 sctrls
, num_sctrls
);
1848 if (tevent_req_nomem(subreq
, req
)) {
1849 return tevent_req_post(req
, ev
);
1851 tevent_req_set_callback(subreq
, tldap_search_done
, req
);
1855 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
1856 return tevent_req_post(req
, ev
);
1859 static void tldap_search_done(struct tevent_req
*subreq
)
1861 struct tevent_req
*req
= tevent_req_callback_data(
1862 subreq
, struct tevent_req
);
1863 struct tldap_req_state
*state
= tevent_req_data(
1864 req
, struct tldap_req_state
);
1867 rc
= tldap_msg_recv(subreq
, state
, &state
->result
);
1868 if (tevent_req_ldap_error(req
, rc
)) {
1871 switch (state
->result
->type
) {
1872 case TLDAP_RES_SEARCH_ENTRY
:
1873 case TLDAP_RES_SEARCH_REFERENCE
:
1874 if (!tldap_msg_set_pending(subreq
)) {
1875 tevent_req_oom(req
);
1878 tevent_req_notify_callback(req
);
1880 case TLDAP_RES_SEARCH_RESULT
:
1881 TALLOC_FREE(subreq
);
1882 if (!asn1_start_tag(state
->result
->data
,
1883 state
->result
->type
) ||
1884 !tldap_decode_response(state
) ||
1885 !asn1_end_tag(state
->result
->data
) ||
1886 !tldap_decode_controls(state
)) {
1887 tevent_req_ldap_error(req
, TLDAP_DECODING_ERROR
);
1890 tevent_req_done(req
);
1893 tevent_req_ldap_error(req
, TLDAP_PROTOCOL_ERROR
);
1898 TLDAPRC
tldap_search_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
1899 struct tldap_message
**pmsg
)
1901 struct tldap_req_state
*state
= tevent_req_data(
1902 req
, struct tldap_req_state
);
1905 if (!tevent_req_is_in_progress(req
)
1906 && tevent_req_is_ldap_error(req
, &rc
)) {
1910 if (tevent_req_is_in_progress(req
)) {
1911 switch (state
->result
->type
) {
1912 case TLDAP_RES_SEARCH_ENTRY
:
1913 case TLDAP_RES_SEARCH_REFERENCE
:
1916 return TLDAP_OPERATIONS_ERROR
;
1920 *pmsg
= talloc_move(mem_ctx
, &state
->result
);
1921 return TLDAP_SUCCESS
;
1924 struct tldap_search_all_state
{
1925 struct tldap_message
**msgs
;
1926 struct tldap_message
*result
;
1929 static void tldap_search_all_done(struct tevent_req
*subreq
);
1931 struct tevent_req
*tldap_search_all_send(
1932 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
1933 struct tldap_context
*ld
, const char *base
, int scope
,
1934 const char *filter
, const char **attrs
, int num_attrs
, int attrsonly
,
1935 struct tldap_control
*sctrls
, int num_sctrls
,
1936 struct tldap_control
*cctrls
, int num_cctrls
,
1937 int timelimit
, int sizelimit
, int deref
)
1939 struct tevent_req
*req
, *subreq
;
1940 struct tldap_search_all_state
*state
;
1942 req
= tevent_req_create(mem_ctx
, &state
,
1943 struct tldap_search_all_state
);
1948 subreq
= tldap_search_send(state
, ev
, ld
, base
, scope
, filter
,
1949 attrs
, num_attrs
, attrsonly
,
1950 sctrls
, num_sctrls
, cctrls
, num_cctrls
,
1951 timelimit
, sizelimit
, deref
);
1952 if (tevent_req_nomem(subreq
, req
)) {
1953 return tevent_req_post(req
, ev
);
1955 tevent_req_set_callback(subreq
, tldap_search_all_done
, req
);
1959 static void tldap_search_all_done(struct tevent_req
*subreq
)
1961 struct tevent_req
*req
= tevent_req_callback_data(
1962 subreq
, struct tevent_req
);
1963 struct tldap_search_all_state
*state
= tevent_req_data(
1964 req
, struct tldap_search_all_state
);
1965 struct tldap_message
*msg
, **tmp
;
1970 rc
= tldap_search_recv(subreq
, state
, &msg
);
1971 /* No TALLOC_FREE(subreq), this is multi-step */
1972 if (tevent_req_ldap_error(req
, rc
)) {
1976 msgtype
= tldap_msg_type(msg
);
1977 if (msgtype
== TLDAP_RES_SEARCH_RESULT
) {
1978 state
->result
= msg
;
1979 tevent_req_done(req
);
1983 num_msgs
= talloc_array_length(state
->msgs
);
1985 tmp
= talloc_realloc(state
, state
->msgs
, struct tldap_message
*,
1987 if (tevent_req_nomem(tmp
, req
)) {
1991 state
->msgs
[num_msgs
] = talloc_move(state
->msgs
, &msg
);
1994 TLDAPRC
tldap_search_all_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
1995 struct tldap_message
***msgs
,
1996 struct tldap_message
**result
)
1998 struct tldap_search_all_state
*state
= tevent_req_data(
1999 req
, struct tldap_search_all_state
);
2002 if (tevent_req_is_ldap_error(req
, &rc
)) {
2007 *msgs
= talloc_move(mem_ctx
, &state
->msgs
);
2009 if (result
!= NULL
) {
2010 *result
= talloc_move(mem_ctx
, &state
->result
);
2013 return TLDAP_SUCCESS
;
2016 TLDAPRC
tldap_search(struct tldap_context
*ld
,
2017 const char *base
, int scope
, const char *filter
,
2018 const char **attrs
, int num_attrs
, int attrsonly
,
2019 struct tldap_control
*sctrls
, int num_sctrls
,
2020 struct tldap_control
*cctrls
, int num_cctrls
,
2021 int timelimit
, int sizelimit
, int deref
,
2022 TALLOC_CTX
*mem_ctx
, struct tldap_message
***pmsgs
)
2025 struct tevent_context
*ev
;
2026 struct tevent_req
*req
;
2027 TLDAPRC rc
= TLDAP_NO_MEMORY
;
2028 struct tldap_message
**msgs
;
2029 struct tldap_message
*result
;
2031 if (tldap_pending_reqs(ld
)) {
2035 frame
= talloc_stackframe();
2037 ev
= samba_tevent_context_init(frame
);
2041 req
= tldap_search_all_send(frame
, ev
, ld
, base
, scope
, filter
,
2042 attrs
, num_attrs
, attrsonly
,
2043 sctrls
, num_sctrls
, cctrls
, num_cctrls
,
2044 timelimit
, sizelimit
, deref
);
2048 if (!tevent_req_poll(req
, ev
)) {
2049 rc
= TLDAP_OPERATIONS_ERROR
;
2052 rc
= tldap_search_all_recv(req
, frame
, &msgs
, &result
);
2054 if (!TLDAP_RC_IS_SUCCESS(rc
)) {
2058 TALLOC_FREE(ld
->last_msg
);
2059 ld
->last_msg
= talloc_move(ld
, &result
);
2061 if (pmsgs
!= NULL
) {
2062 *pmsgs
= talloc_move(mem_ctx
, &msgs
);
2069 static bool tldap_parse_search_entry(struct tldap_message
*msg
)
2071 int num_attribs
= 0;
2073 if (msg
->type
!= TLDAP_RES_SEARCH_ENTRY
) {
2076 if (!asn1_start_tag(msg
->data
, TLDAP_RES_SEARCH_ENTRY
)) {
2082 if (!asn1_read_OctetString_talloc(msg
, msg
->data
, &msg
->dn
)) return false;
2084 if (msg
->dn
== NULL
) {
2089 * Attributes: We overallocate msg->attribs by one, so that while
2090 * looping over the attributes we can directly parse into the last
2091 * array element. Same for the values in the inner loop.
2094 msg
->attribs
= talloc_array(msg
, struct tldap_attribute
, 1);
2095 if (msg
->attribs
== NULL
) {
2099 if (!asn1_start_tag(msg
->data
, ASN1_SEQUENCE(0))) return false;
2100 while (asn1_peek_tag(msg
->data
, ASN1_SEQUENCE(0))) {
2101 struct tldap_attribute
*attrib
;
2104 attrib
= &msg
->attribs
[num_attribs
];
2105 attrib
->values
= talloc_array(msg
->attribs
, DATA_BLOB
, 1);
2106 if (attrib
->values
== NULL
) {
2109 if (!asn1_start_tag(msg
->data
, ASN1_SEQUENCE(0))) return false;
2110 if (!asn1_read_OctetString_talloc(msg
->attribs
, msg
->data
,
2111 &attrib
->name
)) return false;
2112 if (!asn1_start_tag(msg
->data
, ASN1_SET
)) return false;
2114 while (asn1_peek_tag(msg
->data
, ASN1_OCTET_STRING
)) {
2115 if (!asn1_read_OctetString(msg
->data
, msg
,
2116 &attrib
->values
[num_values
])) return false;
2118 attrib
->values
= talloc_realloc(
2119 msg
->attribs
, attrib
->values
, DATA_BLOB
,
2121 if (attrib
->values
== NULL
) {
2126 attrib
->values
= talloc_realloc(msg
->attribs
, attrib
->values
,
2127 DATA_BLOB
, num_values
);
2128 attrib
->num_values
= num_values
;
2130 if (!asn1_end_tag(msg
->data
)) return false; /* ASN1_SET */
2131 if (!asn1_end_tag(msg
->data
)) return false; /* ASN1_SEQUENCE(0) */
2132 msg
->attribs
= talloc_realloc(
2133 msg
, msg
->attribs
, struct tldap_attribute
,
2135 if (msg
->attribs
== NULL
) {
2140 msg
->attribs
= talloc_realloc(
2141 msg
, msg
->attribs
, struct tldap_attribute
, num_attribs
);
2142 return asn1_end_tag(msg
->data
);
2145 bool tldap_entry_dn(struct tldap_message
*msg
, char **dn
)
2147 if ((msg
->dn
== NULL
) && (!tldap_parse_search_entry(msg
))) {
2154 bool tldap_entry_attributes(struct tldap_message
*msg
,
2155 struct tldap_attribute
**attributes
,
2156 int *num_attributes
)
2158 if ((msg
->dn
== NULL
) && (!tldap_parse_search_entry(msg
))) {
2161 *attributes
= msg
->attribs
;
2162 *num_attributes
= talloc_array_length(msg
->attribs
);
2166 static bool tldap_decode_controls(struct tldap_req_state
*state
)
2168 struct tldap_message
*msg
= state
->result
;
2169 struct asn1_data
*data
= msg
->data
;
2170 struct tldap_control
*sctrls
= NULL
;
2171 int num_controls
= 0;
2174 msg
->res_sctrls
= NULL
;
2176 if (!asn1_peek_tag(data
, ASN1_CONTEXT(0))) {
2180 if (!asn1_start_tag(data
, ASN1_CONTEXT(0))) goto out
;
2182 while (asn1_peek_tag(data
, ASN1_SEQUENCE(0))) {
2183 struct tldap_control
*c
;
2186 sctrls
= talloc_realloc(msg
, sctrls
, struct tldap_control
,
2188 if (sctrls
== NULL
) {
2191 c
= &sctrls
[num_controls
];
2193 if (!asn1_start_tag(data
, ASN1_SEQUENCE(0))) goto out
;
2194 if (!asn1_read_OctetString_talloc(msg
, data
, &oid
)) goto out
;
2195 if (asn1_has_error(data
) || (oid
== NULL
)) {
2199 if (asn1_peek_tag(data
, ASN1_BOOLEAN
)) {
2200 if (!asn1_read_BOOLEAN(data
, &c
->critical
)) goto out
;
2202 c
->critical
= false;
2204 c
->value
= data_blob_null
;
2205 if (asn1_peek_tag(data
, ASN1_OCTET_STRING
) &&
2206 !asn1_read_OctetString(data
, msg
, &c
->value
)) {
2209 if (!asn1_end_tag(data
)) goto out
; /* ASN1_SEQUENCE(0) */
2214 if (!asn1_end_tag(data
)) goto out
; /* ASN1_CONTEXT(0) */
2221 msg
->res_sctrls
= sctrls
;
2223 TALLOC_FREE(sctrls
);
2228 static void tldap_simple_done(struct tevent_req
*subreq
, int type
)
2230 struct tevent_req
*req
= tevent_req_callback_data(
2231 subreq
, struct tevent_req
);
2232 struct tldap_req_state
*state
= tevent_req_data(
2233 req
, struct tldap_req_state
);
2236 rc
= tldap_msg_recv(subreq
, state
, &state
->result
);
2237 TALLOC_FREE(subreq
);
2238 if (tevent_req_ldap_error(req
, rc
)) {
2241 if (state
->result
->type
!= type
) {
2242 tevent_req_ldap_error(req
, TLDAP_PROTOCOL_ERROR
);
2245 if (!asn1_start_tag(state
->result
->data
, state
->result
->type
) ||
2246 !tldap_decode_response(state
) ||
2247 !asn1_end_tag(state
->result
->data
) ||
2248 !tldap_decode_controls(state
)) {
2249 tevent_req_ldap_error(req
, TLDAP_DECODING_ERROR
);
2252 if (!TLDAP_RC_IS_SUCCESS(state
->result
->lderr
)) {
2253 tevent_req_ldap_error(req
, state
->result
->lderr
);
2256 tevent_req_done(req
);
2259 static TLDAPRC
tldap_simple_recv(struct tevent_req
*req
)
2262 if (tevent_req_is_ldap_error(req
, &rc
)) {
2265 return TLDAP_SUCCESS
;
2268 static void tldap_add_done(struct tevent_req
*subreq
);
2270 struct tevent_req
*tldap_add_send(TALLOC_CTX
*mem_ctx
,
2271 struct tevent_context
*ev
,
2272 struct tldap_context
*ld
,
2274 struct tldap_mod
*attributes
,
2276 struct tldap_control
*sctrls
,
2278 struct tldap_control
*cctrls
,
2281 struct tevent_req
*req
, *subreq
;
2282 struct tldap_req_state
*state
;
2285 req
= tldap_req_create(mem_ctx
, ld
, &state
);
2290 if (!asn1_push_tag(state
->out
, TLDAP_REQ_ADD
)) goto err
;
2291 if (!asn1_write_OctetString(state
->out
, dn
, strlen(dn
))) goto err
;
2292 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2294 for (i
=0; i
<num_attributes
; i
++) {
2295 struct tldap_mod
*attrib
= &attributes
[i
];
2296 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2297 if (!asn1_write_OctetString(state
->out
, attrib
->attribute
,
2298 strlen(attrib
->attribute
))) goto err
;
2299 if (!asn1_push_tag(state
->out
, ASN1_SET
)) goto err
;
2300 for (j
=0; j
<attrib
->num_values
; j
++) {
2301 if (!asn1_write_OctetString(state
->out
,
2302 attrib
->values
[j
].data
,
2303 attrib
->values
[j
].length
)) goto err
;
2305 if (!asn1_pop_tag(state
->out
)) goto err
;
2306 if (!asn1_pop_tag(state
->out
)) goto err
;
2309 if (!asn1_pop_tag(state
->out
)) goto err
;
2310 if (!asn1_pop_tag(state
->out
)) goto err
;
2312 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
2313 sctrls
, num_sctrls
);
2314 if (tevent_req_nomem(subreq
, req
)) {
2315 return tevent_req_post(req
, ev
);
2317 tevent_req_set_callback(subreq
, tldap_add_done
, req
);
2322 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
2323 return tevent_req_post(req
, ev
);
2326 static void tldap_add_done(struct tevent_req
*subreq
)
2328 tldap_simple_done(subreq
, TLDAP_RES_ADD
);
2331 TLDAPRC
tldap_add_recv(struct tevent_req
*req
)
2333 return tldap_simple_recv(req
);
2336 TLDAPRC
tldap_add(struct tldap_context
*ld
, const char *dn
,
2337 struct tldap_mod
*attributes
, int num_attributes
,
2338 struct tldap_control
*sctrls
, int num_sctrls
,
2339 struct tldap_control
*cctrls
, int num_cctrls
)
2341 TALLOC_CTX
*frame
= talloc_stackframe();
2342 struct tevent_context
*ev
;
2343 struct tevent_req
*req
;
2344 TLDAPRC rc
= TLDAP_NO_MEMORY
;
2346 ev
= samba_tevent_context_init(frame
);
2350 req
= tldap_add_send(frame
, ev
, ld
, dn
, attributes
, num_attributes
,
2351 sctrls
, num_sctrls
, cctrls
, num_cctrls
);
2355 if (!tevent_req_poll(req
, ev
)) {
2356 rc
= TLDAP_OPERATIONS_ERROR
;
2359 rc
= tldap_add_recv(req
);
2360 tldap_save_msg(ld
, req
);
2366 static void tldap_modify_done(struct tevent_req
*subreq
);
2368 struct tevent_req
*tldap_modify_send(TALLOC_CTX
*mem_ctx
,
2369 struct tevent_context
*ev
,
2370 struct tldap_context
*ld
,
2372 struct tldap_mod
*mods
, int num_mods
,
2373 struct tldap_control
*sctrls
,
2375 struct tldap_control
*cctrls
,
2378 struct tevent_req
*req
, *subreq
;
2379 struct tldap_req_state
*state
;
2382 req
= tldap_req_create(mem_ctx
, ld
, &state
);
2387 if (!asn1_push_tag(state
->out
, TLDAP_REQ_MODIFY
)) goto err
;
2388 if (!asn1_write_OctetString(state
->out
, dn
, strlen(dn
))) goto err
;
2389 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2391 for (i
=0; i
<num_mods
; i
++) {
2392 struct tldap_mod
*mod
= &mods
[i
];
2393 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2394 if (!asn1_write_enumerated(state
->out
, mod
->mod_op
)) goto err
;
2395 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2396 if (!asn1_write_OctetString(state
->out
, mod
->attribute
,
2397 strlen(mod
->attribute
))) goto err
;
2398 if (!asn1_push_tag(state
->out
, ASN1_SET
)) goto err
;
2399 for (j
=0; j
<mod
->num_values
; j
++) {
2400 if (!asn1_write_OctetString(state
->out
,
2401 mod
->values
[j
].data
,
2402 mod
->values
[j
].length
)) goto err
;
2404 if (!asn1_pop_tag(state
->out
)) goto err
;
2405 if (!asn1_pop_tag(state
->out
)) goto err
;
2406 if (!asn1_pop_tag(state
->out
)) goto err
;
2409 if (!asn1_pop_tag(state
->out
)) goto err
;
2410 if (!asn1_pop_tag(state
->out
)) goto err
;
2412 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
2413 sctrls
, num_sctrls
);
2414 if (tevent_req_nomem(subreq
, req
)) {
2415 return tevent_req_post(req
, ev
);
2417 tevent_req_set_callback(subreq
, tldap_modify_done
, req
);
2422 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
2423 return tevent_req_post(req
, ev
);
2426 static void tldap_modify_done(struct tevent_req
*subreq
)
2428 tldap_simple_done(subreq
, TLDAP_RES_MODIFY
);
2431 TLDAPRC
tldap_modify_recv(struct tevent_req
*req
)
2433 return tldap_simple_recv(req
);
2436 TLDAPRC
tldap_modify(struct tldap_context
*ld
, const char *dn
,
2437 struct tldap_mod
*mods
, int num_mods
,
2438 struct tldap_control
*sctrls
, int num_sctrls
,
2439 struct tldap_control
*cctrls
, int num_cctrls
)
2441 TALLOC_CTX
*frame
= talloc_stackframe();
2442 struct tevent_context
*ev
;
2443 struct tevent_req
*req
;
2444 TLDAPRC rc
= TLDAP_NO_MEMORY
;
2446 ev
= samba_tevent_context_init(frame
);
2450 req
= tldap_modify_send(frame
, ev
, ld
, dn
, mods
, num_mods
,
2451 sctrls
, num_sctrls
, cctrls
, num_cctrls
);
2455 if (!tevent_req_poll(req
, ev
)) {
2456 rc
= TLDAP_OPERATIONS_ERROR
;
2459 rc
= tldap_modify_recv(req
);
2460 tldap_save_msg(ld
, req
);
2466 static void tldap_delete_done(struct tevent_req
*subreq
);
2468 struct tevent_req
*tldap_delete_send(TALLOC_CTX
*mem_ctx
,
2469 struct tevent_context
*ev
,
2470 struct tldap_context
*ld
,
2472 struct tldap_control
*sctrls
,
2474 struct tldap_control
*cctrls
,
2477 struct tevent_req
*req
, *subreq
;
2478 struct tldap_req_state
*state
;
2480 req
= tldap_req_create(mem_ctx
, ld
, &state
);
2485 if (!asn1_push_tag(state
->out
, TLDAP_REQ_DELETE
)) goto err
;
2486 if (!asn1_write(state
->out
, dn
, strlen(dn
))) goto err
;
2487 if (!asn1_pop_tag(state
->out
)) goto err
;
2489 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
2490 sctrls
, num_sctrls
);
2491 if (tevent_req_nomem(subreq
, req
)) {
2492 return tevent_req_post(req
, ev
);
2494 tevent_req_set_callback(subreq
, tldap_delete_done
, req
);
2499 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
2500 return tevent_req_post(req
, ev
);
2503 static void tldap_delete_done(struct tevent_req
*subreq
)
2505 tldap_simple_done(subreq
, TLDAP_RES_DELETE
);
2508 TLDAPRC
tldap_delete_recv(struct tevent_req
*req
)
2510 return tldap_simple_recv(req
);
2513 TLDAPRC
tldap_delete(struct tldap_context
*ld
, const char *dn
,
2514 struct tldap_control
*sctrls
, int num_sctrls
,
2515 struct tldap_control
*cctrls
, int num_cctrls
)
2517 TALLOC_CTX
*frame
= talloc_stackframe();
2518 struct tevent_context
*ev
;
2519 struct tevent_req
*req
;
2520 TLDAPRC rc
= TLDAP_NO_MEMORY
;
2522 ev
= samba_tevent_context_init(frame
);
2526 req
= tldap_delete_send(frame
, ev
, ld
, dn
, sctrls
, num_sctrls
,
2527 cctrls
, num_cctrls
);
2531 if (!tevent_req_poll(req
, ev
)) {
2532 rc
= TLDAP_OPERATIONS_ERROR
;
2535 rc
= tldap_delete_recv(req
);
2536 tldap_save_msg(ld
, req
);
2542 int tldap_msg_id(const struct tldap_message
*msg
)
2547 int tldap_msg_type(const struct tldap_message
*msg
)
2552 const char *tldap_msg_matcheddn(struct tldap_message
*msg
)
2557 return msg
->res_matcheddn
;
2560 const char *tldap_msg_diagnosticmessage(struct tldap_message
*msg
)
2565 return msg
->res_diagnosticmessage
;
2568 const char *tldap_msg_referral(struct tldap_message
*msg
)
2573 return msg
->res_referral
;
2576 void tldap_msg_sctrls(struct tldap_message
*msg
, int *num_sctrls
,
2577 struct tldap_control
**sctrls
)
2584 *sctrls
= msg
->res_sctrls
;
2585 *num_sctrls
= talloc_array_length(msg
->res_sctrls
);
2588 struct tldap_message
*tldap_ctx_lastmsg(struct tldap_context
*ld
)
2590 return ld
->last_msg
;
2593 static const struct { TLDAPRC rc
; const char *string
; } tldaprc_errmap
[] =
2597 { TLDAP_OPERATIONS_ERROR
,
2598 "TLDAP_OPERATIONS_ERROR" },
2599 { TLDAP_PROTOCOL_ERROR
,
2600 "TLDAP_PROTOCOL_ERROR" },
2601 { TLDAP_TIMELIMIT_EXCEEDED
,
2602 "TLDAP_TIMELIMIT_EXCEEDED" },
2603 { TLDAP_SIZELIMIT_EXCEEDED
,
2604 "TLDAP_SIZELIMIT_EXCEEDED" },
2605 { TLDAP_COMPARE_FALSE
,
2606 "TLDAP_COMPARE_FALSE" },
2607 { TLDAP_COMPARE_TRUE
,
2608 "TLDAP_COMPARE_TRUE" },
2609 { TLDAP_STRONG_AUTH_NOT_SUPPORTED
,
2610 "TLDAP_STRONG_AUTH_NOT_SUPPORTED" },
2611 { TLDAP_STRONG_AUTH_REQUIRED
,
2612 "TLDAP_STRONG_AUTH_REQUIRED" },
2615 { TLDAP_ADMINLIMIT_EXCEEDED
,
2616 "TLDAP_ADMINLIMIT_EXCEEDED" },
2617 { TLDAP_UNAVAILABLE_CRITICAL_EXTENSION
,
2618 "TLDAP_UNAVAILABLE_CRITICAL_EXTENSION" },
2619 { TLDAP_CONFIDENTIALITY_REQUIRED
,
2620 "TLDAP_CONFIDENTIALITY_REQUIRED" },
2621 { TLDAP_SASL_BIND_IN_PROGRESS
,
2622 "TLDAP_SASL_BIND_IN_PROGRESS" },
2623 { TLDAP_NO_SUCH_ATTRIBUTE
,
2624 "TLDAP_NO_SUCH_ATTRIBUTE" },
2625 { TLDAP_UNDEFINED_TYPE
,
2626 "TLDAP_UNDEFINED_TYPE" },
2627 { TLDAP_INAPPROPRIATE_MATCHING
,
2628 "TLDAP_INAPPROPRIATE_MATCHING" },
2629 { TLDAP_CONSTRAINT_VIOLATION
,
2630 "TLDAP_CONSTRAINT_VIOLATION" },
2631 { TLDAP_TYPE_OR_VALUE_EXISTS
,
2632 "TLDAP_TYPE_OR_VALUE_EXISTS" },
2633 { TLDAP_INVALID_SYNTAX
,
2634 "TLDAP_INVALID_SYNTAX" },
2635 { TLDAP_NO_SUCH_OBJECT
,
2636 "TLDAP_NO_SUCH_OBJECT" },
2637 { TLDAP_ALIAS_PROBLEM
,
2638 "TLDAP_ALIAS_PROBLEM" },
2639 { TLDAP_INVALID_DN_SYNTAX
,
2640 "TLDAP_INVALID_DN_SYNTAX" },
2643 { TLDAP_ALIAS_DEREF_PROBLEM
,
2644 "TLDAP_ALIAS_DEREF_PROBLEM" },
2645 { TLDAP_INAPPROPRIATE_AUTH
,
2646 "TLDAP_INAPPROPRIATE_AUTH" },
2647 { TLDAP_INVALID_CREDENTIALS
,
2648 "TLDAP_INVALID_CREDENTIALS" },
2649 { TLDAP_INSUFFICIENT_ACCESS
,
2650 "TLDAP_INSUFFICIENT_ACCESS" },
2653 { TLDAP_UNAVAILABLE
,
2654 "TLDAP_UNAVAILABLE" },
2655 { TLDAP_UNWILLING_TO_PERFORM
,
2656 "TLDAP_UNWILLING_TO_PERFORM" },
2657 { TLDAP_LOOP_DETECT
,
2658 "TLDAP_LOOP_DETECT" },
2659 { TLDAP_NAMING_VIOLATION
,
2660 "TLDAP_NAMING_VIOLATION" },
2661 { TLDAP_OBJECT_CLASS_VIOLATION
,
2662 "TLDAP_OBJECT_CLASS_VIOLATION" },
2663 { TLDAP_NOT_ALLOWED_ON_NONLEAF
,
2664 "TLDAP_NOT_ALLOWED_ON_NONLEAF" },
2665 { TLDAP_NOT_ALLOWED_ON_RDN
,
2666 "TLDAP_NOT_ALLOWED_ON_RDN" },
2667 { TLDAP_ALREADY_EXISTS
,
2668 "TLDAP_ALREADY_EXISTS" },
2669 { TLDAP_NO_OBJECT_CLASS_MODS
,
2670 "TLDAP_NO_OBJECT_CLASS_MODS" },
2671 { TLDAP_RESULTS_TOO_LARGE
,
2672 "TLDAP_RESULTS_TOO_LARGE" },
2673 { TLDAP_AFFECTS_MULTIPLE_DSAS
,
2674 "TLDAP_AFFECTS_MULTIPLE_DSAS" },
2677 { TLDAP_SERVER_DOWN
,
2678 "TLDAP_SERVER_DOWN" },
2679 { TLDAP_LOCAL_ERROR
,
2680 "TLDAP_LOCAL_ERROR" },
2681 { TLDAP_ENCODING_ERROR
,
2682 "TLDAP_ENCODING_ERROR" },
2683 { TLDAP_DECODING_ERROR
,
2684 "TLDAP_DECODING_ERROR" },
2687 { TLDAP_AUTH_UNKNOWN
,
2688 "TLDAP_AUTH_UNKNOWN" },
2689 { TLDAP_FILTER_ERROR
,
2690 "TLDAP_FILTER_ERROR" },
2691 { TLDAP_USER_CANCELLED
,
2692 "TLDAP_USER_CANCELLED" },
2693 { TLDAP_PARAM_ERROR
,
2694 "TLDAP_PARAM_ERROR" },
2696 "TLDAP_NO_MEMORY" },
2697 { TLDAP_CONNECT_ERROR
,
2698 "TLDAP_CONNECT_ERROR" },
2699 { TLDAP_NOT_SUPPORTED
,
2700 "TLDAP_NOT_SUPPORTED" },
2701 { TLDAP_CONTROL_NOT_FOUND
,
2702 "TLDAP_CONTROL_NOT_FOUND" },
2703 { TLDAP_NO_RESULTS_RETURNED
,
2704 "TLDAP_NO_RESULTS_RETURNED" },
2705 { TLDAP_MORE_RESULTS_TO_RETURN
,
2706 "TLDAP_MORE_RESULTS_TO_RETURN" },
2707 { TLDAP_CLIENT_LOOP
,
2708 "TLDAP_CLIENT_LOOP" },
2709 { TLDAP_REFERRAL_LIMIT_EXCEEDED
,
2710 "TLDAP_REFERRAL_LIMIT_EXCEEDED" },
2713 const char *tldap_rc2string(TLDAPRC rc
)
2717 for (i
=0; i
<ARRAY_SIZE(tldaprc_errmap
); i
++) {
2718 if (TLDAP_RC_EQUAL(rc
, tldaprc_errmap
[i
].rc
)) {
2719 return tldaprc_errmap
[i
].string
;
2723 return "Unknown LDAP Error";