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