s3:registry: Initialize struct security_ace ace[]
[samba4-gss.git] / source3 / lib / tldap.c
blobac95272fe0636a9796a406f78d8244db85b2baaa
1 /*
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/>.
20 #include "replace.h"
21 #include "tldap.h"
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)
40 uint64_t err;
42 if (TLDAP_RC_IS_SUCCESS(rc)) {
43 return false;
46 err = TEVENT_TLDAP_RC_MAGIC;
47 err <<= 32;
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;
56 uint64_t err;
58 if (!tevent_req_is_error(req, &state, &err)) {
59 return false;
61 switch (state) {
62 case TEVENT_REQ_TIMED_OUT:
63 *perr = TLDAP_TIMEOUT;
64 break;
65 case TEVENT_REQ_NO_MEMORY:
66 *perr = TLDAP_NO_MEMORY;
67 break;
68 case TEVENT_REQ_USER_ERROR:
69 if ((err >> 32) != TEVENT_TLDAP_RC_MAGIC) {
70 abort();
72 *perr = TLDAP_RC(err & 0xffffffff);
73 break;
74 default:
75 *perr = TLDAP_OPERATIONS_ERROR;
76 break;
78 return true;
81 struct tldap_ctx_attribute {
82 char *name;
83 void *ptr;
86 struct tldap_context {
87 int ld_version;
88 struct tstream_context *plain;
89 bool starttls_needed;
90 struct tstream_context *tls;
91 struct tstream_context *gensec;
92 struct tstream_context *active;
93 int msgid;
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;
101 /* debug */
102 void (*log_fn)(void *context, enum tldap_debug_level level,
103 const char *fmt, va_list ap);
104 void *log_private;
106 struct tldap_ctx_attribute *ctx_attrs;
109 struct tldap_message {
110 struct asn1_data *data;
111 uint8_t *inbuf;
112 int type;
113 int id;
115 /* RESULT_ENTRY */
116 char *dn;
117 struct tldap_attribute *attribs;
119 /* Error data sent by the server */
120 TLDAPRC lderr;
121 char *res_matcheddn;
122 char *res_diagnosticmessage;
123 char *res_referral;
124 DATA_BLOB res_serverSaslCreds;
125 struct {
126 char *oid;
127 DATA_BLOB blob;
128 } res_extended;
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,
138 const char *fmt,
139 va_list ap) PRINTF_ATTRIBUTE(3,0),
140 void *log_private)
142 ld->log_fn = log_fn;
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, ...)
155 va_list ap;
156 if (!ld) {
157 return;
159 if (ld->log_fn == NULL) {
160 return;
162 va_start(ap, fmt);
163 ld->log_fn(ld->log_private, level, fmt, ap);
164 va_end(ap);
167 static int tldap_next_msgid(struct tldap_context *ld)
169 int result;
171 result = ld->msgid++;
172 if (ld->msgid == INT_MAX) {
173 ld->msgid = 1;
175 return result;
178 struct tldap_context *tldap_context_create(TALLOC_CTX *mem_ctx, int fd)
180 struct tldap_context *ctx;
181 int ret;
183 ctx = talloc_zero(mem_ctx, struct tldap_context);
184 if (ctx == NULL) {
185 return NULL;
187 ret = tstream_bsd_existing_socket(ctx, fd, &ctx->plain);
188 if (ret == -1) {
189 TALLOC_FREE(ctx);
190 return NULL;
192 ctx->active = ctx->plain;
193 ctx->msgid = 1;
194 ctx->ld_version = 3;
195 ctx->outgoing = tevent_queue_create(ctx, "tldap_outgoing");
196 if (ctx->outgoing == NULL) {
197 TALLOC_FREE(ctx);
198 return NULL;
200 return ctx;
203 bool tldap_connection_ok(struct tldap_context *ld)
205 int ret;
207 if (ld == NULL) {
208 return false;
211 if (ld->active == NULL) {
212 return false;
215 ret = tstream_pending_bytes(ld->active);
216 if (ret == -1) {
217 return false;
220 return true;
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)
230 return ld->plain;
233 void tldap_set_starttls_needed(struct tldap_context *ld, bool needed)
235 if (ld == NULL) {
236 return;
239 ld->starttls_needed = needed;
242 bool tldap_get_starttls_needed(struct tldap_context *ld)
244 if (ld == NULL) {
245 return false;
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;
270 } else {
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;
289 } else {
290 ld->active = ld->plain;
294 static struct tldap_ctx_attribute *tldap_context_findattr(
295 struct tldap_context *ld, const char *name)
297 size_t i, num_attrs;
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];
306 return NULL;
309 bool tldap_context_setattr(struct tldap_context *ld,
310 const char *name, const void *_pptr)
312 struct tldap_ctx_attribute *tmp, *attr;
313 char *tmpname;
314 int num_attrs;
315 void **pptr = (void **)discard_const_p(void,_pptr);
317 attr = tldap_context_findattr(ld, name);
318 if (attr != NULL) {
320 * We don't actually delete attrs, we don't expect tons of
321 * attributes being shuffled around.
323 TALLOC_FREE(attr->ptr);
324 if (*pptr != NULL) {
325 attr->ptr = talloc_move(ld->ctx_attrs, pptr);
326 *pptr = NULL;
328 return true;
331 tmpname = talloc_strdup(ld, name);
332 if (tmpname == NULL) {
333 return false;
336 num_attrs = talloc_array_length(ld->ctx_attrs);
338 tmp = talloc_realloc(ld, ld->ctx_attrs, struct tldap_ctx_attribute,
339 num_attrs+1);
340 if (tmp == NULL) {
341 TALLOC_FREE(tmpname);
342 return false;
344 tmp[num_attrs].name = talloc_move(tmp, &tmpname);
345 if (*pptr != NULL) {
346 tmp[num_attrs].ptr = talloc_move(tmp, pptr);
347 } else {
348 tmp[num_attrs].ptr = NULL;
350 *pptr = NULL;
351 ld->ctx_attrs = tmp;
352 return true;
355 void *tldap_context_getattr(struct tldap_context *ld, const char *name)
357 struct tldap_ctx_attribute *attr = tldap_context_findattr(ld, name);
359 if (attr == NULL) {
360 return NULL;
362 return attr->ptr;
365 struct read_ldap_state {
366 uint8_t *buf;
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);
380 if (req == NULL) {
381 return NULL;
384 subreq = tstream_read_packet_send(state, ev, conn, 7, read_ldap_more,
385 state);
386 if (tevent_req_nomem(subreq, req)) {
387 return tevent_req_post(req, ev);
389 tevent_req_set_callback(subreq, read_ldap_done, req);
390 return 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);
396 size_t pdu_len = 0;
397 int ret;
399 if (buflen < 7) {
401 * We need at least 6 bytes to workout the length
402 * of the pdu.
404 * And we have asked for 7 because the that's
405 * the size of the smallest possible LDAP pdu.
407 return -1;
410 ret = asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), &pdu_len);
411 if (ret == 0) {
412 return 0;
414 if (ret == EAGAIN) {
415 return pdu_len - buflen;
418 return -1;
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);
427 ssize_t nread;
428 int err;
430 nread = tstream_read_packet_recv(subreq, state, &state->buf, &err);
431 TALLOC_FREE(subreq);
432 if (nread == -1) {
433 tevent_req_error(req, err);
434 return;
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)) {
446 return -1;
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;
455 int id;
456 struct iovec iov;
458 struct asn1_data *data;
459 uint8_t *inbuf;
462 static bool tldap_push_controls(struct asn1_data *data,
463 struct tldap_control *sctrls,
464 int num_sctrls)
466 int i;
468 if ((sctrls == NULL) || (num_sctrls == 0)) {
469 return true;
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;
478 if (c->critical) {
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,
495 TLDAPRC status,
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.
506 return;
509 tldap_debug(ld, TLDAP_DEBUG_WARNING,
510 "tldap_context_disconnect: %s at %s\n",
511 tldap_rc2string(status),
512 location);
513 tevent_queue_stop(ld->outgoing);
514 TALLOC_FREE(ld->read_req);
515 ld->active = NULL;
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,
539 int num_sctrls)
541 struct tevent_req *req, *subreq;
542 struct tldap_msg_state *state;
543 DATA_BLOB blob;
544 bool ok;
546 tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_send: sending msg %d\n",
547 id);
549 req = tevent_req_create(mem_ctx, &state, struct tldap_msg_state);
550 if (req == NULL) {
551 return NULL;
553 state->ld = ld;
554 state->ev = ev;
555 state->id = id;
557 ok = tldap_connection_ok(ld);
558 if (!ok) {
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)) {
580 tevent_req_oom(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,
588 &state->iov, 1);
589 if (tevent_req_nomem(subreq, req)) {
590 return tevent_req_post(req, ev);
592 tevent_req_set_callback(subreq, tldap_msg_sent, req);
593 return 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);
602 int i;
604 tevent_req_set_cleanup_fn(req, NULL);
606 for (i=0; i<num_pending; i++) {
607 if (req == ld->pending[i]) {
608 break;
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.
617 return;
620 if (num_pending == 1) {
621 TALLOC_FREE(ld->pending);
622 return;
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 *,
637 num_pending - 1);
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;
652 int num_pending;
654 ld = state->ld;
655 num_pending = tldap_pending_reqs(ld);
657 pending = talloc_realloc(ld, ld->pending, struct tevent_req *,
658 num_pending+1);
659 if (pending == NULL) {
660 return false;
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) {
667 return true;
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);
677 return false;
679 tevent_req_set_callback(ld->read_req, tldap_msg_received, ld);
680 return true;
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);
689 ssize_t nwritten;
690 int err;
692 nwritten = tstream_writev_queue_recv(subreq, &err);
693 TALLOC_FREE(subreq);
694 if (nwritten == -1) {
695 tldap_context_disconnect(state->ld, TLDAP_SERVER_DOWN);
696 return;
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);
705 return state->id;
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;
715 uint8_t *inbuf;
716 ssize_t received;
717 size_t num_pending;
718 size_t i;
719 int err;
720 TLDAPRC status = TLDAP_PROTOCOL_ERROR;
721 int id;
722 uint8_t type;
723 bool ok;
725 received = read_ldap_recv(subreq, talloc_tos(), &inbuf, &err);
726 TALLOC_FREE(subreq);
727 ld->read_req = NULL;
728 if (received == -1) {
729 status = TLDAP_SERVER_DOWN;
730 goto fail;
733 data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
734 if (data == NULL) {
736 * We have to disconnect all, we can't tell which of
737 * the requests this reply is for.
739 status = TLDAP_NO_MEMORY;
740 goto fail;
742 asn1_load_nocopy(data, inbuf, received);
744 ok = true;
745 ok &= asn1_start_tag(data, ASN1_SEQUENCE(0));
746 ok &= asn1_read_Integer(data, &id);
747 ok &= asn1_peek_uint8(data, &type);
749 if (!ok) {
750 status = TLDAP_PROTOCOL_ERROR;
751 goto fail;
754 tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_received: got msg %d "
755 "type %d\n", id, (int)type);
757 if (id == 0) {
758 tldap_debug(
760 TLDAP_DEBUG_WARNING,
761 "tldap_msg_received: got msgid 0 of "
762 "type %"PRIu8", disconnecting\n",
763 type);
764 tldap_context_disconnect(ld, TLDAP_SERVER_DOWN);
765 return;
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])) {
772 break;
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);
779 TALLOC_FREE(data);
780 TALLOC_FREE(inbuf);
781 goto done;
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);
796 done:
797 if (num_pending == 0) {
798 return;
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;
805 goto fail;
807 tevent_req_set_callback(ld->read_req, tldap_msg_received, ld);
808 return;
810 fail:
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;
820 TLDAPRC err;
821 uint8_t msgtype;
823 if (tevent_req_is_ldap_error(req, &err)) {
824 return err;
827 if (!asn1_peek_uint8(state->data, &msgtype)) {
828 return TLDAP_PROTOCOL_ERROR;
831 if (pmsg == NULL) {
832 return TLDAP_SUCCESS;
835 msg = talloc_zero(mem_ctx, struct tldap_message);
836 if (msg == NULL) {
837 return TLDAP_NO_MEMORY;
839 msg->id = state->id;
841 msg->inbuf = talloc_move(msg, &state->inbuf);
842 msg->data = talloc_move(msg, &state->data);
843 msg->type = msgtype;
845 *pmsg = msg;
846 return TLDAP_SUCCESS;
849 struct tldap_req_state {
850 int id;
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);
863 if (req == NULL) {
864 return NULL;
866 state->out = asn1_init(state, ASN1_MAX_TREE_DEPTH);
867 if (state->out == NULL) {
868 goto err;
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;
875 *pstate = state;
876 return req;
878 err:
880 TALLOC_FREE(req);
881 return NULL;
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) {
898 return NULL;
901 memcpy(result, blob.data, blob.length);
902 result[blob.length] = '\0';
903 return result;
906 static bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
907 struct asn1_data *data,
908 char **presult)
910 DATA_BLOB string;
911 char *result;
912 if (!asn1_read_OctetString(data, mem_ctx, &string))
913 return false;
915 result = blob2string_talloc(mem_ctx, string);
917 data_blob_free(&string);
919 if (result == NULL) {
920 return false;
922 *presult = result;
923 return true;
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;
932 int rc;
933 bool ok = true;
935 ok &= asn1_read_enumerated(data, &rc);
936 if (ok) {
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);
943 if (!ok) return ok;
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,
947 &msg->res_referral);
948 ok &= asn1_end_tag(data);
949 } else {
950 msg->res_referral = NULL;
953 return ok;
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,
961 const char *dn,
962 const char *mechanism,
963 DATA_BLOB *creds,
964 struct tldap_control *sctrls,
965 int num_sctrls,
966 struct tldap_control *cctrls,
967 int num_cctrls)
969 struct tevent_req *req, *subreq;
970 struct tldap_req_state *state;
972 req = tldap_req_create(mem_ctx, ld, &state);
973 if (req == NULL) {
974 return NULL;
977 if (dn == NULL) {
978 dn = "";
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;
989 } else {
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);
1008 return req;
1010 err:
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);
1022 TLDAPRC rc;
1023 bool ok;
1025 rc = tldap_msg_recv(subreq, state, &state->result);
1026 TALLOC_FREE(subreq);
1027 if (tevent_req_ldap_error(req, rc)) {
1028 return;
1030 if (state->result->type != TLDAP_RES_BIND) {
1031 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
1032 return;
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))) {
1039 int len;
1041 ok &= asn1_start_tag(state->result->data,
1042 ASN1_CONTEXT_SIMPLE(7));
1043 if (!ok) {
1044 goto decode_error;
1047 len = asn1_tag_remaining(state->result->data);
1048 if (len == -1) {
1049 goto decode_error;
1052 state->result->res_serverSaslCreds =
1053 data_blob_talloc(state->result, NULL, len);
1054 if (state->result->res_serverSaslCreds.data == NULL) {
1055 goto decode_error;
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);
1067 if (!ok) {
1068 goto decode_error;
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);
1075 return;
1077 tevent_req_done(req);
1078 return;
1080 decode_error:
1081 tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
1082 return;
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);
1090 TLDAPRC rc;
1092 if (tevent_req_is_ldap_error(req, &rc)) {
1093 return 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,
1107 const char *dn,
1108 const char *mechanism,
1109 DATA_BLOB *creds,
1110 struct tldap_control *sctrls,
1111 int num_sctrls,
1112 struct tldap_control *cctrls,
1113 int num_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);
1123 if (ev == NULL) {
1124 goto fail;
1126 req = tldap_sasl_bind_send(frame, ev, ld, dn, mechanism, creds,
1127 sctrls, num_sctrls, cctrls, num_cctrls);
1128 if (req == NULL) {
1129 goto fail;
1131 if (!tevent_req_poll(req, ev)) {
1132 rc = TLDAP_OPERATIONS_ERROR;
1133 goto fail;
1135 rc = tldap_sasl_bind_recv(req, mem_ctx, serverSaslCreds);
1136 tldap_save_msg(ld, req);
1137 fail:
1138 TALLOC_FREE(frame);
1139 return rc;
1142 struct tevent_req *tldap_simple_bind_send(TALLOC_CTX *mem_ctx,
1143 struct tevent_context *ev,
1144 struct tldap_context *ld,
1145 const char *dn,
1146 const char *passwd)
1148 DATA_BLOB cred;
1150 if (passwd != NULL) {
1151 cred.data = discard_const_p(uint8_t, passwd);
1152 cred.length = strlen(passwd);
1153 } else {
1154 cred.data = discard_const_p(uint8_t, "");
1155 cred.length = 0;
1157 return tldap_sasl_bind_send(mem_ctx, ev, ld, dn, NULL, &cred, NULL, 0,
1158 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,
1167 const char *passwd)
1169 DATA_BLOB cred;
1171 if (passwd != NULL) {
1172 cred.data = discard_const_p(uint8_t, passwd);
1173 cred.length = strlen(passwd);
1174 } else {
1175 cred.data = discard_const_p(uint8_t, "");
1176 cred.length = 0;
1178 return tldap_sasl_bind(ld, dn, NULL, &cred, NULL, 0, NULL, 0,
1179 NULL, NULL);
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;
1221 bool dot = false;
1222 int i;
1224 /* first char has stricter rules */
1225 if (isdigit(*s)) {
1226 is_oid = true;
1227 } else if (!tldap_is_alpha(*s)) {
1228 /* bad first char */
1229 return false;
1232 for (i = 1; i < len; i++) {
1234 if (is_oid) {
1235 if (isdigit(s[i])) {
1236 dot = false;
1237 continue;
1239 if (s[i] == '.') {
1240 if (dot) {
1241 /* malformed */
1242 return false;
1244 dot = true;
1245 continue;
1247 } else {
1248 if (tldap_is_adh(s[i])) {
1249 continue;
1253 if (s[i] == ';') {
1254 if (no_tagopts) {
1255 /* no tagging options */
1256 return false;
1258 if (dot) {
1259 /* malformed */
1260 return false;
1262 if ((i + 1) == len) {
1263 /* malformed */
1264 return false;
1267 is_oid = false;
1268 continue;
1272 if (dot) {
1273 /* malformed */
1274 return false;
1277 return true;
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 */
1287 while (*s) {
1288 s = strchr(s, ')');
1289 if (s && (*(s - 1) == '\\')) {
1290 s++;
1291 continue;
1293 break;
1295 if (!s || !(*s == ')')) {
1296 /* malformed filter */
1297 return NULL;
1300 *_s = s;
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];
1309 int c = 0;
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';
1314 c = c << 4;
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';
1319 return c;
1322 return -1;
1325 static bool tldap_find_first_star(const char *val, const char **star)
1327 const char *s;
1329 for (s = val; *s; s++) {
1330 switch (*s) {
1331 case '\\':
1332 if (isxdigit(s[1]) && isxdigit(s[2])) {
1333 s += 2;
1334 break;
1336 /* not hex based escape, check older syntax */
1337 switch (s[1]) {
1338 case '(':
1339 case ')':
1340 case '*':
1341 case '\\':
1342 s++;
1343 break;
1344 default:
1345 /* invalid escape sequence */
1346 return false;
1348 break;
1349 case ')':
1350 /* end of val, nothing found */
1351 *star = s;
1352 return true;
1354 case '*':
1355 *star = s;
1356 return true;
1360 /* string ended without closing parenthesis, filter is malformed */
1361 return false;
1364 static bool tldap_unescape_inplace(char *value, size_t *val_len)
1366 int c;
1367 size_t i, p;
1369 for (i = 0,p = 0; i < *val_len; i++) {
1371 switch (value[i]) {
1372 case '(':
1373 case ')':
1374 case '*':
1375 /* these must be escaped */
1376 return false;
1378 case '\\':
1379 if (!value[i + 1]) {
1380 /* invalid EOL */
1381 return false;
1383 i++;
1385 /* LDAPv3 escaped */
1386 c = tldap_hex2char(&value[i]);
1387 if (c >= 0 && c < 256) {
1388 value[p] = c;
1389 i++;
1390 p++;
1391 break;
1394 /* LDAPv2 escaped */
1395 switch (value[i]) {
1396 case '(':
1397 case ')':
1398 case '*':
1399 case '\\':
1400 value[p] = value[i];
1401 p++;
1403 break;
1404 default:
1405 /* invalid */
1406 return false;
1408 break;
1410 default:
1411 value[p] = value[i];
1412 p++;
1415 value[p] = '\0';
1416 *val_len = p;
1417 return true;
1420 static bool tldap_push_filter_basic(struct tldap_context *ld,
1421 struct asn1_data *data,
1422 const char **_s);
1423 static bool tldap_push_filter_substring(struct tldap_context *ld,
1424 struct asn1_data *data,
1425 const char *val,
1426 const char **_s);
1427 static bool tldap_push_filter_int(struct tldap_context *ld,
1428 struct asn1_data *data,
1429 const char **_s)
1431 const char *s = *_s;
1432 bool ret;
1434 if (*s != '(') {
1435 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1436 "Incomplete or malformed filter\n");
1437 return false;
1439 s++;
1441 /* we are right after a parenthesis,
1442 * find out what op we have at hand */
1443 switch (*s) {
1444 case '&':
1445 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: AND\n");
1446 if (!asn1_push_tag(data, TLDAP_FILTER_AND)) return false;
1447 s++;
1448 break;
1450 case '|':
1451 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: OR\n");
1452 if (!asn1_push_tag(data, TLDAP_FILTER_OR)) return false;
1453 s++;
1454 break;
1456 case '!':
1457 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: NOT\n");
1458 if (!asn1_push_tag(data, TLDAP_FILTER_NOT)) return false;
1459 s++;
1460 ret = tldap_push_filter_int(ld, data, &s);
1461 if (!ret) {
1462 return false;
1464 if (!asn1_pop_tag(data)) return false;
1465 goto done;
1467 case '(':
1468 case ')':
1469 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1470 "Invalid parenthesis '%c'\n", *s);
1471 return false;
1473 case '\0':
1474 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1475 "Invalid filter termination\n");
1476 return false;
1478 default:
1479 ret = tldap_push_filter_basic(ld, data, &s);
1480 if (!ret) {
1481 return false;
1483 goto done;
1486 /* only and/or filters get here.
1487 * go through the list of filters */
1489 if (*s == ')') {
1490 /* RFC 4526: empty and/or */
1491 if (!asn1_pop_tag(data)) return false;
1492 goto done;
1495 while (*s) {
1496 ret = tldap_push_filter_int(ld, data, &s);
1497 if (!ret) {
1498 return false;
1501 if (*s == ')') {
1502 /* end of list, return */
1503 if (!asn1_pop_tag(data)) return false;
1504 break;
1508 done:
1509 if (*s != ')') {
1510 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1511 "Incomplete or malformed filter\n");
1512 return false;
1514 s++;
1516 if (asn1_has_error(data)) {
1517 return false;
1520 *_s = s;
1521 return true;
1525 static bool tldap_push_filter_basic(struct tldap_context *ld,
1526 struct asn1_data *data,
1527 const char **_s)
1529 TALLOC_CTX *tmpctx = talloc_tos();
1530 const char *s = *_s;
1531 const char *e;
1532 const char *eq;
1533 const char *val;
1534 const char *type;
1535 const char *dn;
1536 const char *rule;
1537 const char *star;
1538 size_t type_len = 0;
1539 char *uval;
1540 size_t uval_len;
1541 bool write_octect = true;
1542 bool ret;
1544 eq = strchr(s, '=');
1545 if (!eq) {
1546 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1547 "Invalid filter, missing equal sign\n");
1548 return false;
1551 val = eq + 1;
1552 e = eq - 1;
1554 switch (*e) {
1555 case '<':
1556 if (!asn1_push_tag(data, TLDAP_FILTER_LE)) return false;
1557 break;
1559 case '>':
1560 if (!asn1_push_tag(data, TLDAP_FILTER_GE)) return false;
1561 break;
1563 case '~':
1564 if (!asn1_push_tag(data, TLDAP_FILTER_APX)) return false;
1565 break;
1567 case ':':
1568 if (!asn1_push_tag(data, TLDAP_FILTER_EXT)) return false;
1569 write_octect = false;
1571 type = NULL;
1572 dn = NULL;
1573 rule = NULL;
1575 if (*s == ':') { /* [:dn]:rule:= value */
1576 if (s == e) {
1577 /* malformed filter */
1578 return false;
1580 dn = s;
1581 } else { /* type[:dn][:rule]:= value */
1582 type = s;
1583 dn = strchr(s, ':');
1584 type_len = dn - type;
1585 if (dn == e) { /* type:= value */
1586 dn = NULL;
1589 if (dn) {
1590 dn++;
1592 rule = strchr(dn, ':');
1593 if (rule == NULL) {
1594 return false;
1596 if ((rule == dn + 1) || rule + 1 == e) {
1597 /* malformed filter, contains "::" */
1598 return false;
1601 if (strncasecmp_m(dn, "dn:", 3) != 0) {
1602 if (rule == e) {
1603 rule = dn;
1604 dn = NULL;
1605 } else {
1606 /* malformed filter. With two
1607 * optionals, the first must be "dn"
1609 return false;
1611 } else {
1612 if (rule == e) {
1613 rule = NULL;
1614 } else {
1615 rule++;
1620 if (!type && !dn && !rule) {
1621 /* malformed filter, there must be at least one */
1622 return false;
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 */
1635 if (rule) {
1636 ret = tldap_is_attrdesc(rule, e - rule, true);
1637 if (!ret) {
1638 return false;
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 */
1646 if (type) {
1647 ret = tldap_is_attrdesc(type, type_len, false);
1648 if (!ret) {
1649 return 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);
1657 if (!uval) {
1658 return false;
1660 uval_len = *_s - val;
1661 ret = tldap_unescape_inplace(uval, &uval_len);
1662 if (!ret) {
1663 return false;
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;
1673 break;
1675 default:
1676 e = eq;
1678 ret = tldap_is_attrdesc(s, e - s, false);
1679 if (!ret) {
1680 return false;
1683 if (strncmp(val, "*)", 2) == 0) {
1684 /* presence */
1685 if (!asn1_push_tag(data, TLDAP_FILTER_PRES)) return false;
1686 if (!asn1_write(data, s, e - s)) return false;
1687 *_s = val + 1;
1688 write_octect = false;
1689 break;
1692 ret = tldap_find_first_star(val, &star);
1693 if (!ret) {
1694 return false;
1696 if (*star == '*') {
1697 /* substring */
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);
1701 if (!ret) {
1702 return false;
1704 *_s = s;
1705 write_octect = false;
1706 break;
1709 /* if nothing else, then it is just equality */
1710 if (!asn1_push_tag(data, TLDAP_FILTER_EQ)) return false;
1711 write_octect = true;
1712 break;
1715 if (write_octect) {
1716 uval = tldap_get_val(tmpctx, val, _s);
1717 if (!uval) {
1718 return false;
1720 uval_len = *_s - val;
1721 ret = tldap_unescape_inplace(uval, &uval_len);
1722 if (!ret) {
1723 return false;
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)) {
1731 return false;
1733 return asn1_pop_tag(data);
1736 static bool tldap_push_filter_substring(struct tldap_context *ld,
1737 struct asn1_data *data,
1738 const char *val,
1739 const char **_s)
1741 TALLOC_CTX *tmpctx = talloc_tos();
1742 bool initial = true;
1743 const char *star;
1744 char *chunk;
1745 size_t chunk_len;
1746 bool ret;
1749 SubstringFilter ::= SEQUENCE {
1750 type AttributeDescription,
1751 -- at least one must be present
1752 substrings SEQUENCE OF CHOICE {
1753 initial [0] LDAPString,
1754 any [1] LDAPString,
1755 final [2] LDAPString } }
1757 if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
1759 do {
1760 ret = tldap_find_first_star(val, &star);
1761 if (!ret) {
1762 return false;
1764 chunk_len = star - val;
1766 switch (*star) {
1767 case '*':
1768 if (!initial && chunk_len == 0) {
1769 /* found '**', which is illegal */
1770 return false;
1772 break;
1773 case ')':
1774 if (initial) {
1775 /* no stars ?? */
1776 return false;
1778 /* we are done */
1779 break;
1780 default:
1781 /* ?? */
1782 return false;
1785 if (initial && chunk_len == 0) {
1786 val = star + 1;
1787 initial = false;
1788 continue;
1791 chunk = talloc_strndup(tmpctx, val, chunk_len);
1792 if (!chunk) {
1793 return false;
1795 ret = tldap_unescape_inplace(chunk, &chunk_len);
1796 if (!ret) {
1797 return false;
1799 switch (*star) {
1800 case '*':
1801 if (initial) {
1802 if (!asn1_push_tag(data, TLDAP_SUB_INI)) return false;
1803 initial = false;
1804 } else {
1805 if (!asn1_push_tag(data, TLDAP_SUB_ANY)) return false;
1807 break;
1808 case ')':
1809 if (!asn1_push_tag(data, TLDAP_SUB_FIN)) return false;
1810 break;
1811 default:
1812 /* ?? */
1813 return false;
1815 if (!asn1_write(data, chunk, chunk_len)) return false;
1816 if (!asn1_pop_tag(data)) return false;
1818 val = star + 1;
1820 } while (*star == '*');
1822 *_s = 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,
1835 const char *filter)
1837 const char *s = filter;
1838 bool ret;
1840 ret = tldap_push_filter_int(ld, data, &s);
1841 if (ret && *s) {
1842 tldap_debug(ld, TLDAP_DEBUG_ERROR,
1843 "Incomplete or malformed filter\n");
1844 return false;
1846 return ret;
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,
1857 const char *filter,
1858 const char **attrs,
1859 int num_attrs,
1860 int attrsonly,
1861 struct tldap_control *sctrls,
1862 int num_sctrls,
1863 struct tldap_control *cctrls,
1864 int num_cctrls,
1865 int timelimit,
1866 int sizelimit,
1867 int deref)
1869 struct tevent_req *req, *subreq;
1870 struct tldap_req_state *state;
1871 int i;
1873 req = tldap_req_create(mem_ctx, ld, &state);
1874 if (req == NULL) {
1875 return NULL;
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);
1903 return req;
1905 encoding_error:
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);
1916 TLDAPRC rc;
1918 rc = tldap_msg_recv(subreq, state, &state->result);
1919 if (tevent_req_ldap_error(req, rc)) {
1920 return;
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);
1927 return;
1929 tevent_req_notify_callback(req);
1930 break;
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);
1939 return;
1941 tevent_req_done(req);
1942 break;
1943 default:
1944 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
1945 return;
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);
1954 TLDAPRC rc;
1956 if (!tevent_req_is_in_progress(req)
1957 && tevent_req_is_ldap_error(req, &rc)) {
1958 return 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:
1965 break;
1966 default:
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);
1995 if (req == NULL) {
1996 return NULL;
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);
2007 return 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;
2017 size_t num_msgs;
2018 TLDAPRC rc;
2019 int msgtype;
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)) {
2024 return;
2027 msgtype = tldap_msg_type(msg);
2028 if (msgtype == TLDAP_RES_SEARCH_RESULT) {
2029 state->result = msg;
2030 tevent_req_done(req);
2031 return;
2034 num_msgs = talloc_array_length(state->msgs);
2036 tmp = talloc_realloc(state, state->msgs, struct tldap_message *,
2037 num_msgs + 1);
2038 if (tevent_req_nomem(tmp, req)) {
2039 return;
2041 state->msgs = tmp;
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);
2051 TLDAPRC rc;
2053 if (tevent_req_is_ldap_error(req, &rc)) {
2054 return rc;
2057 if (msgs != NULL) {
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)
2075 TALLOC_CTX *frame;
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)) {
2083 return TLDAP_BUSY;
2086 frame = talloc_stackframe();
2088 ev = samba_tevent_context_init(frame);
2089 if (ev == NULL) {
2090 goto fail;
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);
2096 if (req == NULL) {
2097 goto fail;
2099 if (!tevent_req_poll(req, ev)) {
2100 rc = TLDAP_OPERATIONS_ERROR;
2101 goto fail;
2103 rc = tldap_search_all_recv(req, frame, &msgs, &result);
2104 TALLOC_FREE(req);
2105 if (!TLDAP_RC_IS_SUCCESS(rc)) {
2106 goto fail;
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);
2115 fail:
2116 TALLOC_FREE(frame);
2117 return rc;
2120 static bool tldap_parse_search_entry(struct tldap_message *msg)
2122 int num_attribs = 0;
2124 if (msg->type != TLDAP_RES_SEARCH_ENTRY) {
2125 return false;
2127 if (!asn1_start_tag(msg->data, TLDAP_RES_SEARCH_ENTRY)) {
2128 return false;
2131 /* dn */
2133 if (!asn1_read_OctetString_talloc(msg, msg->data, &msg->dn)) return false;
2135 if (msg->dn == NULL) {
2136 return false;
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) {
2147 return false;
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;
2153 int num_values = 0;
2155 attrib = &msg->attribs[num_attribs];
2156 attrib->values = talloc_array(msg->attribs, DATA_BLOB, 1);
2157 if (attrib->values == NULL) {
2158 return false;
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,
2171 num_values + 2);
2172 if (attrib->values == NULL) {
2173 return false;
2175 num_values += 1;
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,
2185 num_attribs + 2);
2186 if (msg->attribs == NULL) {
2187 return false;
2189 num_attribs += 1;
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))) {
2199 return false;
2201 *dn = msg->dn;
2202 return true;
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))) {
2210 return false;
2212 *attributes = msg->attribs;
2213 *num_attributes = talloc_array_length(msg->attribs);
2214 return true;
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;
2223 bool ret = false;
2225 msg->res_sctrls = NULL;
2227 if (!asn1_peek_tag(data, ASN1_CONTEXT(0))) {
2228 return true;
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;
2235 char *oid = NULL;
2237 sctrls = talloc_realloc(msg, sctrls, struct tldap_control,
2238 num_controls + 1);
2239 if (sctrls == NULL) {
2240 goto out;
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)) {
2247 goto out;
2249 c->oid = oid;
2250 if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
2251 if (!asn1_read_BOOLEAN(data, &c->critical)) goto out;
2252 } else {
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)) {
2258 goto out;
2260 if (!asn1_end_tag(data)) goto out; /* ASN1_SEQUENCE(0) */
2262 num_controls += 1;
2265 if (!asn1_end_tag(data)) goto out; /* ASN1_CONTEXT(0) */
2267 ret = true;
2269 out:
2271 if (ret) {
2272 msg->res_sctrls = sctrls;
2273 } else {
2274 TALLOC_FREE(sctrls);
2276 return ret;
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);
2285 TLDAPRC rc;
2287 rc = tldap_msg_recv(subreq, state, &state->result);
2288 TALLOC_FREE(subreq);
2289 if (tevent_req_ldap_error(req, rc)) {
2290 return;
2292 if (state->result->type != type) {
2293 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
2294 return;
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);
2301 return;
2303 if (!TLDAP_RC_IS_SUCCESS(state->result->lderr)) {
2304 tevent_req_ldap_error(req, state->result->lderr);
2305 return;
2307 tevent_req_done(req);
2310 static TLDAPRC tldap_simple_recv(struct tevent_req *req)
2312 TLDAPRC rc;
2313 if (tevent_req_is_ldap_error(req, &rc)) {
2314 return 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,
2324 const char *dn,
2325 struct tldap_mod *attributes,
2326 int num_attributes,
2327 struct tldap_control *sctrls,
2328 int num_sctrls,
2329 struct tldap_control *cctrls,
2330 int num_cctrls)
2332 struct tevent_req *req, *subreq;
2333 struct tldap_req_state *state;
2334 int i, j;
2336 req = tldap_req_create(mem_ctx, ld, &state);
2337 if (req == NULL) {
2338 return NULL;
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);
2369 return req;
2371 err:
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);
2398 if (ev == NULL) {
2399 goto fail;
2401 req = tldap_add_send(frame, ev, ld, dn, attributes, num_attributes,
2402 sctrls, num_sctrls, cctrls, num_cctrls);
2403 if (req == NULL) {
2404 goto fail;
2406 if (!tevent_req_poll(req, ev)) {
2407 rc = TLDAP_OPERATIONS_ERROR;
2408 goto fail;
2410 rc = tldap_add_recv(req);
2411 tldap_save_msg(ld, req);
2412 fail:
2413 TALLOC_FREE(frame);
2414 return rc;
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,
2422 const char *dn,
2423 struct tldap_mod *mods, int num_mods,
2424 struct tldap_control *sctrls,
2425 int num_sctrls,
2426 struct tldap_control *cctrls,
2427 int num_cctrls)
2429 struct tevent_req *req, *subreq;
2430 struct tldap_req_state *state;
2431 int i, j;
2433 req = tldap_req_create(mem_ctx, ld, &state);
2434 if (req == NULL) {
2435 return NULL;
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);
2469 return req;
2471 err:
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);
2498 if (ev == NULL) {
2499 goto fail;
2501 req = tldap_modify_send(frame, ev, ld, dn, mods, num_mods,
2502 sctrls, num_sctrls, cctrls, num_cctrls);
2503 if (req == NULL) {
2504 goto fail;
2506 if (!tevent_req_poll(req, ev)) {
2507 rc = TLDAP_OPERATIONS_ERROR;
2508 goto fail;
2510 rc = tldap_modify_recv(req);
2511 tldap_save_msg(ld, req);
2512 fail:
2513 TALLOC_FREE(frame);
2514 return rc;
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,
2522 const char *dn,
2523 struct tldap_control *sctrls,
2524 int num_sctrls,
2525 struct tldap_control *cctrls,
2526 int num_cctrls)
2528 struct tevent_req *req, *subreq;
2529 struct tldap_req_state *state;
2531 req = tldap_req_create(mem_ctx, ld, &state);
2532 if (req == NULL) {
2533 return NULL;
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);
2546 return req;
2548 err:
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);
2574 if (ev == NULL) {
2575 goto fail;
2577 req = tldap_delete_send(frame, ev, ld, dn, sctrls, num_sctrls,
2578 cctrls, num_cctrls);
2579 if (req == NULL) {
2580 goto fail;
2582 if (!tevent_req_poll(req, ev)) {
2583 rc = TLDAP_OPERATIONS_ERROR;
2584 goto fail;
2586 rc = tldap_delete_recv(req);
2587 tldap_save_msg(ld, req);
2588 fail:
2589 TALLOC_FREE(frame);
2590 return rc;
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,
2598 const char *in_oid,
2599 const DATA_BLOB *in_blob,
2600 struct tldap_control *sctrls,
2601 int num_sctrls,
2602 struct tldap_control *cctrls,
2603 int num_cctrls)
2605 struct tevent_req *req, *subreq;
2606 struct tldap_req_state *state;
2608 req = tldap_req_create(mem_ctx, ld, &state);
2609 if (req == NULL) {
2610 return NULL;
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);
2633 return req;
2635 err:
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);
2647 TLDAPRC rc;
2648 bool ok;
2650 rc = tldap_msg_recv(subreq, state, &state->result);
2651 TALLOC_FREE(subreq);
2652 if (tevent_req_ldap_error(req, rc)) {
2653 return;
2655 if (state->result->type != TLDAP_RES_EXTENDED) {
2656 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
2657 return;
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));
2666 if (!ok) {
2667 goto decode_error;
2670 ok &= asn1_read_LDAPString(state->result->data,
2671 state->result,
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))) {
2678 int len;
2680 ok &= asn1_start_tag(state->result->data,
2681 ASN1_CONTEXT_SIMPLE(11));
2682 if (!ok) {
2683 goto decode_error;
2686 len = asn1_tag_remaining(state->result->data);
2687 if (len == -1) {
2688 goto decode_error;
2691 state->result->res_extended.blob =
2692 data_blob_talloc(state->result, NULL, len);
2693 if (state->result->res_extended.blob.data == NULL) {
2694 goto decode_error;
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);
2706 if (!ok) {
2707 goto decode_error;
2710 if (!TLDAP_RC_IS_SUCCESS(state->result->lderr)) {
2711 tevent_req_ldap_error(req, state->result->lderr);
2712 return;
2714 tevent_req_done(req);
2715 return;
2717 decode_error:
2718 tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
2719 return;
2722 TLDAPRC tldap_extended_recv(struct tevent_req *req,
2723 TALLOC_CTX *mem_ctx,
2724 char **out_oid,
2725 DATA_BLOB *out_blob)
2727 struct tldap_req_state *state = tevent_req_data(
2728 req, struct tldap_req_state);
2729 TLDAPRC rc;
2731 if (tevent_req_is_ldap_error(req, &rc)) {
2732 return 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);
2743 out_blob->length =
2744 state->result->res_extended.blob.length;
2747 return state->result->lderr;
2750 TLDAPRC tldap_extended(struct tldap_context *ld,
2751 const char *in_oid,
2752 const DATA_BLOB *in_blob,
2753 struct tldap_control *sctrls,
2754 int num_sctrls,
2755 struct tldap_control *cctrls,
2756 int num_cctrls,
2757 TALLOC_CTX *mem_ctx,
2758 char **out_oid,
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);
2767 if (ev == NULL) {
2768 goto fail;
2770 req = tldap_extended_send(frame, ev, ld,
2771 in_oid, in_blob,
2772 sctrls, num_sctrls,
2773 cctrls, num_cctrls);
2774 if (req == NULL) {
2775 goto fail;
2777 if (!tevent_req_poll(req, ev)) {
2778 rc = TLDAP_OPERATIONS_ERROR;
2779 goto fail;
2781 rc = tldap_extended_recv(req, mem_ctx, out_oid, out_blob);
2782 tldap_save_msg(ld, req);
2783 fail:
2784 TALLOC_FREE(frame);
2785 return rc;
2788 int tldap_msg_id(const struct tldap_message *msg)
2790 return msg->id;
2793 int tldap_msg_type(const struct tldap_message *msg)
2795 return msg->type;
2798 const char *tldap_msg_matcheddn(struct tldap_message *msg)
2800 if (msg == NULL) {
2801 return NULL;
2803 return msg->res_matcheddn;
2806 const char *tldap_msg_diagnosticmessage(struct tldap_message *msg)
2808 if (msg == NULL) {
2809 return NULL;
2811 return msg->res_diagnosticmessage;
2814 const char *tldap_msg_referral(struct tldap_message *msg)
2816 if (msg == NULL) {
2817 return NULL;
2819 return msg->res_referral;
2822 void tldap_msg_sctrls(struct tldap_message *msg, int *num_sctrls,
2823 struct tldap_control **sctrls)
2825 if (msg == NULL) {
2826 *sctrls = NULL;
2827 *num_sctrls = 0;
2828 return;
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[] =
2841 { TLDAP_SUCCESS,
2842 "TLDAP_SUCCESS" },
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" },
2859 { TLDAP_REFERRAL,
2860 "TLDAP_REFERRAL" },
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" },
2887 { TLDAP_IS_LEAF,
2888 "TLDAP_IS_LEAF" },
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" },
2897 { TLDAP_BUSY,
2898 "TLDAP_BUSY" },
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" },
2921 { TLDAP_OTHER,
2922 "TLDAP_OTHER" },
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" },
2931 { TLDAP_TIMEOUT,
2932 "TLDAP_TIMEOUT" },
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" },
2941 { TLDAP_NO_MEMORY,
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)
2961 size_t i;
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";