2 Unix SMB/CIFS mplementation.
3 LDAP protocol helper functions for SAMBA
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Stefan Metzmacher 2004
8 Copyright (C) Simo Sorce 2004
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 2 of the License, or
13 (at your option) any later version.
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.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "libcli/util/asn_1.h"
28 #include "dlinklist.h"
29 #include "lib/events/events.h"
30 #include "lib/socket/socket.h"
31 #include "libcli/ldap/ldap.h"
32 #include "libcli/ldap/ldap_client.h"
33 #include "libcli/composite/composite.h"
34 #include "lib/stream/packet.h"
35 #include "auth/gensec/gensec.h"
39 create a new ldap_connection stucture. The event context is optional
41 struct ldap_connection *ldap_new_connection(TALLOC_CTX *mem_ctx,
42 struct event_context *ev)
44 struct ldap_connection *conn;
46 conn = talloc_zero(mem_ctx, struct ldap_connection);
52 ev = event_context_init(conn);
59 conn->next_messageid = 1;
60 conn->event.event_ctx = ev;
62 /* set a reasonable request timeout */
70 the connection is dead
72 static void ldap_connection_dead(struct ldap_connection *conn)
74 struct ldap_request *req;
76 while (conn->pending) {
78 DLIST_REMOVE(req->conn->pending, req);
79 req->state = LDAP_REQUEST_DONE;
80 req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
86 talloc_free(conn->tls);
93 static void ldap_error_handler(void *private, NTSTATUS status)
95 struct ldap_connection *conn = talloc_get_type(private,
96 struct ldap_connection);
97 ldap_connection_dead(conn);
102 match up with a pending message, adding to the replies list
104 static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg)
106 struct ldap_request *req;
108 for (req=conn->pending; req; req=req->next) {
109 if (req->messageid == msg->messageid) break;
111 /* match a zero message id to the last request sent.
112 It seems that servers send 0 if unable to parse */
113 if (req == NULL && msg->messageid == 0) {
117 DEBUG(0,("ldap: no matching message id for %u\n",
123 /* add to the list of replies received */
124 talloc_steal(req, msg);
125 req->replies = talloc_realloc(req, req->replies,
126 struct ldap_message *, req->num_replies+1);
127 if (req->replies == NULL) {
128 req->status = NT_STATUS_NO_MEMORY;
129 req->state = LDAP_REQUEST_DONE;
130 DLIST_REMOVE(conn->pending, req);
137 req->replies[req->num_replies] = talloc_steal(req->replies, msg);
140 if (msg->type != LDAP_TAG_SearchResultEntry &&
141 msg->type != LDAP_TAG_SearchResultReference) {
142 /* currently only search results expect multiple
144 req->state = LDAP_REQUEST_DONE;
145 DLIST_REMOVE(conn->pending, req);
155 check if a blob is a complete ldap packet
156 handle wrapper or unwrapped connections
158 NTSTATUS ldap_complete_packet(void *private, DATA_BLOB blob, size_t *size)
160 struct ldap_connection *conn = talloc_get_type(private,
161 struct ldap_connection);
162 if (conn->enable_wrap) {
163 return packet_full_request_u32(private, blob, size);
165 return ldap_full_packet(private, blob, size);
169 decode/process plain data
171 static NTSTATUS ldap_decode_plain(struct ldap_connection *conn, DATA_BLOB blob)
173 struct asn1_data asn1;
174 struct ldap_message *msg = talloc(conn, struct ldap_message);
177 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
180 if (!asn1_load(&asn1, blob)) {
181 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
184 if (!ldap_decode(&asn1, msg)) {
185 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
188 ldap_match_message(conn, msg);
190 data_blob_free(&blob);
196 decode/process wrapped data
198 static NTSTATUS ldap_decode_wrapped(struct ldap_connection *conn, DATA_BLOB blob)
200 DATA_BLOB wrapped, unwrapped;
201 struct asn1_data asn1;
202 struct ldap_message *msg = talloc(conn, struct ldap_message);
206 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
209 wrapped = data_blob_const(blob.data+4, blob.length-4);
211 status = gensec_unwrap(conn->gensec, msg, &wrapped, &unwrapped);
212 if (!NT_STATUS_IS_OK(status)) {
213 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
216 data_blob_free(&blob);
218 if (!asn1_load(&asn1, unwrapped)) {
219 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
222 while (ldap_decode(&asn1, msg)) {
223 ldap_match_message(conn, msg);
224 msg = talloc(conn, struct ldap_message);
235 handle ldap recv events
237 static NTSTATUS ldap_recv_handler(void *private, DATA_BLOB blob)
239 struct ldap_connection *conn = talloc_get_type(private,
240 struct ldap_connection);
241 if (conn->enable_wrap) {
242 return ldap_decode_wrapped(conn, blob);
245 return ldap_decode_plain(conn, blob);
250 handle ldap socket events
252 static void ldap_io_handler(struct event_context *ev, struct fd_event *fde,
253 uint16_t flags, void *private)
255 struct ldap_connection *conn = talloc_get_type(private,
256 struct ldap_connection);
257 if (flags & EVENT_FD_WRITE) {
258 packet_queue_run(conn->packet);
259 if (conn->tls == NULL) return;
261 if (flags & EVENT_FD_READ) {
262 packet_recv(conn->packet);
269 static NTSTATUS ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
270 char **host, uint16_t *port, BOOL *ldaps)
278 /* skip leading "URL:" (if any) */
279 if (strncasecmp(p, "URL:", 4) == 0) {
284 SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
286 ret = sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
288 return NT_STATUS_INVALID_PARAMETER;
291 if (strequal(protocol, "ldap")) {
294 } else if (strequal(protocol, "ldaps")) {
298 DEBUG(0, ("unrecognised ldap protocol (%s)!\n", protocol));
299 return NT_STATUS_PROTOCOL_UNREACHABLE;
305 *host = talloc_strdup(mem_ctx, tmp_host);
306 NT_STATUS_HAVE_NO_MEMORY(*host);
312 connect to a ldap server
315 struct ldap_connect_state {
316 struct composite_context *ctx;
317 struct ldap_connection *conn;
320 static void ldap_connect_recv_conn(struct composite_context *ctx);
322 struct composite_context *ldap_connect_send(struct ldap_connection *conn,
325 struct composite_context *result, *ctx;
326 struct ldap_connect_state *state;
328 result = talloc_zero(NULL, struct composite_context);
329 if (result == NULL) goto failed;
330 result->state = COMPOSITE_STATE_IN_PROGRESS;
331 result->async.fn = NULL;
332 result->event_ctx = conn->event.event_ctx;
334 state = talloc(result, struct ldap_connect_state);
335 if (state == NULL) goto failed;
337 result->private_data = state;
341 state->ctx->status = ldap_parse_basic_url(conn, url, &conn->host,
342 &conn->port, &conn->ldaps);
343 if (!NT_STATUS_IS_OK(state->ctx->status)) {
344 composite_error(state->ctx, state->ctx->status);
348 ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
349 conn->event.event_ctx);
350 if (ctx == NULL) goto failed;
352 ctx->async.fn = ldap_connect_recv_conn;
353 ctx->async.private_data = state;
361 static void ldap_connect_recv_conn(struct composite_context *ctx)
363 struct ldap_connect_state *state =
364 talloc_get_type(ctx->async.private_data,
365 struct ldap_connect_state);
366 struct ldap_connection *conn = state->conn;
369 state->ctx->status = socket_connect_multi_recv(ctx, state, &conn->sock,
371 if (!composite_is_ok(state->ctx)) return;
373 /* setup a handler for events on this socket */
374 conn->event.fde = event_add_fd(conn->event.event_ctx, conn->sock,
375 socket_get_fd(conn->sock),
376 EVENT_FD_READ, ldap_io_handler, conn);
377 if (conn->event.fde == NULL) {
378 composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
382 conn->tls = tls_init_client(conn->sock, conn->event.fde, conn->ldaps);
383 if (conn->tls == NULL) {
384 talloc_free(conn->sock);
387 talloc_steal(conn, conn->tls);
388 talloc_steal(conn->tls, conn->sock);
390 conn->packet = packet_init(conn);
391 if (conn->packet == NULL) {
392 talloc_free(conn->sock);
395 packet_set_private(conn->packet, conn);
396 packet_set_tls(conn->packet, conn->tls);
397 packet_set_callback(conn->packet, ldap_recv_handler);
398 packet_set_full_request(conn->packet, ldap_complete_packet);
399 packet_set_error_handler(conn->packet, ldap_error_handler);
400 packet_set_event_context(conn->packet, conn->event.event_ctx);
401 packet_set_fde(conn->packet, conn->event.fde);
402 packet_set_serialise(conn->packet);
404 composite_done(state->ctx);
409 NTSTATUS ldap_connect_recv(struct composite_context *ctx)
411 NTSTATUS status = composite_wait(ctx);
416 NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
418 struct composite_context *ctx = ldap_connect_send(conn, url);
419 return ldap_connect_recv(ctx);
422 /* destroy an open ldap request */
423 static int ldap_request_destructor(void *ptr)
425 struct ldap_request *req = talloc_get_type(ptr, struct ldap_request);
426 if (req->state == LDAP_REQUEST_PENDING) {
427 DLIST_REMOVE(req->conn->pending, req);
433 called on timeout of a ldap request
435 static void ldap_request_timeout(struct event_context *ev, struct timed_event *te,
436 struct timeval t, void *private)
438 struct ldap_request *req = talloc_get_type(private, struct ldap_request);
439 req->status = NT_STATUS_IO_TIMEOUT;
440 if (req->state == LDAP_REQUEST_PENDING) {
441 DLIST_REMOVE(req->conn->pending, req);
443 req->state = LDAP_REQUEST_DONE;
451 called on completion of a one-way ldap request
453 static void ldap_request_complete(struct event_context *ev, struct timed_event *te,
454 struct timeval t, void *private)
456 struct ldap_request *req = talloc_get_type(private, struct ldap_request);
463 send a ldap message - async interface
465 struct ldap_request *ldap_request_send(struct ldap_connection *conn,
466 struct ldap_message *msg)
468 struct ldap_request *req;
471 if (conn->tls == NULL) {
475 req = talloc_zero(conn, struct ldap_request);
476 if (req == NULL) goto failed;
478 req->state = LDAP_REQUEST_SEND;
480 req->messageid = conn->next_messageid++;
481 if (conn->next_messageid == 0) {
482 conn->next_messageid = 1;
484 req->type = msg->type;
485 if (req->messageid == -1) {
489 talloc_set_destructor(req, ldap_request_destructor);
491 msg->messageid = req->messageid;
493 if (!ldap_encode(msg, &req->data, req)) {
497 /* possibly encrypt/sign the request */
498 if (conn->enable_wrap) {
501 status = gensec_wrap(conn->gensec, req, &req->data, &wrapped);
502 if (!NT_STATUS_IS_OK(status)) {
505 data_blob_free(&req->data);
506 req->data = data_blob_talloc(req, NULL, wrapped.length + 4);
507 if (req->data.data == NULL) {
510 RSIVAL(req->data.data, 0, wrapped.length);
511 memcpy(req->data.data+4, wrapped.data, wrapped.length);
512 data_blob_free(&wrapped);
515 status = packet_send(conn->packet, req->data);
516 if (!NT_STATUS_IS_OK(status)) {
520 /* some requests don't expect a reply, so don't add those to the
522 if (req->type == LDAP_TAG_AbandonRequest ||
523 req->type == LDAP_TAG_UnbindRequest) {
524 req->status = NT_STATUS_OK;
525 req->state = LDAP_REQUEST_DONE;
526 /* we can't call the async callback now, as it isn't setup, so
527 call it as next event */
528 event_add_timed(conn->event.event_ctx, req, timeval_zero(),
529 ldap_request_complete, req);
533 req->state = LDAP_REQUEST_PENDING;
534 DLIST_ADD(conn->pending, req);
536 /* put a timeout on the request */
537 event_add_timed(conn->event.event_ctx, req,
538 timeval_current_ofs(conn->timeout, 0),
539 ldap_request_timeout, req);
550 wait for a request to complete
551 note that this does not destroy the request
553 NTSTATUS ldap_request_wait(struct ldap_request *req)
555 while (req->state != LDAP_REQUEST_DONE) {
556 if (event_loop_once(req->conn->event.event_ctx) != 0) {
557 req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
566 a mapping of ldap response code to strings
568 static const struct {
569 enum ldap_result_code code;
571 } ldap_code_map[] = {
572 #define _LDAP_MAP_CODE(c) { c, #c }
573 _LDAP_MAP_CODE(LDAP_SUCCESS),
574 _LDAP_MAP_CODE(LDAP_OPERATIONS_ERROR),
575 _LDAP_MAP_CODE(LDAP_PROTOCOL_ERROR),
576 _LDAP_MAP_CODE(LDAP_TIME_LIMIT_EXCEEDED),
577 _LDAP_MAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED),
578 _LDAP_MAP_CODE(LDAP_COMPARE_FALSE),
579 _LDAP_MAP_CODE(LDAP_COMPARE_TRUE),
580 _LDAP_MAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED),
581 _LDAP_MAP_CODE(LDAP_STRONG_AUTH_REQUIRED),
582 _LDAP_MAP_CODE(LDAP_REFERRAL),
583 _LDAP_MAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED),
584 _LDAP_MAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION),
585 _LDAP_MAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED),
586 _LDAP_MAP_CODE(LDAP_SASL_BIND_IN_PROGRESS),
587 _LDAP_MAP_CODE(LDAP_NO_SUCH_ATTRIBUTE),
588 _LDAP_MAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE),
589 _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_MATCHING),
590 _LDAP_MAP_CODE(LDAP_CONSTRAINT_VIOLATION),
591 _LDAP_MAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS),
592 _LDAP_MAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX),
593 _LDAP_MAP_CODE(LDAP_NO_SUCH_OBJECT),
594 _LDAP_MAP_CODE(LDAP_ALIAS_PROBLEM),
595 _LDAP_MAP_CODE(LDAP_INVALID_DN_SYNTAX),
596 _LDAP_MAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM),
597 _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION),
598 _LDAP_MAP_CODE(LDAP_INVALID_CREDENTIALS),
599 _LDAP_MAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTs),
600 _LDAP_MAP_CODE(LDAP_BUSY),
601 _LDAP_MAP_CODE(LDAP_UNAVAILABLE),
602 _LDAP_MAP_CODE(LDAP_UNWILLING_TO_PERFORM),
603 _LDAP_MAP_CODE(LDAP_LOOP_DETECT),
604 _LDAP_MAP_CODE(LDAP_NAMING_VIOLATION),
605 _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_VIOLATION),
606 _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF),
607 _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_RDN),
608 _LDAP_MAP_CODE(LDAP_ENTRY_ALREADY_EXISTS),
609 _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED),
610 _LDAP_MAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS),
611 _LDAP_MAP_CODE(LDAP_OTHER)
615 used to setup the status code from a ldap response
617 NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
620 const char *codename = "unknown";
622 if (r->resultcode == LDAP_SUCCESS) {
626 if (conn->last_error) {
627 talloc_free(conn->last_error);
630 for (i=0;i<ARRAY_SIZE(ldap_code_map);i++) {
631 if (r->resultcode == ldap_code_map[i].code) {
632 codename = ldap_code_map[i].str;
637 conn->last_error = talloc_asprintf(conn, "LDAP error %u %s - %s <%s> <%s>",
640 r->dn?r->dn:"(NULL)",
641 r->errormessage?r->errormessage:"",
642 r->referral?r->referral:"");
644 return NT_STATUS_LDAP(r->resultcode);
648 return error string representing the last error
650 const char *ldap_errstr(struct ldap_connection *conn, NTSTATUS status)
652 if (NT_STATUS_IS_LDAP(status) && conn->last_error != NULL) {
653 return conn->last_error;
655 return nt_errstr(status);
660 return the Nth result message, waiting if necessary
662 NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
666 NT_STATUS_HAVE_NO_MEMORY(req);
668 while (req->state != LDAP_REQUEST_DONE && n >= req->num_replies) {
669 if (event_loop_once(req->conn->event.event_ctx) != 0) {
670 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
674 if (n < req->num_replies) {
675 *msg = req->replies[n];
679 if (!NT_STATUS_IS_OK(req->status)) {
683 return NT_STATUS_NO_MORE_ENTRIES;
688 return a single result message, checking if it is of the expected LDAP type
690 NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
693 status = ldap_result_n(req, 0, msg);
694 if (!NT_STATUS_IS_OK(status)) {
697 if ((*msg)->type != type) {
699 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
705 a simple ldap transaction, for single result requests that only need a status code
706 this relies on single valued requests having the response type == request type + 1
708 NTSTATUS ldap_transaction(struct ldap_connection *conn, struct ldap_message *msg)
710 struct ldap_request *req = ldap_request_send(conn, msg);
711 struct ldap_message *res;
713 status = ldap_result_n(req, 0, &res);
714 if (!NT_STATUS_IS_OK(status)) {
718 if (res->type != msg->type + 1) {
720 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
722 status = ldap_check_response(conn, &res->r.GeneralResult);