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;
90 struct tstream_context *tls;
91 struct tstream_context *gensec;
92 struct tstream_context *active;
94 struct tevent_queue *outgoing;
95 struct tevent_req **pending;
96 struct tevent_req *read_req;
98 /* For the sync wrappers we need something like get_last_error... */
99 struct tldap_message *last_msg;
102 void (*log_fn)(void *context, enum tldap_debug_level level,
103 const char *fmt, va_list ap);
106 struct tldap_ctx_attribute *ctx_attrs;
109 struct tldap_message {
110 struct asn1_data *data;
117 struct tldap_attribute *attribs;
119 /* Error data sent by the server */
122 char *res_diagnosticmessage;
124 DATA_BLOB res_serverSaslCreds;
129 struct tldap_control *res_sctrls;
131 /* Controls sent by the server */
132 struct tldap_control *ctrls;
135 void tldap_set_debug(struct tldap_context *ld,
136 void (*log_fn)(void *log_private,
137 enum tldap_debug_level level,
139 va_list ap) PRINTF_ATTRIBUTE(3,0),
143 ld->log_private = log_private;
146 static void tldap_debug(
147 struct tldap_context *ld,
148 enum tldap_debug_level level,
149 const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
151 static void tldap_debug(struct tldap_context *ld,
152 enum tldap_debug_level level,
153 const char *fmt, ...)
159 if (ld->log_fn == NULL) {
163 ld->log_fn(ld->log_private, level, fmt, ap);
167 static int tldap_next_msgid(struct tldap_context *ld)
171 result = ld->msgid++;
172 if (ld->msgid == INT_MAX) {
178 struct tldap_context *tldap_context_create(TALLOC_CTX *mem_ctx, int fd)
180 struct tldap_context *ctx;
183 ctx = talloc_zero(mem_ctx, struct tldap_context);
187 ret = tstream_bsd_existing_socket(ctx, fd, &ctx->plain);
192 ctx->active = ctx->plain;
195 ctx->outgoing = tevent_queue_create(ctx, "tldap_outgoing");
196 if (ctx->outgoing == NULL) {
203 bool tldap_connection_ok(struct tldap_context *ld)
211 if (ld->active == NULL) {
215 ret = tstream_pending_bytes(ld->active);
223 static size_t tldap_pending_reqs(struct tldap_context *ld)
225 return talloc_array_length(ld->pending);
228 struct tstream_context *tldap_get_plain_tstream(struct tldap_context *ld)
233 void tldap_set_starttls_needed(struct tldap_context *ld, bool needed)
239 ld->starttls_needed = needed;
242 bool tldap_get_starttls_needed(struct tldap_context *ld)
248 return ld->starttls_needed;
251 bool tldap_has_tls_tstream(struct tldap_context *ld)
253 return ld->tls != NULL && ld->active == ld->tls;
256 const DATA_BLOB *tldap_tls_channel_bindings(struct tldap_context *ld)
258 return tstream_tls_channel_bindings(ld->tls);
261 void tldap_set_tls_tstream(struct tldap_context *ld,
262 struct tstream_context **stream)
264 TALLOC_FREE(ld->tls);
265 if (stream != NULL) {
266 ld->tls = talloc_move(ld, stream);
268 if (ld->tls != NULL) {
269 ld->active = ld->tls;
271 ld->active = ld->plain;
275 bool tldap_has_gensec_tstream(struct tldap_context *ld)
277 return ld->gensec != NULL && ld->active == ld->gensec;
280 void tldap_set_gensec_tstream(struct tldap_context *ld,
281 struct tstream_context **stream)
283 TALLOC_FREE(ld->gensec);
284 if (stream != NULL) {
285 ld->gensec = talloc_move(ld, stream);
287 if (ld->gensec != NULL) {
288 ld->active = ld->gensec;
290 ld->active = ld->plain;
294 static struct tldap_ctx_attribute *tldap_context_findattr(
295 struct tldap_context *ld, const char *name)
299 num_attrs = talloc_array_length(ld->ctx_attrs);
301 for (i=0; i<num_attrs; i++) {
302 if (strcmp(ld->ctx_attrs[i].name, name) == 0) {
303 return &ld->ctx_attrs[i];
309 bool tldap_context_setattr(struct tldap_context *ld,
310 const char *name, const void *_pptr)
312 struct tldap_ctx_attribute *tmp, *attr;
315 void **pptr = (void **)discard_const_p(void,_pptr);
317 attr = tldap_context_findattr(ld, name);
320 * We don't actually delete attrs, we don't expect tons of
321 * attributes being shuffled around.
323 TALLOC_FREE(attr->ptr);
325 attr->ptr = talloc_move(ld->ctx_attrs, pptr);
331 tmpname = talloc_strdup(ld, name);
332 if (tmpname == NULL) {
336 num_attrs = talloc_array_length(ld->ctx_attrs);
338 tmp = talloc_realloc(ld, ld->ctx_attrs, struct tldap_ctx_attribute,
341 TALLOC_FREE(tmpname);
344 tmp[num_attrs].name = talloc_move(tmp, &tmpname);
346 tmp[num_attrs].ptr = talloc_move(tmp, pptr);
348 tmp[num_attrs].ptr = NULL;
355 void *tldap_context_getattr(struct tldap_context *ld, const char *name)
357 struct tldap_ctx_attribute *attr = tldap_context_findattr(ld, name);
365 struct read_ldap_state {
369 static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data);
370 static void read_ldap_done(struct tevent_req *subreq);
372 static struct tevent_req *read_ldap_send(TALLOC_CTX *mem_ctx,
373 struct tevent_context *ev,
374 struct tstream_context *conn)
376 struct tevent_req *req, *subreq;
377 struct read_ldap_state *state;
379 req = tevent_req_create(mem_ctx, &state, struct read_ldap_state);
384 subreq = tstream_read_packet_send(state, ev, conn, 7, read_ldap_more,
386 if (tevent_req_nomem(subreq, req)) {
387 return tevent_req_post(req, ev);
389 tevent_req_set_callback(subreq, read_ldap_done, req);
393 static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data)
395 const DATA_BLOB blob = data_blob_const(buf, buflen);
401 * We need at least 6 bytes to workout the length
404 * And we have asked for 7 because the that's
405 * the size of the smallest possible LDAP pdu.
410 ret = asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), &pdu_len);
415 return pdu_len - buflen;
421 static void read_ldap_done(struct tevent_req *subreq)
423 struct tevent_req *req = tevent_req_callback_data(
424 subreq, struct tevent_req);
425 struct read_ldap_state *state = tevent_req_data(
426 req, struct read_ldap_state);
430 nread = tstream_read_packet_recv(subreq, state, &state->buf, &err);
433 tevent_req_error(req, err);
436 tevent_req_done(req);
439 static ssize_t read_ldap_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
440 uint8_t **pbuf, int *perrno)
442 struct read_ldap_state *state = tevent_req_data(
443 req, struct read_ldap_state);
445 if (tevent_req_is_unix_error(req, perrno)) {
448 *pbuf = talloc_move(mem_ctx, &state->buf);
449 return talloc_get_size(*pbuf);
452 struct tldap_msg_state {
453 struct tldap_context *ld;
454 struct tevent_context *ev;
458 struct asn1_data *data;
462 static bool tldap_push_controls(struct asn1_data *data,
463 struct tldap_control *sctrls,
468 if ((sctrls == NULL) || (num_sctrls == 0)) {
472 if (!asn1_push_tag(data, ASN1_CONTEXT(0))) return false;
474 for (i=0; i<num_sctrls; i++) {
475 struct tldap_control *c = &sctrls[i];
476 if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
477 if (!asn1_write_OctetString(data, c->oid, strlen(c->oid))) return false;
479 if (!asn1_write_BOOLEAN(data, true)) return false;
481 if (c->value.data != NULL) {
482 if (!asn1_write_OctetString(data, c->value.data,
483 c->value.length)) return false;
485 if (!asn1_pop_tag(data)) return false; /* ASN1_SEQUENCE(0) */
488 return asn1_pop_tag(data); /* ASN1_CONTEXT(0) */
491 #define tldap_context_disconnect(ld, status) \
492 _tldap_context_disconnect(ld, status, __location__)
494 static void _tldap_context_disconnect(struct tldap_context *ld,
496 const char *location)
498 if (ld->active == NULL) {
500 * We don't need to tldap_debug() on
501 * a potential 2nd run.
503 * The rest of the function would just
504 * be a noop for the 2nd run anyway.
509 tldap_debug(ld, TLDAP_DEBUG_WARNING,
510 "tldap_context_disconnect: %s at %s\n",
511 tldap_rc2string(status),
513 tevent_queue_stop(ld->outgoing);
514 TALLOC_FREE(ld->read_req);
516 TALLOC_FREE(ld->gensec);
517 TALLOC_FREE(ld->tls);
518 TALLOC_FREE(ld->plain);
520 while (talloc_array_length(ld->pending) > 0) {
521 struct tevent_req *req = NULL;
522 struct tldap_msg_state *state = NULL;
524 req = ld->pending[0];
525 state = tevent_req_data(req, struct tldap_msg_state);
526 tevent_req_defer_callback(req, state->ev);
527 tevent_req_ldap_error(req, status);
531 static void tldap_msg_sent(struct tevent_req *subreq);
532 static void tldap_msg_received(struct tevent_req *subreq);
534 static struct tevent_req *tldap_msg_send(TALLOC_CTX *mem_ctx,
535 struct tevent_context *ev,
536 struct tldap_context *ld,
537 int id, struct asn1_data *data,
538 struct tldap_control *sctrls,
541 struct tevent_req *req, *subreq;
542 struct tldap_msg_state *state;
546 tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_send: sending msg %d\n",
549 req = tevent_req_create(mem_ctx, &state, struct tldap_msg_state);
557 ok = tldap_connection_ok(ld);
559 tevent_req_ldap_error(req, TLDAP_SERVER_DOWN);
560 return tevent_req_post(req, ev);
563 if (!tldap_push_controls(data, sctrls, num_sctrls)) {
564 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
565 return tevent_req_post(req, ev);
569 if (!asn1_pop_tag(data)) {
570 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
571 return tevent_req_post(req, ev);
574 if (!asn1_blob(data, &blob)) {
575 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
576 return tevent_req_post(req, ev);
579 if (!tldap_msg_set_pending(req)) {
581 return tevent_req_post(req, ev);;
584 state->iov.iov_base = (void *)blob.data;
585 state->iov.iov_len = blob.length;
587 subreq = tstream_writev_queue_send(state, ev, ld->active, ld->outgoing,
589 if (tevent_req_nomem(subreq, req)) {
590 return tevent_req_post(req, ev);
592 tevent_req_set_callback(subreq, tldap_msg_sent, req);
596 static void tldap_msg_unset_pending(struct tevent_req *req)
598 struct tldap_msg_state *state = tevent_req_data(
599 req, struct tldap_msg_state);
600 struct tldap_context *ld = state->ld;
601 int num_pending = tldap_pending_reqs(ld);
604 tevent_req_set_cleanup_fn(req, NULL);
606 for (i=0; i<num_pending; i++) {
607 if (req == ld->pending[i]) {
611 if (i == num_pending) {
613 * Something's seriously broken. Just returning here is the
614 * right thing nevertheless, the point of this routine is to
615 * remove ourselves from cli->pending.
620 if (num_pending == 1) {
621 TALLOC_FREE(ld->pending);
626 * Remove ourselves from the cli->pending array
628 if (num_pending > 1) {
629 ld->pending[i] = ld->pending[num_pending-1];
633 * No NULL check here, we're shrinking by sizeof(void *), and
634 * talloc_realloc just adjusts the size for this.
636 ld->pending = talloc_realloc(NULL, ld->pending, struct tevent_req *,
640 static void tldap_msg_cleanup(struct tevent_req *req,
641 enum tevent_req_state req_state)
643 tldap_msg_unset_pending(req);
646 static bool tldap_msg_set_pending(struct tevent_req *req)
648 struct tldap_msg_state *state = tevent_req_data(
649 req, struct tldap_msg_state);
650 struct tldap_context *ld;
651 struct tevent_req **pending;
655 num_pending = tldap_pending_reqs(ld);
657 pending = talloc_realloc(ld, ld->pending, struct tevent_req *,
659 if (pending == NULL) {
662 pending[num_pending] = req;
663 ld->pending = pending;
664 tevent_req_set_cleanup_fn(req, tldap_msg_cleanup);
666 if (ld->read_req != NULL) {
671 * We're the first one, add the read_ldap request that waits for the
672 * answer from the server
674 ld->read_req = read_ldap_send(ld->pending, state->ev, ld->active);
675 if (ld->read_req == NULL) {
676 tldap_msg_unset_pending(req);
679 tevent_req_set_callback(ld->read_req, tldap_msg_received, ld);
683 static void tldap_msg_sent(struct tevent_req *subreq)
685 struct tevent_req *req = tevent_req_callback_data(
686 subreq, struct tevent_req);
687 struct tldap_msg_state *state = tevent_req_data(
688 req, struct tldap_msg_state);
692 nwritten = tstream_writev_queue_recv(subreq, &err);
694 if (nwritten == -1) {
695 tldap_context_disconnect(state->ld, TLDAP_SERVER_DOWN);
700 static int tldap_msg_msgid(struct tevent_req *req)
702 struct tldap_msg_state *state = tevent_req_data(
703 req, struct tldap_msg_state);
708 static void tldap_msg_received(struct tevent_req *subreq)
710 struct tldap_context *ld = tevent_req_callback_data(
711 subreq, struct tldap_context);
712 struct tevent_req *req;
713 struct tldap_msg_state *state;
714 struct asn1_data *data;
720 TLDAPRC status = TLDAP_PROTOCOL_ERROR;
725 received = read_ldap_recv(subreq, talloc_tos(), &inbuf, &err);
728 if (received == -1) {
729 status = TLDAP_SERVER_DOWN;
733 data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
736 * We have to disconnect all, we can't tell which of
737 * the requests this reply is for.
739 status = TLDAP_NO_MEMORY;
742 asn1_load_nocopy(data, inbuf, received);
745 ok &= asn1_start_tag(data, ASN1_SEQUENCE(0));
746 ok &= asn1_read_Integer(data, &id);
747 ok &= asn1_peek_uint8(data, &type);
750 status = TLDAP_PROTOCOL_ERROR;
754 tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_received: got msg %d "
755 "type %d\n", id, (int)type);
761 "tldap_msg_received: got msgid 0 of "
762 "type %"PRIu8", disconnecting\n",
764 tldap_context_disconnect(ld, TLDAP_SERVER_DOWN);
768 num_pending = talloc_array_length(ld->pending);
770 for (i=0; i<num_pending; i++) {
771 if (id == tldap_msg_msgid(ld->pending[i])) {
775 if (i == num_pending) {
776 /* Dump unexpected reply */
777 tldap_debug(ld, TLDAP_DEBUG_WARNING, "tldap_msg_received: "
778 "No request pending for msg %d\n", id);
784 req = ld->pending[i];
785 state = tevent_req_data(req, struct tldap_msg_state);
787 state->inbuf = talloc_move(state, &inbuf);
788 state->data = talloc_move(state, &data);
790 tldap_msg_unset_pending(req);
791 num_pending = talloc_array_length(ld->pending);
793 tevent_req_defer_callback(req, state->ev);
794 tevent_req_done(req);
797 if (num_pending == 0) {
801 state = tevent_req_data(ld->pending[0], struct tldap_msg_state);
802 ld->read_req = read_ldap_send(ld->pending, state->ev, ld->active);
803 if (ld->read_req == NULL) {
804 status = TLDAP_NO_MEMORY;
807 tevent_req_set_callback(ld->read_req, tldap_msg_received, ld);
811 tldap_context_disconnect(ld, status);
814 static TLDAPRC tldap_msg_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
815 struct tldap_message **pmsg)
817 struct tldap_msg_state *state = tevent_req_data(
818 req, struct tldap_msg_state);
819 struct tldap_message *msg;
823 if (tevent_req_is_ldap_error(req, &err)) {
827 if (!asn1_peek_uint8(state->data, &msgtype)) {
828 return TLDAP_PROTOCOL_ERROR;
832 return TLDAP_SUCCESS;
835 msg = talloc_zero(mem_ctx, struct tldap_message);
837 return TLDAP_NO_MEMORY;
841 msg->inbuf = talloc_move(msg, &state->inbuf);
842 msg->data = talloc_move(msg, &state->data);
846 return TLDAP_SUCCESS;
849 struct tldap_req_state {
851 struct asn1_data *out;
852 struct tldap_message *result;
855 static struct tevent_req *tldap_req_create(TALLOC_CTX *mem_ctx,
856 struct tldap_context *ld,
857 struct tldap_req_state **pstate)
859 struct tevent_req *req;
860 struct tldap_req_state *state;
862 req = tevent_req_create(mem_ctx, &state, struct tldap_req_state);
866 state->out = asn1_init(state, ASN1_MAX_TREE_DEPTH);
867 if (state->out == NULL) {
870 state->id = tldap_next_msgid(ld);
872 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
873 if (!asn1_write_Integer(state->out, state->id)) goto err;
884 static void tldap_save_msg(struct tldap_context *ld, struct tevent_req *req)
886 struct tldap_req_state *state = tevent_req_data(
887 req, struct tldap_req_state);
889 TALLOC_FREE(ld->last_msg);
890 ld->last_msg = talloc_move(ld, &state->result);
893 static char *blob2string_talloc(TALLOC_CTX *mem_ctx, DATA_BLOB blob)
895 char *result = talloc_array(mem_ctx, char, blob.length+1);
897 if (result == NULL) {
901 memcpy(result, blob.data, blob.length);
902 result[blob.length] = '\0';
906 static bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
907 struct asn1_data *data,
912 if (!asn1_read_OctetString(data, mem_ctx, &string))
915 result = blob2string_talloc(mem_ctx, string);
917 data_blob_free(&string);
919 if (result == NULL) {
926 static bool tldap_decode_controls(struct tldap_req_state *state);
928 static bool tldap_decode_response(struct tldap_req_state *state)
930 struct asn1_data *data = state->result->data;
931 struct tldap_message *msg = state->result;
935 ok &= asn1_read_enumerated(data, &rc);
937 msg->lderr = TLDAP_RC(rc);
940 ok &= asn1_read_OctetString_talloc(msg, data, &msg->res_matcheddn);
941 ok &= asn1_read_OctetString_talloc(msg, data,
942 &msg->res_diagnosticmessage);
944 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
945 ok &= asn1_start_tag(data, ASN1_CONTEXT(3));
946 ok &= asn1_read_OctetString_talloc(msg, data,
948 ok &= asn1_end_tag(data);
950 msg->res_referral = NULL;
956 static void tldap_sasl_bind_done(struct tevent_req *subreq);
958 struct tevent_req *tldap_sasl_bind_send(TALLOC_CTX *mem_ctx,
959 struct tevent_context *ev,
960 struct tldap_context *ld,
962 const char *mechanism,
964 struct tldap_control *sctrls,
966 struct tldap_control *cctrls,
969 struct tevent_req *req, *subreq;
970 struct tldap_req_state *state;
972 req = tldap_req_create(mem_ctx, ld, &state);
981 if (!asn1_push_tag(state->out, TLDAP_REQ_BIND)) goto err;
982 if (!asn1_write_Integer(state->out, ld->ld_version)) goto err;
983 if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
985 if (mechanism == NULL) {
986 if (!asn1_push_tag(state->out, ASN1_CONTEXT_SIMPLE(0))) goto err;
987 if (!asn1_write(state->out, creds->data, creds->length)) goto err;
988 if (!asn1_pop_tag(state->out)) goto err;
990 if (!asn1_push_tag(state->out, ASN1_CONTEXT(3))) goto err;
991 if (!asn1_write_OctetString(state->out, mechanism,
992 strlen(mechanism))) goto err;
993 if ((creds != NULL) && (creds->data != NULL)) {
994 if (!asn1_write_OctetString(state->out, creds->data,
995 creds->length)) goto err;
997 if (!asn1_pop_tag(state->out)) goto err;
1000 if (!asn1_pop_tag(state->out)) goto err;
1002 subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
1003 sctrls, num_sctrls);
1004 if (tevent_req_nomem(subreq, req)) {
1005 return tevent_req_post(req, ev);
1007 tevent_req_set_callback(subreq, tldap_sasl_bind_done, req);
1012 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
1013 return tevent_req_post(req, ev);
1016 static void tldap_sasl_bind_done(struct tevent_req *subreq)
1018 struct tevent_req *req = tevent_req_callback_data(
1019 subreq, struct tevent_req);
1020 struct tldap_req_state *state = tevent_req_data(
1021 req, struct tldap_req_state);
1025 rc = tldap_msg_recv(subreq, state, &state->result);
1026 TALLOC_FREE(subreq);
1027 if (tevent_req_ldap_error(req, rc)) {
1030 if (state->result->type != TLDAP_RES_BIND) {
1031 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
1035 ok = asn1_start_tag(state->result->data, TLDAP_RES_BIND);
1036 ok &= tldap_decode_response(state);
1038 if (asn1_peek_tag(state->result->data, ASN1_CONTEXT_SIMPLE(7))) {
1041 ok &= asn1_start_tag(state->result->data,
1042 ASN1_CONTEXT_SIMPLE(7));
1047 len = asn1_tag_remaining(state->result->data);
1052 state->result->res_serverSaslCreds =
1053 data_blob_talloc(state->result, NULL, len);
1054 if (state->result->res_serverSaslCreds.data == NULL) {
1058 ok = asn1_read(state->result->data,
1059 state->result->res_serverSaslCreds.data,
1060 state->result->res_serverSaslCreds.length);
1062 ok &= asn1_end_tag(state->result->data);
1065 ok &= asn1_end_tag(state->result->data);
1071 if (!TLDAP_RC_IS_SUCCESS(state->result->lderr) &&
1072 !TLDAP_RC_EQUAL(state->result->lderr,
1073 TLDAP_SASL_BIND_IN_PROGRESS)) {
1074 tevent_req_ldap_error(req, state->result->lderr);
1077 tevent_req_done(req);
1081 tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
1085 TLDAPRC tldap_sasl_bind_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1086 DATA_BLOB *serverSaslCreds)
1088 struct tldap_req_state *state = tevent_req_data(
1089 req, struct tldap_req_state);
1092 if (tevent_req_is_ldap_error(req, &rc)) {
1096 if (serverSaslCreds != NULL) {
1097 serverSaslCreds->data = talloc_move(
1098 mem_ctx, &state->result->res_serverSaslCreds.data);
1099 serverSaslCreds->length =
1100 state->result->res_serverSaslCreds.length;
1103 return state->result->lderr;
1106 TLDAPRC tldap_sasl_bind(struct tldap_context *ld,
1108 const char *mechanism,
1110 struct tldap_control *sctrls,
1112 struct tldap_control *cctrls,
1114 TALLOC_CTX *mem_ctx,
1115 DATA_BLOB *serverSaslCreds)
1117 TALLOC_CTX *frame = talloc_stackframe();
1118 struct tevent_context *ev;
1119 struct tevent_req *req;
1120 TLDAPRC rc = TLDAP_NO_MEMORY;
1122 ev = samba_tevent_context_init(frame);
1126 req = tldap_sasl_bind_send(frame, ev, ld, dn, mechanism, creds,
1127 sctrls, num_sctrls, cctrls, num_cctrls);
1131 if (!tevent_req_poll(req, ev)) {
1132 rc = TLDAP_OPERATIONS_ERROR;
1135 rc = tldap_sasl_bind_recv(req, mem_ctx, serverSaslCreds);
1136 tldap_save_msg(ld, req);
1142 struct tevent_req *tldap_simple_bind_send(TALLOC_CTX *mem_ctx,
1143 struct tevent_context *ev,
1144 struct tldap_context *ld,
1150 if (passwd != NULL) {
1151 cred.data = discard_const_p(uint8_t, passwd);
1152 cred.length = strlen(passwd);
1154 cred.data = discard_const_p(uint8_t, "");
1157 return tldap_sasl_bind_send(mem_ctx, ev, ld, dn, NULL, &cred, NULL, 0,
1161 TLDAPRC tldap_simple_bind_recv(struct tevent_req *req)
1163 return tldap_sasl_bind_recv(req, NULL, NULL);
1166 TLDAPRC tldap_simple_bind(struct tldap_context *ld, const char *dn,
1171 if (passwd != NULL) {
1172 cred.data = discard_const_p(uint8_t, passwd);
1173 cred.length = strlen(passwd);
1175 cred.data = discard_const_p(uint8_t, "");
1178 return tldap_sasl_bind(ld, dn, NULL, &cred, NULL, 0, NULL, 0,
1182 /*****************************************************************************/
1184 /* can't use isalpha() as only a strict set is valid for LDAP */
1186 static bool tldap_is_alpha(char c)
1188 return (((c >= 'a') && (c <= 'z')) || \
1189 ((c >= 'A') && (c <= 'Z')));
1192 static bool tldap_is_adh(char c)
1194 return tldap_is_alpha(c) || isdigit(c) || (c == '-');
1197 #define TLDAP_FILTER_AND ASN1_CONTEXT(0)
1198 #define TLDAP_FILTER_OR ASN1_CONTEXT(1)
1199 #define TLDAP_FILTER_NOT ASN1_CONTEXT(2)
1200 #define TLDAP_FILTER_EQ ASN1_CONTEXT(3)
1201 #define TLDAP_FILTER_SUB ASN1_CONTEXT(4)
1202 #define TLDAP_FILTER_LE ASN1_CONTEXT(5)
1203 #define TLDAP_FILTER_GE ASN1_CONTEXT(6)
1204 #define TLDAP_FILTER_PRES ASN1_CONTEXT_SIMPLE(7)
1205 #define TLDAP_FILTER_APX ASN1_CONTEXT(8)
1206 #define TLDAP_FILTER_EXT ASN1_CONTEXT(9)
1208 #define TLDAP_SUB_INI ASN1_CONTEXT_SIMPLE(0)
1209 #define TLDAP_SUB_ANY ASN1_CONTEXT_SIMPLE(1)
1210 #define TLDAP_SUB_FIN ASN1_CONTEXT_SIMPLE(2)
1213 /* oid's should be numerical only in theory,
1214 * but apparently some broken servers may have alphanum aliases instead.
1215 * Do like openldap libraries and allow alphanum aliases for oids, but
1216 * do not allow Tagging options in that case.
1218 static bool tldap_is_attrdesc(const char *s, int len, bool no_tagopts)
1220 bool is_oid = false;
1224 /* first char has stricter rules */
1227 } else if (!tldap_is_alpha(*s)) {
1228 /* bad first char */
1232 for (i = 1; i < len; i++) {
1235 if (isdigit(s[i])) {
1248 if (tldap_is_adh(s[i])) {
1255 /* no tagging options */
1262 if ((i + 1) == len) {
1280 /* this function copies the value until the closing parenthesis is found. */
1281 static char *tldap_get_val(TALLOC_CTX *memctx,
1282 const char *value, const char **_s)
1284 const char *s = value;
1286 /* find terminator */
1289 if (s && (*(s - 1) == '\\')) {
1295 if (!s || !(*s == ')')) {
1296 /* malformed filter */
1302 return talloc_strndup(memctx, value, s - value);
1305 static int tldap_hex2char(const char *x)
1307 if (isxdigit(x[0]) && isxdigit(x[1])) {
1308 const char h1 = x[0], h2 = x[1];
1311 if (h1 >= 'a') c = h1 - (int)'a' + 10;
1312 else if (h1 >= 'A') c = h1 - (int)'A' + 10;
1313 else if (h1 >= '0') c = h1 - (int)'0';
1315 if (h2 >= 'a') c += h2 - (int)'a' + 10;
1316 else if (h2 >= 'A') c += h2 - (int)'A' + 10;
1317 else if (h2 >= '0') c += h2 - (int)'0';
1325 static bool tldap_find_first_star(const char *val, const char **star)
1329 for (s = val; *s; s++) {
1332 if (isxdigit(s[1]) && isxdigit(s[2])) {
1336 /* not hex based escape, check older syntax */
1345 /* invalid escape sequence */
1350 /* end of val, nothing found */
1360 /* string ended without closing parenthesis, filter is malformed */
1364 static bool tldap_unescape_inplace(char *value, size_t *val_len)
1369 for (i = 0,p = 0; i < *val_len; i++) {
1375 /* these must be escaped */
1379 if (!value[i + 1]) {
1385 /* LDAPv3 escaped */
1386 c = tldap_hex2char(&value[i]);
1387 if (c >= 0 && c < 256) {
1394 /* LDAPv2 escaped */
1400 value[p] = value[i];
1411 value[p] = value[i];
1420 static bool tldap_push_filter_basic(struct tldap_context *ld,
1421 struct asn1_data *data,
1423 static bool tldap_push_filter_substring(struct tldap_context *ld,
1424 struct asn1_data *data,
1427 static bool tldap_push_filter_int(struct tldap_context *ld,
1428 struct asn1_data *data,
1431 const char *s = *_s;
1435 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1436 "Incomplete or malformed filter\n");
1441 /* we are right after a parenthesis,
1442 * find out what op we have at hand */
1445 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: AND\n");
1446 if (!asn1_push_tag(data, TLDAP_FILTER_AND)) return false;
1451 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: OR\n");
1452 if (!asn1_push_tag(data, TLDAP_FILTER_OR)) return false;
1457 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: NOT\n");
1458 if (!asn1_push_tag(data, TLDAP_FILTER_NOT)) return false;
1460 ret = tldap_push_filter_int(ld, data, &s);
1464 if (!asn1_pop_tag(data)) return false;
1469 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1470 "Invalid parenthesis '%c'\n", *s);
1474 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1475 "Invalid filter termination\n");
1479 ret = tldap_push_filter_basic(ld, data, &s);
1486 /* only and/or filters get here.
1487 * go through the list of filters */
1490 /* RFC 4526: empty and/or */
1491 if (!asn1_pop_tag(data)) return false;
1496 ret = tldap_push_filter_int(ld, data, &s);
1502 /* end of list, return */
1503 if (!asn1_pop_tag(data)) return false;
1510 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1511 "Incomplete or malformed filter\n");
1516 if (asn1_has_error(data)) {
1525 static bool tldap_push_filter_basic(struct tldap_context *ld,
1526 struct asn1_data *data,
1529 TALLOC_CTX *tmpctx = talloc_tos();
1530 const char *s = *_s;
1538 size_t type_len = 0;
1541 bool write_octect = true;
1544 eq = strchr(s, '=');
1546 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1547 "Invalid filter, missing equal sign\n");
1556 if (!asn1_push_tag(data, TLDAP_FILTER_LE)) return false;
1560 if (!asn1_push_tag(data, TLDAP_FILTER_GE)) return false;
1564 if (!asn1_push_tag(data, TLDAP_FILTER_APX)) return false;
1568 if (!asn1_push_tag(data, TLDAP_FILTER_EXT)) return false;
1569 write_octect = false;
1575 if (*s == ':') { /* [:dn]:rule:= value */
1577 /* malformed filter */
1581 } else { /* type[:dn][:rule]:= value */
1583 dn = strchr(s, ':');
1584 type_len = dn - type;
1585 if (dn == e) { /* type:= value */
1592 rule = strchr(dn, ':');
1596 if ((rule == dn + 1) || rule + 1 == e) {
1597 /* malformed filter, contains "::" */
1601 if (strncasecmp_m(dn, "dn:", 3) != 0) {
1606 /* malformed filter. With two
1607 * optionals, the first must be "dn"
1620 if (!type && !dn && !rule) {
1621 /* malformed filter, there must be at least one */
1626 MatchingRuleAssertion ::= SEQUENCE {
1627 matchingRule [1] MatchingRuleID OPTIONAL,
1628 type [2] AttributeDescription OPTIONAL,
1629 matchValue [3] AssertionValue,
1630 dnAttributes [4] BOOLEAN DEFAULT FALSE
1634 /* check and add rule */
1636 ret = tldap_is_attrdesc(rule, e - rule, true);
1640 if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1))) return false;
1641 if (!asn1_write(data, rule, e - rule)) return false;
1642 if (!asn1_pop_tag(data)) return false;
1645 /* check and add type */
1647 ret = tldap_is_attrdesc(type, type_len, false);
1651 if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2))) return false;
1652 if (!asn1_write(data, type, type_len)) return false;
1653 if (!asn1_pop_tag(data)) return false;
1656 uval = tldap_get_val(tmpctx, val, _s);
1660 uval_len = *_s - val;
1661 ret = tldap_unescape_inplace(uval, &uval_len);
1666 if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3))) return false;
1667 if (!asn1_write(data, uval, uval_len)) return false;
1668 if (!asn1_pop_tag(data)) return false;
1670 if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4))) return false;
1671 if (!asn1_write_uint8(data, dn?1:0)) return false;
1672 if (!asn1_pop_tag(data)) return false;
1678 ret = tldap_is_attrdesc(s, e - s, false);
1683 if (strncmp(val, "*)", 2) == 0) {
1685 if (!asn1_push_tag(data, TLDAP_FILTER_PRES)) return false;
1686 if (!asn1_write(data, s, e - s)) return false;
1688 write_octect = false;
1692 ret = tldap_find_first_star(val, &star);
1698 if (!asn1_push_tag(data, TLDAP_FILTER_SUB)) return false;
1699 if (!asn1_write_OctetString(data, s, e - s)) return false;
1700 ret = tldap_push_filter_substring(ld, data, val, &s);
1705 write_octect = false;
1709 /* if nothing else, then it is just equality */
1710 if (!asn1_push_tag(data, TLDAP_FILTER_EQ)) return false;
1711 write_octect = true;
1716 uval = tldap_get_val(tmpctx, val, _s);
1720 uval_len = *_s - val;
1721 ret = tldap_unescape_inplace(uval, &uval_len);
1726 if (!asn1_write_OctetString(data, s, e - s)) return false;
1727 if (!asn1_write_OctetString(data, uval, uval_len)) return false;
1730 if (asn1_has_error(data)) {
1733 return asn1_pop_tag(data);
1736 static bool tldap_push_filter_substring(struct tldap_context *ld,
1737 struct asn1_data *data,
1741 TALLOC_CTX *tmpctx = talloc_tos();
1742 bool initial = true;
1749 SubstringFilter ::= SEQUENCE {
1750 type AttributeDescription,
1751 -- at least one must be present
1752 substrings SEQUENCE OF CHOICE {
1753 initial [0] LDAPString,
1755 final [2] LDAPString } }
1757 if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
1760 ret = tldap_find_first_star(val, &star);
1764 chunk_len = star - val;
1768 if (!initial && chunk_len == 0) {
1769 /* found '**', which is illegal */
1785 if (initial && chunk_len == 0) {
1791 chunk = talloc_strndup(tmpctx, val, chunk_len);
1795 ret = tldap_unescape_inplace(chunk, &chunk_len);
1802 if (!asn1_push_tag(data, TLDAP_SUB_INI)) return false;
1805 if (!asn1_push_tag(data, TLDAP_SUB_ANY)) return false;
1809 if (!asn1_push_tag(data, TLDAP_SUB_FIN)) return false;
1815 if (!asn1_write(data, chunk, chunk_len)) return false;
1816 if (!asn1_pop_tag(data)) return false;
1820 } while (*star == '*');
1824 /* end of sequence */
1825 return asn1_pop_tag(data);
1828 /* NOTE: although openldap libraries allow for spaces in some places, mostly
1829 * around parentheses, we do not allow any spaces (except in values of
1830 * course) as I couldn't find any place in RFC 4512 or RFC 4515 where
1831 * leading or trailing spaces were allowed.
1833 static bool tldap_push_filter(struct tldap_context *ld,
1834 struct asn1_data *data,
1837 const char *s = filter;
1840 ret = tldap_push_filter_int(ld, data, &s);
1842 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1843 "Incomplete or malformed filter\n");
1849 /*****************************************************************************/
1851 static void tldap_search_done(struct tevent_req *subreq);
1853 struct tevent_req *tldap_search_send(TALLOC_CTX *mem_ctx,
1854 struct tevent_context *ev,
1855 struct tldap_context *ld,
1856 const char *base, int scope,
1861 struct tldap_control *sctrls,
1863 struct tldap_control *cctrls,
1869 struct tevent_req *req, *subreq;
1870 struct tldap_req_state *state;
1873 req = tldap_req_create(mem_ctx, ld, &state);
1878 if (!asn1_push_tag(state->out, TLDAP_REQ_SEARCH)) goto encoding_error;
1879 if (!asn1_write_OctetString(state->out, base, strlen(base))) goto encoding_error;
1880 if (!asn1_write_enumerated(state->out, scope)) goto encoding_error;
1881 if (!asn1_write_enumerated(state->out, deref)) goto encoding_error;
1882 if (!asn1_write_Integer(state->out, sizelimit)) goto encoding_error;
1883 if (!asn1_write_Integer(state->out, timelimit)) goto encoding_error;
1884 if (!asn1_write_BOOLEAN(state->out, attrsonly)) goto encoding_error;
1886 if (!tldap_push_filter(ld, state->out, filter)) {
1887 goto encoding_error;
1890 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto encoding_error;
1891 for (i=0; i<num_attrs; i++) {
1892 if (!asn1_write_OctetString(state->out, attrs[i], strlen(attrs[i]))) goto encoding_error;
1894 if (!asn1_pop_tag(state->out)) goto encoding_error;
1895 if (!asn1_pop_tag(state->out)) goto encoding_error;
1897 subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
1898 sctrls, num_sctrls);
1899 if (tevent_req_nomem(subreq, req)) {
1900 return tevent_req_post(req, ev);
1902 tevent_req_set_callback(subreq, tldap_search_done, req);
1906 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
1907 return tevent_req_post(req, ev);
1910 static void tldap_search_done(struct tevent_req *subreq)
1912 struct tevent_req *req = tevent_req_callback_data(
1913 subreq, struct tevent_req);
1914 struct tldap_req_state *state = tevent_req_data(
1915 req, struct tldap_req_state);
1918 rc = tldap_msg_recv(subreq, state, &state->result);
1919 if (tevent_req_ldap_error(req, rc)) {
1922 switch (state->result->type) {
1923 case TLDAP_RES_SEARCH_ENTRY:
1924 case TLDAP_RES_SEARCH_REFERENCE:
1925 if (!tldap_msg_set_pending(subreq)) {
1926 tevent_req_oom(req);
1929 tevent_req_notify_callback(req);
1931 case TLDAP_RES_SEARCH_RESULT:
1932 TALLOC_FREE(subreq);
1933 if (!asn1_start_tag(state->result->data,
1934 state->result->type) ||
1935 !tldap_decode_response(state) ||
1936 !asn1_end_tag(state->result->data) ||
1937 !tldap_decode_controls(state)) {
1938 tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
1941 tevent_req_done(req);
1944 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
1949 TLDAPRC tldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1950 struct tldap_message **pmsg)
1952 struct tldap_req_state *state = tevent_req_data(
1953 req, struct tldap_req_state);
1956 if (!tevent_req_is_in_progress(req)
1957 && tevent_req_is_ldap_error(req, &rc)) {
1961 if (tevent_req_is_in_progress(req)) {
1962 switch (state->result->type) {
1963 case TLDAP_RES_SEARCH_ENTRY:
1964 case TLDAP_RES_SEARCH_REFERENCE:
1967 return TLDAP_OPERATIONS_ERROR;
1971 *pmsg = talloc_move(mem_ctx, &state->result);
1972 return TLDAP_SUCCESS;
1975 struct tldap_search_all_state {
1976 struct tldap_message **msgs;
1977 struct tldap_message *result;
1980 static void tldap_search_all_done(struct tevent_req *subreq);
1982 struct tevent_req *tldap_search_all_send(
1983 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1984 struct tldap_context *ld, const char *base, int scope,
1985 const char *filter, const char **attrs, int num_attrs, int attrsonly,
1986 struct tldap_control *sctrls, int num_sctrls,
1987 struct tldap_control *cctrls, int num_cctrls,
1988 int timelimit, int sizelimit, int deref)
1990 struct tevent_req *req, *subreq;
1991 struct tldap_search_all_state *state;
1993 req = tevent_req_create(mem_ctx, &state,
1994 struct tldap_search_all_state);
1999 subreq = tldap_search_send(state, ev, ld, base, scope, filter,
2000 attrs, num_attrs, attrsonly,
2001 sctrls, num_sctrls, cctrls, num_cctrls,
2002 timelimit, sizelimit, deref);
2003 if (tevent_req_nomem(subreq, req)) {
2004 return tevent_req_post(req, ev);
2006 tevent_req_set_callback(subreq, tldap_search_all_done, req);
2010 static void tldap_search_all_done(struct tevent_req *subreq)
2012 struct tevent_req *req = tevent_req_callback_data(
2013 subreq, struct tevent_req);
2014 struct tldap_search_all_state *state = tevent_req_data(
2015 req, struct tldap_search_all_state);
2016 struct tldap_message *msg, **tmp;
2021 rc = tldap_search_recv(subreq, state, &msg);
2022 /* No TALLOC_FREE(subreq), this is multi-step */
2023 if (tevent_req_ldap_error(req, rc)) {
2027 msgtype = tldap_msg_type(msg);
2028 if (msgtype == TLDAP_RES_SEARCH_RESULT) {
2029 state->result = msg;
2030 tevent_req_done(req);
2034 num_msgs = talloc_array_length(state->msgs);
2036 tmp = talloc_realloc(state, state->msgs, struct tldap_message *,
2038 if (tevent_req_nomem(tmp, req)) {
2042 state->msgs[num_msgs] = talloc_move(state->msgs, &msg);
2045 TLDAPRC tldap_search_all_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
2046 struct tldap_message ***msgs,
2047 struct tldap_message **result)
2049 struct tldap_search_all_state *state = tevent_req_data(
2050 req, struct tldap_search_all_state);
2053 if (tevent_req_is_ldap_error(req, &rc)) {
2058 *msgs = talloc_move(mem_ctx, &state->msgs);
2060 if (result != NULL) {
2061 *result = talloc_move(mem_ctx, &state->result);
2064 return TLDAP_SUCCESS;
2067 TLDAPRC tldap_search(struct tldap_context *ld,
2068 const char *base, int scope, const char *filter,
2069 const char **attrs, int num_attrs, int attrsonly,
2070 struct tldap_control *sctrls, int num_sctrls,
2071 struct tldap_control *cctrls, int num_cctrls,
2072 int timelimit, int sizelimit, int deref,
2073 TALLOC_CTX *mem_ctx, struct tldap_message ***pmsgs)
2076 struct tevent_context *ev;
2077 struct tevent_req *req;
2078 TLDAPRC rc = TLDAP_NO_MEMORY;
2079 struct tldap_message **msgs;
2080 struct tldap_message *result;
2082 if (tldap_pending_reqs(ld)) {
2086 frame = talloc_stackframe();
2088 ev = samba_tevent_context_init(frame);
2092 req = tldap_search_all_send(frame, ev, ld, base, scope, filter,
2093 attrs, num_attrs, attrsonly,
2094 sctrls, num_sctrls, cctrls, num_cctrls,
2095 timelimit, sizelimit, deref);
2099 if (!tevent_req_poll(req, ev)) {
2100 rc = TLDAP_OPERATIONS_ERROR;
2103 rc = tldap_search_all_recv(req, frame, &msgs, &result);
2105 if (!TLDAP_RC_IS_SUCCESS(rc)) {
2109 TALLOC_FREE(ld->last_msg);
2110 ld->last_msg = talloc_move(ld, &result);
2112 if (pmsgs != NULL) {
2113 *pmsgs = talloc_move(mem_ctx, &msgs);
2120 static bool tldap_parse_search_entry(struct tldap_message *msg)
2122 int num_attribs = 0;
2124 if (msg->type != TLDAP_RES_SEARCH_ENTRY) {
2127 if (!asn1_start_tag(msg->data, TLDAP_RES_SEARCH_ENTRY)) {
2133 if (!asn1_read_OctetString_talloc(msg, msg->data, &msg->dn)) return false;
2135 if (msg->dn == NULL) {
2140 * Attributes: We overallocate msg->attribs by one, so that while
2141 * looping over the attributes we can directly parse into the last
2142 * array element. Same for the values in the inner loop.
2145 msg->attribs = talloc_array(msg, struct tldap_attribute, 1);
2146 if (msg->attribs == NULL) {
2150 if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
2151 while (asn1_peek_tag(msg->data, ASN1_SEQUENCE(0))) {
2152 struct tldap_attribute *attrib;
2155 attrib = &msg->attribs[num_attribs];
2156 attrib->values = talloc_array(msg->attribs, DATA_BLOB, 1);
2157 if (attrib->values == NULL) {
2160 if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
2161 if (!asn1_read_OctetString_talloc(msg->attribs, msg->data,
2162 &attrib->name)) return false;
2163 if (!asn1_start_tag(msg->data, ASN1_SET)) return false;
2165 while (asn1_peek_tag(msg->data, ASN1_OCTET_STRING)) {
2166 if (!asn1_read_OctetString(msg->data, msg,
2167 &attrib->values[num_values])) return false;
2169 attrib->values = talloc_realloc(
2170 msg->attribs, attrib->values, DATA_BLOB,
2172 if (attrib->values == NULL) {
2177 attrib->values = talloc_realloc(msg->attribs, attrib->values,
2178 DATA_BLOB, num_values);
2179 attrib->num_values = num_values;
2181 if (!asn1_end_tag(msg->data)) return false; /* ASN1_SET */
2182 if (!asn1_end_tag(msg->data)) return false; /* ASN1_SEQUENCE(0) */
2183 msg->attribs = talloc_realloc(
2184 msg, msg->attribs, struct tldap_attribute,
2186 if (msg->attribs == NULL) {
2191 msg->attribs = talloc_realloc(
2192 msg, msg->attribs, struct tldap_attribute, num_attribs);
2193 return asn1_end_tag(msg->data);
2196 bool tldap_entry_dn(struct tldap_message *msg, char **dn)
2198 if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
2205 bool tldap_entry_attributes(struct tldap_message *msg,
2206 struct tldap_attribute **attributes,
2207 int *num_attributes)
2209 if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
2212 *attributes = msg->attribs;
2213 *num_attributes = talloc_array_length(msg->attribs);
2217 static bool tldap_decode_controls(struct tldap_req_state *state)
2219 struct tldap_message *msg = state->result;
2220 struct asn1_data *data = msg->data;
2221 struct tldap_control *sctrls = NULL;
2222 int num_controls = 0;
2225 msg->res_sctrls = NULL;
2227 if (!asn1_peek_tag(data, ASN1_CONTEXT(0))) {
2231 if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto out;
2233 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
2234 struct tldap_control *c;
2237 sctrls = talloc_realloc(msg, sctrls, struct tldap_control,
2239 if (sctrls == NULL) {
2242 c = &sctrls[num_controls];
2244 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto out;
2245 if (!asn1_read_OctetString_talloc(msg, data, &oid)) goto out;
2246 if (asn1_has_error(data) || (oid == NULL)) {
2250 if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
2251 if (!asn1_read_BOOLEAN(data, &c->critical)) goto out;
2253 c->critical = false;
2255 c->value = data_blob_null;
2256 if (asn1_peek_tag(data, ASN1_OCTET_STRING) &&
2257 !asn1_read_OctetString(data, msg, &c->value)) {
2260 if (!asn1_end_tag(data)) goto out; /* ASN1_SEQUENCE(0) */
2265 if (!asn1_end_tag(data)) goto out; /* ASN1_CONTEXT(0) */
2272 msg->res_sctrls = sctrls;
2274 TALLOC_FREE(sctrls);
2279 static void tldap_simple_done(struct tevent_req *subreq, int type)
2281 struct tevent_req *req = tevent_req_callback_data(
2282 subreq, struct tevent_req);
2283 struct tldap_req_state *state = tevent_req_data(
2284 req, struct tldap_req_state);
2287 rc = tldap_msg_recv(subreq, state, &state->result);
2288 TALLOC_FREE(subreq);
2289 if (tevent_req_ldap_error(req, rc)) {
2292 if (state->result->type != type) {
2293 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
2296 if (!asn1_start_tag(state->result->data, state->result->type) ||
2297 !tldap_decode_response(state) ||
2298 !asn1_end_tag(state->result->data) ||
2299 !tldap_decode_controls(state)) {
2300 tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
2303 if (!TLDAP_RC_IS_SUCCESS(state->result->lderr)) {
2304 tevent_req_ldap_error(req, state->result->lderr);
2307 tevent_req_done(req);
2310 static TLDAPRC tldap_simple_recv(struct tevent_req *req)
2313 if (tevent_req_is_ldap_error(req, &rc)) {
2316 return TLDAP_SUCCESS;
2319 static void tldap_add_done(struct tevent_req *subreq);
2321 struct tevent_req *tldap_add_send(TALLOC_CTX *mem_ctx,
2322 struct tevent_context *ev,
2323 struct tldap_context *ld,
2325 struct tldap_mod *attributes,
2327 struct tldap_control *sctrls,
2329 struct tldap_control *cctrls,
2332 struct tevent_req *req, *subreq;
2333 struct tldap_req_state *state;
2336 req = tldap_req_create(mem_ctx, ld, &state);
2341 if (!asn1_push_tag(state->out, TLDAP_REQ_ADD)) goto err;
2342 if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
2343 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2345 for (i=0; i<num_attributes; i++) {
2346 struct tldap_mod *attrib = &attributes[i];
2347 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2348 if (!asn1_write_OctetString(state->out, attrib->attribute,
2349 strlen(attrib->attribute))) goto err;
2350 if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
2351 for (j=0; j<attrib->num_values; j++) {
2352 if (!asn1_write_OctetString(state->out,
2353 attrib->values[j].data,
2354 attrib->values[j].length)) goto err;
2356 if (!asn1_pop_tag(state->out)) goto err;
2357 if (!asn1_pop_tag(state->out)) goto err;
2360 if (!asn1_pop_tag(state->out)) goto err;
2361 if (!asn1_pop_tag(state->out)) goto err;
2363 subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
2364 sctrls, num_sctrls);
2365 if (tevent_req_nomem(subreq, req)) {
2366 return tevent_req_post(req, ev);
2368 tevent_req_set_callback(subreq, tldap_add_done, req);
2373 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
2374 return tevent_req_post(req, ev);
2377 static void tldap_add_done(struct tevent_req *subreq)
2379 tldap_simple_done(subreq, TLDAP_RES_ADD);
2382 TLDAPRC tldap_add_recv(struct tevent_req *req)
2384 return tldap_simple_recv(req);
2387 TLDAPRC tldap_add(struct tldap_context *ld, const char *dn,
2388 struct tldap_mod *attributes, int num_attributes,
2389 struct tldap_control *sctrls, int num_sctrls,
2390 struct tldap_control *cctrls, int num_cctrls)
2392 TALLOC_CTX *frame = talloc_stackframe();
2393 struct tevent_context *ev;
2394 struct tevent_req *req;
2395 TLDAPRC rc = TLDAP_NO_MEMORY;
2397 ev = samba_tevent_context_init(frame);
2401 req = tldap_add_send(frame, ev, ld, dn, attributes, num_attributes,
2402 sctrls, num_sctrls, cctrls, num_cctrls);
2406 if (!tevent_req_poll(req, ev)) {
2407 rc = TLDAP_OPERATIONS_ERROR;
2410 rc = tldap_add_recv(req);
2411 tldap_save_msg(ld, req);
2417 static void tldap_modify_done(struct tevent_req *subreq);
2419 struct tevent_req *tldap_modify_send(TALLOC_CTX *mem_ctx,
2420 struct tevent_context *ev,
2421 struct tldap_context *ld,
2423 struct tldap_mod *mods, int num_mods,
2424 struct tldap_control *sctrls,
2426 struct tldap_control *cctrls,
2429 struct tevent_req *req, *subreq;
2430 struct tldap_req_state *state;
2433 req = tldap_req_create(mem_ctx, ld, &state);
2438 if (!asn1_push_tag(state->out, TLDAP_REQ_MODIFY)) goto err;
2439 if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
2440 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2442 for (i=0; i<num_mods; i++) {
2443 struct tldap_mod *mod = &mods[i];
2444 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2445 if (!asn1_write_enumerated(state->out, mod->mod_op)) goto err;
2446 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2447 if (!asn1_write_OctetString(state->out, mod->attribute,
2448 strlen(mod->attribute))) goto err;
2449 if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
2450 for (j=0; j<mod->num_values; j++) {
2451 if (!asn1_write_OctetString(state->out,
2452 mod->values[j].data,
2453 mod->values[j].length)) goto err;
2455 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;
2460 if (!asn1_pop_tag(state->out)) goto err;
2461 if (!asn1_pop_tag(state->out)) goto err;
2463 subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
2464 sctrls, num_sctrls);
2465 if (tevent_req_nomem(subreq, req)) {
2466 return tevent_req_post(req, ev);
2468 tevent_req_set_callback(subreq, tldap_modify_done, req);
2473 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
2474 return tevent_req_post(req, ev);
2477 static void tldap_modify_done(struct tevent_req *subreq)
2479 tldap_simple_done(subreq, TLDAP_RES_MODIFY);
2482 TLDAPRC tldap_modify_recv(struct tevent_req *req)
2484 return tldap_simple_recv(req);
2487 TLDAPRC tldap_modify(struct tldap_context *ld, const char *dn,
2488 struct tldap_mod *mods, int num_mods,
2489 struct tldap_control *sctrls, int num_sctrls,
2490 struct tldap_control *cctrls, int num_cctrls)
2492 TALLOC_CTX *frame = talloc_stackframe();
2493 struct tevent_context *ev;
2494 struct tevent_req *req;
2495 TLDAPRC rc = TLDAP_NO_MEMORY;
2497 ev = samba_tevent_context_init(frame);
2501 req = tldap_modify_send(frame, ev, ld, dn, mods, num_mods,
2502 sctrls, num_sctrls, cctrls, num_cctrls);
2506 if (!tevent_req_poll(req, ev)) {
2507 rc = TLDAP_OPERATIONS_ERROR;
2510 rc = tldap_modify_recv(req);
2511 tldap_save_msg(ld, req);
2517 static void tldap_delete_done(struct tevent_req *subreq);
2519 struct tevent_req *tldap_delete_send(TALLOC_CTX *mem_ctx,
2520 struct tevent_context *ev,
2521 struct tldap_context *ld,
2523 struct tldap_control *sctrls,
2525 struct tldap_control *cctrls,
2528 struct tevent_req *req, *subreq;
2529 struct tldap_req_state *state;
2531 req = tldap_req_create(mem_ctx, ld, &state);
2536 if (!asn1_push_tag(state->out, TLDAP_REQ_DELETE)) goto err;
2537 if (!asn1_write(state->out, dn, strlen(dn))) goto err;
2538 if (!asn1_pop_tag(state->out)) goto err;
2540 subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
2541 sctrls, num_sctrls);
2542 if (tevent_req_nomem(subreq, req)) {
2543 return tevent_req_post(req, ev);
2545 tevent_req_set_callback(subreq, tldap_delete_done, req);
2550 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
2551 return tevent_req_post(req, ev);
2554 static void tldap_delete_done(struct tevent_req *subreq)
2556 tldap_simple_done(subreq, TLDAP_RES_DELETE);
2559 TLDAPRC tldap_delete_recv(struct tevent_req *req)
2561 return tldap_simple_recv(req);
2564 TLDAPRC tldap_delete(struct tldap_context *ld, const char *dn,
2565 struct tldap_control *sctrls, int num_sctrls,
2566 struct tldap_control *cctrls, int num_cctrls)
2568 TALLOC_CTX *frame = talloc_stackframe();
2569 struct tevent_context *ev;
2570 struct tevent_req *req;
2571 TLDAPRC rc = TLDAP_NO_MEMORY;
2573 ev = samba_tevent_context_init(frame);
2577 req = tldap_delete_send(frame, ev, ld, dn, sctrls, num_sctrls,
2578 cctrls, num_cctrls);
2582 if (!tevent_req_poll(req, ev)) {
2583 rc = TLDAP_OPERATIONS_ERROR;
2586 rc = tldap_delete_recv(req);
2587 tldap_save_msg(ld, req);
2593 static void tldap_extended_done(struct tevent_req *subreq);
2595 struct tevent_req *tldap_extended_send(TALLOC_CTX *mem_ctx,
2596 struct tevent_context *ev,
2597 struct tldap_context *ld,
2599 const DATA_BLOB *in_blob,
2600 struct tldap_control *sctrls,
2602 struct tldap_control *cctrls,
2605 struct tevent_req *req, *subreq;
2606 struct tldap_req_state *state;
2608 req = tldap_req_create(mem_ctx, ld, &state);
2613 if (!asn1_push_tag(state->out, TLDAP_REQ_EXTENDED)) goto err;
2615 if (!asn1_push_tag(state->out, ASN1_CONTEXT_SIMPLE(0))) goto err;
2616 if (!asn1_write(state->out, in_oid, strlen(in_oid))) goto err;
2617 if (!asn1_pop_tag(state->out)) goto err;
2619 if (in_blob != NULL) {
2620 if (!asn1_push_tag(state->out, ASN1_CONTEXT_SIMPLE(1))) goto err;
2621 if (!asn1_write_OctetString(state->out, in_blob->data, in_blob->length)) goto err;
2622 if (!asn1_pop_tag(state->out)) goto err;
2625 if (!asn1_pop_tag(state->out)) goto err;
2627 subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
2628 sctrls, num_sctrls);
2629 if (tevent_req_nomem(subreq, req)) {
2630 return tevent_req_post(req, ev);
2632 tevent_req_set_callback(subreq, tldap_extended_done, req);
2637 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
2638 return tevent_req_post(req, ev);
2641 static void tldap_extended_done(struct tevent_req *subreq)
2643 struct tevent_req *req = tevent_req_callback_data(
2644 subreq, struct tevent_req);
2645 struct tldap_req_state *state = tevent_req_data(
2646 req, struct tldap_req_state);
2650 rc = tldap_msg_recv(subreq, state, &state->result);
2651 TALLOC_FREE(subreq);
2652 if (tevent_req_ldap_error(req, rc)) {
2655 if (state->result->type != TLDAP_RES_EXTENDED) {
2656 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
2660 ok = asn1_start_tag(state->result->data, TLDAP_RES_EXTENDED);
2661 ok &= tldap_decode_response(state);
2663 if (asn1_peek_tag(state->result->data, ASN1_CONTEXT_SIMPLE(10))) {
2664 ok &= asn1_start_tag(state->result->data,
2665 ASN1_CONTEXT_SIMPLE(10));
2670 ok &= asn1_read_LDAPString(state->result->data,
2672 &state->result->res_extended.oid);
2674 ok &= asn1_end_tag(state->result->data);
2677 if (asn1_peek_tag(state->result->data, ASN1_CONTEXT_SIMPLE(11))) {
2680 ok &= asn1_start_tag(state->result->data,
2681 ASN1_CONTEXT_SIMPLE(11));
2686 len = asn1_tag_remaining(state->result->data);
2691 state->result->res_extended.blob =
2692 data_blob_talloc(state->result, NULL, len);
2693 if (state->result->res_extended.blob.data == NULL) {
2697 ok = asn1_read(state->result->data,
2698 state->result->res_extended.blob.data,
2699 state->result->res_extended.blob.length);
2701 ok &= asn1_end_tag(state->result->data);
2704 ok &= asn1_end_tag(state->result->data);
2710 if (!TLDAP_RC_IS_SUCCESS(state->result->lderr)) {
2711 tevent_req_ldap_error(req, state->result->lderr);
2714 tevent_req_done(req);
2718 tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
2722 TLDAPRC tldap_extended_recv(struct tevent_req *req,
2723 TALLOC_CTX *mem_ctx,
2725 DATA_BLOB *out_blob)
2727 struct tldap_req_state *state = tevent_req_data(
2728 req, struct tldap_req_state);
2731 if (tevent_req_is_ldap_error(req, &rc)) {
2735 if (out_oid != NULL) {
2736 *out_oid = talloc_move(mem_ctx,
2737 &state->result->res_extended.oid);
2740 if (out_blob != NULL) {
2741 out_blob->data = talloc_move(mem_ctx,
2742 &state->result->res_extended.blob.data);
2744 state->result->res_extended.blob.length;
2747 return state->result->lderr;
2750 TLDAPRC tldap_extended(struct tldap_context *ld,
2752 const DATA_BLOB *in_blob,
2753 struct tldap_control *sctrls,
2755 struct tldap_control *cctrls,
2757 TALLOC_CTX *mem_ctx,
2759 DATA_BLOB *out_blob)
2761 TALLOC_CTX *frame = talloc_stackframe();
2762 struct tevent_context *ev;
2763 struct tevent_req *req;
2764 TLDAPRC rc = TLDAP_NO_MEMORY;
2766 ev = samba_tevent_context_init(frame);
2770 req = tldap_extended_send(frame, ev, ld,
2773 cctrls, num_cctrls);
2777 if (!tevent_req_poll(req, ev)) {
2778 rc = TLDAP_OPERATIONS_ERROR;
2781 rc = tldap_extended_recv(req, mem_ctx, out_oid, out_blob);
2782 tldap_save_msg(ld, req);
2788 int tldap_msg_id(const struct tldap_message *msg)
2793 int tldap_msg_type(const struct tldap_message *msg)
2798 const char *tldap_msg_matcheddn(struct tldap_message *msg)
2803 return msg->res_matcheddn;
2806 const char *tldap_msg_diagnosticmessage(struct tldap_message *msg)
2811 return msg->res_diagnosticmessage;
2814 const char *tldap_msg_referral(struct tldap_message *msg)
2819 return msg->res_referral;
2822 void tldap_msg_sctrls(struct tldap_message *msg, int *num_sctrls,
2823 struct tldap_control **sctrls)
2830 *sctrls = msg->res_sctrls;
2831 *num_sctrls = talloc_array_length(msg->res_sctrls);
2834 struct tldap_message *tldap_ctx_lastmsg(struct tldap_context *ld)
2836 return ld->last_msg;
2839 static const struct { TLDAPRC rc; const char *string; } tldaprc_errmap[] =
2843 { TLDAP_OPERATIONS_ERROR,
2844 "TLDAP_OPERATIONS_ERROR" },
2845 { TLDAP_PROTOCOL_ERROR,
2846 "TLDAP_PROTOCOL_ERROR" },
2847 { TLDAP_TIMELIMIT_EXCEEDED,
2848 "TLDAP_TIMELIMIT_EXCEEDED" },
2849 { TLDAP_SIZELIMIT_EXCEEDED,
2850 "TLDAP_SIZELIMIT_EXCEEDED" },
2851 { TLDAP_COMPARE_FALSE,
2852 "TLDAP_COMPARE_FALSE" },
2853 { TLDAP_COMPARE_TRUE,
2854 "TLDAP_COMPARE_TRUE" },
2855 { TLDAP_STRONG_AUTH_NOT_SUPPORTED,
2856 "TLDAP_STRONG_AUTH_NOT_SUPPORTED" },
2857 { TLDAP_STRONG_AUTH_REQUIRED,
2858 "TLDAP_STRONG_AUTH_REQUIRED" },
2861 { TLDAP_ADMINLIMIT_EXCEEDED,
2862 "TLDAP_ADMINLIMIT_EXCEEDED" },
2863 { TLDAP_UNAVAILABLE_CRITICAL_EXTENSION,
2864 "TLDAP_UNAVAILABLE_CRITICAL_EXTENSION" },
2865 { TLDAP_CONFIDENTIALITY_REQUIRED,
2866 "TLDAP_CONFIDENTIALITY_REQUIRED" },
2867 { TLDAP_SASL_BIND_IN_PROGRESS,
2868 "TLDAP_SASL_BIND_IN_PROGRESS" },
2869 { TLDAP_NO_SUCH_ATTRIBUTE,
2870 "TLDAP_NO_SUCH_ATTRIBUTE" },
2871 { TLDAP_UNDEFINED_TYPE,
2872 "TLDAP_UNDEFINED_TYPE" },
2873 { TLDAP_INAPPROPRIATE_MATCHING,
2874 "TLDAP_INAPPROPRIATE_MATCHING" },
2875 { TLDAP_CONSTRAINT_VIOLATION,
2876 "TLDAP_CONSTRAINT_VIOLATION" },
2877 { TLDAP_TYPE_OR_VALUE_EXISTS,
2878 "TLDAP_TYPE_OR_VALUE_EXISTS" },
2879 { TLDAP_INVALID_SYNTAX,
2880 "TLDAP_INVALID_SYNTAX" },
2881 { TLDAP_NO_SUCH_OBJECT,
2882 "TLDAP_NO_SUCH_OBJECT" },
2883 { TLDAP_ALIAS_PROBLEM,
2884 "TLDAP_ALIAS_PROBLEM" },
2885 { TLDAP_INVALID_DN_SYNTAX,
2886 "TLDAP_INVALID_DN_SYNTAX" },
2889 { TLDAP_ALIAS_DEREF_PROBLEM,
2890 "TLDAP_ALIAS_DEREF_PROBLEM" },
2891 { TLDAP_INAPPROPRIATE_AUTH,
2892 "TLDAP_INAPPROPRIATE_AUTH" },
2893 { TLDAP_INVALID_CREDENTIALS,
2894 "TLDAP_INVALID_CREDENTIALS" },
2895 { TLDAP_INSUFFICIENT_ACCESS,
2896 "TLDAP_INSUFFICIENT_ACCESS" },
2899 { TLDAP_UNAVAILABLE,
2900 "TLDAP_UNAVAILABLE" },
2901 { TLDAP_UNWILLING_TO_PERFORM,
2902 "TLDAP_UNWILLING_TO_PERFORM" },
2903 { TLDAP_LOOP_DETECT,
2904 "TLDAP_LOOP_DETECT" },
2905 { TLDAP_NAMING_VIOLATION,
2906 "TLDAP_NAMING_VIOLATION" },
2907 { TLDAP_OBJECT_CLASS_VIOLATION,
2908 "TLDAP_OBJECT_CLASS_VIOLATION" },
2909 { TLDAP_NOT_ALLOWED_ON_NONLEAF,
2910 "TLDAP_NOT_ALLOWED_ON_NONLEAF" },
2911 { TLDAP_NOT_ALLOWED_ON_RDN,
2912 "TLDAP_NOT_ALLOWED_ON_RDN" },
2913 { TLDAP_ALREADY_EXISTS,
2914 "TLDAP_ALREADY_EXISTS" },
2915 { TLDAP_NO_OBJECT_CLASS_MODS,
2916 "TLDAP_NO_OBJECT_CLASS_MODS" },
2917 { TLDAP_RESULTS_TOO_LARGE,
2918 "TLDAP_RESULTS_TOO_LARGE" },
2919 { TLDAP_AFFECTS_MULTIPLE_DSAS,
2920 "TLDAP_AFFECTS_MULTIPLE_DSAS" },
2923 { TLDAP_SERVER_DOWN,
2924 "TLDAP_SERVER_DOWN" },
2925 { TLDAP_LOCAL_ERROR,
2926 "TLDAP_LOCAL_ERROR" },
2927 { TLDAP_ENCODING_ERROR,
2928 "TLDAP_ENCODING_ERROR" },
2929 { TLDAP_DECODING_ERROR,
2930 "TLDAP_DECODING_ERROR" },
2933 { TLDAP_AUTH_UNKNOWN,
2934 "TLDAP_AUTH_UNKNOWN" },
2935 { TLDAP_FILTER_ERROR,
2936 "TLDAP_FILTER_ERROR" },
2937 { TLDAP_USER_CANCELLED,
2938 "TLDAP_USER_CANCELLED" },
2939 { TLDAP_PARAM_ERROR,
2940 "TLDAP_PARAM_ERROR" },
2942 "TLDAP_NO_MEMORY" },
2943 { TLDAP_CONNECT_ERROR,
2944 "TLDAP_CONNECT_ERROR" },
2945 { TLDAP_NOT_SUPPORTED,
2946 "TLDAP_NOT_SUPPORTED" },
2947 { TLDAP_CONTROL_NOT_FOUND,
2948 "TLDAP_CONTROL_NOT_FOUND" },
2949 { TLDAP_NO_RESULTS_RETURNED,
2950 "TLDAP_NO_RESULTS_RETURNED" },
2951 { TLDAP_MORE_RESULTS_TO_RETURN,
2952 "TLDAP_MORE_RESULTS_TO_RETURN" },
2953 { TLDAP_CLIENT_LOOP,
2954 "TLDAP_CLIENT_LOOP" },
2955 { TLDAP_REFERRAL_LIMIT_EXCEEDED,
2956 "TLDAP_REFERRAL_LIMIT_EXCEEDED" },
2959 const char *tldap_rc2string(TLDAPRC rc)
2963 for (i=0; i<ARRAY_SIZE(tldaprc_errmap); i++) {
2964 if (TLDAP_RC_EQUAL(rc, tldaprc_errmap[i].rc)) {
2965 return tldaprc_errmap[i].string;
2969 return "Unknown LDAP Error";