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"
30 #include "../libcli/util/ntstatus.h"
31 #include "../source4/lib/tls/tls.h"
33 static TLDAPRC
tldap_simple_recv(struct tevent_req
*req
);
34 static bool tldap_msg_set_pending(struct tevent_req
*req
);
36 #define TEVENT_TLDAP_RC_MAGIC (0x87bcd26e)
38 bool tevent_req_ldap_error(struct tevent_req
*req
, TLDAPRC rc
)
42 if (TLDAP_RC_IS_SUCCESS(rc
)) {
46 err
= TEVENT_TLDAP_RC_MAGIC
;
48 err
|= TLDAP_RC_V(rc
);
50 return tevent_req_error(req
, err
);
53 bool tevent_req_is_ldap_error(struct tevent_req
*req
, TLDAPRC
*perr
)
55 enum tevent_req_state state
;
58 if (!tevent_req_is_error(req
, &state
, &err
)) {
62 case TEVENT_REQ_TIMED_OUT
:
63 *perr
= TLDAP_TIMEOUT
;
65 case TEVENT_REQ_NO_MEMORY
:
66 *perr
= TLDAP_NO_MEMORY
;
68 case TEVENT_REQ_USER_ERROR
:
69 if ((err
>> 32) != TEVENT_TLDAP_RC_MAGIC
) {
72 *perr
= TLDAP_RC(err
& 0xffffffff);
75 *perr
= TLDAP_OPERATIONS_ERROR
;
81 struct tldap_ctx_attribute
{
86 struct tldap_context
{
88 struct tstream_context
*plain
;
89 struct tstream_context
*tls
;
90 struct tstream_context
*gensec
;
91 struct tstream_context
*active
;
93 struct tevent_queue
*outgoing
;
94 struct tevent_req
**pending
;
95 struct tevent_req
*read_req
;
97 /* For the sync wrappers we need something like get_last_error... */
98 struct tldap_message
*last_msg
;
101 void (*log_fn
)(void *context
, enum tldap_debug_level level
,
102 const char *fmt
, va_list ap
);
105 struct tldap_ctx_attribute
*ctx_attrs
;
108 struct tldap_message
{
109 struct asn1_data
*data
;
116 struct tldap_attribute
*attribs
;
118 /* Error data sent by the server */
121 char *res_diagnosticmessage
;
123 DATA_BLOB res_serverSaslCreds
;
128 struct tldap_control
*res_sctrls
;
130 /* Controls sent by the server */
131 struct tldap_control
*ctrls
;
134 void tldap_set_debug(struct tldap_context
*ld
,
135 void (*log_fn
)(void *log_private
,
136 enum tldap_debug_level level
,
138 va_list ap
) PRINTF_ATTRIBUTE(3,0),
142 ld
->log_private
= log_private
;
145 static void tldap_debug(
146 struct tldap_context
*ld
,
147 enum tldap_debug_level level
,
148 const char *fmt
, ...) PRINTF_ATTRIBUTE(3,4);
150 static void tldap_debug(struct tldap_context
*ld
,
151 enum tldap_debug_level level
,
152 const char *fmt
, ...)
158 if (ld
->log_fn
== NULL
) {
162 ld
->log_fn(ld
->log_private
, level
, fmt
, ap
);
166 static int tldap_next_msgid(struct tldap_context
*ld
)
170 result
= ld
->msgid
++;
171 if (ld
->msgid
== INT_MAX
) {
177 struct tldap_context
*tldap_context_create_from_plain_stream(
178 TALLOC_CTX
*mem_ctx
, struct tstream_context
**stream
)
180 struct tldap_context
*ctx
;
182 ctx
= talloc_zero(mem_ctx
, struct tldap_context
);
186 ctx
->plain
= talloc_move(ctx
, stream
);
187 ctx
->active
= ctx
->plain
;
190 ctx
->outgoing
= tevent_queue_create(ctx
, "tldap_outgoing");
191 if (ctx
->outgoing
== NULL
) {
198 struct tldap_context
*tldap_context_create(TALLOC_CTX
*mem_ctx
, int fd
)
200 struct tldap_context
*ctx
= NULL
;
201 struct tstream_context
*stream
= NULL
;
204 ret
= tstream_bsd_existing_socket(mem_ctx
, fd
, &stream
);
209 ctx
= tldap_context_create_from_plain_stream(mem_ctx
, &stream
);
217 bool tldap_connection_ok(struct tldap_context
*ld
)
225 if (ld
->active
== NULL
) {
229 ret
= tstream_pending_bytes(ld
->active
);
237 static size_t tldap_pending_reqs(struct tldap_context
*ld
)
239 return talloc_array_length(ld
->pending
);
242 struct tstream_context
*tldap_get_plain_tstream(struct tldap_context
*ld
)
247 bool tldap_has_tls_tstream(struct tldap_context
*ld
)
249 return ld
->tls
!= NULL
&& ld
->active
== ld
->tls
;
252 const DATA_BLOB
*tldap_tls_channel_bindings(struct tldap_context
*ld
)
254 return tstream_tls_channel_bindings(ld
->tls
);
257 void tldap_set_tls_tstream(struct tldap_context
*ld
,
258 struct tstream_context
**stream
)
260 TALLOC_FREE(ld
->tls
);
261 if (stream
!= NULL
) {
262 ld
->tls
= talloc_move(ld
, stream
);
264 if (ld
->tls
!= NULL
) {
265 ld
->active
= ld
->tls
;
267 ld
->active
= ld
->plain
;
271 bool tldap_has_gensec_tstream(struct tldap_context
*ld
)
273 return ld
->gensec
!= NULL
&& ld
->active
== ld
->gensec
;
276 void tldap_set_gensec_tstream(struct tldap_context
*ld
,
277 struct tstream_context
**stream
)
279 TALLOC_FREE(ld
->gensec
);
280 if (stream
!= NULL
) {
281 ld
->gensec
= talloc_move(ld
, stream
);
283 if (ld
->gensec
!= NULL
) {
284 ld
->active
= ld
->gensec
;
286 ld
->active
= ld
->plain
;
290 static struct tldap_ctx_attribute
*tldap_context_findattr(
291 struct tldap_context
*ld
, const char *name
)
295 num_attrs
= talloc_array_length(ld
->ctx_attrs
);
297 for (i
=0; i
<num_attrs
; i
++) {
298 if (strcmp(ld
->ctx_attrs
[i
].name
, name
) == 0) {
299 return &ld
->ctx_attrs
[i
];
305 bool tldap_context_setattr(struct tldap_context
*ld
,
306 const char *name
, const void *_pptr
)
308 struct tldap_ctx_attribute
*tmp
, *attr
;
311 void **pptr
= (void **)discard_const_p(void,_pptr
);
313 attr
= tldap_context_findattr(ld
, name
);
316 * We don't actually delete attrs, we don't expect tons of
317 * attributes being shuffled around.
319 TALLOC_FREE(attr
->ptr
);
321 attr
->ptr
= talloc_move(ld
->ctx_attrs
, pptr
);
327 tmpname
= talloc_strdup(ld
, name
);
328 if (tmpname
== NULL
) {
332 num_attrs
= talloc_array_length(ld
->ctx_attrs
);
334 tmp
= talloc_realloc(ld
, ld
->ctx_attrs
, struct tldap_ctx_attribute
,
337 TALLOC_FREE(tmpname
);
340 tmp
[num_attrs
].name
= talloc_move(tmp
, &tmpname
);
342 tmp
[num_attrs
].ptr
= talloc_move(tmp
, pptr
);
344 tmp
[num_attrs
].ptr
= NULL
;
351 void *tldap_context_getattr(struct tldap_context
*ld
, const char *name
)
353 struct tldap_ctx_attribute
*attr
= tldap_context_findattr(ld
, name
);
361 struct read_ldap_state
{
365 static ssize_t
read_ldap_more(uint8_t *buf
, size_t buflen
, void *private_data
);
366 static void read_ldap_done(struct tevent_req
*subreq
);
368 static struct tevent_req
*read_ldap_send(TALLOC_CTX
*mem_ctx
,
369 struct tevent_context
*ev
,
370 struct tstream_context
*conn
)
372 struct tevent_req
*req
, *subreq
;
373 struct read_ldap_state
*state
;
375 req
= tevent_req_create(mem_ctx
, &state
, struct read_ldap_state
);
380 subreq
= tstream_read_packet_send(state
, ev
, conn
, 7, read_ldap_more
,
382 if (tevent_req_nomem(subreq
, req
)) {
383 return tevent_req_post(req
, ev
);
385 tevent_req_set_callback(subreq
, read_ldap_done
, req
);
389 static ssize_t
read_ldap_more(uint8_t *buf
, size_t buflen
, void *private_data
)
391 const DATA_BLOB blob
= data_blob_const(buf
, buflen
);
397 * We need at least 6 bytes to workout the length
400 * And we have asked for 7 because the that's
401 * the size of the smallest possible LDAP pdu.
406 ret
= asn1_peek_full_tag(blob
, ASN1_SEQUENCE(0), &pdu_len
);
411 return pdu_len
- buflen
;
417 static void read_ldap_done(struct tevent_req
*subreq
)
419 struct tevent_req
*req
= tevent_req_callback_data(
420 subreq
, struct tevent_req
);
421 struct read_ldap_state
*state
= tevent_req_data(
422 req
, struct read_ldap_state
);
426 nread
= tstream_read_packet_recv(subreq
, state
, &state
->buf
, &err
);
429 tevent_req_error(req
, err
);
432 tevent_req_done(req
);
435 static ssize_t
read_ldap_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
436 uint8_t **pbuf
, int *perrno
)
438 struct read_ldap_state
*state
= tevent_req_data(
439 req
, struct read_ldap_state
);
441 if (tevent_req_is_unix_error(req
, perrno
)) {
444 *pbuf
= talloc_move(mem_ctx
, &state
->buf
);
445 return talloc_get_size(*pbuf
);
448 struct tldap_msg_state
{
449 struct tldap_context
*ld
;
450 struct tevent_context
*ev
;
454 struct asn1_data
*data
;
458 static bool tldap_push_controls(struct asn1_data
*data
,
459 struct tldap_control
*sctrls
,
464 if ((sctrls
== NULL
) || (num_sctrls
== 0)) {
468 if (!asn1_push_tag(data
, ASN1_CONTEXT(0))) return false;
470 for (i
=0; i
<num_sctrls
; i
++) {
471 struct tldap_control
*c
= &sctrls
[i
];
472 if (!asn1_push_tag(data
, ASN1_SEQUENCE(0))) return false;
473 if (!asn1_write_OctetString(data
, c
->oid
, strlen(c
->oid
))) return false;
475 if (!asn1_write_BOOLEAN(data
, true)) return false;
477 if (c
->value
.data
!= NULL
) {
478 if (!asn1_write_OctetString(data
, c
->value
.data
,
479 c
->value
.length
)) return false;
481 if (!asn1_pop_tag(data
)) return false; /* ASN1_SEQUENCE(0) */
484 return asn1_pop_tag(data
); /* ASN1_CONTEXT(0) */
487 #define tldap_context_disconnect(ld, status) \
488 _tldap_context_disconnect(ld, status, __location__)
490 static void _tldap_context_disconnect(struct tldap_context
*ld
,
492 const char *location
)
494 if (ld
->active
== NULL
) {
496 * We don't need to tldap_debug() on
497 * a potential 2nd run.
499 * The rest of the function would just
500 * be a noop for the 2nd run anyway.
505 tldap_debug(ld
, TLDAP_DEBUG_WARNING
,
506 "tldap_context_disconnect: %s at %s\n",
507 tldap_rc2string(status
),
509 tevent_queue_stop(ld
->outgoing
);
510 TALLOC_FREE(ld
->read_req
);
512 TALLOC_FREE(ld
->gensec
);
513 TALLOC_FREE(ld
->tls
);
514 TALLOC_FREE(ld
->plain
);
516 while (talloc_array_length(ld
->pending
) > 0) {
517 struct tevent_req
*req
= NULL
;
518 struct tldap_msg_state
*state
= NULL
;
520 req
= ld
->pending
[0];
521 state
= tevent_req_data(req
, struct tldap_msg_state
);
522 tevent_req_defer_callback(req
, state
->ev
);
523 tevent_req_ldap_error(req
, status
);
527 static void tldap_msg_sent(struct tevent_req
*subreq
);
528 static void tldap_msg_received(struct tevent_req
*subreq
);
530 static struct tevent_req
*tldap_msg_send(TALLOC_CTX
*mem_ctx
,
531 struct tevent_context
*ev
,
532 struct tldap_context
*ld
,
533 int id
, struct asn1_data
*data
,
534 struct tldap_control
*sctrls
,
537 struct tevent_req
*req
, *subreq
;
538 struct tldap_msg_state
*state
;
542 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "tldap_msg_send: sending msg %d\n",
545 req
= tevent_req_create(mem_ctx
, &state
, struct tldap_msg_state
);
553 ok
= tldap_connection_ok(ld
);
555 tevent_req_ldap_error(req
, TLDAP_SERVER_DOWN
);
556 return tevent_req_post(req
, ev
);
559 if (!tldap_push_controls(data
, sctrls
, num_sctrls
)) {
560 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
561 return tevent_req_post(req
, ev
);
565 if (!asn1_pop_tag(data
)) {
566 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
567 return tevent_req_post(req
, ev
);
570 if (!asn1_blob(data
, &blob
)) {
571 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
572 return tevent_req_post(req
, ev
);
575 if (!tldap_msg_set_pending(req
)) {
577 return tevent_req_post(req
, ev
);;
580 state
->iov
.iov_base
= (void *)blob
.data
;
581 state
->iov
.iov_len
= blob
.length
;
583 subreq
= tstream_writev_queue_send(state
, ev
, ld
->active
, ld
->outgoing
,
585 if (tevent_req_nomem(subreq
, req
)) {
586 return tevent_req_post(req
, ev
);
588 tevent_req_set_callback(subreq
, tldap_msg_sent
, req
);
592 static void tldap_msg_unset_pending(struct tevent_req
*req
)
594 struct tldap_msg_state
*state
= tevent_req_data(
595 req
, struct tldap_msg_state
);
596 struct tldap_context
*ld
= state
->ld
;
597 int num_pending
= tldap_pending_reqs(ld
);
600 tevent_req_set_cleanup_fn(req
, NULL
);
602 for (i
=0; i
<num_pending
; i
++) {
603 if (req
== ld
->pending
[i
]) {
607 if (i
== num_pending
) {
609 * Something's seriously broken. Just returning here is the
610 * right thing nevertheless, the point of this routine is to
611 * remove ourselves from cli->pending.
616 if (num_pending
== 1) {
617 TALLOC_FREE(ld
->pending
);
622 * Remove ourselves from the cli->pending array
624 if (num_pending
> 1) {
625 ld
->pending
[i
] = ld
->pending
[num_pending
-1];
629 * No NULL check here, we're shrinking by sizeof(void *), and
630 * talloc_realloc just adjusts the size for this.
632 ld
->pending
= talloc_realloc(NULL
, ld
->pending
, struct tevent_req
*,
636 static void tldap_msg_cleanup(struct tevent_req
*req
,
637 enum tevent_req_state req_state
)
639 tldap_msg_unset_pending(req
);
642 static bool tldap_msg_set_pending(struct tevent_req
*req
)
644 struct tldap_msg_state
*state
= tevent_req_data(
645 req
, struct tldap_msg_state
);
646 struct tldap_context
*ld
;
647 struct tevent_req
**pending
;
651 num_pending
= tldap_pending_reqs(ld
);
653 pending
= talloc_realloc(ld
, ld
->pending
, struct tevent_req
*,
655 if (pending
== NULL
) {
658 pending
[num_pending
] = req
;
659 ld
->pending
= pending
;
660 tevent_req_set_cleanup_fn(req
, tldap_msg_cleanup
);
662 if (ld
->read_req
!= NULL
) {
667 * We're the first one, add the read_ldap request that waits for the
668 * answer from the server
670 ld
->read_req
= read_ldap_send(ld
->pending
, state
->ev
, ld
->active
);
671 if (ld
->read_req
== NULL
) {
672 tldap_msg_unset_pending(req
);
675 tevent_req_set_callback(ld
->read_req
, tldap_msg_received
, ld
);
679 static void tldap_msg_sent(struct tevent_req
*subreq
)
681 struct tevent_req
*req
= tevent_req_callback_data(
682 subreq
, struct tevent_req
);
683 struct tldap_msg_state
*state
= tevent_req_data(
684 req
, struct tldap_msg_state
);
688 nwritten
= tstream_writev_queue_recv(subreq
, &err
);
690 if (nwritten
== -1) {
691 tldap_context_disconnect(state
->ld
, TLDAP_SERVER_DOWN
);
696 static int tldap_msg_msgid(struct tevent_req
*req
)
698 struct tldap_msg_state
*state
= tevent_req_data(
699 req
, struct tldap_msg_state
);
704 static void tldap_msg_received(struct tevent_req
*subreq
)
706 struct tldap_context
*ld
= tevent_req_callback_data(
707 subreq
, struct tldap_context
);
708 struct tevent_req
*req
;
709 struct tldap_msg_state
*state
;
710 struct asn1_data
*data
;
716 TLDAPRC status
= TLDAP_PROTOCOL_ERROR
;
721 received
= read_ldap_recv(subreq
, talloc_tos(), &inbuf
, &err
);
724 if (received
== -1) {
725 status
= TLDAP_SERVER_DOWN
;
729 data
= asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH
);
732 * We have to disconnect all, we can't tell which of
733 * the requests this reply is for.
735 status
= TLDAP_NO_MEMORY
;
738 asn1_load_nocopy(data
, inbuf
, received
);
741 ok
&= asn1_start_tag(data
, ASN1_SEQUENCE(0));
742 ok
&= asn1_read_Integer(data
, &id
);
743 ok
&= asn1_peek_uint8(data
, &type
);
746 status
= TLDAP_PROTOCOL_ERROR
;
750 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "tldap_msg_received: got msg %d "
751 "type %d\n", id
, (int)type
);
757 "tldap_msg_received: got msgid 0 of "
758 "type %"PRIu8
", disconnecting\n",
760 tldap_context_disconnect(ld
, TLDAP_SERVER_DOWN
);
764 num_pending
= talloc_array_length(ld
->pending
);
766 for (i
=0; i
<num_pending
; i
++) {
767 if (id
== tldap_msg_msgid(ld
->pending
[i
])) {
771 if (i
== num_pending
) {
772 /* Dump unexpected reply */
773 tldap_debug(ld
, TLDAP_DEBUG_WARNING
, "tldap_msg_received: "
774 "No request pending for msg %d\n", id
);
780 req
= ld
->pending
[i
];
781 state
= tevent_req_data(req
, struct tldap_msg_state
);
783 state
->inbuf
= talloc_move(state
, &inbuf
);
784 state
->data
= talloc_move(state
, &data
);
786 tldap_msg_unset_pending(req
);
787 num_pending
= talloc_array_length(ld
->pending
);
789 tevent_req_defer_callback(req
, state
->ev
);
790 tevent_req_done(req
);
793 if (num_pending
== 0) {
797 state
= tevent_req_data(ld
->pending
[0], struct tldap_msg_state
);
798 ld
->read_req
= read_ldap_send(ld
->pending
, state
->ev
, ld
->active
);
799 if (ld
->read_req
== NULL
) {
800 status
= TLDAP_NO_MEMORY
;
803 tevent_req_set_callback(ld
->read_req
, tldap_msg_received
, ld
);
807 tldap_context_disconnect(ld
, status
);
810 static TLDAPRC
tldap_msg_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
811 struct tldap_message
**pmsg
)
813 struct tldap_msg_state
*state
= tevent_req_data(
814 req
, struct tldap_msg_state
);
815 struct tldap_message
*msg
;
819 if (tevent_req_is_ldap_error(req
, &err
)) {
823 if (!asn1_peek_uint8(state
->data
, &msgtype
)) {
824 return TLDAP_PROTOCOL_ERROR
;
828 return TLDAP_SUCCESS
;
831 msg
= talloc_zero(mem_ctx
, struct tldap_message
);
833 return TLDAP_NO_MEMORY
;
837 msg
->inbuf
= talloc_move(msg
, &state
->inbuf
);
838 msg
->data
= talloc_move(msg
, &state
->data
);
842 return TLDAP_SUCCESS
;
845 struct tldap_req_state
{
847 struct asn1_data
*out
;
848 struct tldap_message
*result
;
851 static struct tevent_req
*tldap_req_create(TALLOC_CTX
*mem_ctx
,
852 struct tldap_context
*ld
,
853 struct tldap_req_state
**pstate
)
855 struct tevent_req
*req
;
856 struct tldap_req_state
*state
;
858 req
= tevent_req_create(mem_ctx
, &state
, struct tldap_req_state
);
862 state
->out
= asn1_init(state
, ASN1_MAX_TREE_DEPTH
);
863 if (state
->out
== NULL
) {
866 state
->id
= tldap_next_msgid(ld
);
868 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
869 if (!asn1_write_Integer(state
->out
, state
->id
)) goto err
;
880 static void tldap_save_msg(struct tldap_context
*ld
, struct tevent_req
*req
)
882 struct tldap_req_state
*state
= tevent_req_data(
883 req
, struct tldap_req_state
);
885 TALLOC_FREE(ld
->last_msg
);
886 ld
->last_msg
= talloc_move(ld
, &state
->result
);
889 static char *blob2string_talloc(TALLOC_CTX
*mem_ctx
, DATA_BLOB blob
)
891 char *result
= talloc_array(mem_ctx
, char, blob
.length
+1);
893 if (result
== NULL
) {
897 memcpy(result
, blob
.data
, blob
.length
);
898 result
[blob
.length
] = '\0';
902 static bool asn1_read_OctetString_talloc(TALLOC_CTX
*mem_ctx
,
903 struct asn1_data
*data
,
908 if (!asn1_read_OctetString(data
, mem_ctx
, &string
))
911 result
= blob2string_talloc(mem_ctx
, string
);
913 data_blob_free(&string
);
915 if (result
== NULL
) {
922 static bool tldap_decode_controls(struct tldap_req_state
*state
);
924 static bool tldap_decode_response(struct tldap_req_state
*state
)
926 struct asn1_data
*data
= state
->result
->data
;
927 struct tldap_message
*msg
= state
->result
;
931 ok
&= asn1_read_enumerated(data
, &rc
);
933 msg
->lderr
= TLDAP_RC(rc
);
936 ok
&= asn1_read_OctetString_talloc(msg
, data
, &msg
->res_matcheddn
);
937 ok
&= asn1_read_OctetString_talloc(msg
, data
,
938 &msg
->res_diagnosticmessage
);
940 if (asn1_peek_tag(data
, ASN1_CONTEXT(3))) {
941 ok
&= asn1_start_tag(data
, ASN1_CONTEXT(3));
942 ok
&= asn1_read_OctetString_talloc(msg
, data
,
944 ok
&= asn1_end_tag(data
);
946 msg
->res_referral
= NULL
;
952 static void tldap_sasl_bind_done(struct tevent_req
*subreq
);
954 struct tevent_req
*tldap_sasl_bind_send(TALLOC_CTX
*mem_ctx
,
955 struct tevent_context
*ev
,
956 struct tldap_context
*ld
,
958 const char *mechanism
,
960 struct tldap_control
*sctrls
,
962 struct tldap_control
*cctrls
,
965 struct tevent_req
*req
, *subreq
;
966 struct tldap_req_state
*state
;
968 req
= tldap_req_create(mem_ctx
, ld
, &state
);
977 if (!asn1_push_tag(state
->out
, TLDAP_REQ_BIND
)) goto err
;
978 if (!asn1_write_Integer(state
->out
, ld
->ld_version
)) goto err
;
979 if (!asn1_write_OctetString(state
->out
, dn
, strlen(dn
))) goto err
;
981 if (mechanism
== NULL
) {
982 if (!asn1_push_tag(state
->out
, ASN1_CONTEXT_SIMPLE(0))) goto err
;
983 if (!asn1_write(state
->out
, creds
->data
, creds
->length
)) goto err
;
984 if (!asn1_pop_tag(state
->out
)) goto err
;
986 if (!asn1_push_tag(state
->out
, ASN1_CONTEXT(3))) goto err
;
987 if (!asn1_write_OctetString(state
->out
, mechanism
,
988 strlen(mechanism
))) goto err
;
989 if ((creds
!= NULL
) && (creds
->data
!= NULL
)) {
990 if (!asn1_write_OctetString(state
->out
, creds
->data
,
991 creds
->length
)) goto err
;
993 if (!asn1_pop_tag(state
->out
)) goto err
;
996 if (!asn1_pop_tag(state
->out
)) goto err
;
998 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
1000 if (tevent_req_nomem(subreq
, req
)) {
1001 return tevent_req_post(req
, ev
);
1003 tevent_req_set_callback(subreq
, tldap_sasl_bind_done
, req
);
1008 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
1009 return tevent_req_post(req
, ev
);
1012 static void tldap_sasl_bind_done(struct tevent_req
*subreq
)
1014 struct tevent_req
*req
= tevent_req_callback_data(
1015 subreq
, struct tevent_req
);
1016 struct tldap_req_state
*state
= tevent_req_data(
1017 req
, struct tldap_req_state
);
1021 rc
= tldap_msg_recv(subreq
, state
, &state
->result
);
1022 TALLOC_FREE(subreq
);
1023 if (tevent_req_ldap_error(req
, rc
)) {
1026 if (state
->result
->type
!= TLDAP_RES_BIND
) {
1027 tevent_req_ldap_error(req
, TLDAP_PROTOCOL_ERROR
);
1031 ok
= asn1_start_tag(state
->result
->data
, TLDAP_RES_BIND
);
1032 ok
&= tldap_decode_response(state
);
1034 if (asn1_peek_tag(state
->result
->data
, ASN1_CONTEXT_SIMPLE(7))) {
1037 ok
&= asn1_start_tag(state
->result
->data
,
1038 ASN1_CONTEXT_SIMPLE(7));
1043 len
= asn1_tag_remaining(state
->result
->data
);
1048 state
->result
->res_serverSaslCreds
=
1049 data_blob_talloc(state
->result
, NULL
, len
);
1050 if (state
->result
->res_serverSaslCreds
.data
== NULL
) {
1054 ok
= asn1_read(state
->result
->data
,
1055 state
->result
->res_serverSaslCreds
.data
,
1056 state
->result
->res_serverSaslCreds
.length
);
1058 ok
&= asn1_end_tag(state
->result
->data
);
1061 ok
&= asn1_end_tag(state
->result
->data
);
1067 if (!TLDAP_RC_IS_SUCCESS(state
->result
->lderr
) &&
1068 !TLDAP_RC_EQUAL(state
->result
->lderr
,
1069 TLDAP_SASL_BIND_IN_PROGRESS
)) {
1070 tevent_req_ldap_error(req
, state
->result
->lderr
);
1073 tevent_req_done(req
);
1077 tevent_req_ldap_error(req
, TLDAP_DECODING_ERROR
);
1081 TLDAPRC
tldap_sasl_bind_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
1082 DATA_BLOB
*serverSaslCreds
)
1084 struct tldap_req_state
*state
= tevent_req_data(
1085 req
, struct tldap_req_state
);
1088 if (tevent_req_is_ldap_error(req
, &rc
)) {
1092 if (serverSaslCreds
!= NULL
) {
1093 serverSaslCreds
->data
= talloc_move(
1094 mem_ctx
, &state
->result
->res_serverSaslCreds
.data
);
1095 serverSaslCreds
->length
=
1096 state
->result
->res_serverSaslCreds
.length
;
1099 return state
->result
->lderr
;
1102 TLDAPRC
tldap_sasl_bind(struct tldap_context
*ld
,
1104 const char *mechanism
,
1106 struct tldap_control
*sctrls
,
1108 struct tldap_control
*cctrls
,
1110 TALLOC_CTX
*mem_ctx
,
1111 DATA_BLOB
*serverSaslCreds
)
1113 TALLOC_CTX
*frame
= talloc_stackframe();
1114 struct tevent_context
*ev
;
1115 struct tevent_req
*req
;
1116 TLDAPRC rc
= TLDAP_NO_MEMORY
;
1118 ev
= samba_tevent_context_init(frame
);
1122 req
= tldap_sasl_bind_send(frame
, ev
, ld
, dn
, mechanism
, creds
,
1123 sctrls
, num_sctrls
, cctrls
, num_cctrls
);
1127 if (!tevent_req_poll(req
, ev
)) {
1128 rc
= TLDAP_OPERATIONS_ERROR
;
1131 rc
= tldap_sasl_bind_recv(req
, mem_ctx
, serverSaslCreds
);
1132 tldap_save_msg(ld
, req
);
1138 struct tevent_req
*tldap_simple_bind_send(TALLOC_CTX
*mem_ctx
,
1139 struct tevent_context
*ev
,
1140 struct tldap_context
*ld
,
1146 if (passwd
!= NULL
) {
1147 cred
.data
= discard_const_p(uint8_t, passwd
);
1148 cred
.length
= strlen(passwd
);
1150 cred
.data
= discard_const_p(uint8_t, "");
1153 return tldap_sasl_bind_send(mem_ctx
, ev
, ld
, dn
, NULL
, &cred
, NULL
, 0,
1157 TLDAPRC
tldap_simple_bind_recv(struct tevent_req
*req
)
1159 return tldap_sasl_bind_recv(req
, NULL
, NULL
);
1162 TLDAPRC
tldap_simple_bind(struct tldap_context
*ld
, const char *dn
,
1167 if (passwd
!= NULL
) {
1168 cred
.data
= discard_const_p(uint8_t, passwd
);
1169 cred
.length
= strlen(passwd
);
1171 cred
.data
= discard_const_p(uint8_t, "");
1174 return tldap_sasl_bind(ld
, dn
, NULL
, &cred
, NULL
, 0, NULL
, 0,
1178 /*****************************************************************************/
1180 /* can't use isalpha() as only a strict set is valid for LDAP */
1182 static bool tldap_is_alpha(char c
)
1184 return (((c
>= 'a') && (c
<= 'z')) || \
1185 ((c
>= 'A') && (c
<= 'Z')));
1188 static bool tldap_is_adh(char c
)
1190 return tldap_is_alpha(c
) || isdigit(c
) || (c
== '-');
1193 #define TLDAP_FILTER_AND ASN1_CONTEXT(0)
1194 #define TLDAP_FILTER_OR ASN1_CONTEXT(1)
1195 #define TLDAP_FILTER_NOT ASN1_CONTEXT(2)
1196 #define TLDAP_FILTER_EQ ASN1_CONTEXT(3)
1197 #define TLDAP_FILTER_SUB ASN1_CONTEXT(4)
1198 #define TLDAP_FILTER_LE ASN1_CONTEXT(5)
1199 #define TLDAP_FILTER_GE ASN1_CONTEXT(6)
1200 #define TLDAP_FILTER_PRES ASN1_CONTEXT_SIMPLE(7)
1201 #define TLDAP_FILTER_APX ASN1_CONTEXT(8)
1202 #define TLDAP_FILTER_EXT ASN1_CONTEXT(9)
1204 #define TLDAP_SUB_INI ASN1_CONTEXT_SIMPLE(0)
1205 #define TLDAP_SUB_ANY ASN1_CONTEXT_SIMPLE(1)
1206 #define TLDAP_SUB_FIN ASN1_CONTEXT_SIMPLE(2)
1209 /* oid's should be numerical only in theory,
1210 * but apparently some broken servers may have alphanum aliases instead.
1211 * Do like openldap libraries and allow alphanum aliases for oids, but
1212 * do not allow Tagging options in that case.
1214 static bool tldap_is_attrdesc(const char *s
, int len
, bool no_tagopts
)
1216 bool is_oid
= false;
1220 /* first char has stricter rules */
1223 } else if (!tldap_is_alpha(*s
)) {
1224 /* bad first char */
1228 for (i
= 1; i
< len
; i
++) {
1231 if (isdigit(s
[i
])) {
1244 if (tldap_is_adh(s
[i
])) {
1251 /* no tagging options */
1258 if ((i
+ 1) == len
) {
1276 /* this function copies the value until the closing parenthesis is found. */
1277 static char *tldap_get_val(TALLOC_CTX
*memctx
,
1278 const char *value
, const char **_s
)
1280 const char *s
= value
;
1282 /* find terminator */
1285 if (s
&& (*(s
- 1) == '\\')) {
1291 if (!s
|| !(*s
== ')')) {
1292 /* malformed filter */
1298 return talloc_strndup(memctx
, value
, s
- value
);
1301 static int tldap_hex2char(const char *x
)
1303 if (isxdigit(x
[0]) && isxdigit(x
[1])) {
1304 const char h1
= x
[0], h2
= x
[1];
1307 if (h1
>= 'a') c
= h1
- (int)'a' + 10;
1308 else if (h1
>= 'A') c
= h1
- (int)'A' + 10;
1309 else if (h1
>= '0') c
= h1
- (int)'0';
1311 if (h2
>= 'a') c
+= h2
- (int)'a' + 10;
1312 else if (h2
>= 'A') c
+= h2
- (int)'A' + 10;
1313 else if (h2
>= '0') c
+= h2
- (int)'0';
1321 static bool tldap_find_first_star(const char *val
, const char **star
)
1325 for (s
= val
; *s
; s
++) {
1328 if (isxdigit(s
[1]) && isxdigit(s
[2])) {
1332 /* not hex based escape, check older syntax */
1341 /* invalid escape sequence */
1346 /* end of val, nothing found */
1356 /* string ended without closing parenthesis, filter is malformed */
1360 static bool tldap_unescape_inplace(char *value
, size_t *val_len
)
1365 for (i
= 0,p
= 0; i
< *val_len
; i
++) {
1371 /* these must be escaped */
1375 if (!value
[i
+ 1]) {
1381 /* LDAPv3 escaped */
1382 c
= tldap_hex2char(&value
[i
]);
1383 if (c
>= 0 && c
< 256) {
1390 /* LDAPv2 escaped */
1396 value
[p
] = value
[i
];
1407 value
[p
] = value
[i
];
1416 static bool tldap_push_filter_basic(struct tldap_context
*ld
,
1417 struct asn1_data
*data
,
1419 static bool tldap_push_filter_substring(struct tldap_context
*ld
,
1420 struct asn1_data
*data
,
1423 static bool tldap_push_filter_int(struct tldap_context
*ld
,
1424 struct asn1_data
*data
,
1427 const char *s
= *_s
;
1431 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1432 "Incomplete or malformed filter\n");
1437 /* we are right after a parenthesis,
1438 * find out what op we have at hand */
1441 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "Filter op: AND\n");
1442 if (!asn1_push_tag(data
, TLDAP_FILTER_AND
)) return false;
1447 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "Filter op: OR\n");
1448 if (!asn1_push_tag(data
, TLDAP_FILTER_OR
)) return false;
1453 tldap_debug(ld
, TLDAP_DEBUG_TRACE
, "Filter op: NOT\n");
1454 if (!asn1_push_tag(data
, TLDAP_FILTER_NOT
)) return false;
1456 ret
= tldap_push_filter_int(ld
, data
, &s
);
1460 if (!asn1_pop_tag(data
)) return false;
1465 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1466 "Invalid parenthesis '%c'\n", *s
);
1470 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1471 "Invalid filter termination\n");
1475 ret
= tldap_push_filter_basic(ld
, data
, &s
);
1482 /* only and/or filters get here.
1483 * go through the list of filters */
1486 /* RFC 4526: empty and/or */
1487 if (!asn1_pop_tag(data
)) return false;
1492 ret
= tldap_push_filter_int(ld
, data
, &s
);
1498 /* end of list, return */
1499 if (!asn1_pop_tag(data
)) return false;
1506 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1507 "Incomplete or malformed filter\n");
1512 if (asn1_has_error(data
)) {
1521 static bool tldap_push_filter_basic(struct tldap_context
*ld
,
1522 struct asn1_data
*data
,
1525 TALLOC_CTX
*tmpctx
= talloc_tos();
1526 const char *s
= *_s
;
1534 size_t type_len
= 0;
1537 bool write_octect
= true;
1540 eq
= strchr(s
, '=');
1542 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1543 "Invalid filter, missing equal sign\n");
1552 if (!asn1_push_tag(data
, TLDAP_FILTER_LE
)) return false;
1556 if (!asn1_push_tag(data
, TLDAP_FILTER_GE
)) return false;
1560 if (!asn1_push_tag(data
, TLDAP_FILTER_APX
)) return false;
1564 if (!asn1_push_tag(data
, TLDAP_FILTER_EXT
)) return false;
1565 write_octect
= false;
1571 if (*s
== ':') { /* [:dn]:rule:= value */
1573 /* malformed filter */
1577 } else { /* type[:dn][:rule]:= value */
1579 dn
= strchr(s
, ':');
1580 type_len
= dn
- type
;
1581 if (dn
== e
) { /* type:= value */
1588 rule
= strchr(dn
, ':');
1592 if ((rule
== dn
+ 1) || rule
+ 1 == e
) {
1593 /* malformed filter, contains "::" */
1597 if (strncasecmp_m(dn
, "dn:", 3) != 0) {
1602 /* malformed filter. With two
1603 * optionals, the first must be "dn"
1616 if (!type
&& !dn
&& !rule
) {
1617 /* malformed filter, there must be at least one */
1622 MatchingRuleAssertion ::= SEQUENCE {
1623 matchingRule [1] MatchingRuleID OPTIONAL,
1624 type [2] AttributeDescription OPTIONAL,
1625 matchValue [3] AssertionValue,
1626 dnAttributes [4] BOOLEAN DEFAULT FALSE
1630 /* check and add rule */
1632 ret
= tldap_is_attrdesc(rule
, e
- rule
, true);
1636 if (!asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(1))) return false;
1637 if (!asn1_write(data
, rule
, e
- rule
)) return false;
1638 if (!asn1_pop_tag(data
)) return false;
1641 /* check and add type */
1643 ret
= tldap_is_attrdesc(type
, type_len
, false);
1647 if (!asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(2))) return false;
1648 if (!asn1_write(data
, type
, type_len
)) return false;
1649 if (!asn1_pop_tag(data
)) return false;
1652 uval
= tldap_get_val(tmpctx
, val
, _s
);
1656 uval_len
= *_s
- val
;
1657 ret
= tldap_unescape_inplace(uval
, &uval_len
);
1662 if (!asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(3))) return false;
1663 if (!asn1_write(data
, uval
, uval_len
)) return false;
1664 if (!asn1_pop_tag(data
)) return false;
1666 if (!asn1_push_tag(data
, ASN1_CONTEXT_SIMPLE(4))) return false;
1667 if (!asn1_write_uint8(data
, dn
?1:0)) return false;
1668 if (!asn1_pop_tag(data
)) return false;
1674 ret
= tldap_is_attrdesc(s
, e
- s
, false);
1679 if (strncmp(val
, "*)", 2) == 0) {
1681 if (!asn1_push_tag(data
, TLDAP_FILTER_PRES
)) return false;
1682 if (!asn1_write(data
, s
, e
- s
)) return false;
1684 write_octect
= false;
1688 ret
= tldap_find_first_star(val
, &star
);
1694 if (!asn1_push_tag(data
, TLDAP_FILTER_SUB
)) return false;
1695 if (!asn1_write_OctetString(data
, s
, e
- s
)) return false;
1696 ret
= tldap_push_filter_substring(ld
, data
, val
, &s
);
1701 write_octect
= false;
1705 /* if nothing else, then it is just equality */
1706 if (!asn1_push_tag(data
, TLDAP_FILTER_EQ
)) return false;
1707 write_octect
= true;
1712 uval
= tldap_get_val(tmpctx
, val
, _s
);
1716 uval_len
= *_s
- val
;
1717 ret
= tldap_unescape_inplace(uval
, &uval_len
);
1722 if (!asn1_write_OctetString(data
, s
, e
- s
)) return false;
1723 if (!asn1_write_OctetString(data
, uval
, uval_len
)) return false;
1726 if (asn1_has_error(data
)) {
1729 return asn1_pop_tag(data
);
1732 static bool tldap_push_filter_substring(struct tldap_context
*ld
,
1733 struct asn1_data
*data
,
1737 TALLOC_CTX
*tmpctx
= talloc_tos();
1738 bool initial
= true;
1745 SubstringFilter ::= SEQUENCE {
1746 type AttributeDescription,
1747 -- at least one must be present
1748 substrings SEQUENCE OF CHOICE {
1749 initial [0] LDAPString,
1751 final [2] LDAPString } }
1753 if (!asn1_push_tag(data
, ASN1_SEQUENCE(0))) return false;
1756 ret
= tldap_find_first_star(val
, &star
);
1760 chunk_len
= star
- val
;
1764 if (!initial
&& chunk_len
== 0) {
1765 /* found '**', which is illegal */
1781 if (initial
&& chunk_len
== 0) {
1787 chunk
= talloc_strndup(tmpctx
, val
, chunk_len
);
1791 ret
= tldap_unescape_inplace(chunk
, &chunk_len
);
1798 if (!asn1_push_tag(data
, TLDAP_SUB_INI
)) return false;
1801 if (!asn1_push_tag(data
, TLDAP_SUB_ANY
)) return false;
1805 if (!asn1_push_tag(data
, TLDAP_SUB_FIN
)) return false;
1811 if (!asn1_write(data
, chunk
, chunk_len
)) return false;
1812 if (!asn1_pop_tag(data
)) return false;
1816 } while (*star
== '*');
1820 /* end of sequence */
1821 return asn1_pop_tag(data
);
1824 /* NOTE: although openldap libraries allow for spaces in some places, mostly
1825 * around parentheses, we do not allow any spaces (except in values of
1826 * course) as I couldn't find any place in RFC 4512 or RFC 4515 where
1827 * leading or trailing spaces were allowed.
1829 static bool tldap_push_filter(struct tldap_context
*ld
,
1830 struct asn1_data
*data
,
1833 const char *s
= filter
;
1836 ret
= tldap_push_filter_int(ld
, data
, &s
);
1838 tldap_debug(ld
, TLDAP_DEBUG_ERROR
,
1839 "Incomplete or malformed filter\n");
1845 /*****************************************************************************/
1847 static void tldap_search_done(struct tevent_req
*subreq
);
1849 struct tevent_req
*tldap_search_send(TALLOC_CTX
*mem_ctx
,
1850 struct tevent_context
*ev
,
1851 struct tldap_context
*ld
,
1852 const char *base
, int scope
,
1857 struct tldap_control
*sctrls
,
1859 struct tldap_control
*cctrls
,
1865 struct tevent_req
*req
, *subreq
;
1866 struct tldap_req_state
*state
;
1869 req
= tldap_req_create(mem_ctx
, ld
, &state
);
1874 if (!asn1_push_tag(state
->out
, TLDAP_REQ_SEARCH
)) goto encoding_error
;
1875 if (!asn1_write_OctetString(state
->out
, base
, strlen(base
))) goto encoding_error
;
1876 if (!asn1_write_enumerated(state
->out
, scope
)) goto encoding_error
;
1877 if (!asn1_write_enumerated(state
->out
, deref
)) goto encoding_error
;
1878 if (!asn1_write_Integer(state
->out
, sizelimit
)) goto encoding_error
;
1879 if (!asn1_write_Integer(state
->out
, timelimit
)) goto encoding_error
;
1880 if (!asn1_write_BOOLEAN(state
->out
, attrsonly
)) goto encoding_error
;
1882 if (!tldap_push_filter(ld
, state
->out
, filter
)) {
1883 goto encoding_error
;
1886 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto encoding_error
;
1887 for (i
=0; i
<num_attrs
; i
++) {
1888 if (!asn1_write_OctetString(state
->out
, attrs
[i
], strlen(attrs
[i
]))) goto encoding_error
;
1890 if (!asn1_pop_tag(state
->out
)) goto encoding_error
;
1891 if (!asn1_pop_tag(state
->out
)) goto encoding_error
;
1893 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
1894 sctrls
, num_sctrls
);
1895 if (tevent_req_nomem(subreq
, req
)) {
1896 return tevent_req_post(req
, ev
);
1898 tevent_req_set_callback(subreq
, tldap_search_done
, req
);
1902 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
1903 return tevent_req_post(req
, ev
);
1906 static void tldap_search_done(struct tevent_req
*subreq
)
1908 struct tevent_req
*req
= tevent_req_callback_data(
1909 subreq
, struct tevent_req
);
1910 struct tldap_req_state
*state
= tevent_req_data(
1911 req
, struct tldap_req_state
);
1914 rc
= tldap_msg_recv(subreq
, state
, &state
->result
);
1915 if (tevent_req_ldap_error(req
, rc
)) {
1918 switch (state
->result
->type
) {
1919 case TLDAP_RES_SEARCH_ENTRY
:
1920 case TLDAP_RES_SEARCH_REFERENCE
:
1921 if (!tldap_msg_set_pending(subreq
)) {
1922 tevent_req_oom(req
);
1925 tevent_req_notify_callback(req
);
1927 case TLDAP_RES_SEARCH_RESULT
:
1928 TALLOC_FREE(subreq
);
1929 if (!asn1_start_tag(state
->result
->data
,
1930 state
->result
->type
) ||
1931 !tldap_decode_response(state
) ||
1932 !asn1_end_tag(state
->result
->data
) ||
1933 !tldap_decode_controls(state
)) {
1934 tevent_req_ldap_error(req
, TLDAP_DECODING_ERROR
);
1937 tevent_req_done(req
);
1940 tevent_req_ldap_error(req
, TLDAP_PROTOCOL_ERROR
);
1945 TLDAPRC
tldap_search_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
1946 struct tldap_message
**pmsg
)
1948 struct tldap_req_state
*state
= tevent_req_data(
1949 req
, struct tldap_req_state
);
1952 if (!tevent_req_is_in_progress(req
)
1953 && tevent_req_is_ldap_error(req
, &rc
)) {
1957 if (tevent_req_is_in_progress(req
)) {
1958 switch (state
->result
->type
) {
1959 case TLDAP_RES_SEARCH_ENTRY
:
1960 case TLDAP_RES_SEARCH_REFERENCE
:
1963 return TLDAP_OPERATIONS_ERROR
;
1967 *pmsg
= talloc_move(mem_ctx
, &state
->result
);
1968 return TLDAP_SUCCESS
;
1971 struct tldap_search_all_state
{
1972 struct tldap_message
**msgs
;
1973 struct tldap_message
*result
;
1976 static void tldap_search_all_done(struct tevent_req
*subreq
);
1978 struct tevent_req
*tldap_search_all_send(
1979 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
1980 struct tldap_context
*ld
, const char *base
, int scope
,
1981 const char *filter
, const char **attrs
, int num_attrs
, int attrsonly
,
1982 struct tldap_control
*sctrls
, int num_sctrls
,
1983 struct tldap_control
*cctrls
, int num_cctrls
,
1984 int timelimit
, int sizelimit
, int deref
)
1986 struct tevent_req
*req
, *subreq
;
1987 struct tldap_search_all_state
*state
;
1989 req
= tevent_req_create(mem_ctx
, &state
,
1990 struct tldap_search_all_state
);
1995 subreq
= tldap_search_send(state
, ev
, ld
, base
, scope
, filter
,
1996 attrs
, num_attrs
, attrsonly
,
1997 sctrls
, num_sctrls
, cctrls
, num_cctrls
,
1998 timelimit
, sizelimit
, deref
);
1999 if (tevent_req_nomem(subreq
, req
)) {
2000 return tevent_req_post(req
, ev
);
2002 tevent_req_set_callback(subreq
, tldap_search_all_done
, req
);
2006 static void tldap_search_all_done(struct tevent_req
*subreq
)
2008 struct tevent_req
*req
= tevent_req_callback_data(
2009 subreq
, struct tevent_req
);
2010 struct tldap_search_all_state
*state
= tevent_req_data(
2011 req
, struct tldap_search_all_state
);
2012 struct tldap_message
*msg
, **tmp
;
2017 rc
= tldap_search_recv(subreq
, state
, &msg
);
2018 /* No TALLOC_FREE(subreq), this is multi-step */
2019 if (tevent_req_ldap_error(req
, rc
)) {
2023 msgtype
= tldap_msg_type(msg
);
2024 if (msgtype
== TLDAP_RES_SEARCH_RESULT
) {
2025 state
->result
= msg
;
2026 tevent_req_done(req
);
2030 num_msgs
= talloc_array_length(state
->msgs
);
2032 tmp
= talloc_realloc(state
, state
->msgs
, struct tldap_message
*,
2034 if (tevent_req_nomem(tmp
, req
)) {
2038 state
->msgs
[num_msgs
] = talloc_move(state
->msgs
, &msg
);
2041 TLDAPRC
tldap_search_all_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
2042 struct tldap_message
***msgs
,
2043 struct tldap_message
**result
)
2045 struct tldap_search_all_state
*state
= tevent_req_data(
2046 req
, struct tldap_search_all_state
);
2049 if (tevent_req_is_ldap_error(req
, &rc
)) {
2054 *msgs
= talloc_move(mem_ctx
, &state
->msgs
);
2056 if (result
!= NULL
) {
2057 *result
= talloc_move(mem_ctx
, &state
->result
);
2060 return TLDAP_SUCCESS
;
2063 TLDAPRC
tldap_search(struct tldap_context
*ld
,
2064 const char *base
, int scope
, const char *filter
,
2065 const char **attrs
, int num_attrs
, int attrsonly
,
2066 struct tldap_control
*sctrls
, int num_sctrls
,
2067 struct tldap_control
*cctrls
, int num_cctrls
,
2068 int timelimit
, int sizelimit
, int deref
,
2069 TALLOC_CTX
*mem_ctx
, struct tldap_message
***pmsgs
)
2072 struct tevent_context
*ev
;
2073 struct tevent_req
*req
;
2074 TLDAPRC rc
= TLDAP_NO_MEMORY
;
2075 struct tldap_message
**msgs
;
2076 struct tldap_message
*result
;
2078 if (tldap_pending_reqs(ld
)) {
2082 frame
= talloc_stackframe();
2084 ev
= samba_tevent_context_init(frame
);
2088 req
= tldap_search_all_send(frame
, ev
, ld
, base
, scope
, filter
,
2089 attrs
, num_attrs
, attrsonly
,
2090 sctrls
, num_sctrls
, cctrls
, num_cctrls
,
2091 timelimit
, sizelimit
, deref
);
2095 if (!tevent_req_poll(req
, ev
)) {
2096 rc
= TLDAP_OPERATIONS_ERROR
;
2099 rc
= tldap_search_all_recv(req
, frame
, &msgs
, &result
);
2101 if (!TLDAP_RC_IS_SUCCESS(rc
)) {
2105 TALLOC_FREE(ld
->last_msg
);
2106 ld
->last_msg
= talloc_move(ld
, &result
);
2108 if (pmsgs
!= NULL
) {
2109 *pmsgs
= talloc_move(mem_ctx
, &msgs
);
2116 static bool tldap_parse_search_entry(struct tldap_message
*msg
)
2118 int num_attribs
= 0;
2120 if (msg
->type
!= TLDAP_RES_SEARCH_ENTRY
) {
2123 if (!asn1_start_tag(msg
->data
, TLDAP_RES_SEARCH_ENTRY
)) {
2129 if (!asn1_read_OctetString_talloc(msg
, msg
->data
, &msg
->dn
)) return false;
2131 if (msg
->dn
== NULL
) {
2136 * Attributes: We overallocate msg->attribs by one, so that while
2137 * looping over the attributes we can directly parse into the last
2138 * array element. Same for the values in the inner loop.
2141 msg
->attribs
= talloc_array(msg
, struct tldap_attribute
, 1);
2142 if (msg
->attribs
== NULL
) {
2146 if (!asn1_start_tag(msg
->data
, ASN1_SEQUENCE(0))) return false;
2147 while (asn1_peek_tag(msg
->data
, ASN1_SEQUENCE(0))) {
2148 struct tldap_attribute
*attrib
;
2151 attrib
= &msg
->attribs
[num_attribs
];
2152 attrib
->values
= talloc_array(msg
->attribs
, DATA_BLOB
, 1);
2153 if (attrib
->values
== NULL
) {
2156 if (!asn1_start_tag(msg
->data
, ASN1_SEQUENCE(0))) return false;
2157 if (!asn1_read_OctetString_talloc(msg
->attribs
, msg
->data
,
2158 &attrib
->name
)) return false;
2159 if (!asn1_start_tag(msg
->data
, ASN1_SET
)) return false;
2161 while (asn1_peek_tag(msg
->data
, ASN1_OCTET_STRING
)) {
2162 if (!asn1_read_OctetString(msg
->data
, msg
,
2163 &attrib
->values
[num_values
])) return false;
2165 attrib
->values
= talloc_realloc(
2166 msg
->attribs
, attrib
->values
, DATA_BLOB
,
2168 if (attrib
->values
== NULL
) {
2173 attrib
->values
= talloc_realloc(msg
->attribs
, attrib
->values
,
2174 DATA_BLOB
, num_values
);
2175 attrib
->num_values
= num_values
;
2177 if (!asn1_end_tag(msg
->data
)) return false; /* ASN1_SET */
2178 if (!asn1_end_tag(msg
->data
)) return false; /* ASN1_SEQUENCE(0) */
2179 msg
->attribs
= talloc_realloc(
2180 msg
, msg
->attribs
, struct tldap_attribute
,
2182 if (msg
->attribs
== NULL
) {
2187 msg
->attribs
= talloc_realloc(
2188 msg
, msg
->attribs
, struct tldap_attribute
, num_attribs
);
2189 return asn1_end_tag(msg
->data
);
2192 bool tldap_entry_dn(struct tldap_message
*msg
, char **dn
)
2194 if ((msg
->dn
== NULL
) && (!tldap_parse_search_entry(msg
))) {
2201 bool tldap_entry_attributes(struct tldap_message
*msg
,
2202 struct tldap_attribute
**attributes
,
2203 int *num_attributes
)
2205 if ((msg
->dn
== NULL
) && (!tldap_parse_search_entry(msg
))) {
2208 *attributes
= msg
->attribs
;
2209 *num_attributes
= talloc_array_length(msg
->attribs
);
2213 static bool tldap_decode_controls(struct tldap_req_state
*state
)
2215 struct tldap_message
*msg
= state
->result
;
2216 struct asn1_data
*data
= msg
->data
;
2217 struct tldap_control
*sctrls
= NULL
;
2218 int num_controls
= 0;
2221 msg
->res_sctrls
= NULL
;
2223 if (!asn1_peek_tag(data
, ASN1_CONTEXT(0))) {
2227 if (!asn1_start_tag(data
, ASN1_CONTEXT(0))) goto out
;
2229 while (asn1_peek_tag(data
, ASN1_SEQUENCE(0))) {
2230 struct tldap_control
*c
;
2233 sctrls
= talloc_realloc(msg
, sctrls
, struct tldap_control
,
2235 if (sctrls
== NULL
) {
2238 c
= &sctrls
[num_controls
];
2240 if (!asn1_start_tag(data
, ASN1_SEQUENCE(0))) goto out
;
2241 if (!asn1_read_OctetString_talloc(msg
, data
, &oid
)) goto out
;
2242 if (asn1_has_error(data
) || (oid
== NULL
)) {
2246 if (asn1_peek_tag(data
, ASN1_BOOLEAN
)) {
2247 if (!asn1_read_BOOLEAN(data
, &c
->critical
)) goto out
;
2249 c
->critical
= false;
2251 c
->value
= data_blob_null
;
2252 if (asn1_peek_tag(data
, ASN1_OCTET_STRING
) &&
2253 !asn1_read_OctetString(data
, msg
, &c
->value
)) {
2256 if (!asn1_end_tag(data
)) goto out
; /* ASN1_SEQUENCE(0) */
2261 if (!asn1_end_tag(data
)) goto out
; /* ASN1_CONTEXT(0) */
2268 msg
->res_sctrls
= sctrls
;
2270 TALLOC_FREE(sctrls
);
2275 static void tldap_simple_done(struct tevent_req
*subreq
, int type
)
2277 struct tevent_req
*req
= tevent_req_callback_data(
2278 subreq
, struct tevent_req
);
2279 struct tldap_req_state
*state
= tevent_req_data(
2280 req
, struct tldap_req_state
);
2283 rc
= tldap_msg_recv(subreq
, state
, &state
->result
);
2284 TALLOC_FREE(subreq
);
2285 if (tevent_req_ldap_error(req
, rc
)) {
2288 if (state
->result
->type
!= type
) {
2289 tevent_req_ldap_error(req
, TLDAP_PROTOCOL_ERROR
);
2292 if (!asn1_start_tag(state
->result
->data
, state
->result
->type
) ||
2293 !tldap_decode_response(state
) ||
2294 !asn1_end_tag(state
->result
->data
) ||
2295 !tldap_decode_controls(state
)) {
2296 tevent_req_ldap_error(req
, TLDAP_DECODING_ERROR
);
2299 if (!TLDAP_RC_IS_SUCCESS(state
->result
->lderr
)) {
2300 tevent_req_ldap_error(req
, state
->result
->lderr
);
2303 tevent_req_done(req
);
2306 static TLDAPRC
tldap_simple_recv(struct tevent_req
*req
)
2309 if (tevent_req_is_ldap_error(req
, &rc
)) {
2312 return TLDAP_SUCCESS
;
2315 static void tldap_add_done(struct tevent_req
*subreq
);
2317 struct tevent_req
*tldap_add_send(TALLOC_CTX
*mem_ctx
,
2318 struct tevent_context
*ev
,
2319 struct tldap_context
*ld
,
2321 struct tldap_mod
*attributes
,
2323 struct tldap_control
*sctrls
,
2325 struct tldap_control
*cctrls
,
2328 struct tevent_req
*req
, *subreq
;
2329 struct tldap_req_state
*state
;
2332 req
= tldap_req_create(mem_ctx
, ld
, &state
);
2337 if (!asn1_push_tag(state
->out
, TLDAP_REQ_ADD
)) goto err
;
2338 if (!asn1_write_OctetString(state
->out
, dn
, strlen(dn
))) goto err
;
2339 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2341 for (i
=0; i
<num_attributes
; i
++) {
2342 struct tldap_mod
*attrib
= &attributes
[i
];
2343 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2344 if (!asn1_write_OctetString(state
->out
, attrib
->attribute
,
2345 strlen(attrib
->attribute
))) goto err
;
2346 if (!asn1_push_tag(state
->out
, ASN1_SET
)) goto err
;
2347 for (j
=0; j
<attrib
->num_values
; j
++) {
2348 if (!asn1_write_OctetString(state
->out
,
2349 attrib
->values
[j
].data
,
2350 attrib
->values
[j
].length
)) goto err
;
2352 if (!asn1_pop_tag(state
->out
)) goto err
;
2353 if (!asn1_pop_tag(state
->out
)) goto err
;
2356 if (!asn1_pop_tag(state
->out
)) goto err
;
2357 if (!asn1_pop_tag(state
->out
)) goto err
;
2359 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
2360 sctrls
, num_sctrls
);
2361 if (tevent_req_nomem(subreq
, req
)) {
2362 return tevent_req_post(req
, ev
);
2364 tevent_req_set_callback(subreq
, tldap_add_done
, req
);
2369 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
2370 return tevent_req_post(req
, ev
);
2373 static void tldap_add_done(struct tevent_req
*subreq
)
2375 tldap_simple_done(subreq
, TLDAP_RES_ADD
);
2378 TLDAPRC
tldap_add_recv(struct tevent_req
*req
)
2380 return tldap_simple_recv(req
);
2383 TLDAPRC
tldap_add(struct tldap_context
*ld
, const char *dn
,
2384 struct tldap_mod
*attributes
, int num_attributes
,
2385 struct tldap_control
*sctrls
, int num_sctrls
,
2386 struct tldap_control
*cctrls
, int num_cctrls
)
2388 TALLOC_CTX
*frame
= talloc_stackframe();
2389 struct tevent_context
*ev
;
2390 struct tevent_req
*req
;
2391 TLDAPRC rc
= TLDAP_NO_MEMORY
;
2393 ev
= samba_tevent_context_init(frame
);
2397 req
= tldap_add_send(frame
, ev
, ld
, dn
, attributes
, num_attributes
,
2398 sctrls
, num_sctrls
, cctrls
, num_cctrls
);
2402 if (!tevent_req_poll(req
, ev
)) {
2403 rc
= TLDAP_OPERATIONS_ERROR
;
2406 rc
= tldap_add_recv(req
);
2407 tldap_save_msg(ld
, req
);
2413 static void tldap_modify_done(struct tevent_req
*subreq
);
2415 struct tevent_req
*tldap_modify_send(TALLOC_CTX
*mem_ctx
,
2416 struct tevent_context
*ev
,
2417 struct tldap_context
*ld
,
2419 struct tldap_mod
*mods
, int num_mods
,
2420 struct tldap_control
*sctrls
,
2422 struct tldap_control
*cctrls
,
2425 struct tevent_req
*req
, *subreq
;
2426 struct tldap_req_state
*state
;
2429 req
= tldap_req_create(mem_ctx
, ld
, &state
);
2434 if (!asn1_push_tag(state
->out
, TLDAP_REQ_MODIFY
)) goto err
;
2435 if (!asn1_write_OctetString(state
->out
, dn
, strlen(dn
))) goto err
;
2436 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2438 for (i
=0; i
<num_mods
; i
++) {
2439 struct tldap_mod
*mod
= &mods
[i
];
2440 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2441 if (!asn1_write_enumerated(state
->out
, mod
->mod_op
)) goto err
;
2442 if (!asn1_push_tag(state
->out
, ASN1_SEQUENCE(0))) goto err
;
2443 if (!asn1_write_OctetString(state
->out
, mod
->attribute
,
2444 strlen(mod
->attribute
))) goto err
;
2445 if (!asn1_push_tag(state
->out
, ASN1_SET
)) goto err
;
2446 for (j
=0; j
<mod
->num_values
; j
++) {
2447 if (!asn1_write_OctetString(state
->out
,
2448 mod
->values
[j
].data
,
2449 mod
->values
[j
].length
)) goto err
;
2451 if (!asn1_pop_tag(state
->out
)) goto err
;
2452 if (!asn1_pop_tag(state
->out
)) goto err
;
2453 if (!asn1_pop_tag(state
->out
)) goto err
;
2456 if (!asn1_pop_tag(state
->out
)) goto err
;
2457 if (!asn1_pop_tag(state
->out
)) goto err
;
2459 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
2460 sctrls
, num_sctrls
);
2461 if (tevent_req_nomem(subreq
, req
)) {
2462 return tevent_req_post(req
, ev
);
2464 tevent_req_set_callback(subreq
, tldap_modify_done
, req
);
2469 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
2470 return tevent_req_post(req
, ev
);
2473 static void tldap_modify_done(struct tevent_req
*subreq
)
2475 tldap_simple_done(subreq
, TLDAP_RES_MODIFY
);
2478 TLDAPRC
tldap_modify_recv(struct tevent_req
*req
)
2480 return tldap_simple_recv(req
);
2483 TLDAPRC
tldap_modify(struct tldap_context
*ld
, const char *dn
,
2484 struct tldap_mod
*mods
, int num_mods
,
2485 struct tldap_control
*sctrls
, int num_sctrls
,
2486 struct tldap_control
*cctrls
, int num_cctrls
)
2488 TALLOC_CTX
*frame
= talloc_stackframe();
2489 struct tevent_context
*ev
;
2490 struct tevent_req
*req
;
2491 TLDAPRC rc
= TLDAP_NO_MEMORY
;
2493 ev
= samba_tevent_context_init(frame
);
2497 req
= tldap_modify_send(frame
, ev
, ld
, dn
, mods
, num_mods
,
2498 sctrls
, num_sctrls
, cctrls
, num_cctrls
);
2502 if (!tevent_req_poll(req
, ev
)) {
2503 rc
= TLDAP_OPERATIONS_ERROR
;
2506 rc
= tldap_modify_recv(req
);
2507 tldap_save_msg(ld
, req
);
2513 static void tldap_delete_done(struct tevent_req
*subreq
);
2515 struct tevent_req
*tldap_delete_send(TALLOC_CTX
*mem_ctx
,
2516 struct tevent_context
*ev
,
2517 struct tldap_context
*ld
,
2519 struct tldap_control
*sctrls
,
2521 struct tldap_control
*cctrls
,
2524 struct tevent_req
*req
, *subreq
;
2525 struct tldap_req_state
*state
;
2527 req
= tldap_req_create(mem_ctx
, ld
, &state
);
2532 if (!asn1_push_tag(state
->out
, TLDAP_REQ_DELETE
)) goto err
;
2533 if (!asn1_write(state
->out
, dn
, strlen(dn
))) goto err
;
2534 if (!asn1_pop_tag(state
->out
)) goto err
;
2536 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
2537 sctrls
, num_sctrls
);
2538 if (tevent_req_nomem(subreq
, req
)) {
2539 return tevent_req_post(req
, ev
);
2541 tevent_req_set_callback(subreq
, tldap_delete_done
, req
);
2546 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
2547 return tevent_req_post(req
, ev
);
2550 static void tldap_delete_done(struct tevent_req
*subreq
)
2552 tldap_simple_done(subreq
, TLDAP_RES_DELETE
);
2555 TLDAPRC
tldap_delete_recv(struct tevent_req
*req
)
2557 return tldap_simple_recv(req
);
2560 TLDAPRC
tldap_delete(struct tldap_context
*ld
, const char *dn
,
2561 struct tldap_control
*sctrls
, int num_sctrls
,
2562 struct tldap_control
*cctrls
, int num_cctrls
)
2564 TALLOC_CTX
*frame
= talloc_stackframe();
2565 struct tevent_context
*ev
;
2566 struct tevent_req
*req
;
2567 TLDAPRC rc
= TLDAP_NO_MEMORY
;
2569 ev
= samba_tevent_context_init(frame
);
2573 req
= tldap_delete_send(frame
, ev
, ld
, dn
, sctrls
, num_sctrls
,
2574 cctrls
, num_cctrls
);
2578 if (!tevent_req_poll(req
, ev
)) {
2579 rc
= TLDAP_OPERATIONS_ERROR
;
2582 rc
= tldap_delete_recv(req
);
2583 tldap_save_msg(ld
, req
);
2589 static void tldap_extended_done(struct tevent_req
*subreq
);
2591 struct tevent_req
*tldap_extended_send(TALLOC_CTX
*mem_ctx
,
2592 struct tevent_context
*ev
,
2593 struct tldap_context
*ld
,
2595 const DATA_BLOB
*in_blob
,
2596 struct tldap_control
*sctrls
,
2598 struct tldap_control
*cctrls
,
2601 struct tevent_req
*req
, *subreq
;
2602 struct tldap_req_state
*state
;
2604 req
= tldap_req_create(mem_ctx
, ld
, &state
);
2609 if (!asn1_push_tag(state
->out
, TLDAP_REQ_EXTENDED
)) goto err
;
2611 if (!asn1_push_tag(state
->out
, ASN1_CONTEXT_SIMPLE(0))) goto err
;
2612 if (!asn1_write(state
->out
, in_oid
, strlen(in_oid
))) goto err
;
2613 if (!asn1_pop_tag(state
->out
)) goto err
;
2615 if (in_blob
!= NULL
) {
2616 if (!asn1_push_tag(state
->out
, ASN1_CONTEXT_SIMPLE(1))) goto err
;
2617 if (!asn1_write_OctetString(state
->out
, in_blob
->data
, in_blob
->length
)) goto err
;
2618 if (!asn1_pop_tag(state
->out
)) goto err
;
2621 if (!asn1_pop_tag(state
->out
)) goto err
;
2623 subreq
= tldap_msg_send(state
, ev
, ld
, state
->id
, state
->out
,
2624 sctrls
, num_sctrls
);
2625 if (tevent_req_nomem(subreq
, req
)) {
2626 return tevent_req_post(req
, ev
);
2628 tevent_req_set_callback(subreq
, tldap_extended_done
, req
);
2633 tevent_req_ldap_error(req
, TLDAP_ENCODING_ERROR
);
2634 return tevent_req_post(req
, ev
);
2637 static void tldap_extended_done(struct tevent_req
*subreq
)
2639 struct tevent_req
*req
= tevent_req_callback_data(
2640 subreq
, struct tevent_req
);
2641 struct tldap_req_state
*state
= tevent_req_data(
2642 req
, struct tldap_req_state
);
2646 rc
= tldap_msg_recv(subreq
, state
, &state
->result
);
2647 TALLOC_FREE(subreq
);
2648 if (tevent_req_ldap_error(req
, rc
)) {
2651 if (state
->result
->type
!= TLDAP_RES_EXTENDED
) {
2652 tevent_req_ldap_error(req
, TLDAP_PROTOCOL_ERROR
);
2656 ok
= asn1_start_tag(state
->result
->data
, TLDAP_RES_EXTENDED
);
2657 ok
&= tldap_decode_response(state
);
2659 if (asn1_peek_tag(state
->result
->data
, ASN1_CONTEXT_SIMPLE(10))) {
2660 ok
&= asn1_start_tag(state
->result
->data
,
2661 ASN1_CONTEXT_SIMPLE(10));
2666 ok
&= asn1_read_LDAPString(state
->result
->data
,
2668 &state
->result
->res_extended
.oid
);
2670 ok
&= asn1_end_tag(state
->result
->data
);
2673 if (asn1_peek_tag(state
->result
->data
, ASN1_CONTEXT_SIMPLE(11))) {
2676 ok
&= asn1_start_tag(state
->result
->data
,
2677 ASN1_CONTEXT_SIMPLE(11));
2682 len
= asn1_tag_remaining(state
->result
->data
);
2687 state
->result
->res_extended
.blob
=
2688 data_blob_talloc(state
->result
, NULL
, len
);
2689 if (state
->result
->res_extended
.blob
.data
== NULL
) {
2693 ok
= asn1_read(state
->result
->data
,
2694 state
->result
->res_extended
.blob
.data
,
2695 state
->result
->res_extended
.blob
.length
);
2697 ok
&= asn1_end_tag(state
->result
->data
);
2700 ok
&= asn1_end_tag(state
->result
->data
);
2706 if (!TLDAP_RC_IS_SUCCESS(state
->result
->lderr
)) {
2707 tevent_req_ldap_error(req
, state
->result
->lderr
);
2710 tevent_req_done(req
);
2714 tevent_req_ldap_error(req
, TLDAP_DECODING_ERROR
);
2718 TLDAPRC
tldap_extended_recv(struct tevent_req
*req
,
2719 TALLOC_CTX
*mem_ctx
,
2721 DATA_BLOB
*out_blob
)
2723 struct tldap_req_state
*state
= tevent_req_data(
2724 req
, struct tldap_req_state
);
2727 if (tevent_req_is_ldap_error(req
, &rc
)) {
2731 if (out_oid
!= NULL
) {
2732 *out_oid
= talloc_move(mem_ctx
,
2733 &state
->result
->res_extended
.oid
);
2736 if (out_blob
!= NULL
) {
2737 out_blob
->data
= talloc_move(mem_ctx
,
2738 &state
->result
->res_extended
.blob
.data
);
2740 state
->result
->res_extended
.blob
.length
;
2743 return state
->result
->lderr
;
2746 TLDAPRC
tldap_extended(struct tldap_context
*ld
,
2748 const DATA_BLOB
*in_blob
,
2749 struct tldap_control
*sctrls
,
2751 struct tldap_control
*cctrls
,
2753 TALLOC_CTX
*mem_ctx
,
2755 DATA_BLOB
*out_blob
)
2757 TALLOC_CTX
*frame
= talloc_stackframe();
2758 struct tevent_context
*ev
;
2759 struct tevent_req
*req
;
2760 TLDAPRC rc
= TLDAP_NO_MEMORY
;
2762 ev
= samba_tevent_context_init(frame
);
2766 req
= tldap_extended_send(frame
, ev
, ld
,
2769 cctrls
, num_cctrls
);
2773 if (!tevent_req_poll(req
, ev
)) {
2774 rc
= TLDAP_OPERATIONS_ERROR
;
2777 rc
= tldap_extended_recv(req
, mem_ctx
, out_oid
, out_blob
);
2778 tldap_save_msg(ld
, req
);
2784 int tldap_msg_id(const struct tldap_message
*msg
)
2789 int tldap_msg_type(const struct tldap_message
*msg
)
2794 const char *tldap_msg_matcheddn(struct tldap_message
*msg
)
2799 return msg
->res_matcheddn
;
2802 const char *tldap_msg_diagnosticmessage(struct tldap_message
*msg
)
2807 return msg
->res_diagnosticmessage
;
2810 const char *tldap_msg_referral(struct tldap_message
*msg
)
2815 return msg
->res_referral
;
2818 void tldap_msg_sctrls(struct tldap_message
*msg
, int *num_sctrls
,
2819 struct tldap_control
**sctrls
)
2826 *sctrls
= msg
->res_sctrls
;
2827 *num_sctrls
= talloc_array_length(msg
->res_sctrls
);
2830 struct tldap_message
*tldap_ctx_lastmsg(struct tldap_context
*ld
)
2832 return ld
->last_msg
;
2835 static const struct { TLDAPRC rc
; const char *string
; } tldaprc_errmap
[] =
2839 { TLDAP_OPERATIONS_ERROR
,
2840 "TLDAP_OPERATIONS_ERROR" },
2841 { TLDAP_PROTOCOL_ERROR
,
2842 "TLDAP_PROTOCOL_ERROR" },
2843 { TLDAP_TIMELIMIT_EXCEEDED
,
2844 "TLDAP_TIMELIMIT_EXCEEDED" },
2845 { TLDAP_SIZELIMIT_EXCEEDED
,
2846 "TLDAP_SIZELIMIT_EXCEEDED" },
2847 { TLDAP_COMPARE_FALSE
,
2848 "TLDAP_COMPARE_FALSE" },
2849 { TLDAP_COMPARE_TRUE
,
2850 "TLDAP_COMPARE_TRUE" },
2851 { TLDAP_STRONG_AUTH_NOT_SUPPORTED
,
2852 "TLDAP_STRONG_AUTH_NOT_SUPPORTED" },
2853 { TLDAP_STRONG_AUTH_REQUIRED
,
2854 "TLDAP_STRONG_AUTH_REQUIRED" },
2857 { TLDAP_ADMINLIMIT_EXCEEDED
,
2858 "TLDAP_ADMINLIMIT_EXCEEDED" },
2859 { TLDAP_UNAVAILABLE_CRITICAL_EXTENSION
,
2860 "TLDAP_UNAVAILABLE_CRITICAL_EXTENSION" },
2861 { TLDAP_CONFIDENTIALITY_REQUIRED
,
2862 "TLDAP_CONFIDENTIALITY_REQUIRED" },
2863 { TLDAP_SASL_BIND_IN_PROGRESS
,
2864 "TLDAP_SASL_BIND_IN_PROGRESS" },
2865 { TLDAP_NO_SUCH_ATTRIBUTE
,
2866 "TLDAP_NO_SUCH_ATTRIBUTE" },
2867 { TLDAP_UNDEFINED_TYPE
,
2868 "TLDAP_UNDEFINED_TYPE" },
2869 { TLDAP_INAPPROPRIATE_MATCHING
,
2870 "TLDAP_INAPPROPRIATE_MATCHING" },
2871 { TLDAP_CONSTRAINT_VIOLATION
,
2872 "TLDAP_CONSTRAINT_VIOLATION" },
2873 { TLDAP_TYPE_OR_VALUE_EXISTS
,
2874 "TLDAP_TYPE_OR_VALUE_EXISTS" },
2875 { TLDAP_INVALID_SYNTAX
,
2876 "TLDAP_INVALID_SYNTAX" },
2877 { TLDAP_NO_SUCH_OBJECT
,
2878 "TLDAP_NO_SUCH_OBJECT" },
2879 { TLDAP_ALIAS_PROBLEM
,
2880 "TLDAP_ALIAS_PROBLEM" },
2881 { TLDAP_INVALID_DN_SYNTAX
,
2882 "TLDAP_INVALID_DN_SYNTAX" },
2885 { TLDAP_ALIAS_DEREF_PROBLEM
,
2886 "TLDAP_ALIAS_DEREF_PROBLEM" },
2887 { TLDAP_INAPPROPRIATE_AUTH
,
2888 "TLDAP_INAPPROPRIATE_AUTH" },
2889 { TLDAP_INVALID_CREDENTIALS
,
2890 "TLDAP_INVALID_CREDENTIALS" },
2891 { TLDAP_INSUFFICIENT_ACCESS
,
2892 "TLDAP_INSUFFICIENT_ACCESS" },
2895 { TLDAP_UNAVAILABLE
,
2896 "TLDAP_UNAVAILABLE" },
2897 { TLDAP_UNWILLING_TO_PERFORM
,
2898 "TLDAP_UNWILLING_TO_PERFORM" },
2899 { TLDAP_LOOP_DETECT
,
2900 "TLDAP_LOOP_DETECT" },
2901 { TLDAP_NAMING_VIOLATION
,
2902 "TLDAP_NAMING_VIOLATION" },
2903 { TLDAP_OBJECT_CLASS_VIOLATION
,
2904 "TLDAP_OBJECT_CLASS_VIOLATION" },
2905 { TLDAP_NOT_ALLOWED_ON_NONLEAF
,
2906 "TLDAP_NOT_ALLOWED_ON_NONLEAF" },
2907 { TLDAP_NOT_ALLOWED_ON_RDN
,
2908 "TLDAP_NOT_ALLOWED_ON_RDN" },
2909 { TLDAP_ALREADY_EXISTS
,
2910 "TLDAP_ALREADY_EXISTS" },
2911 { TLDAP_NO_OBJECT_CLASS_MODS
,
2912 "TLDAP_NO_OBJECT_CLASS_MODS" },
2913 { TLDAP_RESULTS_TOO_LARGE
,
2914 "TLDAP_RESULTS_TOO_LARGE" },
2915 { TLDAP_AFFECTS_MULTIPLE_DSAS
,
2916 "TLDAP_AFFECTS_MULTIPLE_DSAS" },
2919 { TLDAP_SERVER_DOWN
,
2920 "TLDAP_SERVER_DOWN" },
2921 { TLDAP_LOCAL_ERROR
,
2922 "TLDAP_LOCAL_ERROR" },
2923 { TLDAP_ENCODING_ERROR
,
2924 "TLDAP_ENCODING_ERROR" },
2925 { TLDAP_DECODING_ERROR
,
2926 "TLDAP_DECODING_ERROR" },
2929 { TLDAP_AUTH_UNKNOWN
,
2930 "TLDAP_AUTH_UNKNOWN" },
2931 { TLDAP_FILTER_ERROR
,
2932 "TLDAP_FILTER_ERROR" },
2933 { TLDAP_USER_CANCELLED
,
2934 "TLDAP_USER_CANCELLED" },
2935 { TLDAP_PARAM_ERROR
,
2936 "TLDAP_PARAM_ERROR" },
2938 "TLDAP_NO_MEMORY" },
2939 { TLDAP_CONNECT_ERROR
,
2940 "TLDAP_CONNECT_ERROR" },
2941 { TLDAP_NOT_SUPPORTED
,
2942 "TLDAP_NOT_SUPPORTED" },
2943 { TLDAP_CONTROL_NOT_FOUND
,
2944 "TLDAP_CONTROL_NOT_FOUND" },
2945 { TLDAP_NO_RESULTS_RETURNED
,
2946 "TLDAP_NO_RESULTS_RETURNED" },
2947 { TLDAP_MORE_RESULTS_TO_RETURN
,
2948 "TLDAP_MORE_RESULTS_TO_RETURN" },
2949 { TLDAP_CLIENT_LOOP
,
2950 "TLDAP_CLIENT_LOOP" },
2951 { TLDAP_REFERRAL_LIMIT_EXCEEDED
,
2952 "TLDAP_REFERRAL_LIMIT_EXCEEDED" },
2955 const char *tldap_rc2string(TLDAPRC rc
)
2959 for (i
=0; i
<ARRAY_SIZE(tldaprc_errmap
); i
++) {
2960 if (TLDAP_RC_EQUAL(rc
, tldaprc_errmap
[i
].rc
)) {
2961 return tldaprc_errmap
[i
].string
;
2965 return "Unknown LDAP Error";