2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 see RFC1798 for details of CLDAP
26 - carried over UDP on port 389
27 - request and response matched by message ID
28 - request consists of only a single searchRequest element
29 - response can be in one of two forms
30 - a single searchResponse, followed by a searchResult
31 - a single searchResult
35 #include "lib/events/events.h"
36 #include "lib/util/dlinklist.h"
37 #include "libcli/ldap/ldap.h"
38 #include "libcli/ldap/ldap_ndr.h"
39 #include "libcli/cldap/cldap.h"
40 #include "lib/socket/socket.h"
41 #include "libcli/security/security.h"
42 #include "librpc/gen_ndr/ndr_nbt.h"
43 #include "param/param.h"
46 destroy a pending request
48 static int cldap_request_destructor(struct cldap_request *req)
50 if (req->state == CLDAP_REQUEST_SEND) {
51 DLIST_REMOVE(req->cldap->send_queue, req);
53 if (!req->is_reply && req->message_id != 0) {
54 idr_remove(req->cldap->idr, req->message_id);
61 handle recv events on a cldap socket
63 static void cldap_socket_recv(struct cldap_socket *cldap)
65 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
67 struct socket_address *src;
70 struct asn1_data *asn1 = asn1_init(tmp_ctx);
71 struct ldap_message *ldap_msg;
72 struct cldap_request *req;
76 status = socket_pending(cldap->sock, &dsize);
77 if (!NT_STATUS_IS_OK(status)) {
82 blob = data_blob_talloc(tmp_ctx, NULL, dsize);
83 if (blob.data == NULL) {
88 status = socket_recvfrom(cldap->sock, blob.data, blob.length, &nread,
90 if (!NT_STATUS_IS_OK(status)) {
96 DEBUG(2,("Received cldap packet of length %d from %s:%d\n",
97 (int)blob.length, src->addr, src->port));
99 if (!asn1_load(asn1, blob)) {
100 DEBUG(2,("Failed to setup for asn.1 decode\n"));
101 talloc_free(tmp_ctx);
105 ldap_msg = talloc(tmp_ctx, struct ldap_message);
106 if (ldap_msg == NULL) {
107 talloc_free(tmp_ctx);
111 /* this initial decode is used to find the message id */
112 status = ldap_decode(asn1, ldap_msg);
113 if (!NT_STATUS_IS_OK(status)) {
114 DEBUG(2,("Failed to decode ldap message: %s\n", nt_errstr(status)));
115 talloc_free(tmp_ctx);
119 /* find the pending request */
120 req = idr_find(cldap->idr, ldap_msg->messageid);
122 if (cldap->incoming.handler) {
123 cldap->incoming.handler(cldap, ldap_msg, src);
125 DEBUG(2,("Mismatched cldap reply %u from %s:%d\n",
126 ldap_msg->messageid, src->addr, src->port));
128 talloc_free(tmp_ctx);
132 req->asn1 = talloc_steal(req, asn1);
135 req->state = CLDAP_REQUEST_DONE;
136 talloc_free(req->te);
138 talloc_free(tmp_ctx);
146 handle request timeouts
148 static void cldap_request_timeout(struct event_context *event_ctx,
149 struct timed_event *te, struct timeval t,
152 struct cldap_request *req = talloc_get_type(private, struct cldap_request);
154 /* possibly try again */
155 if (req->num_retries != 0) {
156 size_t len = req->encoded.length;
160 socket_sendto(req->cldap->sock, &req->encoded, &len,
163 req->te = event_add_timed(req->cldap->event_ctx, req,
164 timeval_current_ofs(req->timeout, 0),
165 cldap_request_timeout, req);
169 req->state = CLDAP_REQUEST_ERROR;
170 req->status = NT_STATUS_IO_TIMEOUT;
177 handle send events on a cldap socket
179 static void cldap_socket_send(struct cldap_socket *cldap)
181 struct cldap_request *req;
184 while ((req = cldap->send_queue)) {
187 len = req->encoded.length;
188 status = socket_sendto(cldap->sock, &req->encoded, &len,
190 if (NT_STATUS_IS_ERR(status)) {
191 DEBUG(0,("Failed to send cldap request of length %u to %s:%d\n",
192 (unsigned)req->encoded.length, req->dest->addr, req->dest->port));
193 DLIST_REMOVE(cldap->send_queue, req);
194 req->state = CLDAP_REQUEST_ERROR;
195 req->status = status;
202 if (!NT_STATUS_IS_OK(status)) return;
204 DLIST_REMOVE(cldap->send_queue, req);
209 req->state = CLDAP_REQUEST_WAIT;
211 req->te = event_add_timed(cldap->event_ctx, req,
212 timeval_current_ofs(req->timeout, 0),
213 cldap_request_timeout, req);
215 EVENT_FD_READABLE(cldap->fde);
219 EVENT_FD_NOT_WRITEABLE(cldap->fde);
225 handle fd events on a cldap_socket
227 static void cldap_socket_handler(struct event_context *ev, struct fd_event *fde,
228 uint16_t flags, void *private)
230 struct cldap_socket *cldap = talloc_get_type(private, struct cldap_socket);
231 if (flags & EVENT_FD_WRITE) {
232 cldap_socket_send(cldap);
234 if (flags & EVENT_FD_READ) {
235 cldap_socket_recv(cldap);
240 initialise a cldap_socket. The event_ctx is optional, if provided
241 then operations will use that event context
243 struct cldap_socket *cldap_socket_init(TALLOC_CTX *mem_ctx,
244 struct event_context *event_ctx,
245 struct smb_iconv_convenience *iconv_convenience)
247 struct cldap_socket *cldap;
250 cldap = talloc(mem_ctx, struct cldap_socket);
251 if (cldap == NULL) goto failed;
253 if (event_ctx == NULL) {
254 cldap->event_ctx = event_context_init(cldap);
256 cldap->event_ctx = talloc_reference(cldap, event_ctx);
258 if (cldap->event_ctx == NULL) goto failed;
260 cldap->idr = idr_init(cldap);
261 if (cldap->idr == NULL) goto failed;
263 status = socket_create("ip", SOCKET_TYPE_DGRAM, &cldap->sock, 0);
264 if (!NT_STATUS_IS_OK(status)) goto failed;
266 talloc_steal(cldap, cldap->sock);
268 cldap->fde = event_add_fd(cldap->event_ctx, cldap,
269 socket_get_fd(cldap->sock), 0,
270 cldap_socket_handler, cldap);
272 cldap->send_queue = NULL;
273 cldap->incoming.handler = NULL;
274 cldap->iconv_convenience = iconv_convenience;
285 setup a handler for incoming requests
287 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
288 void (*handler)(struct cldap_socket *, struct ldap_message *,
289 struct socket_address *),
292 cldap->incoming.handler = handler;
293 cldap->incoming.private = private;
294 EVENT_FD_READABLE(cldap->fde);
299 queue a cldap request for send
301 struct cldap_request *cldap_search_send(struct cldap_socket *cldap,
302 struct cldap_search *io)
304 struct ldap_message *msg;
305 struct cldap_request *req;
306 struct ldap_SearchRequest *search;
308 req = talloc_zero(cldap, struct cldap_request);
309 if (req == NULL) goto failed;
312 req->state = CLDAP_REQUEST_SEND;
313 req->timeout = io->in.timeout;
314 req->num_retries = io->in.retries;
315 req->is_reply = false;
316 req->asn1 = asn1_init(req);
321 req->dest = socket_address_from_strings(req, cldap->sock->backend_name,
324 if (!req->dest) goto failed;
326 req->message_id = idr_get_new_random(cldap->idr, req, UINT16_MAX);
327 if (req->message_id == -1) goto failed;
329 talloc_set_destructor(req, cldap_request_destructor);
331 msg = talloc(req, struct ldap_message);
332 if (msg == NULL) goto failed;
333 msg->messageid = req->message_id;
334 msg->type = LDAP_TAG_SearchRequest;
335 msg->controls = NULL;
336 search = &msg->r.SearchRequest;
339 search->scope = LDAP_SEARCH_SCOPE_BASE;
340 search->deref = LDAP_DEREFERENCE_NEVER;
341 search->timelimit = 0;
342 search->sizelimit = 0;
343 search->attributesonly = false;
344 search->num_attributes = str_list_length(io->in.attributes);
345 search->attributes = io->in.attributes;
346 search->tree = ldb_parse_tree(req, io->in.filter);
347 if (search->tree == NULL) {
351 if (!ldap_encode(msg, &req->encoded, req)) {
352 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
353 req->dest->addr, req->dest->port));
357 DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
359 EVENT_FD_WRITEABLE(cldap->fde);
370 queue a cldap reply for send
372 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
374 struct ldap_message *msg;
375 struct cldap_request *req;
376 DATA_BLOB blob1, blob2;
377 NTSTATUS status = NT_STATUS_NO_MEMORY;
379 req = talloc_zero(cldap, struct cldap_request);
380 if (req == NULL) goto failed;
383 req->state = CLDAP_REQUEST_SEND;
384 req->is_reply = true;
385 req->asn1 = asn1_init(req);
390 req->dest = io->dest;
391 if (talloc_reference(req, io->dest) == NULL) goto failed;
393 talloc_set_destructor(req, cldap_request_destructor);
395 msg = talloc(req, struct ldap_message);
396 if (msg == NULL) goto failed;
397 msg->messageid = io->messageid;
398 msg->controls = NULL;
401 msg->type = LDAP_TAG_SearchResultEntry;
402 msg->r.SearchResultEntry = *io->response;
404 if (!ldap_encode(msg, &blob1, req)) {
405 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
406 req->dest->addr, req->dest->port));
407 status = NT_STATUS_INVALID_PARAMETER;
411 blob1 = data_blob(NULL, 0);
414 msg->type = LDAP_TAG_SearchResultDone;
415 msg->r.SearchResultDone = *io->result;
417 if (!ldap_encode(msg, &blob2, req)) {
418 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
419 req->dest->addr, req->dest->port));
420 status = NT_STATUS_INVALID_PARAMETER;
424 req->encoded = data_blob_talloc(req, NULL, blob1.length + blob2.length);
425 if (req->encoded.data == NULL) goto failed;
427 memcpy(req->encoded.data, blob1.data, blob1.length);
428 memcpy(req->encoded.data+blob1.length, blob2.data, blob2.length);
430 DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
432 EVENT_FD_WRITEABLE(cldap->fde);
442 receive a cldap reply
444 NTSTATUS cldap_search_recv(struct cldap_request *req,
446 struct cldap_search *io)
448 struct ldap_message *ldap_msg;
452 return NT_STATUS_NO_MEMORY;
455 while (req->state < CLDAP_REQUEST_DONE) {
456 if (event_loop_once(req->cldap->event_ctx) != 0) {
458 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
462 if (req->state == CLDAP_REQUEST_ERROR) {
463 status = req->status;
468 ldap_msg = talloc(mem_ctx, struct ldap_message);
469 NT_STATUS_HAVE_NO_MEMORY(ldap_msg);
471 status = ldap_decode(req->asn1, ldap_msg);
472 if (!NT_STATUS_IS_OK(status)) {
473 DEBUG(2,("Failed to decode cldap search reply: %s\n", nt_errstr(status)));
478 ZERO_STRUCT(io->out);
480 /* the first possible form has a search result in first place */
481 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
482 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
483 NT_STATUS_HAVE_NO_MEMORY(io->out.response);
484 *io->out.response = ldap_msg->r.SearchResultEntry;
486 /* decode the 2nd part */
487 status = ldap_decode(req->asn1, ldap_msg);
488 if (!NT_STATUS_IS_OK(status)) {
489 DEBUG(2,("Failed to decode cldap search result entry: %s\n", nt_errstr(status)));
495 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
497 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
500 io->out.result = talloc(mem_ctx, struct ldap_Result);
501 NT_STATUS_HAVE_NO_MEMORY(io->out.result);
502 *io->out.result = ldap_msg->r.SearchResultDone;
506 if (io->out.result->resultcode != LDAP_SUCCESS) {
507 return NT_STATUS_LDAP(io->out.result->resultcode);
514 synchronous cldap search
516 NTSTATUS cldap_search(struct cldap_socket *cldap,
518 struct cldap_search *io)
520 struct cldap_request *req = cldap_search_send(cldap, io);
521 return cldap_search_recv(req, mem_ctx, io);
527 queue a cldap netlogon for send
529 struct cldap_request *cldap_netlogon_send(struct cldap_socket *cldap,
530 struct cldap_netlogon *io)
532 struct cldap_search search;
534 struct cldap_request *req;
535 const char *attr[] = { "NetLogon", NULL };
536 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
538 filter = talloc_asprintf(tmp_ctx, "(&(NtVer=%s)",
539 ldap_encode_ndr_uint32(tmp_ctx, io->in.version));
540 if (filter == NULL) goto failed;
542 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
543 if (filter == NULL) goto failed;
546 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
547 if (filter == NULL) goto failed;
550 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
551 if (filter == NULL) goto failed;
553 if (io->in.acct_control != -1) {
554 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
555 ldap_encode_ndr_uint32(tmp_ctx, io->in.acct_control));
556 if (filter == NULL) goto failed;
558 if (io->in.domain_sid) {
559 struct dom_sid *sid = dom_sid_parse_talloc(tmp_ctx, io->in.domain_sid);
560 if (sid == NULL) goto failed;
561 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
562 ldap_encode_ndr_dom_sid(tmp_ctx, sid));
563 if (filter == NULL) goto failed;
565 if (io->in.domain_guid) {
568 status = GUID_from_string(io->in.domain_guid, &guid);
569 if (!NT_STATUS_IS_OK(status)) goto failed;
570 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
571 ldap_encode_ndr_GUID(tmp_ctx, &guid));
572 if (filter == NULL) goto failed;
574 filter = talloc_asprintf_append_buffer(filter, ")");
575 if (filter == NULL) goto failed;
577 search.in.dest_address = io->in.dest_address;
578 search.in.dest_port = io->in.dest_port;
579 search.in.filter = filter;
580 search.in.attributes = attr;
581 search.in.timeout = 2;
582 search.in.retries = 2;
584 req = cldap_search_send(cldap, &search);
586 talloc_free(tmp_ctx);
589 talloc_free(tmp_ctx);
595 receive a cldap netlogon reply
597 NTSTATUS cldap_netlogon_recv(struct cldap_request *req,
599 struct cldap_netlogon *io)
602 enum ndr_err_code ndr_err;
603 struct cldap_search search;
606 status = cldap_search_recv(req, mem_ctx, &search);
607 if (!NT_STATUS_IS_OK(status)) {
610 if (search.out.response == NULL) {
611 return NT_STATUS_NOT_FOUND;
614 if (search.out.response->num_attributes != 1 ||
615 strcasecmp(search.out.response->attributes[0].name, "netlogon") != 0 ||
616 search.out.response->attributes[0].num_values != 1 ||
617 search.out.response->attributes[0].values->length < 2) {
618 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
620 data = search.out.response->attributes[0].values;
622 ndr_err = ndr_pull_union_blob_all(data, mem_ctx,
623 req->cldap->iconv_convenience,
625 io->in.version & 0xF,
626 (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
627 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
628 DEBUG(2,("cldap failed to parse netlogon response of type 0x%02x\n",
629 SVAL(data->data, 0)));
630 dump_data(10, data->data, data->length);
631 return ndr_map_error2ntstatus(ndr_err);
638 sync cldap netlogon search
640 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
641 TALLOC_CTX *mem_ctx, struct cldap_netlogon *io)
643 struct cldap_request *req = cldap_netlogon_send(cldap, io);
644 return cldap_netlogon_recv(req, mem_ctx, io);
649 send an empty reply (used on any error, so the client doesn't keep waiting
650 or send the bad request again)
652 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
654 struct socket_address *src)
657 struct cldap_reply reply;
658 struct ldap_Result result;
660 reply.messageid = message_id;
662 reply.response = NULL;
663 reply.result = &result;
667 status = cldap_reply_send(cldap, &reply);
673 send an error reply (used on any error, so the client doesn't keep waiting
674 or send the bad request again)
676 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
678 struct socket_address *src,
680 const char *errormessage)
683 struct cldap_reply reply;
684 struct ldap_Result result;
686 reply.messageid = message_id;
688 reply.response = NULL;
689 reply.result = &result;
692 result.resultcode = resultcode;
693 result.errormessage = errormessage;
695 status = cldap_reply_send(cldap, &reply);
702 send a netlogon reply
704 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
706 struct socket_address *src,
708 union nbt_cldap_netlogon *netlogon)
711 enum ndr_err_code ndr_err;
712 struct cldap_reply reply;
713 struct ldap_SearchResEntry response;
714 struct ldap_Result result;
715 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
718 ndr_err = ndr_push_union_blob(&blob, tmp_ctx,
719 cldap->iconv_convenience,
720 netlogon, version & 0xF,
721 (ndr_push_flags_fn_t)ndr_push_nbt_cldap_netlogon);
722 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
723 talloc_free(tmp_ctx);
724 return ndr_map_error2ntstatus(ndr_err);
727 reply.messageid = message_id;
729 reply.response = &response;
730 reply.result = &result;
735 response.num_attributes = 1;
736 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
737 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
738 response.attributes->name = "netlogon";
739 response.attributes->num_values = 1;
740 response.attributes->values = &blob;
742 status = cldap_reply_send(cldap, &reply);
744 talloc_free(tmp_ctx);