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