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"
43 destroy a pending request
45 static int cldap_request_destructor(void *ptr)
47 struct cldap_request *req = talloc_get_type(ptr, struct cldap_request);
48 if (req->state == CLDAP_REQUEST_SEND) {
49 DLIST_REMOVE(req->cldap->send_queue, req);
51 if (!req->is_reply && req->message_id != 0) {
52 idr_remove(req->cldap->idr, req->message_id);
59 handle recv events on a cldap socket
61 static void cldap_socket_recv(struct cldap_socket *cldap)
63 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
69 struct asn1_data asn1;
70 struct ldap_message *ldap_msg;
71 struct cldap_request *req;
73 status = socket_pending(cldap->sock, &dsize);
74 if (!NT_STATUS_IS_OK(status)) {
79 blob = data_blob_talloc(tmp_ctx, NULL, dsize);
80 if (blob.data == NULL) {
85 status = socket_recvfrom(cldap->sock, blob.data, blob.length, &nread, 0,
86 &src_addr, &src_port);
87 if (!NT_STATUS_IS_OK(status)) {
91 talloc_steal(tmp_ctx, src_addr);
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_addr, src_port);
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, 0,
160 req->dest_addr, req->dest_port);
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, 0,
187 req->dest_addr, req->dest_port);
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 *,
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_addr = talloc_strdup(req, io->in.dest_address);
310 if (req->dest_addr == NULL) goto failed;
311 req->dest_port = lp_cldap_port();
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->num_controls = 0;
323 msg->controls = NULL;
324 search = &msg->r.SearchRequest;
327 search->scope = LDAP_SEARCH_SCOPE_BASE;
328 search->deref = LDAP_DEREFERENCE_NEVER;
329 search->timelimit = 0;
330 search->sizelimit = 0;
331 search->attributesonly = False;
332 search->num_attributes = str_list_length(io->in.attributes);
333 search->attributes = io->in.attributes;
334 search->tree = ldb_parse_tree(req, io->in.filter);
335 if (search->tree == NULL) {
339 if (!ldap_encode(msg, &req->encoded, req)) {
340 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
341 req->dest_addr, req->dest_port));
345 DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
347 EVENT_FD_WRITEABLE(cldap->fde);
358 queue a cldap reply for send
360 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
362 struct ldap_message *msg;
363 struct cldap_request *req;
364 DATA_BLOB blob1, blob2;
365 NTSTATUS status = NT_STATUS_NO_MEMORY;
367 req = talloc_zero(cldap, struct cldap_request);
368 if (req == NULL) goto failed;
371 req->state = CLDAP_REQUEST_SEND;
372 req->is_reply = True;
374 req->dest_addr = talloc_strdup(req, io->dest_address);
375 if (req->dest_addr == NULL) goto failed;
376 req->dest_port = io->dest_port;
378 talloc_set_destructor(req, cldap_request_destructor);
380 msg = talloc(req, struct ldap_message);
381 if (msg == NULL) goto failed;
382 msg->messageid = io->messageid;
383 msg->num_controls = 0;
384 msg->controls = NULL;
387 msg->type = LDAP_TAG_SearchResultEntry;
388 msg->r.SearchResultEntry = *io->response;
390 if (!ldap_encode(msg, &blob1, req)) {
391 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
392 req->dest_addr, req->dest_port));
393 status = NT_STATUS_INVALID_PARAMETER;
397 blob1 = data_blob(NULL, 0);
400 msg->type = LDAP_TAG_SearchResultDone;
401 msg->r.SearchResultDone = *io->result;
403 if (!ldap_encode(msg, &blob2, req)) {
404 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
405 req->dest_addr, req->dest_port));
406 status = NT_STATUS_INVALID_PARAMETER;
410 req->encoded = data_blob_talloc(req, NULL, blob1.length + blob2.length);
411 if (req->encoded.data == NULL) goto failed;
413 memcpy(req->encoded.data, blob1.data, blob1.length);
414 memcpy(req->encoded.data+blob1.length, blob2.data, blob2.length);
416 DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
418 EVENT_FD_WRITEABLE(cldap->fde);
428 receive a cldap reply
430 NTSTATUS cldap_search_recv(struct cldap_request *req,
432 struct cldap_search *io)
434 struct ldap_message *ldap_msg;
437 return NT_STATUS_NO_MEMORY;
440 while (req->state < CLDAP_REQUEST_DONE) {
441 if (event_loop_once(req->cldap->event_ctx) != 0) {
443 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
447 if (req->state == CLDAP_REQUEST_TIMEOUT) {
449 return NT_STATUS_IO_TIMEOUT;
452 ldap_msg = talloc(mem_ctx, struct ldap_message);
453 NT_STATUS_HAVE_NO_MEMORY(ldap_msg);
455 if (!ldap_decode(&req->asn1, ldap_msg)) {
457 return NT_STATUS_INVALID_PARAMETER;
460 ZERO_STRUCT(io->out);
462 /* the first possible form has a search result in first place */
463 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
464 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
465 NT_STATUS_HAVE_NO_MEMORY(io->out.response);
466 *io->out.response = ldap_msg->r.SearchResultEntry;
468 /* decode the 2nd part */
469 if (!ldap_decode(&req->asn1, ldap_msg)) {
471 return NT_STATUS_INVALID_PARAMETER;
475 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
477 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
480 io->out.result = talloc(mem_ctx, struct ldap_Result);
481 NT_STATUS_HAVE_NO_MEMORY(io->out.result);
482 *io->out.result = ldap_msg->r.SearchResultDone;
490 synchronous cldap search
492 NTSTATUS cldap_search(struct cldap_socket *cldap,
494 struct cldap_search *io)
496 struct cldap_request *req = cldap_search_send(cldap, io);
497 return cldap_search_recv(req, mem_ctx, io);
503 queue a cldap netlogon for send
505 struct cldap_request *cldap_netlogon_send(struct cldap_socket *cldap,
506 struct cldap_netlogon *io)
508 struct cldap_search search;
510 struct cldap_request *req;
511 const char *attr[] = { "NetLogon", NULL };
512 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
514 filter = talloc_asprintf(tmp_ctx, "(&(NtVer=%s)",
515 ldap_encode_ndr_uint32(tmp_ctx, io->in.version));
516 if (filter == NULL) goto failed;
518 filter = talloc_asprintf_append(filter, "(User=%s)", io->in.user);
519 if (filter == NULL) goto failed;
522 filter = talloc_asprintf_append(filter, "(Host=%s)", io->in.host);
523 if (filter == NULL) goto failed;
526 filter = talloc_asprintf_append(filter, "(DnsDomain=%s)", io->in.realm);
527 if (filter == NULL) goto failed;
529 if (io->in.acct_control != -1) {
530 filter = talloc_asprintf_append(filter, "(AAC=%s)",
531 ldap_encode_ndr_uint32(tmp_ctx, io->in.acct_control));
532 if (filter == NULL) goto failed;
534 if (io->in.domain_sid) {
535 struct dom_sid *sid = dom_sid_parse_talloc(tmp_ctx, io->in.domain_sid);
536 if (sid == NULL) goto failed;
537 filter = talloc_asprintf_append(filter, "(domainSid=%s)",
538 ldap_encode_ndr_dom_sid(tmp_ctx, sid));
539 if (filter == NULL) goto failed;
541 if (io->in.domain_guid) {
544 status = GUID_from_string(io->in.domain_guid, &guid);
545 if (!NT_STATUS_IS_OK(status)) goto failed;
546 filter = talloc_asprintf_append(filter, "(DomainGuid=%s)",
547 ldap_encode_ndr_GUID(tmp_ctx, &guid));
548 if (filter == NULL) goto failed;
550 filter = talloc_asprintf_append(filter, ")");
551 if (filter == NULL) goto failed;
553 search.in.dest_address = io->in.dest_address;
554 search.in.filter = filter;
555 search.in.attributes = attr;
556 search.in.timeout = 2;
557 search.in.retries = 2;
559 req = cldap_search_send(cldap, &search);
561 talloc_free(tmp_ctx);
564 talloc_free(tmp_ctx);
570 receive a cldap netlogon reply
572 NTSTATUS cldap_netlogon_recv(struct cldap_request *req,
574 struct cldap_netlogon *io)
577 struct cldap_search search;
580 status = cldap_search_recv(req, mem_ctx, &search);
581 if (!NT_STATUS_IS_OK(status)) {
584 if (search.out.response == NULL) {
585 return NT_STATUS_NOT_FOUND;
588 if (search.out.response->num_attributes != 1 ||
589 strcasecmp(search.out.response->attributes[0].name, "netlogon") != 0 ||
590 search.out.response->attributes[0].num_values != 1 ||
591 search.out.response->attributes[0].values->length < 2) {
592 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
594 data = search.out.response->attributes[0].values;
596 status = ndr_pull_union_blob(data, mem_ctx, &io->out.netlogon,
597 io->in.version & 0xF,
598 (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
599 if (!NT_STATUS_IS_OK(status)) {
600 DEBUG(2,("cldap failed to parse netlogon response of type 0x%02x\n",
601 SVAL(data->data, 0)));
602 dump_data(10, data->data, data->length);
609 sync cldap netlogon search
611 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
612 TALLOC_CTX *mem_ctx, struct cldap_netlogon *io)
614 struct cldap_request *req = cldap_netlogon_send(cldap, io);
615 return cldap_netlogon_recv(req, mem_ctx, io);
620 send an empty reply (used on any error, so the client doesn't keep waiting
621 or send the bad request again)
623 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
625 const char *src_address, int src_port)
628 struct cldap_reply reply;
629 struct ldap_Result result;
631 reply.messageid = message_id;
632 reply.dest_address = src_address;
633 reply.dest_port = src_port;
634 reply.response = NULL;
635 reply.result = &result;
639 status = cldap_reply_send(cldap, &reply);
646 send a netlogon reply
648 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
650 const char *src_address, int src_port,
652 union nbt_cldap_netlogon *netlogon)
655 struct cldap_reply reply;
656 struct ldap_SearchResEntry response;
657 struct ldap_Result result;
658 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
661 status = ndr_push_union_blob(&blob, tmp_ctx, netlogon, version & 0xF,
662 (ndr_push_flags_fn_t)ndr_push_nbt_cldap_netlogon);
663 if (!NT_STATUS_IS_OK(status)) {
664 talloc_free(tmp_ctx);
668 reply.messageid = message_id;
669 reply.dest_address = src_address;
670 reply.dest_port = src_port;
671 reply.response = &response;
672 reply.result = &result;
677 response.num_attributes = 1;
678 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
679 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
680 response.attributes->name = "netlogon";
681 response.attributes->num_values = 1;
682 response.attributes->values = &blob;
684 status = cldap_reply_send(cldap, &reply);
686 talloc_free(tmp_ctx);