Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : LDAP protocol helper functions for SAMBA
4 :
5 : Copyright (C) Andrew Tridgell 2004
6 : Copyright (C) Volker Lendecke 2004
7 : Copyright (C) Stefan Metzmacher 2004
8 : Copyright (C) Simo Sorce 2004
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 :
23 : */
24 :
25 : #include "includes.h"
26 : #include <tevent.h>
27 : #include "lib/socket/socket.h"
28 : #include "lib/tsocket/tsocket.h"
29 : #include "libcli/util/tstream.h"
30 : #include "../lib/util/asn1.h"
31 : #include "../lib/util/dlinklist.h"
32 : #include "libcli/ldap/libcli_ldap.h"
33 : #include "libcli/ldap/ldap_proto.h"
34 : #include "libcli/ldap/ldap_client.h"
35 : #include "libcli/composite/composite.h"
36 : #include "lib/tls/tls.h"
37 : #include "auth/gensec/gensec.h"
38 : #include "system/time.h"
39 : #include "param/param.h"
40 : #include "libcli/resolve/resolve.h"
41 :
42 : static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status);
43 :
44 26716 : static int ldap_connection_destructor(struct ldap_connection *conn)
45 : {
46 : /*
47 : * NT_STATUS_OK means that callbacks of pending requests are not
48 : * triggered
49 : */
50 26716 : ldap_connection_dead(conn, NT_STATUS_OK);
51 26716 : return 0;
52 : }
53 :
54 : /**
55 : create a new ldap_connection structure. The event context is optional
56 : */
57 :
58 26716 : _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,
59 : struct loadparm_context *lp_ctx,
60 : struct tevent_context *ev)
61 : {
62 122 : struct ldap_connection *conn;
63 :
64 26716 : if (ev == NULL) {
65 0 : return NULL;
66 : }
67 :
68 26716 : conn = talloc_zero(mem_ctx, struct ldap_connection);
69 26716 : if (conn == NULL) {
70 0 : return NULL;
71 : }
72 :
73 26716 : conn->next_messageid = 1;
74 26716 : conn->event.event_ctx = ev;
75 :
76 26716 : conn->sockets.send_queue = tevent_queue_create(conn,
77 : "ldap_connection send_queue");
78 26716 : if (conn->sockets.send_queue == NULL) {
79 0 : TALLOC_FREE(conn);
80 0 : return NULL;
81 : }
82 :
83 26716 : conn->lp_ctx = lp_ctx;
84 :
85 : /* set a reasonable request timeout */
86 26716 : conn->timeout = 60;
87 :
88 : /* explicitly avoid reconnections by default */
89 26716 : conn->reconnect.max_retries = 0;
90 :
91 26716 : talloc_set_destructor(conn, ldap_connection_destructor);
92 26716 : return conn;
93 : }
94 :
95 : /*
96 : the connection is dead
97 : */
98 26716 : static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status)
99 : {
100 122 : struct ldap_request *req;
101 :
102 26716 : tevent_queue_stop(conn->sockets.send_queue);
103 26716 : TALLOC_FREE(conn->sockets.recv_subreq);
104 26716 : conn->sockets.active = NULL;
105 26716 : TALLOC_FREE(conn->sockets.sasl);
106 26716 : TALLOC_FREE(conn->sockets.tls);
107 26716 : TALLOC_FREE(conn->sockets.raw);
108 :
109 : /* return an error for any pending request ... */
110 26782 : while (conn->pending) {
111 66 : req = conn->pending;
112 66 : DLIST_REMOVE(req->conn->pending, req);
113 66 : req->conn = NULL;
114 66 : req->state = LDAP_REQUEST_DONE;
115 66 : if (NT_STATUS_IS_OK(status)) {
116 66 : continue;
117 : }
118 0 : req->status = status;
119 0 : if (req->async.fn) {
120 0 : req->async.fn(req);
121 : }
122 : }
123 26716 : }
124 :
125 : static void ldap_reconnect(struct ldap_connection *conn);
126 :
127 : /*
128 : handle packet errors
129 : */
130 0 : static void ldap_error_handler(struct ldap_connection *conn, NTSTATUS status)
131 : {
132 0 : ldap_connection_dead(conn, status);
133 :
134 : /* but try to reconnect so that the ldb client can go on */
135 0 : ldap_reconnect(conn);
136 0 : }
137 :
138 :
139 : /*
140 : match up with a pending message, adding to the replies list
141 : */
142 1395562 : static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg)
143 : {
144 1116 : struct ldap_request *req;
145 1116 : int i;
146 :
147 1396075 : for (req=conn->pending; req; req=req->next) {
148 1396074 : if (req->messageid == msg->messageid) break;
149 : }
150 : /* match a zero message id to the last request sent.
151 : It seems that servers send 0 if unable to parse */
152 1395562 : if (req == NULL && msg->messageid == 0) {
153 1 : req = conn->pending;
154 : }
155 1395562 : if (req == NULL) {
156 0 : DEBUG(0,("ldap: no matching message id for %u\n",
157 : msg->messageid));
158 0 : TALLOC_FREE(msg);
159 0 : return;
160 : }
161 :
162 : /* Check for undecoded critical extensions */
163 1516591 : for (i=0; msg->controls && msg->controls[i]; i++) {
164 121029 : if (!msg->controls_decoded[i] &&
165 0 : msg->controls[i]->critical) {
166 0 : TALLOC_FREE(msg);
167 0 : req->status = NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION);
168 0 : req->state = LDAP_REQUEST_DONE;
169 0 : DLIST_REMOVE(conn->pending, req);
170 0 : if (req->async.fn) {
171 0 : req->async.fn(req);
172 : }
173 0 : return;
174 : }
175 : }
176 :
177 : /* add to the list of replies received */
178 1395562 : req->replies = talloc_realloc(req, req->replies,
179 : struct ldap_message *, req->num_replies+1);
180 1395562 : if (req->replies == NULL) {
181 0 : TALLOC_FREE(msg);
182 0 : req->status = NT_STATUS_NO_MEMORY;
183 0 : req->state = LDAP_REQUEST_DONE;
184 0 : DLIST_REMOVE(conn->pending, req);
185 0 : if (req->async.fn) {
186 0 : req->async.fn(req);
187 : }
188 0 : return;
189 : }
190 :
191 1395562 : req->replies[req->num_replies] = talloc_steal(req->replies, msg);
192 1395562 : req->num_replies++;
193 :
194 1395562 : if (msg->type != LDAP_TAG_SearchResultEntry &&
195 762181 : msg->type != LDAP_TAG_SearchResultReference) {
196 : /* currently only search results expect multiple
197 : replies */
198 629758 : req->state = LDAP_REQUEST_DONE;
199 629758 : DLIST_REMOVE(conn->pending, req);
200 : }
201 :
202 1395562 : if (req->async.fn) {
203 1307246 : req->async.fn(req);
204 : }
205 : }
206 :
207 : static void ldap_connection_recv_done(struct tevent_req *subreq);
208 :
209 2025399 : static void ldap_connection_recv_next(struct ldap_connection *conn)
210 : {
211 2025399 : struct tevent_req *subreq = NULL;
212 :
213 2025399 : if (conn->sockets.recv_subreq != NULL) {
214 4794 : return;
215 : }
216 :
217 2020605 : if (conn->sockets.active == NULL) {
218 0 : return;
219 : }
220 :
221 2020605 : if (conn->pending == NULL) {
222 624268 : return;
223 : }
224 :
225 : /*
226 : * The minimum size of a LDAP pdu is 7 bytes
227 : *
228 : * dumpasn1 -hh ldap-unbind-min.dat
229 : *
230 : * <30 05 02 01 09 42 00>
231 : * 0 5: SEQUENCE {
232 : * <02 01 09>
233 : * 2 1: INTEGER 9
234 : * <42 00>
235 : * 5 0: [APPLICATION 2]
236 : * : Error: Object has zero length.
237 : * : }
238 : *
239 : * dumpasn1 -hh ldap-unbind-windows.dat
240 : *
241 : * <30 84 00 00 00 05 02 01 09 42 00>
242 : * 0 5: SEQUENCE {
243 : * <02 01 09>
244 : * 6 1: INTEGER 9
245 : * <42 00>
246 : * 9 0: [APPLICATION 2]
247 : * : Error: Object has zero length.
248 : * : }
249 : *
250 : * This means using an initial read size
251 : * of 7 is ok.
252 : */
253 1395628 : subreq = tstream_read_pdu_blob_send(conn,
254 : conn->event.event_ctx,
255 : conn->sockets.active,
256 : 7, /* initial_read_size */
257 : ldap_full_packet,
258 : conn);
259 1395628 : if (subreq == NULL) {
260 0 : ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
261 0 : return;
262 : }
263 1395628 : tevent_req_set_callback(subreq, ldap_connection_recv_done, conn);
264 1395628 : conn->sockets.recv_subreq = subreq;
265 1395628 : return;
266 : }
267 :
268 : /*
269 : decode/process LDAP data
270 : */
271 1395562 : static void ldap_connection_recv_done(struct tevent_req *subreq)
272 : {
273 1116 : NTSTATUS status;
274 1116 : struct ldap_connection *conn =
275 1395562 : tevent_req_callback_data(subreq,
276 : struct ldap_connection);
277 1116 : struct ldap_message *msg;
278 1116 : struct asn1_data *asn1;
279 1116 : DATA_BLOB blob;
280 1395562 : struct ldap_request_limits limits = {0};
281 :
282 1395562 : msg = talloc_zero(conn, struct ldap_message);
283 1395562 : if (msg == NULL) {
284 0 : ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
285 0 : return;
286 : }
287 :
288 1395562 : asn1 = asn1_init(conn, ASN1_MAX_TREE_DEPTH);
289 1395562 : if (asn1 == NULL) {
290 0 : TALLOC_FREE(msg);
291 0 : ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
292 0 : return;
293 : }
294 :
295 1395562 : conn->sockets.recv_subreq = NULL;
296 :
297 1395562 : status = tstream_read_pdu_blob_recv(subreq,
298 : asn1,
299 : &blob);
300 1395562 : TALLOC_FREE(subreq);
301 1395562 : if (!NT_STATUS_IS_OK(status)) {
302 0 : TALLOC_FREE(msg);
303 0 : asn1_free(asn1);
304 0 : ldap_error_handler(conn, status);
305 0 : return;
306 : }
307 :
308 1395562 : asn1_load_nocopy(asn1, blob.data, blob.length);
309 :
310 1395562 : status = ldap_decode(asn1, &limits, samba_ldap_control_handlers(), msg);
311 1395562 : asn1_free(asn1);
312 1395562 : if (!NT_STATUS_IS_OK(status)) {
313 0 : TALLOC_FREE(msg);
314 0 : ldap_error_handler(conn, status);
315 0 : return;
316 : }
317 :
318 1395562 : ldap_match_message(conn, msg);
319 1395562 : ldap_connection_recv_next(conn);
320 :
321 1395562 : return;
322 : }
323 :
324 : enum ldap_proto {
325 : LDAP_PROTO_NONE,
326 : LDAP_PROTO_LDAP,
327 : LDAP_PROTO_LDAPS,
328 : LDAP_PROTO_LDAPI
329 : };
330 :
331 26716 : static int ldap_parse_basic_url(
332 : const char *url,
333 : enum ldap_proto *pproto,
334 : TALLOC_CTX *mem_ctx,
335 : char **pdest, /* path for ldapi, host for ldap[s] */
336 : uint16_t *pport) /* Not set for ldapi */
337 : {
338 26716 : enum ldap_proto proto = LDAP_PROTO_NONE;
339 26716 : char *host = NULL;
340 122 : int ret, port;
341 :
342 26716 : if (url == NULL) {
343 0 : return EINVAL;
344 : }
345 :
346 26716 : if (strncasecmp_m(url, "ldapi://", strlen("ldapi://")) == 0) {
347 108 : char *path = NULL, *end = NULL;
348 :
349 108 : path = talloc_strdup(mem_ctx, url+8);
350 108 : if (path == NULL) {
351 0 : return ENOMEM;
352 : }
353 108 : end = rfc1738_unescape(path);
354 108 : if (end == NULL) {
355 0 : TALLOC_FREE(path);
356 0 : return EINVAL;
357 : }
358 :
359 108 : *pproto = LDAP_PROTO_LDAPI;
360 108 : *pdest = path;
361 108 : return 0;
362 : }
363 :
364 26608 : if (strncasecmp_m(url, "ldap://", strlen("ldap://")) == 0) {
365 26131 : url += 7;
366 26131 : proto = LDAP_PROTO_LDAP;
367 26131 : port = 389;
368 : }
369 26608 : if (strncasecmp_m(url, "ldaps://", strlen("ldaps://")) == 0) {
370 477 : url += 8;
371 477 : port = 636;
372 477 : proto = LDAP_PROTO_LDAPS;
373 : }
374 :
375 26608 : if (proto == LDAP_PROTO_NONE) {
376 0 : return EPROTONOSUPPORT;
377 : }
378 :
379 26608 : if (url[0] == '[') {
380 : /*
381 : * IPv6 with [aa:bb:cc..]:port
382 : */
383 0 : const char *end = NULL;
384 :
385 0 : url +=1;
386 :
387 0 : end = strchr(url, ']');
388 0 : if (end == NULL) {
389 0 : return EINVAL;
390 : }
391 :
392 0 : ret = sscanf(end+1, ":%d", &port);
393 0 : if (ret < 0) {
394 0 : return EINVAL;
395 : }
396 :
397 0 : *pdest = talloc_strndup(mem_ctx, url, end-url);
398 0 : if (*pdest == NULL) {
399 0 : return ENOMEM;
400 : }
401 0 : *pproto = proto;
402 0 : *pport = port;
403 0 : return 0;
404 : }
405 :
406 26608 : ret = sscanf(url, "%m[^:/]:%d", &host, &port);
407 26608 : if (ret < 1) {
408 0 : return EINVAL;
409 : }
410 :
411 26608 : *pdest = talloc_strdup(mem_ctx, host);
412 26608 : SAFE_FREE(host);
413 26608 : if (*pdest == NULL) {
414 0 : return ENOMEM;
415 : }
416 26608 : *pproto = proto;
417 26608 : *pport = port;
418 :
419 26608 : return 0;
420 : }
421 :
422 : /*
423 : connect to a ldap server
424 : */
425 :
426 : struct ldap_connect_state {
427 : struct composite_context *ctx;
428 : struct ldap_connection *conn;
429 : struct socket_context *sock;
430 : struct tstream_context *raw;
431 : struct tstream_tls_params *tls_params;
432 : struct tstream_context *tls;
433 : };
434 :
435 : static void ldap_connect_recv_unix_conn(struct composite_context *ctx);
436 : static void ldap_connect_recv_tcp_conn(struct composite_context *ctx);
437 :
438 26716 : _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
439 : const char *url)
440 : {
441 122 : struct composite_context *result, *ctx;
442 122 : struct ldap_connect_state *state;
443 122 : enum ldap_proto proto;
444 26716 : char *dest = NULL;
445 122 : uint16_t port;
446 122 : int ret;
447 :
448 26716 : result = talloc_zero(conn, struct composite_context);
449 26716 : if (result == NULL) goto failed;
450 26716 : result->state = COMPOSITE_STATE_IN_PROGRESS;
451 26716 : result->async.fn = NULL;
452 26716 : result->event_ctx = conn->event.event_ctx;
453 :
454 26716 : state = talloc(result, struct ldap_connect_state);
455 26716 : if (state == NULL) goto failed;
456 26716 : state->ctx = result;
457 26716 : result->private_data = state;
458 :
459 26716 : state->conn = conn;
460 :
461 26716 : if (conn->reconnect.url == NULL) {
462 26716 : conn->reconnect.url = talloc_strdup(conn, url);
463 26716 : if (conn->reconnect.url == NULL) goto failed;
464 : }
465 :
466 26716 : ret = ldap_parse_basic_url(url, &proto, conn, &dest, &port);
467 26716 : if (ret != 0) {
468 0 : composite_error(result, map_nt_error_from_unix_common(ret));
469 0 : return result;
470 : }
471 :
472 26716 : if (proto == LDAP_PROTO_LDAPI) {
473 0 : struct socket_address *unix_addr;
474 108 : NTSTATUS status = socket_create(state, "unix",
475 : SOCKET_TYPE_STREAM,
476 : &state->sock, 0);
477 108 : if (!NT_STATUS_IS_OK(status)) {
478 0 : return NULL;
479 : }
480 :
481 108 : conn->host = talloc_asprintf(conn, "%s.%s",
482 : lpcfg_netbios_name(conn->lp_ctx),
483 : lpcfg_dnsdomain(conn->lp_ctx));
484 108 : if (composite_nomem(conn->host, state->ctx)) {
485 0 : return result;
486 : }
487 :
488 108 : unix_addr = socket_address_from_strings(state, state->sock->backend_name,
489 : dest, 0);
490 108 : if (composite_nomem(unix_addr, result)) {
491 0 : return result;
492 : }
493 :
494 108 : ctx = socket_connect_send(state->sock, NULL, unix_addr,
495 : 0, result->event_ctx);
496 108 : ctx->async.fn = ldap_connect_recv_unix_conn;
497 108 : ctx->async.private_data = state;
498 108 : return result;
499 : }
500 :
501 26608 : if ((proto == LDAP_PROTO_LDAP) || (proto == LDAP_PROTO_LDAPS)) {
502 :
503 26608 : conn->ldaps = (proto == LDAP_PROTO_LDAPS);
504 :
505 26608 : conn->host = talloc_move(conn, &dest);
506 26608 : conn->port = port;
507 :
508 26608 : if (conn->ldaps) {
509 477 : char *ca_file = lpcfg_tls_cafile(state, conn->lp_ctx);
510 477 : char *crl_file = lpcfg_tls_crlfile(state, conn->lp_ctx);
511 477 : const char *tls_priority = lpcfg_tls_priority(conn->lp_ctx);
512 477 : enum tls_verify_peer_state verify_peer =
513 477 : lpcfg_tls_verify_peer(conn->lp_ctx);
514 0 : NTSTATUS status;
515 :
516 477 : status = tstream_tls_params_client(state,
517 : ca_file,
518 : crl_file,
519 : tls_priority,
520 : verify_peer,
521 477 : conn->host,
522 : &state->tls_params);
523 477 : if (!NT_STATUS_IS_OK(status)) {
524 6 : composite_error(result, status);
525 6 : return result;
526 : }
527 : }
528 :
529 26602 : ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
530 : lpcfg_resolve_context(conn->lp_ctx),
531 : result->event_ctx);
532 26602 : if (composite_nomem(ctx, result)) {
533 0 : return result;
534 : }
535 :
536 26602 : ctx->async.fn = ldap_connect_recv_tcp_conn;
537 26602 : ctx->async.private_data = state;
538 26602 : return result;
539 : }
540 0 : failed:
541 0 : talloc_free(result);
542 0 : return NULL;
543 : }
544 :
545 : static void ldap_connect_got_tls(struct tevent_req *subreq);
546 :
547 26710 : static void ldap_connect_got_sock(struct composite_context *ctx,
548 : struct ldap_connection *conn)
549 : {
550 122 : struct ldap_connect_state *state =
551 26710 : talloc_get_type_abort(ctx->private_data,
552 : struct ldap_connect_state);
553 26710 : struct tevent_req *subreq = NULL;
554 122 : int fd;
555 122 : int ret;
556 :
557 26710 : socket_set_flags(state->sock, SOCKET_FLAG_NOCLOSE);
558 26710 : fd = socket_get_fd(state->sock);
559 26710 : TALLOC_FREE(state->sock);
560 :
561 26710 : smb_set_close_on_exec(fd);
562 :
563 26710 : ret = set_blocking(fd, false);
564 26710 : if (ret == -1) {
565 0 : NTSTATUS status = map_nt_error_from_unix_common(errno);
566 0 : composite_error(state->ctx, status);
567 0 : return;
568 : }
569 :
570 26710 : ret = tstream_bsd_existing_socket(state, fd, &state->raw);
571 26710 : if (ret == -1) {
572 0 : NTSTATUS status = map_nt_error_from_unix_common(errno);
573 0 : composite_error(state->ctx, status);
574 0 : return;
575 : }
576 :
577 26710 : if (!conn->ldaps) {
578 26239 : conn->sockets.raw = talloc_move(conn, &state->raw);
579 26239 : conn->sockets.active = conn->sockets.raw;
580 26239 : composite_done(state->ctx);
581 26239 : return;
582 : }
583 :
584 471 : subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
585 : state->raw, state->tls_params);
586 471 : if (composite_nomem(subreq, state->ctx)) {
587 0 : return;
588 : }
589 471 : tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
590 : }
591 :
592 471 : static void ldap_connect_got_tls(struct tevent_req *subreq)
593 : {
594 0 : struct ldap_connect_state *state =
595 471 : tevent_req_callback_data(subreq,
596 : struct ldap_connect_state);
597 0 : int err;
598 0 : int ret;
599 :
600 471 : ret = tstream_tls_connect_recv(subreq, &err, state, &state->tls);
601 471 : TALLOC_FREE(subreq);
602 471 : if (ret == -1) {
603 13 : NTSTATUS status = map_nt_error_from_unix_common(err);
604 13 : composite_error(state->ctx, status);
605 13 : return;
606 : }
607 :
608 458 : talloc_steal(state->tls, state->tls_params);
609 :
610 458 : state->conn->sockets.raw = talloc_move(state->conn, &state->raw);
611 458 : state->conn->sockets.tls = talloc_move(state->conn->sockets.raw,
612 : &state->tls);
613 458 : state->conn->sockets.active = state->conn->sockets.tls;
614 458 : composite_done(state->ctx);
615 : }
616 :
617 26602 : static void ldap_connect_recv_tcp_conn(struct composite_context *ctx)
618 : {
619 122 : struct ldap_connect_state *state =
620 26602 : talloc_get_type_abort(ctx->async.private_data,
621 : struct ldap_connect_state);
622 26602 : struct ldap_connection *conn = state->conn;
623 122 : uint16_t port;
624 26602 : NTSTATUS status = socket_connect_multi_recv(ctx, state, &state->sock,
625 : &port);
626 26602 : if (!NT_STATUS_IS_OK(status)) {
627 0 : composite_error(state->ctx, status);
628 0 : return;
629 : }
630 :
631 26602 : ldap_connect_got_sock(state->ctx, conn);
632 : }
633 :
634 108 : static void ldap_connect_recv_unix_conn(struct composite_context *ctx)
635 : {
636 0 : struct ldap_connect_state *state =
637 108 : talloc_get_type_abort(ctx->async.private_data,
638 : struct ldap_connect_state);
639 108 : struct ldap_connection *conn = state->conn;
640 :
641 108 : NTSTATUS status = socket_connect_recv(ctx);
642 :
643 108 : if (!NT_STATUS_IS_OK(state->ctx->status)) {
644 0 : composite_error(state->ctx, status);
645 0 : return;
646 : }
647 :
648 108 : ldap_connect_got_sock(state->ctx, conn);
649 : }
650 :
651 26716 : _PUBLIC_ NTSTATUS ldap_connect_recv(struct composite_context *ctx)
652 : {
653 26716 : NTSTATUS status = composite_wait(ctx);
654 26716 : talloc_free(ctx);
655 26716 : return status;
656 : }
657 :
658 26716 : _PUBLIC_ NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
659 : {
660 26716 : struct composite_context *ctx = ldap_connect_send(conn, url);
661 26716 : return ldap_connect_recv(ctx);
662 : }
663 :
664 : /* set reconnect parameters */
665 :
666 0 : _PUBLIC_ void ldap_set_reconn_params(struct ldap_connection *conn, int max_retries)
667 : {
668 0 : if (conn) {
669 0 : conn->reconnect.max_retries = max_retries;
670 0 : conn->reconnect.retries = 0;
671 0 : conn->reconnect.previous = time_mono(NULL);
672 : }
673 0 : }
674 :
675 : /* Actually this function is NOT ASYNC safe, FIXME? */
676 0 : static void ldap_reconnect(struct ldap_connection *conn)
677 : {
678 0 : NTSTATUS status;
679 0 : time_t now = time_mono(NULL);
680 :
681 : /* do we have set up reconnect ? */
682 0 : if (conn->reconnect.max_retries == 0) return;
683 :
684 : /* is the retry time expired ? */
685 0 : if (now > conn->reconnect.previous + 30) {
686 0 : conn->reconnect.retries = 0;
687 0 : conn->reconnect.previous = now;
688 : }
689 :
690 : /* are we reconnectind too often and too fast? */
691 0 : if (conn->reconnect.retries > conn->reconnect.max_retries) return;
692 :
693 : /* keep track of the number of reconnections */
694 0 : conn->reconnect.retries++;
695 :
696 : /* reconnect */
697 0 : status = ldap_connect(conn, conn->reconnect.url);
698 0 : if ( ! NT_STATUS_IS_OK(status)) {
699 0 : return;
700 : }
701 :
702 : /* rebind */
703 0 : status = ldap_rebind(conn);
704 0 : if ( ! NT_STATUS_IS_OK(status)) {
705 0 : ldap_connection_dead(conn, status);
706 : }
707 : }
708 :
709 13 : static void ldap_request_destructor_abandon(struct ldap_request *abandon)
710 : {
711 13 : TALLOC_FREE(abandon);
712 13 : }
713 :
714 : /* destroy an open ldap request */
715 629918 : static int ldap_request_destructor(struct ldap_request *req)
716 : {
717 629918 : if (req->state == LDAP_REQUEST_PENDING) {
718 79 : struct ldap_message msg = {
719 : .type = LDAP_TAG_AbandonRequest,
720 79 : .r.AbandonRequest.messageid = req->messageid,
721 : };
722 79 : struct ldap_request *abandon = NULL;
723 :
724 79 : DLIST_REMOVE(req->conn->pending, req);
725 :
726 79 : abandon = ldap_request_send(req->conn, &msg);
727 79 : if (abandon == NULL) {
728 0 : ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
729 0 : return 0;
730 : }
731 79 : abandon->async.fn = ldap_request_destructor_abandon;
732 79 : abandon->async.private_data = NULL;
733 : }
734 :
735 629209 : return 0;
736 : }
737 :
738 0 : static void ldap_request_timeout_abandon(struct ldap_request *abandon)
739 : {
740 0 : struct ldap_request *req =
741 0 : talloc_get_type_abort(abandon->async.private_data,
742 : struct ldap_request);
743 :
744 0 : if (req->state == LDAP_REQUEST_PENDING) {
745 0 : DLIST_REMOVE(req->conn->pending, req);
746 : }
747 0 : req->state = LDAP_REQUEST_DONE;
748 0 : if (req->async.fn) {
749 0 : req->async.fn(req);
750 : }
751 0 : }
752 :
753 : /*
754 : called on timeout of a ldap request
755 : */
756 14 : static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer *te,
757 : struct timeval t, void *private_data)
758 : {
759 0 : struct ldap_request *req =
760 14 : talloc_get_type_abort(private_data,
761 : struct ldap_request);
762 :
763 14 : req->status = NT_STATUS_IO_TIMEOUT;
764 14 : if (req->state == LDAP_REQUEST_PENDING) {
765 0 : struct ldap_message msg = {
766 : .type = LDAP_TAG_AbandonRequest,
767 0 : .r.AbandonRequest.messageid = req->messageid,
768 : };
769 0 : struct ldap_request *abandon = NULL;
770 :
771 0 : abandon = ldap_request_send(req->conn, &msg);
772 0 : if (abandon == NULL) {
773 0 : ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
774 0 : return;
775 : }
776 0 : talloc_reparent(req->conn, req, abandon);
777 0 : abandon->async.fn = ldap_request_timeout_abandon;
778 0 : abandon->async.private_data = req;
779 0 : DLIST_REMOVE(req->conn->pending, req);
780 0 : return;
781 : }
782 14 : req->state = LDAP_REQUEST_DONE;
783 14 : if (req->async.fn) {
784 0 : req->async.fn(req);
785 : }
786 : }
787 :
788 :
789 : /*
790 : called on completion of a failed ldap request
791 : */
792 0 : static void ldap_request_failed_complete(struct tevent_context *ev, struct tevent_timer *te,
793 : struct timeval t, void *private_data)
794 : {
795 0 : struct ldap_request *req =
796 0 : talloc_get_type_abort(private_data,
797 : struct ldap_request);
798 :
799 0 : if (req->async.fn) {
800 0 : req->async.fn(req);
801 : }
802 0 : }
803 :
804 : static void ldap_request_written(struct tevent_req *subreq);
805 :
806 : /*
807 : send a ldap message - async interface
808 : */
809 629918 : _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
810 : struct ldap_message *msg)
811 : {
812 709 : struct ldap_request *req;
813 629918 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
814 629918 : struct tevent_req *subreq = NULL;
815 :
816 629918 : req = talloc_zero(conn, struct ldap_request);
817 629918 : if (req == NULL) return NULL;
818 :
819 629918 : if (conn->sockets.active == NULL) {
820 0 : status = NT_STATUS_INVALID_CONNECTION;
821 0 : goto failed;
822 : }
823 :
824 629918 : req->state = LDAP_REQUEST_SEND;
825 629918 : req->conn = conn;
826 629918 : req->messageid = conn->next_messageid++;
827 629918 : if (conn->next_messageid == 0) {
828 0 : conn->next_messageid = 1;
829 : }
830 629918 : req->type = msg->type;
831 629918 : if (req->messageid == -1) {
832 0 : goto failed;
833 : }
834 :
835 629918 : talloc_set_destructor(req, ldap_request_destructor);
836 :
837 629918 : msg->messageid = req->messageid;
838 :
839 629918 : if (!ldap_encode(msg, samba_ldap_control_handlers(), &req->data, req)) {
840 0 : status = NT_STATUS_INTERNAL_ERROR;
841 0 : goto failed;
842 : }
843 :
844 : /* put a timeout on the request */
845 629918 : req->time_event = tevent_add_timer(conn->event.event_ctx, req,
846 : timeval_current_ofs(conn->timeout, 0),
847 : ldap_request_timeout, req);
848 629918 : if (req->time_event == NULL) {
849 0 : status = NT_STATUS_NO_MEMORY;
850 0 : goto failed;
851 : }
852 :
853 629918 : req->write_iov.iov_base = req->data.data;
854 629918 : req->write_iov.iov_len = req->data.length;
855 :
856 630627 : subreq = tstream_writev_queue_send(req, conn->event.event_ctx,
857 : conn->sockets.active,
858 : conn->sockets.send_queue,
859 629918 : &req->write_iov, 1);
860 629918 : if (subreq == NULL) {
861 0 : status = NT_STATUS_NO_MEMORY;
862 0 : goto failed;
863 : }
864 629918 : tevent_req_set_callback(subreq, ldap_request_written, req);
865 :
866 629918 : req->state = LDAP_REQUEST_PENDING;
867 629918 : DLIST_ADD(conn->pending, req);
868 :
869 629209 : return req;
870 :
871 0 : failed:
872 0 : req->status = status;
873 0 : req->state = LDAP_REQUEST_ERROR;
874 0 : tevent_add_timer(conn->event.event_ctx, req, timeval_zero(),
875 : ldap_request_failed_complete, req);
876 :
877 0 : return req;
878 : }
879 :
880 629852 : static void ldap_request_written(struct tevent_req *subreq)
881 : {
882 709 : struct ldap_request *req =
883 629852 : tevent_req_callback_data(subreq,
884 : struct ldap_request);
885 709 : int err;
886 709 : ssize_t ret;
887 :
888 629852 : ret = tstream_writev_queue_recv(subreq, &err);
889 629852 : TALLOC_FREE(subreq);
890 629852 : if (ret == -1) {
891 0 : NTSTATUS error = map_nt_error_from_unix_common(err);
892 0 : ldap_error_handler(req->conn, error);
893 0 : return;
894 : }
895 :
896 629852 : if (req->type == LDAP_TAG_AbandonRequest ||
897 629129 : req->type == LDAP_TAG_UnbindRequest)
898 : {
899 15 : if (req->state == LDAP_REQUEST_PENDING) {
900 15 : DLIST_REMOVE(req->conn->pending, req);
901 : }
902 15 : req->state = LDAP_REQUEST_DONE;
903 15 : if (req->async.fn) {
904 13 : req->async.fn(req);
905 : }
906 15 : return;
907 : }
908 :
909 629837 : ldap_connection_recv_next(req->conn);
910 : }
911 :
912 :
913 : /*
914 : wait for a request to complete
915 : note that this does not destroy the request
916 : */
917 446 : _PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req)
918 : {
919 2988 : while (req->state < LDAP_REQUEST_DONE) {
920 2542 : if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
921 0 : req->state = LDAP_REQUEST_ERROR;
922 0 : req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
923 0 : break;
924 : }
925 : }
926 446 : return req->status;
927 : }
928 :
929 :
930 : /*
931 : a mapping of ldap response code to strings
932 : */
933 : static const struct {
934 : enum ldap_result_code code;
935 : const char *str;
936 : } ldap_code_map[] = {
937 : #define _LDAP_MAP_CODE(c) { c, #c }
938 : _LDAP_MAP_CODE(LDAP_SUCCESS),
939 : _LDAP_MAP_CODE(LDAP_OPERATIONS_ERROR),
940 : _LDAP_MAP_CODE(LDAP_PROTOCOL_ERROR),
941 : _LDAP_MAP_CODE(LDAP_TIME_LIMIT_EXCEEDED),
942 : _LDAP_MAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED),
943 : _LDAP_MAP_CODE(LDAP_COMPARE_FALSE),
944 : _LDAP_MAP_CODE(LDAP_COMPARE_TRUE),
945 : _LDAP_MAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED),
946 : _LDAP_MAP_CODE(LDAP_STRONG_AUTH_REQUIRED),
947 : _LDAP_MAP_CODE(LDAP_REFERRAL),
948 : _LDAP_MAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED),
949 : _LDAP_MAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION),
950 : _LDAP_MAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED),
951 : _LDAP_MAP_CODE(LDAP_SASL_BIND_IN_PROGRESS),
952 : _LDAP_MAP_CODE(LDAP_NO_SUCH_ATTRIBUTE),
953 : _LDAP_MAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE),
954 : _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_MATCHING),
955 : _LDAP_MAP_CODE(LDAP_CONSTRAINT_VIOLATION),
956 : _LDAP_MAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS),
957 : _LDAP_MAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX),
958 : _LDAP_MAP_CODE(LDAP_NO_SUCH_OBJECT),
959 : _LDAP_MAP_CODE(LDAP_ALIAS_PROBLEM),
960 : _LDAP_MAP_CODE(LDAP_INVALID_DN_SYNTAX),
961 : _LDAP_MAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM),
962 : _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION),
963 : _LDAP_MAP_CODE(LDAP_INVALID_CREDENTIALS),
964 : _LDAP_MAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTS),
965 : _LDAP_MAP_CODE(LDAP_BUSY),
966 : _LDAP_MAP_CODE(LDAP_UNAVAILABLE),
967 : _LDAP_MAP_CODE(LDAP_UNWILLING_TO_PERFORM),
968 : _LDAP_MAP_CODE(LDAP_LOOP_DETECT),
969 : _LDAP_MAP_CODE(LDAP_NAMING_VIOLATION),
970 : _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_VIOLATION),
971 : _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF),
972 : _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_RDN),
973 : _LDAP_MAP_CODE(LDAP_ENTRY_ALREADY_EXISTS),
974 : _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED),
975 : _LDAP_MAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS),
976 : _LDAP_MAP_CODE(LDAP_OTHER)
977 : };
978 :
979 : /*
980 : used to setup the status code from a ldap response
981 : */
982 594597 : _PUBLIC_ NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
983 : {
984 587 : size_t i;
985 594597 : const char *codename = "unknown";
986 :
987 594597 : if (r->resultcode == LDAP_SUCCESS) {
988 542595 : return NT_STATUS_OK;
989 : }
990 :
991 52002 : if (conn->last_error) {
992 42013 : talloc_free(conn->last_error);
993 : }
994 :
995 1116008 : for (i=0;i<ARRAY_SIZE(ldap_code_map);i++) {
996 1116008 : if ((enum ldap_result_code)r->resultcode == ldap_code_map[i].code) {
997 52002 : codename = ldap_code_map[i].str;
998 52002 : break;
999 : }
1000 : }
1001 :
1002 156006 : conn->last_error = talloc_asprintf(conn, "LDAP error %u %s - %s <%s> <%s>",
1003 : r->resultcode,
1004 : codename,
1005 52002 : r->dn?r->dn:"(NULL)",
1006 52002 : r->errormessage?r->errormessage:"",
1007 52002 : r->referral?r->referral:"");
1008 :
1009 52002 : return NT_STATUS_LDAP(r->resultcode);
1010 : }
1011 :
1012 : /*
1013 : return error string representing the last error
1014 : */
1015 52906 : _PUBLIC_ const char *ldap_errstr(struct ldap_connection *conn,
1016 : TALLOC_CTX *mem_ctx,
1017 : NTSTATUS status)
1018 : {
1019 52906 : if (NT_STATUS_IS_LDAP(status) && conn->last_error != NULL) {
1020 52324 : return talloc_strdup(mem_ctx, conn->last_error);
1021 : }
1022 582 : return talloc_asprintf(mem_ctx, "LDAP client internal error: %s", nt_errstr(status));
1023 : }
1024 :
1025 :
1026 : /*
1027 : return the Nth result message, waiting if necessary
1028 : */
1029 87870 : _PUBLIC_ NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
1030 : {
1031 87870 : *msg = NULL;
1032 :
1033 87870 : NT_STATUS_HAVE_NO_MEMORY(req);
1034 :
1035 342196 : while (req->state < LDAP_REQUEST_DONE && n >= req->num_replies) {
1036 254326 : if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
1037 0 : return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1038 : }
1039 : }
1040 :
1041 87870 : if (n < req->num_replies) {
1042 87870 : *msg = req->replies[n];
1043 87870 : return NT_STATUS_OK;
1044 : }
1045 :
1046 0 : if (!NT_STATUS_IS_OK(req->status)) {
1047 0 : return req->status;
1048 : }
1049 :
1050 0 : return NT_STATUS_NO_MORE_ENTRIES;
1051 : }
1052 :
1053 :
1054 : /*
1055 : return a single result message, checking if it is of the expected LDAP type
1056 : */
1057 14 : _PUBLIC_ NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
1058 : {
1059 0 : NTSTATUS status;
1060 14 : status = ldap_result_n(req, 0, msg);
1061 14 : if (!NT_STATUS_IS_OK(status)) {
1062 0 : return status;
1063 : }
1064 14 : if ((*msg) != NULL && (*msg)->type != (enum ldap_request_tag)type) {
1065 0 : *msg = NULL;
1066 0 : return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1067 : }
1068 14 : return status;
1069 : }
|