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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 see RFC1798 for details of CLDAP
27 - carried over UDP on port 389
28 - request and response matched by message ID
29 - request consists of only a single searchRequest element
30 - response can be in one of two forms
31 - a single searchResponse, followed by a searchResult
32 - a single searchResult
36 #include "lib/events/events.h"
37 #include "dlinklist.h"
38 #include "libcli/ldap/ldap.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"
45 destroy a pending request
47 static int cldap_request_destructor(void *ptr)
49 struct cldap_request *req = talloc_get_type(ptr, struct cldap_request);
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;
71 struct ldap_message *ldap_msg;
72 struct cldap_request *req;
74 status = socket_pending(cldap->sock, &dsize);
75 if (!NT_STATUS_IS_OK(status)) {
80 blob = data_blob_talloc(tmp_ctx, NULL, dsize);
81 if (blob.data == NULL) {
86 status = socket_recvfrom(cldap->sock, blob.data, blob.length, &nread,
88 if (!NT_STATUS_IS_OK(status)) {
94 DEBUG(2,("Received cldap packet of length %d from %s:%d\n",
95 (int)blob.length, src->addr, src->port));
97 if (!asn1_load(&asn1, blob)) {
98 DEBUG(2,("Failed to setup for asn.1 decode\n"));
102 talloc_steal(tmp_ctx, asn1.data);
104 ldap_msg = talloc(tmp_ctx, struct ldap_message);
105 if (ldap_msg == NULL) {
106 talloc_free(tmp_ctx);
110 /* this initial decode is used to find the message id */
111 if (!ldap_decode(&asn1, ldap_msg)) {
112 DEBUG(2,("Failed to decode ldap message\n"));
113 talloc_free(tmp_ctx);
117 /* find the pending request */
118 req = idr_find(cldap->idr, ldap_msg->messageid);
120 if (cldap->incoming.handler) {
121 cldap->incoming.handler(cldap, ldap_msg, src);
123 DEBUG(2,("Mismatched cldap reply %u from %s:%d\n",
124 ldap_msg->messageid, src->addr, src->port));
126 talloc_free(tmp_ctx);
131 talloc_steal(req, asn1.data);
134 req->state = CLDAP_REQUEST_DONE;
135 talloc_free(req->te);
137 talloc_free(tmp_ctx);
145 handle request timeouts
147 static void cldap_request_timeout(struct event_context *event_ctx,
148 struct timed_event *te, struct timeval t,
151 struct cldap_request *req = talloc_get_type(private, struct cldap_request);
153 /* possibly try again */
154 if (req->num_retries != 0) {
155 size_t len = req->encoded.length;
159 socket_sendto(req->cldap->sock, &req->encoded, &len,
162 req->te = event_add_timed(req->cldap->event_ctx, req,
163 timeval_current_ofs(req->timeout, 0),
164 cldap_request_timeout, req);
168 req->state = CLDAP_REQUEST_TIMEOUT;
175 handle send events on a cldap socket
177 static void cldap_socket_send(struct cldap_socket *cldap)
179 struct cldap_request *req;
182 while ((req = cldap->send_queue)) {
185 len = req->encoded.length;
186 status = socket_sendto(cldap->sock, &req->encoded, &len,
188 if (NT_STATUS_IS_ERR(status)) {
189 DEBUG(3,("Failed to send cldap request of length %u to %s:%d\n",
190 (unsigned)req->encoded.length, req->dest->addr, req->dest->port));
191 DLIST_REMOVE(cldap->send_queue, req);
196 if (!NT_STATUS_IS_OK(status)) return;
198 DLIST_REMOVE(cldap->send_queue, req);
203 req->state = CLDAP_REQUEST_WAIT;
205 req->te = event_add_timed(cldap->event_ctx, req,
206 timeval_current_ofs(req->timeout, 0),
207 cldap_request_timeout, req);
209 EVENT_FD_READABLE(cldap->fde);
213 EVENT_FD_NOT_WRITEABLE(cldap->fde);
219 handle fd events on a cldap_socket
221 static void cldap_socket_handler(struct event_context *ev, struct fd_event *fde,
222 uint16_t flags, void *private)
224 struct cldap_socket *cldap = talloc_get_type(private, struct cldap_socket);
225 if (flags & EVENT_FD_WRITE) {
226 cldap_socket_send(cldap);
228 if (flags & EVENT_FD_READ) {
229 cldap_socket_recv(cldap);
234 initialise a cldap_socket. The event_ctx is optional, if provided
235 then operations will use that event context
237 struct cldap_socket *cldap_socket_init(TALLOC_CTX *mem_ctx,
238 struct event_context *event_ctx)
240 struct cldap_socket *cldap;
243 cldap = talloc(mem_ctx, struct cldap_socket);
244 if (cldap == NULL) goto failed;
246 if (event_ctx == NULL) {
247 cldap->event_ctx = event_context_init(cldap);
249 cldap->event_ctx = talloc_reference(cldap, event_ctx);
251 if (cldap->event_ctx == NULL) goto failed;
253 cldap->idr = idr_init(cldap);
254 if (cldap->idr == NULL) goto failed;
256 status = socket_create("ip", SOCKET_TYPE_DGRAM, &cldap->sock, 0);
257 if (!NT_STATUS_IS_OK(status)) goto failed;
259 talloc_steal(cldap, cldap->sock);
261 cldap->fde = event_add_fd(cldap->event_ctx, cldap,
262 socket_get_fd(cldap->sock), 0,
263 cldap_socket_handler, cldap);
265 cldap->send_queue = NULL;
266 cldap->incoming.handler = NULL;
277 setup a handler for incoming requests
279 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
280 void (*handler)(struct cldap_socket *, struct ldap_message *,
281 struct socket_address *),
284 cldap->incoming.handler = handler;
285 cldap->incoming.private = private;
286 EVENT_FD_READABLE(cldap->fde);
291 queue a cldap request for send
293 struct cldap_request *cldap_search_send(struct cldap_socket *cldap,
294 struct cldap_search *io)
296 struct ldap_message *msg;
297 struct cldap_request *req;
298 struct ldap_SearchRequest *search;
300 req = talloc_zero(cldap, struct cldap_request);
301 if (req == NULL) goto failed;
304 req->state = CLDAP_REQUEST_SEND;
305 req->timeout = io->in.timeout;
306 req->num_retries = io->in.retries;
307 req->is_reply = False;
309 req->dest = socket_address_from_strings(req, cldap->sock->backend_name,
310 io->in.dest_address, lp_cldap_port());
311 if (!req->dest) goto failed;
313 req->message_id = idr_get_new_random(cldap->idr, req, UINT16_MAX);
314 if (req->message_id == -1) goto failed;
316 talloc_set_destructor(req, cldap_request_destructor);
318 msg = talloc(req, struct ldap_message);
319 if (msg == NULL) goto failed;
320 msg->messageid = req->message_id;
321 msg->type = LDAP_TAG_SearchRequest;
322 msg->controls = NULL;
323 search = &msg->r.SearchRequest;
326 search->scope = LDAP_SEARCH_SCOPE_BASE;
327 search->deref = LDAP_DEREFERENCE_NEVER;
328 search->timelimit = 0;
329 search->sizelimit = 0;
330 search->attributesonly = False;
331 search->num_attributes = str_list_length(io->in.attributes);
332 search->attributes = io->in.attributes;
333 search->tree = ldb_parse_tree(req, io->in.filter);
334 if (search->tree == NULL) {
338 if (!ldap_encode(msg, &req->encoded, req)) {
339 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
340 req->dest->addr, req->dest->port));
344 DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
346 EVENT_FD_WRITEABLE(cldap->fde);
357 queue a cldap reply for send
359 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
361 struct ldap_message *msg;
362 struct cldap_request *req;
363 DATA_BLOB blob1, blob2;
364 NTSTATUS status = NT_STATUS_NO_MEMORY;
366 req = talloc_zero(cldap, struct cldap_request);
367 if (req == NULL) goto failed;
370 req->state = CLDAP_REQUEST_SEND;
371 req->is_reply = True;
373 req->dest = io->dest;
374 if (talloc_reference(req, io->dest) == NULL) goto failed;
376 talloc_set_destructor(req, cldap_request_destructor);
378 msg = talloc(req, struct ldap_message);
379 if (msg == NULL) goto failed;
380 msg->messageid = io->messageid;
381 msg->controls = NULL;
384 msg->type = LDAP_TAG_SearchResultEntry;
385 msg->r.SearchResultEntry = *io->response;
387 if (!ldap_encode(msg, &blob1, req)) {
388 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
389 req->dest->addr, req->dest->port));
390 status = NT_STATUS_INVALID_PARAMETER;
394 blob1 = data_blob(NULL, 0);
397 msg->type = LDAP_TAG_SearchResultDone;
398 msg->r.SearchResultDone = *io->result;
400 if (!ldap_encode(msg, &blob2, req)) {
401 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
402 req->dest->addr, req->dest->port));
403 status = NT_STATUS_INVALID_PARAMETER;
407 req->encoded = data_blob_talloc(req, NULL, blob1.length + blob2.length);
408 if (req->encoded.data == NULL) goto failed;
410 memcpy(req->encoded.data, blob1.data, blob1.length);
411 memcpy(req->encoded.data+blob1.length, blob2.data, blob2.length);
413 DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
415 EVENT_FD_WRITEABLE(cldap->fde);
425 receive a cldap reply
427 NTSTATUS cldap_search_recv(struct cldap_request *req,
429 struct cldap_search *io)
431 struct ldap_message *ldap_msg;
434 return NT_STATUS_NO_MEMORY;
437 while (req->state < CLDAP_REQUEST_DONE) {
438 if (event_loop_once(req->cldap->event_ctx) != 0) {
440 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
444 if (req->state == CLDAP_REQUEST_TIMEOUT) {
446 return NT_STATUS_IO_TIMEOUT;
449 ldap_msg = talloc(mem_ctx, struct ldap_message);
450 NT_STATUS_HAVE_NO_MEMORY(ldap_msg);
452 if (!ldap_decode(&req->asn1, ldap_msg)) {
454 return NT_STATUS_INVALID_PARAMETER;
457 ZERO_STRUCT(io->out);
459 /* the first possible form has a search result in first place */
460 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
461 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
462 NT_STATUS_HAVE_NO_MEMORY(io->out.response);
463 *io->out.response = ldap_msg->r.SearchResultEntry;
465 /* decode the 2nd part */
466 if (!ldap_decode(&req->asn1, ldap_msg)) {
468 return NT_STATUS_INVALID_PARAMETER;
472 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
474 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
477 io->out.result = talloc(mem_ctx, struct ldap_Result);
478 NT_STATUS_HAVE_NO_MEMORY(io->out.result);
479 *io->out.result = ldap_msg->r.SearchResultDone;
487 synchronous cldap search
489 NTSTATUS cldap_search(struct cldap_socket *cldap,
491 struct cldap_search *io)
493 struct cldap_request *req = cldap_search_send(cldap, io);
494 return cldap_search_recv(req, mem_ctx, io);
500 queue a cldap netlogon for send
502 struct cldap_request *cldap_netlogon_send(struct cldap_socket *cldap,
503 struct cldap_netlogon *io)
505 struct cldap_search search;
507 struct cldap_request *req;
508 const char *attr[] = { "NetLogon", NULL };
509 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
511 filter = talloc_asprintf(tmp_ctx, "(&(NtVer=%s)",
512 ldap_encode_ndr_uint32(tmp_ctx, io->in.version));
513 if (filter == NULL) goto failed;
515 filter = talloc_asprintf_append(filter, "(User=%s)", io->in.user);
516 if (filter == NULL) goto failed;
519 filter = talloc_asprintf_append(filter, "(Host=%s)", io->in.host);
520 if (filter == NULL) goto failed;
523 filter = talloc_asprintf_append(filter, "(DnsDomain=%s)", io->in.realm);
524 if (filter == NULL) goto failed;
526 if (io->in.acct_control != -1) {
527 filter = talloc_asprintf_append(filter, "(AAC=%s)",
528 ldap_encode_ndr_uint32(tmp_ctx, io->in.acct_control));
529 if (filter == NULL) goto failed;
531 if (io->in.domain_sid) {
532 struct dom_sid *sid = dom_sid_parse_talloc(tmp_ctx, io->in.domain_sid);
533 if (sid == NULL) goto failed;
534 filter = talloc_asprintf_append(filter, "(domainSid=%s)",
535 ldap_encode_ndr_dom_sid(tmp_ctx, sid));
536 if (filter == NULL) goto failed;
538 if (io->in.domain_guid) {
541 status = GUID_from_string(io->in.domain_guid, &guid);
542 if (!NT_STATUS_IS_OK(status)) goto failed;
543 filter = talloc_asprintf_append(filter, "(DomainGuid=%s)",
544 ldap_encode_ndr_GUID(tmp_ctx, &guid));
545 if (filter == NULL) goto failed;
547 filter = talloc_asprintf_append(filter, ")");
548 if (filter == NULL) goto failed;
550 search.in.dest_address = io->in.dest_address;
551 search.in.filter = filter;
552 search.in.attributes = attr;
553 search.in.timeout = 2;
554 search.in.retries = 2;
556 req = cldap_search_send(cldap, &search);
558 talloc_free(tmp_ctx);
561 talloc_free(tmp_ctx);
567 receive a cldap netlogon reply
569 NTSTATUS cldap_netlogon_recv(struct cldap_request *req,
571 struct cldap_netlogon *io)
574 struct cldap_search search;
577 status = cldap_search_recv(req, mem_ctx, &search);
578 if (!NT_STATUS_IS_OK(status)) {
581 if (search.out.response == NULL) {
582 return NT_STATUS_NOT_FOUND;
585 if (search.out.response->num_attributes != 1 ||
586 strcasecmp(search.out.response->attributes[0].name, "netlogon") != 0 ||
587 search.out.response->attributes[0].num_values != 1 ||
588 search.out.response->attributes[0].values->length < 2) {
589 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
591 data = search.out.response->attributes[0].values;
593 status = ndr_pull_union_blob(data, mem_ctx, &io->out.netlogon,
594 io->in.version & 0xF,
595 (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
596 if (!NT_STATUS_IS_OK(status)) {
597 DEBUG(2,("cldap failed to parse netlogon response of type 0x%02x\n",
598 SVAL(data->data, 0)));
599 dump_data(10, data->data, data->length);
606 sync cldap netlogon search
608 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
609 TALLOC_CTX *mem_ctx, struct cldap_netlogon *io)
611 struct cldap_request *req = cldap_netlogon_send(cldap, io);
612 return cldap_netlogon_recv(req, mem_ctx, io);
617 send an empty reply (used on any error, so the client doesn't keep waiting
618 or send the bad request again)
620 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
622 struct socket_address *src)
625 struct cldap_reply reply;
626 struct ldap_Result result;
628 reply.messageid = message_id;
630 reply.response = NULL;
631 reply.result = &result;
635 status = cldap_reply_send(cldap, &reply);
642 send a netlogon reply
644 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
646 struct socket_address *src,
648 union nbt_cldap_netlogon *netlogon)
651 struct cldap_reply reply;
652 struct ldap_SearchResEntry response;
653 struct ldap_Result result;
654 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
657 status = ndr_push_union_blob(&blob, tmp_ctx, netlogon, version & 0xF,
658 (ndr_push_flags_fn_t)ndr_push_nbt_cldap_netlogon);
659 if (!NT_STATUS_IS_OK(status)) {
660 talloc_free(tmp_ctx);
664 reply.messageid = message_id;
666 reply.response = &response;
667 reply.result = &result;
672 response.num_attributes = 1;
673 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
674 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
675 response.attributes->name = "netlogon";
676 response.attributes->num_values = 1;
677 response.attributes->values = &blob;
679 status = cldap_reply_send(cldap, &reply);
681 talloc_free(tmp_ctx);