Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Infrastructure for async ldap client requests
4 : Copyright (C) Volker Lendecke 2009
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
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 :
31 : static TLDAPRC tldap_simple_recv(struct tevent_req *req);
32 : static bool tldap_msg_set_pending(struct tevent_req *req);
33 :
34 : #define TEVENT_TLDAP_RC_MAGIC (0x87bcd26e)
35 :
36 0 : bool tevent_req_ldap_error(struct tevent_req *req, TLDAPRC rc)
37 : {
38 : uint64_t err;
39 :
40 0 : if (TLDAP_RC_IS_SUCCESS(rc)) {
41 0 : return false;
42 : }
43 :
44 0 : err = TEVENT_TLDAP_RC_MAGIC;
45 0 : err <<= 32;
46 0 : err |= TLDAP_RC_V(rc);
47 :
48 0 : return tevent_req_error(req, err);
49 : }
50 :
51 0 : bool tevent_req_is_ldap_error(struct tevent_req *req, TLDAPRC *perr)
52 : {
53 : enum tevent_req_state state;
54 : uint64_t err;
55 :
56 0 : if (!tevent_req_is_error(req, &state, &err)) {
57 0 : return false;
58 : }
59 0 : switch (state) {
60 0 : case TEVENT_REQ_TIMED_OUT:
61 0 : *perr = TLDAP_TIMEOUT;
62 0 : break;
63 0 : case TEVENT_REQ_NO_MEMORY:
64 0 : *perr = TLDAP_NO_MEMORY;
65 0 : break;
66 0 : case TEVENT_REQ_USER_ERROR:
67 0 : if ((err >> 32) != TEVENT_TLDAP_RC_MAGIC) {
68 0 : abort();
69 : }
70 0 : *perr = TLDAP_RC(err & 0xffffffff);
71 0 : break;
72 0 : default:
73 0 : *perr = TLDAP_OPERATIONS_ERROR;
74 0 : break;
75 : }
76 0 : return true;
77 : }
78 :
79 : struct tldap_ctx_attribute {
80 : char *name;
81 : void *ptr;
82 : };
83 :
84 : struct tldap_context {
85 : int ld_version;
86 : struct tstream_context *conn;
87 : int msgid;
88 : struct tevent_queue *outgoing;
89 : struct tevent_req **pending;
90 : struct tevent_req *read_req;
91 :
92 : /* For the sync wrappers we need something like get_last_error... */
93 : struct tldap_message *last_msg;
94 :
95 : /* debug */
96 : void (*log_fn)(void *context, enum tldap_debug_level level,
97 : const char *fmt, va_list ap);
98 : void *log_private;
99 :
100 : struct tldap_ctx_attribute *ctx_attrs;
101 : };
102 :
103 : struct tldap_message {
104 : struct asn1_data *data;
105 : uint8_t *inbuf;
106 : int type;
107 : int id;
108 :
109 : /* RESULT_ENTRY */
110 : char *dn;
111 : struct tldap_attribute *attribs;
112 :
113 : /* Error data sent by the server */
114 : TLDAPRC lderr;
115 : char *res_matcheddn;
116 : char *res_diagnosticmessage;
117 : char *res_referral;
118 : DATA_BLOB res_serverSaslCreds;
119 : struct tldap_control *res_sctrls;
120 :
121 : /* Controls sent by the server */
122 : struct tldap_control *ctrls;
123 : };
124 :
125 0 : void tldap_set_debug(struct tldap_context *ld,
126 : void (*log_fn)(void *log_private,
127 : enum tldap_debug_level level,
128 : const char *fmt,
129 : va_list ap) PRINTF_ATTRIBUTE(3,0),
130 : void *log_private)
131 : {
132 0 : ld->log_fn = log_fn;
133 0 : ld->log_private = log_private;
134 0 : }
135 :
136 : static void tldap_debug(
137 : struct tldap_context *ld,
138 : enum tldap_debug_level level,
139 : const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
140 :
141 0 : static void tldap_debug(struct tldap_context *ld,
142 : enum tldap_debug_level level,
143 : const char *fmt, ...)
144 : {
145 : va_list ap;
146 0 : if (!ld) {
147 0 : return;
148 : }
149 0 : if (ld->log_fn == NULL) {
150 0 : return;
151 : }
152 0 : va_start(ap, fmt);
153 0 : ld->log_fn(ld->log_private, level, fmt, ap);
154 0 : va_end(ap);
155 : }
156 :
157 0 : static int tldap_next_msgid(struct tldap_context *ld)
158 : {
159 : int result;
160 :
161 0 : result = ld->msgid++;
162 0 : if (ld->msgid == 2147483647) {
163 0 : ld->msgid = 1;
164 : }
165 0 : return result;
166 : }
167 :
168 0 : struct tldap_context *tldap_context_create(TALLOC_CTX *mem_ctx, int fd)
169 : {
170 : struct tldap_context *ctx;
171 : int ret;
172 :
173 0 : ctx = talloc_zero(mem_ctx, struct tldap_context);
174 0 : if (ctx == NULL) {
175 0 : return NULL;
176 : }
177 0 : ret = tstream_bsd_existing_socket(ctx, fd, &ctx->conn);
178 0 : if (ret == -1) {
179 0 : TALLOC_FREE(ctx);
180 0 : return NULL;
181 : }
182 0 : ctx->msgid = 1;
183 0 : ctx->ld_version = 3;
184 0 : ctx->outgoing = tevent_queue_create(ctx, "tldap_outgoing");
185 0 : if (ctx->outgoing == NULL) {
186 0 : TALLOC_FREE(ctx);
187 0 : return NULL;
188 : }
189 0 : return ctx;
190 : }
191 :
192 0 : bool tldap_connection_ok(struct tldap_context *ld)
193 : {
194 : int ret;
195 :
196 0 : if (ld == NULL) {
197 0 : return false;
198 : }
199 :
200 0 : if (ld->conn == NULL) {
201 0 : return false;
202 : }
203 :
204 0 : ret = tstream_pending_bytes(ld->conn);
205 0 : if (ret == -1) {
206 0 : return false;
207 : }
208 :
209 0 : return true;
210 : }
211 :
212 0 : static size_t tldap_pending_reqs(struct tldap_context *ld)
213 : {
214 0 : return talloc_array_length(ld->pending);
215 : }
216 :
217 0 : struct tstream_context *tldap_get_tstream(struct tldap_context *ld)
218 : {
219 0 : return ld->conn;
220 : }
221 :
222 0 : void tldap_set_tstream(struct tldap_context *ld,
223 : struct tstream_context *stream)
224 : {
225 0 : ld->conn = stream;
226 0 : }
227 :
228 0 : static struct tldap_ctx_attribute *tldap_context_findattr(
229 : struct tldap_context *ld, const char *name)
230 : {
231 : size_t i, num_attrs;
232 :
233 0 : num_attrs = talloc_array_length(ld->ctx_attrs);
234 :
235 0 : for (i=0; i<num_attrs; i++) {
236 0 : if (strcmp(ld->ctx_attrs[i].name, name) == 0) {
237 0 : return &ld->ctx_attrs[i];
238 : }
239 : }
240 0 : return NULL;
241 : }
242 :
243 0 : bool tldap_context_setattr(struct tldap_context *ld,
244 : const char *name, const void *_pptr)
245 : {
246 : struct tldap_ctx_attribute *tmp, *attr;
247 : char *tmpname;
248 : int num_attrs;
249 0 : void **pptr = (void **)discard_const_p(void,_pptr);
250 :
251 0 : attr = tldap_context_findattr(ld, name);
252 0 : if (attr != NULL) {
253 : /*
254 : * We don't actually delete attrs, we don't expect tons of
255 : * attributes being shuffled around.
256 : */
257 0 : TALLOC_FREE(attr->ptr);
258 0 : if (*pptr != NULL) {
259 0 : attr->ptr = talloc_move(ld->ctx_attrs, pptr);
260 0 : *pptr = NULL;
261 : }
262 0 : return true;
263 : }
264 :
265 0 : tmpname = talloc_strdup(ld, name);
266 0 : if (tmpname == NULL) {
267 0 : return false;
268 : }
269 :
270 0 : num_attrs = talloc_array_length(ld->ctx_attrs);
271 :
272 0 : tmp = talloc_realloc(ld, ld->ctx_attrs, struct tldap_ctx_attribute,
273 : num_attrs+1);
274 0 : if (tmp == NULL) {
275 0 : TALLOC_FREE(tmpname);
276 0 : return false;
277 : }
278 0 : tmp[num_attrs].name = talloc_move(tmp, &tmpname);
279 0 : if (*pptr != NULL) {
280 0 : tmp[num_attrs].ptr = talloc_move(tmp, pptr);
281 : } else {
282 0 : tmp[num_attrs].ptr = NULL;
283 : }
284 0 : *pptr = NULL;
285 0 : ld->ctx_attrs = tmp;
286 0 : return true;
287 : }
288 :
289 0 : void *tldap_context_getattr(struct tldap_context *ld, const char *name)
290 : {
291 0 : struct tldap_ctx_attribute *attr = tldap_context_findattr(ld, name);
292 :
293 0 : if (attr == NULL) {
294 0 : return NULL;
295 : }
296 0 : return attr->ptr;
297 : }
298 :
299 : struct read_ldap_state {
300 : uint8_t *buf;
301 : bool done;
302 : };
303 :
304 : static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data);
305 : static void read_ldap_done(struct tevent_req *subreq);
306 :
307 0 : static struct tevent_req *read_ldap_send(TALLOC_CTX *mem_ctx,
308 : struct tevent_context *ev,
309 : struct tstream_context *conn)
310 : {
311 : struct tevent_req *req, *subreq;
312 : struct read_ldap_state *state;
313 :
314 0 : req = tevent_req_create(mem_ctx, &state, struct read_ldap_state);
315 0 : if (req == NULL) {
316 0 : return NULL;
317 : }
318 0 : state->done = false;
319 :
320 0 : subreq = tstream_read_packet_send(state, ev, conn, 2, read_ldap_more,
321 : state);
322 0 : if (tevent_req_nomem(subreq, req)) {
323 0 : return tevent_req_post(req, ev);
324 : }
325 0 : tevent_req_set_callback(subreq, read_ldap_done, req);
326 0 : return req;
327 : }
328 :
329 0 : static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data)
330 : {
331 0 : struct read_ldap_state *state = talloc_get_type_abort(
332 : private_data, struct read_ldap_state);
333 : size_t len;
334 : int i, lensize;
335 :
336 0 : if (state->done) {
337 : /* We've been here, we're done */
338 0 : return 0;
339 : }
340 :
341 : /*
342 : * From ldap.h: LDAP_TAG_MESSAGE is 0x30
343 : */
344 0 : if (buf[0] != 0x30) {
345 0 : return -1;
346 : }
347 :
348 0 : len = buf[1];
349 0 : if ((len & 0x80) == 0) {
350 0 : state->done = true;
351 0 : return len;
352 : }
353 :
354 0 : lensize = (len & 0x7f);
355 0 : len = 0;
356 :
357 0 : if (buflen == 2) {
358 : /* Please get us the full length */
359 0 : return lensize;
360 : }
361 0 : if (buflen > 2 + lensize) {
362 0 : state->done = true;
363 0 : return 0;
364 : }
365 0 : if (buflen != 2 + lensize) {
366 0 : return -1;
367 : }
368 :
369 0 : for (i=0; i<lensize; i++) {
370 0 : len = (len << 8) | buf[2+i];
371 : }
372 0 : return len;
373 : }
374 :
375 0 : static void read_ldap_done(struct tevent_req *subreq)
376 : {
377 0 : struct tevent_req *req = tevent_req_callback_data(
378 : subreq, struct tevent_req);
379 0 : struct read_ldap_state *state = tevent_req_data(
380 : req, struct read_ldap_state);
381 : ssize_t nread;
382 : int err;
383 :
384 0 : nread = tstream_read_packet_recv(subreq, state, &state->buf, &err);
385 0 : TALLOC_FREE(subreq);
386 0 : if (nread == -1) {
387 0 : tevent_req_error(req, err);
388 0 : return;
389 : }
390 0 : tevent_req_done(req);
391 : }
392 :
393 0 : static ssize_t read_ldap_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
394 : uint8_t **pbuf, int *perrno)
395 : {
396 0 : struct read_ldap_state *state = tevent_req_data(
397 : req, struct read_ldap_state);
398 :
399 0 : if (tevent_req_is_unix_error(req, perrno)) {
400 0 : return -1;
401 : }
402 0 : *pbuf = talloc_move(mem_ctx, &state->buf);
403 0 : return talloc_get_size(*pbuf);
404 : }
405 :
406 : struct tldap_msg_state {
407 : struct tldap_context *ld;
408 : struct tevent_context *ev;
409 : int id;
410 : struct iovec iov;
411 :
412 : struct asn1_data *data;
413 : uint8_t *inbuf;
414 : };
415 :
416 0 : static bool tldap_push_controls(struct asn1_data *data,
417 : struct tldap_control *sctrls,
418 : int num_sctrls)
419 : {
420 : int i;
421 :
422 0 : if ((sctrls == NULL) || (num_sctrls == 0)) {
423 0 : return true;
424 : }
425 :
426 0 : if (!asn1_push_tag(data, ASN1_CONTEXT(0))) return false;
427 :
428 0 : for (i=0; i<num_sctrls; i++) {
429 0 : struct tldap_control *c = &sctrls[i];
430 0 : if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
431 0 : if (!asn1_write_OctetString(data, c->oid, strlen(c->oid))) return false;
432 0 : if (c->critical) {
433 0 : if (!asn1_write_BOOLEAN(data, true)) return false;
434 : }
435 0 : if (c->value.data != NULL) {
436 0 : if (!asn1_write_OctetString(data, c->value.data,
437 0 : c->value.length)) return false;
438 : }
439 0 : if (!asn1_pop_tag(data)) return false; /* ASN1_SEQUENCE(0) */
440 : }
441 :
442 0 : return asn1_pop_tag(data); /* ASN1_CONTEXT(0) */
443 : }
444 :
445 : #define tldap_context_disconnect(ld, status) \
446 : _tldap_context_disconnect(ld, status, __location__)
447 :
448 0 : static void _tldap_context_disconnect(struct tldap_context *ld,
449 : TLDAPRC status,
450 : const char *location)
451 : {
452 0 : if (ld->conn == NULL) {
453 : /*
454 : * We don't need to tldap_debug() on
455 : * a potential 2nd run.
456 : *
457 : * The rest of the function would just
458 : * be a noop for the 2nd run anyway.
459 : */
460 0 : return;
461 : }
462 :
463 0 : tldap_debug(ld, TLDAP_DEBUG_WARNING,
464 : "tldap_context_disconnect: %s at %s\n",
465 : tldap_rc2string(status),
466 : location);
467 0 : tevent_queue_stop(ld->outgoing);
468 0 : TALLOC_FREE(ld->read_req);
469 0 : TALLOC_FREE(ld->conn);
470 :
471 0 : while (talloc_array_length(ld->pending) > 0) {
472 0 : struct tevent_req *req = NULL;
473 0 : struct tldap_msg_state *state = NULL;
474 :
475 0 : req = ld->pending[0];
476 0 : state = tevent_req_data(req, struct tldap_msg_state);
477 0 : tevent_req_defer_callback(req, state->ev);
478 0 : tevent_req_ldap_error(req, status);
479 : }
480 : }
481 :
482 : static void tldap_msg_sent(struct tevent_req *subreq);
483 : static void tldap_msg_received(struct tevent_req *subreq);
484 :
485 0 : static struct tevent_req *tldap_msg_send(TALLOC_CTX *mem_ctx,
486 : struct tevent_context *ev,
487 : struct tldap_context *ld,
488 : int id, struct asn1_data *data,
489 : struct tldap_control *sctrls,
490 : int num_sctrls)
491 : {
492 : struct tevent_req *req, *subreq;
493 : struct tldap_msg_state *state;
494 : DATA_BLOB blob;
495 : bool ok;
496 :
497 0 : tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_send: sending msg %d\n",
498 : id);
499 :
500 0 : req = tevent_req_create(mem_ctx, &state, struct tldap_msg_state);
501 0 : if (req == NULL) {
502 0 : return NULL;
503 : }
504 0 : state->ld = ld;
505 0 : state->ev = ev;
506 0 : state->id = id;
507 :
508 0 : ok = tldap_connection_ok(ld);
509 0 : if (!ok) {
510 0 : tevent_req_ldap_error(req, TLDAP_SERVER_DOWN);
511 0 : return tevent_req_post(req, ev);
512 : }
513 :
514 0 : if (!tldap_push_controls(data, sctrls, num_sctrls)) {
515 0 : tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
516 0 : return tevent_req_post(req, ev);
517 : }
518 :
519 :
520 0 : if (!asn1_pop_tag(data)) {
521 0 : tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
522 0 : return tevent_req_post(req, ev);
523 : }
524 :
525 0 : if (!asn1_blob(data, &blob)) {
526 0 : tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
527 0 : return tevent_req_post(req, ev);
528 : }
529 :
530 0 : if (!tldap_msg_set_pending(req)) {
531 0 : tevent_req_oom(req);
532 0 : return tevent_req_post(req, ev);;
533 : }
534 :
535 0 : state->iov.iov_base = (void *)blob.data;
536 0 : state->iov.iov_len = blob.length;
537 :
538 0 : subreq = tstream_writev_queue_send(state, ev, ld->conn, ld->outgoing,
539 0 : &state->iov, 1);
540 0 : if (tevent_req_nomem(subreq, req)) {
541 0 : return tevent_req_post(req, ev);
542 : }
543 0 : tevent_req_set_callback(subreq, tldap_msg_sent, req);
544 0 : return req;
545 : }
546 :
547 0 : static void tldap_msg_unset_pending(struct tevent_req *req)
548 : {
549 0 : struct tldap_msg_state *state = tevent_req_data(
550 : req, struct tldap_msg_state);
551 0 : struct tldap_context *ld = state->ld;
552 0 : int num_pending = tldap_pending_reqs(ld);
553 : int i;
554 :
555 0 : tevent_req_set_cleanup_fn(req, NULL);
556 :
557 0 : for (i=0; i<num_pending; i++) {
558 0 : if (req == ld->pending[i]) {
559 0 : break;
560 : }
561 : }
562 0 : if (i == num_pending) {
563 : /*
564 : * Something's seriously broken. Just returning here is the
565 : * right thing nevertheless, the point of this routine is to
566 : * remove ourselves from cli->pending.
567 : */
568 0 : return;
569 : }
570 :
571 0 : if (num_pending == 1) {
572 0 : TALLOC_FREE(ld->pending);
573 0 : return;
574 : }
575 :
576 : /*
577 : * Remove ourselves from the cli->pending array
578 : */
579 0 : if (num_pending > 1) {
580 0 : ld->pending[i] = ld->pending[num_pending-1];
581 : }
582 :
583 : /*
584 : * No NULL check here, we're shrinking by sizeof(void *), and
585 : * talloc_realloc just adjusts the size for this.
586 : */
587 0 : ld->pending = talloc_realloc(NULL, ld->pending, struct tevent_req *,
588 : num_pending - 1);
589 : }
590 :
591 0 : static void tldap_msg_cleanup(struct tevent_req *req,
592 : enum tevent_req_state req_state)
593 : {
594 0 : tldap_msg_unset_pending(req);
595 0 : }
596 :
597 0 : static bool tldap_msg_set_pending(struct tevent_req *req)
598 : {
599 0 : struct tldap_msg_state *state = tevent_req_data(
600 : req, struct tldap_msg_state);
601 : struct tldap_context *ld;
602 : struct tevent_req **pending;
603 : int num_pending;
604 :
605 0 : ld = state->ld;
606 0 : num_pending = tldap_pending_reqs(ld);
607 :
608 0 : pending = talloc_realloc(ld, ld->pending, struct tevent_req *,
609 : num_pending+1);
610 0 : if (pending == NULL) {
611 0 : return false;
612 : }
613 0 : pending[num_pending] = req;
614 0 : ld->pending = pending;
615 0 : tevent_req_set_cleanup_fn(req, tldap_msg_cleanup);
616 :
617 0 : if (ld->read_req != NULL) {
618 0 : return true;
619 : }
620 :
621 : /*
622 : * We're the first one, add the read_ldap request that waits for the
623 : * answer from the server
624 : */
625 0 : ld->read_req = read_ldap_send(ld->pending, state->ev, ld->conn);
626 0 : if (ld->read_req == NULL) {
627 0 : tldap_msg_unset_pending(req);
628 0 : return false;
629 : }
630 0 : tevent_req_set_callback(ld->read_req, tldap_msg_received, ld);
631 0 : return true;
632 : }
633 :
634 0 : static void tldap_msg_sent(struct tevent_req *subreq)
635 : {
636 0 : struct tevent_req *req = tevent_req_callback_data(
637 : subreq, struct tevent_req);
638 0 : struct tldap_msg_state *state = tevent_req_data(
639 : req, struct tldap_msg_state);
640 : ssize_t nwritten;
641 : int err;
642 :
643 0 : nwritten = tstream_writev_queue_recv(subreq, &err);
644 0 : TALLOC_FREE(subreq);
645 0 : if (nwritten == -1) {
646 0 : tldap_context_disconnect(state->ld, TLDAP_SERVER_DOWN);
647 0 : return;
648 : }
649 : }
650 :
651 0 : static int tldap_msg_msgid(struct tevent_req *req)
652 : {
653 0 : struct tldap_msg_state *state = tevent_req_data(
654 : req, struct tldap_msg_state);
655 :
656 0 : return state->id;
657 : }
658 :
659 0 : static void tldap_msg_received(struct tevent_req *subreq)
660 : {
661 0 : struct tldap_context *ld = tevent_req_callback_data(
662 : subreq, struct tldap_context);
663 : struct tevent_req *req;
664 : struct tldap_msg_state *state;
665 : struct asn1_data *data;
666 : uint8_t *inbuf;
667 : ssize_t received;
668 : size_t num_pending;
669 : size_t i;
670 : int err;
671 0 : TLDAPRC status = TLDAP_PROTOCOL_ERROR;
672 : int id;
673 : uint8_t type;
674 : bool ok;
675 :
676 0 : received = read_ldap_recv(subreq, talloc_tos(), &inbuf, &err);
677 0 : TALLOC_FREE(subreq);
678 0 : ld->read_req = NULL;
679 0 : if (received == -1) {
680 0 : status = TLDAP_SERVER_DOWN;
681 0 : goto fail;
682 : }
683 :
684 0 : data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
685 0 : if (data == NULL) {
686 : /*
687 : * We have to disconnect all, we can't tell which of
688 : * the requests this reply is for.
689 : */
690 0 : status = TLDAP_NO_MEMORY;
691 0 : goto fail;
692 : }
693 0 : asn1_load_nocopy(data, inbuf, received);
694 :
695 0 : ok = true;
696 0 : ok &= asn1_start_tag(data, ASN1_SEQUENCE(0));
697 0 : ok &= asn1_read_Integer(data, &id);
698 0 : ok &= asn1_peek_uint8(data, &type);
699 :
700 0 : if (!ok) {
701 0 : status = TLDAP_PROTOCOL_ERROR;
702 0 : goto fail;
703 : }
704 :
705 0 : tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_received: got msg %d "
706 : "type %d\n", id, (int)type);
707 :
708 0 : if (id == 0) {
709 0 : tldap_debug(
710 : ld,
711 : TLDAP_DEBUG_WARNING,
712 : "tldap_msg_received: got msgid 0 of "
713 : "type %"PRIu8", disconnecting\n",
714 : type);
715 0 : tldap_context_disconnect(ld, TLDAP_SERVER_DOWN);
716 0 : return;
717 : }
718 :
719 0 : num_pending = talloc_array_length(ld->pending);
720 :
721 0 : for (i=0; i<num_pending; i++) {
722 0 : if (id == tldap_msg_msgid(ld->pending[i])) {
723 0 : break;
724 : }
725 : }
726 0 : if (i == num_pending) {
727 : /* Dump unexpected reply */
728 0 : tldap_debug(ld, TLDAP_DEBUG_WARNING, "tldap_msg_received: "
729 : "No request pending for msg %d\n", id);
730 0 : TALLOC_FREE(data);
731 0 : TALLOC_FREE(inbuf);
732 0 : goto done;
733 : }
734 :
735 0 : req = ld->pending[i];
736 0 : state = tevent_req_data(req, struct tldap_msg_state);
737 :
738 0 : state->inbuf = talloc_move(state, &inbuf);
739 0 : state->data = talloc_move(state, &data);
740 :
741 0 : tldap_msg_unset_pending(req);
742 0 : num_pending = talloc_array_length(ld->pending);
743 :
744 0 : tevent_req_defer_callback(req, state->ev);
745 0 : tevent_req_done(req);
746 :
747 0 : done:
748 0 : if (num_pending == 0) {
749 0 : return;
750 : }
751 :
752 0 : state = tevent_req_data(ld->pending[0], struct tldap_msg_state);
753 0 : ld->read_req = read_ldap_send(ld->pending, state->ev, ld->conn);
754 0 : if (ld->read_req == NULL) {
755 0 : status = TLDAP_NO_MEMORY;
756 0 : goto fail;
757 : }
758 0 : tevent_req_set_callback(ld->read_req, tldap_msg_received, ld);
759 0 : return;
760 :
761 0 : fail:
762 0 : tldap_context_disconnect(ld, status);
763 : }
764 :
765 0 : static TLDAPRC tldap_msg_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
766 : struct tldap_message **pmsg)
767 : {
768 0 : struct tldap_msg_state *state = tevent_req_data(
769 : req, struct tldap_msg_state);
770 : struct tldap_message *msg;
771 : TLDAPRC err;
772 : uint8_t msgtype;
773 :
774 0 : if (tevent_req_is_ldap_error(req, &err)) {
775 0 : return err;
776 : }
777 :
778 0 : if (!asn1_peek_uint8(state->data, &msgtype)) {
779 0 : return TLDAP_PROTOCOL_ERROR;
780 : }
781 :
782 0 : if (pmsg == NULL) {
783 0 : return TLDAP_SUCCESS;
784 : }
785 :
786 0 : msg = talloc_zero(mem_ctx, struct tldap_message);
787 0 : if (msg == NULL) {
788 0 : return TLDAP_NO_MEMORY;
789 : }
790 0 : msg->id = state->id;
791 :
792 0 : msg->inbuf = talloc_move(msg, &state->inbuf);
793 0 : msg->data = talloc_move(msg, &state->data);
794 0 : msg->type = msgtype;
795 :
796 0 : *pmsg = msg;
797 0 : return TLDAP_SUCCESS;
798 : }
799 :
800 : struct tldap_req_state {
801 : int id;
802 : struct asn1_data *out;
803 : struct tldap_message *result;
804 : };
805 :
806 0 : static struct tevent_req *tldap_req_create(TALLOC_CTX *mem_ctx,
807 : struct tldap_context *ld,
808 : struct tldap_req_state **pstate)
809 : {
810 : struct tevent_req *req;
811 : struct tldap_req_state *state;
812 :
813 0 : req = tevent_req_create(mem_ctx, &state, struct tldap_req_state);
814 0 : if (req == NULL) {
815 0 : return NULL;
816 : }
817 0 : state->out = asn1_init(state, ASN1_MAX_TREE_DEPTH);
818 0 : if (state->out == NULL) {
819 0 : goto err;
820 : }
821 0 : state->id = tldap_next_msgid(ld);
822 :
823 0 : if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
824 0 : if (!asn1_write_Integer(state->out, state->id)) goto err;
825 :
826 0 : *pstate = state;
827 0 : return req;
828 :
829 0 : err:
830 :
831 0 : TALLOC_FREE(req);
832 0 : return NULL;
833 : }
834 :
835 0 : static void tldap_save_msg(struct tldap_context *ld, struct tevent_req *req)
836 : {
837 0 : struct tldap_req_state *state = tevent_req_data(
838 : req, struct tldap_req_state);
839 :
840 0 : TALLOC_FREE(ld->last_msg);
841 0 : ld->last_msg = talloc_move(ld, &state->result);
842 0 : }
843 :
844 0 : static char *blob2string_talloc(TALLOC_CTX *mem_ctx, DATA_BLOB blob)
845 : {
846 0 : char *result = talloc_array(mem_ctx, char, blob.length+1);
847 :
848 0 : if (result == NULL) {
849 0 : return NULL;
850 : }
851 :
852 0 : memcpy(result, blob.data, blob.length);
853 0 : result[blob.length] = '\0';
854 0 : return result;
855 : }
856 :
857 0 : static bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
858 : struct asn1_data *data,
859 : char **presult)
860 : {
861 : DATA_BLOB string;
862 : char *result;
863 0 : if (!asn1_read_OctetString(data, mem_ctx, &string))
864 0 : return false;
865 :
866 0 : result = blob2string_talloc(mem_ctx, string);
867 :
868 0 : data_blob_free(&string);
869 :
870 0 : if (result == NULL) {
871 0 : return false;
872 : }
873 0 : *presult = result;
874 0 : return true;
875 : }
876 :
877 : static bool tldap_decode_controls(struct tldap_req_state *state);
878 :
879 0 : static bool tldap_decode_response(struct tldap_req_state *state)
880 : {
881 0 : struct asn1_data *data = state->result->data;
882 0 : struct tldap_message *msg = state->result;
883 : int rc;
884 0 : bool ok = true;
885 :
886 0 : ok &= asn1_read_enumerated(data, &rc);
887 0 : if (ok) {
888 0 : msg->lderr = TLDAP_RC(rc);
889 : }
890 :
891 0 : ok &= asn1_read_OctetString_talloc(msg, data, &msg->res_matcheddn);
892 0 : ok &= asn1_read_OctetString_talloc(msg, data,
893 : &msg->res_diagnosticmessage);
894 0 : if (!ok) return ok;
895 0 : if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
896 0 : ok &= asn1_start_tag(data, ASN1_CONTEXT(3));
897 0 : ok &= asn1_read_OctetString_talloc(msg, data,
898 : &msg->res_referral);
899 0 : ok &= asn1_end_tag(data);
900 : } else {
901 0 : msg->res_referral = NULL;
902 : }
903 :
904 0 : return ok;
905 : }
906 :
907 : static void tldap_sasl_bind_done(struct tevent_req *subreq);
908 :
909 0 : struct tevent_req *tldap_sasl_bind_send(TALLOC_CTX *mem_ctx,
910 : struct tevent_context *ev,
911 : struct tldap_context *ld,
912 : const char *dn,
913 : const char *mechanism,
914 : DATA_BLOB *creds,
915 : struct tldap_control *sctrls,
916 : int num_sctrls,
917 : struct tldap_control *cctrls,
918 : int num_cctrls)
919 : {
920 : struct tevent_req *req, *subreq;
921 : struct tldap_req_state *state;
922 :
923 0 : req = tldap_req_create(mem_ctx, ld, &state);
924 0 : if (req == NULL) {
925 0 : return NULL;
926 : }
927 :
928 0 : if (dn == NULL) {
929 0 : dn = "";
930 : }
931 :
932 0 : if (!asn1_push_tag(state->out, TLDAP_REQ_BIND)) goto err;
933 0 : if (!asn1_write_Integer(state->out, ld->ld_version)) goto err;
934 0 : if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
935 :
936 0 : if (mechanism == NULL) {
937 0 : if (!asn1_push_tag(state->out, ASN1_CONTEXT_SIMPLE(0))) goto err;
938 0 : if (!asn1_write(state->out, creds->data, creds->length)) goto err;
939 0 : if (!asn1_pop_tag(state->out)) goto err;
940 : } else {
941 0 : if (!asn1_push_tag(state->out, ASN1_CONTEXT(3))) goto err;
942 0 : if (!asn1_write_OctetString(state->out, mechanism,
943 0 : strlen(mechanism))) goto err;
944 0 : if ((creds != NULL) && (creds->data != NULL)) {
945 0 : if (!asn1_write_OctetString(state->out, creds->data,
946 0 : creds->length)) goto err;
947 : }
948 0 : if (!asn1_pop_tag(state->out)) goto err;
949 : }
950 :
951 0 : if (!asn1_pop_tag(state->out)) goto err;
952 :
953 0 : subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
954 : sctrls, num_sctrls);
955 0 : if (tevent_req_nomem(subreq, req)) {
956 0 : return tevent_req_post(req, ev);
957 : }
958 0 : tevent_req_set_callback(subreq, tldap_sasl_bind_done, req);
959 0 : return req;
960 :
961 0 : err:
962 :
963 0 : tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
964 0 : return tevent_req_post(req, ev);
965 : }
966 :
967 0 : static void tldap_sasl_bind_done(struct tevent_req *subreq)
968 : {
969 0 : struct tevent_req *req = tevent_req_callback_data(
970 : subreq, struct tevent_req);
971 0 : struct tldap_req_state *state = tevent_req_data(
972 : req, struct tldap_req_state);
973 : TLDAPRC rc;
974 : bool ok;
975 :
976 0 : rc = tldap_msg_recv(subreq, state, &state->result);
977 0 : TALLOC_FREE(subreq);
978 0 : if (tevent_req_ldap_error(req, rc)) {
979 0 : return;
980 : }
981 0 : if (state->result->type != TLDAP_RES_BIND) {
982 0 : tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
983 0 : return;
984 : }
985 :
986 0 : ok = asn1_start_tag(state->result->data, TLDAP_RES_BIND);
987 0 : ok &= tldap_decode_response(state);
988 :
989 0 : if (asn1_peek_tag(state->result->data, ASN1_CONTEXT_SIMPLE(7))) {
990 : int len;
991 :
992 0 : ok &= asn1_start_tag(state->result->data,
993 : ASN1_CONTEXT_SIMPLE(7));
994 0 : if (!ok) {
995 0 : goto decode_error;
996 : }
997 :
998 0 : len = asn1_tag_remaining(state->result->data);
999 0 : if (len == -1) {
1000 0 : goto decode_error;
1001 : }
1002 :
1003 0 : state->result->res_serverSaslCreds =
1004 0 : data_blob_talloc(state->result, NULL, len);
1005 0 : if (state->result->res_serverSaslCreds.data == NULL) {
1006 0 : goto decode_error;
1007 : }
1008 :
1009 0 : ok = asn1_read(state->result->data,
1010 0 : state->result->res_serverSaslCreds.data,
1011 0 : state->result->res_serverSaslCreds.length);
1012 :
1013 0 : ok &= asn1_end_tag(state->result->data);
1014 : }
1015 :
1016 0 : ok &= asn1_end_tag(state->result->data);
1017 :
1018 0 : if (!ok) {
1019 0 : goto decode_error;
1020 : }
1021 :
1022 0 : if (!TLDAP_RC_IS_SUCCESS(state->result->lderr) &&
1023 0 : !TLDAP_RC_EQUAL(state->result->lderr,
1024 : TLDAP_SASL_BIND_IN_PROGRESS)) {
1025 0 : tevent_req_ldap_error(req, state->result->lderr);
1026 0 : return;
1027 : }
1028 0 : tevent_req_done(req);
1029 0 : return;
1030 :
1031 0 : decode_error:
1032 0 : tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
1033 0 : return;
1034 : }
1035 :
1036 0 : TLDAPRC tldap_sasl_bind_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1037 : DATA_BLOB *serverSaslCreds)
1038 : {
1039 0 : struct tldap_req_state *state = tevent_req_data(
1040 : req, struct tldap_req_state);
1041 : TLDAPRC rc;
1042 :
1043 0 : if (tevent_req_is_ldap_error(req, &rc)) {
1044 0 : return rc;
1045 : }
1046 :
1047 0 : if (serverSaslCreds != NULL) {
1048 0 : serverSaslCreds->data = talloc_move(
1049 : mem_ctx, &state->result->res_serverSaslCreds.data);
1050 0 : serverSaslCreds->length =
1051 0 : state->result->res_serverSaslCreds.length;
1052 : }
1053 :
1054 0 : return state->result->lderr;
1055 : }
1056 :
1057 0 : TLDAPRC tldap_sasl_bind(struct tldap_context *ld,
1058 : const char *dn,
1059 : const char *mechanism,
1060 : DATA_BLOB *creds,
1061 : struct tldap_control *sctrls,
1062 : int num_sctrls,
1063 : struct tldap_control *cctrls,
1064 : int num_cctrls,
1065 : TALLOC_CTX *mem_ctx,
1066 : DATA_BLOB *serverSaslCreds)
1067 : {
1068 0 : TALLOC_CTX *frame = talloc_stackframe();
1069 : struct tevent_context *ev;
1070 : struct tevent_req *req;
1071 0 : TLDAPRC rc = TLDAP_NO_MEMORY;
1072 :
1073 0 : ev = samba_tevent_context_init(frame);
1074 0 : if (ev == NULL) {
1075 0 : goto fail;
1076 : }
1077 0 : req = tldap_sasl_bind_send(frame, ev, ld, dn, mechanism, creds,
1078 : sctrls, num_sctrls, cctrls, num_cctrls);
1079 0 : if (req == NULL) {
1080 0 : goto fail;
1081 : }
1082 0 : if (!tevent_req_poll(req, ev)) {
1083 0 : rc = TLDAP_OPERATIONS_ERROR;
1084 0 : goto fail;
1085 : }
1086 0 : rc = tldap_sasl_bind_recv(req, mem_ctx, serverSaslCreds);
1087 0 : tldap_save_msg(ld, req);
1088 0 : fail:
1089 0 : TALLOC_FREE(frame);
1090 0 : return rc;
1091 : }
1092 :
1093 0 : struct tevent_req *tldap_simple_bind_send(TALLOC_CTX *mem_ctx,
1094 : struct tevent_context *ev,
1095 : struct tldap_context *ld,
1096 : const char *dn,
1097 : const char *passwd)
1098 : {
1099 : DATA_BLOB cred;
1100 :
1101 0 : if (passwd != NULL) {
1102 0 : cred.data = discard_const_p(uint8_t, passwd);
1103 0 : cred.length = strlen(passwd);
1104 : } else {
1105 0 : cred.data = discard_const_p(uint8_t, "");
1106 0 : cred.length = 0;
1107 : }
1108 0 : return tldap_sasl_bind_send(mem_ctx, ev, ld, dn, NULL, &cred, NULL, 0,
1109 : NULL, 0);
1110 : }
1111 :
1112 0 : TLDAPRC tldap_simple_bind_recv(struct tevent_req *req)
1113 : {
1114 0 : return tldap_sasl_bind_recv(req, NULL, NULL);
1115 : }
1116 :
1117 0 : TLDAPRC tldap_simple_bind(struct tldap_context *ld, const char *dn,
1118 : const char *passwd)
1119 : {
1120 : DATA_BLOB cred;
1121 :
1122 0 : if (passwd != NULL) {
1123 0 : cred.data = discard_const_p(uint8_t, passwd);
1124 0 : cred.length = strlen(passwd);
1125 : } else {
1126 0 : cred.data = discard_const_p(uint8_t, "");
1127 0 : cred.length = 0;
1128 : }
1129 0 : return tldap_sasl_bind(ld, dn, NULL, &cred, NULL, 0, NULL, 0,
1130 : NULL, NULL);
1131 : }
1132 :
1133 : /*****************************************************************************/
1134 :
1135 : /* can't use isalpha() as only a strict set is valid for LDAP */
1136 :
1137 0 : static bool tldap_is_alpha(char c)
1138 : {
1139 0 : return (((c >= 'a') && (c <= 'z')) || \
1140 0 : ((c >= 'A') && (c <= 'Z')));
1141 : }
1142 :
1143 0 : static bool tldap_is_adh(char c)
1144 : {
1145 0 : return tldap_is_alpha(c) || isdigit(c) || (c == '-');
1146 : }
1147 :
1148 : #define TLDAP_FILTER_AND ASN1_CONTEXT(0)
1149 : #define TLDAP_FILTER_OR ASN1_CONTEXT(1)
1150 : #define TLDAP_FILTER_NOT ASN1_CONTEXT(2)
1151 : #define TLDAP_FILTER_EQ ASN1_CONTEXT(3)
1152 : #define TLDAP_FILTER_SUB ASN1_CONTEXT(4)
1153 : #define TLDAP_FILTER_LE ASN1_CONTEXT(5)
1154 : #define TLDAP_FILTER_GE ASN1_CONTEXT(6)
1155 : #define TLDAP_FILTER_PRES ASN1_CONTEXT_SIMPLE(7)
1156 : #define TLDAP_FILTER_APX ASN1_CONTEXT(8)
1157 : #define TLDAP_FILTER_EXT ASN1_CONTEXT(9)
1158 :
1159 : #define TLDAP_SUB_INI ASN1_CONTEXT_SIMPLE(0)
1160 : #define TLDAP_SUB_ANY ASN1_CONTEXT_SIMPLE(1)
1161 : #define TLDAP_SUB_FIN ASN1_CONTEXT_SIMPLE(2)
1162 :
1163 :
1164 : /* oid's should be numerical only in theory,
1165 : * but apparently some broken servers may have alphanum aliases instead.
1166 : * Do like openldap libraries and allow alphanum aliases for oids, but
1167 : * do not allow Tagging options in that case.
1168 : */
1169 0 : static bool tldap_is_attrdesc(const char *s, int len, bool no_tagopts)
1170 : {
1171 0 : bool is_oid = false;
1172 0 : bool dot = false;
1173 : int i;
1174 :
1175 : /* first char has stricter rules */
1176 0 : if (isdigit(*s)) {
1177 0 : is_oid = true;
1178 0 : } else if (!tldap_is_alpha(*s)) {
1179 : /* bad first char */
1180 0 : return false;
1181 : }
1182 :
1183 0 : for (i = 1; i < len; i++) {
1184 :
1185 0 : if (is_oid) {
1186 0 : if (isdigit(s[i])) {
1187 0 : dot = false;
1188 0 : continue;
1189 : }
1190 0 : if (s[i] == '.') {
1191 0 : if (dot) {
1192 : /* malformed */
1193 0 : return false;
1194 : }
1195 0 : dot = true;
1196 0 : continue;
1197 : }
1198 : } else {
1199 0 : if (tldap_is_adh(s[i])) {
1200 0 : continue;
1201 : }
1202 : }
1203 :
1204 0 : if (s[i] == ';') {
1205 0 : if (no_tagopts) {
1206 : /* no tagging options */
1207 0 : return false;
1208 : }
1209 0 : if (dot) {
1210 : /* malformed */
1211 0 : return false;
1212 : }
1213 0 : if ((i + 1) == len) {
1214 : /* malformed */
1215 0 : return false;
1216 : }
1217 :
1218 0 : is_oid = false;
1219 0 : continue;
1220 : }
1221 : }
1222 :
1223 0 : if (dot) {
1224 : /* malformed */
1225 0 : return false;
1226 : }
1227 :
1228 0 : return true;
1229 : }
1230 :
1231 : /* this function copies the value until the closing parenthesis is found. */
1232 0 : static char *tldap_get_val(TALLOC_CTX *memctx,
1233 : const char *value, const char **_s)
1234 : {
1235 0 : const char *s = value;
1236 :
1237 : /* find terminator */
1238 0 : while (*s) {
1239 0 : s = strchr(s, ')');
1240 0 : if (s && (*(s - 1) == '\\')) {
1241 0 : continue;
1242 : }
1243 0 : break;
1244 : }
1245 0 : if (!s || !(*s == ')')) {
1246 : /* malformed filter */
1247 0 : return NULL;
1248 : }
1249 :
1250 0 : *_s = s;
1251 :
1252 0 : return talloc_strndup(memctx, value, s - value);
1253 : }
1254 :
1255 0 : static int tldap_hex2char(const char *x)
1256 : {
1257 0 : if (isxdigit(x[0]) && isxdigit(x[1])) {
1258 0 : const char h1 = x[0], h2 = x[1];
1259 0 : int c = 0;
1260 :
1261 0 : if (h1 >= 'a') c = h1 - (int)'a' + 10;
1262 0 : else if (h1 >= 'A') c = h1 - (int)'A' + 10;
1263 0 : else if (h1 >= '0') c = h1 - (int)'0';
1264 0 : c = c << 4;
1265 0 : if (h2 >= 'a') c += h2 - (int)'a' + 10;
1266 0 : else if (h2 >= 'A') c += h2 - (int)'A' + 10;
1267 0 : else if (h2 >= '0') c += h2 - (int)'0';
1268 :
1269 0 : return c;
1270 : }
1271 :
1272 0 : return -1;
1273 : }
1274 :
1275 0 : static bool tldap_find_first_star(const char *val, const char **star)
1276 : {
1277 : const char *s;
1278 :
1279 0 : for (s = val; *s; s++) {
1280 0 : switch (*s) {
1281 0 : case '\\':
1282 0 : if (isxdigit(s[1]) && isxdigit(s[2])) {
1283 0 : s += 2;
1284 0 : break;
1285 : }
1286 : /* not hex based escape, check older syntax */
1287 0 : switch (s[1]) {
1288 0 : case '(':
1289 : case ')':
1290 : case '*':
1291 : case '\\':
1292 0 : s++;
1293 0 : break;
1294 0 : default:
1295 : /* invalid escape sequence */
1296 0 : return false;
1297 : }
1298 0 : break;
1299 0 : case ')':
1300 : /* end of val, nothing found */
1301 0 : *star = s;
1302 0 : return true;
1303 :
1304 0 : case '*':
1305 0 : *star = s;
1306 0 : return true;
1307 : }
1308 : }
1309 :
1310 : /* string ended without closing parenthesis, filter is malformed */
1311 0 : return false;
1312 : }
1313 :
1314 0 : static bool tldap_unescape_inplace(char *value, size_t *val_len)
1315 : {
1316 : int c;
1317 : size_t i, p;
1318 :
1319 0 : for (i = 0,p = 0; i < *val_len; i++) {
1320 :
1321 0 : switch (value[i]) {
1322 0 : case '(':
1323 : case ')':
1324 : case '*':
1325 : /* these must be escaped */
1326 0 : return false;
1327 :
1328 0 : case '\\':
1329 0 : if (!value[i + 1]) {
1330 : /* invalid EOL */
1331 0 : return false;
1332 : }
1333 0 : i++;
1334 :
1335 : /* LDAPv3 escaped */
1336 0 : c = tldap_hex2char(&value[i]);
1337 0 : if (c >= 0 && c < 256) {
1338 0 : value[p] = c;
1339 0 : i++;
1340 0 : p++;
1341 0 : break;
1342 : }
1343 :
1344 : /* LDAPv2 escaped */
1345 0 : switch (value[i]) {
1346 0 : case '(':
1347 : case ')':
1348 : case '*':
1349 : case '\\':
1350 0 : value[p] = value[i];
1351 0 : p++;
1352 :
1353 0 : break;
1354 0 : default:
1355 : /* invalid */
1356 0 : return false;
1357 : }
1358 0 : break;
1359 :
1360 0 : default:
1361 0 : value[p] = value[i];
1362 0 : p++;
1363 : }
1364 : }
1365 0 : value[p] = '\0';
1366 0 : *val_len = p;
1367 0 : return true;
1368 : }
1369 :
1370 : static bool tldap_push_filter_basic(struct tldap_context *ld,
1371 : struct asn1_data *data,
1372 : const char **_s);
1373 : static bool tldap_push_filter_substring(struct tldap_context *ld,
1374 : struct asn1_data *data,
1375 : const char *val,
1376 : const char **_s);
1377 0 : static bool tldap_push_filter_int(struct tldap_context *ld,
1378 : struct asn1_data *data,
1379 : const char **_s)
1380 : {
1381 0 : const char *s = *_s;
1382 : bool ret;
1383 :
1384 0 : if (*s != '(') {
1385 0 : tldap_debug(ld, TLDAP_DEBUG_ERROR,
1386 : "Incomplete or malformed filter\n");
1387 0 : return false;
1388 : }
1389 0 : s++;
1390 :
1391 : /* we are right after a parenthesis,
1392 : * find out what op we have at hand */
1393 0 : switch (*s) {
1394 0 : case '&':
1395 0 : tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: AND\n");
1396 0 : if (!asn1_push_tag(data, TLDAP_FILTER_AND)) return false;
1397 0 : s++;
1398 0 : break;
1399 :
1400 0 : case '|':
1401 0 : tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: OR\n");
1402 0 : if (!asn1_push_tag(data, TLDAP_FILTER_OR)) return false;
1403 0 : s++;
1404 0 : break;
1405 :
1406 0 : case '!':
1407 0 : tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: NOT\n");
1408 0 : if (!asn1_push_tag(data, TLDAP_FILTER_NOT)) return false;
1409 0 : s++;
1410 0 : ret = tldap_push_filter_int(ld, data, &s);
1411 0 : if (!ret) {
1412 0 : return false;
1413 : }
1414 0 : if (!asn1_pop_tag(data)) return false;
1415 0 : goto done;
1416 :
1417 0 : case '(':
1418 : case ')':
1419 0 : tldap_debug(ld, TLDAP_DEBUG_ERROR,
1420 0 : "Invalid parenthesis '%c'\n", *s);
1421 0 : return false;
1422 :
1423 0 : case '\0':
1424 0 : tldap_debug(ld, TLDAP_DEBUG_ERROR,
1425 : "Invalid filter termination\n");
1426 0 : return false;
1427 :
1428 0 : default:
1429 0 : ret = tldap_push_filter_basic(ld, data, &s);
1430 0 : if (!ret) {
1431 0 : return false;
1432 : }
1433 0 : goto done;
1434 : }
1435 :
1436 : /* only and/or filters get here.
1437 : * go through the list of filters */
1438 :
1439 0 : if (*s == ')') {
1440 : /* RFC 4526: empty and/or */
1441 0 : if (!asn1_pop_tag(data)) return false;
1442 0 : goto done;
1443 : }
1444 :
1445 0 : while (*s) {
1446 0 : ret = tldap_push_filter_int(ld, data, &s);
1447 0 : if (!ret) {
1448 0 : return false;
1449 : }
1450 :
1451 0 : if (*s == ')') {
1452 : /* end of list, return */
1453 0 : if (!asn1_pop_tag(data)) return false;
1454 0 : break;
1455 : }
1456 : }
1457 :
1458 0 : done:
1459 0 : if (*s != ')') {
1460 0 : tldap_debug(ld, TLDAP_DEBUG_ERROR,
1461 : "Incomplete or malformed filter\n");
1462 0 : return false;
1463 : }
1464 0 : s++;
1465 :
1466 0 : if (asn1_has_error(data)) {
1467 0 : return false;
1468 : }
1469 :
1470 0 : *_s = s;
1471 0 : return true;
1472 : }
1473 :
1474 :
1475 0 : static bool tldap_push_filter_basic(struct tldap_context *ld,
1476 : struct asn1_data *data,
1477 : const char **_s)
1478 : {
1479 0 : TALLOC_CTX *tmpctx = talloc_tos();
1480 0 : const char *s = *_s;
1481 : const char *e;
1482 : const char *eq;
1483 : const char *val;
1484 : const char *type;
1485 : const char *dn;
1486 : const char *rule;
1487 : const char *star;
1488 0 : size_t type_len = 0;
1489 : char *uval;
1490 : size_t uval_len;
1491 0 : bool write_octect = true;
1492 : bool ret;
1493 :
1494 0 : eq = strchr(s, '=');
1495 0 : if (!eq) {
1496 0 : tldap_debug(ld, TLDAP_DEBUG_ERROR,
1497 : "Invalid filter, missing equal sign\n");
1498 0 : return false;
1499 : }
1500 :
1501 0 : val = eq + 1;
1502 0 : e = eq - 1;
1503 :
1504 0 : switch (*e) {
1505 0 : case '<':
1506 0 : if (!asn1_push_tag(data, TLDAP_FILTER_LE)) return false;
1507 0 : break;
1508 :
1509 0 : case '>':
1510 0 : if (!asn1_push_tag(data, TLDAP_FILTER_GE)) return false;
1511 0 : break;
1512 :
1513 0 : case '~':
1514 0 : if (!asn1_push_tag(data, TLDAP_FILTER_APX)) return false;
1515 0 : break;
1516 :
1517 0 : case ':':
1518 0 : if (!asn1_push_tag(data, TLDAP_FILTER_EXT)) return false;
1519 0 : write_octect = false;
1520 :
1521 0 : type = NULL;
1522 0 : dn = NULL;
1523 0 : rule = NULL;
1524 :
1525 0 : if (*s == ':') { /* [:dn]:rule:= value */
1526 0 : if (s == e) {
1527 : /* malformed filter */
1528 0 : return false;
1529 : }
1530 0 : dn = s;
1531 : } else { /* type[:dn][:rule]:= value */
1532 0 : type = s;
1533 0 : dn = strchr(s, ':');
1534 0 : type_len = dn - type;
1535 0 : if (dn == e) { /* type:= value */
1536 0 : dn = NULL;
1537 : }
1538 : }
1539 0 : if (dn) {
1540 0 : dn++;
1541 :
1542 0 : rule = strchr(dn, ':');
1543 0 : if (rule == NULL) {
1544 0 : return false;
1545 : }
1546 0 : if ((rule == dn + 1) || rule + 1 == e) {
1547 : /* malformed filter, contains "::" */
1548 0 : return false;
1549 : }
1550 :
1551 0 : if (strncasecmp_m(dn, "dn:", 3) != 0) {
1552 0 : if (rule == e) {
1553 0 : rule = dn;
1554 0 : dn = NULL;
1555 : } else {
1556 : /* malformed filter. With two
1557 : * optionals, the first must be "dn"
1558 : */
1559 0 : return false;
1560 : }
1561 : } else {
1562 0 : if (rule == e) {
1563 0 : rule = NULL;
1564 : } else {
1565 0 : rule++;
1566 : }
1567 : }
1568 : }
1569 :
1570 0 : if (!type && !dn && !rule) {
1571 : /* malformed filter, there must be at least one */
1572 0 : return false;
1573 : }
1574 :
1575 : /*
1576 : MatchingRuleAssertion ::= SEQUENCE {
1577 : matchingRule [1] MatchingRuleID OPTIONAL,
1578 : type [2] AttributeDescription OPTIONAL,
1579 : matchValue [3] AssertionValue,
1580 : dnAttributes [4] BOOLEAN DEFAULT FALSE
1581 : }
1582 : */
1583 :
1584 : /* check and add rule */
1585 0 : if (rule) {
1586 0 : ret = tldap_is_attrdesc(rule, e - rule, true);
1587 0 : if (!ret) {
1588 0 : return false;
1589 : }
1590 0 : if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1))) return false;
1591 0 : if (!asn1_write(data, rule, e - rule)) return false;
1592 0 : if (!asn1_pop_tag(data)) return false;
1593 : }
1594 :
1595 : /* check and add type */
1596 0 : if (type) {
1597 0 : ret = tldap_is_attrdesc(type, type_len, false);
1598 0 : if (!ret) {
1599 0 : return false;
1600 : }
1601 0 : if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2))) return false;
1602 0 : if (!asn1_write(data, type, type_len)) return false;
1603 0 : if (!asn1_pop_tag(data)) return false;
1604 : }
1605 :
1606 0 : uval = tldap_get_val(tmpctx, val, _s);
1607 0 : if (!uval) {
1608 0 : return false;
1609 : }
1610 0 : uval_len = *_s - val;
1611 0 : ret = tldap_unescape_inplace(uval, &uval_len);
1612 0 : if (!ret) {
1613 0 : return false;
1614 : }
1615 :
1616 0 : if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3))) return false;
1617 0 : if (!asn1_write(data, uval, uval_len)) return false;
1618 0 : if (!asn1_pop_tag(data)) return false;
1619 :
1620 0 : if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4))) return false;
1621 0 : if (!asn1_write_uint8(data, dn?1:0)) return false;
1622 0 : if (!asn1_pop_tag(data)) return false;
1623 0 : break;
1624 :
1625 0 : default:
1626 0 : e = eq;
1627 :
1628 0 : ret = tldap_is_attrdesc(s, e - s, false);
1629 0 : if (!ret) {
1630 0 : return false;
1631 : }
1632 :
1633 0 : if (strncmp(val, "*)", 2) == 0) {
1634 : /* presence */
1635 0 : if (!asn1_push_tag(data, TLDAP_FILTER_PRES)) return false;
1636 0 : if (!asn1_write(data, s, e - s)) return false;
1637 0 : *_s = val + 1;
1638 0 : write_octect = false;
1639 0 : break;
1640 : }
1641 :
1642 0 : ret = tldap_find_first_star(val, &star);
1643 0 : if (!ret) {
1644 0 : return false;
1645 : }
1646 0 : if (*star == '*') {
1647 : /* substring */
1648 0 : if (!asn1_push_tag(data, TLDAP_FILTER_SUB)) return false;
1649 0 : if (!asn1_write_OctetString(data, s, e - s)) return false;
1650 0 : ret = tldap_push_filter_substring(ld, data, val, &s);
1651 0 : if (!ret) {
1652 0 : return false;
1653 : }
1654 0 : *_s = s;
1655 0 : write_octect = false;
1656 0 : break;
1657 : }
1658 :
1659 : /* if nothing else, then it is just equality */
1660 0 : if (!asn1_push_tag(data, TLDAP_FILTER_EQ)) return false;
1661 0 : write_octect = true;
1662 0 : break;
1663 : }
1664 :
1665 0 : if (write_octect) {
1666 0 : uval = tldap_get_val(tmpctx, val, _s);
1667 0 : if (!uval) {
1668 0 : return false;
1669 : }
1670 0 : uval_len = *_s - val;
1671 0 : ret = tldap_unescape_inplace(uval, &uval_len);
1672 0 : if (!ret) {
1673 0 : return false;
1674 : }
1675 :
1676 0 : if (!asn1_write_OctetString(data, s, e - s)) return false;
1677 0 : if (!asn1_write_OctetString(data, uval, uval_len)) return false;
1678 : }
1679 :
1680 0 : if (asn1_has_error(data)) {
1681 0 : return false;
1682 : }
1683 0 : return asn1_pop_tag(data);
1684 : }
1685 :
1686 0 : static bool tldap_push_filter_substring(struct tldap_context *ld,
1687 : struct asn1_data *data,
1688 : const char *val,
1689 : const char **_s)
1690 : {
1691 0 : TALLOC_CTX *tmpctx = talloc_tos();
1692 0 : bool initial = true;
1693 : const char *star;
1694 : char *chunk;
1695 : size_t chunk_len;
1696 : bool ret;
1697 :
1698 : /*
1699 : SubstringFilter ::= SEQUENCE {
1700 : type AttributeDescription,
1701 : -- at least one must be present
1702 : substrings SEQUENCE OF CHOICE {
1703 : initial [0] LDAPString,
1704 : any [1] LDAPString,
1705 : final [2] LDAPString } }
1706 : */
1707 0 : if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
1708 :
1709 : do {
1710 0 : ret = tldap_find_first_star(val, &star);
1711 0 : if (!ret) {
1712 0 : return false;
1713 : }
1714 0 : chunk_len = star - val;
1715 :
1716 0 : switch (*star) {
1717 0 : case '*':
1718 0 : if (!initial && chunk_len == 0) {
1719 : /* found '**', which is illegal */
1720 0 : return false;
1721 : }
1722 0 : break;
1723 0 : case ')':
1724 0 : if (initial) {
1725 : /* no stars ?? */
1726 0 : return false;
1727 : }
1728 : /* we are done */
1729 0 : break;
1730 0 : default:
1731 : /* ?? */
1732 0 : return false;
1733 : }
1734 :
1735 0 : if (initial && chunk_len == 0) {
1736 0 : val = star + 1;
1737 0 : initial = false;
1738 0 : continue;
1739 : }
1740 :
1741 0 : chunk = talloc_strndup(tmpctx, val, chunk_len);
1742 0 : if (!chunk) {
1743 0 : return false;
1744 : }
1745 0 : ret = tldap_unescape_inplace(chunk, &chunk_len);
1746 0 : if (!ret) {
1747 0 : return false;
1748 : }
1749 0 : switch (*star) {
1750 0 : case '*':
1751 0 : if (initial) {
1752 0 : if (!asn1_push_tag(data, TLDAP_SUB_INI)) return false;
1753 0 : initial = false;
1754 : } else {
1755 0 : if (!asn1_push_tag(data, TLDAP_SUB_ANY)) return false;
1756 : }
1757 0 : break;
1758 0 : case ')':
1759 0 : if (!asn1_push_tag(data, TLDAP_SUB_FIN)) return false;
1760 0 : break;
1761 0 : default:
1762 : /* ?? */
1763 0 : return false;
1764 : }
1765 0 : if (!asn1_write(data, chunk, chunk_len)) return false;
1766 0 : if (!asn1_pop_tag(data)) return false;
1767 :
1768 0 : val = star + 1;
1769 :
1770 0 : } while (*star == '*');
1771 :
1772 0 : *_s = star;
1773 :
1774 : /* end of sequence */
1775 0 : return asn1_pop_tag(data);
1776 : }
1777 :
1778 : /* NOTE: although openldap libraries allow for spaces in some places, mosly
1779 : * around parenthesis, we do not allow any spaces (except in values of
1780 : * course) as I couldn't fine any place in RFC 4512 or RFC 4515 where
1781 : * leading or trailing spaces where allowed.
1782 : */
1783 0 : static bool tldap_push_filter(struct tldap_context *ld,
1784 : struct asn1_data *data,
1785 : const char *filter)
1786 : {
1787 0 : const char *s = filter;
1788 : bool ret;
1789 :
1790 0 : ret = tldap_push_filter_int(ld, data, &s);
1791 0 : if (ret && *s) {
1792 0 : tldap_debug(ld, TLDAP_DEBUG_ERROR,
1793 : "Incomplete or malformed filter\n");
1794 0 : return false;
1795 : }
1796 0 : return ret;
1797 : }
1798 :
1799 : /*****************************************************************************/
1800 :
1801 : static void tldap_search_done(struct tevent_req *subreq);
1802 :
1803 0 : struct tevent_req *tldap_search_send(TALLOC_CTX *mem_ctx,
1804 : struct tevent_context *ev,
1805 : struct tldap_context *ld,
1806 : const char *base, int scope,
1807 : const char *filter,
1808 : const char **attrs,
1809 : int num_attrs,
1810 : int attrsonly,
1811 : struct tldap_control *sctrls,
1812 : int num_sctrls,
1813 : struct tldap_control *cctrls,
1814 : int num_cctrls,
1815 : int timelimit,
1816 : int sizelimit,
1817 : int deref)
1818 : {
1819 : struct tevent_req *req, *subreq;
1820 : struct tldap_req_state *state;
1821 : int i;
1822 :
1823 0 : req = tldap_req_create(mem_ctx, ld, &state);
1824 0 : if (req == NULL) {
1825 0 : return NULL;
1826 : }
1827 :
1828 0 : if (!asn1_push_tag(state->out, TLDAP_REQ_SEARCH)) goto encoding_error;
1829 0 : if (!asn1_write_OctetString(state->out, base, strlen(base))) goto encoding_error;
1830 0 : if (!asn1_write_enumerated(state->out, scope)) goto encoding_error;
1831 0 : if (!asn1_write_enumerated(state->out, deref)) goto encoding_error;
1832 0 : if (!asn1_write_Integer(state->out, sizelimit)) goto encoding_error;
1833 0 : if (!asn1_write_Integer(state->out, timelimit)) goto encoding_error;
1834 0 : if (!asn1_write_BOOLEAN(state->out, attrsonly)) goto encoding_error;
1835 :
1836 0 : if (!tldap_push_filter(ld, state->out, filter)) {
1837 0 : goto encoding_error;
1838 : }
1839 :
1840 0 : if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto encoding_error;
1841 0 : for (i=0; i<num_attrs; i++) {
1842 0 : if (!asn1_write_OctetString(state->out, attrs[i], strlen(attrs[i]))) goto encoding_error;
1843 : }
1844 0 : if (!asn1_pop_tag(state->out)) goto encoding_error;
1845 0 : if (!asn1_pop_tag(state->out)) goto encoding_error;
1846 :
1847 0 : subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
1848 : sctrls, num_sctrls);
1849 0 : if (tevent_req_nomem(subreq, req)) {
1850 0 : return tevent_req_post(req, ev);
1851 : }
1852 0 : tevent_req_set_callback(subreq, tldap_search_done, req);
1853 0 : return req;
1854 :
1855 0 : encoding_error:
1856 0 : tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
1857 0 : return tevent_req_post(req, ev);
1858 : }
1859 :
1860 0 : static void tldap_search_done(struct tevent_req *subreq)
1861 : {
1862 0 : struct tevent_req *req = tevent_req_callback_data(
1863 : subreq, struct tevent_req);
1864 0 : struct tldap_req_state *state = tevent_req_data(
1865 : req, struct tldap_req_state);
1866 : TLDAPRC rc;
1867 :
1868 0 : rc = tldap_msg_recv(subreq, state, &state->result);
1869 0 : if (tevent_req_ldap_error(req, rc)) {
1870 0 : return;
1871 : }
1872 0 : switch (state->result->type) {
1873 0 : case TLDAP_RES_SEARCH_ENTRY:
1874 : case TLDAP_RES_SEARCH_REFERENCE:
1875 0 : if (!tldap_msg_set_pending(subreq)) {
1876 0 : tevent_req_oom(req);
1877 0 : return;
1878 : }
1879 0 : tevent_req_notify_callback(req);
1880 0 : break;
1881 0 : case TLDAP_RES_SEARCH_RESULT:
1882 0 : TALLOC_FREE(subreq);
1883 0 : if (!asn1_start_tag(state->result->data,
1884 0 : state->result->type) ||
1885 0 : !tldap_decode_response(state) ||
1886 0 : !asn1_end_tag(state->result->data) ||
1887 0 : !tldap_decode_controls(state)) {
1888 0 : tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
1889 0 : return;
1890 : }
1891 0 : tevent_req_done(req);
1892 0 : break;
1893 0 : default:
1894 0 : tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
1895 0 : return;
1896 : }
1897 : }
1898 :
1899 0 : TLDAPRC tldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1900 : struct tldap_message **pmsg)
1901 : {
1902 0 : struct tldap_req_state *state = tevent_req_data(
1903 : req, struct tldap_req_state);
1904 : TLDAPRC rc;
1905 :
1906 0 : if (!tevent_req_is_in_progress(req)
1907 0 : && tevent_req_is_ldap_error(req, &rc)) {
1908 0 : return rc;
1909 : }
1910 :
1911 0 : if (tevent_req_is_in_progress(req)) {
1912 0 : switch (state->result->type) {
1913 0 : case TLDAP_RES_SEARCH_ENTRY:
1914 : case TLDAP_RES_SEARCH_REFERENCE:
1915 0 : break;
1916 0 : default:
1917 0 : return TLDAP_OPERATIONS_ERROR;
1918 : }
1919 0 : }
1920 :
1921 0 : *pmsg = talloc_move(mem_ctx, &state->result);
1922 0 : return TLDAP_SUCCESS;
1923 : }
1924 :
1925 : struct tldap_search_all_state {
1926 : struct tldap_message **msgs;
1927 : struct tldap_message *result;
1928 : };
1929 :
1930 : static void tldap_search_all_done(struct tevent_req *subreq);
1931 :
1932 0 : struct tevent_req *tldap_search_all_send(
1933 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1934 : struct tldap_context *ld, const char *base, int scope,
1935 : const char *filter, const char **attrs, int num_attrs, int attrsonly,
1936 : struct tldap_control *sctrls, int num_sctrls,
1937 : struct tldap_control *cctrls, int num_cctrls,
1938 : int timelimit, int sizelimit, int deref)
1939 : {
1940 : struct tevent_req *req, *subreq;
1941 : struct tldap_search_all_state *state;
1942 :
1943 0 : req = tevent_req_create(mem_ctx, &state,
1944 : struct tldap_search_all_state);
1945 0 : if (req == NULL) {
1946 0 : return NULL;
1947 : }
1948 :
1949 0 : subreq = tldap_search_send(state, ev, ld, base, scope, filter,
1950 : attrs, num_attrs, attrsonly,
1951 : sctrls, num_sctrls, cctrls, num_cctrls,
1952 : timelimit, sizelimit, deref);
1953 0 : if (tevent_req_nomem(subreq, req)) {
1954 0 : return tevent_req_post(req, ev);
1955 : }
1956 0 : tevent_req_set_callback(subreq, tldap_search_all_done, req);
1957 0 : return req;
1958 : }
1959 :
1960 0 : static void tldap_search_all_done(struct tevent_req *subreq)
1961 : {
1962 0 : struct tevent_req *req = tevent_req_callback_data(
1963 : subreq, struct tevent_req);
1964 0 : struct tldap_search_all_state *state = tevent_req_data(
1965 : req, struct tldap_search_all_state);
1966 : struct tldap_message *msg, **tmp;
1967 : size_t num_msgs;
1968 : TLDAPRC rc;
1969 : int msgtype;
1970 :
1971 0 : rc = tldap_search_recv(subreq, state, &msg);
1972 : /* No TALLOC_FREE(subreq), this is multi-step */
1973 0 : if (tevent_req_ldap_error(req, rc)) {
1974 0 : return;
1975 : }
1976 :
1977 0 : msgtype = tldap_msg_type(msg);
1978 0 : if (msgtype == TLDAP_RES_SEARCH_RESULT) {
1979 0 : state->result = msg;
1980 0 : tevent_req_done(req);
1981 0 : return;
1982 : }
1983 :
1984 0 : num_msgs = talloc_array_length(state->msgs);
1985 :
1986 0 : tmp = talloc_realloc(state, state->msgs, struct tldap_message *,
1987 : num_msgs + 1);
1988 0 : if (tevent_req_nomem(tmp, req)) {
1989 0 : return;
1990 : }
1991 0 : state->msgs = tmp;
1992 0 : state->msgs[num_msgs] = talloc_move(state->msgs, &msg);
1993 : }
1994 :
1995 0 : TLDAPRC tldap_search_all_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1996 : struct tldap_message ***msgs,
1997 : struct tldap_message **result)
1998 : {
1999 0 : struct tldap_search_all_state *state = tevent_req_data(
2000 : req, struct tldap_search_all_state);
2001 : TLDAPRC rc;
2002 :
2003 0 : if (tevent_req_is_ldap_error(req, &rc)) {
2004 0 : return rc;
2005 : }
2006 :
2007 0 : if (msgs != NULL) {
2008 0 : *msgs = talloc_move(mem_ctx, &state->msgs);
2009 : }
2010 0 : if (result != NULL) {
2011 0 : *result = talloc_move(mem_ctx, &state->result);
2012 : }
2013 :
2014 0 : return TLDAP_SUCCESS;
2015 : }
2016 :
2017 0 : TLDAPRC tldap_search(struct tldap_context *ld,
2018 : const char *base, int scope, const char *filter,
2019 : const char **attrs, int num_attrs, int attrsonly,
2020 : struct tldap_control *sctrls, int num_sctrls,
2021 : struct tldap_control *cctrls, int num_cctrls,
2022 : int timelimit, int sizelimit, int deref,
2023 : TALLOC_CTX *mem_ctx, struct tldap_message ***pmsgs)
2024 : {
2025 : TALLOC_CTX *frame;
2026 : struct tevent_context *ev;
2027 : struct tevent_req *req;
2028 0 : TLDAPRC rc = TLDAP_NO_MEMORY;
2029 : struct tldap_message **msgs;
2030 : struct tldap_message *result;
2031 :
2032 0 : if (tldap_pending_reqs(ld)) {
2033 0 : return TLDAP_BUSY;
2034 : }
2035 :
2036 0 : frame = talloc_stackframe();
2037 :
2038 0 : ev = samba_tevent_context_init(frame);
2039 0 : if (ev == NULL) {
2040 0 : goto fail;
2041 : }
2042 0 : req = tldap_search_all_send(frame, ev, ld, base, scope, filter,
2043 : attrs, num_attrs, attrsonly,
2044 : sctrls, num_sctrls, cctrls, num_cctrls,
2045 : timelimit, sizelimit, deref);
2046 0 : if (req == NULL) {
2047 0 : goto fail;
2048 : }
2049 0 : if (!tevent_req_poll(req, ev)) {
2050 0 : rc = TLDAP_OPERATIONS_ERROR;
2051 0 : goto fail;
2052 : }
2053 0 : rc = tldap_search_all_recv(req, frame, &msgs, &result);
2054 0 : TALLOC_FREE(req);
2055 0 : if (!TLDAP_RC_IS_SUCCESS(rc)) {
2056 0 : goto fail;
2057 : }
2058 :
2059 0 : TALLOC_FREE(ld->last_msg);
2060 0 : ld->last_msg = talloc_move(ld, &result);
2061 :
2062 0 : if (pmsgs != NULL) {
2063 0 : *pmsgs = talloc_move(mem_ctx, &msgs);
2064 : }
2065 0 : fail:
2066 0 : TALLOC_FREE(frame);
2067 0 : return rc;
2068 : }
2069 :
2070 0 : static bool tldap_parse_search_entry(struct tldap_message *msg)
2071 : {
2072 0 : int num_attribs = 0;
2073 :
2074 0 : if (msg->type != TLDAP_RES_SEARCH_ENTRY) {
2075 0 : return false;
2076 : }
2077 0 : if (!asn1_start_tag(msg->data, TLDAP_RES_SEARCH_ENTRY)) {
2078 0 : return false;
2079 : }
2080 :
2081 : /* dn */
2082 :
2083 0 : if (!asn1_read_OctetString_talloc(msg, msg->data, &msg->dn)) return false;
2084 :
2085 0 : if (msg->dn == NULL) {
2086 0 : return false;
2087 : }
2088 :
2089 : /*
2090 : * Attributes: We overallocate msg->attribs by one, so that while
2091 : * looping over the attributes we can directly parse into the last
2092 : * array element. Same for the values in the inner loop.
2093 : */
2094 :
2095 0 : msg->attribs = talloc_array(msg, struct tldap_attribute, 1);
2096 0 : if (msg->attribs == NULL) {
2097 0 : return false;
2098 : }
2099 :
2100 0 : if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
2101 0 : while (asn1_peek_tag(msg->data, ASN1_SEQUENCE(0))) {
2102 : struct tldap_attribute *attrib;
2103 0 : int num_values = 0;
2104 :
2105 0 : attrib = &msg->attribs[num_attribs];
2106 0 : attrib->values = talloc_array(msg->attribs, DATA_BLOB, 1);
2107 0 : if (attrib->values == NULL) {
2108 0 : return false;
2109 : }
2110 0 : if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
2111 0 : if (!asn1_read_OctetString_talloc(msg->attribs, msg->data,
2112 0 : &attrib->name)) return false;
2113 0 : if (!asn1_start_tag(msg->data, ASN1_SET)) return false;
2114 :
2115 0 : while (asn1_peek_tag(msg->data, ASN1_OCTET_STRING)) {
2116 0 : if (!asn1_read_OctetString(msg->data, msg,
2117 0 : &attrib->values[num_values])) return false;
2118 :
2119 0 : attrib->values = talloc_realloc(
2120 : msg->attribs, attrib->values, DATA_BLOB,
2121 : num_values + 2);
2122 0 : if (attrib->values == NULL) {
2123 0 : return false;
2124 : }
2125 0 : num_values += 1;
2126 : }
2127 0 : attrib->values = talloc_realloc(msg->attribs, attrib->values,
2128 : DATA_BLOB, num_values);
2129 0 : attrib->num_values = num_values;
2130 :
2131 0 : if (!asn1_end_tag(msg->data)) return false; /* ASN1_SET */
2132 0 : if (!asn1_end_tag(msg->data)) return false; /* ASN1_SEQUENCE(0) */
2133 0 : msg->attribs = talloc_realloc(
2134 : msg, msg->attribs, struct tldap_attribute,
2135 : num_attribs + 2);
2136 0 : if (msg->attribs == NULL) {
2137 0 : return false;
2138 : }
2139 0 : num_attribs += 1;
2140 : }
2141 0 : msg->attribs = talloc_realloc(
2142 : msg, msg->attribs, struct tldap_attribute, num_attribs);
2143 0 : return asn1_end_tag(msg->data);
2144 : }
2145 :
2146 0 : bool tldap_entry_dn(struct tldap_message *msg, char **dn)
2147 : {
2148 0 : if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
2149 0 : return false;
2150 : }
2151 0 : *dn = msg->dn;
2152 0 : return true;
2153 : }
2154 :
2155 0 : bool tldap_entry_attributes(struct tldap_message *msg,
2156 : struct tldap_attribute **attributes,
2157 : int *num_attributes)
2158 : {
2159 0 : if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
2160 0 : return false;
2161 : }
2162 0 : *attributes = msg->attribs;
2163 0 : *num_attributes = talloc_array_length(msg->attribs);
2164 0 : return true;
2165 : }
2166 :
2167 0 : static bool tldap_decode_controls(struct tldap_req_state *state)
2168 : {
2169 0 : struct tldap_message *msg = state->result;
2170 0 : struct asn1_data *data = msg->data;
2171 0 : struct tldap_control *sctrls = NULL;
2172 0 : int num_controls = 0;
2173 0 : bool ret = false;
2174 :
2175 0 : msg->res_sctrls = NULL;
2176 :
2177 0 : if (!asn1_peek_tag(data, ASN1_CONTEXT(0))) {
2178 0 : return true;
2179 : }
2180 :
2181 0 : if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto out;
2182 :
2183 0 : while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
2184 : struct tldap_control *c;
2185 0 : char *oid = NULL;
2186 :
2187 0 : sctrls = talloc_realloc(msg, sctrls, struct tldap_control,
2188 : num_controls + 1);
2189 0 : if (sctrls == NULL) {
2190 0 : goto out;
2191 : }
2192 0 : c = &sctrls[num_controls];
2193 :
2194 0 : if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto out;
2195 0 : if (!asn1_read_OctetString_talloc(msg, data, &oid)) goto out;
2196 0 : if (asn1_has_error(data) || (oid == NULL)) {
2197 0 : goto out;
2198 : }
2199 0 : c->oid = oid;
2200 0 : if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
2201 0 : if (!asn1_read_BOOLEAN(data, &c->critical)) goto out;
2202 : } else {
2203 0 : c->critical = false;
2204 : }
2205 0 : c->value = data_blob_null;
2206 0 : if (asn1_peek_tag(data, ASN1_OCTET_STRING) &&
2207 0 : !asn1_read_OctetString(data, msg, &c->value)) {
2208 0 : goto out;
2209 : }
2210 0 : if (!asn1_end_tag(data)) goto out; /* ASN1_SEQUENCE(0) */
2211 :
2212 0 : num_controls += 1;
2213 : }
2214 :
2215 0 : if (!asn1_end_tag(data)) goto out; /* ASN1_CONTEXT(0) */
2216 :
2217 0 : ret = true;
2218 :
2219 0 : out:
2220 :
2221 0 : if (ret) {
2222 0 : msg->res_sctrls = sctrls;
2223 : } else {
2224 0 : TALLOC_FREE(sctrls);
2225 : }
2226 0 : return ret;
2227 : }
2228 :
2229 0 : static void tldap_simple_done(struct tevent_req *subreq, int type)
2230 : {
2231 0 : struct tevent_req *req = tevent_req_callback_data(
2232 : subreq, struct tevent_req);
2233 0 : struct tldap_req_state *state = tevent_req_data(
2234 : req, struct tldap_req_state);
2235 : TLDAPRC rc;
2236 :
2237 0 : rc = tldap_msg_recv(subreq, state, &state->result);
2238 0 : TALLOC_FREE(subreq);
2239 0 : if (tevent_req_ldap_error(req, rc)) {
2240 0 : return;
2241 : }
2242 0 : if (state->result->type != type) {
2243 0 : tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
2244 0 : return;
2245 : }
2246 0 : if (!asn1_start_tag(state->result->data, state->result->type) ||
2247 0 : !tldap_decode_response(state) ||
2248 0 : !asn1_end_tag(state->result->data) ||
2249 0 : !tldap_decode_controls(state)) {
2250 0 : tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
2251 0 : return;
2252 : }
2253 0 : if (!TLDAP_RC_IS_SUCCESS(state->result->lderr)) {
2254 0 : tevent_req_ldap_error(req, state->result->lderr);
2255 0 : return;
2256 : }
2257 0 : tevent_req_done(req);
2258 : }
2259 :
2260 0 : static TLDAPRC tldap_simple_recv(struct tevent_req *req)
2261 : {
2262 : TLDAPRC rc;
2263 0 : if (tevent_req_is_ldap_error(req, &rc)) {
2264 0 : return rc;
2265 : }
2266 0 : return TLDAP_SUCCESS;
2267 : }
2268 :
2269 : static void tldap_add_done(struct tevent_req *subreq);
2270 :
2271 0 : struct tevent_req *tldap_add_send(TALLOC_CTX *mem_ctx,
2272 : struct tevent_context *ev,
2273 : struct tldap_context *ld,
2274 : const char *dn,
2275 : struct tldap_mod *attributes,
2276 : int num_attributes,
2277 : struct tldap_control *sctrls,
2278 : int num_sctrls,
2279 : struct tldap_control *cctrls,
2280 : int num_cctrls)
2281 : {
2282 : struct tevent_req *req, *subreq;
2283 : struct tldap_req_state *state;
2284 : int i, j;
2285 :
2286 0 : req = tldap_req_create(mem_ctx, ld, &state);
2287 0 : if (req == NULL) {
2288 0 : return NULL;
2289 : }
2290 :
2291 0 : if (!asn1_push_tag(state->out, TLDAP_REQ_ADD)) goto err;
2292 0 : if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
2293 0 : if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2294 :
2295 0 : for (i=0; i<num_attributes; i++) {
2296 0 : struct tldap_mod *attrib = &attributes[i];
2297 0 : if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2298 0 : if (!asn1_write_OctetString(state->out, attrib->attribute,
2299 0 : strlen(attrib->attribute))) goto err;
2300 0 : if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
2301 0 : for (j=0; j<attrib->num_values; j++) {
2302 0 : if (!asn1_write_OctetString(state->out,
2303 0 : attrib->values[j].data,
2304 0 : attrib->values[j].length)) goto err;
2305 : }
2306 0 : if (!asn1_pop_tag(state->out)) goto err;
2307 0 : if (!asn1_pop_tag(state->out)) goto err;
2308 : }
2309 :
2310 0 : if (!asn1_pop_tag(state->out)) goto err;
2311 0 : if (!asn1_pop_tag(state->out)) goto err;
2312 :
2313 0 : subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
2314 : sctrls, num_sctrls);
2315 0 : if (tevent_req_nomem(subreq, req)) {
2316 0 : return tevent_req_post(req, ev);
2317 : }
2318 0 : tevent_req_set_callback(subreq, tldap_add_done, req);
2319 0 : return req;
2320 :
2321 0 : err:
2322 :
2323 0 : tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
2324 0 : return tevent_req_post(req, ev);
2325 : }
2326 :
2327 0 : static void tldap_add_done(struct tevent_req *subreq)
2328 : {
2329 0 : tldap_simple_done(subreq, TLDAP_RES_ADD);
2330 0 : }
2331 :
2332 0 : TLDAPRC tldap_add_recv(struct tevent_req *req)
2333 : {
2334 0 : return tldap_simple_recv(req);
2335 : }
2336 :
2337 0 : TLDAPRC tldap_add(struct tldap_context *ld, const char *dn,
2338 : struct tldap_mod *attributes, int num_attributes,
2339 : struct tldap_control *sctrls, int num_sctrls,
2340 : struct tldap_control *cctrls, int num_cctrls)
2341 : {
2342 0 : TALLOC_CTX *frame = talloc_stackframe();
2343 : struct tevent_context *ev;
2344 : struct tevent_req *req;
2345 0 : TLDAPRC rc = TLDAP_NO_MEMORY;
2346 :
2347 0 : ev = samba_tevent_context_init(frame);
2348 0 : if (ev == NULL) {
2349 0 : goto fail;
2350 : }
2351 0 : req = tldap_add_send(frame, ev, ld, dn, attributes, num_attributes,
2352 : sctrls, num_sctrls, cctrls, num_cctrls);
2353 0 : if (req == NULL) {
2354 0 : goto fail;
2355 : }
2356 0 : if (!tevent_req_poll(req, ev)) {
2357 0 : rc = TLDAP_OPERATIONS_ERROR;
2358 0 : goto fail;
2359 : }
2360 0 : rc = tldap_add_recv(req);
2361 0 : tldap_save_msg(ld, req);
2362 0 : fail:
2363 0 : TALLOC_FREE(frame);
2364 0 : return rc;
2365 : }
2366 :
2367 : static void tldap_modify_done(struct tevent_req *subreq);
2368 :
2369 0 : struct tevent_req *tldap_modify_send(TALLOC_CTX *mem_ctx,
2370 : struct tevent_context *ev,
2371 : struct tldap_context *ld,
2372 : const char *dn,
2373 : struct tldap_mod *mods, int num_mods,
2374 : struct tldap_control *sctrls,
2375 : int num_sctrls,
2376 : struct tldap_control *cctrls,
2377 : int num_cctrls)
2378 : {
2379 : struct tevent_req *req, *subreq;
2380 : struct tldap_req_state *state;
2381 : int i, j;
2382 :
2383 0 : req = tldap_req_create(mem_ctx, ld, &state);
2384 0 : if (req == NULL) {
2385 0 : return NULL;
2386 : }
2387 :
2388 0 : if (!asn1_push_tag(state->out, TLDAP_REQ_MODIFY)) goto err;
2389 0 : if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
2390 0 : if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2391 :
2392 0 : for (i=0; i<num_mods; i++) {
2393 0 : struct tldap_mod *mod = &mods[i];
2394 0 : if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2395 0 : if (!asn1_write_enumerated(state->out, mod->mod_op)) goto err;
2396 0 : if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
2397 0 : if (!asn1_write_OctetString(state->out, mod->attribute,
2398 0 : strlen(mod->attribute))) goto err;
2399 0 : if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
2400 0 : for (j=0; j<mod->num_values; j++) {
2401 0 : if (!asn1_write_OctetString(state->out,
2402 0 : mod->values[j].data,
2403 0 : mod->values[j].length)) goto err;
2404 : }
2405 0 : if (!asn1_pop_tag(state->out)) goto err;
2406 0 : if (!asn1_pop_tag(state->out)) goto err;
2407 0 : if (!asn1_pop_tag(state->out)) goto err;
2408 : }
2409 :
2410 0 : if (!asn1_pop_tag(state->out)) goto err;
2411 0 : if (!asn1_pop_tag(state->out)) goto err;
2412 :
2413 0 : subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
2414 : sctrls, num_sctrls);
2415 0 : if (tevent_req_nomem(subreq, req)) {
2416 0 : return tevent_req_post(req, ev);
2417 : }
2418 0 : tevent_req_set_callback(subreq, tldap_modify_done, req);
2419 0 : return req;
2420 :
2421 0 : err:
2422 :
2423 0 : tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
2424 0 : return tevent_req_post(req, ev);
2425 : }
2426 :
2427 0 : static void tldap_modify_done(struct tevent_req *subreq)
2428 : {
2429 0 : tldap_simple_done(subreq, TLDAP_RES_MODIFY);
2430 0 : }
2431 :
2432 0 : TLDAPRC tldap_modify_recv(struct tevent_req *req)
2433 : {
2434 0 : return tldap_simple_recv(req);
2435 : }
2436 :
2437 0 : TLDAPRC tldap_modify(struct tldap_context *ld, const char *dn,
2438 : struct tldap_mod *mods, int num_mods,
2439 : struct tldap_control *sctrls, int num_sctrls,
2440 : struct tldap_control *cctrls, int num_cctrls)
2441 : {
2442 0 : TALLOC_CTX *frame = talloc_stackframe();
2443 : struct tevent_context *ev;
2444 : struct tevent_req *req;
2445 0 : TLDAPRC rc = TLDAP_NO_MEMORY;
2446 :
2447 0 : ev = samba_tevent_context_init(frame);
2448 0 : if (ev == NULL) {
2449 0 : goto fail;
2450 : }
2451 0 : req = tldap_modify_send(frame, ev, ld, dn, mods, num_mods,
2452 : sctrls, num_sctrls, cctrls, num_cctrls);
2453 0 : if (req == NULL) {
2454 0 : goto fail;
2455 : }
2456 0 : if (!tevent_req_poll(req, ev)) {
2457 0 : rc = TLDAP_OPERATIONS_ERROR;
2458 0 : goto fail;
2459 : }
2460 0 : rc = tldap_modify_recv(req);
2461 0 : tldap_save_msg(ld, req);
2462 0 : fail:
2463 0 : TALLOC_FREE(frame);
2464 0 : return rc;
2465 : }
2466 :
2467 : static void tldap_delete_done(struct tevent_req *subreq);
2468 :
2469 0 : struct tevent_req *tldap_delete_send(TALLOC_CTX *mem_ctx,
2470 : struct tevent_context *ev,
2471 : struct tldap_context *ld,
2472 : const char *dn,
2473 : struct tldap_control *sctrls,
2474 : int num_sctrls,
2475 : struct tldap_control *cctrls,
2476 : int num_cctrls)
2477 : {
2478 : struct tevent_req *req, *subreq;
2479 : struct tldap_req_state *state;
2480 :
2481 0 : req = tldap_req_create(mem_ctx, ld, &state);
2482 0 : if (req == NULL) {
2483 0 : return NULL;
2484 : }
2485 :
2486 0 : if (!asn1_push_tag(state->out, TLDAP_REQ_DELETE)) goto err;
2487 0 : if (!asn1_write(state->out, dn, strlen(dn))) goto err;
2488 0 : if (!asn1_pop_tag(state->out)) goto err;
2489 :
2490 0 : subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
2491 : sctrls, num_sctrls);
2492 0 : if (tevent_req_nomem(subreq, req)) {
2493 0 : return tevent_req_post(req, ev);
2494 : }
2495 0 : tevent_req_set_callback(subreq, tldap_delete_done, req);
2496 0 : return req;
2497 :
2498 0 : err:
2499 :
2500 0 : tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
2501 0 : return tevent_req_post(req, ev);
2502 : }
2503 :
2504 0 : static void tldap_delete_done(struct tevent_req *subreq)
2505 : {
2506 0 : tldap_simple_done(subreq, TLDAP_RES_DELETE);
2507 0 : }
2508 :
2509 0 : TLDAPRC tldap_delete_recv(struct tevent_req *req)
2510 : {
2511 0 : return tldap_simple_recv(req);
2512 : }
2513 :
2514 0 : TLDAPRC tldap_delete(struct tldap_context *ld, const char *dn,
2515 : struct tldap_control *sctrls, int num_sctrls,
2516 : struct tldap_control *cctrls, int num_cctrls)
2517 : {
2518 0 : TALLOC_CTX *frame = talloc_stackframe();
2519 : struct tevent_context *ev;
2520 : struct tevent_req *req;
2521 0 : TLDAPRC rc = TLDAP_NO_MEMORY;
2522 :
2523 0 : ev = samba_tevent_context_init(frame);
2524 0 : if (ev == NULL) {
2525 0 : goto fail;
2526 : }
2527 0 : req = tldap_delete_send(frame, ev, ld, dn, sctrls, num_sctrls,
2528 : cctrls, num_cctrls);
2529 0 : if (req == NULL) {
2530 0 : goto fail;
2531 : }
2532 0 : if (!tevent_req_poll(req, ev)) {
2533 0 : rc = TLDAP_OPERATIONS_ERROR;
2534 0 : goto fail;
2535 : }
2536 0 : rc = tldap_delete_recv(req);
2537 0 : tldap_save_msg(ld, req);
2538 0 : fail:
2539 0 : TALLOC_FREE(frame);
2540 0 : return rc;
2541 : }
2542 :
2543 0 : int tldap_msg_id(const struct tldap_message *msg)
2544 : {
2545 0 : return msg->id;
2546 : }
2547 :
2548 0 : int tldap_msg_type(const struct tldap_message *msg)
2549 : {
2550 0 : return msg->type;
2551 : }
2552 :
2553 0 : const char *tldap_msg_matcheddn(struct tldap_message *msg)
2554 : {
2555 0 : if (msg == NULL) {
2556 0 : return NULL;
2557 : }
2558 0 : return msg->res_matcheddn;
2559 : }
2560 :
2561 0 : const char *tldap_msg_diagnosticmessage(struct tldap_message *msg)
2562 : {
2563 0 : if (msg == NULL) {
2564 0 : return NULL;
2565 : }
2566 0 : return msg->res_diagnosticmessage;
2567 : }
2568 :
2569 0 : const char *tldap_msg_referral(struct tldap_message *msg)
2570 : {
2571 0 : if (msg == NULL) {
2572 0 : return NULL;
2573 : }
2574 0 : return msg->res_referral;
2575 : }
2576 :
2577 0 : void tldap_msg_sctrls(struct tldap_message *msg, int *num_sctrls,
2578 : struct tldap_control **sctrls)
2579 : {
2580 0 : if (msg == NULL) {
2581 0 : *sctrls = NULL;
2582 0 : *num_sctrls = 0;
2583 0 : return;
2584 : }
2585 0 : *sctrls = msg->res_sctrls;
2586 0 : *num_sctrls = talloc_array_length(msg->res_sctrls);
2587 : }
2588 :
2589 0 : struct tldap_message *tldap_ctx_lastmsg(struct tldap_context *ld)
2590 : {
2591 0 : return ld->last_msg;
2592 : }
2593 :
2594 : static const struct { TLDAPRC rc; const char *string; } tldaprc_errmap[] =
2595 : {
2596 : { TLDAP_SUCCESS,
2597 : "TLDAP_SUCCESS" },
2598 : { TLDAP_OPERATIONS_ERROR,
2599 : "TLDAP_OPERATIONS_ERROR" },
2600 : { TLDAP_PROTOCOL_ERROR,
2601 : "TLDAP_PROTOCOL_ERROR" },
2602 : { TLDAP_TIMELIMIT_EXCEEDED,
2603 : "TLDAP_TIMELIMIT_EXCEEDED" },
2604 : { TLDAP_SIZELIMIT_EXCEEDED,
2605 : "TLDAP_SIZELIMIT_EXCEEDED" },
2606 : { TLDAP_COMPARE_FALSE,
2607 : "TLDAP_COMPARE_FALSE" },
2608 : { TLDAP_COMPARE_TRUE,
2609 : "TLDAP_COMPARE_TRUE" },
2610 : { TLDAP_STRONG_AUTH_NOT_SUPPORTED,
2611 : "TLDAP_STRONG_AUTH_NOT_SUPPORTED" },
2612 : { TLDAP_STRONG_AUTH_REQUIRED,
2613 : "TLDAP_STRONG_AUTH_REQUIRED" },
2614 : { TLDAP_REFERRAL,
2615 : "TLDAP_REFERRAL" },
2616 : { TLDAP_ADMINLIMIT_EXCEEDED,
2617 : "TLDAP_ADMINLIMIT_EXCEEDED" },
2618 : { TLDAP_UNAVAILABLE_CRITICAL_EXTENSION,
2619 : "TLDAP_UNAVAILABLE_CRITICAL_EXTENSION" },
2620 : { TLDAP_CONFIDENTIALITY_REQUIRED,
2621 : "TLDAP_CONFIDENTIALITY_REQUIRED" },
2622 : { TLDAP_SASL_BIND_IN_PROGRESS,
2623 : "TLDAP_SASL_BIND_IN_PROGRESS" },
2624 : { TLDAP_NO_SUCH_ATTRIBUTE,
2625 : "TLDAP_NO_SUCH_ATTRIBUTE" },
2626 : { TLDAP_UNDEFINED_TYPE,
2627 : "TLDAP_UNDEFINED_TYPE" },
2628 : { TLDAP_INAPPROPRIATE_MATCHING,
2629 : "TLDAP_INAPPROPRIATE_MATCHING" },
2630 : { TLDAP_CONSTRAINT_VIOLATION,
2631 : "TLDAP_CONSTRAINT_VIOLATION" },
2632 : { TLDAP_TYPE_OR_VALUE_EXISTS,
2633 : "TLDAP_TYPE_OR_VALUE_EXISTS" },
2634 : { TLDAP_INVALID_SYNTAX,
2635 : "TLDAP_INVALID_SYNTAX" },
2636 : { TLDAP_NO_SUCH_OBJECT,
2637 : "TLDAP_NO_SUCH_OBJECT" },
2638 : { TLDAP_ALIAS_PROBLEM,
2639 : "TLDAP_ALIAS_PROBLEM" },
2640 : { TLDAP_INVALID_DN_SYNTAX,
2641 : "TLDAP_INVALID_DN_SYNTAX" },
2642 : { TLDAP_IS_LEAF,
2643 : "TLDAP_IS_LEAF" },
2644 : { TLDAP_ALIAS_DEREF_PROBLEM,
2645 : "TLDAP_ALIAS_DEREF_PROBLEM" },
2646 : { TLDAP_INAPPROPRIATE_AUTH,
2647 : "TLDAP_INAPPROPRIATE_AUTH" },
2648 : { TLDAP_INVALID_CREDENTIALS,
2649 : "TLDAP_INVALID_CREDENTIALS" },
2650 : { TLDAP_INSUFFICIENT_ACCESS,
2651 : "TLDAP_INSUFFICIENT_ACCESS" },
2652 : { TLDAP_BUSY,
2653 : "TLDAP_BUSY" },
2654 : { TLDAP_UNAVAILABLE,
2655 : "TLDAP_UNAVAILABLE" },
2656 : { TLDAP_UNWILLING_TO_PERFORM,
2657 : "TLDAP_UNWILLING_TO_PERFORM" },
2658 : { TLDAP_LOOP_DETECT,
2659 : "TLDAP_LOOP_DETECT" },
2660 : { TLDAP_NAMING_VIOLATION,
2661 : "TLDAP_NAMING_VIOLATION" },
2662 : { TLDAP_OBJECT_CLASS_VIOLATION,
2663 : "TLDAP_OBJECT_CLASS_VIOLATION" },
2664 : { TLDAP_NOT_ALLOWED_ON_NONLEAF,
2665 : "TLDAP_NOT_ALLOWED_ON_NONLEAF" },
2666 : { TLDAP_NOT_ALLOWED_ON_RDN,
2667 : "TLDAP_NOT_ALLOWED_ON_RDN" },
2668 : { TLDAP_ALREADY_EXISTS,
2669 : "TLDAP_ALREADY_EXISTS" },
2670 : { TLDAP_NO_OBJECT_CLASS_MODS,
2671 : "TLDAP_NO_OBJECT_CLASS_MODS" },
2672 : { TLDAP_RESULTS_TOO_LARGE,
2673 : "TLDAP_RESULTS_TOO_LARGE" },
2674 : { TLDAP_AFFECTS_MULTIPLE_DSAS,
2675 : "TLDAP_AFFECTS_MULTIPLE_DSAS" },
2676 : { TLDAP_OTHER,
2677 : "TLDAP_OTHER" },
2678 : { TLDAP_SERVER_DOWN,
2679 : "TLDAP_SERVER_DOWN" },
2680 : { TLDAP_LOCAL_ERROR,
2681 : "TLDAP_LOCAL_ERROR" },
2682 : { TLDAP_ENCODING_ERROR,
2683 : "TLDAP_ENCODING_ERROR" },
2684 : { TLDAP_DECODING_ERROR,
2685 : "TLDAP_DECODING_ERROR" },
2686 : { TLDAP_TIMEOUT,
2687 : "TLDAP_TIMEOUT" },
2688 : { TLDAP_AUTH_UNKNOWN,
2689 : "TLDAP_AUTH_UNKNOWN" },
2690 : { TLDAP_FILTER_ERROR,
2691 : "TLDAP_FILTER_ERROR" },
2692 : { TLDAP_USER_CANCELLED,
2693 : "TLDAP_USER_CANCELLED" },
2694 : { TLDAP_PARAM_ERROR,
2695 : "TLDAP_PARAM_ERROR" },
2696 : { TLDAP_NO_MEMORY,
2697 : "TLDAP_NO_MEMORY" },
2698 : { TLDAP_CONNECT_ERROR,
2699 : "TLDAP_CONNECT_ERROR" },
2700 : { TLDAP_NOT_SUPPORTED,
2701 : "TLDAP_NOT_SUPPORTED" },
2702 : { TLDAP_CONTROL_NOT_FOUND,
2703 : "TLDAP_CONTROL_NOT_FOUND" },
2704 : { TLDAP_NO_RESULTS_RETURNED,
2705 : "TLDAP_NO_RESULTS_RETURNED" },
2706 : { TLDAP_MORE_RESULTS_TO_RETURN,
2707 : "TLDAP_MORE_RESULTS_TO_RETURN" },
2708 : { TLDAP_CLIENT_LOOP,
2709 : "TLDAP_CLIENT_LOOP" },
2710 : { TLDAP_REFERRAL_LIMIT_EXCEEDED,
2711 : "TLDAP_REFERRAL_LIMIT_EXCEEDED" },
2712 : };
2713 :
2714 0 : const char *tldap_rc2string(TLDAPRC rc)
2715 : {
2716 : size_t i;
2717 :
2718 0 : for (i=0; i<ARRAY_SIZE(tldaprc_errmap); i++) {
2719 0 : if (TLDAP_RC_EQUAL(rc, tldaprc_errmap[i].rc)) {
2720 0 : return tldaprc_errmap[i].string;
2721 : }
2722 : }
2723 :
2724 0 : return "Unknown LDAP Error";
2725 : }
|